summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Cain <cjcain@us.ibm.com>2018-09-10 12:57:39 -0500
committerChristopher J. Cain <cjcain@us.ibm.com>2018-09-26 11:17:55 -0500
commitb67db9d09b181dfe8bd0a77cfdca511d124b291e (patch)
tree58b9af1b2f45aea26706bf4533a2d2f0d05c8a92
parent3e23a4ef97bc78aa8c8cf691407fdf9b8da30664 (diff)
downloadtalos-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.h2
-rw-r--r--src/common/dimm_structs.h5
-rw-r--r--src/common/ipc_func_ids.h3
-rw-r--r--src/occ_405/amec/amec_init.c38
-rwxr-xr-xsrc/occ_405/amec/amec_sensors_power.c521
-rwxr-xr-xsrc/occ_405/amec/amec_sensors_power.h10
-rwxr-xr-xsrc/occ_405/amec/amec_service_codes.h3
-rwxr-xr-xsrc/occ_405/amec/amec_slave_smh.c39
-rwxr-xr-xsrc/occ_405/amec/amec_tasks.c14
-rwxr-xr-xsrc/occ_405/cmdh/cmdh_dbug_cmd.c37
-rwxr-xr-xsrc/occ_405/cmdh/cmdh_dbug_cmd.h8
-rwxr-xr-xsrc/occ_405/cmdh/cmdh_fsp_cmds.c24
-rw-r--r--src/occ_405/occ_service_codes.h2
-rwxr-xr-xsrc/occ_405/occbuildname.c2
-rwxr-xr-xsrc/occ_405/pss/apss.c19
-rwxr-xr-xsrc/occ_gpe1/gpe1_dimm.h5
-rw-r--r--src/occ_gpe1/gpe1_dimm_control.c126
-rw-r--r--src/occ_gpe1/gpe1_memory_power_control.c3
-rw-r--r--src/occ_gpe1/ipc_func_tables.c5
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
OpenPOWER on IntegriCloud