summaryrefslogtreecommitdiffstats
path: root/src/occ_405/amec/amec_master_smh.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/occ_405/amec/amec_master_smh.c')
-rwxr-xr-xsrc/occ_405/amec/amec_master_smh.c1076
1 files changed, 1076 insertions, 0 deletions
diff --git a/src/occ_405/amec/amec_master_smh.c b/src/occ_405/amec/amec_master_smh.c
new file mode 100755
index 0000000..c49ca06
--- /dev/null
+++ b/src/occ_405/amec/amec_master_smh.c
@@ -0,0 +1,1076 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/amec/amec_master_smh.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* [+] 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 <occ_common.h>
+#include <ssx.h>
+#include <errl.h> // Error logging
+#include "rtls.h"
+#include "occ_service_codes.h" // for SSX_GENERIC_FAILURE
+#include "sensor.h"
+#include "amec_smh.h"
+#include "amec_master_smh.h"
+#include <trac.h> // For traces
+#include "amec_sys.h"
+#include "amec_service_codes.h" //For AMEC_MST_CHECK_PCAPS_MATCH
+#include "dcom.h"
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//Power cap mismatch threshold set to 8 ticks (2 milliseconds)
+#define PCAPS_MISMATCH_THRESHOLD 8
+
+//Power cap failure threshold set to 32 (ticks)
+#define PCAP_FAILURE_THRESHOLD 32
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+smh_state_t G_amec_mst_state = {AMEC_INITIAL_STATE,
+ AMEC_INITIAL_STATE,
+ AMEC_INITIAL_STATE};
+
+//Array that stores active power cap values of all OCCs
+slave_pcap_info_t G_slave_active_pcaps[MAX_OCCS] = {{0}};
+
+//OCC Power cap mismatch count
+uint8_t G_pcaps_mismatch_count = 0;
+
+//OCC over power cap count
+uint8_t G_over_cap_count = 0;
+
+//Array that stores the exit counts for the IPS algorithm
+uint32_t G_ips_exit_count[MAX_OCCS][MAX_CORES] = {{0}};
+//Array that stores the entry counts for the IPS algorithm
+uint32_t G_ips_entry_count = 0;
+
+//Soft Fmin to be sent to Slave OCCs
+uint16_t G_mst_soft_fmin = 0;
+//Soft Fmax to be sent to Slave OCCs
+uint16_t G_mst_soft_fmax = 0xFFFF;
+//Counter of committed violations by the Slave OCCs
+uint8_t G_mst_violation_cnt[MAX_OCCS] = {0};
+
+// --------------------------------------------------------
+// AMEC Master State 6.1 Substate Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 128ms.
+//
+const smh_tbl_t amec_mst_state_6_1_sub_substate_table[AMEC_SMH_STATES_PER_LVL] =
+{
+ {amec_mst_sub_substate_6_1_0, NULL},
+ {amec_mst_sub_substate_6_1_1, NULL},
+ {amec_mst_sub_substate_6_1_2, NULL},
+ {amec_mst_sub_substate_6_1_3, NULL},
+ {amec_mst_sub_substate_6_1_4, NULL},
+ {amec_mst_sub_substate_6_1_5, NULL},
+ {amec_mst_sub_substate_6_1_6, NULL},
+ {amec_mst_sub_substate_6_1_7, NULL},
+};
+
+// --------------------------------------------------------
+// AMEC Master State 0 Substate Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 16ms.
+//
+// The 2 States are interleaved so each one runs every 4ms.
+//
+const smh_tbl_t amec_mst_state_0_substate_table[AMEC_SMH_STATES_PER_LVL] =
+{
+ {amec_mst_substate_0_0, NULL},
+ {amec_mst_substate_0_1, NULL},
+ {amec_mst_substate_0_0, NULL},
+ {amec_mst_substate_0_1, NULL},
+ {amec_mst_substate_0_0, NULL},
+ {amec_mst_substate_0_1, NULL},
+ {amec_mst_substate_0_0, NULL},
+ {amec_mst_substate_0_1, NULL},
+};
+
+// --------------------------------------------------------
+// AMEC Master State 3 Substate Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 16ms.
+//
+// The 2 States are interleaved so each one runs every 4ms.
+//
+const smh_tbl_t amec_mst_state_3_substate_table[AMEC_SMH_STATES_PER_LVL] =
+
+{
+ {amec_mst_substate_3_0, NULL},
+ {amec_mst_substate_3_1, NULL},
+ {amec_mst_substate_3_0, NULL},
+ {amec_mst_substate_3_1, NULL},
+ {amec_mst_substate_3_0, NULL},
+ {amec_mst_substate_3_1, NULL},
+ {amec_mst_substate_3_0, NULL},
+ {amec_mst_substate_3_1, NULL},
+};
+
+// --------------------------------------------------------
+// AMEC Master State 6 Substate Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 16ms.
+//
+// SubState1: 8 Sub-substates (128ms/sub-substate)
+//
+const smh_tbl_t amec_mst_state_6_substate_table[AMEC_SMH_STATES_PER_LVL] =
+{
+ {amec_mst_substate_6_0, NULL},
+ {amec_mst_substate_6_1, amec_mst_state_6_1_sub_substate_table},
+ {amec_mst_substate_6_2, NULL},
+ {amec_mst_substate_6_3, NULL},
+ {amec_mst_substate_6_4, NULL},
+ {amec_mst_substate_6_5, NULL},
+ {amec_mst_substate_6_6, NULL},
+ {amec_mst_substate_6_7, NULL},
+};
+
+// --------------------------------------------------------
+// Main AMEC Master State Table
+// --------------------------------------------------------
+// Each function inside this state table runs once every 2ms.
+//
+// State0: 2 Substates (4ms/substate)
+// State3: 2 Substates (4ms/substate)
+// State6: 8 Substates (16ms/substate)
+//
+const smh_tbl_t amec_mst_state_table[AMEC_SMH_STATES_PER_LVL] =
+{
+ {amec_mst_state_0, amec_mst_state_0_substate_table},
+ {amec_mst_state_1, NULL},
+ {amec_mst_state_2, NULL},
+ {amec_mst_state_3, amec_mst_state_3_substate_table},
+ {amec_mst_state_4, NULL},
+ {amec_mst_state_5, NULL},
+ {amec_mst_state_6, amec_mst_state_6_substate_table},
+ {amec_mst_state_7, NULL},
+};
+
+// This sets up the function pointer that will be called to update the
+// fw timings when the AMEC master State Machine finishes.
+smh_state_timing_t G_amec_mst_state_timings = {amec_mst_update_smh_sensors};
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+// Function Specification
+//
+// Name: amec_mst_update_smh_sensors
+//
+// Description: Update the sensor
+//
+// End Function Specification
+void amec_mst_update_smh_sensors(int i_smh_state, uint32_t i_duration)
+{
+ // Update the duration in the fw timing table
+ if(G_fw_timing.amess_state != i_smh_state)
+ {
+ AMEC_DBG("Mismatch between Master and Slave AMEC states\n");
+ }
+
+ G_fw_timing.amess_dur += i_duration;
+}
+
+// Function Specification
+//
+// Name: amec_master_auto_slew
+//
+// Description: This function executes the auto-slewing of frequency based on
+// manufacturing parameters.
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_master_auto_slew(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ static int8_t l_direction = 1;
+ uint16_t l_freq = 0;
+ static uint16_t l_step_delay = 0;
+ static bool l_first_time_enable = TRUE;
+ static bool l_first_time_disable = FALSE;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ // Check if auto-slewing has been enabled
+ if (g_amec->mnfg_parms.auto_slew)
+ {
+ // Is this the first time we are enabling auto-slewing?
+ if (l_first_time_enable)
+ {
+ // Need to start the auto-slew from fmax
+ g_amec->mnfg_parms.foverride = g_amec->mnfg_parms.fmax;
+
+ // Reset the delay counter and reset the direction
+ l_step_delay = g_amec->mnfg_parms.delay;
+ l_direction = 1;
+
+ l_first_time_enable = FALSE;
+ l_first_time_disable = TRUE;
+
+ // Break out now to give it some time to get to fmax
+ break;
+ }
+ }
+ else
+ {
+ // Is this the first time we are disabling auto-slewing?
+ if (l_first_time_disable)
+ {
+ // Clear the frequency override parameter
+ g_amec->mnfg_parms.foverride = 0;
+
+ l_first_time_enable = TRUE;
+ l_first_time_disable = FALSE;
+ }
+
+ // We are done, break
+ break;
+ }
+
+ // If we've made it this far, then we are running auto-slew. First,
+ // check if our delay counter has expired.
+ if (l_step_delay != 0)
+ {
+ // Decrement our delay counter and exit
+ l_step_delay--;
+ break;
+ }
+
+ // Our delay counter has expired, reset it to its original value
+ l_step_delay = g_amec->mnfg_parms.delay;
+
+ // Now, generate a new frequency override
+ l_freq = g_amec->mnfg_parms.foverride -
+ (l_direction * g_amec->mnfg_parms.fstep);
+
+ if (l_freq <= g_amec->mnfg_parms.fmin)
+ {
+ // We've reached an edge, increment our counter
+ g_amec->mnfg_parms.slew_counter++;
+
+ // Change direction of the auto-slew
+ l_direction = -l_direction;
+
+ // Clip frequency to fmin
+ l_freq = g_amec->mnfg_parms.fmin;
+ }
+ else if (l_freq >= g_amec->mnfg_parms.fmax)
+ {
+ // We've reached an edge, increment our counter
+ g_amec->mnfg_parms.slew_counter++;
+
+ // Change direction of the auto-slew
+ l_direction = -l_direction;
+
+ // Clip frequency to fmax
+ l_freq = g_amec->mnfg_parms.fmax;
+ }
+ g_amec->mnfg_parms.foverride = l_freq;
+
+ }while(0);
+
+ return;
+}
+
+// Function Specification
+//
+// Name: amec_mst_check_pcaps_match
+//
+// Description: This function checks for mismatch in power caps between
+// occs for 8 consecutive ticks.
+//
+// End Function Specification
+void amec_mst_check_pcaps_match(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint8_t l_chip_id;
+ bool l_prev_pcap_valid = FALSE;
+ uint16_t l_prev_pcap = 0;
+ bool l_pcap_mismatch = FALSE;
+ errlHndl_t l_err = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ //Loop through all occs
+ for(l_chip_id = 0; l_chip_id < MAX_OCCS; l_chip_id++)
+ {
+ //if occ is present && its pcap data is considered valid
+ if((G_sysConfigData.is_occ_present & (1<< l_chip_id)) &&
+ (G_slave_active_pcaps[l_chip_id].pcap_valid != 0))
+ {
+ //TRAC_INFO(" occ[%d]: pcap[%d] valid(%d)",
+ // l_chip_id, G_slave_active_pcaps[l_chip_id].active_pcap, G_slave_active_pcaps[l_chip_id].pcap_valid );
+
+ //Initialize l_prev_pcap to the first valid/present occ's power cap
+ if(!l_prev_pcap_valid)
+ {
+ //TRAC_INFO("First present occ - power cap info[%d]=%d(%d)",
+ // l_chip_id, G_slave_active_pcaps[l_chip_id].active_pcap, G_slave_active_pcaps[l_chip_id].pcap_valid );
+
+ l_prev_pcap = G_slave_active_pcaps[l_chip_id].active_pcap;
+ l_prev_pcap_valid = TRUE;
+ }
+ else
+ {
+ //If there is mismatch between OCCs power caps, increment mismatch
+ // count
+ if(l_prev_pcap != G_slave_active_pcaps[l_chip_id].active_pcap)
+ {
+ G_pcaps_mismatch_count++;
+ l_pcap_mismatch = TRUE;
+
+ TRAC_INFO("Mismatch in OCC power cap values: mismatch cnt=%d pcap=%d vs compared pcap[%d]=%d(%d)",
+ G_pcaps_mismatch_count, l_prev_pcap, l_chip_id, G_slave_active_pcaps[l_chip_id].active_pcap,
+ G_slave_active_pcaps[l_chip_id].pcap_valid);
+
+ //If mismatch occurs for 8 consecutive ticks
+ //i.e 8 * 250 microsecs = 2 milliseconds,then reset occ
+ if(G_pcaps_mismatch_count >= PCAPS_MISMATCH_THRESHOLD)
+ {
+ TRAC_ERR("Mismatch in OCC power cap values: pcap=%d, slave_active_pcap[%d]=%d(%d)",
+ l_prev_pcap, l_chip_id, G_slave_active_pcaps[l_chip_id].active_pcap,
+ G_slave_active_pcaps[l_chip_id].pcap_valid);
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_MST_CHECK_PCAPS_MATCH
+ * @reasoncode INTERNAL_FAILURE
+ * @userdata1 First OCC Power cap
+ * @userdata2 Mismatch OCC Power cap
+ * @devdesc Internal max power limits mismatched
+ *
+ */
+ l_err = createErrl( AMEC_MST_CHECK_PCAPS_MATCH,
+ INTERNAL_FAILURE,
+ ERC_AMEC_PCAPS_MISMATCH_FAILURE,
+ ERRL_SEV_PREDICTIVE,
+ NULL,
+ DEFAULT_TRACE_SIZE,
+ l_prev_pcap,
+ G_slave_active_pcaps[l_chip_id].active_pcap);
+
+ //Callout to OVS
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ //Callout to APSS
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.apss_huid,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ //Callout to DPSS
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.dpss_huid,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+ //Reset OCC
+ REQUEST_RESET(l_err);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ //If there was no power cap mismatch between occ's,then reset count to zero
+ if(!l_pcap_mismatch)
+ {
+ G_pcaps_mismatch_count = 0;
+ }
+}
+
+
+// Function Specification
+//
+// Name: amec_mst_check_under_pcap
+//
+// Description: This function checks if there is failure in maintaining power
+// cap value.
+//
+// End Function Specification
+
+void amec_mst_check_under_pcap(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ errlHndl_t l_err = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Check if ppb_fmax = Fmin and PWR250US > Node power cap and
+ // Node power cap >= hard_min_pcap
+ 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_over_cap_count++;
+
+ //Log error and reset OCC if count >= 32 (ticks)
+ if(G_over_cap_count >= PCAP_FAILURE_THRESHOLD)
+ {
+ TRAC_ERR("Failure to maintain power cap: Power Cap = %d ,"
+ "PWR250US = %d ,PWR250USP0 = %d ,PWR250USFAN = %d ,"
+ "PWR250USMEM0 = %d",g_amec->pcap.active_node_pcap,
+ AMECSENSOR_PTR(PWR250US)->sample,
+ AMECSENSOR_PTR(PWR250USP0)->sample,
+ AMECSENSOR_PTR(PWR250USFAN)->sample,
+ AMECSENSOR_PTR(PWR250USMEM0)->sample);
+
+ TRAC_ERR("PWR250USIO = %d , PWR250USSTORE = %d, PWR250USGPU = %d",
+ AMECSENSOR_PTR(PWR250USIO)->sample,
+ AMECSENSOR_PTR(PWR250USSTORE)->sample,
+ AMECSENSOR_PTR(PWR250USGPU)->sample);
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_MST_CHECK_UNDER_PCAP
+ * @reasoncode POWER_CAP_FAILURE
+ * @userdata1 Power Cap
+ * @userdata2 PWR250US (Node Power)
+ * @devdesc Failure to maintain max power limits
+ *
+ */
+ l_err = createErrl( AMEC_MST_CHECK_UNDER_PCAP,
+ POWER_CAP_FAILURE,
+ ERC_AMEC_UNDER_PCAP_FAILURE,
+ ERRL_SEV_PREDICTIVE,
+ NULL,
+ DEFAULT_TRACE_SIZE,
+ g_amec->pcap.active_node_pcap,
+ AMECSENSOR_PTR(PWR250US)->sample);
+
+ //Callout to firmware
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ //Callout to APSS
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.apss_huid,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ //Reset OCC
+ REQUEST_RESET(l_err);
+ }
+ }
+ else
+ {
+ //Decrement count if node power under power cap value
+ if(G_over_cap_count > 0)
+ {
+ G_over_cap_count--;
+ }
+ }
+
+ return;
+}
+
+// Function Specification
+//
+// Name: amec_mst_ips_main
+//
+// Description: This function executes the Idle Power Saver (IPS)
+// algorithm.
+//
+// End Function Specification
+void amec_mst_ips_main(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint16_t i = 0;
+ uint16_t j = 0;
+ uint16_t l_time_interval = 0;
+ uint16_t l_core_count = 0;
+ uint16_t l_entry_core_count = 0;
+ BOOLEAN l_exit = FALSE;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ do
+ {
+ // If IPS is disabled, no need to execute the algorithm
+ if (g_amec->mst_ips_parms.enable == 0)
+ {
+ // Reset the following parameters
+ g_amec->mst_ips_parms.active = 0;
+ G_ips_entry_count = 0;
+ g_amec->mst_ips_parms.freq_request = g_amec->sys.fmax;
+
+ break;
+ }
+
+ // We made it here, so that means IPS is enabled.
+ l_time_interval = AMEC_DPS_SAMPLING_RATE * AMEC_IPS_AVRG_INTERVAL;
+
+ // If IPS is active, check if the exit criteria has been met
+ if (g_amec->mst_ips_parms.active == 1)
+ {
+ // Useful trace for debugging
+ //TRAC_INFO("DBG_IPS: IPS is active! exit_countp0c5[%u]",
+ // G_ips_exit_count[0][5]);
+
+ for (i=0; i<MAX_OCCS; i++)
+ {
+ if (!(G_sysConfigData.is_occ_present & (1<<i)))
+ {
+ // This OCC is not present, just move along
+ continue;
+ }
+
+ for (j=0; j<MAX_CORES; j++)
+ {
+ // Check if this core's normalized utilization has exceeded
+ // the exit threshold
+ if (G_dcom_slv_outbox_rx[i].nutil3sp0cy[j] >=
+ g_amec->mst_ips_parms.exit_threshold)
+ {
+ // Increment our exit count by the number of samples
+ // used to average utilization (default is 3 seconds)
+ G_ips_exit_count[i][j] += l_time_interval;
+
+ if (G_ips_exit_count[i][j] >=
+ g_amec->mst_ips_parms.exit_delay)
+ {
+ // Found one core that meets the exit criteria!
+ l_exit = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ // If the normalized utilization of this core is below
+ // the exit threshold, reset its exit count
+ G_ips_exit_count[i][j] = 0;
+ }
+ }
+
+ if (l_exit)
+ {
+ break;
+ }
+ }
+
+ // If we found a core that meets the exit criteria, then exit IPS
+ // active state
+ if (l_exit)
+ {
+ g_amec->mst_ips_parms.active = 0;
+ G_ips_entry_count = 0;
+ // A special request of 0 frequency will inform the slaves to
+ // ignore the IPS request from the master
+ g_amec->mst_ips_parms.freq_request = 0;
+
+ TRAC_INFO("amec_mst_ips_main: We have exited IPS active state! exit_count[%u] freq_request[%u]",
+ G_ips_exit_count[i][j], g_amec->mst_ips_parms.freq_request);
+ }
+ }
+ else //IPS is inactive, check if entry criteria has been met
+ {
+ // Useful trace for debugging
+ //TRAC_INFO("DBG_IPS: IPS is inactive! entry_count[%u]",
+ // G_ips_entry_count);
+
+ for (i=0; i<MAX_OCCS; i++)
+ {
+ if (!(G_sysConfigData.is_occ_present & (1<<i)))
+ {
+ // This OCC is not present, just move along
+ continue;
+ }
+
+ for (j=0; j<MAX_CORES; j++)
+ {
+ l_core_count++;
+
+ // Note: cores that are not present will return a zero
+ // utilization, thus fulfilling the check below
+ if (G_dcom_slv_outbox_rx[i].nutil3sp0cy[j] <
+ g_amec->mst_ips_parms.entry_threshold)
+ {
+ // Count how many cores have a normalized utilization
+ // below the entry threshold
+ l_entry_core_count++;
+ }
+ else
+ {
+ // Reset the entry count since we found a core that
+ // has a utilization >= entry threshold
+ G_ips_entry_count = 0;
+ }
+ }
+ }
+
+ // All cores have a utilization lower than the entry threshold
+ if (l_entry_core_count == l_core_count)
+ {
+ // Increment the entry count by the number of samples used to
+ // average utilization (default is 3 seconds)
+ G_ips_entry_count += l_time_interval;
+
+ if (G_ips_entry_count >= g_amec->mst_ips_parms.entry_delay)
+ {
+ // We have met the entry criteria, move IPS state to active
+ g_amec->mst_ips_parms.active = 1;
+
+ for (i=0; i<MAX_OCCS; i++)
+ {
+ if (!(G_sysConfigData.is_occ_present & (1<<i)))
+ {
+ continue;
+ }
+ for (j=0; j<MAX_CORES; j++)
+ {
+ G_ips_exit_count[i][j] = 0;
+ }
+ }
+
+ g_amec->mst_ips_parms.freq_request =
+ G_sysConfigData.sys_mode_freq.table[OCC_MODE_MIN_FREQUENCY];
+
+ TRAC_INFO("amec_mst_ips_main: We have entered IPS active state! entry_count[%u] freq_request[%u]",
+ G_ips_entry_count, g_amec->mst_ips_parms.freq_request);
+ }
+ }
+ }
+ }while(0);
+}
+
+uint8_t AMEC_mst_get_ips_active_status()
+{
+ return g_amec->mst_ips_parms.active;
+}
+
+// Function Specification
+//
+// Name: amec_mst_gen_soft_freq
+//
+// Description: This function executes the algorithm that generates the soft
+// frequency boundaries to be sent to the Slave OCCs. This is the strategy
+// to be used for P8 GA1.
+//
+// End Function Specification
+void amec_mst_gen_soft_freq(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint8_t i = 0;
+ uint16_t l_ftarget = 0;
+ uint16_t l_fdelta = 0;
+ uint16_t l_lowest_fwish = 0;
+ uint16_t l_highest_fwish = 0;
+ BOOLEAN l_need_reset = FALSE;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ do
+ {
+ // First, check if frequency delta has been enabled
+ if (G_mst_tunable_parameter_table_ext[7].adj_value == 0)
+ {
+ // If it hasn't been enabled, then use the full frequency range and
+ // break
+ G_mst_soft_fmin = 0x0000;
+ G_mst_soft_fmax = 0xFFFF;
+
+ break;
+ }
+
+ // Use the frequency delta sent by the customer
+ l_fdelta = (G_sysConfigData.sys_mode_freq.table[OCC_MODE_NOMINAL] *
+ G_mst_tunable_parameter_table_ext[8].adj_value/2) / 100;
+
+ // Check if all OCCs are operating inside the soft frequency boundaries
+ for (i=0; i<MAX_OCCS; i++)
+ {
+ // Ignore OCCs that are sending zeros for factual or fwish
+ if ((G_dcom_slv_outbox_rx[i].factual == 0) ||
+ (G_dcom_slv_outbox_rx[i].fwish == 0))
+ {
+ continue;
+ }
+
+ // Compare factual against the soft frequency boundaries
+ if ((G_dcom_slv_outbox_rx[i].factual < G_mst_soft_fmin) ||
+ (G_dcom_slv_outbox_rx[i].factual > G_mst_soft_fmax))
+ {
+ G_mst_violation_cnt[i]++;
+ }
+ else
+ {
+ G_mst_violation_cnt[i] = 0;
+ }
+
+ // Now check if the violation count has exceeded the threshold
+ if (G_mst_violation_cnt[i] > 3)
+ {
+ // The new target frequency is the violator's factual
+ l_need_reset = TRUE;
+ l_ftarget = G_dcom_slv_outbox_rx[i].factual;
+ }
+ }
+
+ // If all OCCs are inside the soft frequency boundaries, select the
+ // target frequeny based on the power mode
+ if (!l_need_reset)
+ {
+ if ((CURRENT_MODE() == OCC_MODE_DYN_POWER_SAVE) ||
+ (CURRENT_MODE() == OCC_MODE_DYN_POWER_SAVE_FP))
+ {
+ // For DPS and DPS-FP modes, calculate the highest Fwish sent
+ // by all slave OCCs
+ l_highest_fwish = 0;
+ for (i=0; i<MAX_OCCS; i++)
+ {
+ // Ignore OCCs that are sending zeros for factual or fwish
+ if ((G_dcom_slv_outbox_rx[i].factual == 0) ||
+ (G_dcom_slv_outbox_rx[i].fwish == 0))
+ {
+ continue;
+ }
+ if (G_dcom_slv_outbox_rx[i].fwish > l_highest_fwish)
+ {
+ l_highest_fwish = G_dcom_slv_outbox_rx[i].fwish;
+ }
+ }
+
+ // If the highest Fwish is in range, go for it. Otherwise, step
+ // towards it in small steps
+ if ((l_highest_fwish >= G_mst_soft_fmin) &&
+ (l_highest_fwish <= G_mst_soft_fmax))
+ {
+ l_ftarget = l_highest_fwish;
+ }
+ else if (l_highest_fwish > G_mst_soft_fmax)
+ {
+ // Fwish is too high for range, step up (new target is the
+ // old soft Fmax)
+ l_ftarget = G_mst_soft_fmax;
+ }
+ else
+ {
+ // Fwish is too low for range, step down (new target is the
+ // old soft Fmin)
+ l_ftarget = G_mst_soft_fmin;
+ }
+ }
+ else
+ {
+ // For other system power modes, calculate the lowest Fwish sent
+ // by all slave OCCs
+ l_lowest_fwish = 0xFFFF;
+ for (i=0; i<MAX_OCCS; i++)
+ {
+ // Ignore OCCs that are sending zeros for factual or fwish
+ if ((G_dcom_slv_outbox_rx[i].factual == 0) ||
+ (G_dcom_slv_outbox_rx[i].fwish == 0))
+ {
+ continue;
+ }
+ if ((G_dcom_slv_outbox_rx[i].fwish < l_lowest_fwish) &&
+ (G_dcom_slv_outbox_rx[i].fwish != 0))
+ {
+ l_lowest_fwish = G_dcom_slv_outbox_rx[i].fwish;
+ }
+ }
+
+ // If the lowest Fwish is in range, go for it. Otherwise, step
+ // towards it in small steps
+ if ((l_lowest_fwish >= G_mst_soft_fmin) &&
+ (l_lowest_fwish <= G_mst_soft_fmax))
+ {
+ l_ftarget = l_lowest_fwish;
+ }
+ else if (l_lowest_fwish > G_mst_soft_fmax)
+ {
+ // Fwish is too high for range, step up (new target is the
+ // old soft Fmax)
+ l_ftarget = G_mst_soft_fmax;
+ }
+ else
+ {
+ // Fwish is too low for range, step down (new target is the
+ // old soft Fmin)
+ l_ftarget = G_mst_soft_fmin;
+ }
+ }
+ }
+
+ // Calculate the new soft frequency boundaries
+ G_mst_soft_fmin = l_ftarget - l_fdelta;
+ G_mst_soft_fmax = l_ftarget + l_fdelta;
+
+ } while(0);
+}
+
+
+// Function Specification
+//
+// Name: amec_mst_cmmon_tasks_pre
+//
+// Description: master common tasks pre function
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_mst_common_tasks_pre(void)
+{
+ AMEC_DBG("\tAMEC Master Pre-State Common\n");
+
+ // ------------------------------------------------------
+ //
+ // ------------------------------------------------------
+
+
+ // ------------------------------------------------------
+ //
+ // ------------------------------------------------------
+}
+
+
+// Function Specification
+//
+// Name: amec_mst_cmmon_tasks_post
+//
+// Description: master common tasks post function
+//
+// End Function Specification
+void amec_mst_common_tasks_post(void)
+{
+ AMEC_DBG("\tAMEC Master Post-State Common\n");
+
+ // Only execute if OCC is in the active state
+ if ( IS_OCC_STATE_ACTIVE() )
+ {
+ // Call the OCC auto-slew function
+ amec_master_auto_slew();
+
+ //Call OCC pcaps mismatch function
+ amec_mst_check_pcaps_match();
+
+ //Call check under power cap function
+ amec_mst_check_under_pcap();
+ }
+}
+
+
+// Function Specification
+//
+// Name: amec_mst_state_0 ~ amec_mst_state_7
+//
+// Description: master state 0 ~ 7 functions
+//
+// End Function Specification
+void amec_mst_state_0(void){AMEC_DBG("\tAMEC Master State 0\n");}
+void amec_mst_state_1(void){AMEC_DBG("\tAMEC Master State 1\n");}
+void amec_mst_state_2(void){AMEC_DBG("\tAMEC Master State 2\n");}
+void amec_mst_state_3(void){AMEC_DBG("\tAMEC Master State 3\n");}
+void amec_mst_state_4(void){AMEC_DBG("\tAMEC Master State 4\n");}
+
+void amec_mst_state_5(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ static uint16_t l_counter = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ AMEC_DBG("\tAMEC Master State 5\n");
+
+ // Only execute if OCC is in the active state
+ if ( IS_OCC_STATE_ACTIVE() )
+ {
+ // Increment our local counter
+ l_counter++;
+
+ // Is it time to run the Idle Power Saver algorithm? (default is 3sec)
+ if (l_counter == AMEC_DPS_SAMPLING_RATE * AMEC_IPS_AVRG_INTERVAL)
+ {
+ l_counter = 0;
+ amec_mst_ips_main();
+ }
+ }
+}
+
+void amec_mst_state_6(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ AMEC_DBG("\tAMEC Master State 6\n");
+
+ if ( IS_OCC_STATE_ACTIVE() )
+ {
+ amec_mst_gen_soft_freq();
+ }
+}
+
+void amec_mst_state_7(void){AMEC_DBG("\tAMEC Master State 7\n");}
+
+// Function Specification
+//
+// Name: amec_mst_substate_0_0
+// amec_mst_substate_0_1
+//
+// Description: master substate amec_mst_substate_0_0
+// master substate amec_mst_substate_0_1
+//
+// End Function Specification
+void amec_mst_substate_0_0(void){AMEC_DBG("\tAMEC Master SubState 0.0\n");}
+void amec_mst_substate_0_1(void){AMEC_DBG("\tAMEC Master SubState 0.1\n");}
+
+// Function Specification
+//
+// Name: amec_mst_substate_6_0
+// amec_mst_substate_6_1
+// amec_mst_substate_6_2
+// amec_mst_substate_6_3
+// amec_mst_substate_6_4
+// amec_mst_substate_6_5
+// amec_mst_substate_6_6
+// amec_mst_substate_6_7
+//
+// Description: master substate amec_mst_substate_6_0
+// master substate amec_mst_substate_6_1
+// master substate amec_mst_substate_6_2
+// master substate amec_mst_substate_6_3
+// master substate amec_mst_substate_6_4
+// master substate amec_mst_substate_6_5
+// master substate amec_mst_substate_6_6
+// master substate amec_mst_substate_6_7
+//
+// Flow: FN= None
+//
+// End Function Specification
+void amec_mst_substate_6_0(void){AMEC_DBG("\tAMEC Master State 6.0\n");}
+void amec_mst_substate_6_1(void){AMEC_DBG("\tAMEC Master State 6.1\n");}
+void amec_mst_substate_6_2(void){AMEC_DBG("\tAMEC Master State 6.2\n");}
+void amec_mst_substate_6_3(void){AMEC_DBG("\tAMEC Master State 6.3\n");}
+void amec_mst_substate_6_4(void){AMEC_DBG("\tAMEC Master State 6.4\n");}
+void amec_mst_substate_6_5(void){AMEC_DBG("\tAMEC Master State 6.5\n");}
+void amec_mst_substate_6_6(void){AMEC_DBG("\tAMEC Master State 6.6\n");}
+void amec_mst_substate_6_7(void){AMEC_DBG("\tAMEC Master State 6.7\n");}
+
+// Function Specification
+//
+// Name: amec_mst_substate_3_0
+// amec_mst_substate_3_1
+//
+// Description: master substate amec_mst_substate_3_0
+// master substate amec_mst_substate_3_1
+//
+// Flow: FN= None
+//
+// End Function Specification
+void amec_mst_substate_3_0(void){AMEC_DBG("\tAMEC Master State 3.0\n");}
+void amec_mst_substate_3_1(void){AMEC_DBG("\tAMEC Master State 3.1\n");}
+
+
+// Function Specification
+//
+// Name: amec_mst_substate_6_1_0
+// amec_mst_substate_6_1_1
+// amec_mst_substate_6_1_2
+// amec_mst_substate_6_1_3
+// amec_mst_substate_6_1_4
+// amec_mst_substate_6_1_5
+// amec_mst_substate_6_1_6
+// amec_mst_substate_6_1_7
+//
+// Description: master substate amec_mst_substate_6_1_0
+// master substate amec_mst_substate_6_1_1
+// master substate amec_mst_substate_6_1_2
+// master substate amec_mst_substate_6_1_3
+// master substate amec_mst_substate_6_1_4
+// master substate amec_mst_substate_6_1_5
+// master substate amec_mst_substate_6_1_6
+// master substate amec_mst_substate_6_1_7
+//
+// Flow: FN= None
+//
+// End Function Specification
+void amec_mst_sub_substate_6_1_0(void){AMEC_DBG("\tAMEC Master State 6.1.0\n");}
+void amec_mst_sub_substate_6_1_1(void){AMEC_DBG("\tAMEC Master State 6.1.1\n");}
+void amec_mst_sub_substate_6_1_2(void){AMEC_DBG("\tAMEC Master State 6.1.2\n");}
+void amec_mst_sub_substate_6_1_3(void){AMEC_DBG("\tAMEC Master State 6.1.3\n");}
+void amec_mst_sub_substate_6_1_4(void){AMEC_DBG("\tAMEC Master State 6.1.4\n");}
+void amec_mst_sub_substate_6_1_5(void){AMEC_DBG("\tAMEC Master State 6.1.5\n");}
+void amec_mst_sub_substate_6_1_6(void){AMEC_DBG("\tAMEC Master State 6.1.6\n");}
+void amec_mst_sub_substate_6_1_7(void){AMEC_DBG("\tAMEC Master State 6.1.7\n");}
+
+/*----------------------------------------------------------------------------*/
+/* End */
+/*----------------------------------------------------------------------------*/
OpenPOWER on IntegriCloud