From 82156a8c51a11cf1173c5c4064cad903339b07ed Mon Sep 17 00:00:00 2001 From: mbroyles Date: Fri, 23 Jun 2017 20:13:06 -0500 Subject: Support new in-band command/response interface and clear sensor command Change-Id: Ic53e27d851023d99440aa1bfbdf5307920af3397 RTC: 158812 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/42512 Tested-by: FSP CI Jenkins Reviewed-by: Shawn M. McCarney Reviewed-by: Christopher J. Cain Reviewed-by: William A. Bryan --- src/occ_405/amec/amec_slave_smh.c | 71 +++- src/occ_405/amec/amec_slave_smh.h | 6 + src/occ_405/cmdh/cmdh_fsp_cmds.c | 342 ++++++++++++++++-- src/occ_405/cmdh/cmdh_fsp_cmds.h | 99 +++++- src/occ_405/homer.h | 9 + src/occ_405/occLinkInputFile | 1 + src/occ_405/occ_service_codes.h | 9 +- src/occ_405/occ_sys_config.c | 8 + src/occ_405/occ_sys_config.h | 1 + src/occ_405/occbuildname.c | 2 +- src/occ_405/proc/proc_pstate.c | 4 +- src/occ_405/sensor/sensor.h | 21 +- src/occ_405/sensor/sensor_inband_cmd.c | 557 ++++++++++++++++++++++++++++++ src/occ_405/sensor/sensor_inband_cmd.h | 112 ++++++ src/occ_405/sensor/sensor_main_memory.h | 1 - src/occ_405/sensor/sensor_service_codes.h | 6 + src/occ_405/topfiles.mk | 1 + 17 files changed, 1202 insertions(+), 48 deletions(-) create mode 100755 src/occ_405/sensor/sensor_inband_cmd.c create mode 100644 src/occ_405/sensor/sensor_inband_cmd.h (limited to 'src') diff --git a/src/occ_405/amec/amec_slave_smh.c b/src/occ_405/amec/amec_slave_smh.c index b37ab45..cb349f8 100755 --- a/src/occ_405/amec/amec_slave_smh.c +++ b/src/occ_405/amec/amec_slave_smh.c @@ -62,6 +62,7 @@ #include // For CURRENT_STATE(), OCC_STATE_* #include // For DATA_get_present_cnfgdata() #include // For main_mem_sensors_*() +#include // For inband_command_*() //*************************************************************************/ // Externs @@ -180,6 +181,25 @@ const smh_tbl_t amec_slv_state_5_substate_table[AMEC_SMH_STATES_PER_LVL] = {amec_slv_substate_5_7, NULL}, }; +// -------------------------------------------------------- +// AMEC Slave State 6 Substate Table +// -------------------------------------------------------- +// Each function inside this state table runs once every 16ms. +// +// No Substates +// +const smh_tbl_t amec_slv_state_6_substate_table[AMEC_SMH_STATES_PER_LVL] = +{ + {NULL, NULL}, // Substate 6.0 (not used) + {amec_slv_substate_6_1, NULL}, // Substate 6.1 + {NULL, NULL}, // Substate 6.2 (not used) + {amec_slv_substate_6_3, NULL}, // Substate 6.3 + {NULL, NULL}, // Substate 6.4 (not used) + {amec_slv_substate_6_5, NULL}, // Substate 6.5 + {NULL, NULL}, // Substate 6.6 (not used) + {amec_slv_substate_6_7, NULL}, // Substate 6.7 +}; + // -------------------------------------------------------- // AMEC Slave State 7 Substate Table // -------------------------------------------------------- @@ -213,12 +233,11 @@ const smh_tbl_t amec_slv_state_table[AMEC_SMH_STATES_PER_LVL] = {amec_slv_state_3, amec_slv_state_3_substate_table}, {amec_slv_state_4, NULL}, {amec_slv_state_5, amec_slv_state_5_substate_table}, - {amec_slv_state_6, NULL}, + {amec_slv_state_6, amec_slv_state_6_substate_table}, {amec_slv_state_7, amec_slv_state_7_substate_table}, }; - // This sets up the function pointer that will be called to update the // fw timings when the AMEC Slave State Machine finishes. smh_state_timing_t G_amec_slv_state_timings = {amec_slv_update_smh_sensors}; @@ -431,6 +450,7 @@ void amec_slv_common_tasks_post(void) // Call the 250us trace recording if it has been configured via Amester. // If not configured, this call will return immediately. amec_tb_record(AMEC_TB_250US); + } else L_active_1tick = TRUE; @@ -443,6 +463,16 @@ void amec_slv_common_tasks_post(void) G_amec_opal_proc_throt_reason = MANUFACTURING_OVERRIDE; ssx_semaphore_post(&G_dcomThreadWakeupSem); } + // Check if an inband command is being processed + if(G_inband_occ_cmd_state != INBAND_OCC_CMD_NONE) + { + // call inband command handler if in active, char or obs state + if ( (IS_OCC_STATE_ACTIVE() && L_active_1tick) || IS_OCC_STATE_OBSERVATION() || + IS_OCC_STATE_CHARACTERIZATION() ) + { + inband_command_handler(); + } + } } // Function Specification @@ -1227,6 +1257,43 @@ void amec_slv_substate_5_7(void) amec_update_proc_core_group(6); } +// Function Specification +// +// Name: amec_slv_substate_6_1 +// amec_slv_substate_6_3 +// amec_slv_substate_6_5 +// amec_slv_substate_6_7 +// +// Description: slave substate amec_slv_substate_6_1 +// slave substate amec_slv_substate_6_3 +// slave substate amec_slv_substate_6_5 +// slave substate amec_slv_substate_6_7 +// other substates of state 6 are not currently used +// +// End Function Specification +void amec_slv_substate_6_1(void) +{ + AMEC_DBG("\tAMEC Slave State 6.1\n"); + inband_command_check(); +} + +void amec_slv_substate_6_3(void) +{ + AMEC_DBG("\tAMEC Slave State 6.3\n"); + inband_command_check(); +} + +void amec_slv_substate_6_5(void) +{ + AMEC_DBG("\tAMEC Slave State 6.5\n"); + inband_command_check(); +} + +void amec_slv_substate_6_7(void) +{ + AMEC_DBG("\tAMEC Slave State 6.7\n"); + inband_command_check(); +} // Function Specification // diff --git a/src/occ_405/amec/amec_slave_smh.h b/src/occ_405/amec/amec_slave_smh.h index a10f419..6cca955 100755 --- a/src/occ_405/amec/amec_slave_smh.h +++ b/src/occ_405/amec/amec_slave_smh.h @@ -124,6 +124,12 @@ void amec_slv_substate_5_5(void); void amec_slv_substate_5_6(void); void amec_slv_substate_5_7(void); +// Slave SubState 6 (4 SubStates unused) check for inband cmd every 4ms +void amec_slv_substate_6_1(void); +void amec_slv_substate_6_3(void); +void amec_slv_substate_6_5(void); +void amec_slv_substate_6_7(void); + // Slave SubState 7 void amec_slv_substate_7_0(void); void amec_slv_substate_7_1(void); diff --git a/src/occ_405/cmdh/cmdh_fsp_cmds.c b/src/occ_405/cmdh/cmdh_fsp_cmds.c index c047d15..0933372 100755 --- a/src/occ_405/cmdh/cmdh_fsp_cmds.c +++ b/src/occ_405/cmdh/cmdh_fsp_cmds.c @@ -50,6 +50,7 @@ #include #include "cmdh_dbug_cmd.h" #include "wof.h" +#include "sensor_main_memory.h" extern dimm_sensor_flags_t G_dimm_temp_expired_bitmap; extern bool G_vrm_thermal_monitoring; @@ -1824,74 +1825,101 @@ errlHndl_t cmdh_tmgt_get_field_debug_data(const cmdh_fsp_cmd_t * i_cmd_ptr, // Function Specification // -// Name: cmdh_set_user_pcap +// Name: cmdh_set_user_pcap_common // -// Description: Implements the Set Use Power Cap command. +// Description: Implements the common part of Set Use Power Cap cmd from inband or out of band // // End Function Specification -errlHndl_t cmdh_set_user_pcap(const cmdh_fsp_cmd_t * i_cmd_ptr, - cmdh_fsp_rsp_t * o_rsp_ptr) +uint8_t cmdh_set_user_pcap_common(uint16_t i_pcap, + uint8_t i_source) { - errlHndl_t l_err = NULL; - ERRL_RC l_rc = ERRL_RC_SUCCESS; - - - G_rsp_status = ERRL_RC_SUCCESS; - o_rsp_ptr->data_length[0] = 0; - o_rsp_ptr->data_length[1] = 0; + uint8_t l_rc = ERRL_RC_SUCCESS; do { // Can't send this command to a slave if (OCC_SLAVE == G_occ_role) { + TRAC_ERR("From source %d User PCAP %d must be sent to master OCC", + i_source, i_pcap); l_rc = ERRL_RC_INVALID_CMD; break; } - if (CMDH_DATALEN_FIELD_UINT16(i_cmd_ptr) != CMDH_SET_USER_PCAP_DATALEN) - { - l_rc = ERRL_RC_INVALID_CMD_LEN; - break; - } - - uint16_t l_pcap = CONVERT_UINT8_ARRAY_UINT16(i_cmd_ptr->data[0], - i_cmd_ptr->data[1]); - //A value of 0 means this pcap has been deactivated, otherwise //make sure it's within the min & max. - if ((l_pcap != 0) && (l_pcap < G_master_pcap_data.soft_min_pcap)) + if ((i_pcap != 0) && (i_pcap < G_master_pcap_data.soft_min_pcap)) { - TRAC_ERR("User PCAP %d is below the minimum allowed (%d)", - l_pcap, G_master_pcap_data.soft_min_pcap); + TRAC_ERR("From source %d User PCAP %d is below the minimum allowed (%d)", + i_source, i_pcap, G_master_pcap_data.soft_min_pcap); l_rc = ERRL_RC_INVALID_DATA; break; } - else if ((l_pcap > G_master_pcap_data.system_pcap) && + else if ((i_pcap > G_master_pcap_data.system_pcap) && (G_master_pcap_data.system_pcap != 0)) { - TRAC_ERR("User PCAP %d is above the maximum allowed (%d)", - l_pcap, G_master_pcap_data.system_pcap); + TRAC_ERR("From source %d User PCAP %d is above the maximum allowed (%d)", + i_source, i_pcap, G_master_pcap_data.system_pcap); l_rc = ERRL_RC_INVALID_DATA; break; } else { - G_master_pcap_data.current_pcap = l_pcap; + G_master_pcap_data.current_pcap = i_pcap; //Indicate there is new PCAP data available G_master_pcap_data.pcap_data_count++; - - G_master_pcap_data.source = OUT_OF_BAND; // BMC/(H)TMGT + // if user pcap was just disabled set source to 0 (no user pcap) + if(i_pcap == 0) + { + G_master_pcap_data.source = 0; + } + else + { + G_master_pcap_data.source = i_source; + } } - TRAC_INFO("User selected power limit = %d", - G_master_pcap_data.current_pcap); + TRAC_INFO("User selected power limit = %d set from source %d", + G_master_pcap_data.current_pcap, i_source); } while (0); + return l_rc; +} + +// Function Specification +// +// Name: cmdh_set_user_pcap +// +// Description: Implements the Set Use Power Cap command from out of band interface +// +// End Function Specification +errlHndl_t cmdh_set_user_pcap(const cmdh_fsp_cmd_t * i_cmd_ptr, + cmdh_fsp_rsp_t * o_rsp_ptr) +{ + errlHndl_t l_err = NULL; + ERRL_RC l_rc = ERRL_RC_SUCCESS; + + + G_rsp_status = ERRL_RC_SUCCESS; + o_rsp_ptr->data_length[0] = 0; + o_rsp_ptr->data_length[1] = 0; + + if (CMDH_DATALEN_FIELD_UINT16(i_cmd_ptr) != CMDH_SET_USER_PCAP_DATALEN) + { + TRAC_ERR("cmdh_set_user_pcap: Invalid command length %u, expected %u ", + CMDH_DATALEN_FIELD_UINT16(i_cmd_ptr), CMDH_SET_USER_PCAP_DATALEN); + l_rc = ERRL_RC_INVALID_CMD_LEN; + } + else + { + uint16_t l_pcap = CONVERT_UINT8_ARRAY_UINT16(i_cmd_ptr->data[0], + i_cmd_ptr->data[1]); + l_rc = cmdh_set_user_pcap_common(l_pcap, OUT_OF_BAND); + } if (ERRL_RC_SUCCESS != l_rc) { @@ -1901,3 +1929,255 @@ errlHndl_t cmdh_set_user_pcap(const cmdh_fsp_cmd_t * i_cmd_ptr, return l_err; } + +// Function Specification +// +// Name: cmdh_clear_sensor_data +// +// Description: Implements the Clear sensor data command +// +// End Function Specification +uint8_t cmdh_clear_sensor_data(const uint16_t i_cmd_data_length, + const uint8_t* i_cmd_data_ptr, + const uint16_t i_max_rsp_data_length, + uint16_t* o_rsp_data_length, + uint8_t* o_rsp_data_ptr) +{ + uint8_t l_rc = ERRL_RC_SUCCESS; + cmdh_clear_sensor_cmd_data_t *l_cmd_ptr = (cmdh_clear_sensor_cmd_data_t *) i_cmd_data_ptr; + cmdh_clear_sensor_rsp_data_t *l_rsp_ptr = (cmdh_clear_sensor_rsp_data_t*) o_rsp_data_ptr; + *o_rsp_data_length = 0; + + do + { + // Command Length Check + if( i_cmd_data_length != sizeof(cmdh_clear_sensor_cmd_data_t) ) + { + TRAC_ERR("cmdh_clear_sensor_data: Invalid command length %u, expected %u ", + i_cmd_data_length, sizeof(cmdh_clear_sensor_cmd_data_t)); + l_rc = ERRL_RC_INVALID_CMD_LEN; + break; + } + // Make sure there is enough room in response buffer + if( sizeof(cmdh_clear_sensor_rsp_data_t) > i_max_rsp_data_length ) + { + TRAC_ERR("cmdh_clear_sensor_data: Response size %u is larger than buffer size %u ", + sizeof(cmdh_clear_sensor_rsp_data_t), i_max_rsp_data_length); + l_rc = ERRL_RC_INTERNAL_FAIL; + break; + } + // Check that the owner(s) to clear sensors for are valid + if( (l_cmd_ptr->sensor_owner_id & ~(VALID_CLEAR_SENSOR_OWNER_MASK) ) || + (l_cmd_ptr->sensor_owner_id == 0) ) + { + TRAC_ERR("cmdh_clear_sensor_data: Invalid sensor owners = 0x%02X", + l_cmd_ptr->sensor_owner_id); + l_rc = ERRL_RC_INVALID_DATA; + break; + } + + // clear min/max fields of all sensors for the given owner(s) + sensor_t *l_sensor_ptr = NULL; + uint16_t i = 0; + for( i = 0;i < G_amec_sensor_count; i++) + { + l_sensor_ptr = getSensorByGsid(i); + sensor_clear_minmax(l_sensor_ptr, l_cmd_ptr->sensor_owner_id); + } + + // copy the owner_id to the response buffer and set the rsp length + l_rsp_ptr->sensor_owner_id = l_cmd_ptr->sensor_owner_id; + *o_rsp_data_length = (uint16_t) sizeof(cmdh_clear_sensor_rsp_data_t); + TRAC_INFO("cmdh_clear_sensor_data: Sensor min/max cleared for owners = 0x%02X", + l_rsp_ptr->sensor_owner_id); + } while (0); + + return l_rc; +} + +// Function Specification +// +// Name: cmdh_set_pcap_inband +// +// Description: Implements setting a power cap from the inband interface +// +// End Function Specification +uint8_t cmdh_set_pcap_inband(const uint16_t i_cmd_data_length, + const uint8_t* i_cmd_data_ptr, + const uint16_t i_max_rsp_data_length, + uint16_t* o_rsp_data_length, + uint8_t* o_rsp_data_ptr) +{ + uint8_t l_rc = ERRL_RC_SUCCESS; + cmdh_set_inband_pcap_cmd_data_t *l_cmd_ptr = (cmdh_set_inband_pcap_cmd_data_t *) i_cmd_data_ptr; + cmdh_set_inband_pcap_rsp_data_t *l_rsp_ptr = (cmdh_set_inband_pcap_rsp_data_t*) o_rsp_data_ptr; + *o_rsp_data_length = 0; + + do + { + // Command Length Check + if( i_cmd_data_length != sizeof(cmdh_set_inband_pcap_cmd_data_t) ) + { + TRAC_ERR("cmdh_set_pcap_inband: Invalid command length %u, expected %u ", + i_cmd_data_length, sizeof(cmdh_set_inband_pcap_cmd_data_t)); + l_rc = ERRL_RC_INVALID_CMD_LEN; + break; + } + + // Make sure there is enough room in response buffer + if( sizeof(cmdh_set_inband_pcap_rsp_data_t) > i_max_rsp_data_length ) + { + TRAC_ERR("cmdh_set_pcap_inband: Response size %u is larger than buffer size %u ", + sizeof(cmdh_set_inband_pcap_rsp_data_t), i_max_rsp_data_length); + l_rc = ERRL_RC_INTERNAL_FAIL; + break; + } + + uint16_t l_pcap = CONVERT_UINT8_ARRAY_UINT16(l_cmd_ptr->power_cap[0], + l_cmd_ptr->power_cap[1]); + l_rc = cmdh_set_user_pcap_common(l_pcap, IN_BAND); + + // if successful copy the power cap to the response buffer and set the rsp length + if(l_rc == ERRL_RC_SUCCESS) + { + l_rsp_ptr->power_cap[0] = l_cmd_ptr->power_cap[0]; + l_rsp_ptr->power_cap[1] = l_cmd_ptr->power_cap[1]; + *o_rsp_data_length = (uint16_t) sizeof(cmdh_set_inband_pcap_rsp_data_t); + } + } while (0); + + return l_rc; +} + +// Function Specification +// +// Name: cmdh_write_psr +// +// Description: Implements the Write Power Shifting Ratio command +// +// End Function Specification +uint8_t cmdh_write_psr(const uint16_t i_cmd_data_length, + const uint8_t* i_cmd_data_ptr, + const uint16_t i_max_rsp_data_length, + uint16_t* o_rsp_data_length, + uint8_t* o_rsp_data_ptr) +{ + uint8_t l_rc = ERRL_RC_SUCCESS; + cmdh_write_psr_cmd_data_t *l_cmd_ptr = (cmdh_write_psr_cmd_data_t *) i_cmd_data_ptr; + cmdh_write_psr_rsp_data_t *l_rsp_ptr = (cmdh_write_psr_rsp_data_t*) o_rsp_data_ptr; + *o_rsp_data_length = 0; + + do + { + // Command Length Check + if( i_cmd_data_length != sizeof(cmdh_write_psr_cmd_data_t) ) + { + TRAC_ERR("cmdh_write_psr: Invalid command length %u, expected %u ", + i_cmd_data_length, sizeof(cmdh_write_psr_cmd_data_t)); + l_rc = ERRL_RC_INVALID_CMD_LEN; + break; + } + // Make sure there is enough room in response buffer + if( sizeof(cmdh_write_psr_rsp_data_t) > i_max_rsp_data_length ) + { + TRAC_ERR("cmdh_write_psr: Response size %u is larger than buffer size %u ", + sizeof(cmdh_write_psr_rsp_data_t), i_max_rsp_data_length); + l_rc = ERRL_RC_INTERNAL_FAIL; + break; + } + // Verify PSR is within range 0-100% + if(l_cmd_ptr->psr > 100) + { + TRAC_ERR("cmdh_write_psr: Invalid PSR %u", + l_cmd_ptr->psr); + l_rc = ERRL_RC_INVALID_DATA; + break; + } + + // PSR is valid + TRAC_INFO("cmdh_write_psr: PSR changed from %u to %u", G_sysConfigData.psr, l_cmd_ptr->psr); + G_sysConfigData.psr = l_cmd_ptr->psr; + + // copy the PSR to the response buffer and set the rsp length + l_rsp_ptr->psr = l_cmd_ptr->psr; + *o_rsp_data_length = (uint16_t) sizeof(cmdh_write_psr_rsp_data_t); + } while (0); + + return l_rc; +} + +// Function Specification +// +// Name: cmdh_select_sensor_groups +// +// Description: Implements the Select sensor Groups command to select +// sensor types that will be copied to main memory +// +// End Function Specification +uint8_t cmdh_select_sensor_groups(const uint16_t i_cmd_data_length, + const uint8_t* i_cmd_data_ptr, + const uint16_t i_max_rsp_data_length, + uint16_t* o_rsp_data_length, + uint8_t* o_rsp_data_ptr) +{ + uint8_t l_rc = ERRL_RC_SUCCESS; + uint16_t l_sensor_groups = 0; + cmdh_select_sensor_groups_cmd_data_t *l_cmd_ptr = (cmdh_select_sensor_groups_cmd_data_t *) i_cmd_data_ptr; + cmdh_select_sensor_groups_rsp_data_t *l_rsp_ptr = (cmdh_select_sensor_groups_rsp_data_t*) o_rsp_data_ptr; + *o_rsp_data_length = 0; + do + { + // Command Length Check + if( i_cmd_data_length != sizeof(cmdh_select_sensor_groups_cmd_data_t) ) + { + TRAC_ERR("cmdh_select_sensor_groups: Invalid command length %u, expected %u ", + i_cmd_data_length, sizeof(cmdh_select_sensor_groups_cmd_data_t)); + l_rc = ERRL_RC_INVALID_CMD_LEN; + break; + } + // Make sure there is enough room in response buffer + if( sizeof(cmdh_select_sensor_groups_rsp_data_t) > i_max_rsp_data_length ) + { + TRAC_ERR("cmdh_select_sensor_groups: Response size %u is larger than buffer size %u ", + sizeof(cmdh_select_sensor_groups_rsp_data_t), i_max_rsp_data_length); + l_rc = ERRL_RC_INTERNAL_FAIL; + break; + } + // Check that the sensor group(s) to select are valid + // 0 is valid and means not to copy any sensors to main memory + l_sensor_groups = CONVERT_UINT8_ARRAY_UINT16(l_cmd_ptr->sensor_groups[0], + l_cmd_ptr->sensor_groups[1]); + if(l_sensor_groups & ~(VALID_SET_SENSOR_GROUPS_MASK)) + { + TRAC_ERR("cmdh_select_sensor_groups: Invalid sensor groups = 0x%04X", + l_sensor_groups); + l_rc = ERRL_RC_INVALID_DATA; + break; + } + + // Loop thru 16 bits to check all possible sensor types + uint8_t l_bit = 0; + uint16_t l_sensor_type = 0; + bool l_enabled = false; + for(l_bit = 0; l_bit < 16; l_bit++) + { + l_sensor_type = 0x0001 << l_bit; + // only set eanbled for sensor types that are valid + if( l_sensor_type & (VALID_SET_SENSOR_GROUPS_MASK) ) + { + // type is valid now set enabled based on sensor groups selected + l_enabled = (l_sensor_groups & l_sensor_type) ? true : false; + main_mem_sensors_set_enabled(l_sensor_type, l_enabled); + } + } + + // copy the sensor groups to the response buffer and set the rsp length + l_rsp_ptr->sensor_groups[0] = l_cmd_ptr->sensor_groups[0]; + l_rsp_ptr->sensor_groups[1] = l_cmd_ptr->sensor_groups[1]; + *o_rsp_data_length = (uint16_t) sizeof(cmdh_select_sensor_groups_rsp_data_t); + TRAC_INFO("cmdh_select_sensor_groups: Sensor groups 0x%04X selected", + l_sensor_groups); + } while (0); + + return l_rc; +} diff --git a/src/occ_405/cmdh/cmdh_fsp_cmds.h b/src/occ_405/cmdh/cmdh_fsp_cmds.h index 7e63f92..254c42a 100755 --- a/src/occ_405/cmdh/cmdh_fsp_cmds.h +++ b/src/occ_405/cmdh/cmdh_fsp_cmds.h @@ -34,13 +34,11 @@ #include "occ_common.h" #include "state.h" #include "cmdh_fsp.h" -//#include "gpsm.h" -//#include "pstates.h" #include "cmdh_fsp_cmds_datacnfg.h" #include "sensor.h" #include "apss.h" -// Enum of the various commands that TMGT may send to OCC +// Enum of the various commands that may be sent to OCC typedef enum { CMDH_POLL = 0x00, @@ -56,6 +54,10 @@ typedef enum CMDH_GET_FIELD_DEBUG_DATA = 0x42, CMDH_MFG_TEST_CMD = 0x53, CMDH_TUNABLE_PARMS = 0x60, + CMDH_CLEAR_SENSOR_DATA = 0xD0, + CMDH_SET_PCAP_INBAND = 0xD1, + CMDH_WRITE_PSR = 0xD2, + CMDH_SELECT_SENSOR_GROUPS = 0xD3, } eCmdhCommands; #define SENSOR_TEMP "TEMP" @@ -64,7 +66,7 @@ typedef enum #define SENSOR_CAPS "CAPS" #define SENSOR_EXTN "EXTN" #define EXTN_NAME_FMIN 0x464D494E // "FMIN" -#define EXTN_NAME_FNOM 0x464E4F00 // "FNOM" +#define EXTN_NAME_FNOM 0x464E4F4D // "FNOM" #define EXTN_NAME_FTURBO 0x46540000 // "FT" #define EXTN_NAME_FUTURBO 0x46555400 // "FUT" @@ -605,6 +607,65 @@ extern cmdh_tunable_param_table_t G_mst_tunable_parameter_table[CMDH_DEFAULT_TUN #define CMDH_SET_USER_PCAP_DATALEN 2 +//--------------------------------------------------------- +// Clear Sensor Data Command +//--------------------------------------------------------- + +typedef struct __attribute__ ((packed)) +{ + uint8_t sensor_owner_id; + uint8_t reserved[3]; +}cmdh_clear_sensor_cmd_data_t; + +typedef struct __attribute__ ((packed)) +{ + uint8_t sensor_owner_id; + uint8_t reserved[3]; +}cmdh_clear_sensor_rsp_data_t; + +//--------------------------------------------------------- +// Set Power Cap In-band Command +//--------------------------------------------------------- + +typedef struct __attribute__ ((packed)) +{ + uint8_t power_cap[2]; +}cmdh_set_inband_pcap_cmd_data_t; + +typedef struct __attribute__ ((packed)) +{ + uint8_t power_cap[2]; +}cmdh_set_inband_pcap_rsp_data_t; + +//--------------------------------------------------------- +// Write Power Shifting Ratio Command +//--------------------------------------------------------- + +typedef struct __attribute__ ((packed)) +{ + uint8_t psr; +}cmdh_write_psr_cmd_data_t; + +typedef struct __attribute__ ((packed)) +{ + uint8_t psr; +}cmdh_write_psr_rsp_data_t; + +//--------------------------------------------------------- +// Select Sensor Groups Command +//--------------------------------------------------------- + +typedef struct __attribute__ ((packed)) +{ + uint8_t sensor_groups[2]; +}cmdh_select_sensor_groups_cmd_data_t; + +typedef struct __attribute__ ((packed)) +{ + uint8_t sensor_groups[2]; +}cmdh_select_sensor_groups_rsp_data_t; + + errlHndl_t cmdh_tmgt_setmodestate(const cmdh_fsp_cmd_t * i_cmd_ptr, cmdh_fsp_rsp_t * i_rsp_ptr); @@ -629,5 +690,35 @@ errlHndl_t cmdh_tmgt_get_field_debug_data(const cmdh_fsp_cmd_t * i_cmd_ptr, errlHndl_t cmdh_set_user_pcap(const cmdh_fsp_cmd_t * i_cmd_ptr, cmdh_fsp_rsp_t * o_rsp_ptr); + +//------------------------------------------------------------------------------------ +// Commands supported via in-band interface must have additional inputs/output/return +// Any out of band commands that are to be supported in-band should change to this +// common format to allow calling by either i.e. AMESTER pass thru is supported on both +//------------------------------------------------------------------------------------ +uint8_t cmdh_clear_sensor_data(const uint16_t i_cmd_data_length, + const uint8_t* i_cmd_data_ptr, + const uint16_t i_max_rsp_data_length, + uint16_t* o_rsp_data_length, + uint8_t* o_rsp_data_ptr); + +uint8_t cmdh_set_pcap_inband(const uint16_t i_cmd_data_length, + const uint8_t* i_cmd_data_ptr, + const uint16_t i_max_rsp_data_length, + uint16_t* o_rsp_data_length, + uint8_t* o_rsp_data_ptr); + +uint8_t cmdh_write_psr(const uint16_t i_cmd_data_length, + const uint8_t* i_cmd_data_ptr, + const uint16_t i_max_rsp_data_length, + uint16_t* o_rsp_data_length, + uint8_t* o_rsp_data_ptr); + +uint8_t cmdh_select_sensor_groups(const uint16_t i_cmd_data_length, + const uint8_t* i_cmd_data_ptr, + const uint16_t i_max_rsp_data_length, + uint16_t* o_rsp_data_length, + uint8_t* o_rsp_data_ptr); + #endif diff --git a/src/occ_405/homer.h b/src/occ_405/homer.h index b634701..4f2061e 100755 --- a/src/occ_405/homer.h +++ b/src/occ_405/homer.h @@ -46,6 +46,15 @@ #define OPAL_STATIC_ADDRESS_HOMER OPAL_ADDRESS_HOMER // OPAL's Static Address #define OPAL_DYNAMIC_ADDRESS_HOMER (OPAL_ADDRESS_HOMER+OPAL_DYNAMIC_OFFSET) // OPAL's Dynamic Address + +// Inband OCC command buffer offset in HOMER from the start of OPAL data +#define INBAND_OCC_CMD_OFFSET_HOMER 0x00000C00 +#define INBAND_OCC_CMD_ADDRESS_HOMER (OPAL_ADDRESS_HOMER+INBAND_OCC_CMD_OFFSET_HOMER) + +// Inband OCC response buffer offset in HOMER from the start of OPAL data +#define INBAND_OCC_RSP_OFFSET_HOMER 0x00001C00 +#define INBAND_OCC_RSP_ADDRESS_HOMER (OPAL_ADDRESS_HOMER+INBAND_OCC_RSP_OFFSET_HOMER) + // OCC/HTMGT command buffer offset in HOMER #define OCC_HTMGT_CMD_OFFSET_HOMER 0x000E0000 #define OCC_HTMGT_CMD_ADDRESS_HOMER (HOMER_BASE_ADDRESS+OCC_HTMGT_CMD_OFFSET_HOMER) diff --git a/src/occ_405/occLinkInputFile b/src/occ_405/occLinkInputFile index 0ee9eca..378fe57 100644 --- a/src/occ_405/occLinkInputFile +++ b/src/occ_405/occLinkInputFile @@ -80,6 +80,7 @@ INPUT ( amec_amester.o rtls_tables.o rtls.o scom.o + sensor_inband_cmd.o sensor_info.o sensor_main_memory.o sensor_query_list.o diff --git a/src/occ_405/occ_service_codes.h b/src/occ_405/occ_service_codes.h index a39d31a..2b066df 100644 --- a/src/occ_405/occ_service_codes.h +++ b/src/occ_405/occ_service_codes.h @@ -135,8 +135,14 @@ enum occReasonCode INVALID_FREQUENCY = 0xDE, WOF_RE_ENABLED = 0xDF, +// NOTE: 0xE0 - 0xEF can NOT be used these are reserved for critical +// OCC errors. (H)TMGT will be looking for 0xEy ERRL_RC in cmd response RC +// and create an OCC error log with OCC component ID and 0xEy RC if found + /// Error copying sensors to main memory - SENSOR_MAIN_MEM_ERROR = 0xE0, + SENSOR_MAIN_MEM_ERROR = 0xF0, + + INBAND_CMD_ERROR = 0xF1, /// Success! OCC_SUCCESS_REASON_CODE = 0xFF, @@ -226,6 +232,7 @@ enum occExtReasonCode ERC_BCE_REQ_SCHED_INPROG_FAILURE = 0x0073, ERC_BCE_REQ_CREATE_WRITE_FAILURE = 0x0074, ERC_BCE_REQ_SCHED_WRITE_FAILURE = 0x0075, + ERC_BCE_REQ_CALLBACK_TIMEOUT = 0x0076, ERC_DIMM_SCHEDULE_FAILURE = 0x0080, ERC_DIMM_COMPLETE_FAILURE = 0x0081, diff --git a/src/occ_405/occ_sys_config.c b/src/occ_405/occ_sys_config.c index 2335220..79a2fd0 100755 --- a/src/occ_405/occ_sys_config.c +++ b/src/occ_405/occ_sys_config.c @@ -222,6 +222,14 @@ occSysConfigData_t G_sysConfigData = {{0}, {0}, {0}, {0}}, {{0}, {0}, {0}, {0}} }, + + // ----------------------------------------------------------- + // GPU Initialization + // ----------------------------------------------------------- + .gpu_sensor_ids = {0}, + .total_non_gpu_max_pwr_watts = 0, + .total_proc_mem_pwr_drop_watts = 0, + .psr = 100, // default to 100% take all possible power away from CPU/memory first }; diff --git a/src/occ_405/occ_sys_config.h b/src/occ_405/occ_sys_config.h index 14c2645..951690a 100755 --- a/src/occ_405/occ_sys_config.h +++ b/src/occ_405/occ_sys_config.h @@ -436,6 +436,7 @@ typedef struct uint32_t gpu_sensor_ids[MAX_NUM_GPU_PER_DOMAIN]; uint16_t total_non_gpu_max_pwr_watts; uint16_t total_proc_mem_pwr_drop_watts; + uint8_t psr; // power shifting ratio for power capping between GPU/Proc&mem } occSysConfigData_t; __attribute__ ((__aligned__ (128))) diff --git a/src/occ_405/occbuildname.c b/src/occ_405/occbuildname.c index 5887e1b..c285868 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"))) = /**/ "op_occ_170607a\0" /**/ ; +volatile const char G_occ_buildname[16] __attribute__((section(".buildname"))) = /**/ "op_occ_170630a\0" /**/ ; #endif diff --git a/src/occ_405/proc/proc_pstate.c b/src/occ_405/proc/proc_pstate.c index 986fd2b..277399d 100755 --- a/src/occ_405/proc/proc_pstate.c +++ b/src/occ_405/proc/proc_pstate.c @@ -209,7 +209,7 @@ void populate_opal_dynamic_data() G_opal_dynamic_table.dynamic.mem_throt_status = G_amec_opal_mem_throt_reason; G_opal_dynamic_table.dynamic.quick_power_drop = AMEC_INTF_GET_OVERSUBSCRIPTION(); - G_opal_dynamic_table.dynamic.power_shift_ratio = 50; // @TODO: Power Shift Ratio is not Implemented yet RTC:133825 + G_opal_dynamic_table.dynamic.power_shift_ratio = G_sysConfigData.psr; G_opal_dynamic_table.dynamic.power_cap_type = G_master_pcap_data.source; G_opal_dynamic_table.dynamic.min_power_cap = G_master_pcap_data.soft_min_pcap; G_opal_dynamic_table.dynamic.max_power_cap = G_master_pcap_data.max_pcap; @@ -419,7 +419,7 @@ void check_for_opal_updates(void) // else, if a dynamic OPAL parameter changed, update OPAL dynamic table and OPAL data in memory else if(G_opal_dynamic_table.dynamic.occ_state != CURRENT_STATE() || G_opal_dynamic_table.dynamic.quick_power_drop != AMEC_INTF_GET_OVERSUBSCRIPTION() || - G_opal_dynamic_table.dynamic.power_shift_ratio != 50 || // @TODO: Power Shift Ratio is not Implemented yet RTC:133825 + G_opal_dynamic_table.dynamic.power_shift_ratio != G_sysConfigData.psr || G_opal_dynamic_table.dynamic.power_cap_type != G_master_pcap_data.source || G_opal_dynamic_table.dynamic.min_power_cap != G_master_pcap_data.soft_min_pcap || G_opal_dynamic_table.dynamic.max_power_cap != G_master_pcap_data.max_pcap || diff --git a/src/occ_405/sensor/sensor.h b/src/occ_405/sensor/sensor.h index c28b0cd..3b301d9 100755 --- a/src/occ_405/sensor/sensor.h +++ b/src/occ_405/sensor/sensor.h @@ -75,6 +75,12 @@ typedef enum AMEC_SENSOR_TYPE_PERF = 0x0200, AMEC_SENSOR_TYPE_ALL = 0xffff, }AMEC_SENSOR_TYPE; +// Changes to sensor type bits would require changes to select sensor groups command +// Define the sensor types allowed to be selected via select sensor groups command +#define VALID_SET_SENSOR_GROUPS_MASK (AMEC_SENSOR_TYPE_GENERIC | AMEC_SENSOR_TYPE_CURRENT | \ + AMEC_SENSOR_TYPE_VOLTAGE | AMEC_SENSOR_TYPE_TEMP | AMEC_SENSOR_TYPE_UTIL | \ + AMEC_SENSOR_TYPE_TIME | AMEC_SENSOR_TYPE_FREQ | AMEC_SENSOR_TYPE_POWER | \ + AMEC_SENSOR_TYPE_PERF) // AMEC_SENSOR_LOC_INVALID can not be used to identify sensor location. // A bit vector mask is used to specify sensor locations that AMESTER is @@ -113,13 +119,16 @@ typedef enum // AMEC_SENSOR_CLEAR_ALL_MINMAX clears all min/max values in the sensor. typedef enum { - AMEC_SENSOR_CLEAR_SAMPLE_MINMAX = 0x0001, - AMEC_SENSOR_CLEAR_CSM_SAMPLE_MINMAX = 0x0002, - AMEC_SENSOR_CLEAR_PROFILER_SAMPLE_MINMAX = 0x0004, - AMEC_SENSOR_CLEAR_JOB_S_SAMPLE_MINMAX = 0x0008, - AMEC_SENSOR_CLEAR_ALL_MINMAX = 0xffff, + AMEC_SENSOR_CLEAR_SAMPLE_MINMAX = 0x01, + AMEC_SENSOR_CLEAR_CSM_SAMPLE_MINMAX = 0x10, + AMEC_SENSOR_CLEAR_PROFILER_SAMPLE_MINMAX = 0x20, + AMEC_SENSOR_CLEAR_JOB_S_SAMPLE_MINMAX = 0x40, + AMEC_SENSOR_CLEAR_ALL_MINMAX = 0xff, } AMEC_SENSOR_CLEAR_TYPE; - +// The bits for types must match the defined owners in the clear sensor data command +// Define the owners allowed to be cleared via clear sensor data command +#define VALID_CLEAR_SENSOR_OWNER_MASK (AMEC_SENSOR_CLEAR_CSM_SAMPLE_MINMAX | \ + AMEC_SENSOR_CLEAR_PROFILER_SAMPLE_MINMAX | AMEC_SENSOR_CLEAR_JOB_S_SAMPLE_MINMAX) /*****************************************************************************/ // Forward declaration as used in vectorSensor struct sensor; diff --git a/src/occ_405/sensor/sensor_inband_cmd.c b/src/occ_405/sensor/sensor_inband_cmd.c new file mode 100755 index 0000000..15a8967 --- /dev/null +++ b/src/occ_405/sensor/sensor_inband_cmd.c @@ -0,0 +1,557 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/sensor/sensor_inband_cmd.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + + +//****************************************************************************** +// Includes +//****************************************************************************** +#include +#include +#include +#include +#include +#include +#include +#include + + +//****************************************************************************** +// Block Copy Engine (BCE) Defines/Globals +//****************************************************************************** + +// Buffer in SRAM to copy larger commands cmd/rsp buffer from/to main memory using the BCE +DMA_BUFFER(inband_max_cmd_t G_inband_cmd_max_data_bce_buff) = {{0}}; + +// Buffer in SRAM to copy smaller commands cmd/rsp buffer from/to main memory using the BCE +DMA_BUFFER(inband_min_cmd_t G_inband_cmd_min_data_bce_buff) = {{0}}; + +// BCE request structure. Used by BCE functions to schedule copy request. +BceRequest G_inband_cmd_bce_req; + +/** + * Specifies whether the BCE request was scheduled. If false, the request + * finished or has never been scheduled/initialized. + */ +bool G_inband_cmd_req_scheduled = false; + +// Number of tics passed waiting for BCE callback +uint8_t G_bce_callback_wait = 0; + +volatile uint8_t G_inband_occ_cmd_state = INBAND_OCC_CMD_NONE; +volatile uint8_t G_inband_occ_bce_saved_state = INBAND_OCC_CMD_NONE; + +//****************************************************************************** +// Functions +//****************************************************************************** + + +/** + * Logs an error caused by the Block Copy Engine. Does nothing if a BCE error + * has already been logged. + * + * Note that the required error log comment containing tags like 'userdata4' and + * 'devdesc' must be located by the call to this function. It is not located + * inside this function because the value of those tags varies. + * + * @param i_modId Module ID + * @param i_extReasonCode Extended reason code + * @param i_userData1 Userdata1 value + * @param i_userData2 Userdata2 value + */ +void inband_cmd_log_bce_error(uint16_t i_modId, uint16_t i_extReasonCode, + uint32_t i_userData1, uint32_t i_userData2) +{ + static bool L_error_logged = false; + if (!L_error_logged) + { + // Create and commit error + errlHndl_t l_errl = createErrl(i_modId, // Module ID + INBAND_CMD_ERROR, // Reason code + i_extReasonCode, // Extended reason code + ERRL_SEV_INFORMATIONAL, // Severity + NULL, // Trace Buffers + DEFAULT_TRACE_SIZE, // Trace Size + i_userData1, // Userdata1 + i_userData2); // Userdata2 + commitErrl(&l_errl); + L_error_logged = true; + } +} + + +/** + * Returns whether the global BCE request struct is idle and ready for re-use. + * Returns true immediately if the request was not scheduled. If the request + * was scheduled, checks to see if it has finished. + * + * @param i_caller_mod_id Module ID of calling function in case an error occurs + * @return True if BCE request is idle, false otherwise + */ +bool inband_cmd_is_bce_req_idle(uint16_t i_caller_mod_id) +{ + // Number of times we've waited for current request to finish + static uint8_t L_wait_count = 0; + + // If the request was not previously scheduled, then it is idle. This also + // handles the case where the request has not been initialized yet. + if (!G_inband_cmd_req_scheduled) + { + return true; + } + + // Request was scheduled; check if it finished and is now idle + if (async_request_is_idle(&G_inband_cmd_bce_req.request)) + { + // Request is now idle and ready for re-use + G_inband_cmd_req_scheduled = false; + + // If we were waiting for request to finish, trace and clear wait count + if (L_wait_count > 0) + { + TRAC_INFO("inband_cmd_is_bce_req_idle: " + "Request finished after waiting %u times: caller=0x%04X", + L_wait_count, i_caller_mod_id); + L_wait_count = 0; + } + return true; + } + + // Request was scheduled but has not finished. Increment wait count unless + // we are already at the max (to avoid overflow). + if (L_wait_count < UINT8_MAX) + { + ++L_wait_count; + } + + // If this is the first time we've waited for this request, trace it + if (L_wait_count == 1) + { + TRAC_INFO("inband_cmd_is_bce_req_idle: " + "Waiting for request to finish: caller=0x%04X", + i_caller_mod_id); + } + + // If this is the second time we've waited for this request, log BCE error + if (L_wait_count == 2) + { + /* @ + * @errortype + * @moduleid INBAND_CMD_IS_BCE_REQ_IDLE_MOD + * @reasoncode INBAND_CMD_ERROR + * @userdata1 Caller module ID + * @userdata2 0 + * @userdata4 ERC_GENERIC_TIMEOUT + * @devdesc BCE request not finished after waiting twice + */ + inband_cmd_log_bce_error(INBAND_CMD_IS_BCE_REQ_IDLE_MOD, ERC_GENERIC_TIMEOUT, + i_caller_mod_id, 0); + } + + // Return false since request is not idle + return false; +} + +/** + * inband_cmd_bce_callback + * + * Description: Callback function for G_inband_cmd_bce_req BCE request + * NO TRACING OR CALLING FUNCTIONS THAT TRACE ALLOWED + */ +void inband_cmd_bce_callback( void ) +{ + static bool L_processed_at_least_one_cmd = FALSE; + static uint8_t L_last_seq_num_processed = 0; + uint8_t seq_num = 0; + uint8_t cmd_flags = 0; + + // Decide what to do next for processing an in-band command for the BCE that finished + switch (G_inband_occ_cmd_state) + { + case INBAND_OCC_CMD_CHECK_FOR_CMD: + // check for command uses min bce data buffer + // If we processed at least one cmd it is not a new command if same seq number + cmd_flags = G_inband_cmd_min_data_bce_buff.header.flags; + seq_num = G_inband_cmd_min_data_bce_buff.header.seq; + if( ( (!L_processed_at_least_one_cmd) || + (L_processed_at_least_one_cmd && (seq_num != L_last_seq_num_processed)) ) && + ( (cmd_flags & IN_BAND_CMD_READY_MASK) == IN_BAND_CMD_READY_MASK) ) + { + // There is a command to process + G_inband_occ_cmd_state = INBAND_OCC_CMD_START; + // now that we have a cmd save seq num so we don't keep processing the same cmd + L_processed_at_least_one_cmd = TRUE; + L_last_seq_num_processed = seq_num; + } + else + { + // No command + G_inband_occ_cmd_state = INBAND_OCC_CMD_NONE; + } + break; + + case INBAND_OCC_CMD_RSP_READY: + // response is ready send interrupt + G_inband_occ_cmd_state = INBAND_OCC_CMD_RSP_INT; + break; + + default: + // Invalid state. Can't trace here set state to invalid to trace later + G_inband_occ_bce_saved_state = G_inband_occ_cmd_state; + G_inband_occ_cmd_state = INBAND_OCC_INVALID_BCE_CALLBACK; + break; + } +} + +/** + * Copies the specified number of bytes either to main mem or down from main mem + * for handling an inband command using the Block Copy Engine (BCE). + * + * @param i_main_mem_addr Main memory address for copy. Must be 128-byte aligned + * @param i_sram_addr SRAM address for copy. Must be 128-byte aligned + * @param i_byte_count Number of bytes to copy. Must be multiple of 128. + * Must be <= INBAND_OCC_CMD_BCE_BUF_SIZE. 0 bytes is not valid + * @param i_to_main_mem TRUE indicates copy is sram to main memory + * FALSE indicates copy is main memory to sram + * @param i_caller_mod_id Module ID of the calling function in case an error occurs + * @return True if BCE request was successfully scheduled, false otherwise + */ +bool inband_cmd_bce_copy(uint32_t i_main_mem_addr, uint32_t i_sram_addr, + size_t i_byte_count, bool i_to_main_mem, uint16_t i_caller_mod_id) +{ + int l_rc = 0; + + // Verify address and byte count are valid + static bool L_traced_param_error = false; + if (((i_main_mem_addr % 128) != 0) || ((i_sram_addr % 128) != 0) || + ((i_byte_count % 128) != 0) || (i_byte_count > INBAND_CMD_MAX_BCE_BUF_SIZE) || + (i_byte_count == 0) ) + { + if (!L_traced_param_error) + { + TRAC_ERR("inband_cmd_bce_copy: Input parameter error: " + "address=0x%08X SRAM=0x%08X length=%u caller=0x%04X", + i_main_mem_addr, i_sram_addr, i_byte_count, i_caller_mod_id); + L_traced_param_error = true; + } + return false; + } + + // Check if a copy request was previously scheduled and is not yet finished + static bool L_traced_sched_error = false; + if (!inband_cmd_is_bce_req_idle(i_caller_mod_id)) + { + if (!L_traced_sched_error) + { + TRAC_ERR("inband_cmd_bce_copy: Previous request not finished: caller=0x%04X", + i_caller_mod_id); + L_traced_sched_error = true; + } + return false; + } + + // Create BCE request based on if copy is up or down from main memory + if (i_to_main_mem) + { + l_rc = bce_request_create(&G_inband_cmd_bce_req, // Block copy request + &G_pba_bcue_queue, // SRAM up to mainstore + i_main_mem_addr, // Mainstore address + i_sram_addr, // SRAM start address + i_byte_count, // Size of copy + SSX_WAIT_FOREVER, // No timeout + (AsyncRequestCallback) inband_cmd_bce_callback, + NULL, // No call back args + ASYNC_CALLBACK_IMMEDIATE); + } + else + { + l_rc = bce_request_create(&G_inband_cmd_bce_req, // Block copy request + &G_pba_bcde_queue, // mainstore down to SRAM + i_main_mem_addr, // Mainstore address + i_sram_addr, // SRAM start address + i_byte_count, // Size of copy + SSX_WAIT_FOREVER, // No timeout + (AsyncRequestCallback) inband_cmd_bce_callback, + NULL, // No call back args + ASYNC_CALLBACK_IMMEDIATE); + } + + if (l_rc != SSX_OK) // fail to create BCE request? + { + TRAC_ERR("inband_cmd_bce_copy: Request create failure: rc=0x%08X caller=0x%04X", + -l_rc, i_caller_mod_id); + /* @ + * @errortype + * @moduleid INBAND_CMD_BCE_COPY_MOD + * @reasoncode INBAND_CMD_ERROR + * @userdata1 Return code from bce_request_create() + * @userdata2 Caller module ID + * @userdata4 ERC_BCE_REQUEST_CREATE_FAILURE + * @devdesc Failed to create BCE request + */ + inband_cmd_log_bce_error(INBAND_CMD_BCE_COPY_MOD, ERC_BCE_REQUEST_CREATE_FAILURE, + -l_rc, i_caller_mod_id); + return false; + } + + // Schedule BCE request + l_rc = bce_request_schedule(&G_inband_cmd_bce_req); + if (l_rc != SSX_OK) + { + TRAC_ERR("inband_cmd_bce_copy: Request schedule failure: rc=0x%08X caller=0x%04X", + -l_rc, i_caller_mod_id); + /* @ + * @errortype + * @moduleid INBAND_CMD_BCE_COPY_MOD + * @reasoncode INBAND_CMD_ERROR + * @userdata1 Return code from bce_request_schedule() + * @userdata2 Caller module ID + * @userdata4 ERC_BCE_REQUEST_SCHEDULE_FAILURE + * @devdesc Failed to schedule BCE request + */ + inband_cmd_log_bce_error(INBAND_CMD_BCE_COPY_MOD, ERC_BCE_REQUEST_SCHEDULE_FAILURE, + -l_rc, i_caller_mod_id); + return false; + } + + // Successfully scheduled request. Copy is not blocking, so need to check + // whether it finished later. Set flag indicating request is scheduled. + G_inband_cmd_req_scheduled = true; + return true; +} + + +// Function Specification +// +// Name: inband_command_check +// +// Description: Check for command from the inband interface +// +// End Function Specification +void inband_command_check(void) +{ + // Only check for a new command if not currently processing an inband command + if (G_inband_occ_cmd_state == INBAND_OCC_CMD_NONE) + { + // Create and Schedule BCE to read minimum bytes of OCC inband command buffer in HOMER + memset((void*)&G_inband_cmd_min_data_bce_buff, 0x00, sizeof(inband_min_cmd_t)); + bool i_to_main_mem = FALSE; // this request is main mem down to SRAM + G_inband_occ_cmd_state = INBAND_OCC_CMD_CHECK_FOR_CMD; + G_bce_callback_wait = 0; + if (inband_cmd_bce_copy(INBAND_OCC_CMD_ADDRESS_HOMER, (uint32_t)&G_inband_cmd_min_data_bce_buff, + INBAND_CMD_MIN_BCE_BUF_SIZE, i_to_main_mem, INBAND_CMD_CHECK_MOD)) + { + // Copy succeeded. The BCE callback will handle next + } + else + { + // copy failed try again next time + G_inband_occ_cmd_state = INBAND_OCC_CMD_NONE; + } + } +} + +// Function Specification +// +// Name: inband_command_handler +// +// Description: Command handler for inband commands this should only be called if +// it is already known that there is an in-band command in process +// This is checked to be called on every tick +// +// End Function Specification +void inband_command_handler(void) +{ + uint8_t l_reason_code = ERRL_RC_INTERNAL_FAIL; + uint16_t l_cmd_data_len = 0; + uint8_t l_seq_num = 0; + uint8_t l_cmd_type = 0xFF; + uint16_t l_rsp_data_length = 0; + uint16_t l_bce_copy_size = 0; + uint8_t l_bce_padding = 0; + bool l_to_main_mem = TRUE; // BCE requests from here are going SRAM to main memory + bool l_bce_scheduled = FALSE; + + // Decide what to do next for processing an in-band command + if(G_inband_occ_cmd_state == INBAND_OCC_CMD_START) + { + // We use the max buffer for response + memset((void*)&G_inband_cmd_max_data_bce_buff, 0x00, INBAND_CMD_MAX_BCE_BUF_SIZE); + + // When we check for command we used the minimum bce buffer + l_seq_num = G_inband_cmd_min_data_bce_buff.header.seq; + l_cmd_type = G_inband_cmd_min_data_bce_buff.header.cmd_type; + l_cmd_data_len = CONVERT_UINT8_ARRAY_UINT16(G_inband_cmd_min_data_bce_buff.header.data_length[0], + G_inband_cmd_min_data_bce_buff.header.data_length[1]); + + // if data is more than min we will need to do another BCE to read the rest of the cmd + if(l_cmd_data_len > INBAND_MIN_DATA_LENGTH) + { + // invalid command, currently no cmd supported is larger than min requiring 2nd BCE + l_reason_code = ERRL_RC_INVALID_CMD_LEN; + } + else + { + // Have the full command, process it based on command type. + // cmd data is in min data BCE buffer the rsp data will go in the max data BCE buffer + uint8_t* l_cmd_data_ptr = (uint8_t*) &G_inband_cmd_min_data_bce_buff.data; + uint8_t* l_rsp_data_ptr = (uint8_t*) &G_inband_cmd_max_data_bce_buff.data; + + switch(l_cmd_type) + { + case CMDH_CLEAR_SENSOR_DATA: + l_reason_code = cmdh_clear_sensor_data(l_cmd_data_len, + l_cmd_data_ptr, + INBAND_MAX_DATA_LENGTH, + &l_rsp_data_length, + l_rsp_data_ptr); + break; + + case CMDH_SET_PCAP_INBAND: + l_reason_code = cmdh_set_pcap_inband(l_cmd_data_len, + l_cmd_data_ptr, + INBAND_MAX_DATA_LENGTH, + &l_rsp_data_length, + l_rsp_data_ptr); + break; + + case CMDH_WRITE_PSR: + l_reason_code = cmdh_write_psr(l_cmd_data_len, + l_cmd_data_ptr, + INBAND_MAX_DATA_LENGTH, + &l_rsp_data_length, + l_rsp_data_ptr); + break; + + case CMDH_SELECT_SENSOR_GROUPS: + l_reason_code = cmdh_select_sensor_groups(l_cmd_data_len, + l_cmd_data_ptr, + INBAND_MAX_DATA_LENGTH, + &l_rsp_data_length, + l_rsp_data_ptr); + break; + + default: + l_reason_code = ERRL_RC_INVALID_CMD; + break; + } // end switch + } // end cmd process + + // fill in response header in G_inband_cmd_max_data_bce_buff + G_inband_cmd_max_data_bce_buff.header.flags = IN_BAND_RSP_READY_MASK; + G_inband_cmd_max_data_bce_buff.header.seq = l_seq_num; + G_inband_cmd_max_data_bce_buff.header.cmd_type = l_cmd_type; + G_inband_cmd_max_data_bce_buff.header.reserved_rc = l_reason_code; + G_inband_cmd_max_data_bce_buff.header.data_length[0] = ((uint8_t *)&l_rsp_data_length)[0]; + G_inband_cmd_max_data_bce_buff.header.data_length[1] = ((uint8_t *)&l_rsp_data_length)[1]; + + // Copy the response from SRAM to main memory + // Determine BCE copy size, must be factor of 128 + l_bce_copy_size = sizeof(inband_occ_cmd_header_t) + l_rsp_data_length; + l_bce_padding = l_bce_copy_size % 128; + if(l_bce_padding) + { + l_bce_copy_size += (128 - l_bce_padding); + } + + G_bce_callback_wait = 0; + G_inband_occ_cmd_state = INBAND_OCC_CMD_RSP_READY; + l_bce_scheduled = inband_cmd_bce_copy(INBAND_OCC_RSP_ADDRESS_HOMER, + (uint32_t)&G_inband_cmd_max_data_bce_buff, + l_bce_copy_size, + l_to_main_mem, + INBAND_CMD_HANDLER_MOD); + if (!l_bce_scheduled) + { + // failed to copy response + G_inband_occ_cmd_state = INBAND_OCC_CMD_NONE; + } + else + { + TRAC_INFO("inband_command_handler: Command 0x%02X with " + "seq_num 0x%02X finished with RC 0x%02X", + l_cmd_type, l_seq_num, l_reason_code); + } + + } // INBAND_OCC_CMD_START + + else if(G_inband_occ_cmd_state == INBAND_OCC_CMD_RSP_INT) + { + // Send interrupt to indciate response is ready in main mem + notify_host(INTR_REASON_OPAL_SHARED_MEM_CHANGE); + G_inband_occ_cmd_state = INBAND_OCC_CMD_NONE; + } + + else if( (G_inband_occ_cmd_state == INBAND_OCC_CMD_CHECK_FOR_CMD) || + (G_inband_occ_cmd_state == INBAND_OCC_CMD_RSP_READY) ) + { + // Waiting for BCE to finish, these states are handled by BCE callback + // if the callback is never called (BCE failure) for a max wait log error + G_bce_callback_wait++; + if(G_bce_callback_wait == MAX_TICS_INBAND_BCE_CALLBACK_WAIT) + { + TRAC_ERR("inband_command_handler: Timeout waiting for BCE callback cmd state 0x%02X", + G_inband_occ_cmd_state); + G_inband_occ_cmd_state = INBAND_OCC_CMD_NONE; + /* @ + * @errortype + * @moduleid INBAND_CMD_HANDLER_MOD + * @reasoncode INBAND_CMD_ERROR + * @userdata1 Inband command state + * @userdata2 Caller module ID + * @userdata4 ERC_BCE_REQ_CALLBACK_TIMEOUT + * @devdesc Timeout waiting for BCE callback + */ + inband_cmd_log_bce_error(INBAND_CMD_HANDLER_MOD, ERC_BCE_REQ_CALLBACK_TIMEOUT, + G_inband_occ_cmd_state, INBAND_CMD_HANDLER_MOD); + } + } + + else if(G_inband_occ_cmd_state == INBAND_OCC_INVALID_BCE_CALLBACK) + { + // BCE callback was called with invalid state, trace now and set state to none + static bool L_traced_bce_bad_state = FALSE; + if (!L_traced_bce_bad_state) + { + TRAC_ERR("inband_command_handler: inband_cmd_bce_callback detected invalid state %u", + G_inband_occ_bce_saved_state); + L_traced_bce_bad_state = TRUE; + } + G_inband_occ_cmd_state = INBAND_OCC_CMD_NONE; + G_inband_occ_bce_saved_state = INBAND_OCC_CMD_NONE; + } + + else + { + // Invalid state + static bool L_traced_bad_state = FALSE; + if (!L_traced_bad_state) + { + TRAC_ERR("inband_command_handler: Called with invalid state %u", + G_inband_occ_cmd_state); + L_traced_bad_state = TRUE; + } + G_inband_occ_cmd_state = INBAND_OCC_CMD_NONE; + } +} diff --git a/src/occ_405/sensor/sensor_inband_cmd.h b/src/occ_405/sensor/sensor_inband_cmd.h new file mode 100644 index 0000000..4e39f84 --- /dev/null +++ b/src/occ_405/sensor/sensor_inband_cmd.h @@ -0,0 +1,112 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/sensor/sensor_inband_cmd.h $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#ifndef _SENSOR_INBAND_CMD_H +#define _SENSOR_INBAND_CMD_H + +/** + * @file sensor_inband_cmd.h + * + * This file declares the functions and global variables for supporting the inband + * command protocol defined in the OCC Firmware Interface spec + * + */ + +//****************************************************************************** +// Defines/Structs/Globals +//****************************************************************************** + +// States of inband OCC command processing +typedef enum +{ + INBAND_OCC_CMD_NONE = 0x00, // No inband command in process + INBAND_OCC_CMD_CHECK_FOR_CMD = 0x01, // Check for cmd when BCE read finishes + INBAND_OCC_CMD_START = 0x02, // Start processing the command + INBAND_OCC_CMD_RSP_READY = 0x03, // Response ready + INBAND_OCC_CMD_RSP_INT = 0x04, // Send Response Interrupt + INBAND_OCC_INVALID_BCE_CALLBACK = 0x05, // BCE callback called with invalid OCC cmd state +} INBAND_OCC_CMD_STATE; + +// Current state of inband OCC command processing +extern volatile uint8_t G_inband_occ_cmd_state; +// Last state saved for error handling +extern volatile uint8_t G_inband_occ_bce_saved_state; + +#define MAX_TICS_INBAND_BCE_CALLBACK_WAIT 0x03 +#define IN_BAND_CMD_READY_MASK 0x80 +#define IN_BAND_RSP_IN_PROGRESS_MASK 0x02 +#define IN_BAND_RSP_READY_MASK 0x01 + +typedef struct __attribute__ ((packed)) +{ + uint8_t flags; + uint8_t seq; + uint8_t cmd_type; + uint8_t reserved_rc; // as a command reserved, as a response RC + uint8_t data_length[2]; +} inband_occ_cmd_header_t; + +// Data Size is Block Copy Engine dependent, 128 min to 4kB max +#define INBAND_CMD_MIN_BCE_BUF_SIZE 128 +#define INBAND_CMD_MAX_BCE_BUF_SIZE 4096 +#define INBAND_MAX_DATA_LENGTH INBAND_CMD_MAX_BCE_BUF_SIZE - sizeof(inband_occ_cmd_header_t) +#define INBAND_MIN_DATA_LENGTH INBAND_CMD_MIN_BCE_BUF_SIZE - sizeof(inband_occ_cmd_header_t) + +typedef struct __attribute__ ((packed)) +{ + inband_occ_cmd_header_t header; + // Data bytes + uint8_t data[INBAND_MIN_DATA_LENGTH]; +}inband_min_cmd_t; + +typedef struct __attribute__ ((packed)) +{ + inband_occ_cmd_header_t header; + // Data bytes + uint8_t data[INBAND_MAX_DATA_LENGTH]; +}inband_max_cmd_t; + +//****************************************************************************** +// Function Prototypes +//****************************************************************************** + +/** + * Check for a command from the inband command/response interface + * + * There are inband commands to select sensors to write to main memory and + * clear sensors min/max by user + * + * This function is called from amec_slv_common_tasks_post() + */ +void inband_command_check(void); + +/** + * Handle a command from the inband command/response interface + * + * This function is called from amec_slv_substate_6_x + */ +void inband_command_handler(void); + +#endif // _SENSOR_INBAND_CMD_H diff --git a/src/occ_405/sensor/sensor_main_memory.h b/src/occ_405/sensor/sensor_main_memory.h index f9cd29f..f989e13 100644 --- a/src/occ_405/sensor/sensor_main_memory.h +++ b/src/occ_405/sensor/sensor_main_memory.h @@ -302,5 +302,4 @@ void main_mem_sensors_update(void); */ void main_mem_sensors_set_enabled(AMEC_SENSOR_TYPE i_sensor_type, bool i_enabled); - #endif // _SENSOR_MAIN_MEMORY_H diff --git a/src/occ_405/sensor/sensor_service_codes.h b/src/occ_405/sensor/sensor_service_codes.h index 397a2d5..f511edf 100755 --- a/src/occ_405/sensor/sensor_service_codes.h +++ b/src/occ_405/sensor/sensor_service_codes.h @@ -44,6 +44,12 @@ enum occSensorModuleId MM_SENSORS_WRITE_NAMES_MOD = SNSR_COMP_ID | 0x16, MM_SENSORS_WRITE_READINGS_MOD = SNSR_COMP_ID | 0x17, MM_SENSORS_VALIDATE_READINGS_MOD = SNSR_COMP_ID | 0x18, + + // Inband commands + INBAND_CMD_IS_BCE_REQ_IDLE_MOD = SNSR_COMP_ID | 0x20, + INBAND_CMD_BCE_COPY_MOD = SNSR_COMP_ID | 0x21, + INBAND_CMD_HANDLER_MOD = SNSR_COMP_ID | 0x22, + INBAND_CMD_CHECK_MOD = SNSR_COMP_ID | 0x23, }; #endif /* #ifndef _SENSOR_SERVICE_CODES_H_ */ diff --git a/src/occ_405/topfiles.mk b/src/occ_405/topfiles.mk index 61f9348..ca38569 100644 --- a/src/occ_405/topfiles.mk +++ b/src/occ_405/topfiles.mk @@ -93,6 +93,7 @@ TOP-C-SOURCES = amec/amec_analytics.c \ rtls/rtls_tables.c \ rtls/rtls.c \ scom.c \ + sensor/sensor_inband_cmd.c \ sensor/sensor_info.c \ sensor/sensor_main_memory.c \ sensor/sensor_query_list.c \ -- cgit v1.2.1