Skip to content

Commit

Permalink
New mfg test command to set per quad pstate
Browse files Browse the repository at this point in the history
Change-Id: I3f3b187608b0bfaf83cfa612358b40257db7d5b6
RTC: 170583
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/37765
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: William A. Bryan <wilbryan@us.ibm.com>
Reviewed-by: Christopher J. Cain <cjcain@us.ibm.com>
Reviewed-by: Martha Broyles <mbroyles@us.ibm.com>
  • Loading branch information
marthabroyles committed Mar 13, 2017
1 parent 35eb166 commit ad7e525
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 40 deletions.
83 changes: 61 additions & 22 deletions src/occ_405/amec/amec_freq.c
Expand Up @@ -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];
Expand Down Expand Up @@ -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_idx<NUM_CORES_PER_QUAD; core_idx++) // scan quad cores
for (core_idx=0; core_idx<NUM_CORES_PER_QUAD; core_idx++) // loop thru all cores in quad
{
core_num = (quad*NUM_CORES_PER_QUAD) + core_idx; // loop through all cores
core_num = (quad*NUM_CORES_PER_QUAD) + core_idx;

// The higher the pstate number, the lower the frequency
if(pmax < proc_freq2pstate(g_amec->proc[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;
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/occ_405/amec/amec_sys.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

//-------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/occ_405/cmdh/cmdh_fsp.c
Expand Up @@ -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:
Expand Down
8 changes: 8 additions & 0 deletions src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c
Expand Up @@ -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);

Expand Down
117 changes: 109 additions & 8 deletions src/occ_405/cmdh/cmdh_mnfg_intf.c
Expand Up @@ -609,15 +609,116 @@ 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
//
// 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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}


32 changes: 25 additions & 7 deletions src/occ_405/cmdh/cmdh_mnfg_intf.h
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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
1 change: 0 additions & 1 deletion src/occ_405/occ_sys_config.h
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions src/occ_405/state.c
Expand Up @@ -40,6 +40,7 @@
#include <dimm.h>
#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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit ad7e525

Please sign in to comment.