summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRahul Batra <rbatra@us.ibm.com>2017-12-20 13:31:00 -0600
committerJoshua Hunsberger <jahunsbe@us.ibm.com>2018-02-01 16:20:31 -0600
commit60228223467973be108d7a4f21368bb914e9d4b2 (patch)
tree7ecb5e93973c4abd42f78bb0449b4b13a5c073f2
parent83dffa512475467ce688c5756f4392d82c21f90e (diff)
downloadtalos-hcode-60228223467973be108d7a4f21368bb914e9d4b2.tar.gz
talos-hcode-60228223467973be108d7a4f21368bb914e9d4b2.zip
PM: VDM Prolonged Droop Fix
Key_Cronus_Test=PM_REGRESS Change-Id: I842b6100bf8537425fe1f0ac92bea44f75051348 Original-Change-Id: I73d38d6029a5b84590d1081855e12c145a535869 CQ: SW413192 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/51338 Reviewed-by: Michael S. Floyd <mfloyd@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: HWSV CI <hwsv-ci+hostboot@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com> Reviewed-by: Gregory S. Still <stillgs@us.ibm.com> Tested-by: Cronus HW CI <cronushw-ci+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: RANGANATHPRASAD G. BRAHMASAMUDRA <prasadbgr@in.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com>
-rw-r--r--import/chips/p9/common/pmlib/include/pstate_pgpe_cme_api.h38
-rw-r--r--import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_intercme.c121
-rw-r--r--import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.c160
-rw-r--r--import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.h55
-rw-r--r--import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.c346
-rw-r--r--import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_actuate_pstates.c22
-rw-r--r--import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_process_requests.c51
7 files changed, 609 insertions, 184 deletions
diff --git a/import/chips/p9/common/pmlib/include/pstate_pgpe_cme_api.h b/import/chips/p9/common/pmlib/include/pstate_pgpe_cme_api.h
index 5492995a..b0785f57 100644
--- a/import/chips/p9/common/pmlib/include/pstate_pgpe_cme_api.h
+++ b/import/chips/p9/common/pmlib/include/pstate_pgpe_cme_api.h
@@ -98,24 +98,44 @@ enum MESSAGE_ID_DB0
MSGID_DB0_START_PSTATE_BROADCAST = 3,
MSGID_DB0_STOP_PSTATE_BROADCAST = 4,
MSGID_DB0_CLIP_BROADCAST = 5,
- MSGID_DB0_SAFE_MODE_BROADCAST = 6,
+ MSGID_DB0_PMSR_UPDT = 6,
MSGID_DB0_VALID_END = 6 //This for error checking
};
+enum MESSAGE_ID_DB3
+{
+ MSGID_DB3_RESERVED = 0,
+ MSGID_DB3_VALID_START = 1, //This for error checking
+ MSGID_DB3_PSTATE_START = 1,
+ MSGID_DB3_PSTATE_END = 0xF0,
+ MSGID_DB3_IMMEDIATE_HALT = 0xF1,
+ MSGID_DB3_RESTORE_STATE_AND_HALT = 0xF2,
+ MSGID_DB3_REPLAY_DB0 = 0xF3,
+ MSGID_DB3_VALID_END = 0xF3 //This for error checking
+};
+
enum MESSAGEID_PCB_TYPE4_ACK_TYPES
{
MSGID_PCB_TYPE4_ACK_ERROR = 0,
MSGID_PCB_TYPE4_ACK_PSTATE_PROTO_ACK = 1,
MSGID_PCB_TYPE4_ACK_PSTATE_SUSPENDED = 2,
- MSGID_PCB_TYPE4_QUAD_MGR_AVAILABLE = 3
+ MSGID_PCB_TYPE4_QUAD_MGR_AVAILABLE = 3,
+ MSGID_PCB_TYPE4_NACK_DROOP_PRESENT = 4
};
-enum DB0_FIELDS
+enum DB0_CLIP_BCAST_FIELDS
{
DB0_CLIP_BCAST_TYPE_PMIN = 0,
DB0_CLIP_BCAST_TYPE_PMAX = 1
};
+enum DB0_PMSR_UPDT_COMMANDS
+{
+ DB0_PMSR_UPDT_SET_SAFE_MODE = 0x0,
+ DB0_PMSR_UPDT_SET_PSTATES_SUSPENDED = 0x1,
+ DB0_PMSR_UPDT_CLEAR_PSTATES_SUSPENDED = 0x2
+};
+
//
//PGPE-CME Doorbell0(Global Actual Broadcast)
//
@@ -225,22 +245,24 @@ typedef union pgpe_db0_clip_bcast
} pgpe_db0_clip_bcast_t;
//
-//PGPE-CME Doorbell0(Safe Mode Broadcast)
+//PGPE-CME Doorbell0(PMSR Update)
//
-typedef union pgpe_db0_safe_mode_bcast
+typedef union pgpe_db0_pmsr_updt
{
uint64_t value;
struct
{
#ifdef _BIG_ENDIAN
uint64_t msg_id : 8;
- uint64_t reserved: 56;
+ uint64_t command : 8;
+ uint64_t reserved: 48;
#else
- uint64_t reserved: 56;
+ uint64_t reserved: 48;
+ uint64_t command : 8;
uint64_t msg_id : 8;
#endif
} fields;
-} pgpe_db0_safe_mode_bcast_t;
+} pgpe_db0_pmsr_updt_t;
#endif //__PSTATE_PGPE_CME_API_H__
diff --git a/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_intercme.c b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_intercme.c
index c4c3d7d7..958ca201 100644
--- a/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_intercme.c
+++ b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_intercme.c
@@ -49,33 +49,89 @@ extern CmeRecord G_cme_record;
//
void p9_cme_pstate_intercme_in0_irq_handler(void* arg, PkIrqId irq)
{
- p9_cme_pstate_intercme_in0_handler();
+ PkMachineContext ctx __attribute__((unused));
+
+ //Read DB0 from first good core since PGPE
+ //writes same value for both cores
+ uint64_t dbData;
+
+ if (in32(CME_LCL_FLAGS) & (BIT32(CME_FLAGS_CORE0_GOOD)))
+ {
+ CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C0, dbData);
+ }
+ else
+ {
+ CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C1, dbData);
+ }
+
+ p9_cme_pstate_process_db0_sibling(dbData);
+
+ pk_irq_vec_restore(&ctx);
}
-void p9_cme_pstate_intercme_in0_handler()
+void p9_cme_pstate_intercme_msg_handler(void* arg, PkIrqId irq)
{
- cppm_cmedb0_t dbData;
- dbData.value = 0;
- uint32_t dbQuadInfo, dbBit8_15;
- uint32_t cme_flags = in32(CME_LCL_FLAGS);
PkMachineContext ctx __attribute__((unused));
- PK_TRACE("INTER0: Enter\n");
+ p9_cme_pstate_sibling_lock_and_intercme_protocol(0, 1, 0);
- //Read DB0 from first good core since PGPE
- //writes same value for both cores
- do
+ pk_irq_vec_restore(&ctx);
+}
+
+void p9_cme_pstate_sibling_lock_and_intercme_protocol(uint32_t process_intercme_in0, uint32_t readDB0, uint64_t dbData)
+{
+ PK_TRACE("SIBL: Enter\n");
+ uint32_t msg;
+ uint64_t data;
+ intercme_msg_recv(&msg, IMT_LOCK_SIBLING);
+
+ // Block on the intercme0/intercme1 interrupt
+ while((!(in32(CME_LCL_EISR) & BIT32(7))) &&
+ (!(in32_sh(CME_LCL_EISR) & BIT64SH(38)))) {}
+
+ //If INTERCME_DIRECT_IN1, then error.
+ if(in32_sh(CME_LCL_EISR) & BIT64SH(38))
{
- if (cme_flags & (BIT32(CME_FLAGS_CORE0_GOOD)))
+ G_cme_pstate_record.pstatesSuspended = 1;
+ p9_cme_pstate_pmsr_updt(G_cme_record.core_enabled);
+ intercme_direct(INTERCME_DIRECT_IN1, INTERCME_DIRECT_ACK, 0);
+ }
+
+ //If INTERCME_DIRECT_IN0, then process DB0 data
+ if((in32(CME_LCL_EISR) & BIT32(7)) && (process_intercme_in0 == 1))
+ {
+ if(readDB0)
{
- CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C0, dbData.value);
+ //Read DB0 from first good core since PGPE
+ //writes same value for both cores
+ if (in32(CME_LCL_FLAGS) & (BIT32(CME_FLAGS_CORE0_GOOD)))
+ {
+ CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C0, data);
+ }
+ else
+ {
+ CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C1, data);
+ }
}
else
{
- CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C1, dbData.value);
+ data = dbData;
}
+
+ p9_cme_pstate_process_db0_sibling(data);
}
- while(dbData.value == 0);
+
+ PK_TRACE("SIBL: Enter\n");
+}
+
+void p9_cme_pstate_process_db0_sibling(uint64_t data)
+{
+ cppm_cmedb0_t dbData;
+ dbData.value = data;
+ uint32_t dbQuadInfo, dbBit8_15;
+ //uint32_t cme_flags = in32(CME_LCL_FLAGS);
+
+ PK_TRACE("INTER0: Enter\n");
dbQuadInfo = (dbData.value >> (in32(CME_LCL_SRTCH0) &
(BITS32(CME_SCRATCH_LOCAL_PSTATE_IDX_START, CME_SCRATCH_LOCAL_PSTATE_IDX_LENGTH)
@@ -119,7 +175,6 @@ void p9_cme_pstate_intercme_in0_handler()
}
p9_cme_pstate_pmsr_updt(G_cme_record.core_enabled);
- PKTRACE("INTER0: pmin=0x%08x,pmax=0x%08x", G_cme_pstate_record.pmin, G_cme_pstate_record.pmax);
}
else if(dbData.fields.cme_message_number0 == MSGID_DB0_STOP_PSTATE_BROADCAST)
{
@@ -134,11 +189,24 @@ void p9_cme_pstate_intercme_in0_handler()
//Set Core GPMMR RESET_STATE_INDICATOR bit to show pstates have stopped
CME_PUTSCOM(PPM_GPMMR_OR, G_cme_record.core_enabled, BIT64(15));
}
- else if(dbData.fields.cme_message_number0 == MSGID_DB0_SAFE_MODE_BROADCAST)
+ else if(dbData.fields.cme_message_number0 == MSGID_DB0_PMSR_UPDT)
{
- PK_TRACE("INTER0: DB0 Safe Mode");
+ PK_TRACE("INTER0: DB0 PMSR Updt");
+
+ switch(dbBit8_15)
+ {
+ case DB0_PMSR_UPDT_SET_SAFE_MODE:
+ G_cme_pstate_record.safeMode = 1;
+ break;
- G_cme_pstate_record.safeMode = 1;
+ case DB0_PMSR_UPDT_SET_PSTATES_SUSPENDED:
+ G_cme_pstate_record.pstatesSuspended = 1;
+ break;
+
+ case DB0_PMSR_UPDT_CLEAR_PSTATES_SUSPENDED:
+ G_cme_pstate_record.pstatesSuspended = 0;
+ break;
+ }
p9_cme_pstate_pmsr_updt(G_cme_record.core_enabled);
}
@@ -151,22 +219,5 @@ void p9_cme_pstate_intercme_in0_handler()
intercme_direct(INTERCME_DIRECT_IN0, INTERCME_DIRECT_ACK, 0);
- pk_irq_vec_restore(&ctx);
-
PK_TRACE("INTER0: Exit");
}
-
-void p9_cme_pstate_intercme_msg_handler(void* arg, PkIrqId irq)
-{
- PkMachineContext ctx __attribute__((unused));
- // Override mask, disable every interrupt except high-priority ones via the
- // priority mask for this interrupt (p9_pk_irq.c)
- uint32_t msg;
- intercme_msg_recv(&msg, IMT_LOCK_SIBLING);
-
- // Block on the intercme0 interrupt
- while(!(in32(CME_LCL_EISR) & BIT32(7))) {}
-
- // Restore the mask, cede control to the intercme0 interrupt handler
- pk_irq_vec_restore(&ctx);
-}
diff --git a/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.c b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.c
index b5bf3379..b87635f3 100644
--- a/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.c
+++ b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.c
@@ -88,19 +88,87 @@ int send_pig_packet(uint64_t data, uint32_t coreMask)
return rc;
}
-void poll_dpll_update_complete()
+uint32_t poll_dpll_stat()
{
- data64_t polldata;
- PK_TRACE_INF("Poll on DPLL_STAT[update_complete]");
+ data64_t data;
+ uint32_t cme_flags = in32(CME_LCL_FLAGS);
+ uint32_t rc = 0;
- // ... to indicate that the DPLL has sampled the newly requested
- // frequency into its internal registers as a target,
- // but may not yet be there
- do
+ // DPLL Mode 2
+ if(!(cme_flags & BIT32(CME_FLAGS_VDM_OPERABLE)))
{
- ippm_read(QPPM_DPLL_STAT, &polldata.value);
+ PK_TRACE_INF("Poll on DPLL_STAT[freq_change=0]");
+
+ // ... to indicate that the DPLL is safely either at the new frequency
+ // or in droop protection below the new frequency
+ do
+ {
+ ippm_read(QPPM_DPLL_STAT, &data.value);
+ }
+ while((data.words.lower & BIT64SH(61)));
+ }
+
+ // DPLL Mode 3
+ if(cme_flags & BIT32(CME_FLAGS_VDM_OPERABLE))
+ {
+ PK_TRACE_INF("Poll on DPLL_STAT[update_complete=1]");
+ // ... to indicate that the DPLL has sampled the newly requested
+ // frequency into its internal registers as a target,
+ // but may not yet be there
+ uint32_t tbStart, tbEnd, elapsed;
+ cppm_csar_t csar;
+ csar.value = 0;
+
+ //Read CPPM_CSAR
+ if (cme_flags & BIT32(CME_FLAGS_CORE0_GOOD))
+ {
+ CME_GETSCOM(CPPM_CSAR, CME_MASK_C0, csar.value);
+ }
+ else if (cme_flags & BIT32(CME_FLAGS_CORE1_GOOD))
+ {
+ CME_GETSCOM(CPPM_CSAR, CME_MASK_C1, csar.value);
+ }
+
+ //Read TimebaseStart
+ tbStart = in32(CME_LCL_TBR);
+
+ do
+ {
+ //Read DPLL_STAT
+ ippm_read(QPPM_DPLL_STAT, &data.value);
+
+ //If QPPM_DPLL_STAT[60/UPDATE_COMPLETE]=1
+ if(data.words.lower & BIT64SH(60))
+ {
+ break;
+ }
+
+ //Read TimebaseEnd
+ tbEnd = in32(CME_LCL_TBR);
+
+ //Compute Elapsed Count with accounting for Timebase Wrapping
+ if (tbEnd > tbStart)
+ {
+ elapsed = tbEnd - tbStart;
+ }
+ else
+ {
+ elapsed = 0xFFFFFFFF - tbStart + tbEnd + 1;
+ }
+
+ //If !CPPM_CSAR[DIS_NACK] AND (Elapsed Count > DROOP_POLL_COUNT), then prolonged
+ //droop detected
+ if (!(csar.value & BIT64(CPPM_CSAR_DISABLE_CME_NACK_ON_PROLONGED_DROOP)) &&
+ elapsed > DROOP_POLL_COUNT)
+ {
+ rc = 1; //Non-zero return code
+ break;
+ }
+ }
+ while(1);
}
- while(!(polldata.words.lower & BIT32(28)));
+
+ return rc;
}
// Non-atomic Interppm-read, this function is not made availabe via the header
@@ -437,8 +505,9 @@ uint32_t calc_vdm_jump_values(uint32_t pstate, uint32_t region)
return new_jump_values;
}
-void update_vdm_jump_values_in_dpll(uint32_t pstate, uint32_t region)
+uint32_t update_vdm_jump_values_in_dpll(uint32_t pstate, uint32_t region)
{
+ uint32_t rc = 0;
data64_t scom_data = { 0 };
uint32_t new_jump_values = calc_vdm_jump_values(pstate, region);
// Read the current contents of DPLL_CTRL and then update only the jump
@@ -472,38 +541,44 @@ void update_vdm_jump_values_in_dpll(uint32_t pstate, uint32_t region)
reduced_dpll_val.fields.fmin = reduced_dpll_val.fields.fmult;
// Write the reduced frequency
nonatomic_ippm_write(QPPM_DPLL_FREQ, reduced_dpll_val.value);
- poll_dpll_update_complete();
- // Clear jump enable (drop to Mode 2)
- nonatomic_ippm_write(QPPM_DPLL_CTRL_CLR, BIT64(1));
- // Poll for lock
- PK_TRACE_INF("Poll on DPLL_STAT[block_active|lock]");
+ rc = poll_dpll_stat();
- // ... to indicate that the DPLL is safely either at the new frequency
- // or in droop protection below the new frequency
- do
+ if (!rc)
{
- nonatomic_ippm_read(QPPM_DPLL_STAT, &poll_data.value);
- }
- while(!(poll_data.words.lower & BITS32(30, 2)));
-
- // Write the new jump values (clear jump enable)
- scom_data.value &= ~BIT64(1);
- scom_data.words.lower = new_jump_values;
- nonatomic_ippm_write(QPPM_DPLL_CTRL, scom_data.value);
- // Set jump enable (switch back to Mode 3)
- nonatomic_ippm_write(QPPM_DPLL_CTRL_OR, BIT64(1));
-
- // The frequency will be raised as part of the pstate transition if
- // lowering the pstate, don't need to do anything here
- if(pstate >= G_cme_pstate_record.quadPstate)
- {
- // Restore frequency
- nonatomic_ippm_write(QPPM_DPLL_FREQ, saved_dpll_val.value);
- poll_dpll_update_complete();
+ // Clear jump enable (drop to Mode 2)
+ nonatomic_ippm_write(QPPM_DPLL_CTRL_CLR, BIT64(1));
+ // Poll for lock
+ PK_TRACE_INF("Poll on DPLL_STAT[block_active|lock]");
+
+ // ... to indicate that the DPLL is safely either at the new frequency
+ // or in droop protection below the new frequency
+ do
+ {
+ nonatomic_ippm_read(QPPM_DPLL_STAT, &poll_data.value);
+ }
+ while(!(poll_data.words.lower & BITS32(30, 2)));
+
+ // Write the new jump values (clear jump enable)
+ scom_data.value &= ~BIT64(1);
+ scom_data.words.lower = new_jump_values;
+ nonatomic_ippm_write(QPPM_DPLL_CTRL, scom_data.value);
+ // Set jump enable (switch back to Mode 3)
+ nonatomic_ippm_write(QPPM_DPLL_CTRL_OR, BIT64(1));
+
+ // The frequency will be raised as part of the pstate transition if
+ // lowering the pstate, don't need to do anything here
+ if(pstate >= G_cme_pstate_record.quadPstate)
+ {
+ // Restore frequency
+ nonatomic_ippm_write(QPPM_DPLL_FREQ, saved_dpll_val.value);
+ rc = poll_dpll_stat();
+ }
}
pk_critical_section_exit(&ctx);
}
+
+ return rc;
}
#endif//NIMBUS_DD_LEVEL
@@ -549,11 +624,11 @@ void calc_vdm_threshold_indices(uint32_t pstate, uint32_t region,
? indices[VDM_SMALL_IDX] : indices[VDM_XTREME_IDX];
}
-void p9_cme_vdm_update(uint32_t pstate)
+uint32_t p9_cme_vdm_update(uint32_t pstate)
{
// Static forces this array into .sbss instead of calling memset()
static uint32_t new_idx[NUM_THRESHOLD_POINTS] = { 0 };
- uint32_t i = 0;
+ uint32_t i = 0, rc = 0;
// Set one bit per threshold starting at bit 31 (28,29,30,31)
uint32_t not_done = BITS32(32 - NUM_THRESHOLD_POINTS, NUM_THRESHOLD_POINTS);
uint64_t scom_data = 0;
@@ -603,8 +678,9 @@ void p9_cme_vdm_update(uint32_t pstate)
while(not_done);
#if NIMBUS_DD_LEVEL != 10
- update_vdm_jump_values_in_dpll(pstate, region);
+ rc = update_vdm_jump_values_in_dpll(pstate, region);
#endif//NIMBUS_DD_LEVEL
+ return rc;
}
#endif//USE_CME_VDM_FEATURE
@@ -712,6 +788,12 @@ void p9_cme_pstate_pmsr_updt(uint32_t coreMask)
pmsrData |= BIT64(33);
}
+ //PMSR[35] is PSTATES_SUSPENDED bit
+ if(G_cme_pstate_record.pstatesSuspended)
+ {
+ pmsrData |= BIT64(35);
+ }
+
out64(CME_LCL_PMSRS0 + ((cm & 0x1) << 5), pmsrData);
}
}
diff --git a/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.h b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.h
index 8fabc5b0..b13ca15f 100644
--- a/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.h
+++ b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.h
@@ -57,18 +57,24 @@ enum DPLL
DPLL_MAX_VALUE = 300, //DPLL value @5000Mhz (5000/16.667)
};
+enum DROOP_POLL
+{
+ DROOP_POLL_TIME_NS = 200000, //This defines the duration
+ DROOP_POLL_COUNT = DROOP_POLL_TIME_NS / 32 //32ns per timebase tick
+};
+
typedef struct
{
- uint32_t core0_resclk_idx;
- uint32_t core1_resclk_idx;
- uint32_t l2_ex0_resclk_idx;
- uint32_t l2_ex1_resclk_idx;
- uint32_t common_resclk_idx;
+ uint32_t core0_resclk_idx; //4
+ uint32_t core1_resclk_idx; //8
+ uint32_t l2_ex0_resclk_idx; //12
+ uint32_t l2_ex1_resclk_idx; //16
+ uint32_t common_resclk_idx; //20
} cme_resclk_data_t;
typedef struct
{
- uint32_t vdm_threshold_idx[NUM_THRESHOLD_POINTS];
+ uint32_t vdm_threshold_idx[NUM_THRESHOLD_POINTS]; //4*4=16
} cme_vdm_data_t;
typedef enum
@@ -160,20 +166,21 @@ typedef struct
#if !defined(__IOTA__)
PkSemaphore sem[2];
#endif
- uint32_t qmFlag;
- uint32_t siblingCMEFlag;
- uint32_t quadPstate;
- uint32_t cmeMaskGoodCore;
- uint32_t globalPstate;
+ uint32_t qmFlag; //4
+ uint32_t siblingCMEFlag; //8
+ uint32_t quadPstate; //12
+ uint32_t cmeMaskGoodCore; //16
+ uint32_t globalPstate; //20
#ifdef USE_CME_RESCLK_FEATURE
- cme_resclk_data_t resclkData;
+ cme_resclk_data_t resclkData; //40
#endif//USE_CME_RESCLK_FEATURE
#ifdef USE_CME_VDM_FEATURE
- cme_vdm_data_t vdmData;
+ cme_vdm_data_t vdmData; //56
#endif//USE_CME_VDM_FEATURE
- uint32_t pmin;
- uint32_t safeMode;
- uint32_t pmax;
+ uint32_t pmin; //60
+ uint32_t safeMode; //64
+ uint32_t pmax; //68
+ uint32_t pstatesSuspended; //72(0x48)
} CmePstateRecord;
typedef struct
@@ -182,14 +189,17 @@ typedef struct
} cme_pstate_pmcr_data_t;
void p9_cme_pstate_pmcr_thread(void*);
-void p9_cme_pstate_db_thread(void*);
+void p9_cme_pstate_db0_thread(void*);
void p9_cme_pstate_pmcr_handler(void*, PkIrqId);
-void p9_cme_pstate_db_handler(void*, PkIrqId);
+void p9_cme_pstate_db0_handler(void*, PkIrqId);
+void p9_cme_pstate_db3_handler(void*, PkIrqId);
+void p9_cme_pstate_db3_handler_replay_db0();
+void p9_cme_pstate_db3_handler_high_priority_pstate(uint32_t pstate);
void p9_cme_pstate_intercme_in0_irq_handler(void*, PkIrqId);
void p9_cme_pstate_intercme_msg_handler(void* arg, PkIrqId irq);
void p9_cme_pstate_db0_safe_mode();
int send_pig_packet(uint64_t data, uint32_t coreMask);
-void poll_dpll_update_complete();
+uint32_t poll_dpll_stat();
void ippm_read(uint32_t addr, uint64_t* data);
void ippm_write(uint32_t addr, uint64_t data);
void intercme_msg_send(uint32_t msg, INTERCME_MSG_TYPE type);
@@ -198,7 +208,8 @@ void intercme_direct(INTERCME_DIRECT_INTF intf, INTERCME_DIRECT_TYPE type, uint3
void p9_cme_core_stop_analog_control(uint32_t core_mask, ANALOG_CONTROL enable);
void p9_cme_pstate_pmsr_updt(uint32_t coreMask);
void p9_cme_pstate_pmsr_updt_in_progress(uint32_t coreMask);
-void p9_cme_pstate_intercme_in0_handler();
+void p9_cme_pstate_sibling_lock_and_intercme_protocol(uint32_t process_intercme_in0, uint32_t readDB0, uint64_t dbData);
+void p9_cme_pstate_process_db0_sibling(uint64_t dbData);
#ifdef USE_CME_RESCLK_FEATURE
uint32_t p9_cme_resclk_get_index(uint32_t pstate);
@@ -206,8 +217,8 @@ void p9_cme_pstate_intercme_in0_handler();
#endif//USE_CME_RESCLK_FEATURE
#ifdef USE_CME_VDM_FEATURE
uint32_t calc_vdm_jump_values(uint32_t pstate, uint32_t region);
-void update_vdm_jump_values_in_dpll(uint32_t pstate, uint32_t region);
-void p9_cme_vdm_update(uint32_t pstate);
+uint32_t update_vdm_jump_values_in_dpll(uint32_t pstate, uint32_t region);
+uint32_t p9_cme_vdm_update(uint32_t pstate);
uint32_t pstate_to_vid_compare(uint32_t pstate, uint32_t region);
uint32_t pstate_to_vpd_region(uint32_t pstate);
void calc_vdm_threshold_indices(uint32_t pstate, uint32_t region,
diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.c b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.c
index 49e946e5..59c1b1ea 100644
--- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.c
+++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.c
@@ -34,6 +34,7 @@
#include "wof_sgpe_pgpe_api.h"
#include "p9_pgpe_header.h"
#include "p9_pgpe_optrace.h"
+#include "ppe42_cache.h"
//
//#Defines
@@ -51,6 +52,7 @@ extern uint32_t G_ext_vrm_inc_rate_mult_usperus;
extern uint32_t G_ext_vrm_dec_rate_mult_usperus;
extern PgpePstateRecord G_pgpe_pstate_record;
extern void p9_pgpe_ipc_ack_sgpe_ctrl_stop_updt(ipc_msg_t* msg, void* arg);
+extern void p9_pgpe_ipc_ack_sgpe_suspend_stop(ipc_msg_t* msg, void* arg);
//
//Global Data
@@ -61,8 +63,9 @@ GPE_BUFFER(ipcmsg_p2s_suspend_stop_t G_sgpe_suspend_stop);
//Local Functions
void p9_pgpe_pstate_freq_updt();
-void p9_pgpe_suspend_stop_callback(ipc_msg_t* msg, void* arg);
void p9_pgpe_pstate_dpll_write(uint32_t quadsVector, uint64_t val);
+void p9_pgpe_droop_throttle();
+void p9_pgpe_droop_unthrottle();
//
//p9_pgpe_pstate_init
@@ -438,12 +441,16 @@ void p9_pgpe_pstate_updt_actual_quad(uint32_t quadsVector)
//p9_pgpe_send_db0
//
//Sends DB0 to CMEs
-void p9_pgpe_send_db0(uint64_t db0, uint32_t coreVector, uint32_t unicast, uint32_t ack, uint32_t ackVector)
+void p9_pgpe_send_db0(uint64_t db0, uint32_t origCoreVector,
+ uint32_t unicast, uint32_t ackWait, uint32_t origAckVector)
{
- uint32_t c;
+ uint32_t c, q;
+ uint32_t ackVector = origAckVector;
+ uint32_t coreVector = origCoreVector;
+ G_pgpe_pstate_record.quadsNACKed = 0;
- PK_TRACE_DBG("SDB: Send DB0");
+ PK_TRACE_DBG("SDB: Send DB0 coreVector=0x%x,unicast=0x%x,ackVector=0x%x", origCoreVector, unicast, origAckVector);
//In case of unicast, only write DB0 for active cores. However, in case of
//multicast just write DB0 of every configured core, but care only about active cores.
@@ -471,16 +478,94 @@ void p9_pgpe_send_db0(uint64_t db0, uint32_t coreVector, uint32_t unicast, uint3
#endif
}
- if (ack == PGPE_DB0_ACK_WAIT_CME)
+ p9_pgpe_wait_cme_db_ack(ackVector);//Wait for ACKs from QuadManagers
+
+ PK_TRACE_DBG("SDB: quadsNACKed=0x%x", G_pgpe_pstate_record.quadsNACKed);
+
+ if(G_pgpe_pstate_record.quadsNACKed)
{
- p9_pgpe_wait_cme_db_ack(ackVector);//Wait for ACKs from QuadManagers
+ PK_TRACE_DBG("SDB: quadsNACKed=0x%x", G_pgpe_pstate_record.quadsNACKed);
+
+ //a. If OCC Scratch2 Core Throttle Continuous Change Enable bit is set (i.e. during Manufacturing test), halt the PGPE with a unique error code.
+ //Engineering Note: characterization team is responsible to set CSAR bit "Disable CME NACK on Prolonged Droop" when doing PGPE throttle scom injection.
+ if(in32(OCB_OCCS2) & BIT32(CORE_THROTTLE_CONTINUOUS_CHANGE_ENABLE))
+ {
+ PGPE_PANIC_AND_TRACE(PGPE_DROOP_AND_CORE_THRTLE_ENABLED);
+ }
+
+ //b) If OCC flag PGPE Prolonged Droop Workaround Active bit is not set,
+ // call droop_throttle()
+
+ if (!(in32(OCB_OCCFLG) & BIT32(PGPE_PROLONGED_DROOP_WORKAROUND_ACTIVE)))
+ {
+ p9_pgpe_droop_throttle();
+ }
+
+ //c) Send DB3 (Replay Previous DB0 Operation) to only the CME Quad Managers, and
+ //their Sibling CME (if present), that responded with a NACK.
+ uint64_t db3val = (uint64_t)MSGID_DB3_REPLAY_DB0 << 56;
+
+ while(G_pgpe_pstate_record.quadsNACKed)
+ {
+ G_pgpe_pstate_record.cntNACKs++;
+ ackVector = G_pgpe_pstate_record.quadsNACKed;
+
+ for (q = 0; q < MAX_QUADS; q++)
+ {
+ //If quad provided an ACK, then don't send DB3 again
+ if(!(G_pgpe_pstate_record.quadsNACKed & QUAD_MASK(q)))
+ {
+ coreVector &= (~QUAD_ALL_CORES_MASK(q));
+ }
+ else
+ {
+ G_pgpe_pstate_record.quadsCntNACKs[q]++;
+ }
+ }
+
+ //If a NACK received was in response to the first retry (i.e. second failed attempt):
+ if (G_pgpe_pstate_record.cntNACKs == 2)
+ {
+ // 1 SCOM Write to OCC FIR[prolonged_droop_detected] bit. This FIR bit is set to recoverable so that it will create an informational error log.
+ GPE_PUTSCOM(OCB_OCCLFIR_OR, BIT64(OCCLFIR_PROLONGED_DROOP_DETECTED));
+
+ // 2 Set OCC Flag register PGPE PM Reset Suppress bit that OCC
+ // will read to tell OCC not to attempt a PM Complex reset on
+ // PGPE timeouts in the meantime.
+ out32(OCB_OCCFLG_OR, BIT32(PGPE_PM_RESET_SUPPRESS));
+
+ // 3 Send DB0 PMSR Update with message Set Pstates Suspended only
+ // to the CME QM (and their Siblings) that provided an ACK
+ // (note: PGPE must also wait for them to ACK the DB0)
+ p9_pgpe_pstate_pmsr_updt(DB0_PMSR_UPDT_SET_PSTATES_SUSPENDED,
+ origCoreVector & (~coreVector),
+ origAckVector & (~G_pgpe_pstate_record.quadsNACKed));
+ }
+
+ //The PGPE then retries the DB3 (Replay Previous DB0 Operation)
+ //again as described above to all CME QM (and their Siblings)
+ //that responded with NACK until it no longer gets a NACK (attempt to self-heal)
+ for (c = 0; c < MAX_CORES; c++)
+ {
+ if (coreVector & CORE_MASK(c))
+ {
+ GPE_PUTSCOM(GPE_SCOM_ADDR_CORE(CPPM_CMEDB3, c), db3val)
+ }
+ }
+
+ p9_pgpe_wait_cme_db_ack(ackVector);//Wait for ACKs from QuadManagers
+ }//End while(quadNACked) loop
+
+ //if OCC Flag Register PGPE Prolonged Droop Workaround Active bit is set and all CME QMs respond with ACK
+ p9_pgpe_droop_unthrottle();
}
}
void p9_pgpe_wait_cme_db_ack(uint32_t quadAckExpect)
{
- uint32_t q;
+ uint32_t q, c;
uint32_t opit4pr, opit4prQuad, opit4Clr = 0;
+ ocb_opit4cn_t opit4cn;
PK_TRACE_INF("DBW: AckExpect=0x%x", quadAckExpect);
@@ -498,9 +583,45 @@ void p9_pgpe_wait_cme_db_ack(uint32_t quadAckExpect)
{
if (quadAckExpect & QUAD_MASK(q))
{
+ PK_TRACE_INF("DBW: Quad[%d] Acked", q);
quadAckExpect &= ~QUAD_MASK(q);
opit4Clr |= (opit4prQuad << ((MAX_QUADS - q + 1) << 2));
- PK_TRACE_DBG("DBW: GotAck from %d", q);
+ c = 0;
+
+ while(!(opit4prQuad & (0x8 >> c)))
+ {
+ c++;
+ }
+
+ opit4cn.value = in32(OCB_OPIT4CN((q * 4) + c));
+
+ PK_TRACE_INF("DBW: opit4cn[%d]=0x%x", c, opit4cn.value);
+
+ switch (opit4cn.value & 0xf)
+ {
+ case MSGID_PCB_TYPE4_ACK_ERROR: //0x0
+ PGPE_PANIC_AND_TRACE(PGPE_CME_DB0_ERROR_ACK);
+ break;
+
+ case MSGID_PCB_TYPE4_ACK_PSTATE_PROTO_ACK: //0x1
+ case MSGID_PCB_TYPE4_ACK_PSTATE_SUSPENDED: //0x2
+ //Do nothing as there is no error
+ break;
+
+ case MSGID_PCB_TYPE4_NACK_DROOP_PRESENT: //0x4
+ //Mark that this quad sent a NACK
+ PK_TRACE_DBG("DBW: Got NACK from %d", q);
+ G_pgpe_pstate_record.quadsNACKed |= QUAD_MASK(q);
+ PK_TRACE_DBG("DBW: QuadsNACKed=0x%x", G_pgpe_pstate_record.quadsNACKed);
+ break;
+
+ //Note this includes MSGID_PCB_TYPE4_QUAD_MGR_AVAILABLE(0x3)
+ //and other undefined encoding
+ default:
+ PK_TRACE_ERR("DBW:Unexpected qCME[%u] ACK type", q);
+ PGPE_PANIC_AND_TRACE(PGPE_CME_UNEXPECTED_DB0_ACK);
+ }
+
}
else if(!(G_pgpe_pstate_record.pendQuadsRegisterReceive & QUAD_MASK(q)))
{
@@ -513,7 +634,7 @@ void p9_pgpe_wait_cme_db_ack(uint32_t quadAckExpect)
out32(OCB_OPIT4PRA_CLR, opit4Clr);
}
- PK_TRACE_DBG("DBW:qCME ACKs rcvd");
+ PK_TRACE_DBG("DBW: QuadsNACKed=0x%x", G_pgpe_pstate_record.quadsNACKed);
}
//
@@ -730,6 +851,11 @@ void p9_pgpe_pstate_start(uint32_t pstate_start_origin)
PGPE_DB0_ACK_WAIT_CME,
G_pgpe_pstate_record.activeQuads);
+ //In case VDM Prolonged Droop event occured during PSTATE_START, then clearing
+ //ensures OCC is notified about Prolonged Droop event resolution.
+ //Also, at this point nothing else should be pending from OCC, so safe to clear.
+ out32(OCB_OCCFLG_CLR, BIT32(PGPE_PM_RESET_SUPPRESS));
+
//Lower voltage if boot voltage > syncPstate voltage
if (G_pgpe_pstate_record.eVidCurr > G_pgpe_pstate_record.eVidNext)
{
@@ -865,9 +991,8 @@ void p9_pgpe_pstate_stop()
GPE_PUTSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_LMCR_OR, q, 1), BIT64(0));
}
- //PGPE opens DPLL for SCOMs on quads that are about to enter STOP11
- //or have exited STOP11, but not registered yet. Or, to said another
- //non-active quads that are powered on will have DPLL open for SCOMs
+ //Only need to do that for active quads here because PGPE opens DPLL for SCOMs
+ //for other quads.
GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(QPPM_QPMMR_CLR, q), BIT64(26));
}
}
@@ -1218,14 +1343,9 @@ void p9_pgpe_pstate_safe_mode()
PK_TRACE_INF("SAF: Safe Mode Actuation Done!");
//Send SAFE Mode Bcast to all CMEs
- pgpe_db0_safe_mode_bcast_t db0_sm_bcast;
- db0_sm_bcast.value = 0;
- db0_sm_bcast.fields.msg_id = MSGID_DB0_SAFE_MODE_BROADCAST;
- p9_pgpe_send_db0(db0_sm_bcast.value,
- G_pgpe_pstate_record.activeDB,
- PGPE_DB0_UNICAST,
- PGPE_DB0_ACK_WAIT_CME,
- G_pgpe_pstate_record.activeQuads);
+ p9_pgpe_pstate_pmsr_updt(DB0_PMSR_UPDT_SET_SAFE_MODE,
+ G_pgpe_pstate_record.activeDB,
+ G_pgpe_pstate_record.activeQuads);
//Update PstatesStatus to PM_SUSPEND_PENDING or PSTATE_SAFE_MODE
G_pgpe_pstate_record.pstatesStatus = suspend ? PSTATE_PM_SUSPEND_PENDING : PSTATE_SAFE_MODE;
@@ -1297,31 +1417,75 @@ void p9_pgpe_pstate_safe_mode()
//
//p9_pgpe_pstate_send_suspend_stop
//
-void p9_pgpe_pstate_send_suspend_stop()
+void p9_pgpe_pstate_send_suspend_stop(uint32_t command)
{
-#if SGPE_IPC_ENABLED == 1
+//#if SGPE_IPC_ENABLED == 1
p9_pgpe_optrace(PRC_PM_SUSP);
int rc;
G_sgpe_suspend_stop.fields.msg_num = MSGID_PGPE_SGPE_SUSPEND_STOP;
+ G_sgpe_suspend_stop.fields.command = command;
G_sgpe_suspend_stop.fields.return_code = 0x0;
G_ipc_msg_pgpe_sgpe.cmd_data = &G_sgpe_suspend_stop;
ipc_init_msg(&G_ipc_msg_pgpe_sgpe.cmd,
IPC_MSGID_PGPE_SGPE_SUSPEND_STOP,
- p9_pgpe_suspend_stop_callback,
+ p9_pgpe_ipc_ack_sgpe_suspend_stop,
(void*)NULL);
- //Set SCOM Ownership of PMCR
- PK_TRACE_INF("SUSP: Setting SCOM Ownership of PMCRs");
+ //send the command
+ PK_TRACE_INF("SUSP:Sending Suspend Stop(cmd=0x%x)", command);
+ rc = ipc_send_cmd(&G_ipc_msg_pgpe_sgpe.cmd);
+ if(rc)
+ {
+ PK_TRACE_ERR("SUSP:Suspend Stop BAD ACK");
+ PGPE_PANIC_AND_TRACE(PGPE_SGPE_SUSPEND_STOP_BAD_ACK);
+ }
+
+ //Just block until SGPE writes the return code field
+ //It is assumed that SGPE will write this field right before
+ //calling ipc_send_rsp(). Also, note that PGPE will get the ACK
+ //in the form of IPC interrupt which will call the ipc_ack_suspend_stop
+ //This IPC handler is effectively a NOP writing the return code fields
+ //act as ACK for PGPE. Alternative is to wait until ACKs arrives and do processing
+ //in the IPC ACK handler, but this requires opening up IPC interrupt. Instead, we
+ //do processing after blocking
+ while(G_sgpe_suspend_stop.fields.return_code == IPC_SGPE_PGPE_RC_NULL)
+ {
+ dcbi(((void*)(&G_sgpe_suspend_stop)));
+ }
+
+ if (G_sgpe_suspend_stop.fields.return_code != IPC_SGPE_PGPE_RC_SUCCESS)
+ {
+ PK_TRACE_ERR("ERROR: SGPE Suspend STOP Bad RC. Halting PGPE!");
+ PGPE_PANIC_AND_TRACE(PGPE_SGPE_SUSPEND_STOP_BAD_ACK);
+ }
+
+ PK_TRACE_INF("SUSP:Suspend Stop(cmd=0x%x) ACKed", command);
+}
+
+//
+//This function sends Suspend Stop(Entry and Exit) to SGPE
+//It is called as part of PM Complex Suspend processing. Before
+//calling this function it is assumed the system is in SAFE_MODE.
+//There is no function to undo the suspend. Only PM Reset can bring the
+//PM Complex out of this state.
+//
+void p9_pgpe_pstate_pm_complex_suspend()
+{
int q = 0;
ocb_qcsr_t qcsr;
+
+ //Send IPC and wait for ACK
+ p9_pgpe_pstate_send_suspend_stop(SUSPEND_STOP_SUSPEND_ENTRY_EXIT);
+
+ //Change PMCR ownership
+ PK_TRACE_INF("SUSP: Setting SCOM Ownership of PMCRs");
qcsr.value = in32(OCB_QCSR);
//Set LMCR for each CME
for (q = 0; q < MAX_QUADS; q++)
{
- //if(G_pgpe_pstate_record.pReqActQuads->fields.requested_active_quads & (0x80 >> q))
if(G_pgpe_pstate_record.activeQuads & QUAD_MASK(q))
{
//CME0 within this quad
@@ -1338,27 +1502,7 @@ void p9_pgpe_pstate_send_suspend_stop()
}
}
- //send the command
- PK_TRACE_INF("SUSP:Sending Suspend IPC to SGPE");
- rc = ipc_send_cmd(&G_ipc_msg_pgpe_sgpe.cmd);
-
- if(rc)
- {
- PK_TRACE_ERR("SUSP:Suspend Stop BAD ACK");
- PGPE_PANIC_AND_TRACE(PGPE_SGPE_SUSPEND_STOP_BAD_ACK);
- }
-
-#else
- p9_pgpe_suspend_stop_callback(NULL, NULL);
-#endif
-}
-
-//
-//p9_pgpe_suspend_stop_callback
-//
-void p9_pgpe_suspend_stop_callback(ipc_msg_t* msg, void* arg)
-{
- PK_TRACE_INF("SUSP:Stop Cb");
+ //OP Trace and Set OCCS2[PM_COMPLEX_SUSPENDED)
p9_pgpe_optrace(ACK_PM_SUSP);
uint32_t occScr2 = in32(OCB_OCCS2);
occScr2 |= BIT32(PM_COMPLEX_SUSPENDED);
@@ -1366,6 +1510,21 @@ void p9_pgpe_suspend_stop_callback(ipc_msg_t* msg, void* arg)
out32(OCB_OCCS2, occScr2);
}
+
+void p9_pgpe_pstate_pmsr_updt(uint32_t command, uint32_t targetCoresVector, uint32_t quadsAckVector)
+{
+ pgpe_db0_pmsr_updt_t db0_pmsr_updt;
+ db0_pmsr_updt.value = 0;
+ db0_pmsr_updt.fields.msg_id = MSGID_DB0_PMSR_UPDT;
+ db0_pmsr_updt.fields.command = command;
+ p9_pgpe_send_db0(db0_pmsr_updt.value,
+ targetCoresVector,
+ PGPE_DB0_UNICAST,
+ PGPE_DB0_ACK_WAIT_CME,
+ quadsAckVector);
+}
+
+
//
//p9_pgpe_pstate_at_target
//
@@ -1702,3 +1861,96 @@ void p9_pgpe_pstate_ipc_rsp_cb_sem_post(ipc_msg_t* msg, void* arg)
{
pk_semaphore_post((PkSemaphore*)arg);
}
+
+// Write to the PC Throttle Control register. Ignore any PCB errors.
+// Option to retry on known PC hardware bug (always cleanup if happens)
+//
+void p9_pgpe_pstate_write_core_throttle(uint32_t throttleData, uint32_t enable_retry)
+{
+ uint32_t pc_fail;
+ uint32_t value = mfmsr();
+ mtmsr(value | MSR_THROTTLE_MASK); //don't cause halt if all cores offline or address error (PC Timeout)
+
+ do
+ {
+ out64(THROTTLE_SCOM_MULTICAST_WRITE, ((uint64_t) throttleData << 32)); //apply new throttle SCOM setting
+
+ // Work-around for PC HW problem. See SW407201
+ // If ADDRESS_ERROR then perform a SCOM write of all zeros to
+ // 2n010800 where n is the core number. Ignore ADDRESS_ERROR
+ // and TIMEOUT returned.
+ pc_fail = (((mfmsr() >> 20) & 0x7) == 0x4);
+
+ if (pc_fail)
+ {
+ out64(WORKAROUND_SCOM_MULTICAST_WRITE, 0);
+ }
+ }
+ while (enable_retry && pc_fail);
+
+ mtmsr(value); // restore MSR
+}
+
+void p9_pgpe_droop_throttle()
+{
+ PK_TRACE_DBG("DTH: Droop Throttle Enter");
+
+ uint32_t q;
+ //1. PGPE sends IPC to SGPE to Suspend Stop Entries Only, and poll for Success return code (do not open IPCs, ignore the subsequent ACK). This will prevent a core from going into Stop2 and missing the subsequent "unthrottle."
+ //p9_pgpe_pstate_send_suspend_stop(SUSPEND_STOP_SUSPEND_ENTRY);
+
+
+ //2. Call the core_instruction_throttle() procedure to enable throttle (same as used by FIT).
+ p9_pgpe_pstate_write_core_throttle(CORE_IFU_THROTTLE, RETRY);
+
+ //3. Set the OCC flag PGPE Prolonged Droop Workaround Active bit.
+ out32(OCB_OCCFLG_OR, BIT32(PGPE_PROLONGED_DROOP_WORKAROUND_ACTIVE));
+
+ //4. Clear the Prolonged Droop Global variables (Bit vector and retry counts).
+ G_pgpe_pstate_record.cntNACKs = 0;
+
+ for (q = 0; q < MAX_QUADS; q++)
+ {
+ G_pgpe_pstate_record.quadsCntNACKs[q] = 0;
+ }
+
+ //5. Write PK Trace and Optrace record that the Prolonged Throttle workaround was engaged, including a bit vector of Quads that provided the NACK(s).
+ G_pgpe_optrace_data.word[0] = (G_pgpe_pstate_record.activeQuads << 24) |
+ (G_pgpe_pstate_record.globalPSCurr << 16) |
+ (G_pgpe_pstate_record.globalPSTarget << 8) |
+ G_pgpe_pstate_record.quadsNACKed;
+ p9_pgpe_optrace(PROLONGED_DROOP_EVENT);
+
+
+ PK_TRACE_DBG("DTH: Droop Throttle Exit");
+}
+
+
+void p9_pgpe_droop_unthrottle()
+{
+ PK_TRACE_DBG("DTH: Droop Unthrottle Enter");
+
+ //1. Call the core_instruction_throttle() procedure to disable throttle (same as used by FIT).
+ p9_pgpe_pstate_write_core_throttle(CORE_THROTTLE_OFF, RETRY);
+
+ //2. PGPE sends IPC to SGPE to Unsuspend STOP entries & poll for Success return code (do not open IPCs, ignore the subsequent ACK).
+ // p9_pgpe_pstate_send_suspend_stop(SUSPEND_STOP_UNSUSPEND_ENTRY);
+
+ //3. Send Doorbell0 PMSR Update with message Clear Pstates Suspended to all configured cores in the active Quads.
+ p9_pgpe_pstate_pmsr_updt(DB0_PMSR_UPDT_CLEAR_PSTATES_SUSPENDED,
+ G_pgpe_pstate_record.activeDB,
+ G_pgpe_pstate_record.activeQuads);
+
+ //4. Clear the OCC flag PGPE Prolonged Droop Workaround Active. OCCFLG[PM_RESET_SUPPRESS] will be cleared later
+ //after any pending IPCs from OCC have been processed and acked.
+ out32(OCB_OCCFLG_CLR, BIT32(PGPE_PROLONGED_DROOP_WORKAROUND_ACTIVE));
+
+ //5. Write PK Trace and Optrace record that the Prolonged Throttle workaround was removed,
+ //including the Total Retry Count and the most recent bit vector of Quads that provided the NACK(s) .
+ G_pgpe_optrace_data.word[0] = (G_pgpe_pstate_record.quadsNACKed << 24) |
+ (G_pgpe_pstate_record.activeCores);
+ G_pgpe_optrace_data.word[0] = G_pgpe_pstate_record.cntNACKs;
+ p9_pgpe_optrace(PROLONGED_DROOP_RESOLVED);
+
+ PK_TRACE_DBG("DTH: Droop Unthrottle Exit");
+}
diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_actuate_pstates.c b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_actuate_pstates.c
index 541ee0ba..4ae8e342 100644
--- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_actuate_pstates.c
+++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_actuate_pstates.c
@@ -105,6 +105,26 @@ void p9_pgpe_thread_actuate_pstates(void* arg)
//Loop while Pstate is ACTIVE
while(G_pgpe_pstate_record.pstatesStatus == PSTATE_ACTIVE)
{
+ //If a VDM prolonged droop happened, then we set OCB_OCCFLG[PGPE_PM_RESET_SUPPRESS]
+ //It should be cleared once VDM prolonged droop condition has subsided and all pending IPCs
+ //from OCC have been processed and acked. Note, that pending processing and pending ack are
+ //only set inside IPC handler, and it's possible that while PGPE is stuck in the VDM prolonged
+ //droop loop(the p9_pgpe_pstate_do_step function call) an IPC interrupt happened, so
+ //PGPE must be given a change to take IPC interrupt and see if any other IPC from OCC
+ //needs processing.
+ if ((in32(OCB_OCCFLG) & BIT32(PGPE_PM_RESET_SUPPRESS)))
+ {
+ if ((G_pgpe_pstate_record.ipcPendTbl[IPC_PEND_CLIP_UPDT].pending_ack == 0) &&
+ (G_pgpe_pstate_record.ipcPendTbl[IPC_PEND_WOF_VFRT].pending_ack == 0) &&
+ (G_pgpe_pstate_record.ipcPendTbl[IPC_PEND_WOF_CTRL].pending_ack == 0) &&
+ (G_pgpe_pstate_record.ipcPendTbl[IPC_PEND_CLIP_UPDT].pending_processing == 0) &&
+ (G_pgpe_pstate_record.ipcPendTbl[IPC_PEND_WOF_VFRT].pending_processing == 0) &&
+ (G_pgpe_pstate_record.ipcPendTbl[IPC_PEND_WOF_CTRL].pending_processing == 0))
+ {
+ out32(OCB_OCCFLG_CLR, BIT32(PGPE_PM_RESET_SUPPRESS));
+ }
+ }
+
//Actuate step(if needed)
if(p9_pgpe_pstate_at_target() == 0)
{
@@ -286,7 +306,7 @@ void p9_pgpe_thread_actuate_pstates(void* arg)
//This check must come after the possible p9_pgpe_pstate_safe_mode() call above
if (G_pgpe_pstate_record.pstatesStatus == PSTATE_PM_SUSPEND_PENDING)
{
- p9_pgpe_pstate_send_suspend_stop();
+ p9_pgpe_pstate_pm_complex_suspend();
}
if (G_pgpe_pstate_record.pstatesStatus == PSTATE_STOP_PENDING)
diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_process_requests.c b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_process_requests.c
index 33cd1b2f..48a44233 100644
--- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_process_requests.c
+++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_process_requests.c
@@ -53,6 +53,7 @@ void p9_pgpe_process_wof_vfrt();
void p9_pgpe_process_set_pmcr_req();
void p9_pgpe_process_registration();
void p9_pgpe_process_ack_sgpe_ctrl_stop_updt();
+void p9_pgpe_process_ack_sgpe_suspend_stop();
//
//Process Request Thread
@@ -167,11 +168,11 @@ void p9_pgpe_thread_process_requests(void* arg)
if (G_pgpe_pstate_record.ipcPendTbl[IPC_ACK_CTRL_STOP_UPDT].pending_processing)
{
p9_pgpe_process_ack_sgpe_ctrl_stop_updt();
+ }
- if(G_pgpe_pstate_record.ipcPendTbl[IPC_ACK_CTRL_STOP_UPDT].pending_ack == 1)
- {
- restore_irq = 0;
- }
+ if (G_pgpe_pstate_record.ipcPendTbl[IPC_ACK_SUSPEND_STOP].pending_processing)
+ {
+ p9_pgpe_process_ack_sgpe_suspend_stop();
}
if (G_pgpe_pstate_record.pendQuadsRegisterProcess != 0)
@@ -905,8 +906,7 @@ void p9_pgpe_process_registration()
ccsr.value = in32(OCB_CCSR);
ocb_qcsr_t qcsr;
qcsr.value = in32(OCB_QCSR);
- volatile uint32_t opit4pr;
- uint32_t opit4prQuad, q, c, oldActiveDB, oldActiveQuads, unicastCoresVector = 0, quadsRegisterProcess;
+ uint32_t q, c, oldActiveDB, oldActiveQuads, unicastCoresVector = 0, quadsRegisterProcess;
uint32_t quadAckExpect = 0;
uint64_t value;
pgpe_db0_start_ps_bcast_t db0_glb_bcast;
@@ -1077,35 +1077,16 @@ void p9_pgpe_process_registration()
db0_glb_bcast.fields.quad3_ps = G_pgpe_pstate_record.quadPSTarget[3];
db0_glb_bcast.fields.quad4_ps = G_pgpe_pstate_record.quadPSTarget[4];
db0_glb_bcast.fields.quad5_ps = G_pgpe_pstate_record.quadPSTarget[5];
- p9_pgpe_send_db0(db0_glb_bcast.value, unicastCoresVector, PGPE_DB0_UNICAST, PGPE_DB0_ACK_SKIP, 0);
+ p9_pgpe_send_db0(db0_glb_bcast.value, unicastCoresVector, PGPE_DB0_UNICAST, PGPE_DB0_ACK_WAIT_CME, quadAckExpect);
- //Now collect ACKS for Pstate Start DB0
- while(quadAckExpect != 0)
+ //Quads
+ for (q = 0; q < MAX_QUADS; q++)
{
- opit4pr = in32(OCB_OPIT4PRA);
-
- for (q = 0; q < MAX_QUADS; q++)
+ if (quadAckExpect & QUAD_MASK(q))
{
- opit4prQuad = (opit4pr >> ((MAX_QUADS - q + 1) << 2)) & 0xf;
-
- if (opit4prQuad)
- {
- //We expect type4 from this quad for the Pstate Start sent above
- if (quadAckExpect & QUAD_MASK(q))
- {
- quadAckExpect &= ~QUAD_MASK(q);
- out32(OCB_OPIT4PRA_CLR, opit4prQuad << ((MAX_QUADS - q + 1) << 2));
- PK_TRACE_DBG("PTH: Got DB0 Start ACK from %d", q);
- G_pgpe_pstate_record.quadPSCurr[q] = G_pgpe_pstate_record.quadPSTarget[q];
- G_pgpe_pstate_record.quadPSNext[q] = G_pgpe_pstate_record.quadPSTarget[q];
- p9_pgpe_pstate_updt_actual_quad(QUAD_MASK(q));
- }
- else if(!(G_pgpe_pstate_record.pendQuadsRegisterReceive & QUAD_MASK(q)))
- {
- PK_TRACE_ERR("PTH: Unexpected ACK q=0x%x,opit4prQuad=0x%x", q, opit4prQuad);
- PK_PANIC(PGPE_CME_UNEXPECTED_REGISTRATION);
- }
- }
+ G_pgpe_pstate_record.quadPSCurr[q] = G_pgpe_pstate_record.quadPSTarget[q];
+ G_pgpe_pstate_record.quadPSNext[q] = G_pgpe_pstate_record.quadPSTarget[q];
+ p9_pgpe_pstate_updt_actual_quad(QUAD_MASK(q));
}
}
}
@@ -1118,3 +1099,9 @@ void p9_pgpe_process_ack_sgpe_ctrl_stop_updt()
G_pgpe_pstate_record.ipcPendTbl[IPC_ACK_CTRL_STOP_UPDT].pending_processing = 0;
G_pgpe_pstate_record.ipcPendTbl[IPC_ACK_CTRL_STOP_UPDT].pending_ack = 0;
}
+
+void p9_pgpe_process_ack_sgpe_suspend_stop()
+{
+ G_pgpe_pstate_record.ipcPendTbl[IPC_ACK_SUSPEND_STOP].pending_processing = 0;
+ G_pgpe_pstate_record.ipcPendTbl[IPC_ACK_SUSPEND_STOP].pending_ack = 0;
+}
OpenPOWER on IntegriCloud