diff options
author | Ilya Smirnov <ismirno@us.ibm.com> | 2017-07-31 10:35:00 -0500 |
---|---|---|
committer | William A. Bryan <wilbryan@us.ibm.com> | 2017-08-21 15:09:44 -0400 |
commit | 7efcfd6eaba07fbdd3eeed455c81c34e75735dc1 (patch) | |
tree | e4118313c1ba75cc5491345cc0d9d9005d23ce67 /src/occ_405 | |
parent | 3b72373a3bfd5716902b48515f96faac683ef8dd (diff) | |
download | talos-occ-7efcfd6eaba07fbdd3eeed455c81c34e75735dc1.tar.gz talos-occ-7efcfd6eaba07fbdd3eeed455c81c34e75735dc1.zip |
IPL Time Checkstop Analysis Part 3: OCC bootloader and main
Change-Id: Id4d050f1d78a1921afc839c8b2b382961def64f0
RTC:155065
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/43938
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: William G. Hoffa <wghoffa@us.ibm.com>
Reviewed-by: Martha Broyles <mbroyles@us.ibm.com>
Reviewed-by: William A. Bryan <wilbryan@us.ibm.com>
Diffstat (limited to 'src/occ_405')
-rwxr-xr-x | src/occ_405/common.c | 31 | ||||
-rw-r--r-- | src/occ_405/common.h | 7 | ||||
-rwxr-xr-x | src/occ_405/incl/common_types.h | 18 | ||||
-rwxr-xr-x | src/occ_405/main.c | 355 |
4 files changed, 258 insertions, 153 deletions
diff --git a/src/occ_405/common.c b/src/occ_405/common.c index 02da123..fd031e2 100755 --- a/src/occ_405/common.c +++ b/src/occ_405/common.c @@ -1,11 +1,11 @@ /* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ -/* $Source: src/occ/common.c $ */ +/* $Source: src/occ_405/common.c $ */ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* Contributors Listed Below - COPYRIGHT 2011,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -31,6 +31,7 @@ #include <occ_service_codes.h> uint8_t G_host_notifications_pending = 0; +extern bool G_ipl_time; // Function Specification @@ -54,6 +55,8 @@ void task_misc_405_checks(task_t *i_self) static bool L_checkstop_traced = false; uint8_t l_reason_code = 0; + bool l_create_errl = false; + do { @@ -67,10 +70,28 @@ void task_misc_405_checks(task_t *i_self) // indicates if the system has check-stopped. l_oisr0_status.value = in32(OCB_OISR0); // read high order 32 bits of OISR0 + // We're only interested in system checkstop during IPL, so only check + // for that if the IPL flag is set (in 405 main.c). If gpe0/1_error is + // set before ppc405 checkstop, then we won't get a chance to collect + // firdata, so only check for GPE0/1 errors in runtime. + if(G_ipl_time) + { + if(l_oisr0_status.fields.check_stop_ppc405) + { + l_create_errl = true; + } + } + else + { + if (l_oisr0_status.fields.check_stop_ppc405 || // System Checkstop + l_oisr0_status.fields.gpe0_error || // GPE0 Halt + l_oisr0_status.fields.gpe1_error) // GPE1 Halt + { + l_create_errl = true; + } + } - if (l_oisr0_status.fields.check_stop_ppc405 || // System Checkstop - l_oisr0_status.fields.gpe0_error || // GPE0 Halt - l_oisr0_status.fields.gpe1_error) // GPE1 Halt + if(l_create_errl) { errlHndl_t l_err = NULL; diff --git a/src/occ_405/common.h b/src/occ_405/common.h index ac4a9fd..787af35 100644 --- a/src/occ_405/common.h +++ b/src/occ_405/common.h @@ -1,11 +1,11 @@ /* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ -/* $Source: src/occ/common.h $ */ +/* $Source: src/occ_405/common.h $ */ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -27,6 +27,9 @@ #include <rtls.h> +// Start of SRAM memory +#define SRAM_START_ADDRESS_405 0xFFF40000 + // Reasons why the OCCMISC external interrupt was triggered typedef enum { diff --git a/src/occ_405/incl/common_types.h b/src/occ_405/incl/common_types.h index d8d8aab..a2f2363 100755 --- a/src/occ_405/incl/common_types.h +++ b/src/occ_405/incl/common_types.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2016 */ +/* Contributors Listed Below - COPYRIGHT 2011,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -74,6 +74,14 @@ typedef enum #define ID_NUM_INVALID 0xFFFF #define SRAM_HEADER_HACK 0x48000042 + +struct OCC_FLAGS +{ + uint16_t reserved : 15; + uint16_t ipl_time_flag : 1; // Used to indicate whether OCC was started + // during IPL. Used for IPL-time checkstop +}; + #ifndef __ASSEMBLER__ // Structure for the common image header (total size is 162 bytes). @@ -132,6 +140,12 @@ struct image_header uint32_t version; // image version char image_id_str[IMAGE_ID_STR_SZ]; // image id string uint16_t aplt_id; // type: enum OCC_APLT + union + { + uint16_t flags; + struct OCC_FLAGS flag_bits; + } occ_flags; // bit field for occ flags + uint32_t nest_frequency; // nest frequency uint8_t reserved[RESERVED_SZ]; // reserved for future use } __attribute__ ((__packed__)); @@ -188,6 +202,8 @@ const volatile imageHdr_t nameStr __attribute__((section("imageHeader")))= \ 0, /* version (filled in later by imageHdrScript) */ \ IdStr, /* image_id_str */ \ (uint16_t)IdNum, /* aplt_id */ \ + {0}, /* flags */ \ + 0, /* nest frequency */ \ {0} /* reserved */ \ }; diff --git a/src/occ_405/main.c b/src/occ_405/main.c index 842f71e..a641806 100755 --- a/src/occ_405/main.c +++ b/src/occ_405/main.c @@ -62,6 +62,11 @@ #include "pgpe_service_codes.h" #include <common.h> +// Used to indicate if OCC was started during IPL, in which case OCC's only +// job is to look for checkstops. This flag is set by hostboot in OCC's header +// in SRAM +bool G_ipl_time = false; + extern uint32_t __ssx_boot; // Function address is 32 bits extern uint32_t G_occ_phantom_critical_count; extern uint32_t G_occ_phantom_noncritical_count; @@ -1601,30 +1606,33 @@ void Main_thread_routine(void *private) dcom_initialize_roles(); CHECKPOINT(ROLES_INITIALIZED); - // Sensor Initialization - // All Master & Slave Sensor are initialized here, it is up to the - // rest of the firmware if it uses them or not. - sensor_init_all(); - CHECKPOINT(SENSORS_INITIALIZED); - - // SPIVID Initialization must be done before Pstates - // All SPIVID inits are done by Hostboot, remove this section. - - //Initialize structures for collecting core data. - //It needs to run before RTLoop starts, as gpe request initialization - //needs to be done before task to collect core data starts. - proc_core_init(); - CHECKPOINT(PROC_CORE_INITIALIZED); - - // Initialize structures for collecting nest dts data. - // Needs to run before RTL to initialize the gpe request - nest_dts_init(); - CHECKPOINT(NEST_DTS_INITIALIZED); - - // Run slave OCC init on all OCCs. Master-only initialization will be - // done after determining actual role. By default all OCCs are slave. - slave_occ_init(); - CHECKPOINT(SLAVE_OCC_INITIALIZED); + if(!G_ipl_time) + { + // Sensor Initialization + // All Master & Slave Sensor are initialized here, it is up to the + // rest of the firmware if it uses them or not. + sensor_init_all(); + CHECKPOINT(SENSORS_INITIALIZED); + + // SPIVID Initialization must be done before Pstates + // All SPIVID inits are done by Hostboot, remove this section. + + //Initialize structures for collecting core data. + //It needs to run before RTLoop starts, as gpe request initialization + //needs to be done before task to collect core data starts. + proc_core_init(); + CHECKPOINT(PROC_CORE_INITIALIZED); + + // Initialize structures for collecting nest dts data. + // Needs to run before RTL to initialize the gpe request + nest_dts_init(); + CHECKPOINT(NEST_DTS_INITIALIZED); + + // Run slave OCC init on all OCCs. Master-only initialization will be + // done after determining actual role. By default all OCCs are slave. + slave_occ_init(); + CHECKPOINT(SLAVE_OCC_INITIALIZED); + } //G_ipl_time if (G_simics_environment) { @@ -1655,8 +1663,11 @@ void Main_thread_routine(void *private) } else { - // Read hcode headers (PPMR, OCC pstate parameter block, PGPE, WOF) - read_hcode_headers(); + if(!G_ipl_time) + { + // Read hcode headers (PPMR, OCC pstate parameter block, PGPE, WOF) + read_hcode_headers(); + } } // Initialize watchdog timers. This needs to be right before @@ -1667,20 +1678,26 @@ void Main_thread_routine(void *private) initWatchdogTimers(); CHECKPOINT(WATCHDOG_INITIALIZED); - // Initialize Real time Loop Timer Interrupt - rtl_ocb_init(); - CHECKPOINT(RTL_TIMER_INITIALIZED); + if(!G_ipl_time) + { + // Initialize Real time Loop Timer Interrupt + rtl_ocb_init(); + CHECKPOINT(RTL_TIMER_INITIALIZED); + } // Initialize semaphores and timer for handling health monitor and // FFDC functions. initMainThrdSemAndTimer(); CHECKPOINT(SEMS_AND_TIMERS_INITIALIZED); - //Initialize the thread scheduler. - //Other thread initialization is done here so that don't have to handle - // blocking commnad handler thread as FSP might start communicating - // through cmd handler thread in middle of the initialization. - initThreadScheduler(); + if(!G_ipl_time) + { + //Initialize the thread scheduler. + //Other thread initialization is done here so that don't have to handle + // blocking commnad handler thread as FSP might start communicating + // through cmd handler thread in middle of the initialization. + initThreadScheduler(); + } int l_ssxrc = SSX_OK; // initWatchdogTimers called before will start running the timer but @@ -1688,6 +1705,7 @@ void Main_thread_routine(void *private) // enable switch to actually start the watchdog function. // ENABLE_WDOG; + while (TRUE) { // Count each loop so the watchdog can tell the main thread is @@ -1701,6 +1719,13 @@ void Main_thread_routine(void *private) dcache_flush(g_trac_imp_buffer, TRACE_BUFFER_SIZE); dcache_flush(g_trac_err_buffer, TRACE_BUFFER_SIZE); + + // This task is not auto-scheduled during IPL, so run it manually + if(G_ipl_time) + { + task_misc_405_checks(NULL); + } + static bool L_fir_collection_completed = FALSE; uint32_t l_rc = 0; @@ -1729,8 +1754,10 @@ void Main_thread_routine(void *private) G_fir_collection_request_created = TRUE; TRAC_IMP("fir data collection: scheduling gpe request"); l_rc = gpe_request_schedule(&G_fir_collection_request); + if(l_rc != SUCCESS) { - TRAC_IMP("failed to schedule fir data collection job"); + TRAC_IMP("failed to schedule fir data collection" + " job. RC = %x", (uint32_t)l_rc); } L_fir_collection_completed = TRUE; @@ -1763,8 +1790,11 @@ void Main_thread_routine(void *private) } else { - // call health monitor routine - hmon_routine(); + if(!G_ipl_time) + { + // call health monitor routine + hmon_routine(); + } } } @@ -1779,10 +1809,13 @@ void Main_thread_routine(void *private) } else { - // Only Master OCC will log call home data - if (OCC_MASTER == G_occ_role) + if(!G_ipl_time) { - chom_main(); + // Only Master OCC will log call home data + if (OCC_MASTER == G_occ_role) + { + chom_main(); + } } } } @@ -1978,40 +2011,54 @@ int main(int argc, char **argv) homer_rc_t l_homerrc = HOMER_SUCCESS; homer_rc_t l_homerrc2 = HOMER_SUCCESS; - // Get the homer version + imageHdr_t* l_headerPtr = (imageHdr_t*)SRAM_START_ADDRESS_405; + G_ipl_time = l_headerPtr->occ_flags.flag_bits.ipl_time_flag; + + // Set to whatever is in the header. Frequency will be overwritten + // below if necessary. + uint32_t l_tb_freq_hz = (l_headerPtr->nest_frequency * 1000000) / 4; uint32_t l_homer_version = 0; - l_homerrc = homer_hd_map_read_unmap(HOMER_VERSION, - &l_homer_version, - &l_ssxrc); - - // Get proc_pb_frequency from HOMER host data and calculate the timebase - // frequency for the OCC. Pass the timebase frequency to ssx_initialize. - // The passed value must be in Hz. The occ 405 runs at 1/4 the proc - // frequency so the passed value is 1/4 of the proc_pb_frequency from the - // HOMER, ie. if the MRW says that proc_pb_frequency is 2400 MHz, then - // pass 600000000 (600MHz) - - // The offset from the start of the HOMER is 0x000C0000, we will need to - // create a temporary mapping to this section of the HOMER with ppc405_mmu_map - // (at address 0x800C0000) read the value, convert it, and then unmap. - - // Don't do a version check before reading the nest freq, it's present in - // all HOMER versions. - uint32_t l_tb_freq_hz = 0; - l_homerrc2 = homer_hd_map_read_unmap(HOMER_NEST_FREQ, - &G_nest_frequency_mhz, - &l_ssxrc2); - - if ((HOMER_SUCCESS == l_homerrc2) || (HOMER_SSX_UNMAP_ERR == l_homerrc2)) + + if(!G_ipl_time) { - // Data is in Mhz upon return and needs to be converted to Hz and then - // quartered. - l_tb_freq_hz = G_nest_frequency_mhz * (1000000 / 4); - } + // Get the homer version + l_homerrc = homer_hd_map_read_unmap(HOMER_VERSION, + &l_homer_version, + &l_ssxrc); + + // Get proc_pb_frequency from HOMER host data and calculate the timebase + // frequency for the OCC. Pass the timebase frequency to ssx_initialize. + // The passed value must be in Hz. The occ 405 runs at 1/4 the proc + // frequency so the passed value is 1/4 of the proc_pb_frequency from the + // HOMER, ie. if the MRW says that proc_pb_frequency is 2400 MHz, then + // pass 600000000 (600MHz) + + // The offset from the start of the HOMER is 0x000C0000, we will need to + // create a temporary mapping to this section of the HOMER with ppc405_mmu_map + // (at address 0x800C0000) read the value, convert it, and then unmap. + + // Don't do a version check before reading the nest freq, it's present in + // all HOMER versions. + l_homerrc2 = homer_hd_map_read_unmap(HOMER_NEST_FREQ, + &G_nest_frequency_mhz, + &l_ssxrc2); + + if ((HOMER_SUCCESS == l_homerrc2) || (HOMER_SSX_UNMAP_ERR == l_homerrc2)) + { + // Data is in Mhz upon return and needs to be converted to Hz and then + // quartered. + l_tb_freq_hz = G_nest_frequency_mhz * (1000000 / 4); + } + else + { + l_tb_freq_hz = PPC405_TIMEBASE_HZ; + G_nest_frequency_mhz = (l_tb_freq_hz * 4) / 1000000; + } + } //!G_ipl_time else { - l_tb_freq_hz = PPC405_TIMEBASE_HZ; - G_nest_frequency_mhz = (l_tb_freq_hz * 4) / 1000000; + MAIN_TRAC_INFO("freq = %d", l_tb_freq_hz); + G_nest_frequency_mhz = l_tb_freq_hz; } CHECKPOINT(SSX_STARTING); @@ -2036,6 +2083,15 @@ int main(int argc, char **argv) MAIN_TRAC_INFO("Inside OCC Main"); + if(G_ipl_time) + { + MAIN_TRAC_INFO("ipl flag is set"); + } + else + { + MAIN_TRAC_INFO("ipl flag is NOT set"); + } + if (G_simics_environment == FALSE) { MAIN_TRAC_INFO("Currently not running in Simics environment"); @@ -2053,94 +2109,103 @@ int main(int argc, char **argv) } } - // Trace what happened before ssx initialization - MAIN_TRAC_INFO("HOMER accessed, rc=%d, version=%d, ssx_rc=%d", - l_homerrc, l_homer_version, l_ssxrc); - - MAIN_TRAC_INFO("HOMER accessed, rc=%d, nest_freq=%d, ssx_rc=%d", - l_homerrc2, l_tb_freq_hz, l_ssxrc2); - - // Handle any errors from the version access - homer_log_access_error(l_homerrc, - l_ssxrc, - l_homer_version); - - // Handle any errors from the nest freq access - homer_log_access_error(l_homerrc2, - l_ssxrc2, - l_tb_freq_hz); - - // Time to access any initialization data needed from the HOMER (besides the - // nest frequency which was required above to enable SSX and tracing). - CHECKPOINT(HOMER_ACCESS_INITS); - - // Get OCC interrupt type from HOMER host data area. This will tell OCC - // which interrupt to Host it should be using. - uint32_t l_occ_int_type = 0; - l_homerrc = homer_hd_map_read_unmap(HOMER_INT_TYPE, - &l_occ_int_type, - &l_ssxrc); - - if ((HOMER_SUCCESS == l_homerrc) || (HOMER_SSX_UNMAP_ERR == l_homerrc)) + if(!G_ipl_time) { - G_occ_interrupt_type = (uint8_t) l_occ_int_type; - } - else - { - // if HOMER host data read fails, assume the FSP communication - // path as the default - G_occ_interrupt_type = FSP_SUPPORTED_OCC; - //G_occ_interrupt_type = PSIHB_INTERRUPT; - } + // Trace what happened before ssx initialization + MAIN_TRAC_INFO("HOMER accessed, rc=%d, version=%d, ssx_rc=%d", + l_homerrc, l_homer_version, l_ssxrc); - MAIN_TRAC_INFO("HOMER accessed, rc=%d, host interrupt type=%d, ssx_rc=%d", - l_homerrc, l_occ_int_type, l_ssxrc); + MAIN_TRAC_INFO("HOMER accessed, rc=%d, nest_freq=%d, ssx_rc=%d", + l_homerrc2, l_tb_freq_hz, l_ssxrc2); - // Handle any errors from the interrupt type access - homer_log_access_error(l_homerrc, - l_ssxrc, - l_occ_int_type); - - // Get the FIR Master indicator - uint32_t l_fir_master = FIR_OCC_NOT_FIR_MASTER; - l_homerrc = homer_hd_map_read_unmap(HOMER_FIR_MASTER, - &l_fir_master, - &l_ssxrc); + // Handle any errors from the version access + homer_log_access_error(l_homerrc, + l_ssxrc, + l_homer_version); + + // Handle any errors from the nest freq access + homer_log_access_error(l_homerrc2, + l_ssxrc2, + l_tb_freq_hz); + + // Time to access any initialization data needed from the HOMER (besides the + // nest frequency which was required above to enable SSX and tracing). + CHECKPOINT(HOMER_ACCESS_INITS); + + // Get OCC interrupt type from HOMER host data area. This will tell OCC + // which interrupt to Host it should be using. + uint32_t l_occ_int_type = 0; + l_homerrc = homer_hd_map_read_unmap(HOMER_INT_TYPE, + &l_occ_int_type, + &l_ssxrc); - if (((HOMER_SUCCESS == l_homerrc) || (HOMER_SSX_UNMAP_ERR == l_homerrc)) - && - (FIR_OCC_IS_FIR_MASTER == l_fir_master)) - { - OCC_SET_FIR_MASTER(FIR_OCC_IS_FIR_MASTER); - } - else - { - OCC_SET_FIR_MASTER(FIR_OCC_NOT_FIR_MASTER); - } + if ((HOMER_SUCCESS == l_homerrc) || (HOMER_SSX_UNMAP_ERR == l_homerrc)) + { + G_occ_interrupt_type = (uint8_t) l_occ_int_type; + } + else + { + // if HOMER host data read fails, assume the FSP communication + // path as the default + G_occ_interrupt_type = FSP_SUPPORTED_OCC; + //G_occ_interrupt_type = PSIHB_INTERRUPT; + } - TRAC_IMP("HOMER accessed, rc=%d, FIR master=%d, ssx_rc=%d", - l_homerrc, l_fir_master, l_ssxrc); + MAIN_TRAC_INFO("HOMER accessed, rc=%d, host interrupt type=%d, ssx_rc=%d", + l_homerrc, l_occ_int_type, l_ssxrc); - // Handle any errors from the FIR master access - homer_log_access_error(l_homerrc, - l_ssxrc, - l_fir_master); + // Handle any errors from the interrupt type access + homer_log_access_error(l_homerrc, + l_ssxrc, + l_occ_int_type); - // If this OCC is the FIR master read in the FIR collection parms - if (OCC_IS_FIR_MASTER()) - { - // Read the FIR parms buffer - l_homerrc = homer_hd_map_read_unmap(HOMER_FIR_PARMS, - &G_fir_data_parms[0], + // Get the FIR Master indicator + uint32_t l_fir_master = FIR_OCC_NOT_FIR_MASTER; + l_homerrc = homer_hd_map_read_unmap(HOMER_FIR_MASTER, + &l_fir_master, &l_ssxrc); - TRAC_IMP("HOMER accessed, rc=%d, FIR parms buffer 0x%x, ssx_rc=%d", - l_homerrc, &G_fir_data_parms[0], l_ssxrc); + if (((HOMER_SUCCESS == l_homerrc) || (HOMER_SSX_UNMAP_ERR == l_homerrc)) + && + (FIR_OCC_IS_FIR_MASTER == l_fir_master)) + { + OCC_SET_FIR_MASTER(FIR_OCC_IS_FIR_MASTER); + } + else + { + OCC_SET_FIR_MASTER(FIR_OCC_NOT_FIR_MASTER); + } + + TRAC_IMP("HOMER accessed, rc=%d, FIR master=%d, ssx_rc=%d", + l_homerrc, l_fir_master, l_ssxrc); // Handle any errors from the FIR master access homer_log_access_error(l_homerrc, l_ssxrc, - (uint32_t)&G_fir_data_parms[0]); + l_fir_master); + + // If this OCC is the FIR master read in the FIR collection parms + if (OCC_IS_FIR_MASTER()) + { + // Read the FIR parms buffer + l_homerrc = homer_hd_map_read_unmap(HOMER_FIR_PARMS, + &G_fir_data_parms[0], + &l_ssxrc); + + TRAC_IMP("HOMER accessed, rc=%d, FIR parms buffer 0x%x, ssx_rc=%d", + l_homerrc, &G_fir_data_parms[0], l_ssxrc); + + // Handle any errors from the FIR master access + homer_log_access_error(l_homerrc, + l_ssxrc, + (uint32_t)&G_fir_data_parms[0]); + } + }//G_ipl_time + else + { + // No access to HOMER. Set this occ as FIR master + TRAC_IMP("I am the FIR master"); + OCC_SET_FIR_MASTER(FIR_OCC_IS_FIR_MASTER); } //Set the fir_heap and fir_params pointer in the shared buffer |