summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormbroyles <mbroyles@us.ibm.com>2016-09-19 11:54:55 -0500
committerMartha Broyles <mbroyles@us.ibm.com>2016-09-29 11:28:53 -0400
commita57f623c26bdf3889703ed63334745c966c6096d (patch)
treeb2f81389aa3bf5a420c6a115d8c10ae787375ede
parentd137bd848a05d5afd8a9ee5c9803f421ebd0a922 (diff)
downloadtalos-occ-a57f623c26bdf3889703ed63334745c966c6096d.tar.gz
talos-occ-a57f623c26bdf3889703ed63334745c966c6096d.zip
Enable power capping and oversubscription. RTC:137621 RTC:133156
Change-Id: I98b745ccb56d89d066508d4195250b1bf446dbc6 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/29898 Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Christopher J. Cain <cjcain@us.ibm.com> Reviewed-by: Martha Broyles <mbroyles@us.ibm.com>
-rwxr-xr-xsrc/occ_405/amec/amec_data.c28
-rwxr-xr-xsrc/occ_405/amec/amec_freq.c120
-rw-r--r--src/occ_405/amec/amec_init.c4
-rwxr-xr-xsrc/occ_405/amec/amec_master_smh.c10
-rwxr-xr-xsrc/occ_405/amec/amec_oversub.c45
-rwxr-xr-xsrc/occ_405/amec/amec_oversub.h17
-rwxr-xr-xsrc/occ_405/amec/amec_pcap.c178
-rwxr-xr-xsrc/occ_405/amec/amec_pcap.h6
-rwxr-xr-xsrc/occ_405/amec/amec_service_codes.h3
-rwxr-xr-xsrc/occ_405/amec/amec_slave_smh.c16
-rwxr-xr-xsrc/occ_405/cent/centaur_control.c18
-rwxr-xr-xsrc/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c44
-rwxr-xr-xsrc/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.h24
-rwxr-xr-xsrc/occ_405/cmdh/cmdh_mnfg_intf.c79
-rwxr-xr-xsrc/occ_405/dcom/dcom.c9
-rw-r--r--src/occ_405/dimm/dimm_control.c41
-rwxr-xr-xsrc/occ_405/main.c10
-rwxr-xr-xsrc/occ_405/mode.c19
-rwxr-xr-xsrc/occ_405/mode.h5
-rw-r--r--src/occ_405/occ_service_codes.h2
-rwxr-xr-xsrc/occ_405/occ_sys_config.h22
-rwxr-xr-xsrc/occ_405/rtls/rtls.c6
-rwxr-xr-xsrc/occ_405/state.h16
23 files changed, 319 insertions, 403 deletions
diff --git a/src/occ_405/amec/amec_data.c b/src/occ_405/amec/amec_data.c
index a658f63..c5bde89 100755
--- a/src/occ_405/amec/amec_data.c
+++ b/src/occ_405/amec/amec_data.c
@@ -1,11 +1,11 @@
/* IBM_PROLOG_BEGIN_TAG */
/* This is an automatically generated prolog. */
/* */
-/* $Source: src/occ/amec/amec_data.c $ */
+/* $Source: src/occ_405/amec/amec_data.c $ */
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -110,9 +110,10 @@ errlHndl_t AMEC_data_write_fcurr(const OCC_MODE i_mode)
}
}
- // If we are in OpenPower environment, load this new range into DVFS
- // min/max for AMEC component
- if(G_occ_interrupt_type != FSP_SUPPORTED_OCC)
+ // If we are in OpenPower environment with OPAL, load this new range into DVFS
+ // min/max for AMEC component. PowerVM on BMC and FSP the min/max is set above
+ // in amec_set_freq_range() based on mode
+ if((G_occ_interrupt_type != FSP_SUPPORTED_OCC) && (G_sysConfigData.system_type.kvm))
{
g_amec->sys.fmax = G_proc_fmax;
g_amec->sys.fmin = G_proc_fmin; // = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY]
@@ -131,8 +132,7 @@ errlHndl_t AMEC_data_write_fcurr(const OCC_MODE i_mode)
//
// Description: This function loads data from the Thermal Control Threshold
// data packet (format 0x13) into g_amec structure. This function should be
-// called when OCC goes active or changes modes or goes in/out of Acoustic
-// mode (ITE-only mode).
+// called when OCC goes active or changes modes
//
// Thread: RealTime Loop
//
@@ -166,8 +166,6 @@ errlHndl_t AMEC_data_write_thrm_thresholds(const OCC_MODE i_mode)
l_frudata = l_data->data;
- // TODO: Need to check if acoustic mode has been enabled (ITE-only mode)
-
// Store the processor thermal data
if(i_mode == OCC_MODE_NOMINAL)
{
@@ -346,6 +344,11 @@ errlHndl_t AMEC_data_change(const uint32_t i_data_mask)
if(i_data_mask & DATA_MASK_FREQ_PRESENT)
{
l_err = AMEC_data_write_fcurr(l_cur_mode);
+
+ if(l_err)
+ {
+ TRAC_ERR("AMEC_data_change: Error writing frequency range!");
+ }
}
else if(i_data_mask & DATA_MASK_THRM_THRESHOLDS)
{
@@ -405,13 +408,6 @@ void amec_data_write_pcap(void)
memcpy(&(G_sysConfigData.pcap),&(G_dcom_slv_inbox_doorbell_rx.pcap),
sizeof(pcap_config_data_t));
- //Affects ITE ONLY: Check if it's ok (1) to exit the oversubscribed state
- if(1 == G_sysConfigData.pcap.unthrottle)
- {
- //Clear throttle flag
- g_amec->oversub_status.cmeThrottleLatchAmec = 0;
- }
-
//Check node power cap requested by customer/system.
// 0 means there is no pcap for that parameter.
if(0 == G_sysConfigData.pcap.current_pcap)
diff --git a/src/occ_405/amec/amec_freq.c b/src/occ_405/amec/amec_freq.c
index 5cc198f..0f7d764 100755
--- a/src/occ_405/amec/amec_freq.c
+++ b/src/occ_405/amec/amec_freq.c
@@ -165,52 +165,84 @@ errlHndl_t amec_set_freq_range(const OCC_MODE i_mode)
l_freq_max = G_sysConfigData.sys_mode_freq.table[i_mode];
}
- // If SMS is set then TMGT wants us to pin to frequency which
- // corresponds to input mode. They will use this function
- // when powering off and they wish to have us bring the system
- // back up to real nominal frequency (without being impacted
- // by power caps or thermal actuations)
- if(CURRENT_SMS() == SMGR_SMS_STATIC_VF_CHANGE_REQ)
+ if( (l_freq_min == 0) || (l_freq_max == 0) )
{
- l_freq_min = l_freq_max;
+ // Do not update amec vars with a 0 frequency.
+ // The frequency limit for each mode should have been set prior
+ // to calling or the mode passed was invalid
+ TRAC_ERR("amec_set_freq_range: Freq of 0 found! mode[0x%02x] Fmin[%u] Fmax[%u]",
+ i_mode,
+ l_freq_min,
+ l_freq_max);
+
+ // Log an error if this is PowerVM as this should never happen when OCC
+ // supports modes
+ if(!G_sysConfigData.system_type.kvm)
+ {
+ /* @
+ * @errortype
+ * @moduleid AMEC_SET_FREQ_RANGE
+ * @reasoncode INTERNAL_FW_FAILURE
+ * @userdata1 Mode
+ * @userdata2 0
+ * @userdata4 ERC_FW_ZERO_FREQ_LIMIT
+ * @devdesc Fmin or Fmax of 0 found for mode
+ */
+ errlHndl_t l_err = createErrl(AMEC_SET_FREQ_RANGE, //modId
+ INTERNAL_FW_FAILURE, //reasoncode
+ ERC_FW_ZERO_FREQ_LIMIT, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ i_mode, //userdata1
+ 0); //userdata2
+
+ // Callout Firmware
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_LOW
+ );
+ }
+ }
+ else
+ {
+ 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]",
+ i_mode,
+ l_freq_min,
+ l_freq_max);
+
+ // 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];
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_DYN_POWER_SAVE];
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_DYN_POWER_SAVE_FP];
+
+ // Determine the min frequency for the PPM structure. This Fmin should
+ // always be set to the system Fmin
+ l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+
+ // Determine the min speed allowed for DPS power policies (this is needed
+ // by the DPS algorithms)
+ l_temp = (l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmin * 1000)/l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax;
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS].min_speed = l_temp;
+
+ l_temp = (l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmin * 1000)/l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmax;
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].min_speed = l_temp;
+
+ // Copy the PPM frequency information into g_amec
+ memcpy(g_amec->part_mode_freq, l_ppm_freq, sizeof(l_ppm_freq));
+
+ TRAC_INFO("amec_set_freq_range: PPM Fmin[%u] Fnom[%u] Fmax[%u] min_speed[%u]",
+ l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmin,
+ l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmax,
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax,
+ l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].min_speed);
}
-
- 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]",
- i_mode,
- l_freq_min,
- l_freq_max);
-
- // 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];
- l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_DYN_POWER_SAVE];
- l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmax = G_sysConfigData.sys_mode_freq.table[OCC_MODE_DYN_POWER_SAVE_FP];
-
- // Determine the min frequency for the PPM structure. This Fmin should
- // always be set to the system Fmin
- l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
- l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
- l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
-
- // Determine the min speed allowed for DPS power policies (this is needed
- // by the DPS algorithms)
- l_temp = (l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmin * 1000)/l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax;
- l_ppm_freq[OCC_INTERNAL_MODE_DPS].min_speed = l_temp;
-
- l_temp = (l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmin * 1000)/l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].fmax;
- l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].min_speed = l_temp;
-
- // Copy the PPM frequency information into g_amec
- memcpy(g_amec->part_mode_freq, l_ppm_freq, sizeof(l_ppm_freq));
-
- TRAC_INFO("amec_set_freq_range: PPM Fmin[%u] Fnom[%u] Fmax[%u] min_speed[%u]",
- l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmin,
- l_ppm_freq[OCC_INTERNAL_MODE_NOM].fmax,
- l_ppm_freq[OCC_INTERNAL_MODE_DPS].fmax,
- l_ppm_freq[OCC_INTERNAL_MODE_DPS_MP].min_speed);
-
return l_err;
}
diff --git a/src/occ_405/amec/amec_init.c b/src/occ_405/amec/amec_init.c
index e0fdd84..b89f038 100644
--- a/src/occ_405/amec/amec_init.c
+++ b/src/occ_405/amec/amec_init.c
@@ -285,6 +285,10 @@ void amec_init_gamec_struct(void)
g_amec->vrhotproc.freq_request = -1;
g_amec->vrhotproc.speed_request = 1000;
+ // Initialize component power caps
+ g_amec->pcap.active_proc_pcap = 0;
+ g_amec->pcap.active_mem_level = 0;
+
// @TODO - TEMP: not ready yet in Phase 1
/*
// Initialize partition information
diff --git a/src/occ_405/amec/amec_master_smh.c b/src/occ_405/amec/amec_master_smh.c
index c49ca06..c980f3a 100755
--- a/src/occ_405/amec/amec_master_smh.c
+++ b/src/occ_405/amec/amec_master_smh.c
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -457,11 +457,13 @@ void amec_mst_check_under_pcap(void)
/* Code */
/*------------------------------------------------------------------------*/
- // Check if ppb_fmax = Fmin and PWR250US > Node power cap and
- // Node power cap >= hard_min_pcap
+ // Check if done everything possible to shed power and power still above a hard power cap
+ // ppb_fmax = Fmin and PWR250US > Node power cap and
+ // Node power cap >= hard_min_pcap AND memory is throttled
if((g_amec->proc[0].pwr_votes.ppb_fmax == g_amec->sys.fmin) &&
(AMECSENSOR_PTR(PWR250US)->sample > g_amec->pcap.active_node_pcap) &&
- (g_amec->pcap.active_node_pcap >= G_sysConfigData.pcap.hard_min_pcap))
+ (g_amec->pcap.active_node_pcap >= G_sysConfigData.pcap.hard_min_pcap) &&
+ (g_amec->pcap.active_mem_level != 0) )
{
G_over_cap_count++;
diff --git a/src/occ_405/amec/amec_oversub.c b/src/occ_405/amec/amec_oversub.c
index 6b5ab3c..0a5993b 100755
--- a/src/occ_405/amec/amec_oversub.c
+++ b/src/occ_405/amec/amec_oversub.c
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -68,21 +68,17 @@
// Function Specification
//
-// Name: amec_oversub_pmax_clip
+// Name: amec_set_pmax_clip
//
-// Description: Set Pmax_Clip in PMC to lowest Pstate
+// Description: Set Pmax_Clip in PMC to Pstate
//
// Task Flags:
//
// End Function Specification
-void amec_oversub_pmax_clip(Pstate i_pstate)
+void amec_set_pmax_clip(Pstate i_pstate)
{
- pmc_rail_bounds_register_t prbr;
+ // TODO: Send IPC cmd to PGPE to set Pmax_Clip
- // Set Pmax_Clip in PMC to lowest Pstate
- prbr.value = in32(PMC_RAIL_BOUNDS_REGISTER);
- prbr.fields.pmax_rail = i_pstate;
- out32(PMC_RAIL_BOUNDS_REGISTER, prbr.value);
}
// Function Specification
@@ -107,13 +103,9 @@ void amec_oversub_isr(void)
// SSX_IRQ_POLARITY_ACTIVE_LOW means over-subscription is active
if(l_polarity == SSX_IRQ_POLARITY_ACTIVE_LOW)
{
- // If RTL doesn't control it, do it here
- if(g_amec->oversub_status.oversubLatchAmec == 0)
- {
- // TODO: Throttle all Centaurs via PORE-GPE by setting 'Emergency Throttle'
-
- g_amec->oversub_status.oversubReasonLatchCount = OVERSUB_REASON_DELAY_4MS;
- }
+ // oversub only switches pcap in amec_pcap_calc
+ // throttling only done if actually needed due to reaching power cap
+ g_amec->oversub_status.oversubReasonLatchCount = OVERSUB_REASON_DELAY_4MS;
// Set oversubPinLive and oversubActiveTime
g_amec->oversub_status.oversubPinLive = 1;
@@ -159,27 +151,8 @@ void amec_oversub_isr(void)
// End Function Specification
void amec_oversub_check(void)
{
- uint8_t l_cme_pin_value = 1; // low active, so set default to high
static BOOLEAN l_prev_ovs_state = FALSE; // oversub happened
- // Get CME Pin state
- // No longer reading gpio from APSS in GA1 due to instability in APSS composite mode
- //apss_gpio_get(l_cme_pin, &l_cme_pin_value);
-
- // Check CME Pin? OR CME Oversub Mnfg Active
- if( (l_cme_pin_value == 0) ||
- (g_amec->oversub_status.cmeThrottlePinMnfg == 1) )
- {
- g_amec->oversub_status.cmeThrottlePinLive = 1;
- g_amec->oversub_status.cmeThrottleLatchAmec = 1;
- }
- else
- {
- // Do not clear cmeThrottleLatchAmec.
- // That will only be done via the PowerCa command from TMGT.
- g_amec->oversub_status.cmeThrottlePinLive = 0;
- }
-
// oversubscription condition happened?
if ( AMEC_INTF_GET_OVERSUBSCRIPTION() == TRUE )
{
@@ -226,7 +199,7 @@ void amec_oversub_check(void)
// Figure out the over-subscription reason
if(g_amec->oversub_status.oversubReasonLatchCount > 1)
{
- // Try to figure out why we throttled based on APSS GPIO pins
+ // TODO: Try to figure out why we throttled based on APSS GPIO pins
if( g_amec->oversub_status.oversubReasonLatchCount == OVERSUB_REASON_COUNT_TIMEOUT)
{
g_amec->oversub_status.oversubReason = INDETERMINATE;
diff --git a/src/occ_405/amec/amec_oversub.h b/src/occ_405/amec/amec_oversub.h
index 6d17a19..8da6f76 100755
--- a/src/occ_405/amec/amec_oversub.h
+++ b/src/occ_405/amec/amec_oversub.h
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -69,10 +69,6 @@ typedef struct oversub_status
// Live Status of oversub Pin
uint32_t oversubPinLive : 1;
- // AMEC status of oversub pin, so it doesn't
- // change mid-RTL
- uint32_t oversubLatchAmec : 1;
-
// Used for SRC logging of performance loss,
// need to have countdown b/c we don't get
// APSS gpio signals as quick as we get
@@ -86,15 +82,6 @@ typedef struct oversub_status
// For debug, tracks time oversub last went active
SsxTimebase oversubActiveTime;
- // Live status of CME throttle pin, doesn't change mid-RTL
- uint32_t cmeThrottlePinLive :1;
-
- // Status of CME Throttle, doesn't get cleared until MM/TMGT
- // tells us to clear it/un-throttle.
- uint32_t cmeThrottleLatchAmec :1;
-
- // Way to emulate cmeThrottle for MNFG or Developers
- uint32_t cmeThrottlePinMnfg :1;
}oversub_status_t;
/*----------------------------------------------------------------------------*/
@@ -105,7 +92,7 @@ void amec_oversub_isr(void);
void amec_oversub_check(void);
-void amec_oversub_pmax_clip(Pstate i_pstate);
+void amec_set_pmax_clip(Pstate i_pstate);
bool apss_gpio_get(uint8_t i_pin_number, uint8_t *o_pin_value);
diff --git a/src/occ_405/amec/amec_pcap.c b/src/occ_405/amec/amec_pcap.c
index fcc70aa..bf05c04 100755
--- a/src/occ_405/amec/amec_pcap.c
+++ b/src/occ_405/amec/amec_pcap.c
@@ -1,11 +1,11 @@
/* IBM_PROLOG_BEGIN_TAG */
/* This is an automatically generated prolog. */
/* */
-/* $Source: src/occ/amec/amec_pcap.c $ */
+/* $Source: src/occ_405/amec/amec_pcap.c $ */
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -81,76 +81,13 @@ uint8_t G_over_pcap_count=0;
// Functions
//*************************************************************************/
-//////////////////////////
-// Function Specification
-//
-// Name: amec_pmax_clip_controller
-//
-// Description: Calculate the pmax_clip_freq vote. Initialized to Turbo.
-//
-// Thread: Real Time Loop
-//
-// End Function Specification
-void amec_pmax_clip_controller(void)
-{
-// @TODO - TEMP Pstate functions not defined yet
-#if 0
- /*------------------------------------------------------------------------*/
- /* Local Variables */
- /*------------------------------------------------------------------------*/
- uint16_t l_fturbo = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
- uint32_t l_pmax_clip_freq = g_amec->proc[0].pwr_votes.pmax_clip_freq;
- Pstate l_pstate = 0;
-
- /*------------------------------------------------------------------------*/
- /* Code */
- /*------------------------------------------------------------------------*/
-
- //Note: quickPowerDrop interrupts will not preempt the real time loop
- // interrupt. No locking is needed between the two interrupts.
- //Note: oversubLatchAmec represents the oversubscription signal
-
- // See the oversub event and control oversub in AMEC
- if(AMEC_INTF_GET_OVERSUBSCRIPTION()&&
- (g_amec->oversub_status.oversubLatchAmec==FALSE) )
- {
- // ISR already did it but still need to do it again here due to
- // l_pmax_clip_freq is incorrect
- l_pmax_clip_freq = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
- g_amec->oversub_status.oversubLatchAmec = TRUE;
- }
- else if( !AMEC_INTF_GET_OVERSUBSCRIPTION() )
- {
- // AMEC doesn't control it and let ISR do it
- g_amec->oversub_status.oversubLatchAmec = FALSE;
- }
-
- if(l_pmax_clip_freq < l_fturbo)
- {
- l_pmax_clip_freq += G_mhz_per_pstate;
-
- if(l_pmax_clip_freq > l_fturbo)
- {
- l_pmax_clip_freq = l_fturbo;
- }
-
- //call proc_freq2pstate
- l_pstate = proc_freq2pstate(l_pmax_clip_freq);
-
- //Set the pmax_clip register via OCI write.
- amec_oversub_pmax_clip(l_pstate);
- }
-
- g_amec->proc[0].pwr_votes.pmax_clip_freq = l_pmax_clip_freq;
-#endif // @TODO - TEMP Pstate functions not defined yet
-}
//////////////////////////
// Function Specification
//
// Name: amec_pcap_calc
//
-// Description: Calculate the node power cap and the processor power cap.
+// Description: Calculate the node, memory and processor power caps.
//
// Thread: Real Time Loop
//
@@ -164,18 +101,23 @@ void amec_pcap_calc(void)
uint16_t l_node_pwr = AMECSENSOR_PTR(PWR250US)->sample;
uint16_t l_p0_pwr = AMECSENSOR_PTR(PWR250USP0)->sample;
int32_t l_avail_power = 0;
+ uint16_t mem_pwr_diff = 0;
uint32_t l_proc_fraction = 0;
static uint32_t L_prev_node_pcap = 0;
- static bool l_apss_error_traced = FALSE;
+ static bool L_apss_error_traced = FALSE;
/*------------------------------------------------------------------------*/
/* Code */
/*------------------------------------------------------------------------*/
- //TRAC_INFO("amec_pcap_calc: Calculate active_node_pcap, and nom_pcap_fmin.");
l_oversub_state = AMEC_INTF_GET_OVERSUBSCRIPTION();
- if(TRUE == l_oversub_state)
+ // Determine the active power cap. norm_node_pcap is set as lowest
+ // between sys and user in amec_data_write_pcap()
+ // when in oversub only use oversub pcap if lower than norm_node_pcap
+ // to handle user set power cap lower than the oversub power cap
+ if( (TRUE == l_oversub_state) &&
+ (g_amec->pcap.ovs_node_pcap < g_amec->pcap.norm_node_pcap) )
{
g_amec->pcap.active_node_pcap = g_amec->pcap.ovs_node_pcap;
}
@@ -199,36 +141,78 @@ void amec_pcap_calc(void)
if(l_node_pwr != 0)
{
l_proc_fraction = ((uint32_t)(l_p0_pwr) << 16)/l_node_pwr;
- if(l_apss_error_traced)
+ if(L_apss_error_traced)
{
TRAC_ERR("PCAP: PWR250US sensor is no longer 0.");
- l_apss_error_traced = FALSE;
+ L_apss_error_traced = FALSE;
+ }
+
+ // check if allowed to increase power AND memory throttled due to pcap
+ if((l_avail_power > 0) && (g_amec->pcap.active_mem_level != 0))
+ {
+ // un-throttle memory if there is enough available power between
+ // current and new throttles
+ if (CURRENT_MODE() == OCC_MODE_NOMINAL)
+ {
+ mem_pwr_diff = g_amec->pcap.nominal_mem_pwr;
+ }
+ else
+ {
+ mem_pwr_diff = g_amec->pcap.turbo_mem_pwr;
+ }
+
+ // currently there's only 1 mem pcap throt level so must be pcap1
+ mem_pwr_diff -= g_amec->pcap.pcap1_mem_pwr;
+
+ if(l_avail_power >= mem_pwr_diff)
+ {
+ TRAC_IMP("PCAP: Un-Throttling memory");
+ g_amec->pcap.active_mem_level = 0;
+ // don't let the proc have any available power this tick
+ l_avail_power = 0;
+ }
+ }
+ // check if need to reduce power and frequency is already at the min
+ else if((l_avail_power < 0) && (g_amec->proc[0].pwr_votes.ppb_fmax == g_amec->sys.fmin))
+ {
+ // frequency at min now shed additional power by throttling
+ // memory if memory is currently un-throttled due to power
+ if (g_amec->pcap.active_mem_level == 0)
+ {
+ TRAC_IMP("PCAP: Throttling memory");
+ g_amec->pcap.active_mem_level = 1;
+ }
+ }
+ else
+ {
+ // no changes to memory throttles due to power
}
}
else
{
- if(!l_apss_error_traced)
+ if(!L_apss_error_traced)
{
TRAC_ERR("PCAP: PWR250US sensor is showing a value of 0.");
- l_apss_error_traced = TRUE;
+ L_apss_error_traced = TRUE;
}
}
- g_amec->pcap.active_proc_pcap = l_p0_pwr + ((l_proc_fraction * l_avail_power) >> 16);
-
- //TRAC_INFO("PCAP: calculated active proc pcap: avail_power[0x%X],proc_fraction[0x%X],"
- // "active_proc_pcap[0x%X].",l_avail_power,l_proc_fraction,g_amec->pcap.active_proc_pcap);
-
- //NOTE: Power capping will not affect nominal cores unless a customer power cap is set below the
- // max pcap or oversubscription occurs.
- // However, nominal cores will drop below nominal if ppb_fmax drops below nominal.
- if(g_amec->pcap.active_node_pcap < G_sysConfigData.pcap.max_pcap)
+ // skip processor changes until memory is un-capped
+ if(!g_amec->pcap.active_mem_level)
{
- g_amec->proc[0].pwr_votes.nom_pcap_fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
- }
- else
- {
- g_amec->proc[0].pwr_votes.nom_pcap_fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL];
+ g_amec->pcap.active_proc_pcap = l_p0_pwr + ((l_proc_fraction * l_avail_power) >> 16);
+
+ //NOTE: Power capping will not affect nominal cores unless a customer pcap
+ // is set below the max pcap or oversubscription occurs. However,
+ // nominal cores will drop below nominal if ppb_fmax drops below nominal
+ if(g_amec->pcap.active_node_pcap < G_sysConfigData.pcap.max_pcap)
+ {
+ g_amec->proc[0].pwr_votes.nom_pcap_fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+ }
+ else
+ {
+ g_amec->proc[0].pwr_votes.nom_pcap_fmin = G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL];
+ }
}
}
@@ -510,21 +494,21 @@ void amec_power_control(void)
/* Code */
/*------------------------------------------------------------------------*/
- // Call amec pmax clip controller to control the Pmax_clip register setting
- // and voting box input.
- amec_pmax_clip_controller();
-
- // Calculate the power cap for the processor and the power capping limit
+ // Calculate the pcap for the proc, memory and the power capping limit
// for nominal cores.
amec_pcap_calc();
- // Calculate the voting box input frequency for staying with the current pcap
- amec_pcap_controller();
+ // skip processor changes until memory is un-capped
+ if(!g_amec->pcap.active_mem_level)
+ {
+ // Calculate voting box input freq for staying with the current pcap
+ amec_pcap_controller();
- // Calculate the performance preserving bounds voting box input frequency.
- amec_ppb_fmax_calc();
+ // Calculate the performance preserving bounds voting box input freq
+ amec_ppb_fmax_calc();
+ }
- // Check for connector overcurrent condition and calculate voting box input frequency.
+ // Check for connector oc condition and calculate voting box input freq
amec_conn_oc_controller();
}
diff --git a/src/occ_405/amec/amec_pcap.h b/src/occ_405/amec/amec_pcap.h
index 47a065b..70c9147 100755
--- a/src/occ_405/amec/amec_pcap.h
+++ b/src/occ_405/amec/amec_pcap.h
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -55,6 +55,10 @@ typedef struct amec_pcap
uint16_t norm_node_pcap; //Normal node power cap in 1W units
uint16_t active_node_pcap; //Currently active node power cap in 1W units
uint16_t active_proc_pcap; //Currently active proc power cap in 1W units
+ uint16_t nominal_mem_pwr; //Memory power in 1W units for nominal throttles
+ uint16_t turbo_mem_pwr; //Memory power in 1W units for turbo throttles
+ uint16_t pcap1_mem_pwr; //Memory power in 1W units for power capping level 1 throttles
+ uint8_t active_mem_level; //Currently active memory throttles pcap level 0=no active mem pcap
} amec_pcap_t;
//*************************************************************************
diff --git a/src/occ_405/amec/amec_service_codes.h b/src/occ_405/amec/amec_service_codes.h
index 73146a2..ddc92e0 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,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -65,6 +65,7 @@ enum occAmecModuleId
AMEC_HEALTH_CHECK_PROC_TIMEOUT = AMEC_COMP_ID | 0x14,
AMEC_HEALTH_CHECK_PROC_VRHOT = AMEC_COMP_ID | 0x15,
AMEC_CALC_DTS_SENSORS = AMEC_COMP_ID | 0x16,
+ AMEC_SET_FREQ_RANGE = AMEC_COMP_ID | 0x17,
};
/*----------------------------------------------------------------------------*/
diff --git a/src/occ_405/amec/amec_slave_smh.c b/src/occ_405/amec/amec_slave_smh.c
index c42c815..c3f5454 100755
--- a/src/occ_405/amec/amec_slave_smh.c
+++ b/src/occ_405/amec/amec_slave_smh.c
@@ -245,8 +245,9 @@ void amec_slv_check_apss_fail(void)
l_pmax_rail_freq = G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL];
l_pstate = proc_freq2pstate(l_pmax_rail_freq);
- // Set the Pmax_rail register via OCI write
- amec_oversub_pmax_clip(l_pstate);
+ // Set the Pmax clip via PGPE
+ // There is no Pmax "rail" in P9, just set clips via PGPE
+ amec_set_pmax_clip(l_pstate);
L_lower_pmax_rail = TRUE;
L_raise_pmax_rail = FALSE;
@@ -260,8 +261,8 @@ void amec_slv_check_apss_fail(void)
l_pmax_rail_freq = G_sysConfigData.sys_mode_freq.table[OCC_MODE_TURBO];
l_pstate = proc_freq2pstate(l_pmax_rail_freq);
- // Set the Pmax_rail register via OCI write
- amec_oversub_pmax_clip(l_pstate);
+ // Set the Pmax clip via PGPE
+ amec_set_pmax_clip(l_pstate);
L_lower_pmax_rail = FALSE;
L_raise_pmax_rail = TRUE;
@@ -293,10 +294,6 @@ void amec_slv_common_tasks_pre(void)
// Update the FW Worst Case sensors every tick
amec_update_fw_sensors();
- // Update the fast core data sensors every tick
-// @TODO - TEMP - Not ready yet in Phase 1
-// amec_update_fast_core_data_sensors();
-
// Update the sensors that come from the APSS every tick
amec_update_apss_sensors();
@@ -324,8 +321,7 @@ void amec_slv_common_tasks_pre(void)
amec_update_current_sensor(); // Compute estimate for Vdd output current
// Over-subscription check
-// @TODO - TEMP - Not ready yet in Phase 1
-// amec_oversub_check();
+ amec_oversub_check();
}
// Function Specification
diff --git a/src/occ_405/cent/centaur_control.c b/src/occ_405/cent/centaur_control.c
index 461d7c9..08e3005 100755
--- a/src/occ_405/cent/centaur_control.c
+++ b/src/occ_405/cent/centaur_control.c
@@ -1,11 +1,11 @@
/* IBM_PROLOG_BEGIN_TAG */
/* This is an automatically generated prolog. */
/* */
-/* $Source: src/occ/cent/centaur_control.c $ */
+/* $Source: src/occ_405/cent/centaur_control.c $ */
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2014,2015 */
+/* Contributors Listed Below - COPYRIGHT 2014,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -178,17 +178,27 @@ void cent_update_nlimits(uint32_t i_cent)
l_active_limits01->min_n_per_mba = l_state_limits01->min_n_per_mba;
l_active_limits23->min_n_per_mba = l_state_limits23->min_n_per_mba;
- if(CURRENT_MODE() == OCC_MODE_NOMINAL)
+ //Power Capping memory?
+ if(g_amec->pcap.active_mem_level == 1)
+ {
+ l_mba01_mba_maxn = l_state_limits01->pcap_n_per_mba;
+ l_mba01_chip_maxn = l_state_limits01->pcap_n_per_chip;
+ l_mba23_mba_maxn = l_state_limits23->pcap_n_per_mba;
+ l_mba23_chip_maxn = l_state_limits23->pcap_n_per_chip;
+ }
+ else if(CURRENT_MODE() == OCC_MODE_NOMINAL)
{
l_mba01_mba_maxn = l_state_limits01->nom_n_per_mba;
l_mba01_chip_maxn = l_state_limits01->nom_n_per_chip;
l_mba23_mba_maxn = l_state_limits23->nom_n_per_mba;
l_mba23_chip_maxn = l_state_limits23->nom_n_per_chip;
}
- else //DPS, TURBO, FFO, and SPS modes will use these settings
+ else //all other modes will use turbo settings
{
l_mba01_mba_maxn = l_state_limits01->turbo_n_per_mba;
+ l_mba01_chip_maxn = l_state_limits01->turbo_n_per_chip;
l_mba23_mba_maxn = l_state_limits23->turbo_n_per_mba;
+ l_mba23_chip_maxn = l_state_limits23->turbo_n_per_chip;
}
l_active_limits01->max_n_per_chip = l_mba01_chip_maxn;
diff --git a/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c b/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c
index 33cefed..e4e2414 100755
--- a/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c
+++ b/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c
@@ -1696,6 +1696,9 @@ errlHndl_t data_store_mem_throt(const cmdh_fsp_cmd_t * i_cmd_ptr,
uint8_t i;
uint16_t l_configured_mbas = 0;
bool l_invalid_input = TRUE; //Assume bad input
+ uint32_t l_total_turbo_mem_power = 0;
+ uint32_t l_total_nominal_mem_power = 0;
+ uint32_t l_total_pcap_mem_power = 0;
do
{
@@ -1777,8 +1780,8 @@ errlHndl_t data_store_mem_throt(const cmdh_fsp_cmd_t * i_cmd_ptr,
// Copy into a temporary buffer while we check for N values of 0
memcpy(&l_temp_set, &(l_data_set->min_n_per_mba), sizeof(mem_throt_config_data_t));
- // A 0 for any N value is an error
- for(l_n_ptr = &l_temp_set.min_n_per_mba; l_n_ptr <= &l_temp_set.reserved_mem_power; l_n_ptr++)
+ // A 0 for any power or N value is an error
+ for(l_n_ptr = &l_temp_set.min_n_per_mba; l_n_ptr <= &l_temp_set.nom_mem_power; l_n_ptr++)
{
if(!(*l_n_ptr))
{
@@ -1818,38 +1821,29 @@ errlHndl_t data_store_mem_throt(const cmdh_fsp_cmd_t * i_cmd_ptr,
l_configured_mbas |= 1 << ((cent* NUM_MBAS_PER_CENTAUR) + mba);
}
- } // data_sets for loop
- if(l_err) // Invalid Info Parameter?
- {
- break;
- }
+ // Add memory power
+ l_total_turbo_mem_power += l_data_set->turbo_mem_power;
+ l_total_nominal_mem_power += l_data_set->nom_mem_power;
+ l_total_pcap_mem_power += l_data_set->pcap_mem_power;
- } while(0);
+ } // data_sets for loop
+ } while(0);
if(!l_err)
{
// If there were no errors, indicate that we got this data
G_data_cnfg->data_mask |= DATA_MASK_MEM_THROT;
+ CMDH_TRAC_IMP("data_store_mem_throt: Got valid mem throt packet. configured_mba_bitmap=0x%04x",
+ l_configured_mbas);
- if(MEM_TYPE_NIMBUS == G_sysConfigData.mem_type)
- {
- CMDH_TRAC_IMP("data_store_mem_throt: Got valid mem throt packet. "
- "configured DIMM bitmap=0x%04x",
- l_configured_mbas);
- }
- else if (MEM_TYPE_CUMULUS == G_sysConfigData.mem_type)
- {
- CMDH_TRAC_IMP("data_store_mem_throt: Got valid centaur mem throt packet. "
- "configured_mba_bitmap=0x%04x",
- l_configured_mbas);
-
- }
-
- // Update the configured mba bitmap
+ // Update the configured mba bitmap and save the total memory powers
G_configured_mbas = l_configured_mbas;
-
+ // g_amec is in Watts, config data is in cW
+ g_amec->pcap.nominal_mem_pwr = l_total_nominal_mem_power / 100;
+ g_amec->pcap.turbo_mem_pwr = l_total_turbo_mem_power / 100;
+ g_amec->pcap.pcap1_mem_pwr = l_total_pcap_mem_power / 100;
}
return l_err;
@@ -2181,7 +2175,7 @@ errlHndl_t DATA_store_cnfgdata (const cmdh_fsp_cmd_t * i_cmd_ptr,
if((!l_errlHndl) && (l_new_data))
{
// Notify AMEC component of new data
- AMEC_data_change(l_new_data);
+ l_errlHndl = AMEC_data_change(l_new_data);
}
if(l_errlHndl)
diff --git a/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.h b/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.h
index 4c0f3ad..206bdc5 100755
--- a/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.h
+++ b/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.h
@@ -1,11 +1,11 @@
/* IBM_PROLOG_BEGIN_TAG */
/* This is an automatically generated prolog. */
/* */
-/* $Source: src/occ/cmdh/cmdh_fsp_cmds_datacnfg.h $ */
+/* $Source: src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.h $ */
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -287,7 +287,7 @@ typedef struct __attribute__ ((packed))
// Provides memory throttle min and max values for Nimbus systems
typedef struct __attribute__ ((packed))
{
- uint8_t mc_num; // Physical MC: [0=MC01, 2=MC23]
+ uint8_t mc_num; // Physical MC: [0=MC01, 1=MC23]
uint8_t port_num; // Physical port # [0-3]
} cmdh_mem_throt_nimbus_info_t;
@@ -310,23 +310,23 @@ typedef struct __attribute__ ((packed))
cmdh_mem_throt_info_t mem_throt_info; // Nimbus/Cumulus information header
uint16_t min_n_per_mba; // Lowest per MBA allowed numerator
- uint16_t min_mem_power; // Max mem Power @min (x0.1W)
+ uint16_t min_mem_power; // Max mem Power @min (x0.01W)
uint16_t turbo_n_per_mba; // Static per MBA numerator @Turbo
uint16_t turbo_n_per_chip; // Static per chip numerator @Turbo
- uint16_t turbo_mem_power; // Max memory power @Turbo (x0.1W)
+ uint16_t turbo_mem_power; // Max memory power @Turbo (x0.01W)
uint16_t pcap_n_per_mba; // Static per MBA numerator @PCAP
uint16_t pcap_n_per_chip; // Static per chip numerator @PCAP
- uint16_t pcap_mem_power; // Max memory power @PCAP (x0.1W)
+ uint16_t pcap_mem_power; // Max memory power @PCAP (x0.01W)
- uint16_t nom_n_per_mba; // Static per MBA @Redundant (no ovs)
- uint16_t nom_n_per_chip; // Static per chip @Redundant
- uint16_t nom_mem_power; // Max memory power @Redundant(x0.1W)
+ uint16_t nom_n_per_mba; // Static per MBA N for nominal mode
+ uint16_t nom_n_per_chip; // Static per chip N for nominal mode
+ uint16_t nom_mem_power; // Max memory power @nominal (x0.01W)
- uint16_t reserved_n_per_mba; // reserved
- uint16_t reserved_n_per_chip; // reserved
- uint16_t reserved_mem_power; // reserved
+ uint16_t reserved1; // reserved
+ uint16_t reserved2; // reserved
+ uint16_t reserved3; // reserved
} cmdh_mem_throt_data_set_t;
diff --git a/src/occ_405/cmdh/cmdh_mnfg_intf.c b/src/occ_405/cmdh/cmdh_mnfg_intf.c
index cd38489..edaf3bb 100755
--- a/src/occ_405/cmdh/cmdh_mnfg_intf.c
+++ b/src/occ_405/cmdh/cmdh_mnfg_intf.c
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -32,8 +32,6 @@
#include "sensor_query_list.h"
#include "amec_smh.h"
#include "amec_master_smh.h"
-#include "centaur_data.h"
-#include "centaur_control.h"
extern task_t G_task_table[TASK_END];
@@ -237,69 +235,22 @@ uint8_t cmdh_mnfg_mem_slew(const cmdh_fsp_cmd_t * i_cmd_ptr,
// If we made it here, that means we are starting up a slew run
TRAC_INFO("cmdh_mnfg_mem_slew: We are about to start auto-slewing function");
-// TEMP -- NOT SUPPORTED YET IN PHASE1
-// when implementing see dimm/dimm.c - memory_init()
-/*
- // Force activation of memory monitoring and control
- if(!rtl_task_is_runnable(TASK_ID_CENTAUR_CONTROL))
- {
- uint32_t l_cent, l_mba;
-
- // Only run initialization on an active OCC
- if(!IS_OCC_STATE_ACTIVE())
- {
- TRAC_ERR("cmdh_mnfg_mem_slew: OCC must be active to start mem slewing");
- l_rc = ERRL_RC_INVALID_STATE;
- break;
- }
-
- // Force all MBA's to be present
- G_configured_mbas = -1;
-
- TRAC_INFO("cmdh_mnfg_mem_slew: calling centaur_init()");
- centaur_init(); //no rc, handles errors internally
-
- // Check if centaur_init resulted in a reset
- // since we don't have a return code from centaur_init.
- if(isSafeStateRequested())
- {
- TRAC_ERR("cmdh_mnfg_mem_slew: OCC is being reset");
- l_rc = ERRL_RC_INTERNAL_FAIL;
- break;
- }
+ // If the OCC is active (we can only run auto-slew in active state) the memory control
+ // task must be running and there is no support (or need) to force activation of
+ // memory monitoring and control
- for(l_cent = 0; l_cent < MAX_NUM_CENTAURS; l_cent++)
- {
- if(!CENTAUR_PRESENT(l_cent))
- {
- continue;
- }
-
- for(l_mba = 0; l_mba < NUM_MBAS_PER_CENTAUR; l_mba++)
- {
- mem_throt_config_data_t * l_throt_ptr =
- &G_sysConfigData.mem_throt_limits[l_cent][l_mba];
-
- // Uses values seen on tuleta as defaults
- l_throt_ptr->min_n_per_mba = 13;
- l_throt_ptr->nom_n_per_mba = 72;
- l_throt_ptr->nom_n_per_chip = 72;
- l_throt_ptr->pcap1_n_per_mba = 72;
- l_throt_ptr->pcap2_n_per_mba = 72;
- l_throt_ptr->ovs_n_per_mba = 72;
- l_throt_ptr->ovs_n_per_chip = 72;
- }
-
- }
-
-
- // Initialization was successful.
- // Set task flags to allow centaur control task to run and
- // also to prevent us from doing initialization again.
- G_task_table[TASK_ID_CENTAUR_DATA].flags = CENTAUR_DATA_RTL_FLAGS;
- G_task_table[TASK_ID_CENTAUR_CONTROL].flags = CENTAUR_CONTROL_RTL_FLAGS;
+ if(!IS_OCC_STATE_ACTIVE())
+ {
+ TRAC_ERR("cmdh_mnfg_mem_slew: OCC must be active to start mem slewing");
+ l_rc = ERRL_RC_INVALID_STATE;
+ break;
+ }
+ if(!rtl_task_is_runnable(TASK_ID_MEMORY_CONTROL))
+ {
+ TRAC_ERR("cmdh_mnfg_mem_slew: memory control task not running");
+ l_rc = ERRL_RC_INTERNAL_FAIL;
+ break;
}
-*/
// Zero out the slew count
g_amec->mnfg_parms.mem_slew_counter = 0;
diff --git a/src/occ_405/dcom/dcom.c b/src/occ_405/dcom/dcom.c
index 87ae396..df00eeb 100755
--- a/src/occ_405/dcom/dcom.c
+++ b/src/occ_405/dcom/dcom.c
@@ -450,6 +450,8 @@ void dcom_build_occfw_msg( const dcom_error_type_t i_which_msg )
// End Function Specification
void task_dcom_parse_occfwmsg(task_t *i_self)
{
+ errlHndl_t l_errl = NULL;
+
if(G_occ_role == OCC_MASTER)
{
// Local slave index counter
@@ -549,7 +551,12 @@ void task_dcom_parse_occfwmsg(task_t *i_self)
G_data_cnfg->data_mask |= DATA_MASK_FREQ_PRESENT;
// Notify AMEC that the frequencies have changed
- AMEC_data_change(DATA_MASK_FREQ_PRESENT);
+ l_errl = AMEC_data_change(DATA_MASK_FREQ_PRESENT);
+ if(l_errl)
+ {
+ // Commit log
+ commitErrl(&l_errl);
+ }
}
}
else
diff --git a/src/occ_405/dimm/dimm_control.c b/src/occ_405/dimm/dimm_control.c
index 1188e76..2b3a43d 100644
--- a/src/occ_405/dimm/dimm_control.c
+++ b/src/occ_405/dimm/dimm_control.c
@@ -111,7 +111,6 @@ bool dimm_control(uint8_t mc, uint8_t port)
//
// End Function Specification
-#define DIMM_TRACE_THROTTLE_DELAY 8
void dimm_update_nlimits(uint8_t mc, uint8_t port)
{
/*------------------------------------------------------------------------*/
@@ -123,6 +122,10 @@ void dimm_update_nlimits(uint8_t mc, uint8_t port)
/*------------------------------------------------------------------------*/
/* Code */
/*------------------------------------------------------------------------*/
+ if (L_trace_throttle_count == 0)
+ {
+ L_trace_throttle_count = G_configured_mbas;
+ }
do
{
@@ -138,12 +141,18 @@ void dimm_update_nlimits(uint8_t mc, uint8_t port)
//Minimum N value is not state dependent
l_active_limits->min_n_per_mba = l_state_limits->min_n_per_mba;
- if(CURRENT_MODE() == OCC_MODE_NOMINAL)
+ //Power Capping memory?
+ if(g_amec->pcap.active_mem_level == 1)
+ {
+ l_port_dimm_maxn = l_state_limits->pcap_n_per_chip;
+ l_slot_dimm_maxn = l_state_limits->pcap_n_per_mba;
+ }
+ else if(CURRENT_MODE() == OCC_MODE_NOMINAL)
{
l_port_dimm_maxn = l_state_limits->nom_n_per_chip;
l_slot_dimm_maxn = l_state_limits->nom_n_per_mba;
}
- else //DPS, TURBO, FFO, and SPS modes will use these settings
+ else //all other modes will use turbo settings
{
l_port_dimm_maxn = l_state_limits->turbo_n_per_chip;
l_slot_dimm_maxn = l_state_limits->turbo_n_per_mba;
@@ -156,25 +165,23 @@ void dimm_update_nlimits(uint8_t mc, uint8_t port)
{
l_active_limits->max_n_per_mba = l_slot_dimm_maxn;
- //Don't repeatedly trace same slot changing, just once
- if(!L_trace_throttle_count)
+ //Don't trace all MCAs changing, just trace one they will all
+ //be the same unless there is a different number of DIMMs behind
+ //the MCAs or a mix of DIMM sizes is supported
+ if(L_trace_throttle_count == G_configured_mbas)
{
- L_trace_throttle_count = DIMM_TRACE_THROTTLE_DELAY;
TRAC_IMP("dimm_update_nlimits: New DIMM slot throttle values: "
- "MC#|Port:[0x%08x], "
- "Max|Min slot Power:[0x%08x], Max port power:[0x%08x] ",
- (uint32_t)((mc << 16) | port),
- (uint32_t)( l_active_limits->min_n_per_mba |
- (l_active_limits->max_n_per_mba << 16)),
- l_active_limits->max_n_per_chip << 16);
-
+ "MC#|Port:[0x%04x], "
+ "Max|Min N_PER_MBA:[0x%08x], Max N_PER_CHIP:[0x%04x] ",
+ (uint16_t)((mc << 8) | port),
+ (uint32_t)( (l_active_limits->max_n_per_mba << 16) |
+ l_active_limits->min_n_per_mba),
+ l_active_limits->max_n_per_chip);
}
}
- if(L_trace_throttle_count)
- {
- L_trace_throttle_count--;
- }
+ L_trace_throttle_count &= ~(0x8000 >> ((mc * (MAX_NUM_MCU_PORTS)) + port));
+
} // NIMBUS_DIMM_THROTTLING_CONFIGURED ?
}while(0);
diff --git a/src/occ_405/main.c b/src/occ_405/main.c
index b12ad1c..8c26e8f 100755
--- a/src/occ_405/main.c
+++ b/src/occ_405/main.c
@@ -576,8 +576,7 @@ void slave_occ_init()
{
// Init the DPSS oversubscription IRQ handler
MAIN_DBG("Initializing Oversubscription IRQ...");
- // TEMP -- NO DPSS/ERRL YET
-/*
+
errlHndl_t l_errl = dpss_oversubscription_irq_initialize();
if( l_errl )
@@ -585,15 +584,14 @@ void slave_occ_init()
// Trace and commit error
MAIN_TRAC_ERR("Initialization of Oversubscription IRQ handler failed");
- // commit log ... log should be deleted by reader mechanism
- // TEMP -- NO ERRL YET
- //commitErrl( &l_errl );
+ // commit log
+ commitErrl( &l_errl );
}
else
{
MAIN_TRAC_INFO("Oversubscription IRQ initialized");
}
-*/
+
//Set up doorbell queues
dcom_initialize_pbax_queues();
diff --git a/src/occ_405/mode.c b/src/occ_405/mode.c
index e4a6715..84bc0e2 100755
--- a/src/occ_405/mode.c
+++ b/src/occ_405/mode.c
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -53,10 +53,6 @@ OCC_MODE G_occ_external_req_mode = OCC_MODE_NOCHANGE;
// Mode that TMGT is requesting OCC go to in KVM
OCC_MODE G_occ_external_req_mode_kvm = OCC_MODE_NOCHANGE;
-// Indicates if OCC must actually change the voltage / frequency during
-// a mode change.
-SMGR_SMS_CMD_TYPE G_occ_internal_sms = SMGR_SMS_VF_INFO_ONLY;
-
// Indicates if we are currently in a mode transition
bool G_mode_transition_occuring = FALSE;
@@ -236,24 +232,11 @@ errlHndl_t SMGR_set_mode(const OCC_MODE i_mode,
// Load correct thermal thresholds based on the current mode
l_errlHndl = AMEC_data_write_thrm_thresholds(CURRENT_MODE());
- // Update the CPU speed in AME?
- // Register the New Mode?
- // Update Power Policy Requirements?
- // Update CPM Calibration
-
}while(0);
- // If we have a mode change failure, Mode change flag needs to be set,
- // otherwise, it needs be be cleared/unset.
- if(l_errlHndl)
- {
-
- }
-
// Unlock critical section
ssx_semaphore_post(&G_smgrModeChangeSem);
-
return l_errlHndl;
}
diff --git a/src/occ_405/mode.h b/src/occ_405/mode.h
index 818cada..dfce6ca 100755
--- a/src/occ_405/mode.h
+++ b/src/occ_405/mode.h
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -38,9 +38,6 @@
#define REQUESTED_MODE() G_occ_internal_req_mode
// Returns the 'Requested' SMS Mode
-#define CURRENT_SMS() G_occ_internal_sms
-
-// Returns the 'Requested' SMS Mode
#define VALID_MODE(mode) ((mode < OCC_MODE_COUNT) ? 1 : 0)
// Typedef of the various modes that TMGT can put OCC into.
diff --git a/src/occ_405/occ_service_codes.h b/src/occ_405/occ_service_codes.h
index e867cd9..a4633b2 100644
--- a/src/occ_405/occ_service_codes.h
+++ b/src/occ_405/occ_service_codes.h
@@ -207,6 +207,8 @@ enum occExtReasonCode
ERC_MEM_CONTROL_SCHEDULE_FAILURE = 0x0080,
ERC_MEM_CONTROL_COMPLETE_FAILURE = 0x0081,
+
+ ERC_FW_ZERO_FREQ_LIMIT = 0x0090,
};
// Error log Module Ids
diff --git a/src/occ_405/occ_sys_config.h b/src/occ_405/occ_sys_config.h
index c065786..8df5579 100755
--- a/src/occ_405/occ_sys_config.h
+++ b/src/occ_405/occ_sys_config.h
@@ -233,31 +233,33 @@ typedef struct
uint8_t source; // source of PCAP value currently in use
} pcap_config_data_t;
+
// source of PCAP value
#define OUT_OF_BAND 1 // source is BMC or (H)TMGT
#define IN_BAND 2 // source is OPAL
-// Memory Centaur Throttle settings
+
+// Memory Throttle settings
typedef struct
{
uint16_t min_n_per_mba; //minimum value
- uint16_t min_mem_power; //Max mem Power @min (x0.1W)
+ uint16_t min_mem_power; //Max mem Power @min (x0.01W)
- uint16_t turbo_n_per_mba; //max mba value for Power Cap @Turbo
+ uint16_t turbo_n_per_mba; //max mba value for Turbo
uint16_t turbo_n_per_chip; //Static per chip numerator @Turbo
- uint16_t turbo_mem_power; //max memory power @Turbo L1
+ uint16_t turbo_mem_power; //max memory power @Turbo
- uint16_t pcap_n_per_mba; //max mba value for Power Cap Level 2
+ uint16_t pcap_n_per_mba; //max mba value for Power Cap
uint16_t pcap_n_per_chip; //Static per chip numerator @PCAP
- uint16_t pcap_mem_power; //max memory power @PCAP L2
+ uint16_t pcap_mem_power; //max memory power @PCAP
uint16_t nom_n_per_mba; //max mba value for nominal mode
uint16_t nom_n_per_chip; //chip setting for nominal mode
- uint16_t nom_mem_power; //max memory power @Redundant
+ uint16_t nom_mem_power; //max memory power @nominal
- uint16_t reserved_n_per_mba; //reserved
- uint16_t reserved_n_per_chip; //reserved
- uint16_t reserved_mem_power; //reserved
+ uint16_t reserved1; //reserved
+ uint16_t reserved2; //reserved
+ uint16_t reserved3; //reserved
} mem_throt_config_data_t;
diff --git a/src/occ_405/rtls/rtls.c b/src/occ_405/rtls/rtls.c
index 51a0bba..5788c69 100755
--- a/src/occ_405/rtls/rtls.c
+++ b/src/occ_405/rtls/rtls.c
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -176,9 +176,9 @@ bool rtl_task_is_runnable(const task_id_t i_task_id)
if ( i_task_id < TASK_END )
{
- if ( G_task_table[i_task_id].flags & RTL_FLAG_RUN )
+ if ( (G_task_table[i_task_id].flags & G_run_mask) == G_run_mask )
{
- // Yes, the task CAN run
+ // Yes, the task CAN run. task's flags match the global run mask
task_can_run = TRUE;
}
}
diff --git a/src/occ_405/state.h b/src/occ_405/state.h
index 8e8e9ba..16d1940 100755
--- a/src/occ_405/state.h
+++ b/src/occ_405/state.h
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -66,21 +66,8 @@ typedef enum
#define OCC_STATE_IS_VALID(state) ((state == OCC_STATE_NOCHANGE) || \
(state == OCC_STATE_OBSERVATION) || \
(state == OCC_STATE_ACTIVE))
-/**
- * @enum SMGR_SMS_CMD_TYPE
- * @brief SMGR set-mode-state commands version 0 contains a byte that indicates if
- * the TPMD must actually change the voltage / frequency during a mode change.
- */
-typedef enum
-{
- SMGR_SMS_VF_INFO_ONLY = 0x00,
- SMGR_SMS_VF_CHANGE_REQ = 0x01,
- SMGR_SMS_STATIC_VF_CHANGE_REQ = 0x02,
-} SMGR_SMS_CMD_TYPE;
-extern SMGR_SMS_CMD_TYPE G_occ_internal_sms; // TODO: Move to state.c
/**
- * @enum SMGR_SMS_STATUS_TYPE
* @brief TMGT Poll contains a byte that indicates status based on this
* bitmask
*/
@@ -171,7 +158,6 @@ typedef struct
extern OCC_STATE G_occ_internal_state;
extern OCC_STATE G_occ_internal_req_state;
-extern SMGR_SMS_CMD_TYPE G_occ_internal_sms;
extern OCC_STATE G_occ_master_state;
extern OCC_STATE G_occ_external_req_state;
OpenPOWER on IntegriCloud