diff options
author | Chris Cain <cjcain@us.ibm.com> | 2018-09-10 12:57:39 -0500 |
---|---|---|
committer | Christopher J. Cain <cjcain@us.ibm.com> | 2018-09-26 11:17:55 -0500 |
commit | b67db9d09b181dfe8bd0a77cfdca511d124b291e (patch) | |
tree | 58b9af1b2f45aea26706bf4533a2d2f0d05c8a92 | |
parent | 3e23a4ef97bc78aa8c8cf691407fdf9b8da30664 (diff) | |
download | talos-occ-b67db9d09b181dfe8bd0a77cfdca511d124b291e.tar.gz talos-occ-b67db9d09b181dfe8bd0a77cfdca511d124b291e.zip |
Support for NVDIMMs
Change-Id: I8ccf44287bc72a73b16662ba29b71e731c70b30e
RTC:173789
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/65917
Reviewed-by: Martha Broyles <mbroyles@us.ibm.com>
Reviewed-by: William A. Bryan <wilbryan@us.ibm.com>
Tested-by: Christopher J. Cain <cjcain@us.ibm.com>
Reviewed-by: Christopher J. Cain <cjcain@us.ibm.com>
-rw-r--r-- | src/common/apss_structs.h | 2 | ||||
-rw-r--r-- | src/common/dimm_structs.h | 5 | ||||
-rw-r--r-- | src/common/ipc_func_ids.h | 3 | ||||
-rw-r--r-- | src/occ_405/amec/amec_init.c | 38 | ||||
-rwxr-xr-x | src/occ_405/amec/amec_sensors_power.c | 521 | ||||
-rwxr-xr-x | src/occ_405/amec/amec_sensors_power.h | 10 | ||||
-rwxr-xr-x | src/occ_405/amec/amec_service_codes.h | 3 | ||||
-rwxr-xr-x | src/occ_405/amec/amec_slave_smh.c | 39 | ||||
-rwxr-xr-x | src/occ_405/amec/amec_tasks.c | 14 | ||||
-rwxr-xr-x | src/occ_405/cmdh/cmdh_dbug_cmd.c | 37 | ||||
-rwxr-xr-x | src/occ_405/cmdh/cmdh_dbug_cmd.h | 8 | ||||
-rwxr-xr-x | src/occ_405/cmdh/cmdh_fsp_cmds.c | 24 | ||||
-rw-r--r-- | src/occ_405/occ_service_codes.h | 2 | ||||
-rwxr-xr-x | src/occ_405/occbuildname.c | 2 | ||||
-rwxr-xr-x | src/occ_405/pss/apss.c | 19 | ||||
-rwxr-xr-x | src/occ_gpe1/gpe1_dimm.h | 5 | ||||
-rw-r--r-- | src/occ_gpe1/gpe1_dimm_control.c | 126 | ||||
-rw-r--r-- | src/occ_gpe1/gpe1_memory_power_control.c | 3 | ||||
-rw-r--r-- | src/occ_gpe1/ipc_func_tables.c | 5 |
19 files changed, 595 insertions, 271 deletions
diff --git a/src/common/apss_structs.h b/src/common/apss_structs.h index 416f27a..fd66b7e 100644 --- a/src/common/apss_structs.h +++ b/src/common/apss_structs.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ diff --git a/src/common/dimm_structs.h b/src/common/dimm_structs.h index 3302845..115bdbf 100644 --- a/src/common/dimm_structs.h +++ b/src/common/dimm_structs.h @@ -113,4 +113,9 @@ typedef struct perf_mon_counts_t idle_counts; } reset_mem_deadman_args_t; +typedef struct { + GpeErrorStruct error; + uint16_t configured_mbas; +} epow_gpio_args_t; + #endif // _DIMM_STRUCTS_H diff --git a/src/common/ipc_func_ids.h b/src/common/ipc_func_ids.h index df4d9ed..748a337 100644 --- a/src/common/ipc_func_ids.h +++ b/src/common/ipc_func_ids.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -78,6 +78,7 @@ IPC_FUNCIDS_TABLE_START IPC_FUNC_ID(IPC_ST_CENTAUR_SCOM_FUNCID) IPC_FUNC_ID(IPC_ST_CENTAUR_DATA_FUNCID) IPC_FUNC_ID(IPC_ST_CENTAUR_INIT_FUNCID) + IPC_FUNC_ID(IPC_ST_EPOW_GPIO_ASSERT_FUNCID) IPC_FUNCIDS_ST_END(OCCHW_INST_ID_GPE1) //Functions that are only supported by GPE2 should be defined here diff --git a/src/occ_405/amec/amec_init.c b/src/occ_405/amec/amec_init.c index 242c36f..75e9d4d 100644 --- a/src/occ_405/amec/amec_init.c +++ b/src/occ_405/amec/amec_init.c @@ -372,34 +372,34 @@ void amec_slave_init() // Initializes the GPE routine that will be used to measure the worst case // timings for GPE0 - rc = gpe_request_create(&G_gpe_nop_request[0], //gpe_req for the task - &G_async_gpe_queue0, //queue - IPC_ST_GPE0_NOP, //Function ID - NULL, //parm for the task - SSX_WAIT_FOREVER, //no timeout - (AsyncRequestCallback) - amec_slv_update_gpe_sensors, //callback - (void *) GPE_ENGINE_0, //callback argument - ASYNC_CALLBACK_IMMEDIATE ); //options + rc = gpe_request_create( &G_gpe_nop_request[0], //gpe_req for the task + &G_async_gpe_queue0, //GPE0 queue + IPC_ST_GPE0_NOP, //Function ID + NULL, //parm for the task + SSX_WAIT_FOREVER, //no timeout + (AsyncRequestCallback) + amec_slv_update_gpe_sensors, //callback + (void *) GPE_ENGINE_0, //callback argument + ASYNC_CALLBACK_IMMEDIATE ); //options // Initializes the GPE routine that will be used to measure the worst case // timings for GPE1 - rc2 = gpe_request_create( &G_gpe_nop_request[1], //gpe_req for the task - &G_async_gpe_queue1, //queue - IPC_ST_GPE1_NOP, //Function ID - NULL, //parm for the task - SSX_WAIT_FOREVER, //no timeout - (AsyncRequestCallback) - amec_slv_update_gpe_sensors, //callback - (void *) GPE_ENGINE_1, //callback argument - ASYNC_CALLBACK_IMMEDIATE ); //options + rc2 = gpe_request_create( &G_gpe_nop_request[1], //gpe_req for the task + &G_async_gpe_queue1, //GPE1 queue + IPC_ST_GPE1_NOP, //Function ID + NULL, //parm for the task + SSX_WAIT_FOREVER, //no timeout + (AsyncRequestCallback) + amec_slv_update_gpe_sensors, //callback + (void *) GPE_ENGINE_1, //callback argument + ASYNC_CALLBACK_IMMEDIATE ); //options // If we couldn't create the GpeRequest objects, there must be a major problem // so we will log an error and halt OCC. if( rc || rc2 ) { //If fail to create GpeRequest object then there is a problem. - TRAC_ERR("Failed to create GPE duration GpeRequest object[0x%x, 0x%x]", rc, rc2 ); + TRAC_ERR("Failed to create GPE duration GpeRequest object[0x%x, 0x%x]", rc, rc2); /* @ * @errortype diff --git a/src/occ_405/amec/amec_sensors_power.c b/src/occ_405/amec/amec_sensors_power.c index b9fd358..bf13cb4 100755 --- a/src/occ_405/amec/amec_sensors_power.c +++ b/src/occ_405/amec/amec_sensors_power.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -56,6 +56,12 @@ uint32_t G_lastValidAdcValue[MAX_APSS_ADC_CHANNELS] = {0}; // Indicates if we have determined GPU presence bool G_gpu_config_done = FALSE; +// GPE Request Structure used to communicate an EPOW GPIO event to GPE1 for NVDIMMs +GpeRequest G_epow_gpio_detected_req; +GPE_BUFFER(epow_gpio_args_t G_epow_gpio_parms); +bool G_epow_gpio_scheduled = FALSE; + + // Bitmap of GPUs present uint32_t G_first_proc_gpu_config = 0; uint32_t G_first_sys_gpu_config = 0; @@ -76,6 +82,9 @@ extern bool G_apss_present; extern OCCPstateParmBlock G_oppb; extern task_t G_task_table[TASK_END]; +extern uint16_t G_configured_mbas; +extern uint8_t G_injected_epow_asserted; + //*************************************************************************/ // Code //*************************************************************************/ @@ -192,241 +201,257 @@ uint32_t amec_value_from_apss_adc(uint8_t i_chan) // // Thread: RealTime Loop // +// Returns: FALSE if GPIO EPOW was asserted (sensors NOT updated) +// // End Function Specification -void amec_update_apss_sensors(void) +bool amec_update_apss_sensors(void) { - // Need to check to make sure APSS data has been received - // via slave inbox first - if (G_slv_inbox_received && - (G_pwr_reading_type == PWR_READING_TYPE_APSS) && - (0 == G_dcom_slv_inbox_doorbell_rx.apss_recovery_in_progress)) + bool l_sensors_updated = TRUE; + do { - uint8_t l_proc = G_pbax_id.chip_id; - uint32_t temp32 = 0; - uint8_t l_idx = 0; - uint32_t l_bulk_current_sum = 0; - - // ---------------------------------------------------- - // Convert all ADC Channels immediately - // ---------------------------------------------------- - for (l_idx = 0; l_idx < MAX_APSS_ADC_CHANNELS; l_idx++) + // Need to check to make sure APSS data has been received + // via slave inbox first + if (G_slv_inbox_received && + (G_pwr_reading_type == PWR_READING_TYPE_APSS) && + (0 == G_dcom_slv_inbox_doorbell_rx.apss_recovery_in_progress)) { - // These values returned are gain adjusted. The APSS readings for - // the remote ground and 12V sense are returned in mVs, all other - // readings are treated as mAs. - G_lastValidAdcValue[l_idx] = amec_value_from_apss_adc(l_idx); - - // Add up all channels now, we will subtract ones later that don't - // count towards the system power - l_bulk_current_sum += G_lastValidAdcValue[l_idx]; - } + uint8_t l_proc = G_pbax_id.chip_id; + uint32_t temp32 = 0; + uint8_t l_idx = 0; + uint32_t l_bulk_current_sum = 0; - // -------------------------------------------------------------- - // Convert 12Vsense into interim value - this has to happen first - // -------------------------------------------------------------- - // Calculations involving bulk_voltage must be 64bit so final result - // does not get truncated (before dividing by ADCMULT_TO_UNITS) - uint64_t l_bulk_voltage = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.sense_12v); + // Check GPIO_EPOW. Skip everything if asserted + if (epow_gpio_asserted()) + { + l_sensors_updated = FALSE; + break; + } - if (OCC_MASTER == G_occ_role) - { - // Update channel sensors for all channels (except 12v sense and gnd) + // ---------------------------------------------------- + // Convert all ADC Channels immediately + // ---------------------------------------------------- for (l_idx = 0; l_idx < MAX_APSS_ADC_CHANNELS; l_idx++) { - if(l_idx == G_sysConfigData.apss_adc_map.current_12v_stby) - { - // Save value of 12V Standby Current (.01A) in a sensor for lab use only - temp32 = ADC_CONVERTED_VALUE(l_idx)/100; // convert mA to .01A - sensor_update(AMECSENSOR_PTR(CUR12VSTBY), (uint16_t) temp32); - } - else if((l_idx != G_sysConfigData.apss_adc_map.sense_12v) && - (l_idx != G_sysConfigData.apss_adc_map.remote_gnd)) + // These values returned are gain adjusted. The APSS readings for + // the remote ground and 12V sense are returned in mVs, all other + // readings are treated as mAs. + G_lastValidAdcValue[l_idx] = amec_value_from_apss_adc(l_idx); + + // Add up all channels now, we will subtract ones later that don't + // count towards the system power + l_bulk_current_sum += G_lastValidAdcValue[l_idx]; + } + + // -------------------------------------------------------------- + // Convert 12Vsense into interim value - this has to happen first + // -------------------------------------------------------------- + // Calculations involving bulk_voltage must be 64bit so final result + // does not get truncated (before dividing by ADCMULT_TO_UNITS) + uint64_t l_bulk_voltage = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.sense_12v); + + if (OCC_MASTER == G_occ_role) + { + // Update channel sensors for all channels (except 12v sense and gnd) + for (l_idx = 0; l_idx < MAX_APSS_ADC_CHANNELS; l_idx++) { - temp32 = ((ADC_CONVERTED_VALUE(l_idx) * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; - sensor_update(AMECSENSOR_PTR(PWRAPSSCH0 + l_idx), (uint16_t) temp32); + if(l_idx == G_sysConfigData.apss_adc_map.current_12v_stby) + { + // Save value of 12V Standby Current (.01A) in a sensor for lab use only + temp32 = ADC_CONVERTED_VALUE(l_idx)/100; // convert mA to .01A + sensor_update(AMECSENSOR_PTR(CUR12VSTBY), (uint16_t) temp32); + } + else if((l_idx != G_sysConfigData.apss_adc_map.sense_12v) && + (l_idx != G_sysConfigData.apss_adc_map.remote_gnd)) + { + temp32 = ((ADC_CONVERTED_VALUE(l_idx) * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; + sensor_update(AMECSENSOR_PTR(PWRAPSSCH0 + l_idx), (uint16_t) temp32); + } } + + amec_update_apss_gpio(); } - amec_update_apss_gpio(); - } + // ---------------------------------------------------------- + // Convert Raw Vdd/Vcs/Vio/Vpcie Power from APSS into sensors + // ---------------------------------------------------------- + // Some sensor values are in Watts so after getting the mA readings we + // multiply by the bulk voltage (mVs) which requires us to then divide + // by 1000000 to get W (A.V), ie. + // divide by 1000 to get it back to milliUnits (0.001) + // divide by 10000 to get it to centiUnits (0.01) + // divide by 100000 to get it to deciUnits (0.1) + // divide by 1000000 to get it to Units (1) + + //Update channel specific sensors based on saved pairing between function Ids and Channels. + + // Make sure there is a channel for processor power else proc power sensor is using AVS bus and will + // be updated in update_avsbus_power_sensors() instead + if( (G_sysConfigData.apss_adc_map.vdd[l_proc] != SYSCFG_INVALID_ADC_CHAN) || + (G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_proc] != SYSCFG_INVALID_ADC_CHAN) ) + { + uint32_t l_vdd = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vdd[l_proc]); + uint32_t l_vcs_vio_vpcie = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_proc]); + temp32 = ((l_vcs_vio_vpcie + l_vdd) * l_bulk_voltage)/ADCMULT_TO_UNITS; + sensor_update(AMECSENSOR_PTR(PWRPROC), (uint16_t) temp32); + } - // ---------------------------------------------------------- - // Convert Raw Vdd/Vcs/Vio/Vpcie Power from APSS into sensors - // ---------------------------------------------------------- - // Some sensor values are in Watts so after getting the mA readings we - // multiply by the bulk voltage (mVs) which requires us to then divide - // by 1000000 to get W (A.V), ie. - // divide by 1000 to get it back to milliUnits (0.001) - // divide by 10000 to get it to centiUnits (0.01) - // divide by 100000 to get it to deciUnits (0.1) - // divide by 1000000 to get it to Units (1) - - //Update channel specific sensors based on saved pairing between function Ids and Channels. - - // Make sure there is a channel for processor power else proc power sensor is using AVS bus and will - // be updated in update_avsbus_power_sensors() instead - if( (G_sysConfigData.apss_adc_map.vdd[l_proc] != SYSCFG_INVALID_ADC_CHAN) || - (G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_proc] != SYSCFG_INVALID_ADC_CHAN) ) - { - uint32_t l_vdd = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vdd[l_proc]); - uint32_t l_vcs_vio_vpcie = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_proc]); - temp32 = ((l_vcs_vio_vpcie + l_vdd) * l_bulk_voltage)/ADCMULT_TO_UNITS; - sensor_update(AMECSENSOR_PTR(PWRPROC), (uint16_t) temp32); - } + // Save off the combined power from all modules + for (l_idx=0; l_idx < MAX_NUM_CHIP_MODULES; l_idx++) + { + uint32_t l_vd = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vdd[l_idx]); + uint32_t l_vpcie = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_idx]); + g_amec->proc_snr_pwr[l_idx] = ((l_vpcie + l_vd) * l_bulk_voltage)/ADCMULT_TO_UNITS; + } - // Save off the combined power from all modules - for (l_idx=0; l_idx < MAX_NUM_CHIP_MODULES; l_idx++) - { - uint32_t l_vd = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vdd[l_idx]); - uint32_t l_vpcie = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_idx]); - g_amec->proc_snr_pwr[l_idx] = ((l_vpcie + l_vd) * l_bulk_voltage)/ADCMULT_TO_UNITS; - } + // All readings from APSS come back as milliUnits, so if we want + // to convert one, we need to + // divide by 1 to get it back to milliUnits (0.001) + // divide by 10 to get it to centiUnits (0.01) + // divide by 100 to get it to deciUnits (0.1) + // divide by 1000 to get it to Units (1) + + // ---------------------------------------------------- + // Convert Other Raw Misc Power from APSS into sensors + // ---------------------------------------------------- + + // Fans: Add up all Fan channels + temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.fans[0]); + temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.fans[1]); + temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; + sensor_update( AMECSENSOR_PTR(PWRFAN), (uint16_t)temp32); + + // I/O: Add up all I/O channels + temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[0]); + temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[1]); + temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[2]); + temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; + sensor_update( AMECSENSOR_PTR(PWRIO), (uint16_t)temp32); + + // Memory: Add up all channels for the same processor. + temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc][0]); + temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc][1]); + temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc][2]); + temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc][3]); + //Only for FSP-LESS systems do we add in Centaur power because it is measured on its own A/D channel, but is part of memory power + if (FSP_SUPPORTED_OCC != G_occ_interrupt_type) + { + temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.mem_cache); + } + temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; + sensor_update( AMECSENSOR_PTR(PWRMEM), (uint16_t)temp32); - // All readings from APSS come back as milliUnits, so if we want - // to convert one, we need to - // divide by 1 to get it back to milliUnits (0.001) - // divide by 10 to get it to centiUnits (0.01) - // divide by 100 to get it to deciUnits (0.1) - // divide by 1000 to get it to Units (1) - - // ---------------------------------------------------- - // Convert Other Raw Misc Power from APSS into sensors - // ---------------------------------------------------- - - // Fans: Add up all Fan channels - temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.fans[0]); - temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.fans[1]); - temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; - sensor_update( AMECSENSOR_PTR(PWRFAN), (uint16_t)temp32); - - // I/O: Add up all I/O channels - temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[0]); - temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[1]); - temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[2]); - temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; - sensor_update( AMECSENSOR_PTR(PWRIO), (uint16_t)temp32); - - // Memory: Add up all channels for the same processor. - temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc][0]); - temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc][1]); - temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc][2]); - temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc][3]); - //Only for FSP-LESS systems do we add in Centaur power because it is measured on its own A/D channel, but is part of memory power - if (FSP_SUPPORTED_OCC != G_occ_interrupt_type) - { - temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.mem_cache); - } - temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; - sensor_update( AMECSENSOR_PTR(PWRMEM), (uint16_t)temp32); + // Save off the combined power from all memory + for (l_idx=0; l_idx < MAX_NUM_CHIP_MODULES; l_idx++) + { + uint32_t l_temp = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx][0]); + l_temp += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx][1]); + l_temp += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx][2]); + l_temp += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx][3]); + g_amec->mem_snr_pwr[l_idx] = ((l_temp * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; + } - // Save off the combined power from all memory - for (l_idx=0; l_idx < MAX_NUM_CHIP_MODULES; l_idx++) - { - uint32_t l_temp = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx][0]); - l_temp += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx][1]); - l_temp += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx][2]); - l_temp += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx][3]); - g_amec->mem_snr_pwr[l_idx] = ((l_temp * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; - } + // Storage/Media + temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.storage_media[0]); + temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.storage_media[1]); + temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; + sensor_update( AMECSENSOR_PTR(PWRSTORE), (uint16_t)temp32); - // Storage/Media - temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.storage_media[0]); - temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.storage_media[1]); - temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; - sensor_update( AMECSENSOR_PTR(PWRSTORE), (uint16_t)temp32); + // Save total GPU adapter for this proc + if (l_proc < MAX_GPU_DOMAINS) + { + temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.gpu[l_proc][0]); + temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.gpu[l_proc][1]); + temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.gpu[l_proc][2]); + temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; + sensor_update( AMECSENSOR_PTR(PWRGPU), (uint16_t)temp32); + } - // Save total GPU adapter for this proc - if (l_proc < MAX_GPU_DOMAINS) - { - temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.gpu[l_proc][0]); - temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.gpu[l_proc][1]); - temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.gpu[l_proc][2]); + // ---------------------------------------------------- + // Convert Raw Bulk Power from APSS into sensors + // ---------------------------------------------------- + // We don't get this adc channel in some systems, we have to add it manually. + // With valid sysconfig data the code here should automatically use what + // is provided by the APSS if it is available, or manually sum it up if not. + temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.total_current_12v); temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; - sensor_update( AMECSENSOR_PTR(PWRGPU), (uint16_t)temp32); - } - // ---------------------------------------------------- - // Convert Raw Bulk Power from APSS into sensors - // ---------------------------------------------------- - // We don't get this adc channel in some systems, we have to add it manually. - // With valid sysconfig data the code here should automatically use what - // is provided by the APSS if it is available, or manually sum it up if not. - temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.total_current_12v); - temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; - - // To calculated the total 12V current based on a sum of all ADC channels, - // Subract adc channels that don't measure power - l_bulk_current_sum -= ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.sense_12v); - l_bulk_current_sum -= ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.remote_gnd); - l_bulk_current_sum -= ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.current_12v_stby); - - // If we don't have a ADC channel that measures the bulk 12v power, use - // the ADC sum instead - if(0 == temp32) - { - temp32 = ((l_bulk_current_sum * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; - } - sensor_update(AMECSENSOR_PTR(PWRSYS), (uint16_t)temp32); + // To calculated the total 12V current based on a sum of all ADC channels, + // Subract adc channels that don't measure power + l_bulk_current_sum -= ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.sense_12v); + l_bulk_current_sum -= ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.remote_gnd); + l_bulk_current_sum -= ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.current_12v_stby); + + // If we don't have a ADC channel that measures the bulk 12v power, use + // the ADC sum instead + if(0 == temp32) + { + temp32 = ((l_bulk_current_sum * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; + } + sensor_update(AMECSENSOR_PTR(PWRSYS), (uint16_t)temp32); - // Calculate average frequency of all OCCs. - uint32_t l_allOccAvgFreqOver250us = 0; - uint8_t l_presentOCCs = 0; - uint8_t l_occCount = 0; + // Calculate average frequency of all OCCs. + uint32_t l_allOccAvgFreqOver250us = 0; + uint8_t l_presentOCCs = 0; + uint8_t l_occCount = 0; - // Add up the average freq from all OCCs. - for (l_occCount = 0; l_occCount < MAX_OCCS; l_occCount++) - { - if (G_sysConfigData.is_occ_present & (1<< l_occCount)) + // Add up the average freq from all OCCs. + for (l_occCount = 0; l_occCount < MAX_OCCS; l_occCount++) { - l_allOccAvgFreqOver250us += G_dcom_slv_outbox_rx[l_occCount].freqa; - l_presentOCCs++; + if (G_sysConfigData.is_occ_present & (1<< l_occCount)) + { + l_allOccAvgFreqOver250us += G_dcom_slv_outbox_rx[l_occCount].freqa; + l_presentOCCs++; + } } - } - //Calculate average of all the OCCs. - l_allOccAvgFreqOver250us /= l_presentOCCs; + //Calculate average of all the OCCs. + l_allOccAvgFreqOver250us /= l_presentOCCs; - // Save the max and min pwr sensors and keep an accumulator of the - // average frequency over 30 seconds. - if (g_pwr250us_over30sec.count == 0) - { - //The counter has been reset, therefore initialize the stored values. - g_pwr250us_over30sec.max = (uint16_t) temp32; - g_pwr250us_over30sec.min = (uint16_t) temp32; - g_pwr250us_over30sec.freqaAccum = l_allOccAvgFreqOver250us; - } - else - { - //Check for max. - if (temp32 > g_pwr250us_over30sec.max) + // Save the max and min pwr sensors and keep an accumulator of the + // average frequency over 30 seconds. + if (g_pwr250us_over30sec.count == 0) { + //The counter has been reset, therefore initialize the stored values. g_pwr250us_over30sec.max = (uint16_t) temp32; + g_pwr250us_over30sec.min = (uint16_t) temp32; + g_pwr250us_over30sec.freqaAccum = l_allOccAvgFreqOver250us; } - //Check for min. - if (temp32 < g_pwr250us_over30sec.min) + else { - g_pwr250us_over30sec.min = (uint16_t) temp32; + //Check for max. + if (temp32 > g_pwr250us_over30sec.max) + { + g_pwr250us_over30sec.max = (uint16_t) temp32; + } + //Check for min. + if (temp32 < g_pwr250us_over30sec.min) + { + g_pwr250us_over30sec.min = (uint16_t) temp32; + } + //Average frequency accumulator. + g_pwr250us_over30sec.freqaAccum += l_allOccAvgFreqOver250us; } - //Average frequency accumulator. - g_pwr250us_over30sec.freqaAccum += l_allOccAvgFreqOver250us; - } - //Count of number of updates. - g_pwr250us_over30sec.count++; + //Count of number of updates. + g_pwr250us_over30sec.count++; - // Check the GPU presence signals - amec_update_gpu_configuration(); + // Check the GPU presence signals + amec_update_gpu_configuration(); - // ---------------------------------------------------- - // Clear Flag to indicate that AMEC has received the data. - // ---------------------------------------------------- - G_slv_inbox_received = FALSE; - } - else - { - // Skip it...AMEC Health Monitor will figure out we didn't - // update this sensor. - } -} + // ---------------------------------------------------- + // Clear Flag to indicate that AMEC has received the data. + // ---------------------------------------------------- + G_slv_inbox_received = FALSE; + } + else + { + // Skip it...AMEC Health Monitor will figure out we didn't + // update this sensor. + } + } while( 0 ); + + return l_sensors_updated; + +} // end amec_update_apss_sensors() // Read the current from AVS Bus and update sensors @@ -908,6 +933,96 @@ void amec_update_gpu_configuration(void) } } } + +// Function Specification +// +// Name: epow_gpio_asserted +// +// Description: Check if the GPIO EPOW was asserted +// If asserted: +// Call GPE1 task to notify NVDIMMs to back up their data +// Create unrecoverable error (EPOW_ASSERTED) and request safe mode +// Return TRUE +// +// Thread: RealTime Loop +// +// End Function Specification +bool epow_gpio_asserted() +{ + bool l_epow_valid = FALSE; + uint8_t l_epow_value = 1; + bool l_epow_asserted = FALSE; + + // Get the value of GPIO_EPOW and make sure it is valid + l_epow_valid = apss_gpio_get(G_sysConfigData.apss_gpio_map.nvdimm_epow, + &l_epow_value); + + // DEBUG TRACE + static bool L_trace = TRUE; + if (G_injected_epow_asserted && L_trace) + { + TRAC_IMP("epow_gpio_asserted: G_injected_epow_asserted was set to true!"); + TRAC_IMP("epow_gpio_asserted: epow valid? %c, nvdimm epow: 0x%02X", + l_epow_valid?'y':'n', G_sysConfigData.apss_gpio_map.nvdimm_epow); + L_trace = false; + } + + // Signal is active-low + if (l_epow_valid && !l_epow_value) + { + TRAC_IMP("epow_gpio_asserted: GPIO EPOW Detected! Notifying GPE1"); + l_epow_asserted = TRUE; + // GPIO_EPOW was asserted create GpeRequest object to notify GPE1 + int l_rc = gpe_request_create(&G_epow_gpio_detected_req, // Task Request + &G_async_gpe_queue1, // GPE1 queue + IPC_ST_EPOW_GPIO_ASSERT_FUNCID, // Function ID + &G_epow_gpio_parms, // Task Parameters + SSX_WAIT_FOREVER, // No timeout + NULL, // No callback + NULL, // No callback parms + ASYNC_CALLBACK_IMMEDIATE); // Options + if (0 == l_rc) + { + // Need to send the configured MBA's bit field to GPE1 + G_epow_gpio_parms.configured_mbas = G_configured_mbas; + l_rc = gpe_request_schedule(&G_epow_gpio_detected_req); + if (0 == l_rc) + { + G_epow_gpio_scheduled = TRUE; + } + else + { + TRAC_ERR("epow_gpio_asserted: schedule failed w/rc=0x%08X", l_rc); + } + } + else + { + TRAC_ERR("epow_gpio_asserted: Failed to create epow_gpio_detected IPC task (rc=%d)", l_rc); + } + + // Create informational error and request safe mode since system is powering off + /* + * @errortype + * @moduleid AMEC_UPDATE_APSS_SENSORS + * @reasoncode EPOW_ASSERTED + * @userdata1 GPE IPC RC + * @userdata2 Configured MBAs + * @userdata4 OCC_NO_EXTENDED_RC + * @devdesc GPIO_EPOW was asserted + */ + errlHndl_t l_err = createErrl(AMEC_UPDATE_APSS_SENSORS, + EPOW_ASSERTED, + OCC_NO_EXTENDED_RC, + ERRL_SEV_INFORMATIONAL, + NULL, + DEFAULT_TRACE_SIZE, + l_rc, + G_configured_mbas); + REQUEST_SAFE_MODE( l_err ); + } + + return l_epow_asserted; +} /*----------------------------------------------------------------------------*/ /* End */ /*----------------------------------------------------------------------------*/ diff --git a/src/occ_405/amec/amec_sensors_power.h b/src/occ_405/amec/amec_sensors_power.h index 2cb55fb..1b52d33 100755 --- a/src/occ_405/amec/amec_sensors_power.h +++ b/src/occ_405/amec/amec_sensors_power.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -44,7 +44,8 @@ // Function that is called by AMEC State Machine that will update the AMEC // sensors for data that comes from the APSS (Power Data from APSS ADCs) -void amec_update_apss_sensors(void); +// Returns False if GPIO EPOW was asserted (sensors not updated) +bool amec_update_apss_sensors(void); // Function that is called by AMEC State Machine that will update the AMEC // sensors for GPIO data collected from the APSS. @@ -58,4 +59,9 @@ void amec_update_avsbus_sensors(void); // successfully determined void amec_update_gpu_configuration(void); +// Helper function called when updating the AMEC sensors for GPIO to detect +// GPIO_EPOW. If it has been asserted, we send an IPC command to GPE1 to +// perform some SCOMs allowing NVDIMMs to back up their data. +// Returns TRUE if EPOW was asserted. +bool epow_gpio_asserted(void); #endif // _AMEC_SENSORS_POWER_H diff --git a/src/occ_405/amec/amec_service_codes.h b/src/occ_405/amec/amec_service_codes.h index 8c87e5f..983b9bf 100755 --- a/src/occ_405/amec/amec_service_codes.h +++ b/src/occ_405/amec/amec_service_codes.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -69,6 +69,7 @@ enum occAmecModuleId AMEC_GPU_PCAP_MID = AMEC_COMP_ID | 0x19, AMEC_HEALTH_CHECK_VRM_VDD_TEMP = AMEC_COMP_ID | 0x1A, AMEC_HEALTH_CHECK_VRM_VDD_TIMEOUT = AMEC_COMP_ID | 0x1B, + AMEC_UPDATE_APSS_SENSORS = AMEC_COMP_ID | 0x1C, }; /*----------------------------------------------------------------------------*/ diff --git a/src/occ_405/amec/amec_slave_smh.c b/src/occ_405/amec/amec_slave_smh.c index d6fdcdf..1cfe3ea 100755 --- a/src/occ_405/amec/amec_slave_smh.c +++ b/src/occ_405/amec/amec_slave_smh.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -381,23 +381,21 @@ void amec_slv_update_main_mem_sensors(void) // End Function Specification void amec_slv_common_tasks_pre(void) { - AMEC_DBG("\tAMEC Slave Pre-State Common\n"); + AMEC_DBG("\tAMEC Slave Pre-State Common\n"); - // Update the FW Worst Case sensors every tick - amec_update_fw_sensors(); + // Update the FW Worst Case sensors every tick + amec_update_fw_sensors(); - // Update the sensors that come from the APSS every tick - amec_update_apss_sensors(); - - // Read the AVS Bus sensors (Vdd / Vdn) - amec_update_avsbus_sensors(); - - // Call the stream buffer recording function - // TODO: RTC 163683 - AMEC analytics - //amec_analytics_sb_recording(); + // Update the sensors that come from the APSS every tick + // If sensors were not updated due to EPOW event, skip remaining tasks + if (amec_update_apss_sensors()) + { + // Read the AVS Bus sensors (Vdd / Vdn) + amec_update_avsbus_sensors(); - // Over-subscription check - amec_oversub_check(); + // Over-subscription check + amec_oversub_check(); + } } // Function Specification @@ -575,13 +573,6 @@ void amec_slv_state_3(void) // Update Centaur sensors (for this tick) //------------------------------------------------------- amec_update_centaur_sensors(CENTAUR_3); - - //------------------------------------------------------- - // Perform amec_analytics (set amec_analytics_slot to 3) - //------------------------------------------------------- -/* TODO: RTC 163683 - AMEC analytics - amec_analytics_main(); -*/ } @@ -865,7 +856,7 @@ void amec_slv_substate_1_7(void) // // Description: even numbered slave substates // gives state 2 substate function to be called every 16th tick -// Time = 16 * MICS_PER_TICK +// Time = 16 * MICS_PER_TICK // odd substates of state 2 are not currently used // // End Function Specification @@ -1252,7 +1243,7 @@ void amec_slv_substate_5_7(void) // // Description: Called for every substate of state 6 // gives state 6 substate function to be called every 8th tick -// Time = 8 * MICS_PER_TICK +// Time = 8 * MICS_PER_TICK // // End Function Specification void amec_slv_substate_6_all(void) diff --git a/src/occ_405/amec/amec_tasks.c b/src/occ_405/amec/amec_tasks.c index 452532e..5aa604c 100755 --- a/src/occ_405/amec/amec_tasks.c +++ b/src/occ_405/amec/amec_tasks.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -270,12 +270,16 @@ void task_amec_slave( task_t *i_self) amec_slv_common_tasks_pre(); - amec_generic_smh( amec_slv_state_table, &G_amec_slv_state, &G_amec_slv_state_timings ); + if (FALSE == isSafeStateRequested()) + { + amec_generic_smh( amec_slv_state_table, &G_amec_slv_state, &G_amec_slv_state_timings ); + + amec_slv_common_tasks_post(); - amec_slv_common_tasks_post(); + // Set the total AMEC int task time for this tick, to the duration of the slave tasks. + G_fw_timing.ameint_dur = DURATION_IN_US_UNTIL_NOW_FROM(l_start); + } - // Set the total AMEC int task time for this tick, to the duration of the slave tasks. - G_fw_timing.ameint_dur = DURATION_IN_US_UNTIL_NOW_FROM(l_start); } /*----------------------------------------------------------------------------*/ diff --git a/src/occ_405/cmdh/cmdh_dbug_cmd.c b/src/occ_405/cmdh/cmdh_dbug_cmd.c index ac5aa91..6aa22b0 100755 --- a/src/occ_405/cmdh/cmdh_dbug_cmd.c +++ b/src/occ_405/cmdh/cmdh_dbug_cmd.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -51,6 +51,7 @@ // Externs //*************************************************************************/ extern uint64_t G_inject_dimm; +uint8_t G_injected_epow_asserted = 0; extern gpe_shared_data_t G_shared_gpe_data; //*************************************************************************/ @@ -634,9 +635,37 @@ void cmdh_dbug_allow_trace( const cmdh_fsp_cmd_t * i_cmd_ptr, } - // Function Specification // +// Name: cmdh_dbug_trigger_epow +// +// Description: Injects a fake epow event to trigger the EPOW asserted code path +// for debug purposes. It will be cleared after event is processed. +// +// End Function Specification +void cmdh_dbug_trigger_epow( void ) +{ + // Make sure gpio is valid + uint8_t l_epow_value = 1; + const bool l_epow_valid = apss_gpio_get(G_sysConfigData.apss_gpio_map.nvdimm_epow, &l_epow_value); + if (l_epow_valid) + { + G_injected_epow_asserted = 1; + TRAC_INFO("cmdh_dbug_trigger_epow: DEBUG - Injecting EPOW for NVDIMM testing"); + G_rsp_status = ERRL_RC_SUCCESS; + } + else + { + TRAC_ERR("cmdh_dbug_trigger_epow: Rejected because EPOW GPIO is not valid"); + G_rsp_status = ERRL_RC_INVALID_DATA; + } + + return; +} + + +/// Function Specification +// // Name: cmdh_dbug_dimm_inject // // Description: Set/Clear internal debug flags @@ -1119,6 +1148,10 @@ void cmdh_dbug_cmd (const cmdh_fsp_cmd_t * i_cmd_ptr, cmdh_dbug_internal_flags( i_cmd_ptr, o_rsp_ptr ); break; + case DBUG_TRIGGER_EPOW: // NVDIMM EPOW injection + cmdh_dbug_trigger_epow(); + break; + case DBUG_FLUSH_DCACHE: dcache_flush_all(); break; diff --git a/src/occ_405/cmdh/cmdh_dbug_cmd.h b/src/occ_405/cmdh/cmdh_dbug_cmd.h index 198ffe7..f1a5e51 100755 --- a/src/occ_405/cmdh/cmdh_dbug_cmd.h +++ b/src/occ_405/cmdh/cmdh_dbug_cmd.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -71,10 +71,10 @@ typedef enum // free = 0x0F, // free = 0x10, // free = 0x11, -// free = 0x12 + DBUG_TRIGGER_EPOW = 0x12, // free = 0x13 - DBUG_INJECT_ERRL = 0x14, - DBUG_DIMM_INJECT = 0x15, + DBUG_INJECT_ERRL = 0x14, + DBUG_DIMM_INJECT = 0x15, // free = 0x16 // free = 0x17, // free = 0x18, diff --git a/src/occ_405/cmdh/cmdh_fsp_cmds.c b/src/occ_405/cmdh/cmdh_fsp_cmds.c index 938af04..df7ae94 100755 --- a/src/occ_405/cmdh/cmdh_fsp_cmds.c +++ b/src/occ_405/cmdh/cmdh_fsp_cmds.c @@ -57,9 +57,12 @@ extern bool G_vrm_vdd_temp_expired; extern bool G_reset_prep; extern uint16_t G_amester_max_data_length; extern uint8_t G_occ_interrupt_type; +extern bool G_epow_gpio_scheduled; +extern GpeRequest G_epow_gpio_detected_req; extern opal_proc_voting_reason_t G_amec_opal_proc_throt_reason; + // This table contains tunable parameter information that can be exposed to // customers (only Master OCC should access/control this table) cmdh_tunable_param_table_t G_mst_tunable_parameter_table[CMDH_DEFAULT_TUNABLE_PARAM_NUM] = @@ -830,6 +833,27 @@ errlHndl_t cmdh_reset_prep (const cmdh_fsp_cmd_t * i_cmd_ptr, do { + if (G_epow_gpio_scheduled) + { + // Check to see if EPOW_GPIO IPC request is not idle. If not, sleep + // 4ms to give it time to finish and then continue. + if(!async_request_is_idle(&G_epow_gpio_detected_req.request)) + { + TRAC_IMP("cmdh_reset_prep: EPOW IPC request is NOT idle. Sleeping for 4ms"); + ssx_sleep(SSX_MILLISECONDS(4)); + if(!async_request_is_idle(&G_epow_gpio_detected_req.request)) + { + TRAC_ERR("cmdh_reset_prep: EPOW IPC request is still NOT idle. completion state=0x%08X", + G_epow_gpio_detected_req.request.completion_state); + } + } + else + { + TRAC_IMP("cmdh_reset_prep: EPOW IPC request IS idle. completion state=0x%08X", + G_epow_gpio_detected_req.request.completion_state); + } + } + // Command Length Check - make sure we at least have a version number if( CMDH_DATALEN_FIELD_UINT16(i_cmd_ptr) < CMDH_RESET_PREP_MIN_DATALEN) { diff --git a/src/occ_405/occ_service_codes.h b/src/occ_405/occ_service_codes.h index ee140d3..59e7ce9 100644 --- a/src/occ_405/occ_service_codes.h +++ b/src/occ_405/occ_service_codes.h @@ -61,6 +61,8 @@ enum occReasonCode VRM_VDD_ERROR_TEMP = 0x20, /// GPIO_VR_HOT_MEM_PROC signal from APSS asserted VR_HOT_MEM_PROC_ASSERTED = 0x23, + /// GPIO_EPOW signal from APSS asserted + EPOW_ASSERTED = 0x24, /// DIMM reached error threshold DIMM_ERROR_TEMP = 0x30, /// Frequency limited due to oversubscription condition diff --git a/src/occ_405/occbuildname.c b/src/occ_405/occbuildname.c index cbc30a6..757dfa5 100755 --- a/src/occ_405/occbuildname.c +++ b/src/occ_405/occbuildname.c @@ -34,6 +34,6 @@ volatile const char G_occ_buildname[16] __attribute__((section(".buildname"))) = #else -volatile const char G_occ_buildname[16] __attribute__((section(".buildname"))) = /*<BuildName>*/ "op_occ_180914a\0" /*</BuildName>*/ ; +volatile const char G_occ_buildname[16] __attribute__((section(".buildname"))) = /*<BuildName>*/ "op_occ_180926a\0" /*</BuildName>*/ ; #endif diff --git a/src/occ_405/pss/apss.c b/src/occ_405/pss/apss.c index 6c68a74..854e24b 100755 --- a/src/occ_405/pss/apss.c +++ b/src/occ_405/pss/apss.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -52,6 +52,8 @@ const apssModeConfigStruct_t G_apss_mode_config = { APSS_MODE_COMPOSITE, 16, 2 } // Power Measurements (read from APSS every RealTime loop) apssPwrMeasStruct_t G_apss_pwr_meas = { {0} }; + + GPE_BUFFER(initGpioArgs_t G_gpe_apss_initialize_gpio_args); GPE_BUFFER(setApssModeArgs_t G_gpe_apss_set_mode_args); @@ -90,6 +92,9 @@ volatile bool G_ApssPwrMeasCompleted = FALSE; // Used to tell slave inbox that pwr meas is complete but is invalid volatile bool G_ApssPwrMeasDoneInvalid = FALSE; +// Used for debug to simulate an EPOW assertion event +extern uint8_t G_injected_epow_asserted; + // Function Specification // // Name: dumpHexString @@ -668,6 +673,18 @@ void reformat_meas_data() memcpy(G_apss_pwr_meas.adc, &l_buffer[l_index], (G_apss_mode_config.numAdcChannelsToRead * 2)); l_index += (G_apss_mode_config.numAdcChannelsToRead * 2); memcpy(G_apss_pwr_meas.gpio, &l_buffer[l_index], (G_apss_mode_config.numGpioPortsToRead * 2)); + + //Check if injected EPOW has been asserted via debug command + if( G_injected_epow_asserted ) + { + uint8_t l_epow_port = G_sysConfigData.apss_gpio_map.nvdimm_epow / + NUM_OF_APSS_PINS_PER_GPIO_PORT; + uint8_t l_epow_mask = 0x1 << + (G_sysConfigData.apss_gpio_map.nvdimm_epow % + NUM_OF_APSS_PINS_PER_GPIO_PORT); + G_apss_pwr_meas.gpio[l_epow_port] &= (~l_epow_mask); + } + // TOD is always located at same offset memcpy(&G_apss_pwr_meas.tod, &l_buffer[l_continue_meas_length+l_complete_meas_length-8], 8); } diff --git a/src/occ_gpe1/gpe1_dimm.h b/src/occ_gpe1/gpe1_dimm.h index 3e413f6..301b47f 100755 --- a/src/occ_gpe1/gpe1_dimm.h +++ b/src/occ_gpe1/gpe1_dimm.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -26,6 +26,9 @@ #ifndef _GPE1_DIMM_H #define _GPE1_DIMM_H +#define NUM_MBAS_NIMBUS 2 +#define NUM_PORTS_PER_MBA 4 + #include "gpe_export.h" void dimm_set_ffdc(GpeErrorStruct *o_error, uint32_t i_addr, uint32_t i_rc, uint64_t i_ffdc); diff --git a/src/occ_gpe1/gpe1_dimm_control.c b/src/occ_gpe1/gpe1_dimm_control.c index 4ba1287..7a0a492 100644 --- a/src/occ_gpe1/gpe1_dimm_control.c +++ b/src/occ_gpe1/gpe1_dimm_control.c @@ -32,6 +32,128 @@ #include "dimm_structs.h" #include "mca_addresses.h" #include "gpe1.h" +#include "gpe1_dimm.h" + +/* + * Function Specifications: + * + * Name: gpe_scom_nvdimms_nimbus + * + * Description: Sends SCOMs to NVDIMMs to tell them to back up their data. + * Occurs when GPIO_EPOW is asserted. + * + * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct + * + * End Function Specification + */ +void gpe_scom_nvdimms_nimbus(ipc_msg_t* cmd, void* arg) +{ + int rc = 0; + int mc = 0; + int port = 0; + uint64_t mbarpc_regValue = 0; + uint64_t mbastr_regValue = 0; + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd; + + epow_gpio_args_t *args = (epow_gpio_args_t*)async_cmd->cmd_data; + + // Debug trace - Can remove + PK_TRACE("gpe_scom_nvdimms_nimbus: configured_mbas: 0x%04x", + args->configured_mbas ); + + // Iterate over each bit in configured_mbas + // If mc is configured, send scoms + uint16_t mask = 0x8000; + for (mc = 0; mc < NUM_MBAS_NIMBUS; mc++) + { + for (port = 0; port < NUM_PORTS_PER_MBA; port++) + { + if (args->configured_mbas & mask) + { + PK_TRACE("gpe_scom_nvdimms_nimbus: scoms for mc: %d, port: %d", mc, port); + + const uint32_t reg_MBARPC0Q = POWER_CTRL_REG0(mc,port); + // Step 1 - In MBARPC0Q, disable power domain control, set domain + // to MAXALL_MINALL(0b000), and enable minimum domain + // reduction + // bit 2 - power domain control, + // bits 3:5 - min/max domains + // bit 22 - domain reduction + rc = getscom_abs(reg_MBARPC0Q, &mbarpc_regValue); + if (rc) + { + PK_TRACE("E>gpe_scom_nvdimms_nimbus: Failed to read (MBARPC0Q) Reg:0x%08X, rc:0x%08x", + reg_MBARPC0Q, rc); + } + else + { + mbarpc_regValue &= 0xC3FFFFFFFFFFFFFF; // zero out bits 2-5 + mbarpc_regValue |= 0x0000020000000000; // set bit 22 + rc = putscom_abs(reg_MBARPC0Q, mbarpc_regValue); + if (rc) + { + PK_TRACE("E>gpe_scom_nvdimms_nimbus: Failed to disable power domain control (MBARPC0Q)" + " Reg:0x%08X, Data:0x%08X %08X, rc:0x%08x", + reg_MBARPC0Q, WORD_HIGH(mbarpc_regValue), WORD_LOW(mbarpc_regValue), rc); + gpe_set_ffdc(&(args->error), reg_MBARPC0Q, + GPE_RC_SCOM_PUT_FAILED, rc); + } + + // Step 2 - In MBASTR0Q, enable STR entry + // bit 0 - STR enable + const uint32_t reg_MBASTR0Q = STR_REG0(mc,port); + rc = getscom_abs(reg_MBASTR0Q, &mbastr_regValue); + if (rc) + { + PK_TRACE("E>gpe_scom_nvdimms_nimbus: Failed to read (MBASTR0Q) Reg:0x%08X, rc:0x%08x", + reg_MBASTR0Q, rc); + } + else + { + mbastr_regValue |= 0x8000000000000000; // set bit 0 + rc = putscom_abs(reg_MBASTR0Q, mbastr_regValue); + if (rc) + { + PK_TRACE("E>gpe_scom_nvdimms_nimbus: Failed to enable STR entry (MBASTR0Q)" + " Reg:0x%08X, Data:0x%08X %08X, rc:0x%08x", + reg_MBASTR0Q, WORD_HIGH(mbastr_regValue), WORD_LOW(mbastr_regValue), rc); + gpe_set_ffdc(&(args->error), reg_MBASTR0Q, + GPE_RC_SCOM_PUT_FAILED, rc); + } + } + + // Step 3 - In MBARPC0Q, re-enable power domain control + // bit 2 - power domain control + mbarpc_regValue |= 0x2000000000000000; // set bit 2 + rc = putscom_abs(reg_MBARPC0Q, mbarpc_regValue); + if (rc) + { + PK_TRACE(">gpe_scom_nvdimms_nimbus: Failed to re-enable power domain control (MBARPC0Q)" + " Reg:0x%08X, Data:0x%08X %08X, rc:0x%08x", + reg_MBARPC0Q, WORD_HIGH(mbarpc_regValue), WORD_LOW(mbarpc_regValue), rc); + gpe_set_ffdc(&(args->error), reg_MBARPC0Q, + GPE_RC_SCOM_PUT_FAILED, rc); + } + } + } + mask = mask >> 1; + } // for each MBA port + } // for each MC + + PK_TRACE("gpe_scom_nvdimms_nimbus: completed (rc=%d)", rc); + + // Always send back success + rc = ipc_send_rsp(cmd, IPC_RC_SUCCESS); + if(rc) + { + PK_TRACE("E>gpe_scom_nvdimms_nimbus: Failed to send response back (rc=%d)", rc); + gpe_set_ffdc(&(args->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc); + pk_halt(); + } + + PK_TRACE("gpe_scom_nvdimms_nimbus: exiting"); + +} // end gpe_scom_nvdimms_nimbus() /* * Function Specifications: @@ -121,7 +243,7 @@ void gpe_dimm_control(ipc_msg_t* cmd, void* arg) rc = ipc_send_rsp(cmd, IPC_RC_SUCCESS); if(rc) { - PK_TRACE("gpe_dimm_control: Failed to send response back. Halting GPE1", rc); + PK_TRACE("E>gpe_dimm_control: Failed to send response back. Halting GPE1 (rc=%d)", rc); gpe_set_ffdc(&(args->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc); pk_halt(); } @@ -307,7 +429,7 @@ void gpe_reset_mem_deadman(ipc_msg_t* cmd, void* arg) rc = ipc_send_rsp(cmd, IPC_RC_SUCCESS); if(rc) { - PK_TRACE("gpe_reset_mem_deadman: Failed to send response back. Halting GPE1", rc); + PK_TRACE("E>gpe_reset_mem_deadman: Failed to send response back. Halting GPE1 (rc=%d)", rc); gpe_set_ffdc(&(args->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc); pk_halt(); } diff --git a/src/occ_gpe1/gpe1_memory_power_control.c b/src/occ_gpe1/gpe1_memory_power_control.c index c9fe901..a988d48 100644 --- a/src/occ_gpe1/gpe1_memory_power_control.c +++ b/src/occ_gpe1/gpe1_memory_power_control.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -48,7 +48,6 @@ * * End Function Specification */ - void gpe_mem_power_control(ipc_msg_t* cmd, void* arg) { // Note: arg was set to 0 in ipc func table (ipc_func_tables.c), so don't use it. diff --git a/src/occ_gpe1/ipc_func_tables.c b/src/occ_gpe1/ipc_func_tables.c index 2ca2486..abc1575 100644 --- a/src/occ_gpe1/ipc_func_tables.c +++ b/src/occ_gpe1/ipc_func_tables.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -34,6 +34,7 @@ void gpe_reset_mem_deadman(ipc_msg_t* cmd, void* arg); void gpe_24x7(ipc_msg_t* cmd, void* arg); void gpe_mem_power_control(ipc_msg_t* cmd, void* arg); void gpe_gpu_init(ipc_msg_t* cmd, void* arg); +void gpe_scom_nvdimms_nimbus(ipc_msg_t* cmd, void* arg); #ifdef OCC_GPU_SUPPORT void gpe_gpu_sm(ipc_msg_t* cmd, void* arg); @@ -88,7 +89,7 @@ IPC_HANDLER(gpe_gpu_init, 0) // 7 - IPC_ST_GPE_GPU_INIT_FUNCID IPC_HANDLER(gpe_centaur_scom, 0) // 8 - IPC_ST_CENTAUR_SCOM_FUNCID IPC_HANDLER(gpe_centaur_data, 0) // 9 - IPC_ST_CENTAUR_DATA_FUNCID IPC_HANDLER(gpe_centaur_init, 0) // 10 -IPC_ST_CENTAUR_INIT_FUNCID -IPC_HANDLER_DEFAULT // 11 +IPC_HANDLER(gpe_scom_nvdimms_nimbus, 0) // 11 -IPC_ST_EPOW_GPIO_ASSERT_FUNCID IPC_HANDLER_DEFAULT // 12 IPC_HANDLER_DEFAULT // 13 IPC_HANDLER_DEFAULT // 14 |