diff --git a/src/occ_405/amec/amec_freq.c b/src/occ_405/amec/amec_freq.c index 57ac0470..6b33d1eb 100755 --- a/src/occ_405/amec/amec_freq.c +++ b/src/occ_405/amec/amec_freq.c @@ -180,10 +180,12 @@ errlHndl_t amec_set_freq_range(const OCC_MODE i_mode) g_amec->sys.fmin = l_freq_min; g_amec->sys.fmax = l_freq_max; - TRAC_INFO("amec_set_freq_range: Mode[0x%02x] Fmin[%u] Fmax[%u]", + TRAC_INFO("amec_set_freq_range: Mode[0x%02x] Fmin[%u] (Pmin 0x%02x) Fmax[%u] (Pmax 0x%02x)", i_mode, l_freq_min, - l_freq_max); + proc_freq2pstate(g_amec->sys.fmin), + l_freq_max, + proc_freq2pstate(g_amec->sys.fmax)); // Now determine the max frequency for the PPM structure l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL]; @@ -528,51 +530,88 @@ void amec_slv_freq_smh(void) /*------------------------------------------------------------------------*/ /* Local Variables */ /*------------------------------------------------------------------------*/ - uint8_t quad = 0; // loop through quads - uint8_t core_num = 0; // core ID - uint8_t core_idx = 0; // loop through cores within each quad - Pstate pmax = 0; // select the maximum pstate (minimum frequency) - // within each quad, initialize to 0 (max frequency) + uint8_t quad = 0; // loop through quads + uint8_t core_num = 0; // core ID + uint8_t core_idx = 0; // loop through cores within each quad + Pstate pmax[MAX_QUADS] = {0}; // max pstate (min frequency) within each quad + Pstate pmax_chip = 0; // highest Pstate (lowest frequency) across all quads + bool l_atLeast1Core[MAX_QUADS] = {FALSE}; // at least 1 core present in quad + static bool L_mfg_set_trace[MAX_QUADS] = {FALSE}; + static bool L_mfg_clear_trace[MAX_QUADS] = {FALSE}; /*------------------------------------------------------------------------*/ /* Code */ /*------------------------------------------------------------------------*/ - // loop through all quads, get f_requests, translate to pstates + // loop through all quads, get f_requests, translate to pstates and determine pmax across chip for (quad = 0; quad < MAX_QUADS; quad++) { - for (core_idx=0; core_idxproc[0].core[core_num].f_request)) + // ignore core if freq request is 0 (core not present when amec_slv_proc_voting_box ran) + if(g_amec->proc[0].core[core_num].f_request != 0) { - pmax = proc_freq2pstate(g_amec->proc[0].core[core_num].f_request); + l_atLeast1Core[quad] = TRUE; + // The higher the pstate number, the lower the frequency + if(pmax[quad] < proc_freq2pstate(g_amec->proc[0].core[core_num].f_request)) + { + pmax[quad] = proc_freq2pstate(g_amec->proc[0].core[core_num].f_request); + if(pmax_chip < pmax[quad]) // check if this is a new lowest freq for the chip + pmax_chip = pmax[quad]; + } } } + } + + // check for mfg quad Pstate request and set Pstate for each quad + for (quad = 0; quad < MAX_QUADS; quad++) + { + // set quad with no cores present to lowest frequency for the chip + if(l_atLeast1Core[quad] == FALSE) + pmax[quad] = pmax_chip; + + // check if there is a mnfg Pstate request for this quad + if(g_amec->mnfg_parms.quad_pstate[quad] != 0xFF) + { + // use mnfg request if it is a lower frequency (higher pState) + if(g_amec->mnfg_parms.quad_pstate[quad] > pmax[quad]) + pmax[quad] = g_amec->mnfg_parms.quad_pstate[quad]; + + if(L_mfg_clear_trace[quad] == FALSE) + L_mfg_set_trace[quad] = TRUE; + } + else if(L_mfg_clear_trace[quad] == TRUE) + { + TRAC_INFO("amec_slv_freq_smh: mfg Quad %d Pstate request cleared. New Pstate = 0x%02x", quad, pmax[quad]); + L_mfg_clear_trace[quad] = FALSE; + } // set quad clip bounds/pstates based on system type if(G_sysConfigData.system_type.kvm) { // update quad bounds on OPAL systems - G_core_data_control_occwrite_ptr->clips.ps_val_clip_min[quad] = - G_opal_static_table.config.pmin; - G_core_data_control_occwrite_ptr->clips.ps_val_clip_max[quad] = pmax; + G_core_data_control_occwrite_ptr->clips.ps_val_clip_min[quad] = G_opal_static_table.config.pmin; + G_core_data_control_occwrite_ptr->clips.ps_val_clip_max[quad] = pmax[quad]; PROC_DBG("Setting Quad %d's min-max clip bounds to %d-%d\n", - quad, G_opal_static_table.config.pmin, pmax); + quad, G_opal_static_table.config.pmin, pmax[quad]); } else { - // update quad pstate request on non-OPAL systems - G_core_data_control_occwrite_ptr->pstates.pmcr[quad] = - ((uint64_t) pmax << 48) +1; // Version 1 (Power9 format) + // update quad pstate request on non-OPAL systems. Version 1 (P9 format) + G_core_data_control_occwrite_ptr->pstates.pmcr[quad] = ((uint64_t) pmax[quad] << 48) +1; - PROC_DBG("Setting Quad %d's Pstate to %d\n",quad, pmax); + PROC_DBG("Setting Quad %d's Pstate to %d\n",quad, pmax[quad]); } - pmax = 0; // initialize for next loop iteration + if(L_mfg_set_trace[quad] == TRUE) + { + TRAC_INFO("amec_slv_freq_smh: mfg Quad %d Pstate request set = 0x%02x", quad, pmax[quad]); + L_mfg_set_trace[quad] = FALSE; + L_mfg_clear_trace[quad] = TRUE; + } } } diff --git a/src/occ_405/amec/amec_sys.h b/src/occ_405/amec/amec_sys.h index 7fd0f957..0757466d 100755 --- a/src/occ_405/amec/amec_sys.h +++ b/src/occ_405/amec/amec_sys.h @@ -438,7 +438,7 @@ typedef struct amec_memctl_t memctl[MAX_NUM_MEM_CONTROLLERS]; amec_vrm_t vrm[NUM_PROC_VRMS]; amec_proc_pwr_votes_t pwr_votes; - amec_quad_t quad[MAX_NUM_QUADS]; + amec_quad_t quad[MAX_QUADS]; // Processor Sensors sensor_t freqa4ms; @@ -526,6 +526,8 @@ typedef struct amec_mnfg bool mem_autoslew; ///memory slewing count uint32_t mem_slew_counter; + ///Per Quad Pstate request: 0xFF=no request + uint8_t quad_pstate[MAX_QUADS]; } amec_mnfg_t; //------------------------------------------------------------- diff --git a/src/occ_405/cmdh/cmdh_fsp.c b/src/occ_405/cmdh/cmdh_fsp.c index aa5b00d1..1247e8a4 100755 --- a/src/occ_405/cmdh/cmdh_fsp.c +++ b/src/occ_405/cmdh/cmdh_fsp.c @@ -941,7 +941,7 @@ errlHndl_t cmdh_processTmgtRequest (const cmdh_fsp_cmd_t * i_cmd_ptr, break; case CMDH_MFG_TEST_CMD: - cmdh_mnfg_test_parse(i_cmd_ptr,i_rsp_ptr); + l_err = cmdh_mnfg_test_parse(i_cmd_ptr,i_rsp_ptr); break; case CMDH_GET_FIELD_DEBUG_DATA: diff --git a/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c b/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c index 8afaf67c..db63d39a 100755 --- a/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c +++ b/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c @@ -340,6 +340,14 @@ errlHndl_t data_store_freq_data(const cmdh_fsp_cmd_t * i_cmd_ptr, // Bytes 11-12 Static Power Save Frequency Point l_freq = (l_buf[8] << 8 | l_buf[9]); + // in case min freq was clipped verify power save not below min + if(l_freq < l_table[OCC_MODE_MIN_FREQUENCY]) + { + CMDH_TRAC_ERR("Power Save Frequency[%d] is lower than min[%d]", + l_freq, l_table[OCC_MODE_MIN_FREQUENCY]); + l_freq = l_table[OCC_MODE_MIN_FREQUENCY]; + } + l_table[OCC_MODE_PWRSAVE] = l_freq; CMDH_TRAC_INFO("Static Power Save frequency = %d MHz", l_freq); diff --git a/src/occ_405/cmdh/cmdh_mnfg_intf.c b/src/occ_405/cmdh/cmdh_mnfg_intf.c index 2d78b689..a270b760 100755 --- a/src/occ_405/cmdh/cmdh_mnfg_intf.c +++ b/src/occ_405/cmdh/cmdh_mnfg_intf.c @@ -609,6 +609,107 @@ uint8_t cmdh_mnfg_get_sensor(const cmdh_fsp_cmd_t * i_cmd_ptr, return l_rc; } +// Function Specification +// +// Name: cmdh_mnfg_request_quad_pstate +// +// Description: This function handles the manufacturing command to request +// a Pstate per Quad. +// +// End Function Specification +uint8_t cmdh_mnfg_request_quad_pstate(const cmdh_fsp_cmd_t * i_cmd_ptr, + cmdh_fsp_rsp_t * o_rsp_ptr) +{ + uint8_t l_rc = ERRL_RC_SUCCESS; + uint16_t l_datalength = 0; + uint16_t l_resp_data_length = 0; + uint8_t l_pmin = 0xFF; + uint8_t l_pmax = 0xFF; + uint8_t l_pstate_request = 0xFF; + uint8_t l_quad = 0; + mnfg_quad_pstate_cmd_t *l_cmd_ptr = (mnfg_quad_pstate_cmd_t*) i_cmd_ptr; + mnfg_quad_pstate_rsp_t *l_rsp_ptr = (mnfg_quad_pstate_rsp_t*) o_rsp_ptr; + + do + { + if(!IS_OCC_STATE_ACTIVE()) + { + TRAC_ERR("cmdh_mnfg_request_quad_pstate: OCC must be active to request pstate"); + l_rc = ERRL_RC_INVALID_STATE; + break; + } + + if(G_sysConfigData.system_type.kvm) + { + TRAC_ERR("cmdh_mnfg_request_quad_pstate: Must be PowerVM to request pstate"); + l_rc = ERRL_RC_INVALID_CMD; + break; + } + + // Check command packet data length + l_datalength = CMDH_DATALEN_FIELD_UINT16(i_cmd_ptr); + if(l_datalength != (sizeof(mnfg_quad_pstate_cmd_t) - + sizeof(cmdh_fsp_cmd_header_t))) + { + TRAC_ERR("cmdh_mnfg_request_quad_pstate: incorrect data length. exp[%d] act[%d]", + (sizeof(mnfg_quad_pstate_cmd_t) - + sizeof(cmdh_fsp_cmd_header_t)), + l_datalength); + l_rc = ERRL_RC_INVALID_CMD_LEN; + break; + } + + // Check version + if(l_cmd_ptr->version != MFG_QUAD_PSTATE_VERSION) + { + TRAC_ERR("cmdh_mnfg_request_quad_pstate: incorrect version. exp[%d] act[%d]", + MFG_QUAD_PSTATE_VERSION, + l_cmd_ptr->version); + l_rc = ERRL_RC_INVALID_DATA; + break; + } + + // only allow a Pstate within the current range based on mode + l_pmin = proc_freq2pstate(g_amec->sys.fmin); + l_pmax = proc_freq2pstate(g_amec->sys.fmax); + + // Process each quad Pstate request, clip any request to min/max + // 0xFF has special meaning that OCC is in control + for(l_quad = 0; l_quad < MAX_QUADS; l_quad++) + { + l_pstate_request = l_cmd_ptr->quad_pstate_in[l_quad]; + if(l_pstate_request != 0xFF) + { + // pmin is lowest frequency corresponding to highest pState value + if(l_pstate_request > l_pmin) + l_pstate_request = l_pmin; + + // pmax is highest frequency corresponding to lowest pState value + else if(l_pstate_request < l_pmax) + l_pstate_request = l_pmax; + } + // save the quad pState request for amec and return in rsp data + g_amec->mnfg_parms.quad_pstate[l_quad] = l_pstate_request; + l_rsp_ptr->quad_pstate_out[l_quad] = l_pstate_request; + TRAC_INFO("cmdh_mnfg_request_quad_pstate: Quad %d Pstate in = 0x%02x Pstate out = 0x%02x", + l_quad, + l_cmd_ptr->quad_pstate_in[l_quad], + l_rsp_ptr->quad_pstate_out[l_quad]); + } + + }while(0); + + // Populate the response data header + G_rsp_status = l_rc; + l_resp_data_length = sizeof(mnfg_quad_pstate_rsp_t) - sizeof(cmdh_fsp_rsp_header_t); + l_rsp_ptr->data_length[0] = ((uint8_t *)&l_resp_data_length)[0]; + l_rsp_ptr->data_length[1] = ((uint8_t *)&l_resp_data_length)[1]; + + return l_rc; +} + + + // Function Specification // // Name: cmdh_mnfg_test_parse @@ -616,8 +717,8 @@ uint8_t cmdh_mnfg_get_sensor(const cmdh_fsp_cmd_t * i_cmd_ptr, // Description: This function parses the manufacturing commands sent via TMGT. // // End Function Specification -void cmdh_mnfg_test_parse (const cmdh_fsp_cmd_t * i_cmd_ptr, - cmdh_fsp_rsp_t * o_rsp_ptr) +errlHndl_t cmdh_mnfg_test_parse (const cmdh_fsp_cmd_t * i_cmd_ptr, + cmdh_fsp_rsp_t * o_rsp_ptr) { uint8_t l_rc = 0; uint8_t l_sub_cmd = 0; @@ -650,11 +751,10 @@ void cmdh_mnfg_test_parse (const cmdh_fsp_cmd_t * i_cmd_ptr, l_rc = cmdh_mnfg_mem_slew(i_cmd_ptr, o_rsp_ptr); break; - case MNFG_RETRIEVE_EAR: - case MNFG_SET_FMINMAX: - case MNFG_CPM_STRESS_CALI: - case MNFG_UV_CONTROL: - case MNFG_FCHECK_CONTROL: + case MNFG_QUAD_PSTATE: + l_rc = cmdh_mnfg_request_quad_pstate(i_cmd_ptr, o_rsp_ptr); + break; + default: // Should never get here... l_rc = ERRL_RC_INVALID_DATA; @@ -669,6 +769,7 @@ void cmdh_mnfg_test_parse (const cmdh_fsp_cmd_t * i_cmd_ptr, cmdh_build_errl_rsp(i_cmd_ptr, o_rsp_ptr, l_rc, &l_errl); } - return; + return l_errl; } + diff --git a/src/occ_405/cmdh/cmdh_mnfg_intf.h b/src/occ_405/cmdh/cmdh_mnfg_intf.h index c3a47d50..e96ce0c6 100755 --- a/src/occ_405/cmdh/cmdh_mnfg_intf.h +++ b/src/occ_405/cmdh/cmdh_mnfg_intf.h @@ -28,18 +28,15 @@ #include "cmdh_fsp.h" #include "sensor.h" +#include "p9_pstates_common.h" typedef enum { MNFG_RUN_STOP_SLEW = 0x02, MNFG_LIST_SENSORS = 0x05, MNFG_GET_SENSOR = 0x06, MNFG_OVERSUB_EMULATION = 0x07, - MNFG_RETRIEVE_EAR = 0x08, MNFG_MEMORY_SLEW = 0x09, - MNFG_SET_FMINMAX = 0x0A, - MNFG_CPM_STRESS_CALI = 0x0D, - MNFG_UV_CONTROL = 0x0E, - MNFG_FCHECK_CONTROL = 0x0F, + MNFG_QUAD_PSTATE = 0x0A, } MNFG_CMD; #define MNFG_INTF_SLEW_START 0x00 @@ -172,8 +169,26 @@ typedef struct __attribute__ ((packed)) uint16_t checksum; }cmdh_mfg_get_sensor_resp_t; -void cmdh_mnfg_test_parse (const cmdh_fsp_cmd_t * i_cmd_ptr, - cmdh_fsp_rsp_t * o_rsp_ptr); +#define MFG_QUAD_PSTATE_VERSION 0 + +// Used by OCC to get mnfg request quad pstate command +typedef struct __attribute__ ((packed)) +{ + struct cmdh_fsp_cmd_header; + uint8_t sub_cmd; + uint8_t version; + uint8_t quad_pstate_in[MAX_QUADS]; +}mnfg_quad_pstate_cmd_t; + +// Used by OCC firmware to respond to mnfg request quad pstate command +typedef struct __attribute__ ((packed)) +{ + struct cmdh_fsp_rsp_header; + uint8_t quad_pstate_out[MAX_QUADS]; +}mnfg_quad_pstate_rsp_t; + +errlHndl_t cmdh_mnfg_test_parse (const cmdh_fsp_cmd_t * i_cmd_ptr, + cmdh_fsp_rsp_t * o_rsp_ptr); uint8_t cmdh_mnfg_emulate_oversub(const cmdh_fsp_cmd_t * i_cmd_ptr, cmdh_fsp_rsp_t * o_rsp_ptr); @@ -187,4 +202,7 @@ uint8_t cmdh_mnfg_get_sensor(const cmdh_fsp_cmd_t * i_cmd_ptr, uint8_t cmdh_mnfg_run_stop_slew(const cmdh_fsp_cmd_t * i_cmd_ptr, cmdh_fsp_rsp_t * o_rsp_ptr); +uint8_t cmdh_mnfg_request_quad_pstate(const cmdh_fsp_cmd_t * i_cmd_ptr, + cmdh_fsp_rsp_t * o_rsp_ptr); + #endif diff --git a/src/occ_405/occ_sys_config.h b/src/occ_405/occ_sys_config.h index b774b76e..25e3bd83 100755 --- a/src/occ_405/occ_sys_config.h +++ b/src/occ_405/occ_sys_config.h @@ -39,7 +39,6 @@ #define MAX_NUM_OCC 4 #define MAX_NUM_NODES 4 #define MAX_NUM_CORES 24 -#define MAX_NUM_QUADS 6 #define NUM_CORES_PER_QUAD 4 #define MAX_THREADS_PER_CORE 4 #define MAX_NUM_CHIP_MODULES 4 diff --git a/src/occ_405/state.c b/src/occ_405/state.c index 15990851..03d1402f 100755 --- a/src/occ_405/state.c +++ b/src/occ_405/state.c @@ -40,6 +40,7 @@ #include #include "pgpe_interface.h" #include "pstate_pgpe_occ_api.h" +#include "amec_sys.h" extern bool G_mem_monitoring_allowed; extern task_t G_task_table[TASK_END]; // Global task table @@ -588,6 +589,10 @@ errlHndl_t SMGR_observation_to_active() static bool l_error_logged = FALSE; // To prevent trace and error log happened over and over int l_extRc = OCC_NO_EXTENDED_RC; int l_rc = 0; + + // clear mnfg quad pstate request to default OCC to control all quads + memset(&g_amec->mnfg_parms.quad_pstate[0], 0xFF, MAX_QUADS); + do { // NOTE that this is really unnecessary if you follow the TMGT OCC