From e5e276106c9e8fbb648c8f9ff4d2c7f6b82dcb97 Mon Sep 17 00:00:00 2001 From: Rahul Batra Date: Wed, 5 Dec 2018 11:59:26 -0600 Subject: PGPE: WOV Hcode Updates (3/3) 3rd commit in the series of 3 commits for Workload Optimized Voltage(WOV) Commit 1. Adds WOV attributes Commit 2(Hostboot). WOV HW procedures changes and global parm updates Commit 3(Hcode). PGPE Hcode changes for WOV(undervolting only) feature Key_Cronus_Test=PM_REGRESS HW-Image-Prereq: I9833e8713d362684c1537b08478a9c9934e5012e CMVC-Prereq: 1074650 Change-Id: I9833e8713d362684c1537b08478a9c9934e5012e Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/69465 Tested-by: Jenkins Server Tested-by: Cronus HW CI Tested-by: FSP CI Jenkins Reviewed-by: RANGANATHPRASAD G. BRAHMASAMUDRA Reviewed-by: Gregory S. Still Reviewed-by: Jennifer A. Stofer --- .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_fit.c | 101 ++++-- .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_gppb.c | 8 +- .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_gppb.h | 5 +- .../pgpe/pstate_gpe/p9_pgpe_irq_handlers.c | 12 +- .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.c | 403 +++++++++++++++++---- .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.h | 52 ++- .../pstate_gpe/p9_pgpe_thread_actuate_pstates.c | 5 +- .../pstate_gpe/p9_pgpe_thread_process_requests.c | 26 +- .../ppe_closed/pgpe/pstate_gpe/pgpe_panic_codes.h | 8 +- .../ppe_closed/pgpe/pstate_gpe/pstate_common.mk | 4 +- .../ppe_closed/pgpe/pstate_gpe/pstate_gpe.mk | 4 +- 11 files changed, 487 insertions(+), 141 deletions(-) diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_fit.c b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_fit.c index 708b1c4a..ccb76618 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_fit.c +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_fit.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HCODE Project */ /* */ -/* COPYRIGHT 2016,2018 */ +/* COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -50,6 +50,8 @@ uint32_t G_tb_sync_count; uint32_t G_quad_hb_value; +uint32_t G_wov_count; + extern GlobalPstateParmBlock* G_gppb; extern PgpeHeader_t* G_pgpe_header_data; extern PgpePstateRecord G_pgpe_pstate_record; @@ -129,7 +131,7 @@ void p9_pgpe_fit_init() G_throttleCount = 0; G_beacon_count = 0; G_tb_sync_count = 0; - + G_wov_count = 0; //Set FIT handler which is called on every FIT interrupt tick ppe42_fit_setup(p9_pgpe_fit_handler, NULL); } @@ -146,52 +148,55 @@ __attribute__((always_inline)) inline void handle_core_throttle() uint32_t config = in32(G_OCB_OCCS2); //bits 16-18 in OCC Scratch Register 2 uint32_t run = (config >> 14) & 0x3; //this looks at the inject and enable bits, if either are high we run - if(run) //Currently running + if (!(in32(G_OCB_OCCFLG) & BIT32(PGPE_PROLONGED_DROOP_WORKAROUND_ACTIVE))) { - uint32_t throttleData = G_orig_throttle; - uint32_t inject = run & 0x1; //Inject is bit 17, if this is high we run one throttle burst then turn off - uint32_t type = (config >> 13) & 0x1; //type is bit 18, this determines which kind of throttling we do - uint32_t mask = type ? CORE_SLOWDOWN : CORE_IFU_THROTTLE; - uint32_t pgpe_throttle_assert = G_pgpe_header_data->g_pgpe_core_throttle_assert_cnt; - uint32_t pgpe_throttle_deassert = G_pgpe_header_data->g_pgpe_core_throttle_deassert_cnt; - - //if currently off, we don't desire always off, this is the first evaluation since become enabled, we are in always on, - //or we (re enabled and have reached the count, then we turn throttling on (if both assert and deassert are 0 this statement fails) - if(!G_throttleOn && pgpe_throttle_assert != 0 && - (G_throttleCount == 0 || pgpe_throttle_deassert == 0 || pgpe_throttle_deassert == G_throttleCount)) + if(run) //Currently running { - G_throttleOn = 1; - G_throttleCount = 0; - throttleData |= mask; //data for start throttle + uint32_t throttleData = G_orig_throttle; + uint32_t inject = run & 0x1; //Inject is bit 17, if this is high we run one throttle burst then turn off + uint32_t type = (config >> 13) & 0x1; //type is bit 18, this determines which kind of throttling we do + uint32_t mask = type ? CORE_SLOWDOWN : CORE_IFU_THROTTLE; + uint32_t pgpe_throttle_assert = G_pgpe_header_data->g_pgpe_core_throttle_assert_cnt; + uint32_t pgpe_throttle_deassert = G_pgpe_header_data->g_pgpe_core_throttle_deassert_cnt; + + //if currently off, we don't desire always off, this is the first evaluation since become enabled, we are in always on, + //or we (re enabled and have reached the count, then we turn throttling on (if both assert and deassert are 0 this statement fails) + if(!G_throttleOn && pgpe_throttle_assert != 0 && + (G_throttleCount == 0 || pgpe_throttle_deassert == 0 || pgpe_throttle_deassert == G_throttleCount)) + { + G_throttleOn = 1; + G_throttleCount = 0; + throttleData |= mask; //data for start throttle - } - //if currently on and we desire always off or we don't desire always on and have reached the count, - //then we turn it off (if both assert and deassert are 0 this statement true) - else if(G_throttleOn && - (pgpe_throttle_assert == 0 || ( pgpe_throttle_deassert != 0 && pgpe_throttle_assert == G_throttleCount))) - { - G_throttleOn = 0; - G_throttleCount = 0; - throttleData &= ~mask; //data for stop throttle + } + //if currently on and we desire always off or we don't desire always on and have reached the count, + //then we turn it off (if both assert and deassert are 0 this statement true) + else if(G_throttleOn && + (pgpe_throttle_assert == 0 || ( pgpe_throttle_deassert != 0 && pgpe_throttle_assert == G_throttleCount))) + { + G_throttleOn = 0; + G_throttleCount = 0; + throttleData &= ~mask; //data for stop throttle + + if(inject == 1) + { + out32(G_OCB_OCCS2, (config & 0xFFFFBFFF)); //write out to indicate inject has finished + } + } - if(inject == 1) + if(G_throttleCount == 0) { - out32(G_OCB_OCCS2, (config & 0xFFFFBFFF)); //write out to indicate inject has finished + p9_pgpe_pstate_write_core_throttle(throttleData, NO_RETRY); } - } - if(G_throttleCount == 0) + G_throttleCount++; //count always incremented, it is impossible to reach a count of 0 while enabled + } + else if(G_throttleCount != 0) { - p9_pgpe_pstate_write_core_throttle(throttleData, NO_RETRY); + G_throttleCount = 0; + G_throttleOn = 0; + p9_pgpe_pstate_write_core_throttle(G_orig_throttle, NO_RETRY); } - - G_throttleCount++; //count always incremented, it is impossible to reach a count of 0 while enabled - } - else if(G_throttleCount != 0) - { - G_throttleCount = 0; - G_throttleOn = 0; - p9_pgpe_pstate_write_core_throttle(G_orig_throttle, NO_RETRY); } } //Quads must get HB value @@ -378,6 +383,23 @@ __attribute__((always_inline)) inline void handle_fit_timebase_sync() } } +// +// handle_undervolt +// +__attribute__((always_inline)) inline void handle_wov() +{ + if (G_pgpe_pstate_record.wov.status & WOV_UNDERVOLT_ENABLED) + { + G_wov_count++; + + if (G_gppb->wov_sample_125us == G_wov_count) + { + p9_pgpe_pstate_adjust_wov(); + G_wov_count = 0; + } + } +} + // p9_pgpe_fit_handler // // This is a periodic FIT Handler which is called up at fixed period @@ -392,4 +414,5 @@ void p9_pgpe_fit_handler(void* arg, PkIrqId irq) handle_occflg_requests(); handle_aux_task(); handle_fit_timebase_sync(); + handle_wov(); } diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_gppb.c b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_gppb.c index 0864fae8..ee54b194 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_gppb.c +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_gppb.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HCODE Project */ /* */ -/* COPYRIGHT 2016,2018 */ +/* COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -26,6 +26,7 @@ #include "p9_pgpe_gppb.h" #include "p9_pgpe_header.h" #include "p9_hcode_image_defines.H" +#include "ppehw_common.h" typedef enum { @@ -301,3 +302,8 @@ uint16_t p9_pgpe_gppb_vdm_threshold_from_ps(uint32_t pstate) return ret; } + +uint32_t p9_pgpe_gppb_freq_from_ps(Pstate ps) +{ + return (G_gppb->reference_frequency_khz - ((ps) * G_gppb->frequency_step_khz)) / 1000; +} diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_gppb.h b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_gppb.h index bbcc2d74..685654aa 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_gppb.h +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_gppb.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HCODE Project */ /* */ -/* COPYRIGHT 2016,2018 */ +/* COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -72,4 +72,7 @@ uint32_t p9_pgpe_gppb_vdm_vid_cmp_from_ps(Pstate ps); // retval - VDM Threshold(VDM_OVERVOLT:VDM_DROOP_SMALL:VDM_DROOP_LARGE:VDM_DROOP_XTREME] uint16_t p9_pgpe_gppb_vdm_threshold_from_ps(uint32_t pstate); +//Get Frequency for a Pstate +uint32_t p9_pgpe_gppb_freq_from_ps(Pstate ps); + #endif //_P9_PGPE_GPPB_H_ diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq_handlers.c b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq_handlers.c index d5590ac2..d1cc75e7 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq_handlers.c +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq_handlers.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HCODE Project */ /* */ -/* COPYRIGHT 2016,2018 */ +/* COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -162,7 +162,7 @@ void p9_pgpe_irq_handler_ocb_err() G_pgpe_optrace_data.word[0] = (G_pgpe_pstate_record.activeQuads << 24) | (G_pgpe_pstate_record.activeCores << 8); G_pgpe_optrace_data.word[1] = (G_pgpe_pstate_record.psCurr.fields.glb << 24) | - (G_pgpe_pstate_record.eVidCurr << 8) | + (G_pgpe_pstate_record.extVrmCurr << 8) | PGPE_OP_TRACE_OCC_HB_FAULT; p9_pgpe_optrace(SEVERE_FAULT_DETECTED); @@ -203,7 +203,7 @@ void p9_pgpe_irq_handler_sgpe_err() G_pgpe_optrace_data.word[0] = (G_pgpe_pstate_record.activeQuads << 24) | (G_pgpe_pstate_record.activeCores << 8); G_pgpe_optrace_data.word[1] = (G_pgpe_pstate_record.psCurr.fields.glb << 24) | - (G_pgpe_pstate_record.eVidCurr << 8) | + (G_pgpe_pstate_record.extVrmCurr << 8) | PGPE_OP_TRACE_SGPE_FAULT; p9_pgpe_optrace(SEVERE_FAULT_DETECTED); @@ -243,7 +243,7 @@ void p9_pgpe_irq_handler_pvref_err() G_pgpe_optrace_data.word[0] = (G_pgpe_pstate_record.activeQuads << 24) | (G_pgpe_pstate_record.activeCores << 8); G_pgpe_optrace_data.word[1] = (G_pgpe_pstate_record.psCurr.fields.glb << 24) | - (G_pgpe_pstate_record.eVidCurr << 8) | + (G_pgpe_pstate_record.extVrmCurr << 8) | PGPE_OP_TRACE_PVREF_FAULT; p9_pgpe_optrace(SEVERE_FAULT_DETECTED); @@ -288,7 +288,7 @@ void p9_pgpe_irq_handler_system_xstop(void* arg, PkIrqId irq) G_pgpe_optrace_data.word[0] = (G_pgpe_pstate_record.activeQuads << 24) | (G_pgpe_pstate_record.activeCores << 8); G_pgpe_optrace_data.word[1] = (G_pgpe_pstate_record.psCurr.fields.glb << 24) | - (G_pgpe_pstate_record.eVidCurr << 8) | + (G_pgpe_pstate_record.extVrmCurr << 8) | PGPE_OP_TRACE_SYS_XSTOP; p9_pgpe_optrace(SEVERE_FAULT_DETECTED); @@ -454,7 +454,7 @@ void p9_pgpe_irq_handler_cme_err() G_pgpe_optrace_data.word[0] = (G_pgpe_pstate_record.activeQuads << 24) | (G_pgpe_pstate_record.activeCores << 8); G_pgpe_optrace_data.word[1] = (G_pgpe_pstate_record.psCurr.fields.glb << 24) | - (G_pgpe_pstate_record.eVidCurr << 8) | + (G_pgpe_pstate_record.extVrmCurr << 8) | PGPE_OP_TRACE_CME_FAULT; p9_pgpe_optrace(SEVERE_FAULT_DETECTED); 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 09d59832..f268a0d4 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 @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HCODE Project */ /* */ -/* COPYRIGHT 2016,2018 */ +/* COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -65,6 +65,7 @@ GPE_BUFFER(ipcmsg_p2s_suspend_stop_t G_sgpe_suspend_stop); //Local Functions void p9_pgpe_handle_nacks(uint32_t origCoreVector, uint32_t origAckVector, uint32_t expectedAcks); void p9_pgpe_pstate_freq_updt(); +void p9_pgpe_pstate_wov_init(); inline void p9_pgpe_droop_throttle() __attribute__((always_inline)); inline void p9_pgpe_droop_unthrottle() __attribute__((always_inline)); @@ -138,6 +139,9 @@ void p9_pgpe_pstate_init() pk_semaphore_create(&(G_pgpe_pstate_record.sem_actuate), 0, 1); pk_semaphore_create(&(G_pgpe_pstate_record.sem_sgpe_wait), 0, 1); pk_semaphore_create(&(G_pgpe_pstate_record.sem_process_req), 0, 1); + + //WOV init + p9_pgpe_pstate_wov_init(); } // @@ -367,7 +371,6 @@ void p9_pgpe_pstate_calc_wof() { G_pgpe_pstate_record.vratio = (G_pgpe_pstate_record.numActiveCores * MAX_VRATIO) / (G_pgpe_pstate_record.numSortCores); - // Note we separate out numActiveCores = 0 case. Otherwise, subtracting 1 will // result in invalid vindex if (G_pgpe_pstate_record.numActiveCores != 0) @@ -411,7 +414,7 @@ void p9_pgpe_pstate_update_wof_state() PK_TRACE_DBG("WFU: Updt WOF Shr Sram"); pgpe_wof_state_t* wof_state = (pgpe_wof_state_t*)G_pgpe_header_data->g_pgpe_wof_state_address; wof_state->fields.fclip_ps = G_pgpe_pstate_record.wofClip; - wof_state->fields.vclip_mv = G_pgpe_pstate_record.eVidCurr; + wof_state->fields.vclip_mv = G_pgpe_pstate_record.extVrmCurr; wof_state->fields.fratio = G_pgpe_pstate_record.fratio; wof_state->fields.vratio = G_pgpe_pstate_record.vratio; PK_TRACE_INF("WFU: FClip_PS=0x%x, vindex=0x%x, vratio=0x%x", G_pgpe_pstate_record.wofClip, G_pgpe_pstate_record.vindex, @@ -674,20 +677,8 @@ void p9_pgpe_handle_nacks(uint32_t origTargetCores, uint32_t origExpectedAckFrom p.waitForAcks = PGPE_DB_ACK_WAIT_CME; p.checkNACKs = PGPE_DB3_SKIP_CHECK_NACKS; - //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(G_OCB_OCCS2) & BIT32(CORE_THROTTLE_CONTINUOUS_CHANGE_ENABLE)) - { - PGPE_TRACE_AND_PANIC(PGPE_DROOP_AND_CORE_THROTTLE_ENABLED); - } - - //b) If OCC flag PGPE Prolonged Droop Workaround Active bit is not set, - // call droop_throttle() - - if (!(in32(G_OCB_OCCFLG) & BIT32(PGPE_PROLONGED_DROOP_WORKAROUND_ACTIVE))) - { - p9_pgpe_droop_throttle(); - } + G_pgpe_pstate_record.wov.target_pct = 0; + p9_pgpe_pstate_updt_ext_volt(); //c) Send DB3 (Replay Previous DB0 Operation) to only the CME Quad Managers, and //their Sibling CME (if present), that responded with a NACK. @@ -713,6 +704,14 @@ void p9_pgpe_handle_nacks(uint32_t origTargetCores, uint32_t origExpectedAckFrom //If a NACK received was in response to the first retry (i.e. second failed attempt): if (G_pgpe_pstate_record.cntNACKs == 2) { + + //b) If OCC flag PGPE Prolonged Droop Workaround Active bit is not set, + // call droop_throttle() + if (!(in32(G_OCB_OCCFLG) & BIT32(PGPE_PROLONGED_DROOP_WORKAROUND_ACTIVE))) + { + p9_pgpe_droop_throttle(); + } + // 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)); @@ -811,21 +810,26 @@ void p9_pgpe_pstate_start(uint32_t pstate_start_origin) } //3. Move system to SyncPState - external_voltage_control_init(&G_pgpe_pstate_record.eVidCurr); - G_pgpe_pstate_record.eVidNext = p9_pgpe_gppb_intp_vdd_from_ps(syncPstate, VPD_PT_SET_BIASED_SYSP); - PK_TRACE_INF("PST: SyncPstate=0x%x eVid(Boot)=%umV,eVid(SyncPstate)=%umV", syncPstate, G_pgpe_pstate_record.eVidCurr, - G_pgpe_pstate_record.eVidNext); + external_voltage_control_init(&G_pgpe_pstate_record.extVrmCurr); + G_pgpe_pstate_record.biasSyspExtVrmCurr = G_pgpe_pstate_record.extVrmCurr; + G_pgpe_pstate_record.biasSyspExtVrmNext = p9_pgpe_gppb_intp_vdd_from_ps(syncPstate, VPD_PT_SET_BIASED_SYSP); + PK_TRACE_INF("PST: SyncPstate=0x%x eVid(Boot)=%umV,eVid(SyncPstate)=%umV", syncPstate, + G_pgpe_pstate_record.biasSyspExtVrmCurr, + G_pgpe_pstate_record.biasSyspExtVrmNext); dpllFreq.value = 0; dpllFreq.fields.fmax = G_gppb->dpll_pstate0_value - syncPstate; dpllFreq.fields.fmult = dpllFreq.fields.fmax; dpllFreq.fields.fmin = dpllFreq.fields.fmax; + G_pgpe_pstate_record.psNext.fields.glb = syncPstate; + p9_pgpe_pstate_reset_wov(); + //Move voltage only if raising it. Otherwise, we lower it later after //sending Pstate Start DB0. This is to make sure VDMs are not affected in //this window - if(G_pgpe_pstate_record.eVidCurr < G_pgpe_pstate_record.eVidNext) + if(G_pgpe_pstate_record.biasSyspExtVrmCurr < G_pgpe_pstate_record.biasSyspExtVrmNext) { - p9_pgpe_pstate_updt_ext_volt(G_pgpe_pstate_record.eVidNext); //update voltage + p9_pgpe_pstate_updt_ext_volt(); //update voltage } for (q = 0; q < MAX_QUADS; q++) @@ -857,6 +861,7 @@ void p9_pgpe_pstate_start(uint32_t pstate_start_origin) p9_pgpe_pstate_do_auction(); p9_pgpe_pstate_apply_clips(); + G_pgpe_pstate_record.psNext.value = G_pgpe_pstate_record.psTarget.value; //5. Set up CME_SCRATCH0[Local_Pstate_Index] for (q = 0; q < MAX_QUADS; q++) @@ -949,9 +954,9 @@ void p9_pgpe_pstate_start(uint32_t pstate_start_origin) out32(G_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) + if (G_pgpe_pstate_record.biasSyspExtVrmCurr > G_pgpe_pstate_record.biasSyspExtVrmNext) { - p9_pgpe_pstate_updt_ext_volt(G_pgpe_pstate_record.eVidNext); //update voltage + p9_pgpe_pstate_updt_ext_volt(); //update voltage } G_pgpe_pstate_record.psCurr.value = G_pgpe_pstate_record.psTarget.value; @@ -966,6 +971,13 @@ void p9_pgpe_pstate_start(uint32_t pstate_start_origin) PK_TRACE_DBG("PST: PGPE_PSTATE_PROTOCOL_ACTIVE set"); out32(G_OCB_OCCS2, occScr2); + //7. Enable Undervolt if needed + if (G_pgpe_header_data->g_pgpe_flags & PGPE_FLAG_WOV_UNDERVOLT_ENABLE) + { + G_pgpe_pstate_record.wov.status = WOV_UNDERVOLT_ENABLED; + PK_TRACE_INF("PST: Undervolting Enabled"); + } + PK_TRACE_DBG("PST: Start Done"); } @@ -1400,7 +1412,7 @@ void p9_pgpe_pstate_process_quad_exit_notify(uint32_t quadsRequested) GPE_GETSCOM(GPE_SCOM_ADDR_QUAD(QPPM_VDMCFGR, q), vdmcfg.value); } - vdmcfg.fields.vdm_vid_compare = (G_pgpe_pstate_record.eVidCurr - 512) >> 2; + vdmcfg.fields.vdm_vid_compare = (G_pgpe_pstate_record.biasSyspExtVrmCurr - 512) >> 2; GPE_PUTSCOM(GPE_SCOM_ADDR_QUAD(QPPM_VDMCFGR, q), vdmcfg.value); } } @@ -1825,6 +1837,18 @@ int32_t p9_pgpe_pstate_at_target() } } +int32_t p9_pgpe_pstate_at_wov_target() +{ + if (G_pgpe_pstate_record.wov.curr_pct ^ G_pgpe_pstate_record.wov.target_pct) + { + return 0; + } + else + { + return 1; + } +} + // // p9_pgpe_pstate_do_step // @@ -1836,34 +1860,35 @@ void p9_pgpe_pstate_do_step() //Do one actuate step PK_TRACE_DBG("STEP: Entry"); - PK_TRACE_DBG("STEP: GTgt,GCurr 0x%x, 0x%x", G_pgpe_pstate_record.psTarget.fields.glb, + PK_TRACE_INF("STEP: GTgt,GCurr 0x%x, 0x%x", G_pgpe_pstate_record.psTarget.fields.glb, G_pgpe_pstate_record.psCurr.fields.glb); - PK_TRACE_DBG("STEP: QTgt,QCurr 0x%x,0x%x 0x%x,0x%x", G_pgpe_pstate_record.psTarget.fields.quads[0], + PK_TRACE_INF("STEP: QTgt,QCurr 0x%x,0x%x 0x%x,0x%x", G_pgpe_pstate_record.psTarget.fields.quads[0], G_pgpe_pstate_record.psCurr.fields.quads[0], G_pgpe_pstate_record.psTarget.fields.quads[1], G_pgpe_pstate_record.psCurr.fields.quads[1]); - PK_TRACE_DBG("STEP:QTgt,QCurr 0x%x,0x%x 0x%x,0x%x", G_pgpe_pstate_record.psTarget.fields.quads[2], + PK_TRACE_INF("STEP:QTgt,QCurr 0x%x,0x%x 0x%x,0x%x", G_pgpe_pstate_record.psTarget.fields.quads[2], G_pgpe_pstate_record.psCurr.fields.quads[2], G_pgpe_pstate_record.psTarget.fields.quads[3], G_pgpe_pstate_record.psCurr.fields.quads[3]); - PK_TRACE_DBG("STEP:QTgt,QCurr 0x%x,0x%x 0x%x,0x%x", G_pgpe_pstate_record.psTarget.fields.quads[4], + PK_TRACE_INF("STEP:QTgt,QCurr 0x%x,0x%x 0x%x,0x%x", G_pgpe_pstate_record.psTarget.fields.quads[4], G_pgpe_pstate_record.psCurr.fields.quads[4], G_pgpe_pstate_record.psTarget.fields.quads[5], G_pgpe_pstate_record.psCurr.fields.quads[5]); uint32_t q; uint32_t targetEVid = p9_pgpe_gppb_intp_vdd_from_ps(G_pgpe_pstate_record.psTarget.fields.glb, VPD_PT_SET_BIASED_SYSP); - PK_TRACE_DBG("STEP: eVidCurr=0x%x, eVidNext=0x%x, targetEVid=0x%x", G_pgpe_pstate_record.eVidCurr, - G_pgpe_pstate_record.eVidNext, targetEVid); + PK_TRACE_INF("STEP: biasSyspExtVrmCurr=0x%x, biasSyspExtVrmNext=0x%x, targetEVid=0x%x", + G_pgpe_pstate_record.biasSyspExtVrmCurr, + G_pgpe_pstate_record.biasSyspExtVrmNext, targetEVid); //Higher number PState if (((int16_t)(G_pgpe_pstate_record.psTarget.fields.glb) - (int16_t)(G_pgpe_pstate_record.psCurr.fields.glb)) > 0) { - if ((G_pgpe_pstate_record.eVidCurr - targetEVid ) <= G_gppb->ext_vrm_step_size_mv) + if ((G_pgpe_pstate_record.biasSyspExtVrmCurr - targetEVid ) <= G_gppb->ext_vrm_step_size_mv) { - G_pgpe_pstate_record.eVidNext = targetEVid; + G_pgpe_pstate_record.biasSyspExtVrmNext = targetEVid; G_pgpe_pstate_record.psNext.fields.glb = G_pgpe_pstate_record.psTarget.fields.glb; - PK_TRACE_DBG("STEP: <= step_size"); + PK_TRACE_INF("STEP: <= step_size"); for (q = 0; q < MAX_QUADS; q++) { @@ -1875,8 +1900,8 @@ void p9_pgpe_pstate_do_step() } else { - G_pgpe_pstate_record.eVidNext = G_pgpe_pstate_record.eVidCurr - G_gppb->ext_vrm_step_size_mv; - G_pgpe_pstate_record.psNext.fields.glb = p9_pgpe_gppb_intp_ps_from_ext_vdd(G_pgpe_pstate_record.eVidNext); + G_pgpe_pstate_record.biasSyspExtVrmNext = G_pgpe_pstate_record.biasSyspExtVrmCurr - G_gppb->ext_vrm_step_size_mv; + G_pgpe_pstate_record.psNext.fields.glb = p9_pgpe_gppb_intp_ps_from_ext_vdd(G_pgpe_pstate_record.biasSyspExtVrmNext); //It's possible that the interpolation function returns Pstate higher than //target due to rounding errors, so we adjust back. @@ -1886,8 +1911,8 @@ void p9_pgpe_pstate_do_step() } //Make sure voltage written corresponds exactly to a pstate - G_pgpe_pstate_record.eVidNext = p9_pgpe_gppb_intp_vdd_from_ps(G_pgpe_pstate_record.psNext.fields.glb, - VPD_PT_SET_BIASED_SYSP); + G_pgpe_pstate_record.biasSyspExtVrmNext = p9_pgpe_gppb_intp_vdd_from_ps(G_pgpe_pstate_record.psNext.fields.glb, + VPD_PT_SET_BIASED_SYSP); for (q = 0; q < MAX_QUADS; q++) { @@ -1899,19 +1924,19 @@ void p9_pgpe_pstate_do_step() } - PK_TRACE_DBG("STEP: eVidNext=0x%x, glbPSNext=0x%x", G_pgpe_pstate_record.eVidCurr, + PK_TRACE_INF("STEP: biasSyspExtVrmNext=0x%x, glbPSNext=0x%x", G_pgpe_pstate_record.biasSyspExtVrmCurr, G_pgpe_pstate_record.psNext.fields.glb); - p9_pgpe_pstate_freq_updt(); - p9_pgpe_pstate_updt_ext_volt(targetEVid); + p9_pgpe_pstate_freq_updt(PGPE_FREQ_DIRECTION_DOWN); + p9_pgpe_pstate_updt_ext_volt(); } //Lower number PState else if (((int16_t)(G_pgpe_pstate_record.psTarget.fields.glb) - (int16_t)(G_pgpe_pstate_record.psCurr.fields.glb)) < 0) { - if ((targetEVid - G_pgpe_pstate_record.eVidCurr) <= G_gppb->ext_vrm_step_size_mv) + if ((targetEVid - G_pgpe_pstate_record.biasSyspExtVrmCurr) <= G_gppb->ext_vrm_step_size_mv) { - PK_TRACE_DBG("STEP: <= step_size"); - G_pgpe_pstate_record.eVidNext = targetEVid; + PK_TRACE_INF("STEP: <= step_size"); + G_pgpe_pstate_record.biasSyspExtVrmNext = targetEVid; G_pgpe_pstate_record.psNext.fields.glb = G_pgpe_pstate_record.psTarget.fields.glb; for (q = 0; q < MAX_QUADS; q++) @@ -1924,9 +1949,9 @@ void p9_pgpe_pstate_do_step() } else { - PK_TRACE_DBG("STEP: > step_size"); - G_pgpe_pstate_record.eVidNext = G_pgpe_pstate_record.eVidCurr + G_gppb->ext_vrm_step_size_mv; - G_pgpe_pstate_record.psNext.fields.glb = p9_pgpe_gppb_intp_ps_from_ext_vdd(G_pgpe_pstate_record.eVidNext); + PK_TRACE_INF("STEP: > step_size"); + G_pgpe_pstate_record.biasSyspExtVrmNext = G_pgpe_pstate_record.biasSyspExtVrmCurr + G_gppb->ext_vrm_step_size_mv; + G_pgpe_pstate_record.psNext.fields.glb = p9_pgpe_gppb_intp_ps_from_ext_vdd(G_pgpe_pstate_record.biasSyspExtVrmNext); //It's possible that the interpolation function returns Pstate lower than //target due to rounding errors, so we adjust back. @@ -1936,8 +1961,8 @@ void p9_pgpe_pstate_do_step() } //Make sure voltage written corresponds exactly to a pstate - G_pgpe_pstate_record.eVidNext = p9_pgpe_gppb_intp_vdd_from_ps(G_pgpe_pstate_record.psNext.fields.glb, - VPD_PT_SET_BIASED_SYSP); + G_pgpe_pstate_record.biasSyspExtVrmNext = p9_pgpe_gppb_intp_vdd_from_ps(G_pgpe_pstate_record.psNext.fields.glb, + VPD_PT_SET_BIASED_SYSP); for (q = 0; q < MAX_QUADS; q++) { @@ -1956,22 +1981,33 @@ void p9_pgpe_pstate_do_step() } } - PK_TRACE_DBG("STEP: eVidNext=0x%x, glbPSNext=0x%x", G_pgpe_pstate_record.eVidCurr, + PK_TRACE_INF("STEP: biasSyspExtVrmNext=0x%x, glbPSNext=0x%x", G_pgpe_pstate_record.biasSyspExtVrmCurr, G_pgpe_pstate_record.psNext.fields.glb); - p9_pgpe_pstate_updt_ext_volt(targetEVid); - p9_pgpe_pstate_freq_updt(); + p9_pgpe_pstate_updt_ext_volt(); + p9_pgpe_pstate_freq_updt(PGPE_FREQ_DIRECTION_UP); } else { - for (q = 0; q < MAX_QUADS; q++) + //Local Pstate change + if (p9_pgpe_pstate_at_target() == 0) { - if(G_pgpe_pstate_record.activeQuads & QUAD_MASK(q)) + for (q = 0; q < MAX_QUADS; q++) { - G_pgpe_pstate_record.psNext.fields.quads[q] = G_pgpe_pstate_record.psTarget.fields.quads[q]; + if(G_pgpe_pstate_record.activeQuads & QUAD_MASK(q)) + { + G_pgpe_pstate_record.psNext.fields.quads[q] = G_pgpe_pstate_record.psTarget.fields.quads[q]; + } } + + //Only local pstate change + p9_pgpe_pstate_freq_updt(PGPE_FREQ_DIRECTION_NO_CHANGE); } - p9_pgpe_pstate_freq_updt(); + if (p9_pgpe_pstate_at_wov_target() == 0) + { + PK_TRACE_INF("WOV updt ext_volt"); + p9_pgpe_pstate_updt_ext_volt(); + } } //Update current @@ -1987,7 +2023,7 @@ void p9_pgpe_pstate_do_step() (G_pgpe_pstate_record.psCurr.fields.quads[5] << 16) | G_pgpe_pstate_record.psCurr.fields.glb << 8 | G_pgpe_pstate_record.psTarget.fields.glb; - G_pgpe_optrace_data.word[2] = (G_pgpe_pstate_record.eVidCurr << 16) | G_pgpe_pstate_record.eVidCurr; + G_pgpe_optrace_data.word[2] = (G_pgpe_pstate_record.biasSyspExtVrmCurr << 16) | G_pgpe_pstate_record.biasSyspExtVrmCurr; p9_pgpe_optrace(ACTUATE_STEP_DONE); PK_TRACE_DBG("STEP: Exit"); } @@ -1997,32 +2033,41 @@ void p9_pgpe_pstate_do_step() // // Update External VRM to G_eVidNext // -void p9_pgpe_pstate_updt_ext_volt(uint32_t tgtEVid) +void p9_pgpe_pstate_updt_ext_volt() { qppm_vdmcfgr_t vdmcfg; uint32_t cmeInterppmVdataEnableSet, q; qppm_qpmmr_t qpmmr; + G_pgpe_pstate_record.wov.target_mv = + (G_pgpe_pstate_record.biasSyspExtVrmNext * G_pgpe_pstate_record.wov.target_pct) / 1000; + G_pgpe_pstate_record.extVrmNext = G_pgpe_pstate_record.biasSyspExtVrmNext - G_pgpe_pstate_record.wov.target_mv; + + if (G_gppb->wov_underv_vmin_mv > G_pgpe_pstate_record.extVrmNext) + { + G_pgpe_pstate_record.extVrmNext = G_gppb->wov_underv_vmin_mv; + } + #if !EPM_P9_TUNING uint32_t delay_us = 0; //Decreasing - if (G_pgpe_pstate_record.eVidNext < G_pgpe_pstate_record.eVidCurr) + if (G_pgpe_pstate_record.extVrmNext < G_pgpe_pstate_record.extVrmCurr) { - delay_us = (G_pgpe_pstate_record.eVidCurr - G_pgpe_pstate_record.eVidNext) * + delay_us = (G_pgpe_pstate_record.extVrmCurr - G_pgpe_pstate_record.extVrmNext) * G_ext_vrm_dec_rate_mult_usperus; } //Increasing - else if(G_pgpe_pstate_record.eVidNext > G_pgpe_pstate_record.eVidCurr) + else if (G_pgpe_pstate_record.extVrmNext > G_pgpe_pstate_record.extVrmCurr) { - delay_us = (G_pgpe_pstate_record.eVidNext - G_pgpe_pstate_record.eVidCurr) * + delay_us = (G_pgpe_pstate_record.extVrmNext - G_pgpe_pstate_record.extVrmCurr) * G_ext_vrm_inc_rate_mult_usperus; } #endif //Update external voltage - external_voltage_control_write(G_pgpe_pstate_record.eVidNext); + external_voltage_control_write(G_pgpe_pstate_record.extVrmNext); #if !EPM_P9_TUNING @@ -2032,20 +2077,34 @@ void p9_pgpe_pstate_updt_ext_volt(uint32_t tgtEVid) pk_sleep(PK_MICROSECONDS((delay_us))); } - if(G_pgpe_pstate_record.eVidNext == tgtEVid) + if(G_pgpe_pstate_record.biasSyspExtVrmNext == p9_pgpe_gppb_intp_vdd_from_ps(G_pgpe_pstate_record.psNext.fields.glb, + VPD_PT_SET_BIASED_SYSP)) { pk_sleep(PK_MICROSECONDS((G_gppb->ext_vrm_stabilization_time_us))); } #endif - G_pgpe_pstate_record.eVidCurr = G_pgpe_pstate_record.eVidNext; + G_pgpe_pstate_record.biasSyspExtVrmCurr = G_pgpe_pstate_record.biasSyspExtVrmNext; + G_pgpe_pstate_record.extVrmCurr = G_pgpe_pstate_record.extVrmNext; + G_pgpe_pstate_record.wov.curr_mv = G_pgpe_pstate_record.wov.target_mv; + G_pgpe_pstate_record.wov.curr_pct = G_pgpe_pstate_record.wov.target_pct; + + if (G_pgpe_pstate_record.wov.min_volt > G_pgpe_pstate_record.wov.curr_mv) + { + G_pgpe_pstate_record.wov.min_volt = G_pgpe_pstate_record.wov.curr_mv; + } + + if (G_pgpe_pstate_record.wov.max_volt < G_pgpe_pstate_record.wov.curr_mv) + { + G_pgpe_pstate_record.wov.max_volt = G_pgpe_pstate_record.wov.curr_mv; + } //If VDM is disabled, update VDMCFG register for every quad if (!(G_pgpe_header_data->g_pgpe_flags & PGPE_FLAG_VDM_ENABLE)) { vdmcfg.value = 0; - vdmcfg.fields.vdm_vid_compare = (G_pgpe_pstate_record.eVidCurr - 512) >> 2; + vdmcfg.fields.vdm_vid_compare = (G_pgpe_pstate_record.biasSyspExtVrmCurr - 512) >> 2; for (q = 0; q < MAX_QUADS; q++) { @@ -2074,11 +2133,13 @@ void p9_pgpe_pstate_updt_ext_volt(uint32_t tgtEVid) // // Frequency Update // -// Sends a DB0 to all active CMEs, so that Quad Managers(CMEs) update DPLL -void p9_pgpe_pstate_freq_updt() +//Sends a DB0 to all active CMEs, so that Quad Managers(CMEs) update DPLL +void p9_pgpe_pstate_freq_updt(uint32_t freq_change_dir) { PK_TRACE_DBG("FREQ: Enter"); + G_pgpe_pstate_record.wov.frequency_change_direction = freq_change_dir; + p9_pgpe_pstate_adjust_wov(); pgpe_db0_glb_bcast_t db0; db0.value = G_pgpe_pstate_record.psNext.value; @@ -2134,6 +2195,8 @@ void p9_pgpe_pstate_freq_updt() p9_pgpe_optrace(ACK_ACTL_DONE); + G_pgpe_pstate_record.wov.frequency_change_direction = PGPE_FREQ_DIRECTION_NO_CHANGE; + PK_TRACE_DBG("FREQ: Exit"); } @@ -2149,6 +2212,7 @@ void p9_pgpe_pstate_write_core_throttle(uint32_t throttleData, uint32_t enable_r 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 @@ -2175,7 +2239,7 @@ void p9_pgpe_pstate_write_core_throttle(uint32_t throttleData, uint32_t enable_r // inline void p9_pgpe_droop_throttle() { - + PkMachineContext ctx __attribute__((unused)); uint32_t q; ocb_qcsr_t qcsr; qcsr.value = in32(G_OCB_QCSR); @@ -2230,12 +2294,14 @@ inline void p9_pgpe_droop_throttle() } } - //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(G_OCB_OCCFLG_OR, BIT32(PGPE_PROLONGED_DROOP_WORKAROUND_ACTIVE)); + //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); + + //4. Clear the Prolonged Droop Global variables (Bit vector and retry counts). G_pgpe_pstate_record.cntNACKs = 0; @@ -2296,3 +2362,196 @@ inline void p9_pgpe_droop_unthrottle() PK_TRACE_INF("DTH: Droop Unthrottle Done"); } + + +// +// p9_pgpe_pstate_wov_init +// +void p9_pgpe_pstate_wov_init() +{ + //G_pgpe_pstate_record.wov.freq_loss_threshold_tenths = UNDERVOLT_LOSS_THRESHOLD_TENTHS; + G_pgpe_pstate_record.wov.avg_freq_gt_target_freq = 0; + G_pgpe_pstate_record.wov.freq_loss_tenths_gt_max_droop_tenths = 0; + G_pgpe_pstate_record.wov.status = WOV_DISABLED; + G_pgpe_pstate_record.wov.info = 0xdeadbeef; +} + +// +//p9_pgpe_pstate_adjust_wov +// +void p9_pgpe_pstate_adjust_wov() +{ + uint32_t max_freq_loss_percent_tenths = 0; + uint32_t sample_valid = 0; + uint32_t q = 0; + uint32_t freq_loss = 0; + uint64_t qfmr; + uint32_t delta_tb, delta_cycles, new_tb, new_cycles; + + PK_TRACE_INF("WOV: Adjust"); + + ocb_qcsr_t qcsr; + qcsr.value = in32(G_OCB_QCSR); + + //Determine performance loss + for (q = 0; q < MAX_QUADS; q++) + { + //If quad not in STOP11. Active quads only has quads that are NOT in STOP11, and + //have been registered with PGPE. Therefore we OR in the requested_active_quads which + //include quads that are up, but not yet registered with PGPE + if (G_pgpe_pstate_record.activeQuads & QUAD_MASK(q)) + { + //Sample Frequency + //Read from EX0(if configured). Otherwise, read from EX1 + if (qcsr.fields.ex_config & QUAD_EX0_MASK(q)) + { + GPE_GETSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_QFMR, q, 0), qfmr); + } + else + { + GPE_GETSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_QFMR, q, 1), qfmr); + } + + new_tb = qfmr >> 32; + new_cycles = qfmr & (0xFFFFFFFF); + + PK_TRACE_INF("WOV: QFMR[%d]=0x%08x %08x ", q, qfmr >> 32, qfmr); + + //If freq_change_in_progress + if (G_pgpe_pstate_record.wov.frequency_change_direction != PGPE_FREQ_DIRECTION_NO_CHANGE) + { + G_pgpe_pstate_record.wov.freq_changed[q] = G_pgpe_pstate_record.wov.frequency_change_direction; + } + else + { + sample_valid = 1; + G_pgpe_pstate_record.wov.target_freq[q] = p9_pgpe_gppb_freq_from_ps(G_pgpe_pstate_record.psCurr.fields.quads[q]); + + //Calculate delta timebase while accounting for rollover + delta_tb = new_tb - G_pgpe_pstate_record.wov.last_qfmr_tb[q]; + + if (delta_tb & 0x80000000) + { + delta_tb += 0xFFFFFFFF; + } + + //Calculate delta cyles while accounting for rollover + delta_cycles = new_cycles - G_pgpe_pstate_record.wov.last_qfmr_cycles[q]; + + if (delta_cycles & 0x80000000) + { + delta_cycles += 0xFFFFFFFF; + } + + G_pgpe_pstate_record.wov.avg_freq[q] = (delta_cycles * (G_gppb->nest_frequency_mhz >> 3)) / + delta_tb; + + + if (G_pgpe_pstate_record.wov.avg_freq[q] > + G_pgpe_pstate_record.wov.target_freq[q]) // ensure that the calculation doesn't result in negative loss + { + //\todo Understand why is happening on pstate change and Add this back + PK_TRACE_INF("WOV: WARNING Avg Freq sampled greater than target freq for quad[%d], avg=0x%x,tgt=0x%x", q, + G_pgpe_pstate_record.wov.avg_freq[q], + G_pgpe_pstate_record.wov.target_freq[q]); + G_pgpe_pstate_record.wov.avg_freq_gt_target_freq = 1; + // PGPE_TRACE_AND_PANIC(PGPE_UVOLT_AVG_FREQ_GREATER_THAN_TARGET);//should not happen since we interlock with Pstate change + } + else + { + freq_loss = G_pgpe_pstate_record.wov.target_freq[q] - G_pgpe_pstate_record.wov.avg_freq[q]; + } + + G_pgpe_pstate_record.wov.freq_loss_percent_tenths[q] = (freq_loss * 1000) / G_pgpe_pstate_record.wov.target_freq[q]; + + PK_TRACE_INF("AUV: Quad[%d] TgtFreq=0x%x Avg_Freq=0x%x FreqLossPercentTenths=0x%x", q, + G_pgpe_pstate_record.wov.target_freq[q], G_pgpe_pstate_record.wov.avg_freq[q], + G_pgpe_pstate_record.wov.freq_loss_percent_tenths[q]); + + if (G_pgpe_pstate_record.wov.freq_loss_percent_tenths[q] > G_gppb->wov_max_droop_pct) + { + //\todo Understand why is happening on pstate change and Add this back + PK_TRACE_INF("AUV: WARNING Freq Lost Percent Tenths greater than Max Droop Percent Tenths for quad [%d], freq_loss=0x%x", + q, G_pgpe_pstate_record.wov.freq_loss_percent_tenths[q]); + G_pgpe_pstate_record.wov.freq_loss_tenths_gt_max_droop_tenths = + G_pgpe_pstate_record.wov.freq_loss_percent_tenths[q]; + // PGPE_TRACE_AND_PANIC(PGPE_UVOLT_FREQ_LOSS_GREATER_THAN_MAX_DROOP); // only DPLL droop can reduce frequency if not pstate change + } + + // remember the most freq loss seen across all quads that didnt change pstate + if (G_pgpe_pstate_record.wov.freq_loss_percent_tenths[q] > max_freq_loss_percent_tenths) + { + max_freq_loss_percent_tenths = G_pgpe_pstate_record.wov.freq_loss_percent_tenths[q]; + } + } + + G_pgpe_pstate_record.wov.last_qfmr_tb[q] = new_tb; + G_pgpe_pstate_record.wov.last_qfmr_cycles[q] = new_cycles; + } + } + + if (sample_valid) // don't update wov parameters unless at least one quad has a valid sample + { + // WOV ALGORITHM BEGIN + if (max_freq_loss_percent_tenths < G_gppb->wov_underv_perf_loss_thresh_pct) + { + if (G_pgpe_pstate_record.wov.curr_pct < G_gppb->wov_underv_max_pct) + { + G_pgpe_pstate_record.wov.target_pct += G_gppb->wov_underv_step_incr_pct; + } + else + { + G_pgpe_pstate_record.wov.target_pct = G_gppb->wov_underv_max_pct; + } + } + else + { + if (G_pgpe_pstate_record.wov.target_pct > 0) + { + G_pgpe_pstate_record.wov.target_pct -= G_gppb->wov_underv_step_incr_pct; + } + } + }// WOV ALGORITHM END + + PK_TRACE_INF("WOV: wov_curr_pct=%d, wov_tgt_pct=%d", + G_pgpe_pstate_record.wov.curr_pct, + G_pgpe_pstate_record.wov.target_pct); + +} + +// +// p9_pgpe_pstate_reset_wov() +// +void p9_pgpe_pstate_reset_wov() +{ + uint64_t qfmr; + ocb_qcsr_t qcsr; + uint32_t q; + + //Reset wov steps to 0 + G_pgpe_pstate_record.wov.curr_pct = 0; + G_pgpe_pstate_record.wov.target_pct = 0; + + //Update QFMR snapshot + qcsr.value = in32(G_OCB_QCSR); + + for (q = 0; q < MAX_QUADS; q++) + { + if (G_pgpe_pstate_record.activeQuads & QUAD_MASK(q)) + { + //Read from EX0(if configured). Otherwise, read from EX1 + if (qcsr.fields.ex_config & QUAD_EX0_MASK(q)) + { + GPE_GETSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_QFMR, q, 0), qfmr); + } + else + { + GPE_GETSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_QFMR, q, 1), qfmr); + } + + G_pgpe_pstate_record.wov.last_qfmr_tb[q] = ((qfmr >> 32) & 0xFFFFFFFF); + G_pgpe_pstate_record.wov.last_qfmr_cycles[q] = qfmr & 0xFFFFFFFF; + } + } + +} diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.h b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.h index 4c0860a9..9ccb5d03 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.h +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HCODE Project */ /* */ -/* COPYRIGHT 2016,2018 */ +/* COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -33,7 +33,6 @@ #include "p9_pgpe_header.h" #include "p9_stop_recovery_trigger.h" - enum IPC_PEND_TBL { IPC_PEND_PSTATE_START_STOP = 0, @@ -77,6 +76,13 @@ enum WOF_STATUS WOF_ENABLED = 2 //Pstates are active }; +enum WOV_STATUS +{ + WOV_DISABLED = 0x0, //WOV Disabled + WOV_UNDERVOLT_ENABLED = 0x1, //WOV Undervolt Enabled + WOV_OVERVOLT_ENABLED = 0x2, //WOV Overvolt Enabled +}; + enum SAFE_MODE_FAULT_INDEX { SAFE_MODE_FAULT_OCC = 0, @@ -108,7 +114,7 @@ enum PGPE_CORE_THROTTLE // Include core offline, address error, and timeout. The timeout is // included to avoid an extra mtmsr in the event we need to cleanup // from SW407201 - MSR_THROTTLE_MASK = 0x39000000, + MSR_THROTTLE_MASK = 0x29000000, WORKAROUND_SCOM_MULTICAST_WRITE = 0x69010800, THROTTLE_SCOM_MULTICAST_WRITE = 0x69010A9E, CORE_IFU_THROTTLE = 0x80000000, @@ -130,6 +136,13 @@ enum ACTIVE_CORE_UPDATE_ACTION ACTIVE_CORE_UPDATE_ACTION_ACK_ONLY = 0x2 }; +enum PGPE_FREQ_DIRECTION +{ + PGPE_FREQ_DIRECTION_NO_CHANGE = 0, + PGPE_FREQ_DIRECTION_DOWN = -1, + PGPE_FREQ_DIRECTION_UP = 1 +}; + //Task list entry typedef struct ipc_req { @@ -151,6 +164,27 @@ typedef union sys_ps } fields; } sys_ps_t; +// +// Struct for WOV(Workload Optimized Voltage) data +// +typedef struct wov +{ + uint32_t curr_pct, target_pct; + uint32_t curr_mv, target_mv; + uint32_t status; + uint32_t info; + uint32_t min_volt, max_volt; + uint32_t avg_freq_gt_target_freq; + uint32_t freq_loss_tenths_gt_max_droop_tenths; + uint32_t avg_freq[MAX_QUADS]; + uint32_t target_freq[MAX_QUADS]; + uint32_t freq_loss_percent_tenths[MAX_QUADS]; + uint32_t frequency_change_direction; //Indicates frequency change direction + uint32_t freq_changed[MAX_QUADS]; + uint32_t last_qfmr_tb[MAX_QUADS]; //CME_QFMR timebase field + uint32_t last_qfmr_cycles[MAX_QUADS]; //CME_QFMR cycles field +} wov_t; + // // PGPE PState // @@ -170,7 +204,7 @@ typedef struct sys_ps_t psTarget; //56 sys_ps_t psCurr; //64 sys_ps_t psNext; //72 - uint32_t eVidCurr, eVidNext; //84 + uint32_t extVrmCurr, extVrmNext;//84 ipc_req_t ipcPendTbl[MAX_IPC_PEND_TBL_ENTRIES]; //156(9entries*8bytes) HomerVFRTLayout_t* pVFRT; //160 quad_state0_t* pQuadState0; //164 @@ -191,6 +225,8 @@ typedef struct uint8_t severeFault[4]; uint32_t pendingActiveQuadUpdtDone; uint32_t activeCoreUpdtAction; + uint32_t biasSyspExtVrmCurr, biasSyspExtVrmNext; + wov_t wov; } PgpePstateRecord __attribute__ ((aligned (8))); @@ -264,7 +300,13 @@ void p9_pgpe_pstate_handle_pending_sgpe_ack_on_fault(); //Actuation int32_t p9_pgpe_pstate_at_target(); +int32_t p9_pgpe_pstate_at_wov_target(); void p9_pgpe_pstate_do_step(); -void p9_pgpe_pstate_updt_ext_volt(uint32_t tgtEVid); +void p9_pgpe_pstate_updt_ext_volt(); void p9_pgpe_pstate_write_core_throttle(uint32_t throttleData, uint32_t enable_retry); + +//Wov +void p9_pgpe_pstate_adjust_wov(); +void p9_pgpe_pstate_reset_wov(); + #endif // 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 24f352b6..d01a7d86 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 @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HCODE Project */ /* */ -/* COPYRIGHT 2016,2018 */ +/* COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -130,7 +130,8 @@ void p9_pgpe_thread_actuate_pstates(void* arg) } //Actuate step(if needed) - if(p9_pgpe_pstate_at_target() == 0) + if ((p9_pgpe_pstate_at_target() == 0) || + (p9_pgpe_pstate_at_wov_target() == 0)) { pk_irq_sub_critical_enter(&ctx); 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 41d974cd..c9f8d0f5 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 @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HCODE Project */ /* */ -/* COPYRIGHT 2016,2018 */ +/* COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -1210,18 +1210,32 @@ inline void p9_pgpe_process_registration() VPD_PT_SET_BIASED_SYSP); //Move voltage by voltage step-size - while(G_pgpe_pstate_record.eVidCurr != targetEVid) + while(G_pgpe_pstate_record.biasSyspExtVrmCurr != targetEVid) { - if ((targetEVid - G_pgpe_pstate_record.eVidCurr) <= G_gppb->ext_vrm_step_size_mv) + if ((targetEVid - G_pgpe_pstate_record.biasSyspExtVrmCurr) <= G_gppb->ext_vrm_step_size_mv) { - G_pgpe_pstate_record.eVidNext = targetEVid; + G_pgpe_pstate_record.biasSyspExtVrmNext = targetEVid; + G_pgpe_pstate_record.psNext.fields.glb = G_pgpe_pstate_record.psTarget.fields.glb; } else { - G_pgpe_pstate_record.eVidNext = G_pgpe_pstate_record.eVidCurr + G_gppb->ext_vrm_step_size_mv; + G_pgpe_pstate_record.biasSyspExtVrmNext = G_pgpe_pstate_record.biasSyspExtVrmCurr + G_gppb->ext_vrm_step_size_mv; + G_pgpe_pstate_record.psNext.fields.glb = p9_pgpe_gppb_intp_ps_from_ext_vdd(G_pgpe_pstate_record.biasSyspExtVrmNext); + + //It's possible that the interpolation function returns Pstate higher than + //target due to rounding errors, so we adjust back. + if (G_pgpe_pstate_record.psNext.fields.glb > G_pgpe_pstate_record.psTarget.fields.glb) + { + G_pgpe_pstate_record.psNext.fields.glb = G_pgpe_pstate_record.psTarget.fields.glb; + } + + //Make sure voltage written corresponds exactly to a pstate + G_pgpe_pstate_record.biasSyspExtVrmNext = p9_pgpe_gppb_intp_vdd_from_ps(G_pgpe_pstate_record.psNext.fields.glb, + VPD_PT_SET_BIASED_SYSP); + } - p9_pgpe_pstate_updt_ext_volt(targetEVid); + p9_pgpe_pstate_updt_ext_volt(); } //Set GlobalPSCurr and Next diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pgpe_panic_codes.h b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pgpe_panic_codes.h index 6955845a..7703cd35 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pgpe_panic_codes.h +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pgpe_panic_codes.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HCODE Project */ /* */ -/* COPYRIGHT 2016,2018 */ +/* COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -86,10 +86,8 @@ PGPE_SET_PMCR_TRAP_INJECT = 0x1e05, PGPE_DROOP_AND_CORE_THROTTLE_ENABLED = 0x1e06, PGPE_INVALID_FREQ_UPDT = 0x1e07, PGPE_PMAX_RCV_GREATER_THAN_PSAFE = 0x1e08, -//_UNUSED_1e07 = 0x1e07, -//_UNUSED_1e08 = 0x1e08, -//_UNUSED_1e09 = 0x1e09, -//_UNUSED_1e0a = 0x1e0a, +PGPE_UVOLT_FREQ_LOSS_GREATER_THAN_MAX_DROOP = 0x1e09, +PGPE_UVOLT_AVG_FREQ_GREATER_THAN_TARGET = 0x1e0a, //_UNUSED_1e0d = 0x1e0d, //_UNUSED_1e1c = 0x1e1c, //_UNUSED_1e1d = 0x1e1d, diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pstate_common.mk b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pstate_common.mk index 6e8376bf..04c17452 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pstate_common.mk +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pstate_common.mk @@ -5,7 +5,7 @@ # # OpenPOWER HCODE Project # -# COPYRIGHT 2017,2018 +# COPYRIGHT 2017,2019 # [+] International Business Machines Corp. # # @@ -91,7 +91,7 @@ PSTATE_COMMONFLAGS+= -DPK_TRACE_SUPPORT=1 PSTATE_COMMONFLAGS+= -DUSE_PK_APP_CFG_H=1 PSTATE_COMMONFLAGS+= -D__PPE_PLAT PSTATE_COMMONFLAGS+= -D__PK__=1 -PSTATE_COMMONFLAGS+= -DPK_TRACE_SZ=1024 +PSTATE_COMMONFLAGS+= -DPK_TRACE_SZ=2048 PSTATE_COMMONFLAGS+= -DPSTATE_GPE diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pstate_gpe.mk b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pstate_gpe.mk index f7965d8f..c516d6bf 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pstate_gpe.mk +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pstate_gpe.mk @@ -5,7 +5,7 @@ # # OpenPOWER HCODE Project # -# COPYRIGHT 2016,2018 +# COPYRIGHT 2016,2019 # [+] International Business Machines Corp. # # @@ -94,7 +94,7 @@ $(IMAGE)_COMMONFLAGS+= -DUSE_PK_APP_CFG_H=1 $(IMAGE)_COMMONFLAGS+= -D__PPE_PLAT $(IMAGE)_COMMONFLAGS+= -D__PK__=1 #$(IMAGE)_COMMONFLAGS+= -fstack-usage -$(IMAGE)_COMMONFLAGS+= -DPK_TRACE_SZ=1024 +$(IMAGE)_COMMONFLAGS+= -DPK_TRACE_SZ=2048 # add include paths $(call ADD_PPEIMAGE_INCDIR,$(IMAGE),\ -- cgit v1.2.1