From 3ca9f1f8636f794d287e2cfef135f0a1bf31e55d Mon Sep 17 00:00:00 2001 From: Rahul Batra Date: Fri, 18 Nov 2016 17:10:30 -0600 Subject: WOF Enablement in PGPE -Full functionality for OCC Start/Stop, Set PMCR, Clip Updt -New code structure for PGPE(actuate/process thread, etc) -Update CME code as per the new Doorbell0 -Added place holders for SGPE-PGPE IPCs -Place holders for Error Interrupts like OCB_Error, XSTOP -Added code to correctly account for VRM transition delays Change-Id: I301b14304677e2ed0130f1c3479d523dcb931293 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/34156 Tested-by: Jenkins Server Tested-by: Hostboot CI Reviewed-by: ASHISH A. MORE Reviewed-by: Gregory S. Still Reviewed-by: Jennifer A. Stofer --- .../p9/common/pmlib/include/pstate_pgpe_cme_api.h | 153 ++++ .../p9/common/pmlib/include/pstate_pgpe_occ_api.h | 31 +- import/chips/p9/common/pmlib/occlib/ipc_core.c | 2 + .../chips/p9/procedures/hwp/lib/p9_pstates_pgpe.h | 22 +- .../ppe_closed/cme/pstate_cme/p9_cme_intercme.c | 99 +++ .../ppe_closed/cme/pstate_cme/p9_cme_pstate.c | 406 ----------- .../ppe_closed/cme/pstate_cme/p9_cme_pstate.h | 35 +- .../ppe_closed/cme/pstate_cme/p9_cme_thread_db.c | 528 ++++++++++++++ .../ppe_closed/cme/pstate_cme/p9_cme_thread_pmcr.c | 131 ++++ .../chips/p9/procedures/ppe_closed/cme/topfiles.mk | 10 +- .../ppe_closed/pgpe/pstate_gpe/p9_pgpe.h | 18 +- .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_boot_temp.c | 14 +- .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_gppb.c | 13 + .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_gppb.h | 1 + .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_header.c | 3 +- .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_header.h | 2 +- .../pgpe/pstate_gpe/p9_pgpe_ipc_handlers.c | 413 +++++++++++ .../pgpe/pstate_gpe/p9_pgpe_ipc_handlers.h | 51 ++ .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.c | 156 ++-- .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.h | 36 +- .../pgpe/pstate_gpe/p9_pgpe_irq_handlers.c | 147 ++++ .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_main.c | 55 +- .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.c | 544 +++++--------- .../ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.h | 74 ++ .../pstate_gpe/p9_pgpe_thread_actuate_pstates.c | 783 +++++++++++++++++++++ .../pstate_gpe/p9_pgpe_thread_process_requests.c | 574 +++++++++++++++ .../ppe_closed/pgpe/pstate_gpe/pk_app_cfg.h | 30 +- .../ppe_closed/pgpe/pstate_gpe/pstate_gpe.mk | 5 + .../ppe_closed/pgpe/pstate_gpe/topfiles.mk | 8 +- 29 files changed, 3400 insertions(+), 944 deletions(-) create mode 100644 import/chips/p9/common/pmlib/include/pstate_pgpe_cme_api.h create mode 100644 import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_intercme.c create mode 100644 import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_thread_db.c create mode 100644 import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_thread_pmcr.c create mode 100644 import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_ipc_handlers.c create mode 100644 import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_ipc_handlers.h create mode 100644 import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq_handlers.c create mode 100644 import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.h create mode 100644 import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_actuate_pstates.c create mode 100644 import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_process_requests.c 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 new file mode 100644 index 00000000..e3ab881d --- /dev/null +++ b/import/chips/p9/common/pmlib/include/pstate_pgpe_cme_api.h @@ -0,0 +1,153 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/common/pmlib/include/pstate_pgpe_cme_api.h $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2016,2017 */ +/* [+] 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 */ +#ifndef __PSTATE_PGPE_CME_API_H__ +#define __PSTATE_PGPE_CME_API_H__ + +#define DPLL_REFCLK_DIVIDER 16667 +#define PIG_PAYLOAD_PS_PHASE1_MASK 0x03FF000000000000 +#define PIG_PAYLOAD_PS_PHASE2_MASK 0x000003FF00000000 +#define PIG_PAYLOAD_MASK 0x0fff000000000000 +#define PIG_INTR_FIELD_MASK 0x7000000000000000 +#define PIG_INTR_GRANTED_MASK 0x0000000080000000 + +// Type1 specific defines +#define PIG_PAYLOAD_PSTATE_MASK 0x03ff000000000000 +#define PIG_PAYLOAD_PSTATE_SEQ_INCR 0x0400000000000000 // Seq increment value + +// PIR defines +#define PIR_INSTANCE_EVEN_ODD_MASK (uint32_t)(0x00000001) +#define PIR_INSTANCE_NUM_MASK (uint32_t)(0x0000000F) + +//Bit0 WR: 0 +//Bit1 Multicast: 1 +//Bit 2:4 Multicast Type: 101 +//Bit 5:7 Mutlicast Grp: 001 +#define PCB_MUTLICAST_GRP1 0x69000000 + +#define QUAD_FROM_CORE(c) \ + ((c&0x1C) >> 2) + +#define QUAD_FROM_CME_INSTANCE_NUM(num) \ + ((num&0xE) >> 1) + +// +// CME<->PGPE API +// +enum MESSAGE_ID_DB0 +{ + MSGID_DB0_INVALID = 0, + MSGID_DB0_RESERVED = 1, + MSGID_DB0_GLOBAL_ACTUAL_BROADCAST = 2, + MSGID_DB0_START_PSTATE_BROADCAST = 3, + MSGID_DB0_STOP_PSTATE_BROADCAST = 4 +}; + +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, +}; + + +// +//PGPE-CME Doorbell0(Global Actual Broadcast) +// +typedef union pgpe_db0_glb_bcast_t +{ + uint64_t value; + struct + { +#ifdef _BIG_ENDIAN + uint64_t msg_id : 8; + uint64_t global_actual : 8; + uint64_t quad0_ps: 8; + uint64_t quad1_ps: 8; + uint64_t quad2_ps: 8; + uint64_t quad3_ps: 8; + uint64_t quad4_ps: 8; + uint64_t quad5_ps: 8; +#else + uint64_t quad5_ps: 8; + uint64_t quad4_ps: 8; + uint64_t quad3_ps: 8; + uint64_t quad2_ps: 8; + uint64_t quad1_ps: 8; + uint64_t quad0_ps: 8; + uint64_t global_actual : 8; + uint64_t msg_id : 8; +#endif + } fields; +} pgpe_db0_glb_bcast_t; + +// +//PGPE-CME Doorbell0(Start Pstate Broaadcast) +// +typedef union pgpe_db0_start_ps_bcast +{ + uint64_t value; + struct + { +#ifdef _BIG_ENDIAN + uint64_t msg_id : 8; + uint64_t global_actual : 8; + uint64_t quad0_ps : 8; + uint64_t quad1_ps : 8; + uint64_t quad2_ps : 8; + uint64_t quad3_ps : 8; + uint64_t quad4_ps : 8; + uint64_t quad5_ps : 8; +#else + uint64_t quad5_ps : 8; + uint64_t quad4_ps : 8; + uint64_t quad3_ps : 8; + uint64_t quad2_ps : 8; + uint64_t quad1_ps : 8; + uint64_t quad0_ps : 8; + uint64_t global_actual : 8; + uint64_t msg_id : 8; +#endif + } fields; +} pgpe_db0_start_ps_bcast_t; + +// +//PGPE-CME Doorbell0(Pstate Stop Broaadcast) +// +typedef union pgpe_db0_stop_ps_bcast +{ + uint64_t value; + struct + { +#ifdef _BIG_ENDIAN + uint64_t msg_id : 8; + uint64_t reserved : 56; +#else + uint64_t reserved : 56; + uint64_t msg_id : 8; +#endif + } fields; +} pgpe_db0_stop_ps_bcast_t; + +#endif //__PSTATE_PGPE_CME_API_H__ diff --git a/import/chips/p9/common/pmlib/include/pstate_pgpe_occ_api.h b/import/chips/p9/common/pmlib/include/pstate_pgpe_occ_api.h index 32f10398..08850fed 100644 --- a/import/chips/p9/common/pmlib/include/pstate_pgpe_occ_api.h +++ b/import/chips/p9/common/pmlib/include/pstate_pgpe_occ_api.h @@ -41,9 +41,6 @@ extern "C" { #endif -// Maximum Number of Quads supported -#define MAX_QUADS 6 - //--------------- // IPC from 405 @@ -62,11 +59,19 @@ enum MESSAGE_ID_IPI2HI // // Return Codes // -#define PGPE_RC_SUCCESS 0x01 -#define PGPE_WOF_RC_NOT_ENABLED 0x10 +//\todo +//Get feedback from Martha and Greg on these return codes +// +#define PGPE_RC_SUCCESS 0x01 +#define PGPE_WOF_RC_NOT_ENABLED 0x10 +#define PGPE_RC_PSTATES_DISABLED 0x11 +#define PGPE_RC_REQ_PSTATE_ALREADY_STARTED 0x12 +#define PGPE_RC_REQ_PSTATE_ALREADY_SUSPENDED 0x13 +#define PGPE_RC_OCC_NOT_PMCR_OWNER 0x14 // Active quad mismatch with requested active quads. PGPE did not switch // to using the new VFRT. The original VFRT is still being used. #define PGPE_WOF_RC_VFRT_QUAD_MISMATCH 0x20 +#define PGPE_RC_REQ_WHILE_PENDING_ACK 0x21 // // PMCR Owner @@ -74,7 +79,8 @@ enum MESSAGE_ID_IPI2HI typedef enum { PMCR_OWNER_HOST = 0, - PMCR_OWNER_OCC = 1 + PMCR_OWNER_OCC = 1, + PMCR_OWNER_CHAR = 2 } PMCR_OWNER; @@ -88,14 +94,14 @@ typedef struct ipcmsg_base // Start Suspend Actions // #define PGPE_ACTION_PSTATE_START 0 -#define PGPE_ACTION_PSTATE_SUSPEND 1 +#define PGPE_ACTION_PSTATE_STOP 1 -typedef struct ipcmsg_start_suspend +typedef struct ipcmsg_start_stop { ipcmsg_base_t msg_cb; uint8_t action; PMCR_OWNER pmcr_owner; -} ipcmsg_start_suspend_t; +} ipcmsg_start_stop_t; typedef struct ipcmsg_clip_update @@ -269,9 +275,9 @@ typedef union quad_state0 uint64_t quad1_pstate : 8; // Pstate of Quad 1; 0xFF indicates EQ is off uint64_t quad2_pstate : 8; // Pstate of Quad 2; 0xFF indicates EQ is off uint64_t quad3_pstate : 8; // Pstate of Quad 3; 0xFF indicates EQ is off + uint64_t core_poweron_state : 16; // bit vector: 0:core0, 1:core1, ..., 15:core15 uint64_t ivrm_state : 4; // ivrm state: bit vector 0:quad0, 1:quad1, 2:quad2, 3;quad3 uint64_t ivrm_state_rsvd : 4; - uint64_t core_poweron_state : 16; // bit vector: 0:core0, 1:core1, ..., 15:core15 uint64_t external_vrm_setpoint : 8; // set point in mV } fields; } quad_state0_t; @@ -288,12 +294,11 @@ typedef union quad_state1 { uint64_t quad4_pstate : 8; // Pstate of Quad 4; 0xFF indicates EQ is off uint64_t quad5_pstate : 8; // Pstate of Quad 5; 0xFF indicates EQ is off - uint64_t requested_active_quad : 6; // Pstate of Quad 5; 0xFF indicates EQ is off - uint64_t quad_pstate_rsvd : 10; + uint64_t reserved : 16; uint64_t ivrm_state : 2; // ivrm state: bit vector 0:quad4, 1:quad5 uint64_t ivrm_state_rsvd : 6; uint64_t core_poweron_state : 8; // bit vector: 0:core16, 1:core17, ..., 7:core23 - uint64_t core_poweron_state_rsvd : 8; + uint64_t requested_active_quad : 8; uint64_t external_vrm_setpoint : 8; // set point in mV } fields; } quad_state1_t; diff --git a/import/chips/p9/common/pmlib/occlib/ipc_core.c b/import/chips/p9/common/pmlib/occlib/ipc_core.c index e6096932..65a8625a 100644 --- a/import/chips/p9/common/pmlib/occlib/ipc_core.c +++ b/import/chips/p9/common/pmlib/occlib/ipc_core.c @@ -355,8 +355,10 @@ void ipc_process_cbuf(uint32_t sender_id) ipc_process_cbuf(sender_id); } +#ifndef UNIFIED_IRQ_HANDLER_GPE // Unmask the irq before returning KERN_IRQ_ENABLE(IPC_GET_IRQ(OCCHW_INST_ID_SELF)); +#endif } diff --git a/import/chips/p9/procedures/hwp/lib/p9_pstates_pgpe.h b/import/chips/p9/procedures/hwp/lib/p9_pstates_pgpe.h index ea7fd0d1..789cdd17 100644 --- a/import/chips/p9/procedures/hwp/lib/p9_pstates_pgpe.h +++ b/import/chips/p9/procedures/hwp/lib/p9_pstates_pgpe.h @@ -218,13 +218,31 @@ typedef struct /// Resonant Clock Grid Management Setup ResonantClockingSetup resclk; - //Voltage change step size - uint32_t ext_vdd_step_size_mv; + //Time b/w ext VRM detects write voltage cmd and when voltage begins to move + uint32_t ext_vrm_transition_start_ns; + //Transition rate for an increasing VDD voltage excursion + uint32_t ext_vrm_transition_rate_inc_uv_per_us; + + //Transition rate for an decreasing VDD voltage excursion + uint32_t ext_vrm_transition_rate_dec_uv_per_us; + + //Delay to account for VDD rail setting + uint32_t ext_vrm_stabilization_time_us; + + //External VRM transition step size + uint32_t ext_vrm_step_size_mv; + + //Nest frequency in Mhz. This is used by FIT interrupt uint32_t nest_frequency_mhz; + //Precalculated Pstate-Voltage Slopes uint16_t PsVSlopes[VPD_NUM_SLOPES_SET][VPD_NUM_SLOPES_REGION]; + + //Precalculated Voltage-Pstates Slopes uint16_t VPsSlopes[VPD_NUM_SLOPES_SET][VPD_NUM_SLOPES_REGION]; + + // @todo DPLL Droop Settings. These need communication to SGPE for STOP } GlobalPstateParmBlock; 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 new file mode 100644 index 00000000..45860434 --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_intercme.c @@ -0,0 +1,99 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_intercme.c $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2016,2017 */ +/* [+] 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 */ +#include "pk.h" +#include "ppe42_scom.h" +#include "cppm_register_addresses.h" +#include "cppm_firmware_registers.h" +#include "cme_register_addresses.h" +#include "cmehw_common.h" +#include "ppehw_common.h" + +#include "p9_cme_irq.h" +#include "p9_cme_flags.h" +#include "p9_cme_pstate.h" +#include "pstate_pgpe_cme_api.h" +#include "p9_pstate_vpd.h" +#include "ppe42_cache.h" + +// +//Globals +// +extern CmePstateRecord G_cme_pstate_record; + +// +//InterCME_IN0 handler +// +void p9_cme_pstate_intercme_in0_handler(void* arg, PkIrqId irq) +{ + cppm_cmedb0_t dbData; + dbData.value = 0; + uint32_t localPS = 0; + uint32_t cme_flags = in32(CME_LCL_FLAGS); + uint64_t pmsrData = 0; + int32_t c = 0; + PkMachineContext ctx; + + PK_TRACE("INTERCME_IN0: Enter\n"); + + for (c = 0; c < CORES_PER_EX; c++ ) + { + if (cme_flags & (CME_FLAGS_CORE0_GOOD >> c)) + { + if(dbData.fields.cme_message_number0 == MSGID_DB0_START_PSTATE_BROADCAST) + { + PK_TRACE("INTERCME_IN0: DB0 Start\n"); + //Clear any pending PMCR interrupts + out32_sh(CME_LCL_EISR_CLR, BIT32(2) >> c); + out32_sh(CME_LCL_EIMR_CLR, BIT32(2) >> c);//Enable PMCR0/1 + } + else if(dbData.fields.cme_message_number0 == MSGID_DB0_GLOBAL_ACTUAL_BROADCAST) + { + PK_TRACE("INTERCME_IN0: DB0 GlbBcast\n"); + localPS = (dbData.value >> + ((MAX_QUADS - G_cme_pstate_record.quadNum - 1) << 8)) & 0xFF; + pmsrData = (dbData.value << 8) & 0xFF00000000000000; + pmsrData |= ((uint64_t)localPS << 48) & 0x00FF000000000000; + out64((CME_LCL_PMSRS0 + (c << 5)), pmsrData); + out32_sh(CME_LCL_EISR_CLR, BIT32(4) >> c);//Clear DB0_C0 + } + else if(dbData.fields.cme_message_number0 == MSGID_DB0_STOP_PSTATE_BROADCAST) + { + PK_TRACE("INTERCME_IN0: DB0 Stop\n"); + out32_sh(CME_LCL_EIMR_OR, BIT32(2) >> c);//Enable PMCR0/1 + } + else + { + pk_halt(); + } + } + } + + out32(CME_LCL_ICCR_OR, BIT32(5));//Send Direct InterCME_IN0(Ack to QM-CME) + out32(CME_LCL_ICCR_CLR, BIT32(5));//Clear Ack + out32(CME_LCL_EISR_CLR, BIT32(7));//Clear InterCME_IN0 + + pk_irq_vec_restore(&ctx); + PK_TRACE("INTERCME_IN0: Exit\n"); +} 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 e963814c..e96fcb89 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 @@ -49,418 +49,12 @@ #include "ppehw_common.h" #include "cmehw_common.h" #include "cmehw_interrupts.h" - -#include "p9_cme_irq.h" -#include "p9_cme_flags.h" #include "p9_cme_pstate.h" -#include "p9_pstate_common.h" -#include "p9_pstate_vpd.h" -#include "ppe42_cache.h" // //Globals // -extern CmePstateRecord G_cme_pstate_record; -cme_pstate_db_data_t G_db_thread_data; -cme_pstate_pmcr_data_t G_pmcr_thread_data; - -//\todo Use PState Parameter Block structures. RTC -extern global_pstate_table_t G_gpst; -extern freq_2_idx_entry_t G_freq2idx[NUM_FREQ_REGIONS]; -extern uint16_t G_cgm_table[CGM_TRANSITIONS]; -extern uint8_t G_resclkEnabled; - -// -//Function Prototypes -// -void freq_update(uint64_t dbData); -void resclk_update(); -int send_pig_packet(uint64_t data, uint32_t coreMask); - -// -//PMCR Interrupt Handler -// -void p9_cme_pstate_pmcr_handler(void* arg, PkIrqId irq) -{ - pk_semaphore_post((PkSemaphore*)arg); -} - -// -//Doorbell0 interrupt handler -// -//Only enabled on QuadManager-CME -void p9_cme_pstate_db_handler(void* arg, PkIrqId irq) -{ - pk_semaphore_post((PkSemaphore*)arg); -} - -// -//InterCME_IN0 handler -// -void p9_cme_pstate_intercme_in0_handler(void* arg, PkIrqId irq) -{ - pgpe_db0_glb_bcast_t db0C0Data, db0C1Data; - uint8_t localPS = 0; - uint32_t cme_flags = in32(CME_LCL_FLAGS); - uint64_t pmsrData; - PkMachineContext ctx; - - //read DB0 for both cores and update PMSR - if (cme_flags & CME_FLAGS_CORE0_GOOD) - { - CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C0, CME_SCOM_EQ, db0C0Data.value); - localPS = (db0C0Data.value >> - ((MAX_QUADS - G_db_thread_data.quadNum - 1) * 8)) & 0xFF; - pmsrData = (db0C0Data.value << 8) & 0xFF00000000000000; - pmsrData |= ((uint64_t)localPS << 48) & 0x00FF000000000000; - - out64(CME_LCL_PMSRS0, pmsrData); - out32_sh(CME_LCL_EISR_CLR, BIT32(4));//Clear DB0_C0 - } - - if (cme_flags & CME_FLAGS_CORE1_GOOD) - { - CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C1, CME_SCOM_EQ, db0C1Data.value); - localPS = (db0C1Data.value >> - ((MAX_QUADS - G_db_thread_data.quadNum - 1) * 8)) & 0xFF; - pmsrData = (db0C1Data.value << 8) & 0xFF00000000000000; - pmsrData |= ((uint64_t)localPS << 48) & 0x00FF000000000000; - - out64(CME_LCL_PMSRS1, pmsrData); - out32_sh(CME_LCL_EISR_CLR, BIT32(5));//Clear DB0_C1 - } - - out32(CME_LCL_ICCR_OR, BIT32(5));//Send Direct InterCME_IN0(Ack to QM-CME) - out32(CME_LCL_ICCR_CLR, BIT32(5));//Clear Ack - out32(CME_LCL_EISR_CLR, BIT32(7));//Clear InterCME_IN0 - - pk_irq_vec_restore(&ctx); -} - -// -//p9_cme_pmcr_thread -// -void p9_cme_pstate_pmcr_thread(void* arg) -{ - int32_t c; - PkMachineContext ctx; - cme_scom_pmcrs0_t pmcr[2]; - ppm_pig_t ppmPigData; - uint32_t eisr; - uint32_t coreMask[CORES_PER_EX]; - coreMask[0] = CME_MASK_C0; - coreMask[1] = CME_MASK_C1; - - G_pmcr_thread_data.seqNum = 0; - - G_pmcr_thread_data.coreGood[0] = 0; - G_pmcr_thread_data.coreGood[1] = 0; - G_pmcr_thread_data.cmeFlags = in32(CME_LCL_FLAGS); - - if (G_pmcr_thread_data.cmeFlags & CME_FLAGS_CORE0_GOOD) - { - G_pmcr_thread_data.coreGood[0] = 1; - out64(CME_LCL_EIMR_CLR, BIT64(34));//Enable PMCR0 - } - - if (G_pmcr_thread_data.cmeFlags & CME_FLAGS_CORE1_GOOD) - { - G_pmcr_thread_data.coreGood[1] = 1; - out64(CME_LCL_EIMR_CLR, BIT64(35));//Enable PMCR1 - } - - pk_semaphore_create(&G_cme_pstate_record.sem[0], 0, 1); - - while(1) - { - //pend on sempahore - pk_semaphore_pend(&G_cme_pstate_record.sem[0], PK_WAIT_FOREVER); - wrteei(1); - - //Determine which core have pending request - for(c = 0; c < CORES_PER_EX; c++) - { - if (G_pmcr_thread_data.coreGood[c]) - { - eisr = in32_sh(CME_LCL_EISR); //EISR - - if (eisr & (BIT32(2) >> c)) - { - //Clear interrupt and read PMCR - out32_sh(CME_LCL_EISR_CLR, BIT32(2) >> c); - pmcr[c].value = in64(CME_LCL_PMCRS0 + (c << 5)); - - //Send Phase 1 - ppmPigData.value = 0; - ppmPigData.fields.req_intr_type = 0; - ppmPigData.value |= (((pmcr[c].value & PIG_PAYLOAD_PS_PHASE1_MASK))); - ppmPigData.value |= ((G_pmcr_thread_data.seqNum & 0x6) << 57); - send_pig_packet(ppmPigData.value, coreMask[c]); - G_pmcr_thread_data.seqNum++; - - //Send Phase 2 - ppmPigData.value = 0; - ppmPigData.fields.req_intr_type = 1; - ppmPigData.value |= ((pmcr[c].value & PIG_PAYLOAD_PS_PHASE2_MASK) << 16); - ppmPigData.value |= ((G_pmcr_thread_data.seqNum & 0x6) << 57); - send_pig_packet(ppmPigData.value, coreMask[c]); - G_pmcr_thread_data.seqNum++; - } - } - } - - pk_irq_vec_restore(&ctx); - } -} - -// -//p9_cme_db_thread -// -void p9_cme_pstate_db_thread(void* arg) -{ - uint32_t cme_flags; - PkMachineContext ctx; - //int rc = 0; - cppm_cmedb0_t dbData; - uint8_t intercme_acked; - uint64_t eisr, pmsrData; - ppm_pig_t ppmPigData; - uint32_t pir; - uint8_t localPS; - - //\todo Read the data from HOMER code. RTC - p9_pstate_vpd_init(); - - //Read CME_LCL_FLAGS - cme_flags = in32(CME_LCL_FLAGS); - - //Determine quad number and exID for this CME - asm volatile ("mfpir %[data] \n" : [data]"=r"(pir) ); - - //We found a bug in HW late, so this is a workaround. However, in SIMICS the model - //is as per original spec. -#if !SIMICS_TUNING - G_db_thread_data.quadNum = (pir & PIR_INSTANCE_NUM_MASK); -#else - G_db_thread_data.quadNum = QUAD_FROM_CME_INSTANCE_NUM((pir & PIR_INSTANCE_NUM_MASK)); -#endif - - if (cme_flags & CME_FLAGS_QMGR_MASTER) - { - G_db_thread_data.qmFlag = 1; - - if (cme_flags & CME_FLAGS_SIBLING_FUNCTIONAL) - { - G_db_thread_data.siblingCMEFlag = 1; - } - else - { - G_db_thread_data.siblingCMEFlag = 0; - } - } - else - { - G_db_thread_data.qmFlag = 0; - G_db_thread_data.siblingCMEFlag = 0; - } - - //if quadManager - if (G_db_thread_data.qmFlag) - { - if (cme_flags & CME_FLAGS_CORE0_GOOD) - { - out32_sh(CME_LCL_EIMR_CLR, BIT32(4));//Enable DB0_0 - out32_sh(CME_LCL_EIMR_OR, BIT32(5));//Disable DB0_1 - g_eimr_override |= BIT64(37); - G_db_thread_data.cmeMaskGoodCore = CME_MASK_C0; - } - else if (cme_flags & CME_FLAGS_CORE1_GOOD) - { - out32_sh(CME_LCL_EIMR_OR, BIT32(4));//Disable DB0_0 - out32_sh(CME_LCL_EIMR_CLR, BIT32(5));//Enable DB0_1 - g_eimr_override |= BIT64(36); - G_db_thread_data.cmeMaskGoodCore = CME_MASK_C1; - } - - out64(CME_LCL_EIMR_OR, BIT64(7));//Disable InterCME_IN0 - g_eimr_override |= BIT64(7); - - G_db_thread_data.dpll_pstate0_value = G_gpst.pstate0_frequency_khz / G_gpst.frequency_step_khz; - } - else - { - out64(CME_LCL_EIMR_OR, BIT64(36) | BIT64(37));//Disable DB0_0 and DB0_1 - out64(CME_LCL_EIMR_CLR, BIT64(7)); //Enable InterCME_IN0 - g_eimr_override |= BIT64(37); - g_eimr_override |= BIT64(36); - } - - - //\todo (RTC) Set intial GlobalPS, LocalPS, resClkIdx, etc. - //Most likely will come from SGPE. Need to know precisely - - //Only Quad Manager CME executes. The sibling CME - //has intercme_in0 enabled - if (G_db_thread_data.qmFlag) - { - pk_semaphore_create(&G_cme_pstate_record.sem[1], 0, 1); - - while(1) - { - //pend on sempahore - pk_semaphore_pend(&G_cme_pstate_record.sem[1], PK_WAIT_FOREVER); - wrteei(1); - - if (cme_flags & CME_FLAGS_CORE0_GOOD) - { - out32_sh(CME_LCL_EISR_CLR, BIT32(4)); - out32_sh(CME_LCL_EISR_CLR, BIT32(5)); - CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C0, CME_SCOM_EQ, dbData.value); - } - else if (cme_flags & CME_FLAGS_CORE1_GOOD) - { - out32_sh(CME_LCL_EISR_CLR, BIT32(5)); - CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C1, CME_SCOM_EQ, dbData.value); - } - - //Update analog - if (G_resclkEnabled) - { - resclk_update(); - } - -#if !SIMICS_TUNING - freq_update(dbData.value); -#endif - - //Notify sibling CME(if any) - if (G_db_thread_data.siblingCMEFlag == 1) - { - //Send interCME interrupt - out32(CME_LCL_ICCR_OR, BIT32(5)); //Send direct InterCME_IN0 - out32(CME_LCL_ICCR_CLR, BIT32(5));//Clear - -#if !SIMICS_TUNING - //poll on interCME interrupt - intercme_acked = 0; -#else - intercme_acked = 1; -#endif - - while (!intercme_acked) - { - eisr = in64(CME_LCL_EISR); - - if (eisr & 0x0100000000000000) - { - intercme_acked = 1; - } - } - - out32(CME_LCL_EISR_CLR, BIT32(7));//Clear InterCME_IN0 - } - - //Update PMSR - localPS = (dbData.value >> - ((MAX_QUADS - G_db_thread_data.quadNum - 1) * 8)) & 0xFF; - pmsrData = (dbData.value << 8) & 0xFF00000000000000; - pmsrData |= ((uint64_t)localPS << 48) & 0x00FF000000000000; - - if (cme_flags & CME_FLAGS_CORE0_GOOD) - { - out64(CME_LCL_PMSRS0, pmsrData); - } - - if (cme_flags & CME_FLAGS_CORE1_GOOD) - { - out64(CME_LCL_PMSRS1, pmsrData); - } - - //Send type4(ack doorbell) - ppmPigData.value = 0; - ppmPigData.fields.req_intr_type = 4; - ppmPigData.fields.req_intr_payload = 0; - send_pig_packet(ppmPigData.value, G_db_thread_data.cmeMaskGoodCore); - - pk_irq_vec_restore(&ctx); - } - } -} - -// -//freq_update -// -void freq_update(uint64_t dbData) -{ - uint8_t localPS = (dbData >> - ((MAX_QUADS - G_db_thread_data.quadNum - 1) * 8)) & 0xFF; - - //Adjust DPLL - cppm_ippmcmd_t cppm_ippmcmd; - qppm_dpll_freq_t dpllFreq; - - //Write new value of DPLL using INTERPPM - dpllFreq.value = 0; - dpllFreq.fields.fmax = (uint16_t)(G_db_thread_data.dpll_pstate0_value - localPS) << 3; - dpllFreq.fields.fmult = (uint16_t)(G_db_thread_data.dpll_pstate0_value - localPS) << 3; - dpllFreq.fields.fmin = (uint16_t)(G_db_thread_data.dpll_pstate0_value - localPS) << 3; - CME_PUTSCOM(CPPM_IPPMWDATA, G_db_thread_data.cmeMaskGoodCore, dpllFreq.value); - cppm_ippmcmd.value = 0; - cppm_ippmcmd.fields.qppm_reg = QPPM_DPLL_FREQ & 0x000000ff; - cppm_ippmcmd.fields.qppm_rnw = 0; - CME_PUTSCOM(CPPM_IPPMCMD, G_db_thread_data.cmeMaskGoodCore, cppm_ippmcmd.value); -} - -// -//resclk_update -// -void resclk_update() -{ - uint64_t val; - uint8_t tidx, step; - int32_t i; - - //get targetIndex from Table1(ControlIndex) by indexing with localPState - tidx = G_db_thread_data.resClkTblIdx; - - for (i = NUM_FREQ_REGIONS - 1; i >= 0; i--) - { - if (G_freq2idx[i].pstate > G_db_thread_data.localPS) - { - tidx = i; - break; - } - } - - //walk Table2[Resonant Grids Control Data) - if (tidx > G_db_thread_data.resClkTblIdx) - { - step = 1; - } - else - { - step = -1; - } - - while(G_db_thread_data.resClkTblIdx != tidx) - { - G_db_thread_data.resClkTblIdx += step; - val = (uint64_t)(G_cgm_table[G_db_thread_data.resClkTblIdx]) << 48; - val |= G_db_thread_data.qaccr21_23InitVal; - -#if !SIMICS_TUNING - //int rc = 0; - cppm_ippmcmd_t cppm_ippmcmd; - //Write val to QACCR - CME_PUTSCOM(CPPM_IPPMWDATA, G_db_thread_data.cmeMaskGoodCore, val); - cppm_ippmcmd.value = 0; - cppm_ippmcmd.fields.qppm_reg = QPPM_QACCR & 0x000000ff; - cppm_ippmcmd.fields.qppm_rnw = 0; - CME_PUTSCOM(CPPM_IPPMCMD, G_db_thread_data.cmeMaskGoodCore, cppm_ippmcmd.value); -#endif - } -} // //send_pig_packet 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 57313ebc..5ed3c178 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 @@ -32,38 +32,51 @@ /// \brief Shared and global definitions for pstate H codes. /// \owner Rahul Batra Email: rbatra@us.ibm.com /// +#ifndef _P9_CME_PSTATE_H_ +#define _P9_CME_PSTATE_H_ #include "pk.h" -#include "p9_pstate_common.h" +#include "pstate_pgpe_cme_api.h" #include "gpehw_common.h" +enum PMCR_CONTROL +{ + PMCR0_DISABLE = 0x1, + PMCR1_DISABLE = 0x2, + PMCR0_ENABLE = 0x4, + PMCR1_ENABLE = 0x8 +}; + void p9_cme_pstate_pmcr_thread(void*); void p9_cme_pstate_db_thread(void*); void p9_cme_pstate_pmcr_handler(void*, PkIrqId); void p9_cme_pstate_db_handler(void*, PkIrqId); void p9_cme_pstate_intercme_in0_handler(void*, PkIrqId); +int send_pig_packet(uint64_t data, uint32_t coreMask); + typedef struct { PkSemaphore sem[2]; + uint32_t quadNum; + uint32_t pstatesEnabled; } CmePstateRecord; typedef struct { uint64_t seqNum; - uint32_t cmeFlags; - uint8_t coreGood[CORES_PER_EX]; } cme_pstate_pmcr_data_t; typedef struct { - uint8_t qmFlag; - uint8_t siblingCMEFlag; + uint32_t qmFlag; + uint32_t siblingCMEFlag; uint32_t cmeMaskGoodCore; - uint8_t globalPS; //\todo use PState as type - uint8_t localPS; //\todo use PState as type - uint8_t resClkTblIdx; - uint8_t qaccr21_23InitVal; - uint8_t quadNum; - uint8_t dpll_pstate0_value; + uint32_t globalPS; + uint32_t localPS; + uint32_t resClkTblIdx; + uint32_t qaccr21_23InitVal; + uint32_t dpll_pstate0_value; } cme_pstate_db_data_t; + +#endif //_P9_CME_PSTATE_H_ diff --git a/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_thread_db.c b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_thread_db.c new file mode 100644 index 00000000..f26e5ef0 --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_thread_db.c @@ -0,0 +1,528 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_thread_db.c $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2016,2017 */ +/* [+] 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 */ +#include "pk.h" +#include "ppe42_scom.h" + +#include "cme_firmware_registers.h" +#include "cme_register_addresses.h" +#include "cppm_firmware_registers.h" +#include "cppm_register_addresses.h" +#include "ppm_firmware_registers.h" +#include "ppm_register_addresses.h" +#include "qppm_firmware_registers.h" +#include "qppm_register_addresses.h" + +#include "ppehw_common.h" +#include "cmehw_common.h" +#include "cmehw_interrupts.h" + +#include "p9_cme_irq.h" +#include "p9_cme_flags.h" +#include "p9_cme_pstate.h" +#include "p9_cme_header.h" +#include "pstate_pgpe_cme_api.h" +#include "p9_pstate_vpd.h" +#include "ppe42_cache.h" + + +// +//Globals +// +extern CmePstateRecord G_cme_pstate_record; +cme_pstate_db_data_t G_db_thread_data; + +//\todo Use PState Parameter Block structures. RTC +extern global_pstate_table_t G_gpst; +extern freq_2_idx_entry_t G_freq2idx[NUM_FREQ_REGIONS]; +extern uint16_t G_cgm_table[CGM_TRANSITIONS]; +extern uint8_t G_resclkEnabled; +extern cme_header_t* G_cme_header; + +// +//Function Prototypes +// +inline void p9_cme_pstate_process_db0(); +inline void p9_cme_pstate_db0_start(cppm_cmedb0_t dbData, uint32_t cme_flags); +inline void p9_cme_pstate_db0_glb_bcast(cppm_cmedb0_t dbData, uint32_t cme_flags); +inline void p9_cme_pstate_db0_suspend(cppm_cmedb0_t dbData, uint32_t cme_flags); +inline void p9_cme_pstate_freq_update(uint64_t dbData); +inline void p9_cme_pstate_resclk_update(); + +// +//Doorbell0 interrupt handler +// +//Only enabled on QuadManager-CME +void p9_cme_pstate_db_handler(void* arg, PkIrqId irq) +{ + pk_semaphore_post((PkSemaphore*)arg); +} + +// +//p9_cme_db_thread +// +void p9_cme_pstate_db_thread(void* arg) +{ + PK_TRACE("DB_TH: Started\n"); + uint32_t cme_flags; + PkMachineContext ctx; + uint32_t pir; + + //\todo Read the data from HOMER code. RTC + p9_pstate_vpd_init(); + + //Read CME_LCL_FLAGS + cme_flags = in32(CME_LCL_FLAGS); + + //Determine quad number and exID for this CME + asm volatile ("mfpir %[data] \n" : [data]"=r"(pir) ); + + //We found a bug in HW late, so this is a workaround. However, in SIMICS the model + //is as per original spec. +#if !SIMICS_TUNING + G_cme_pstate_record.quadNum = (pir & PIR_INSTANCE_NUM_MASK); +#else + G_cme_pstate_record.quadNum = QUAD_FROM_CME_INSTANCE_NUM((pir & PIR_INSTANCE_NUM_MASK)); +#endif + + if (cme_flags & CME_FLAGS_QMGR_MASTER) + { + G_db_thread_data.qmFlag = 1; + + if (cme_flags & CME_FLAGS_SIBLING_FUNCTIONAL) + { + G_db_thread_data.siblingCMEFlag = 1; + } + else + { + G_db_thread_data.siblingCMEFlag = 0; + } + } + else + { + G_db_thread_data.qmFlag = 0; + G_db_thread_data.siblingCMEFlag = 0; + } + + //if quadManager + if (G_db_thread_data.qmFlag) + { + if (cme_flags & CME_FLAGS_CORE0_GOOD) + { + out32_sh(CME_LCL_EIMR_CLR, BIT32(4));//Enable DB0_0 + out32_sh(CME_LCL_EIMR_OR, BIT32(5));//Disable DB0_1 + g_eimr_override |= BIT64(37); + G_db_thread_data.cmeMaskGoodCore = CME_MASK_C0; + } + else if (cme_flags & CME_FLAGS_CORE1_GOOD) + { + out32_sh(CME_LCL_EIMR_OR, BIT32(4));//Disable DB0_0 + out32_sh(CME_LCL_EIMR_CLR, BIT32(5));//Enable DB0_1 + g_eimr_override |= BIT64(36); + G_db_thread_data.cmeMaskGoodCore = CME_MASK_C1; + } + + out64(CME_LCL_EIMR_OR, BIT64(7));//Disable InterCME_IN0 + g_eimr_override |= BIT64(7); + + G_db_thread_data.dpll_pstate0_value = G_gpst.pstate0_frequency_khz / G_gpst.frequency_step_khz; + } + else + { + out64(CME_LCL_EIMR_OR, BIT64(36) | BIT64(37));//Disable DB0_0 and DB0_1 + out64(CME_LCL_EIMR_CLR, BIT64(7)); //Enable InterCME_IN0 + g_eimr_override |= BIT64(37); + g_eimr_override |= BIT64(36); + } + + //Only Quad Manager CME executes this. The sibling CME + //has intercme_in0 enabled + if (G_db_thread_data.qmFlag) + { + pk_semaphore_create(&G_cme_pstate_record.sem[1], 0, 1); + + PK_TRACE("DB_TH: Inited\n"); + + while(1) + { + //pend on sempahore + pk_semaphore_pend(&G_cme_pstate_record.sem[1], PK_WAIT_FOREVER); + wrteei(1); + + p9_cme_pstate_process_db0(); + + pk_irq_vec_restore(&ctx); + } + } + + PK_TRACE("DB_TH: Exit\n"); +} + +// +//Process Doorbell0 +// +inline void p9_cme_pstate_process_db0() +{ + cppm_cmedb0_t dbData; + uint32_t cme_flags = in32(CME_LCL_FLAGS); + + PK_TRACE("DB_TH: Process DB0 Enter\n"); + + //Read DB0 value + if (cme_flags & CME_FLAGS_CORE0_GOOD) + { + out32_sh(CME_LCL_EISR_CLR, BIT32(4)); + out32_sh(CME_LCL_EISR_CLR, BIT32(5)); + CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C0, CME_SCOM_EQ, dbData.value); + } + else if (cme_flags & CME_FLAGS_CORE1_GOOD) + { + out32_sh(CME_LCL_EISR_CLR, BIT32(5)); + CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C1, CME_SCOM_EQ, dbData.value); + } + + PK_TRACE("DB_TH: DB0 0x%x\n"dbData.value); + + if(dbData.fields.cme_message_number0 == MSGID_DB0_START_PSTATE_BROADCAST) + { + p9_cme_pstate_db0_start(dbData, cme_flags); + } + else if(dbData.fields.cme_message_number0 == MSGID_DB0_GLOBAL_ACTUAL_BROADCAST) + { + p9_cme_pstate_db0_glb_bcast(dbData, cme_flags); + } + else if(dbData.fields.cme_message_number0 == MSGID_DB0_STOP_PSTATE_BROADCAST) + { + p9_cme_pstate_db0_suspend(dbData, cme_flags); + } + else + { + pk_halt(); + } + + PK_TRACE("DB_TH: Process DB0 Exit\n"); +} + +// +//Doorbell0 Start +// +inline void p9_cme_pstate_db0_start(cppm_cmedb0_t dbData, uint32_t cme_flags) +{ + PK_TRACE("DB_TH: DB0 Start Enter\n"); + uint32_t intercme_acked; + uint64_t eisr, pmsrData; + uint8_t localPS; + ppm_pig_t ppmPigData; + + if (G_cme_pstate_record.pstatesEnabled == 1) + { + //Send type4(ack doorbell) + ppmPigData.value = 0; + ppmPigData.fields.req_intr_type = 4; + ppmPigData.fields.req_intr_payload = MSGID_PCB_TYPE4_ACK_ERROR; + send_pig_packet(ppmPigData.value, G_db_thread_data.cmeMaskGoodCore); + PK_TRACE("DB_TH: DB0 Start while already started\n"); + pk_halt(); + } + + //\TODO RTC: 152965 + //Check operable bits + //Check if resonant clkss are either all 0s or "OFF" encode(from the Parm) + //Check for iVRM disable + //Check for VDM disable + + //Pstate Update +#if !SIMICS_TUNING + p9_cme_pstate_freq_update(dbData.value); +#endif + + //Notify sibling CME(if any) + if (G_db_thread_data.siblingCMEFlag == 1) + { + //Send interCME interrupt + out32(CME_LCL_ICCR_OR, BIT32(5)); //Send direct InterCME_IN0 + out32(CME_LCL_ICCR_CLR, BIT32(5));//Clear + +#if !SIMICS_TUNING + //poll on interCME interrupt + intercme_acked = 0; +#else + intercme_acked = 1; +#endif + + while (!intercme_acked) + { + eisr = in64(CME_LCL_EISR); + + if (eisr & 0x0100000000000000) + { + intercme_acked = 1; + } + } + + out32(CME_LCL_EISR_CLR, BIT32(7));//Clear InterCME_IN0 + } + + //Update PMSR + localPS = (dbData.value >> + ((MAX_QUADS - G_cme_pstate_record.quadNum - 1) * 8)) & 0xFF; + pmsrData = (dbData.value << 8) & 0xFF00000000000000; + pmsrData |= ((uint64_t)localPS << 48) & 0x00FF000000000000; + + if (cme_flags & CME_FLAGS_CORE0_GOOD) + { + out64(CME_LCL_PMSRS0, pmsrData); + } + + if (cme_flags & CME_FLAGS_CORE1_GOOD) + { + out64(CME_LCL_PMSRS1, pmsrData); + } + + //\TODO RTC: 152965 + //Enable Resonant Clks if flag + //Enable ivrm if flag + //Enable vdm if flag + + G_cme_pstate_record.pstatesEnabled = 1; + + //Send type4(ack doorbell) + ppmPigData.value = 0; + ppmPigData.fields.req_intr_type = 4; + ppmPigData.fields.req_intr_payload = MSGID_PCB_TYPE4_ACK_PSTATE_PROTO_ACK; + send_pig_packet(ppmPigData.value, G_db_thread_data.cmeMaskGoodCore); + + //Clear Pending PMCR interrupts and Enable PMCR Interrupts + if (cme_flags & CME_FLAGS_CORE0_GOOD) + { + out32_sh(CME_LCL_EISR_CLR, BIT32(2)); + out64(CME_LCL_EIMR_CLR, BIT64(34));//Enable PMCR0 + } + + if (cme_flags & CME_FLAGS_CORE1_GOOD) + { + out32_sh(CME_LCL_EISR_CLR, BIT32(3)); + out64(CME_LCL_EIMR_CLR, BIT64(35));//Enable PMCR1 + } + + PK_TRACE("DB_TH: DB0 Start Exit\n"); +} + +// +//Doorbell0 Global Broadcast +// +inline void p9_cme_pstate_db0_glb_bcast(cppm_cmedb0_t dbData, uint32_t cme_flags) +{ + PK_TRACE("DB_TH: DB0 GlbBcast Enter\n"); + uint32_t intercme_acked; + uint64_t eisr, pmsrData; + uint8_t localPS; + ppm_pig_t ppmPigData; + + if (G_cme_pstate_record.pstatesEnabled == 0) + { + //Send type4(ack doorbell) + ppmPigData.value = 0; + ppmPigData.fields.req_intr_type = 4; + ppmPigData.fields.req_intr_payload = MSGID_PCB_TYPE4_ACK_ERROR; + send_pig_packet(ppmPigData.value, G_db_thread_data.cmeMaskGoodCore); + PK_TRACE("DB_TH: DB0Bcast while PS disabled\n"); + pk_halt(); + } + + //Update analog + if (G_resclkEnabled) + { + p9_cme_pstate_resclk_update(); + } + +#if !SIMICS_TUNING + p9_cme_pstate_freq_update(dbData.value); +#endif + + //Notify sibling CME(if any) + if (G_db_thread_data.siblingCMEFlag == 1) + { + //Send interCME interrupt + out32(CME_LCL_ICCR_OR, BIT32(5)); //Send direct InterCME_IN0 + out32(CME_LCL_ICCR_CLR, BIT32(5));//Clear + +#if !SIMICS_TUNING + //poll on interCME interrupt + intercme_acked = 0; +#else + intercme_acked = 1; +#endif + + while (!intercme_acked) + { + eisr = in64(CME_LCL_EISR); + + if (eisr & 0x0100000000000000) + { + intercme_acked = 1; + } + } + + out32(CME_LCL_EISR_CLR, BIT32(7));//Clear InterCME_IN0 + } + + //Update PMSR + localPS = (dbData.value >> + ((MAX_QUADS - G_cme_pstate_record.quadNum - 1) * 8)) & 0xFF; + pmsrData = (dbData.value << 8) & 0xFF00000000000000; + pmsrData |= ((uint64_t)localPS << 48) & 0x00FF000000000000; + + if (cme_flags & CME_FLAGS_CORE0_GOOD) + { + out64(CME_LCL_PMSRS0, pmsrData); + } + + if (cme_flags & CME_FLAGS_CORE1_GOOD) + { + out64(CME_LCL_PMSRS1, pmsrData); + } + + //Send type4(ack doorbell) + ppmPigData.value = 0; + ppmPigData.fields.req_intr_type = 4; + ppmPigData.fields.req_intr_payload = MSGID_PCB_TYPE4_ACK_PSTATE_PROTO_ACK; + send_pig_packet(ppmPigData.value, G_db_thread_data.cmeMaskGoodCore); + PK_TRACE("DB_TH: DB0 GlbBcast Exit\n"); +} + +// +//Doorbell0 Suspend +// +inline void p9_cme_pstate_db0_suspend(cppm_cmedb0_t dbData, uint32_t cme_flags) +{ + PK_TRACE("DB_TH: DB0 Suspend Enter\n"); + ppm_pig_t ppmPigData; + + if (G_cme_pstate_record.pstatesEnabled == 0) + { + //Send type4(ack doorbell) + ppmPigData.value = 0; + ppmPigData.fields.req_intr_type = 4; + ppmPigData.fields.req_intr_payload = MSGID_PCB_TYPE4_ACK_ERROR; + send_pig_packet(ppmPigData.value, G_db_thread_data.cmeMaskGoodCore); + pk_halt(); + } + + G_cme_pstate_record.pstatesEnabled = 0; + + if (cme_flags & CME_FLAGS_CORE0_GOOD) + { + out64(CME_LCL_EIMR_OR, BIT64(34));//Disable PMCR0 + } + + if (cme_flags & CME_FLAGS_CORE1_GOOD) + { + out64(CME_LCL_EIMR_OR, BIT64(35));//Disable PMCR1 + } + + //\TODO RTC: 152965 + //Disable iVRM, move into bypass + //Disable resonant clocking, move to non-resonant value + + //Send type4(ack doorbell) + ppmPigData.value = 0; + ppmPigData.fields.req_intr_type = 4; + ppmPigData.fields.req_intr_payload = MSGID_PCB_TYPE4_ACK_PSTATE_SUSPENDED; + send_pig_packet(ppmPigData.value, G_db_thread_data.cmeMaskGoodCore); + PK_TRACE("DB_TH: DB0 Suspend Exit\n"); +} + +// +//p9_cme_pstate_freq_update +// +inline void p9_cme_pstate_freq_update(uint64_t dbData) +{ + uint8_t localPS = (dbData >> + ((MAX_QUADS - G_cme_pstate_record.quadNum - 1) * 8)) & 0xFF; + + //Adjust DPLL + cppm_ippmcmd_t cppm_ippmcmd; + qppm_dpll_freq_t dpllFreq; + + //Write new value of DPLL using INTERPPM + dpllFreq.value = 0; + dpllFreq.fields.fmax = (uint16_t)(G_db_thread_data.dpll_pstate0_value - localPS) << 3; + dpllFreq.fields.fmult = (uint16_t)(G_db_thread_data.dpll_pstate0_value - localPS) << 3; + dpllFreq.fields.fmin = (uint16_t)(G_db_thread_data.dpll_pstate0_value - localPS) << 3; + CME_PUTSCOM(CPPM_IPPMWDATA, G_db_thread_data.cmeMaskGoodCore, dpllFreq.value); + cppm_ippmcmd.value = 0; + cppm_ippmcmd.fields.qppm_reg = QPPM_DPLL_FREQ & 0x000000ff; + cppm_ippmcmd.fields.qppm_rnw = 0; + CME_PUTSCOM(CPPM_IPPMCMD, G_db_thread_data.cmeMaskGoodCore, cppm_ippmcmd.value); +} + +// +//p9_cme_pstate_resclk_update +// +inline void p9_cme_pstate_resclk_update() +{ + uint64_t val; + uint8_t tidx, step; + int32_t i; + + //get targetIndex from Table1(ControlIndex) by indexing with localPState + tidx = G_db_thread_data.resClkTblIdx; + + for (i = NUM_FREQ_REGIONS - 1; i >= 0; i--) + { + if (G_freq2idx[i].pstate > G_db_thread_data.localPS) + { + tidx = i; + break; + } + } + + //walk Table2[Resonant Grids Control Data) + if (tidx > G_db_thread_data.resClkTblIdx) + { + step = 1; + } + else + { + step = -1; + } + + while(G_db_thread_data.resClkTblIdx != tidx) + { + G_db_thread_data.resClkTblIdx += step; + val = (uint64_t)(G_cgm_table[G_db_thread_data.resClkTblIdx]) << 48; + val |= G_db_thread_data.qaccr21_23InitVal; + +#if !SIMICS_TUNING + cppm_ippmcmd_t cppm_ippmcmd; + //Write val to QACCR + CME_PUTSCOM(CPPM_IPPMWDATA, G_db_thread_data.cmeMaskGoodCore, val); + cppm_ippmcmd.value = 0; + cppm_ippmcmd.fields.qppm_reg = QPPM_QACCR & 0x000000ff; + cppm_ippmcmd.fields.qppm_rnw = 0; + CME_PUTSCOM(CPPM_IPPMCMD, G_db_thread_data.cmeMaskGoodCore, cppm_ippmcmd.value); +#endif + } +} diff --git a/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_thread_pmcr.c b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_thread_pmcr.c new file mode 100644 index 00000000..eeec7fad --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_thread_pmcr.c @@ -0,0 +1,131 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_thread_pmcr.c $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2016,2017 */ +/* [+] 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 */ +#include "pk.h" +#include "ppe42_scom.h" + +#include "cme_firmware_registers.h" +#include "cme_register_addresses.h" +#include "cppm_firmware_registers.h" +#include "cppm_register_addresses.h" +#include "ppm_firmware_registers.h" +#include "ppm_register_addresses.h" +#include "qppm_firmware_registers.h" +#include "qppm_register_addresses.h" + +#include "ppehw_common.h" +#include "cmehw_common.h" +#include "cmehw_interrupts.h" + +#include "p9_cme_irq.h" +#include "p9_cme_flags.h" +#include "p9_cme_pstate.h" +#include "p9_cme_header.h" +#include "pstate_pgpe_cme_api.h" +#include "p9_pstate_vpd.h" +#include "ppe42_cache.h" + +// +//Globals +// +cme_pstate_pmcr_data_t G_pmcr_thread_data; +extern CmePstateRecord G_cme_pstate_record; + +// +//PMCR Interrupt Handler +// +void p9_cme_pstate_pmcr_handler(void* arg, PkIrqId irq) +{ + pk_semaphore_post((PkSemaphore*)arg); +} + +// +//p9_cme_pmcr_thread +// +void p9_cme_pstate_pmcr_thread(void* arg) +{ + PK_TRACE("PMCR_TH: Enter\n"); + int32_t c; + PkMachineContext ctx; + cme_scom_pmcrs0_t pmcr[2]; + ppm_pig_t ppmPigData; + uint32_t eisr; + uint32_t coreMask[CORES_PER_EX]; + uint32_t cme_flags; + coreMask[0] = CME_MASK_C0; + coreMask[1] = CME_MASK_C1; + + G_pmcr_thread_data.seqNum = 0; + + cme_flags = in32(CME_LCL_FLAGS); + + pk_semaphore_create(&G_cme_pstate_record.sem[0], 0, 1); + + PK_TRACE("PMCR_TH: Inited\n"); + + while(1) + { + //pend on sempahore + pk_semaphore_pend(&G_cme_pstate_record.sem[0], PK_WAIT_FOREVER); + wrteei(1); + + //Determine which core have pending request + for(c = 0; c < CORES_PER_EX; c++) + { + if (cme_flags & (CME_FLAGS_CORE0_GOOD >> c)) + { + eisr = in32_sh(CME_LCL_EISR); //EISR + + if (eisr & (BIT32(2) >> c)) + { + //Clear interrupt and read PMCR + out32_sh(CME_LCL_EISR_CLR, BIT32(2) >> c); + pmcr[c].value = in64(CME_LCL_PMCRS0 + (c << 5)); + + //Send Phase 1 + ppmPigData.value = 0; + ppmPigData.fields.req_intr_type = 0; + ppmPigData.value |= (((pmcr[c].value & PIG_PAYLOAD_PS_PHASE1_MASK))); + + ppmPigData.value |= ((G_pmcr_thread_data.seqNum & 0x6) << 57); + send_pig_packet(ppmPigData.value, coreMask[c]); + G_pmcr_thread_data.seqNum++; + + //Send Phase 2 + ppmPigData.value = 0; + ppmPigData.fields.req_intr_type = 1; + ppmPigData.value |= ((pmcr[c].value & PIG_PAYLOAD_PS_PHASE2_MASK) << 16); + ppmPigData.value |= ((G_pmcr_thread_data.seqNum & 0x6) << 57); + send_pig_packet(ppmPigData.value, coreMask[c]); + G_pmcr_thread_data.seqNum++; + PK_TRACE("PMCR_TH: Fwd PMCR %d\n", c); + } + } + } + + pk_irq_vec_restore(&ctx); + } + + PK_TRACE("PMCR_TH: Exit\n"); +} diff --git a/import/chips/p9/procedures/ppe_closed/cme/topfiles.mk b/import/chips/p9/procedures/ppe_closed/cme/topfiles.mk index 4a8b5ce6..7bfb7e3d 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/topfiles.mk +++ b/import/chips/p9/procedures/ppe_closed/cme/topfiles.mk @@ -1,4 +1,3 @@ - # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # @@ -25,14 +24,19 @@ # IBM_PROLOG_END_TAG + TOP-C-SOURCES = p9_cme_main.c \ p9_cme_irq.c UTILS-C-SOURCES = utils/p9_putringutils.c \ utils/plat_ring_traverse.c -PSTATE-C-SOURCES = pstate_cme/p9_cme_pstate.c \ - pstate_cme/p9_pstate_vpd.c +PSTATE-C-SOURCES = pstate_cme/p9_cme_pstate.c \ + pstate_cme/p9_cme_thread_db.c \ + pstate_cme/p9_cme_thread_pmcr.c \ + pstate_cme/p9_cme_header.c \ + pstate_cme/p9_cme_intercme.c \ + pstate_cme/p9_pstate_vpd.c STOP-C-SOURCES = stop_cme/p9_cme_stop_irq_handlers.c \ stop_cme/p9_cme_stop_enter_thread.c \ diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe.h b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe.h index 3cfe39eb..078c883e 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe.h +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe.h @@ -51,18 +51,28 @@ #include "qppm_firmware_registers.h" #include "p9_pgpe_irq.h" -#include "p9_pstate_common.h" +#include "pstate_pgpe_cme_api.h" #include "p9_pm_hcd_flags.h" +#include "ipc_api.h" +#include "ipc_async_cmd.h" + +// +//#Defines +// +#define OCC_IPC_IMMEDIATE_RESP 0x0080 /// PGPE PState typedef struct { - PkSemaphore sem[1]; + PkSemaphore sem_process_req; + PkSemaphore sem_actuate; + PkSemaphore sem_sgpe_wait; } PgpePstateRecord; /// PGPE PState -void p9_pgpe_pstate_pig_handler(void* arg, PkIrqId irq); -void p9_pgpe_pstate_thread(void* arg); +void p9_pgpe_irq_handler_pcb_type1(void* arg, PkIrqId irq); +void p9_pgpe_thread_process_requests(void* arg); +void p9_pgpe_thread_actuate_pstates(void* arg); ///PGPE PState Info void p9_pgpe_gen_pstate_info(); diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_boot_temp.c b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_boot_temp.c index 05a971c0..789f5b8b 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_boot_temp.c +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_boot_temp.c @@ -57,6 +57,11 @@ void p9_pgpe_boot_pgpe_header_init() G_pgpe_header_data->magic_number[0] = 0x32323232;//magic G_pgpe_header_data->_system_reset_addr = (uint32_t*)0xffff2040;//system_reset_address G_pgpe_header_data->IVPR_address = (uint32_t*)0xffff2000;//IVPR address +#if !BOOT_TEMP_SET_FULL_OCC_IPC_FUNC + G_pgpe_header_data->pgpeflags = (uint16_t)(0x0080); //OCC IPC Immediate Response +#else + G_pgpe_header_data->pgpeflags = (uint16_t)(0x0000); //OCC IPC Full Functionality +#endif //BOOT_TEMP_SET_FULL_OCC_IPC_FUNC G_pgpe_header_data->gppb_sram_addr = (uint32_t*)0xfff27000;//GPPB Sram Offset G_pgpe_header_data->gppb_memory_offset = 0;//GPPB Memory Offset G_pgpe_header_data->gppb_block_length = 0x2000;//GPPB Block Length @@ -64,7 +69,8 @@ void p9_pgpe_boot_pgpe_header_init() G_pgpe_header_data->pstate_tbl_length = 0x6000;//Pstate Tables Length G_pgpe_header_data->occ_pstate_tbl_addr = (uint32_t*)0xfff29000;//OCC Pstate table address G_pgpe_header_data->occ_pstate_tbl_length = 0x100;//OCC Pstate table length - G_pgpe_header_data->pgpe_beacon = (uint32_t*)0xfff26ff0; + G_pgpe_header_data->pgpe_beacon = (uint32_t*)(0xfff26fe0 + 4); + G_pgpe_header_data->actual_quad_status_addr = (uint32_t*)(0xfff26fe0 + 8); } // @@ -84,7 +90,11 @@ void p9_pgpe_boot_gppb_init() gppb->options.options = 0; gppb->reference_frequency_khz = 4150000; gppb->frequency_step_khz = 16667; - gppb->ext_vdd_step_size_mv = 50; + gppb->ext_vrm_transition_start_ns = 50; + gppb->ext_vrm_transition_rate_inc_uv_per_us = 10000; + gppb->ext_vrm_transition_rate_dec_uv_per_us = 10000; + gppb->ext_vrm_stabilization_time_us = 500; + gppb->ext_vrm_step_size_mv = 50; gppb->nest_frequency_mhz = 2000; gppb->operating_points[ULTRA].frequency_mhz = 4150; 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 9e7d49cf..0242fd42 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 @@ -30,6 +30,9 @@ GlobalPstateParmBlock* G_gppb; //Global array to store calculated slopes VpdOperatingPoint G_operating_points[NUM_VPD_PTS_SET][VPD_PV_POINTS]; +uint8_t G_pstate0_dpll_value; +uint32_t G_ext_vrm_inc_rate_mult_usperus; +uint32_t G_ext_vrm_dec_rate_mult_usperus; extern pgpe_header_data_t* G_pgpe_header_data; // @@ -57,6 +60,16 @@ void p9_pgpe_gppb_init() //Calculate slope co-efficents. p9_pgpe_gppb_compute_PsV_slopes(); + + //Dpll value corresponding to Pstate 0 + G_pstate0_dpll_value = ((G_gppb->reference_frequency_khz + (G_gppb->frequency_step_khz - 1)) / + G_gppb->frequency_step_khz); + + //External VRM increasing rate in us/uv + G_ext_vrm_inc_rate_mult_usperus = 1 / G_gppb->ext_vrm_transition_rate_inc_uv_per_us; + + //External VRM decreasing rate in us/uv + G_ext_vrm_dec_rate_mult_usperus = 1 / G_gppb->ext_vrm_transition_rate_dec_uv_per_us; } // 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 9e701157..ae603670 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 @@ -33,6 +33,7 @@ //#define REGION_TURBO_ULTRA 2 #define EVID_SLOPE_FP_SHIFT 13 +#define MAX_DPLL_VALUE 255 #define NUM_VPD_PTS_SET 4 #define VPD_PT_SET_RAW 0 diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_header.c b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_header.c index 2d073e6a..c819b021 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_header.c +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_header.c @@ -29,7 +29,8 @@ pgpe_header_data_t* G_pgpe_header_data; // //Set the pgpe_header_data struct to point to PGPE HEADER in SRAM // -//\todo: RTC 164339 Get this address passed from linker script. +//\TODO: RTC 164339 +//Get this address passed from linker script. // void p9_pgpe_header_init() { diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_header.h b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_header.h index 030f0e2e..1c91be93 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_header.h +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_header.h @@ -41,7 +41,7 @@ typedef struct pgpe_header_data uint32_t shared_sram_length; uint32_t build_date; uint32_t version; - uint16_t qmflags; + uint16_t pgpeflags; uint16_t reserved0[3]; uint32_t* gppb_sram_addr; uint32_t reserved1; diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_ipc_handlers.c b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_ipc_handlers.c new file mode 100644 index 00000000..c025196e --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_ipc_handlers.c @@ -0,0 +1,413 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_ipc_handlers.c $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2016,2017 */ +/* [+] 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 */ +#include "pk.h" +#include "p9_pgpe.h" +#include "ppe42_cache.h" +#include "ipc_api.h" +#include "ipc_async_cmd.h" +#include "p9_pgpe_header.h" +#include "pstate_pgpe_occ_api.h" +//#include "pstate_pgpe_sgpe_api.h" +#include "ipc_messages.h" +#include "occhw_shared_data.h" +#include "p9_pgpe_ipc_handlers.h" +#include "p9_pgpe_pstate.h" +#include "qppm_firmware_registers.h" +#include "qppm_register_addresses.h" + +// +//#Defines +// + +// +//External Global Data +// +extern ipc_req_t G_ipc_pend_tbl[MAX_IPC_PEND_TBL_ENTRIES]; +extern uint8_t G_pstatesEnabled; +extern PgpePstateRecord G_pgpe_pstate_record; +extern uint32_t G_already_sem_posted; +extern uint8_t G_pmcrOwner; +extern pgpe_header_data_t* G_pgpe_header_data; + +// +//p9_pgpe_ipc_init +// +//Called during PGPE initialziation to enable IPC functions +//and init task list +// +void p9_pgpe_ipc_init() +{ + uint32_t i; + + ipc_init(); + ipc_enable(); + + for (i = 0; i < MAX_IPC_PEND_TBL_ENTRIES; i++) + { + G_ipc_pend_tbl[i].cmd = NULL; + G_ipc_pend_tbl[i].pending_ack = 0; + G_ipc_pend_tbl[i].pending_processing = 0; + } + + G_already_sem_posted = 0; +} + +// +//p9_pgpe_ipc_405_start_stop +// +//IPC function called upon receiving 'Pstate Start/Stop' IPC from OCC +// +void p9_pgpe_ipc_405_start_stop(ipc_msg_t* cmd, void* arg) +{ + PK_TRACE_DBG("START_STOP: Entry\n"); + + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)cmd; + ipcmsg_start_stop_t* args = (ipcmsg_start_stop_t*)async_cmd->cmd_data; + + if(G_pgpe_header_data->pgpeflags & OCC_IPC_IMMEDIATE_RESP) + { + args->msg_cb.rc = PGPE_RC_SUCCESS; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + G_ipc_pend_tbl[IPC_PEND_PSTATE_START].pending_ack = 0; + G_ipc_pend_tbl[IPC_PEND_PSTATE_START].pending_processing = 0; + + //Yes, here we post to process thread when START/STOP is rcv. + //This is done to ensure that pk_irq_vec_restore is called correctly + //We can call it here, but other IPCs could be processed in this invocation + //of IPC interrupt handler and pk_irq_vec_restore can get called twice. + //Much cleaner to call it always from process thread. + if (G_already_sem_posted == 0) + { + pk_semaphore_post(&G_pgpe_pstate_record.sem_process_req); + G_already_sem_posted = 1; + } + } + else + { + //START + if (args->action == PGPE_ACTION_PSTATE_START) + { + if (G_ipc_pend_tbl[IPC_PEND_PSTATE_START].pending_ack == 0) + { + if(G_pstatesEnabled == 0) + { + PK_TRACE_DBG("START_STOP: Start Rcvd\n"); + + //Add task + G_ipc_pend_tbl[IPC_PEND_PSTATE_START].cmd = cmd; + G_ipc_pend_tbl[IPC_PEND_PSTATE_START].pending_ack = 1; + G_ipc_pend_tbl[IPC_PEND_PSTATE_START].pending_processing = 0; + + //Post to Actuate Thread + pk_semaphore_post(&G_pgpe_pstate_record.sem_actuate); + } + else + { + PK_TRACE_DBG("START_STOP: Pstate Already Started\n"); + args->msg_cb.rc = PGPE_RC_REQ_PSTATE_ALREADY_STARTED; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + } + } + else + { + PK_TRACE_DBG("START_STOP: Duplicate\n"); + args->msg_cb.rc = PGPE_RC_REQ_WHILE_PENDING_ACK; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + } + } + //STOP + else if(args->action == PGPE_ACTION_PSTATE_STOP) + { + PK_TRACE_DBG("START_STOP: Stop Rcvd\n"); + + if (G_ipc_pend_tbl[IPC_PEND_PSTATE_STOP].pending_ack == 0) + { + if(G_pstatesEnabled == 1) + { + G_pstatesEnabled = 0; + G_ipc_pend_tbl[IPC_PEND_PSTATE_STOP].cmd = cmd; + G_ipc_pend_tbl[IPC_PEND_PSTATE_STOP].pending_ack = 1; + G_ipc_pend_tbl[IPC_PEND_PSTATE_STOP].pending_processing = 0; + } + else + { + PK_TRACE_DBG("START_STOP: Pstate Already Stopped\n"); + args->msg_cb.rc = PGPE_RC_REQ_PSTATE_ALREADY_SUSPENDED; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + } + } + else + { + PK_TRACE_DBG("START_STOP: Duplicate\n"); + args->msg_cb.rc = PGPE_RC_REQ_WHILE_PENDING_ACK; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + } + } + } + + PK_TRACE_DBG("START_STOP: Exit\n"); +} + +// +//p9_pgpe_ipc_405_clips +// +//IPC function called upon receiving 'Clip Update' IPC from OCC +// +void p9_pgpe_ipc_405_clips(ipc_msg_t* cmd, void* arg) +{ + PK_TRACE_DBG("405_CLIPS: Entry\n"); + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)cmd; + ipcmsg_set_pmcr_t* args = (ipcmsg_set_pmcr_t*)async_cmd->cmd_data; + + if (G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].pending_ack == 0) + { + G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].cmd = cmd; + G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].pending_processing = 1; + G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].pending_ack = 1; + } + else + { + args->msg_cb.rc = PGPE_RC_REQ_WHILE_PENDING_ACK; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + } + + if (G_already_sem_posted == 0) + { + pk_semaphore_post(&G_pgpe_pstate_record.sem_process_req); + G_already_sem_posted = 1; + } + + PK_TRACE_DBG("405_CLIPS: Exit\n"); +} + +// +//p9_pgpe_ipc_405_set_pmcr +// +//IPC function called upon receiving 'Set PMCR' IPC from OCC +// +void p9_pgpe_ipc_405_set_pmcr(ipc_msg_t* cmd, void* arg) +{ + PK_TRACE_DBG("405_SET_PMCR: Entry\n"); + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)cmd; + ipcmsg_set_pmcr_t* args = (ipcmsg_set_pmcr_t*)async_cmd->cmd_data; + + if (G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].pending_ack == 0) + { + if(G_pmcrOwner != PMCR_OWNER_OCC) + { + args->msg_cb.rc = PGPE_RC_OCC_NOT_PMCR_OWNER; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + } + else + { + G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].cmd = cmd; + G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].pending_processing = 1; + G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].pending_ack = 1; + } + } + else + { + PK_TRACE_DBG("405_SET_PMCR: Duplicate\n"); + args->msg_cb.rc = PGPE_RC_REQ_WHILE_PENDING_ACK; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + } + + if (G_already_sem_posted == 0) + { + pk_semaphore_post(&G_pgpe_pstate_record.sem_process_req); + G_already_sem_posted = 1; + } + + PK_TRACE_DBG("405_SET_PMCR: Exit\n"); +} + +// +//p9_pgpe_ipc_405_wof_control +// +//IPC function called upon receiving 'WOF Control' IPC from OCC +// +void p9_pgpe_ipc_405_wof_control(ipc_msg_t* cmd, void* arg) +{ + PK_TRACE_DBG("405_WOF_CTRL: Entry\n"); + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)cmd; + ipcmsg_wof_control_t* args = (ipcmsg_wof_control_t*)async_cmd->cmd_data; + + if (G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].pending_ack == 0) + { + G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].cmd = cmd; + G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].pending_processing = 1; + G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].pending_ack = 1; + } + else + { + args->msg_cb.rc = PGPE_RC_REQ_WHILE_PENDING_ACK; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + } + + if (G_already_sem_posted == 0) + { + pk_semaphore_post(&G_pgpe_pstate_record.sem_process_req); + G_already_sem_posted = 1; + } + + PK_TRACE_DBG("405_WOF_CTRL: Exit\n"); +} + +// +//p9_pgpe_ipc_405_wof_vfrt +// +//IPC function called upon receiving 'WOF VFRT' IPC from OCC +// +void p9_pgpe_ipc_405_wof_vfrt(ipc_msg_t* cmd, void* arg) +{ + PK_TRACE_DBG("405_WOF_VFRT: Entry\n"); + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)cmd; + ipcmsg_wof_vfrt_t* args = (ipcmsg_wof_vfrt_t*)async_cmd->cmd_data; + + if (G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].pending_ack == 0) + { + G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].cmd = cmd; + G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].pending_processing = 1; + G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].pending_ack = 1; + } + else + { + args->msg_cb.rc = PGPE_RC_REQ_WHILE_PENDING_ACK; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + } + + if (G_already_sem_posted == 0) + { + pk_semaphore_post(&G_pgpe_pstate_record.sem_process_req); + G_already_sem_posted = 1; + } + + PK_TRACE_DBG("405_WOF_VFRT: Exit\n"); +} + +// +//p9_pgpe_ipc_sgpe_suspend_pstates +// +//IPC function called upon receiving 'Suspend PStates' IPC from SGPE +// +void p9_pgpe_ipc_sgpe_suspend_pstates(ipc_msg_t* cmd, void* arg) +{ + PK_TRACE_DBG("SGPE_SUSPEND_PSTATES: Entry\n"); + + if (G_ipc_pend_tbl[IPC_PEND_SGPE_SUSPEND_PSTATES].pending_ack == 0 && + G_ipc_pend_tbl[IPC_PEND_SGPE_SUSPEND_PSTATES].pending_processing == 0) + { + G_ipc_pend_tbl[IPC_PEND_SGPE_SUSPEND_PSTATES].cmd = cmd; + G_ipc_pend_tbl[IPC_PEND_SGPE_SUSPEND_PSTATES].pending_processing = 1; + G_ipc_pend_tbl[IPC_PEND_SGPE_SUSPEND_PSTATES].pending_ack = 1; + } + else + { + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)cmd; + ipcmsg_s2p_suspend_pstate_t* args = + (ipcmsg_s2p_suspend_pstate_t*)async_cmd->cmd_data; + args->fields.return_code = SGPE_PGPE_RC_REQ_WHILE_PENDING_ACK; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + } + + if (G_already_sem_posted == 0) + { + pk_semaphore_post(&G_pgpe_pstate_record.sem_process_req); + G_already_sem_posted = 1; + } + + PK_TRACE_DBG("SGPE_SUSPEND_PSTATES: Exit\n"); +} + +// +//p9_pgpe_ipc_sgpe_updt_active_cores +// +//IPC function called upon receiving 'Update Active Cores' IPC from SGPE +// +void p9_pgpe_ipc_sgpe_updt_active_cores(ipc_msg_t* cmd, void* arg) +{ + PK_TRACE_DBG("SGPE_UPDT_CORES: Entry\n"); + + if (G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].pending_ack == 0 && + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].pending_processing == 0) + { + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].cmd = cmd; + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].pending_processing = 1; + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].pending_ack = 1; + } + else + { + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)cmd; + ipcmsg_s2p_update_active_cores_t* args = + (ipcmsg_s2p_update_active_cores_t*)async_cmd->cmd_data; + args->fields.return_code = SGPE_PGPE_RC_REQ_WHILE_PENDING_ACK; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + } + + if (G_already_sem_posted == 0) + { + pk_semaphore_post(&G_pgpe_pstate_record.sem_process_req); + G_already_sem_posted = 1; + } + + PK_TRACE_DBG("SGPE_UPDT_CORES: Exit\n"); +} + +// +//p9_pgpe_ipc_sgpe_updt_active_quads +// +//IPC function called upon receiving 'Update Active Quads' IPC from SGPE +// +void p9_pgpe_ipc_sgpe_updt_active_quads(ipc_msg_t* cmd, void* arg) +{ + PK_TRACE_DBG("SGPE_UPDT_QUADS: Entry\n"); + + if (G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].pending_ack == 0 && + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].pending_processing == 0 && + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].pending_ack == 0 && + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].pending_processing == 0) + { + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].cmd = cmd; + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].pending_processing = 1; + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].pending_ack = 1; + + } + else + { + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)cmd; + ipcmsg_s2p_update_active_quads_t* args = + (ipcmsg_s2p_update_active_quads_t*)async_cmd->cmd_data; + args->fields.return_code = SGPE_PGPE_RC_REQ_WHILE_PENDING_ACK; + ipc_send_rsp(cmd, IPC_RC_SUCCESS); + } + + if (G_already_sem_posted == 0) + { + pk_semaphore_post(&G_pgpe_pstate_record.sem_process_req); + G_already_sem_posted = 1; + } + + PK_TRACE_DBG("SGPE_UPDT_QUADS: Exit\n"); +} diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_ipc_handlers.h b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_ipc_handlers.h new file mode 100644 index 00000000..f336a526 --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_ipc_handlers.h @@ -0,0 +1,51 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_ipc_handlers.h $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2016,2017 */ +/* [+] 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 */ +#ifndef _P9_PGPE_IPC_H_ +#define _P9_PGPE_IPC_H_ + +#include "pk.h" + +// +//PGPE IPC Initialization +// +void p9_pgpe_ipc_init(); + +// +//405 IPCs +// +void p9_pgpe_ipc_405_start_stop(ipc_msg_t* cmd, void* arg); +void p9_pgpe_ipc_405_clips(ipc_msg_t* cmd, void* arg); +void p9_pgpe_ipc_405_set_pmcr(ipc_msg_t* cmd, void* arg); +void p9_pgpe_ipc_405_wof_control(ipc_msg_t* cmd, void* arg); +void p9_pgpe_ipc_405_wof_vfrt(ipc_msg_t* cmd, void* arg); + +// +//SGPE IPCs +// +void p9_pgpe_ipc_sgpe_updt_active_cores(ipc_msg_t* cmd, void* arg); +void p9_pgpe_ipc_sgpe_updt_active_quads(ipc_msg_t* cmd, void* arg); +void p9_pgpe_ipc_sgpe_suspend_pstates(ipc_msg_t* cmd, void* arg); + +#endif //_P9_PGPE_IPC_H_ diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.c b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.c index 6ab938dc..e371d552 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.c +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.c @@ -35,10 +35,6 @@ #include "pk.h" #include "p9_pgpe_irq.h" -//-------------------------------------------------------------------// -// DO NOT modify this file unless you're the owner // -//-------------------------------------------------------------------// - // Notes: // - The following two lists, ext_irq_vectors_gpe[][] and IDX_PRTY_LVL_, // must match. IDX_PRTY_LVL_ is the tasks priority level and serves @@ -48,38 +44,44 @@ const uint64_t ext_irq_vectors_gpe[NUM_EXT_IRQ_PRTY_LEVELS][2] = { { - IRQ_VEC_PRTY0_GPE, IRQ_VEC_PRTY3_GPE2 | /* 0: IDX_PRTY_LVL_HIPRTY */ + IRQ_VEC_PRTY0_GPE, IRQ_VEC_PRTY5_GPE2 | /* 0 */ + IRQ_VEC_PRTY4_GPE2 | + IRQ_VEC_PRTY3_GPE2 | IRQ_VEC_PRTY2_GPE2 | IRQ_VEC_PRTY1_GPE2 | IRQ_VEC_PRTY0_GPE } , { - IRQ_VEC_PRTY1_GPE2, IRQ_VEC_PRTY3_GPE2 | /* 1: IDX_PRTY_LVL_OCBERR */ + IRQ_VEC_PRTY1_GPE2, IRQ_VEC_PRTY5_GPE2 | /* 1 */ + IRQ_VEC_PRTY4_GPE2 | + IRQ_VEC_PRTY3_GPE2 | IRQ_VEC_PRTY2_GPE2 | IRQ_VEC_PRTY1_GPE2 } , { - IRQ_VEC_PRTY2_GPE2, IRQ_VEC_PRTY3_GPE2 | /* 2: IDX_PRTY_LVL_IPI2HI */ + IRQ_VEC_PRTY2_GPE2, IRQ_VEC_PRTY5_GPE2 | /* 2 */ + IRQ_VEC_PRTY4_GPE2 | + IRQ_VEC_PRTY3_GPE2 | IRQ_VEC_PRTY2_GPE2 } , - { IRQ_VEC_PRTY3_GPE2, IRQ_VEC_PRTY3_GPE2 } , /* 3: IDX_PRTY_LVL_TYPE1 */ - - { IRQ_VEC_PRTY4_GPE2, IRQ_VEC_PRTY4_GPE2 } /* 4: IDX_PRTY_LVL_DISABLED */ + { + IRQ_VEC_PRTY3_GPE2, IRQ_VEC_PRTY5_GPE2 | /* 2 */ + IRQ_VEC_PRTY4_GPE2 | + IRQ_VEC_PRTY3_GPE2 + } , - /* 0: IDX_PRTY_VEC 1: IDX_MASK_VEC */ -}; + { + IRQ_VEC_PRTY4_GPE2, IRQ_VEC_PRTY5_GPE2 | /* 2 */ + IRQ_VEC_PRTY4_GPE2 + } , + { IRQ_VEC_PRTY5_GPE2, IRQ_VEC_PRTY5_GPE2 } , /* 3 */ -/*const uint8_t IDX_PRTY_LVL_HIPRTY = 0; -const uint8_t IDX_PRTY_LVL_OCBERR = 1; -const uint8_t IDX_PRTY_LVL_IPI2HI = 2; -const uint8_t IDX_PRTY_LVL_TYPE1 = 3; -const uint8_t IDX_PRTY_LVL_DISABLED = 4; + { IRQ_VEC_PRTY6_GPE2, IRQ_VEC_PRTY6_GPE2 } /* 4 */ -const uint8_t IDX_PRTY_VEC = 0; -const uint8_t IDX_MASK_VEC = 1;*/ +}; uint8_t g_oimr_stack[NUM_EXT_IRQ_PRTY_LEVELS]; int g_oimr_stack_ctr = -1; @@ -87,20 +89,18 @@ uint8_t g_current_prty_level = NUM_EXT_IRQ_PRTY_LEVELS - 1; uint64_t g_oimr_override = 0x0000000000000000; uint64_t g_oimr_override_stack[NUM_EXT_IRQ_PRTY_LEVELS]; + // // Unified IRQ priority and masking handler. -// - Locates the highest priority IRQ task vector that has at least one of its -// interrupts in the current external PK interrupt vector. +// Locates the highest priority IRQ task vector that has at least one of its +// interrupts in the current external PK interrupt vector. // void pk_unified_irq_prty_mask_handler(void) { uint8_t iPrtyLvl, bFound; uint64_t ext_irq_vector_pk; - // // 1. Identify the priority level of the interrupt. - // - ext_irq_vector_pk = ((uint64_t)in32(OCB_G0ISR0 + APPCFG_OCC_INSTANCE_ID * 8)) << 32 | (uint64_t)in32(OCB_G0ISR1 + APPCFG_OCC_INSTANCE_ID * 8); //ext_irq_vector_pk = ((uint64_t)in32(OCB_OISR0))<<32 | @@ -121,58 +121,11 @@ void pk_unified_irq_prty_mask_handler(void) } while (++iPrtyLvl < (NUM_EXT_IRQ_PRTY_LEVELS - 1)); // No need to check DISABLED. - // - // Only manipulate OIMR masks for task level prty levels. Let shared non-task - // IRQs (iPrtyLvl=0) be processed by the PK kernel in usual fashion. - // + // 2. Only manipulate OIMR masks for task level prty levels. Let shared non-task + // IRQs (iPrtyLvl=0) be processed by the PK kernel in usual fashion. if (bFound) { - - // - // 2. Save current mask (assume current prty level). - // - - // Note, reading EIMR is NOT safe because overrides may already have - // happened to the EIMR. And we always want to restore - // the EIMR to a known value when we exit our thread. - // - if (++g_oimr_stack_ctr < NUM_EXT_IRQ_PRTY_LEVELS) - { - //prev: g_oimr_stack[g_oimr_stack_ctr] = ((uint64_t)in32(OCB_OIMR0))<<32 | - // (uint64_t)in32(OCB_OIMR1); - // Make a note of present prty level and then update tracker to new prty level. - g_oimr_stack[g_oimr_stack_ctr] = g_current_prty_level; - g_current_prty_level = iPrtyLvl; // Update prty level tracker. - g_oimr_override_stack[g_oimr_stack_ctr] = g_oimr_override; - } - else - { - MY_TRACE_ERR("Code bug: OIMR S/R stack counter=%d >= max=%d.", - g_oimr_stack_ctr, NUM_EXT_IRQ_PRTY_LEVELS); - pk_halt(); - } - - // - // 3. Write the new mask for this priority level. - // - - // First, clear all those IRQs that could possibly interrupt this instance. - // This includes all those IRQs which belong to this instance as well as - // those high-prty IRQs shared with the other instances. - // - out32(OCB_OIMR0_CLR, (uint32_t)(IRQ_VEC_ALL_OUR_IRQS >> 32)); - out32(OCB_OIMR1_CLR, (uint32_t)IRQ_VEC_ALL_OUR_IRQS); - - // Second, mask IRQs belonging to this task and lower prty tasks. - // Note, that we do not modify the permanently disabled IRQs, such as the - // _RESERVED_ ones. Nor do we touch other instances' IRQs. Iow, the - // IDX_PRTY_LVL_DISABLED mask is NOT part of the mask we apply below. - // - out32(OCB_OIMR0_OR, (uint32_t)((ext_irq_vectors_gpe[iPrtyLvl][IDX_MASK_VEC] | - g_oimr_override) >> 32) ); - out32(OCB_OIMR1_OR, (uint32_t)(ext_irq_vectors_gpe[iPrtyLvl][IDX_MASK_VEC] | - g_oimr_override) ); - + pk_irq_save_and_set_mask(iPrtyLvl); } else { @@ -181,19 +134,58 @@ void pk_unified_irq_prty_mask_handler(void) pk_halt(); } - - // - // 4. Return the priority vector in d5 and let hwmacro_get_ext_irq do the - // rest, i.e. route first found IRQ in the returned priority vector - // to the registered [unified] interrupt handler. - // - + // 3. Return the priority vector in d5 and let hwmacro_get_ext_irq do the + // rest, i.e. route first found IRQ in the returned priority vector + // to the registered [unified] interrupt handler. uint32_t register l_vecH asm("r5"); uint32_t register l_vecL asm("r6") __attribute__((unused)); - l_vecL = 0; asm volatile ("lvd %[data], 0(%[addr]) \n" \ : [data]"=r"(l_vecH) \ : [addr]"r"(&ext_irq_vectors_gpe[iPrtyLvl][IDX_PRTY_VEC]) ); } + +// +//pk_irq_save_and_set_mask() +// +void pk_irq_save_and_set_mask(uint32_t iPrtyLvl) +{ + // Save current mask (assume current prty level). + // Note, reading OIMR is NOT safe because overrides may already have + // happened to the OIMR. And we always want to restore + // the OIMR to a known value when we exit our thread. + if (++g_oimr_stack_ctr < NUM_EXT_IRQ_PRTY_LEVELS) + { + //prev: g_oimr_stack[g_oimr_stack_ctr] = ((uint64_t)in32(OCB_OIMR0))<<32 | + // (uint64_t)in32(OCB_OIMR1); + // Make a note of present prty level and then update tracker to new prty level. + g_oimr_stack[g_oimr_stack_ctr] = g_current_prty_level; + g_current_prty_level = iPrtyLvl; // Update prty level tracker. + g_oimr_override_stack[g_oimr_stack_ctr] = g_oimr_override; + } + else + { + MY_TRACE_ERR("Code bug: OIMR S/R stack counter=%d >= max=%d.", + g_oimr_stack_ctr, NUM_EXT_IRQ_PRTY_LEVELS); + pk_halt(); + } + + // Write the new mask for this priority level. + // First, clear all those IRQs that could possibly interrupt this instance. + // This includes all those IRQs which belong to this instance as well as + // those high-prty IRQs shared with the other instances. + // + out32(OCB_OIMR0_CLR, (uint32_t)(IRQ_VEC_ALL_OUR_IRQS >> 32)); + out32(OCB_OIMR1_CLR, (uint32_t)IRQ_VEC_ALL_OUR_IRQS); + + // Second, mask IRQs belonging to this task and lower prty tasks. + // Note, that we do not modify the permanently disabled IRQs, such as the + // _RESERVED_ ones. Nor do we touch other instances' IRQs. Iow, the + // IDX_PRTY_LVL_DISABLED mask is NOT part of the mask we apply below. + out32(OCB_OIMR0_OR, (uint32_t)((ext_irq_vectors_gpe[iPrtyLvl][IDX_MASK_VEC] | + g_oimr_override) >> 32) ); + out32(OCB_OIMR1_OR, (uint32_t)(ext_irq_vectors_gpe[iPrtyLvl][IDX_MASK_VEC] | + g_oimr_override) ); + +} diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.h b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.h index 02770ae1..04b3d6f1 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.h +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.h @@ -32,9 +32,6 @@ /// \brief Shared and global definitions for PGPE (GPE2) H-codes. /// -//-------------------------------------------------------------------// -// DO NOT modify this file unless you're the owner // -//-------------------------------------------------------------------// // Notes: // - The only define names that should be changed/added/removed @@ -43,7 +40,6 @@ // - IDX_PRTY_LVL_(task_abbr) and reflect in relevant H-code as well // - All other define names are used in H-codes // - The variable names and actions in this file must perfectly match associated -// definitions in gpe2_irq_common.c #ifndef _P9_PGPE_IRQ_H_ #define _P9_PGPE_IRQ_H_ @@ -68,38 +64,33 @@ #define IDX_PRTY_LVL_HIPRTY 0 #define IDX_PRTY_LVL_OCBERR 1 #define IDX_PRTY_LVL_IPI2HI 2 -#define IDX_PRTY_LVL_TYPE1_TYPE4 3 +#define IDX_PRTY_LVL_TYPE1 3 #define IDX_PRTY_LVL_DISABLED 4 #define IDX_PRTY_VEC 0 #define IDX_MASK_VEC 1 -#define NUM_EXT_IRQ_PRTY_LEVELS (uint8_t)(5) +#define NUM_EXT_IRQ_PRTY_LEVELS (uint8_t)(7) extern const uint64_t ext_irq_vectors_gpe[NUM_EXT_IRQ_PRTY_LEVELS][2]; -#define IRQ_VEC_PRTY0_GPE (uint64_t)(0x0001000000000000) // Non-task hi-prty IRQs +#define IRQ_VEC_PRTY0_GPE (uint64_t)(0x0000000000000000) // Non-task hi-prty IRQs // Shared between all instances -#define IRQ_VEC_PRTY1_GPE2 (uint64_t)(0x0000000000000000) // Task1-OCCHW_IRQ_OCB_ERROR=HB loss? -#define IRQ_VEC_PRTY2_GPE2 (uint64_t)(0x0000001000000000) // Task2-IPC msgs from 405 -#define IRQ_VEC_PRTY3_GPE2 (uint64_t)(0x0000000000020000) // Task3-CME interrupts -#define IRQ_VEC_PRTY4_GPE2 (uint64_t)(0xFFFEFFEFFFFDFFFF) // Other instances' IRQs +#define IRQ_VEC_PRTY1_GPE2 (uint64_t)(0x0080000000000000) // Task1-OCB_ERROR(HeartBeat Loss)/GPE3_HALT +#define IRQ_VEC_PRTY2_GPE2 (uint64_t)(0x0001000000000000) // Task2-CHECK_STOP_GPE2 +#define IRQ_VEC_PRTY3_GPE2 (uint64_t)(0x0000000000000008) // Task3-IPI2-LO(Process Flags) +#define IRQ_VEC_PRTY4_GPE2 (uint64_t)(0x0000001000000000) // Task4-IPI2-HI(IPC from OCC/SGPE) +#define IRQ_VEC_PRTY5_GPE2 (uint64_t)(0x0000000000020000) // Task5-PCB_INTR_TYPE1(PCB Type1 from CME) +#define IRQ_VEC_PRTY6_GPE2 (uint64_t)(0xFF7EFFE3FFFDFFF5) // Other instances' IRQs // Unique to each instance // We should never detect these #define IRQ_VEC_ALL_OUR_IRQS ( IRQ_VEC_PRTY0_GPE | \ IRQ_VEC_PRTY1_GPE2 | \ IRQ_VEC_PRTY2_GPE2 | \ - IRQ_VEC_PRTY3_GPE2 ) // Note, we do not incl PRTY4 here! + IRQ_VEC_PRTY3_GPE2 | \ + IRQ_VEC_PRTY4_GPE2 | \ + IRQ_VEC_PRTY5_GPE2 ) // Note, we do not incl PRTY6 here! #define IRQ_VEC_PRTY_CHECK ( IRQ_VEC_ALL_OUR_IRQS | \ - IRQ_VEC_PRTY4_GPE2 ) // This should be 0xFFFFFFFFFFFFFFFF - -/*extern const uint8_t IDX_PRTY_VEC; -extern const uint8_t IDX_MASK_VEC; - -extern const uint8_t IDX_PRTY_LVL_HIPRTY; -extern const uint8_t IDX_PRTY_LVL_OCBERR; -extern const uint8_t IDX_PRTY_LVL_IPI2HI; -extern const uint8_t IDX_PRTY_LVL_TYPE1; -extern const uint8_t IDX_PRTY_LVL_DISABLED;*/ + IRQ_VEC_PRTY6_GPE2 ) // This should be 0xFFFFFFFFFFFFFFFF extern uint8_t g_current_prty_level; extern uint8_t g_oimr_stack[NUM_EXT_IRQ_PRTY_LEVELS]; @@ -107,6 +98,7 @@ extern int g_oimr_stack_ctr; extern uint64_t g_oimr_override_stack[NUM_EXT_IRQ_PRTY_LEVELS]; extern uint64_t g_oimr_override; +void pk_irq_save_and_set_mask(uint32_t iPrtyLvl); /// Restore a vector of interrupts by overwriting OIMR. UNLESS__PPE42_IRQ_CORE_C__(extern) 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 new file mode 100644 index 00000000..284480e4 --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq_handlers.c @@ -0,0 +1,147 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq_handlers.c $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2016,2017 */ +/* [+] 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 */ +#include "pk.h" +#include "p9_pgpe.h" +#include "p9_pgpe_pstate.h" +#include "pstate_pgpe_occ_api.h" + +// +//External Global Data +// +extern uint8_t G_coresPSRequest[MAX_CORES]; //per core requested pstate +extern uint8_t G_pmcrOwner; +extern uint8_t G_pstatesEnabled; //pstates_enabled/disable + +// +//OCB Error Interrupt Handler +// +//\TODO: +//Implement this handler. Implement Safe Mode +void p9_pgpe_irq_handler_ocb_error(void* arg, PkIrqId irq) +{ + PK_TRACE_DBG("OCB Error: Enter\n"); + PkMachineContext ctx; + + pk_irq_vec_restore(&ctx);//Restore interrupts + PK_TRACE_DBG("OCB Error: Exit\n"); +} + +// +//SGPE Halt Interrupt Handler +// +//\TODO: RTC 164107 +//Implement this handler. Implement Safe Mode +void p9_pgpe_irq_handler_sgpe_halt(void* arg, PkIrqId irq) +{ + PK_TRACE_DBG("SGPE Halt: Enter\n"); + PkMachineContext ctx; + + pk_irq_vec_restore(&ctx);//Restore interrupts + PK_TRACE_DBG("SGPE Halt: Exit\n"); +} + +// +//Checkstop GPE2 Interrupt Handler +// +//\TODO +//Implement this handler. Should call code same as "Pstart STOP" IPC from OCC +void p9_pgpe_irq_handler_xstop_gpe2(void* arg, PkIrqId irq) +{ + PK_TRACE_DBG("XSTOP GPE2: Enter\n"); + PkMachineContext ctx; + + pk_irq_vec_restore(&ctx);//Restore interrupts + PK_TRACE_DBG("XSTOP GPE2: Exit\n"); +} + +// +//IPI2 Lo Priority Interrupt Handler +// +//\TODO: RTC 164107 +//Implement this handler. Should call "process_flags" function(needs to be implemented). +void p9_pgpe_irq_handler_ipi2_lo(void* arg, PkIrqId irq) +{ + PK_TRACE_DBG("IPI2 Lo: Enter\n"); + PkMachineContext ctx; + + pk_irq_vec_restore(&ctx);//Restore interrupts + PK_TRACE_DBG("IPI2 Lo: Exit\n"); +} + +// +//PCB Type 1 Interrupt Handler +// +void p9_pgpe_irq_handler_pcb_type1(void* arg, PkIrqId irq) +{ + PK_TRACE_DBG("PCB_TYPE1: Enter\n"); + + //Snapshot + PkMachineContext ctx; + ocb_opit0cn_t opit0cn; + ocb_opit1cn_t opit1cn; + uint32_t coresPendPSReq = in32(OCB_OPIT1PRA); + uint32_t c; + + if (G_pstatesEnabled && (G_pmcrOwner == PMCR_OWNER_HOST || + G_pmcrOwner == PMCR_OWNER_CHAR)) + { + + //Process pending requests + for (c = 0; c < MAX_CORES; c++) + { + //For each pending bit OPIT1PR[c] (OPIT1PR is 24 bits) + if (coresPendPSReq & (0x80000000 >> c)) + { + //Read payload from OPIT0C[c] and OPIT1C[c] register corresponding to the core 'c' + //Bits 20:31 OPIT0C - Phase 1 OPIT1C - Phase 2 + opit0cn.value = in32(OCB_OPIT0CN(c)); + opit1cn.value = in32(OCB_OPIT1CN(c)); + + uint16_t op0 = opit0cn.fields.pcb_intr_payload; + uint16_t op1 = opit1cn.fields.pcb_intr_payload; + + //make sure seq number matches for both phases + //otherwise, ignore the request + if (((op0 >> 10) && 0x3) == + ((op1 >> 10) && 0x3)) + { + //Extract the LowerPState field + G_coresPSRequest[c] = op1 & 0xff; + out32(OCB_OPIT1PRA_CLR, 0x80000000 >> c); //Clear out pending bits + } + } + } + + p9_pgpe_pstate_do_auction(ALL_QUADS_BIT_MASK); + p9_pgpe_pstate_apply_clips(); + } + +#if SIMICS_TUNING + out32(OCB_OPIT1PRA, 0x00000000); //Clear out pending bits + out32(OCB_OISR1_CLR, BIT32(14)); +#endif + pk_irq_vec_restore(&ctx);//Restore interrupts + PK_TRACE_DBG("PCB_TYPE1: Exit\n"); +} diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_main.c b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_main.c index 42ec5987..df7820f4 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_main.c +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_main.c @@ -27,6 +27,7 @@ #include "p9_pgpe_header.h" #include "p9_pgpe_gppb.h" #include "p9_pgpe_boot_temp.h" +#include "p9_pgpe_pstate.h" PgpePstateRecord G_pgpe_pstate_record; @@ -77,7 +78,7 @@ IRQ_HANDLER_DEFAULT //OCCHW_IRQ_STRM2_PUSH IRQ_HANDLER_DEFAULT //OCCHW_IRQ_STRM3_PULL IRQ_HANDLER_DEFAULT //OCCHW_IRQ_STRM3_PUSH IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PMC_PCB_INTR_TYPE0_PENDING -IRQ_HANDLER(p9_pgpe_pstate_pig_handler, (void*) & G_pgpe_pstate_record.sem[0]) +IRQ_HANDLER(p9_pgpe_irq_handler_pcb_type1, (void*) & G_pgpe_pstate_record.sem_process_req) //OCCHW_IRQ_PMC_PCB_INTR_TYPE1_PENDING IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PMC_PCB_INTR_TYPE2_PENDING IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PMC_PCB_INTR_TYPE3_PENDING @@ -101,13 +102,18 @@ EXTERNAL_IRQ_TABLE_END #define KERNEL_STACK_SIZE 512 #define THREAD_STACK_SIZE 512 -#define PGPE_THREAD_PRIORITY_PSTATE 1 +#define PGPE_THREAD_PRIORITY_PROCESS_REQUESTS 1 +#define PGPE_THREAD_PRIORITY_ACTUATE_PSTATES 2 uint8_t G_kernel_stack[KERNEL_STACK_SIZE]; -uint8_t G_p9_pgpe_pstate_thread_stack[THREAD_STACK_SIZE]; +//Thread Stacks +uint8_t G_p9_pgpe_thread_process_requests_stack[THREAD_STACK_SIZE]; +uint8_t G_p9_pgpe_thread_actuate_pstates_stack[THREAD_STACK_SIZE]; -PkThread G_p9_pgpe_pstate_thread; +//Thread Control Block +PkThread G_p9_pgpe_thread_process_requests; +PkThread G_p9_pgpe_thread_actuate_pstates; void __eabi() { @@ -124,31 +130,43 @@ main(int argc, char** argv) asm volatile ("tw 0, 31, 0"); } - // Initializes kernel data (stack, threads, timebase, timers, etc.) pk_initialize((PkAddress)G_kernel_stack, KERNEL_STACK_SIZE, 0, PPE_TIMEBASE_HZ); - // Initialize the thread control block for G_p9_pgpe_pstate_thread - pk_thread_create(&G_p9_pgpe_pstate_thread, - (PkThreadRoutine)p9_pgpe_pstate_thread, + // Initialize the thread control block for G_p9_pgpe_thread_process_requests + pk_thread_create(&G_p9_pgpe_thread_process_requests, + (PkThreadRoutine)p9_pgpe_thread_process_requests, (void*)NULL, - (PkAddress)G_p9_pgpe_pstate_thread_stack, + (PkAddress)G_p9_pgpe_thread_process_requests_stack, (size_t)THREAD_STACK_SIZE, - (PkThreadPriority)PGPE_THREAD_PRIORITY_PSTATE); + (PkThreadPriority)PGPE_THREAD_PRIORITY_PROCESS_REQUESTS); + + PK_TRACE_BIN("G_p9_pgpe_thread_process_requests", + &G_p9_pgpe_thread_process_requests, + sizeof(G_p9_pgpe_thread_process_requests)); - PK_TRACE_BIN("G_p9_pgpe_pstate_thread", - &G_p9_pgpe_pstate_thread, - sizeof(G_p9_pgpe_pstate_thread)); + // Initialize the thread control block for G_p9_pgpe_thread_actuate_pstates + pk_thread_create(&G_p9_pgpe_thread_actuate_pstates, + (PkThreadRoutine)p9_pgpe_thread_actuate_pstates, + (void*)NULL, + (PkAddress)G_p9_pgpe_thread_actuate_pstates_stack, + (size_t)THREAD_STACK_SIZE, + (PkThreadPriority)PGPE_THREAD_PRIORITY_ACTUATE_PSTATES); - // Make G_p9_pgpe_pstate_thread runnable - pk_thread_resume(&G_p9_pgpe_pstate_thread); + PK_TRACE_BIN("G_p9_pgpe_thread_actuate_pstates", + &G_p9_pgpe_thread_actuate_pstates, + sizeof(G_p9_pgpe_thread_actuate_pstates)); + + // Make G_p9_pgpe_thread pstates_update runnable + pk_thread_resume(&G_p9_pgpe_thread_process_requests); + pk_thread_resume(&G_p9_pgpe_thread_actuate_pstates); //Do initialization p9_pgpe_header_init(); -#if MIMIC_BOOT_TEMP +#if USE_BOOT_TEMP //This is to be used for development and testing/verif //if Global Pstate Parameter Block is not initialized through other means. // @@ -167,6 +185,11 @@ main(int argc, char** argv) //Setup FIT(Fixed-Interval Timer) p9_pgpe_fit_init(); + //Initialize all pstate related data to some default values + p9_pgpe_pstate_init(); + + PK_TRACE_DBG("Starting PK Threads\n"); + // Start running the highest priority thread. // This function never returns pk_start_threads(); 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 94382d4b..12c93b9c 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 @@ -23,463 +23,253 @@ /* */ /* IBM_PROLOG_END_TAG */ #include "p9_pgpe.h" -#include "p9_pstate_common.h" +#include "pstate_pgpe_cme_api.h" #include "p9_pstates_common.h" #include "p9_pgpe_gppb.h" #include "p9_pgpe_boot_temp.h" #include "avs_driver.h" #include "p9_dd1_doorbell_wr.h" +#include "p9_pgpe_pstate.h" +#include "pstate_pgpe_occ_api.h" +//#include "pstate_pgpe_sgpe_api.h" +#include "ipc_messages.h" +#include "p9_pgpe_header.h" +// +//Global External Data +// +extern pgpe_header_data_t* G_pgpe_header_data; -#define CCSR_CORE_CONFIG_MASK 0xC0000000 +// +//Global Data +// +uint8_t G_safeModeEnabled; //safe mode enabled/disabled +uint8_t G_pstatesEnabled; //pstates_enabled/disable +uint8_t G_pmcrOwner; +uint8_t G_wofEnabled; //wof enable/disable +uint8_t G_wofPending; //wof enable pending +uint8_t G_psClipMax[MAX_QUADS], + G_psClipMin[MAX_QUADS]; //pmin and pmax clips +uint8_t G_wofClip; //wof clip +uint8_t G_coresPSRequest[MAX_CORES]; //per core requested pstate +uint8_t G_quadPSComputed[MAX_QUADS]; //computed Pstate per quad +uint8_t G_globalPSComputed; //computed global Pstate +uint8_t G_quadPSTarget[MAX_QUADS]; //target Pstate per quad +uint8_t G_globalPSTarget; //target global Pstate +uint8_t G_quadPSCurr[MAX_QUADS]; //target Pstate per quad +uint8_t G_globalPSCurr; //target global Pstate +uint8_t G_quadPSNext[MAX_QUADS]; //target Pstate per quad +uint8_t G_globalPSNext; +uint32_t G_eVidCurr, G_eVidNext; +VFRT_Hcode_t* G_vfrt_ptr; +quad_state0_t* G_quadState0; +quad_state1_t* G_quadState1; -enum quadManager -{ - QUAD_MANAGER_NONE = -1, - QUAD_MANAGER_CME0 = 0, - QUAD_MANAGER_CME1 = 1 -}; +#define GPE_BUFFER(declaration) \ + declaration __attribute__ ((__aligned__(8))) __attribute__ ((section (".noncacheable"))) +GPE_BUFFER(ipc_async_cmd_t G_ipc_msg_pgpe_sgpe); +GPE_BUFFER(ipcmsg_p2s_ctrl_stop_updates_t G_sgpe_control_updt); -//External Voltage, GlobalPState, Local PStates -uint32_t G_eVidCurr, G_eVidNext; -uint8_t G_globalCurrPS, G_globalNextPS; -uint8_t G_localPSCurr[MAX_QUADS]; -uint8_t G_localPSNext[MAX_QUADS]; -uint8_t G_globalPSTgt; -uint8_t G_localPSTgt[MAX_QUADS]; -uint32_t G_tgtEVid; -int8_t G_quadManagerCME[MAX_QUADS]; //0->CME0, 1->CME1, -1->Quad not configured -uint8_t G_quadPendPSReq[MAX_QUADS]; -uint8_t G_coresPendPSReqData[MAX_CORES]; -uint32_t G_ccsr; -extern PgpePstateRecord G_pgpe_pstate_record; -extern GlobalPstateParmBlock* G_gppb; -extern VpdOperatingPoint G_operating_points[NUM_VPD_PTS_SET][VPD_PV_POINTS]; // -//Function Prototypes +//Data passing between IPC interrupt and threads // -void p9_pgpe_pstate_get_config(); -void p9_pgpe_pstate_update_ext_volt(); -void p9_pgpe_pstate_freq_update(); +ipc_req_t G_ipc_pend_tbl[MAX_IPC_PEND_TBL_ENTRIES]; +uint32_t G_already_sem_posted; -// -// -// +extern VpdOperatingPoint G_operating_points[NUM_VPD_PTS_SET][VPD_PV_POINTS]; // -//PIG Interrupt Handler +//p9_pgpe_pstate_init // -void p9_pgpe_pstate_pig_handler(void* arg, PkIrqId irq) +void p9_pgpe_pstate_init() { - //Read OCC_FLAG[PGPE_STARTNOTSTOP]] - uint32_t occFlag = in32(OCB_OCCFLG); + uint32_t q; + + G_safeModeEnabled = 0; + G_pstatesEnabled = 0; + G_wofEnabled = 0; + G_wofPending = 0; - if (occFlag & BIT32(PGPE_START_NOT_STOP)) + for (q = 0; q < MAX_QUADS; q++) { - pk_semaphore_post((PkSemaphore*)arg); + G_psClipMax[q] = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; + G_psClipMin[q] = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; + G_quadPSComputed[q] = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; + G_globalPSComputed = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; + G_quadPSTarget[q] = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; + G_globalPSTarget = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; + G_quadPSCurr[q] = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; + G_globalPSCurr = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; + G_quadPSNext[q] = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; + G_globalPSNext = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; } + G_quadState0 = (quad_state0_t*)G_pgpe_header_data->actual_quad_status_addr; + G_quadState1 = (quad_state1_t*)(G_pgpe_header_data->actual_quad_status_addr + 2); } // -//PState Thread +//p9_pgpe_pstate_update_ // -void p9_pgpe_pstate_thread(void* arg) +void p9_pgpe_pstate_update(uint8_t* s) { - int32_t q, c; - uint8_t psClipMax, psClipMin; - uint32_t coresPendPSReq; - ocb_opit0cn_t opit0cn; - ocb_opit1cn_t opit1cn; - PkMachineContext ctx; - uint8_t effPSClipMin, effPSClipMax; - uint8_t done; - - //\todo Set initial eVid, Global PState, Local PState, Max/Mins PStateClip for PGPE. RTC. 159900 - psClipMax = 0; - psClipMin = 140; - coresPendPSReq = 0; - G_eVidCurr = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].vdd_mv; - G_eVidNext = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].vdd_mv; - G_globalCurrPS = G_globalNextPS = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; + uint32_t q, c; for (q = 0; q < MAX_QUADS; q++) { - G_localPSCurr[q] = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; - G_localPSNext[q] = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; - G_localPSTgt[q] = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; - G_quadPendPSReq[q] = 0; - } + for (c = (q * CORES_PER_QUAD); c < (q + 1)*CORES_PER_QUAD; c++) + { + G_coresPSRequest[c] = s[q]; + } - for (c = 0; c < MAX_CORES; c++) - { - G_coresPendPSReqData[c] = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; + G_quadPSCurr[q] = s[q]; + G_quadPSNext[q] = s[q]; } - //Initialization - external_voltage_control_init(&G_eVidCurr); - G_eVidCurr = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].vdd_mv; //\todo RTC 159900. Remove this - p9_pgpe_pstate_get_config(); - - out32(OCB_OIMR1_CLR, BIT32(14)); //Enable PCB_INTR_TYPE1 - - pk_semaphore_create(&(G_pgpe_pstate_record.sem[0]), 0, 1); - - //Initialize IPC - p9_pgpe_ipc_init(); - - - //Set OCC_SCRATCH2[PGPE_ACTIVE] - out32(OCB_OCCS2, BIT32(PGPE_ACTIVE)); -#if EPM_P9_TUNING - asm volatile ("tw 0, 31, 0"); -#endif + p9_pgpe_pstate_do_auction(ALL_QUADS_BIT_MASK); + p9_pgpe_pstate_apply_clips(NULL); +} - //Thread Loop - while (1) +// +//p9_pgpe_pstate_do_auction +// +void p9_pgpe_pstate_do_auction(uint8_t quadAuctionRequest) +{ + PK_TRACE_DBG("AUCT: Enter\n"); + //Get active cores and quads + uint32_t q, c; + uint32_t activeCores = G_quadState0->fields.core_poweron_state ; + activeCores = (activeCores << 16) | (G_quadState1->fields.core_poweron_state); + uint32_t activeQuads = G_quadState1->fields.requested_active_quad; + + //Local PStates Auction + for (q = 0; q < MAX_QUADS; q++) { - //pend on semaphore - pk_semaphore_pend(&(G_pgpe_pstate_record.sem[0]), PK_WAIT_FOREVER); - - done = 0; - - while (done == 0) + //Make sure quad is active + if ((activeQuads & (QUAD0_BIT_MASK >> q)) & + (quadAuctionRequest & (QUAD0_BIT_MASK >> q))) { - //Snapshot - coresPendPSReq = in32(OCB_OPIT1PRA); - - //Make sure clips aren't below or above VPD points - if (psClipMax < G_operating_points[VPD_PT_SET_BIASED_SYSP][ULTRA].pstate) - { - effPSClipMax = G_operating_points[VPD_PT_SET_BIASED_SYSP][ULTRA].pstate; - } - else - { - effPSClipMax = psClipMax; - } - - if (psClipMin > G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate) - { - effPSClipMin = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; - } - else - { - effPSClipMin = psClipMin; - } + //Go through all the cores in this quad with pending request + //and find the lowest numbered PState + G_quadPSComputed[q] = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; - //Process pending requests - for (c = 0; c < MAX_CORES; c++) + for (c = (q * CORES_PER_QUAD); c < (q + 1)*CORES_PER_QUAD; c++) { - //For each pending bit OPIT1PR[c] (OPIT1PR is 24 bits) - if (coresPendPSReq & (0x80000000 >> c)) + if (activeCores & (0x80000000 >> c)) { - //Read payload from OPIT0C[c] and OPIT1C[c] register corresponding to the core 'c' - //Bits 20:31 OPIT0C - Phase 1 OPIT1C - Phase 2 - opit0cn.value = in32(OCB_OPIT0CN(c)); - opit1cn.value = in32(OCB_OPIT1CN(c)); - - uint16_t op0 = opit0cn.fields.pcb_intr_payload; - uint16_t op1 = opit1cn.fields.pcb_intr_payload; - - //make sure seq number matches for both phases - //otherwise, ignore the request - if (((op0 >> 10) && 0x3) == - ((op1 >> 10) && 0x3)) + if (G_quadPSComputed[q] > G_coresPSRequest[c]) { - //Extract the LowerPState field - G_coresPendPSReqData[c] = op1 & 0xff; - G_quadPendPSReq[QUAD_FROM_CORE(c)] = 1; - out32(OCB_OPIT1PRA_CLR, 0x80000000 >> c); //Clear out pending bits + G_quadPSComputed[q] = G_coresPSRequest[c]; } } } + } + else + { + G_quadPSComputed[q] = 0xFF; + } - //Local PStates Auction - for (q = 0; q < MAX_QUADS; q++) - { - //Make sure quad is configured and there is a pending request - if ((G_quadManagerCME[q] != QUAD_MANAGER_NONE) && (G_quadPendPSReq[q] == 1)) - { - //Go through all the cores in this quad with pending request - //and find the lowest numbered PState - G_localPSTgt[q] = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; - - for (c = (q * CORES_PER_QUAD); c < (q + 1)*CORES_PER_QUAD; c++) - { - if (G_ccsr & (0x80000000 >> c)) - { - if (G_localPSTgt[q] > G_coresPendPSReqData[c]) - { - G_localPSTgt[q] = G_coresPendPSReqData[c]; - } - } - } - - //Apply Clip - if (G_localPSTgt[q] < effPSClipMax) - { - G_localPSTgt[q] = effPSClipMax; - } - else if (G_localPSTgt[q] > effPSClipMin) - { - G_localPSTgt[q] = effPSClipMin; - } - - G_quadPendPSReq[q] = 0; - } - } + // PK_TRACE_DBG("AUCTION: G_quadPSComputed: 0x%x\n", G_quadPSComputed[q]); + } - //Global PState Auction - G_globalPSTgt = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; + //Global PState Auction + G_globalPSComputed = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; - for (q = 0; q < MAX_QUADS; q++) + for (q = 0; q < MAX_QUADS; q++) + { + if (activeQuads & (QUAD0_BIT_MASK >> q)) + { + if (G_globalPSComputed > G_quadPSComputed[q]) { - if ((G_quadManagerCME[q] != QUAD_MANAGER_NONE)) - { - if (G_globalPSTgt > G_localPSTgt[q]) - { - G_globalPSTgt = G_localPSTgt[q]; - } - } + G_globalPSComputed = G_quadPSComputed[q]; } + } + } + PK_TRACE_DBG("AUCT glbPSCmpted: 0x%x\n", G_globalPSComputed); + PK_TRACE_DBG("AUCT: Exit\n"); +} -#if EPM_P9_TUNING - asm volatile ("tw 0, 31, 0"); -#endif - - //Determine targetVoltage - G_tgtEVid = p9_pgpe_gppb_intp_vdd_from_ps(G_globalPSTgt, VPD_PT_SET_BIASED_SYSP, VPD_SLOPES_BIASED); +// +//p9_pgpe_pstate_apply_clips +// +void p9_pgpe_pstate_apply_clips() +{ + PK_TRACE_DBG("APCLP: Enter\n"); + uint32_t q; + uint32_t activeQuads = G_quadState1->fields.requested_active_quad; - //Higher number PState - if (((int16_t)(G_globalPSTgt) - (int16_t)(G_globalCurrPS)) > 0) - { - if ((G_eVidCurr - G_tgtEVid) <= G_gppb->ext_vdd_step_size_mv) - { - G_eVidNext = G_tgtEVid; - G_globalNextPS = G_globalPSTgt; + //Apply clips to quad computed + PK_TRACE_DBG("APCLP: 0x%x\n", activeQuads); - for (q = 0; q < MAX_QUADS; q++) - { - G_localPSNext[q] = G_localPSTgt[q]; - } + for (q = 0; q < MAX_QUADS; q++) + { + if (activeQuads & (QUAD0_BIT_MASK >> q)) + { + uint8_t maxPS = G_psClipMax[q]; - done = 1; - } - else + if (G_wofEnabled == 1) + { + if (G_wofClip <= G_psClipMax[q]) { - G_eVidNext = G_eVidCurr - G_gppb->ext_vdd_step_size_mv; - G_globalNextPS = p9_pgpe_gppb_intp_ps_from_ext_vdd(G_eVidNext); - - for (q = 0; q < MAX_QUADS; q++) - { - if (G_localPSTgt[q] < G_globalNextPS) //Keep localPS under GlobalPS - { - G_localPSNext[q] = G_globalNextPS; - } - else - { - G_localPSNext[q] = G_localPSTgt[q]; - } - } + maxPS = G_wofClip; } + } - p9_pgpe_pstate_freq_update(); - p9_pgpe_pstate_update_ext_volt(); + if (G_quadPSComputed[q] > maxPS) + { + G_quadPSTarget[q] = maxPS; } - //Lower number PState - else if (((int16_t)(G_globalPSTgt) - (int16_t)(G_globalCurrPS)) < 0) + else if(G_quadPSComputed[q] < G_psClipMin[q]) { - if ((G_tgtEVid - G_eVidCurr) <= G_gppb->ext_vdd_step_size_mv) - { - G_eVidNext = G_tgtEVid; - G_globalNextPS = G_globalPSTgt; - - for (q = 0; q < MAX_QUADS; q++) - { - G_localPSNext[q] = G_localPSTgt[q]; - } - - done = 1; - } - else - { - G_eVidNext = G_eVidCurr + G_gppb->ext_vdd_step_size_mv; - G_globalNextPS = p9_pgpe_gppb_intp_ps_from_ext_vdd(G_eVidNext); - - for (q = 0; q < MAX_QUADS; q++) - { - if (G_localPSTgt[q] < G_globalNextPS) //Keep localPS under GlobalPS - { - G_localPSNext[q] = G_globalNextPS; - } - else - { - G_localPSNext[q] = G_localPSTgt[q]; - } - } - } - - p9_pgpe_pstate_update_ext_volt(); - p9_pgpe_pstate_freq_update(); + G_quadPSTarget[q] = G_psClipMin[q]; } else { - for (q = 0; q < MAX_QUADS; q++) - { - G_localPSNext[q] = G_localPSTgt[q]; - } - - p9_pgpe_pstate_freq_update(); - done = 1; + G_quadPSTarget[q] = G_quadPSComputed[q]; } - }//Step-Loop - - pk_irq_vec_restore(&ctx);//Restore interrupts - }//Thread Loop -} - - -// -//p9_pgpe_pstate_update_ext_volt -// -void p9_pgpe_pstate_update_ext_volt() -{ - //Update external voltage - external_voltage_control_write(G_eVidNext); - -#if !EPM_P9_TUNING - //Do we need the pk_sleep call here now that we only increase voltage - //by small step-size? - uint32_t vddDelta; - - if (G_eVidCurr > G_eVidNext) - { - vddDelta = G_eVidCurr - G_eVidNext; - } - else if(G_eVidCurr < G_eVidNext) - { - vddDelta = G_eVidNext - G_eVidCurr; - } - else - { - vddDelta = 1; - } - - pk_sleep(PK_NANOSECONDS((vddDelta))); -#endif - - G_eVidCurr = G_eVidNext; -} - -// -//frequency_update -// -void p9_pgpe_pstate_freq_update() -{ - int32_t c, q; - //int rc; - uint32_t opit4pr; - uint8_t pendingAcks = 0; - uint8_t quadPendDBAck[MAX_QUADS]; - pgpe_db0_glb_bcast_t db0; - - //Send Doorbell0 to every core by doing a multicast operation - db0.value = 0; - db0.fields.msg_id = MSGID_DB0_GLOBAL_ACTUAL_BROADCAST; - db0.fields.global_actual = G_globalNextPS; - db0.fields.quad0_ps = G_localPSNext[0]; - db0.fields.quad1_ps = G_localPSNext[1]; - db0.fields.quad2_ps = G_localPSNext[2]; - db0.fields.quad3_ps = G_localPSNext[3]; - db0.fields.quad4_ps = G_localPSNext[4]; - db0.fields.quad5_ps = G_localPSNext[5]; - p9_dd1_db_multicast_wr(PCB_MUTLICAST_GRP1 | CPPM_CMEDB0, db0.value, G_ccsr); - //GPE_PUTSCOM(PCB_MUTLICAST_GRP1 | CPPM_CMEDB0, db0.value); - - for (q = 0; q < MAX_QUADS; q++) - { - if (G_quadManagerCME[q] != QUAD_MANAGER_NONE) - { - quadPendDBAck[q] = 1; } else { - quadPendDBAck[q] = 0; + G_quadPSTarget[q] = 0xFF; } + + // PK_TRACE_DBG("APP_CLIP: G_quadPSTarget: 0x%x\n", G_quadPSTarget[q]); } - //Wait for all the acks to come - pendingAcks = 1; + //Global PState Auction + G_globalPSTarget = G_operating_points[VPD_PT_SET_BIASED_SYSP][POWERSAVE].pstate; - while (pendingAcks) + for (q = 0; q < MAX_QUADS; q++) { - //Process acks - opit4pr = in32(OCB_OPIT4PRA); - - for (c = 0; c < MAX_CORES; c++) + if (activeQuads & (QUAD0_BIT_MASK >> q)) { - if (opit4pr & (0x80000000 >> c)) + if (G_globalPSTarget > G_quadPSTarget[q]) { - if (quadPendDBAck[QUAD_FROM_CORE(c)]) - { - quadPendDBAck[QUAD_FROM_CORE(c)] = 0; - out32(OCB_OPIT4PRA_CLR, 0x80000000 >> c); //Clear out pending bits - } - else - { - pk_halt(); - } - } - } - - //Check if any pending left - pendingAcks = 0; - - for (q = 0; q < MAX_QUADS; q++) - { - if (quadPendDBAck[q]) - { - pendingAcks = 1; + G_globalPSTarget = G_quadPSTarget[q]; } } } - //Update Current Global and Local PState - G_globalCurrPS = G_globalNextPS; - - for (q = 0; q < MAX_QUADS; q++) - { - G_localPSCurr[q] = G_localPSNext[q]; - } + PK_TRACE_DBG("APCLP: glbPSTgt: 0x%x\n", G_globalPSTarget); + PK_TRACE_DBG("APCLP: Exit\n"); } // -//Determine which CMEs are quad manager +//p9_pgpe_pstate_calc_wof // -void p9_pgpe_pstate_get_config() +void p9_pgpe_pstate_calc_wof() { - int32_t q; - ocb_ccsr_t ccsr; - ccsr.value = in32(OCB_CCSR); - G_ccsr = ccsr.value; + //\TODO RTC 162896 + //Figure out how to calculate WOF Clip + G_wofClip = 150; - for (q = 0; q < MAX_QUADS; q++) - { - //CME0 is quad manager - if (ccsr.value & (CCSR_CORE_CONFIG_MASK >> (q * CORES_PER_QUAD))) - { - G_quadManagerCME[q] = QUAD_MANAGER_CME0; - } - else if (ccsr.value & (CCSR_CORE_CONFIG_MASK >> (q * CORES_PER_QUAD + 2))) - { - G_quadManagerCME[q] = QUAD_MANAGER_CME1; - } - else - { - G_quadManagerCME[q] = QUAD_MANAGER_NONE; - } - } + p9_pgpe_pstate_apply_clips(); +} + +void p9_pgpe_pstate_ipc_rsp_cb_sem_post(ipc_msg_t* msg, void* arg) +{ + pk_semaphore_post((PkSemaphore*)arg); } 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 new file mode 100644 index 00000000..56771f6e --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.h @@ -0,0 +1,74 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.h $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2016,2017 */ +/* [+] 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 */ +#ifndef _P9_PGPE_PSTATE_HEADER_ +#define _P9_PGPE_PSTATE_HEADER_ + +#include "pk.h" +#include "ipc_api.h" +#include "ipc_async_cmd.h" + +#define MAX_IPC_PEND_TBL_ENTRIES 9 +#define IPC_PEND_PSTATE_START 0 +#define IPC_PEND_PSTATE_STOP 1 +#define IPC_PEND_SGPE_ACTIVE_CORES_UPDT 2 +#define IPC_PEND_SGPE_ACTIVE_QUADS_UPDT 3 +#define IPC_PEND_CLIP_UPDT 4 +#define IPC_PEND_WOF_CTRL 5 +#define IPC_PEND_WOF_VFRT 6 +#define IPC_PEND_SET_PMCR_REQ 7 +#define IPC_PEND_SGPE_SUSPEND_PSTATES 8 + + +#define ALL_QUADS_BIT_MASK QUAD0_BIT_MASK | QUAD1_BIT_MASK | \ + QUAD2_BIT_MASK | QUAD3_BIT_MASK | \ + QUAD4_BIT_MASK | QUAD5_BIT_MASK +#define QUAD0_BIT_MASK 0x80 +#define QUAD1_BIT_MASK 0x40 +#define QUAD2_BIT_MASK 0x20 +#define QUAD3_BIT_MASK 0x10 +#define QUAD4_BIT_MASK 0x8 +#define QUAD5_BIT_MASK 0x4 + +// +//Task list entry +// +typedef struct ipc_req +{ + ipc_msg_t* cmd; + uint8_t pending_ack; + uint8_t pending_processing; +} ipc_req_t; + +// +//Functions called by threads +// +void p9_pgpe_pstate_init(); +void p9_pgpe_pstate_update(uint8_t* quadPstates); +void p9_pgpe_pstate_do_auction(uint8_t quadAuctionRequest); +void p9_pgpe_pstate_calc_wof(); +void p9_pgpe_pstate_apply_clips(); +void p9_pgpe_pstate_ipc_rsp_cb_sem_post(ipc_msg_t* msg, void* arg); + +#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 new file mode 100644 index 00000000..2bdd43ee --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_actuate_pstates.c @@ -0,0 +1,783 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_actuate_pstates.c $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2016,2017 */ +/* [+] 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 */ +#include "pk.h" +#include "p9_pgpe.h" +#include "p9_pgpe_header.h" +#include "p9_pgpe_pstate.h" +#include "ipc_api.h" +#include "ipc_async_cmd.h" +#include "p9_pgpe_gppb.h" +#include "pstate_pgpe_occ_api.h" +//#include "pstate_pgpe_sgpe_api.h" +#include "ipc_messages.h" +#include "p9_dd1_doorbell_wr.h" +#include "avs_driver.h" + +//Constants, #defines +#define CCSR_CORE_CONFIG_MASK 0x80000000 + +//Local Function Prototypes +void p9_pgpe_thread_actuate_start(); +void p9_pgpe_thread_actuate_stop(); +void p9_pgpe_wait_cme_db_ack(uint8_t msg_id, uint32_t activeCores); +void p9_pgpe_thread_actuate_updt_ext_volt(uint32_t tgtEVid); +void p9_pgpe_thread_actuate_freq_updt(uint32_t activeCores); +void p9_pgpe_thread_actuate_do_step(); +void p9_pgpe_thread_actuate_init_actual_quad(); + +// +//External Global Data +// +extern PgpePstateRecord G_pgpe_pstate_record; +extern uint8_t G_pstatesEnabled; //pstates_enabled/disable +extern uint8_t G_wofEnabled; //wof enable/disable +extern uint8_t G_quadPSTarget[MAX_QUADS]; //target Pstate per quad +extern volatile uint8_t G_globalPSTarget; //target global Pstate +extern uint8_t G_quadPSCurr[MAX_QUADS]; //target Pstate per quad +extern volatile uint8_t G_globalPSCurr; //target global Pstate +extern uint8_t G_quadPSNext[MAX_QUADS]; //target Pstate per quad +extern uint8_t G_globalPSNext; +extern uint32_t G_eVidCurr, G_eVidNext; +extern GlobalPstateParmBlock* G_gppb; +extern pgpe_header_data_t* G_pgpe_header_data; +extern uint8_t G_psClipMax[MAX_QUADS], + G_psClipMin[MAX_QUADS]; //pmin and pmax clips +extern uint8_t G_pmcrOwner; +extern ipc_req_t G_ipc_pend_tbl[MAX_IPC_PEND_TBL_ENTRIES]; +extern uint8_t G_pstate0_dpll_value; +extern uint32_t G_ext_vrm_inc_rate_mult_usperus; +extern uint32_t G_ext_vrm_dec_rate_mult_usperus; +extern VpdOperatingPoint G_operating_points[NUM_VPD_PTS_SET][VPD_PV_POINTS]; +extern quad_state0_t* G_quadState0; +extern quad_state1_t* G_quadState1; +extern ipc_async_cmd_t G_ipc_msg_pgpe_sgpe; +GPE_BUFFER(extern ipcmsg_p2s_ctrl_stop_updates_t G_sgpe_control_updt); + +//Payload data non-cacheable region for IPCs sent to SGPE +// +//Thread Actuate PStates +// +void p9_pgpe_thread_actuate_pstates(void* arg) +{ + PK_TRACE_DBG("ACT_TH: Started\n"); + uint32_t inRange, q = 0; + PkMachineContext ctx; + uint32_t restore_irq = 0; + + pk_semaphore_create(&(G_pgpe_pstate_record.sem_actuate), 0, 1); + pk_semaphore_create(&(G_pgpe_pstate_record.sem_sgpe_wait), 0, 1); + + PK_TRACE_DBG("ACT_TH: Inited\n"); + + //Initialize Shared SRAM to a known state + p9_pgpe_thread_actuate_init_actual_quad(); + +#if PGPE_UNIT_TEST + out32(OCB_OCCS2, BIT32(30)); +#endif + + //Thread Loop + while(1) + { + PK_TRACE_DBG("ACT_TH: Pend\n"); + pk_semaphore_pend(&(G_pgpe_pstate_record.sem_actuate), PK_WAIT_FOREVER); + wrteei(1); + + //Pstates Start. This call will unmask IPC and block on SGPE ACK + p9_pgpe_thread_actuate_start(); + + //Loop while Pstate is enabled + while(G_pstatesEnabled) + { + asm volatile ("tw 0, 31, 0"); + + if( G_globalPSCurr != G_globalPSTarget || + G_quadPSCurr[0] ^ G_quadPSTarget[0] || + G_quadPSCurr[1] ^ G_quadPSTarget[1] || + G_quadPSCurr[2] ^ G_quadPSTarget[2] || + G_quadPSCurr[3] ^ G_quadPSTarget[3] || + G_quadPSCurr[4] ^ G_quadPSTarget[4] || + G_quadPSCurr[5] ^ G_quadPSTarget[5] ) + { + //We don't want actuate_step to interrupted by any external interrupt. + //However, we still want FIT Timer to be active, so we mask of all interrupts + //in the OIMR through UIH(by setting UIH priority lvl = 0) + pk_critical_section_enter(&ctx); + pk_irq_save_and_set_mask(0); + pk_critical_section_exit(&ctx); + + restore_irq = 0; + + //Do one actuate step + PK_TRACE_DBG("ACT_TH: PSTgt: 0x%x PSCurr: 0x%x\n", G_globalPSTarget, G_globalPSCurr); + p9_pgpe_thread_actuate_do_step(); + + //evaluate conditions for pending ACKs + inRange = 1; + + for (q = 0; q < MAX_QUADS; q++) + { + if (G_psClipMax[q] < G_quadPSCurr[q] || + G_quadPSCurr[q] > G_psClipMin[q]) + { + inRange = 0; + } + } + + //ACK any pending and unmask IPC interrupt + if (inRange == 1) + { + if (G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].pending_ack == 1) + { + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].cmd; + ipcmsg_clip_update_t* args = (ipcmsg_clip_update_t*)async_cmd->cmd_data; + args->msg_cb.rc = PGPE_RC_SUCCESS; + G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].pending_ack = 0; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].cmd, IPC_RC_SUCCESS); + restore_irq = 1; + } + } + + //Now, PGPE is done with actuate step, let's + //restore the interrupts in OIMR through UIH + pk_irq_vec_restore(&ctx); + } + + //Check if IPC should be opened again + if (restore_irq == 1) + { + PK_TRACE_DBG("ACT_TH: IRQ Restore\n"); + restore_irq = 0; + pk_irq_vec_restore(&ctx); + } + } + + //Pstates Stop + //This call will unmask IPC and block on SGPE ACK + p9_pgpe_thread_actuate_stop(); + }//Thread loop +} + +// +//p9_pgpe_thread_actuate_start() +// +void p9_pgpe_thread_actuate_start() +{ + PK_TRACE_DBG("ACT_TH: Start Enter\n"); + ocb_ccsr_t ccsr; + ccsr.value = in32(OCB_CCSR); +// PK_TRACE_DBG("ACT_TH: Read CCSR\n"); + ocb_qcsr_t qcsr; + qcsr.value = in32(OCB_QCSR); +// PK_TRACE_DBG("ACT_TH: Read QCSR\n"); + uint8_t quadPstates[MAX_QUADS]; + uint8_t lowestDpll, syncPstate; + qppm_dpll_freq_t dpll; + PkMachineContext ctx; + uint32_t active_conf_cores = 0; + uint32_t q; + + //1. Send 'Control Stop Updates' IPC to SGPE +#if SGPE_IPC_ENABLED == 1 + uint32_t rc; + G_sgpe_control_updt.fields.msg_num = MSGID_PGPE_SGPE_CONTROL_STOP_UPDATES; + G_sgpe_control_updt.fields.return_code = 0x0; + G_sgpe_control_updt.fields.action = CTRL_STOP_UPDT_ENABLE_QUAD; + G_ipc_msg_pgpe_sgpe.cmd_data = &G_sgpe_control_updt; + ipc_init_msg(&G_ipc_msg_pgpe_sgpe.cmd, + IPC_MSGID_PGPE_SGPE_CONTROL_STOP_UPDATES, + p9_pgpe_pstate_ipc_rsp_cb_sem_post, + (void*)&G_pgpe_pstate_record.sem_sgpe_wait); + + //send the command + PK_TRACE_DBG("ACT_TH: CtrlStopUpdt Sent\n"); + rc = ipc_send_cmd(&G_ipc_msg_pgpe_sgpe.cmd); + + if(rc) + { + pk_halt(); + } + + //Wait for SGPE ACK with alive Quads + pk_irq_vec_restore(&ctx); + pk_semaphore_pend(&(G_pgpe_pstate_record.sem_sgpe_wait), PK_WAIT_FOREVER); + + PK_TRACE_DBG("ACT_TH: CtrlStopUpdt Resp\n"); + + if (G_sgpe_control_updt.fields.return_code == SGPE_PGPE_IPC_RC_SUCCESS) + { + //Update Shared Memory Region + G_quadState0->fields.core_poweron_state = (ccsr.value >> 8); + G_quadState1->fields.core_poweron_state = (ccsr.value & 0xFF) << 8; + G_quadState1->fields.requested_active_quad = G_sgpe_control_updt.fields.active_quads; + } + else + { + pk_halt(); + } + +#else + G_quadState0->fields.core_poweron_state = (ccsr.value >> 16); + G_quadState1->fields.core_poweron_state = (ccsr.value & 0xFF00); + + for (q = 0; q < MAX_QUADS; q++ ) + { + if ((qcsr.fields.ex_config & (0x800 >> (2 * q))) || + (qcsr.fields.ex_config & (0x400 >> (2 * q)))) + { + G_quadState1->fields.requested_active_quad |= (0x80 >> q) ; + } + } + + PK_TRACE_DBG("ACT_TH: Shr Mem Updt\n"); +#endif //_SGPE_IPC_ENABLED_ + + //2. Read DPLLs + lowestDpll = 255; + dpll.value = 0; + PK_TRACE_DBG("ACT_TH: DPLL0Value=0x%x\n", G_pstate0_dpll_value ); + + for (q = 0; q < MAX_QUADS; q++) + { + if((G_quadState1->fields.requested_active_quad & (0x80 >> q)) && + (qcsr.fields.ex_config & (0xC00 >> 2 * q))) + { +#if SIMICS_TUNING == 0 + GPE_GETSCOM(GPE_SCOM_ADDR_QUAD(QPPM_DPLL_FREQ, q), dpll.value); +#else + dpll.fields.fmax = (G_pstate0_dpll_value + - G_operating_points[VPD_PT_SET_BIASED_SYSP][NOMINAL].pstate) << 3; +#endif + + if ((dpll.fields.fmax >> 3) < lowestDpll ) + { + lowestDpll = dpll.fields.fmax >> 3; + } + + PK_TRACE_DBG("ACT_TH: Quad[%d]: DPLL=0x%x\n", q, (dpll.fields.fmax )); + active_conf_cores |= (0xF0000000 >> q * 4); + } + } + + //3. Determine Sync Pstate + // + //\TODO: Need Greg's Response + //Why does HCode Spec says current frequency might not + //correspond to frequency of any Pstate? As I understand, + //DPLL encoding and frequency/pstate have same step size, so + //they should correspond one to one + // + syncPstate = G_pstate0_dpll_value - lowestDpll; + + //Init Core PStates + for (q = 0; q < MAX_QUADS; q++) + { + if((qcsr.fields.ex_config & (0xC00 >> 2 * q))) + { + quadPstates[q] = syncPstate; + } + else + { + quadPstates[q] = 0xFF; + } + } + + p9_pgpe_pstate_update(quadPstates); + PK_TRACE_DBG("ACT_TH: Sync Pstate=0x%x\n", syncPstate); + PK_TRACE_DBG("ACT_TH: LowDPLL:0x%x\n", q, lowestDpll); + PK_TRACE_DBG("ACT_TH: GlblPsTgt:0x%x\n", G_globalPSTarget); + + //4. Set External VRM + //\TODO: Need Greg's Response + //Why does spec says to read external VDD. Is there + //any other reason besides PGPE storing it + external_voltage_control_init(&G_eVidCurr); +#if SIMICS_TUNING + G_eVidCurr = p9_pgpe_gppb_intp_vdd_from_ps(G_globalPSTarget, VPD_PT_SET_BIASED_SYSP, VPD_SLOPES_BIASED); +#endif + G_eVidNext = p9_pgpe_gppb_intp_vdd_from_ps(G_globalPSTarget, VPD_PT_SET_BIASED_SYSP, VPD_SLOPES_BIASED); + p9_pgpe_thread_actuate_updt_ext_volt(G_eVidNext); + G_globalPSCurr = G_globalPSTarget; + + PK_TRACE_DBG("ACT_TH: eVidCurr=0x%x\n", G_eVidCurr); + PK_TRACE_DBG("ACT_TH: eVidNext=0x%x\n", G_eVidNext); + PK_TRACE_DBG("ACT_TH: GlbPSCurr:0x%x\n", G_globalPSCurr ); + + //5. Determine PMCR Owner + //We save it off so that CMEs that are currently in STOP11 + //can be told upon STOP11 Exit + PK_TRACE_DBG("ACT_TH: g_oimr_override:0x%llx\n", g_oimr_override); + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)G_ipc_pend_tbl[IPC_PEND_PSTATE_START].cmd; + ipcmsg_start_stop_t* args = (ipcmsg_start_stop_t*)async_cmd->cmd_data; + + if (args->pmcr_owner == PMCR_OWNER_HOST) + { + G_pmcrOwner = PMCR_OWNER_HOST; + g_oimr_override &= ~(BIT64(46)); + out32(OCB_OIMR1_CLR, BIT32(14)); //Enable PCB_INTR_TYPE1 + } + else if (args->pmcr_owner == PMCR_OWNER_OCC) + { + G_pmcrOwner = PMCR_OWNER_OCC; + g_oimr_override |= BIT64(46); + out32(OCB_OIMR1_OR, BIT32(14)); //Disable PCB_INTR_TYPE1 + } + else if (args->pmcr_owner == PMCR_OWNER_CHAR) + { + G_pmcrOwner = PMCR_OWNER_CHAR; + g_oimr_override &= ~(BIT64(46)); + out32(OCB_OIMR1_CLR, BIT32(14)); //Enable PCB_INTR_TYPE1 + } + else + { + pk_halt(); + } + + PK_TRACE_DBG("ACT_TH: g_oimr_override:0x%llx\n", g_oimr_override); + //Set LMCR for each CME +#if !SIMICS_TUNING + + //8 Byte write to LMCR register in SIMICS results in error + //So, adding a build flag for SIMICS this out. Instead, in SIMICS set this through command line + for (q = 0; q < MAX_QUADS; q++) + { + if(G_quadState1->fields.requested_active_quad & (0x80 >> q)) + { + //CME0 within this quad + if (qcsr.fields.ex_config & (0x800 >> 2 * q)) + { + if (G_pmcrOwner == PMCR_OWNER_HOST) + { + GPE_PUTSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_LMCR_CLR, q, 0), BIT64(0)); + } + else if (G_pmcrOwner == PMCR_OWNER_OCC) + { + GPE_PUTSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_LMCR_OR, q, 0), BIT64(0)); + } + } + + //CME1 within this quad + if (qcsr.fields.ex_config & (0x400 >> 2 * q)) + { + if (G_pmcrOwner == PMCR_OWNER_HOST) + { + GPE_PUTSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_LMCR_CLR, q, 1), BIT64(0)); + } + else if (G_pmcrOwner == PMCR_OWNER_OCC) + { + GPE_PUTSCOM(GPE_SCOM_ADDR_CME(CME_SCOM_LMCR_OR, q, 1), BIT64(0)); + } + } + } + } + +#endif + + //6. Send Doorbell0 to every active CME by doing a multicast operation + // + //\TODO: Need Greg's Response + //Check if this is fine + //Slight deviation from Hcode Spec. PGPE sends DB0 to + //configured and active cores bc sibling CME reads DB register + //to set it's PMSR. They are not communicated by quad manager. + // + pgpe_db0_start_ps_bcast_t db0; + db0.value = 0; + db0.fields.msg_id = MSGID_DB0_START_PSTATE_BROADCAST; + db0.fields.global_actual = G_globalPSTarget; + db0.fields.quad0_ps = G_quadPSTarget[0]; + db0.fields.quad1_ps = G_quadPSTarget[1]; + db0.fields.quad2_ps = G_quadPSTarget[2]; + db0.fields.quad3_ps = G_quadPSTarget[3]; + db0.fields.quad4_ps = G_quadPSTarget[4]; + db0.fields.quad5_ps = G_quadPSTarget[5]; + p9_dd1_db_multicast_wr(PCB_MUTLICAST_GRP1 | CPPM_CMEDB0, db0.value, active_conf_cores); + PK_TRACE_DBG("ACT_TH: Mltcast DB0\n"); + p9_pgpe_wait_cme_db_ack(MSGID_DB0_START_PSTATE_BROADCAST, active_conf_cores);//Wait for ACKs from all QuadManagers + PK_TRACE_DBG("ACT_TH: DB0 ACKed\n"); + + //7. Enable PStates + G_pstatesEnabled = 1; + + //8. Send Pstate Start ACK to OCC + args->msg_cb.rc = PGPE_RC_SUCCESS; + G_ipc_pend_tbl[IPC_PEND_PSTATE_START].pending_ack = 0; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_PSTATE_START].cmd, IPC_RC_SUCCESS); + + pk_irq_vec_restore(&ctx); + PK_TRACE_DBG("ACT_TH: Start Exit\n"); +} + +// +//p9_pgpe_thread_actuate_stop() +// +void p9_pgpe_thread_actuate_stop() +{ + PK_TRACE_DBG("ACT_TH: Stop Enter\n"); + uint32_t q; + PkMachineContext ctx; + uint32_t active_conf_cores = 0; + ocb_qcsr_t qcsr; + qcsr.value = in32(OCB_QCSR); + + //Determine active and configured cores + for (q = 0; q < MAX_QUADS; q++) + { + if(G_quadState1->fields.requested_active_quad & (0x80 >> q)) + { + if (qcsr.fields.ex_config & (0x800 >> 2 * q)) + { + active_conf_cores |= (0xC0000000 >> q * 4); + } + + if (qcsr.fields.ex_config & (0x400 >> 2 * q)) + { + active_conf_cores |= (0x30000000 >> q * 4); + } + } + } + + pgpe_db0_stop_ps_bcast_t db0_stop; + db0_stop.value = 0; + db0_stop.fields.msg_id = MSGID_DB0_STOP_PSTATE_BROADCAST; + p9_dd1_db_multicast_wr(PCB_MUTLICAST_GRP1 | CPPM_CMEDB0, db0_stop.value, active_conf_cores); + + //Wait for ACKs from all CMEs + p9_pgpe_wait_cme_db_ack(MSGID_DB0_STOP_PSTATE_BROADCAST, active_conf_cores); + +#if SGPE_IPC_ENABLED == 1 + uint32_t rc; + //Send "Disable Core & Quad Stop Updates" IPC to SGPE + G_sgpe_control_updt.fields.return_code = 0x0; + G_sgpe_control_updt.fields.action = CTRL_STOP_UPDT_DISABLE_CORE_QUAD; + G_ipc_msg_pgpe_sgpe.cmd_data = &G_sgpe_control_updt; + ipc_init_msg(&G_ipc_msg_pgpe_sgpe.cmd, + IPC_MSGID_PGPE_SGPE_CONTROL_STOP_UPDATES, + p9_pgpe_pstate_ipc_rsp_cb_sem_post, + (void*)&G_pgpe_pstate_record.sem_sgpe_wait); + + //send the command + rc = ipc_send_cmd(&G_ipc_msg_pgpe_sgpe.cmd); + + if(rc) + { + pk_halt(); + } + + //Wait for SGPE ACK with alive Quads + pk_irq_vec_restore(&ctx); + pk_semaphore_pend(&(G_pgpe_pstate_record.sem_actuate), PK_WAIT_FOREVER); + + if (G_sgpe_control_updt.fields.return_code != SGPE_PGPE_IPC_RC_SUCCESS) + { + pk_halt(); + } + +#endif// _SGPE_IPC_ENABLED_ + + //Send STOP ACK to OCC + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)G_ipc_pend_tbl[IPC_PEND_PSTATE_STOP].cmd; + ipcmsg_start_stop_t* args = (ipcmsg_start_stop_t*)async_cmd->cmd_data; + args->msg_cb.rc = PGPE_RC_SUCCESS; + G_ipc_pend_tbl[IPC_PEND_PSTATE_STOP].pending_ack = 0; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_PSTATE_STOP].cmd, IPC_RC_SUCCESS); + + pk_irq_vec_restore(&ctx); + PK_TRACE_DBG("ACT_TH: Stop Exit\n"); +} + +// +//p9_pgpe_thread_actuate_do_step +// +void p9_pgpe_thread_actuate_do_step() +{ + PK_TRACE_DBG("ACT_TH: Step Entry\n"); + uint32_t q; + ocb_qcsr_t qcsr; + qcsr.value = in32(OCB_QCSR); + uint32_t active_conf_cores = 0; + uint32_t targetEVid = p9_pgpe_gppb_intp_vdd_from_ps(G_globalPSTarget, VPD_PT_SET_BIASED_SYSP, VPD_SLOPES_BIASED); + + //Determine active and configured cores + for (q = 0; q < MAX_QUADS; q++) + { + if(G_quadState1->fields.requested_active_quad & (0x80 >> q)) + { + if (qcsr.fields.ex_config & (0x800 >> 2 * q)) + { + active_conf_cores |= (0xC0000000 >> q * 4); + } + + if (qcsr.fields.ex_config & (0x400 >> 2 * q)) + { + active_conf_cores |= (0x30000000 >> q * 4); + } + } + } + + //Higher number PState + if (((int16_t)(G_globalPSTarget) - (int16_t)(G_globalPSCurr)) > 0) + { + if ((G_eVidCurr - targetEVid ) <= G_gppb->ext_vrm_step_size_mv) + { + G_eVidNext = targetEVid; + G_globalPSNext = G_globalPSTarget; + + for (q = 0; q < MAX_QUADS; q++) + { + G_quadPSNext[q] = G_quadPSTarget[q]; + } + } + else + { + G_eVidNext = G_eVidCurr - G_gppb->ext_vrm_step_size_mv; + G_globalPSNext = p9_pgpe_gppb_intp_ps_from_ext_vdd(G_eVidNext); + + for (q = 0; q < MAX_QUADS; q++) + { + if (G_quadPSTarget[q] > G_globalPSNext) //Keep localPS under GlobalPS + { + G_quadPSNext[q] = G_globalPSNext; + } + else + { + G_quadPSNext[q] = G_quadPSTarget[q]; + } + } + } + + p9_pgpe_thread_actuate_freq_updt(active_conf_cores); + p9_pgpe_thread_actuate_updt_ext_volt(targetEVid); + } + //Lower number PState + else if (((int16_t)(G_globalPSTarget) - (int16_t)(G_globalPSCurr)) < 0) + { + if ((targetEVid - G_eVidCurr) <= G_gppb->ext_vrm_step_size_mv) + { + G_eVidNext = targetEVid; + G_globalPSNext = G_globalPSTarget; + + for (q = 0; q < MAX_QUADS; q++) + { + G_quadPSNext[q] = G_quadPSTarget[q]; + } + } + else + { + G_eVidNext = G_eVidCurr + G_gppb->ext_vrm_step_size_mv; + G_globalPSNext = p9_pgpe_gppb_intp_ps_from_ext_vdd(G_eVidNext); + + for (q = 0; q < MAX_QUADS; q++) + { + if (G_quadPSTarget[q] < G_globalPSNext) //Keep localPS under GlobalPS + { + G_quadPSNext[q] = G_globalPSNext; + } + else + { + G_quadPSNext[q] = G_quadPSTarget[q]; + } + } + } + + p9_pgpe_thread_actuate_updt_ext_volt(targetEVid); + p9_pgpe_thread_actuate_freq_updt(active_conf_cores); + } + else + { + for (q = 0; q < MAX_QUADS; q++) + { + G_quadPSNext[q] = G_quadPSTarget[q]; + } + + p9_pgpe_thread_actuate_freq_updt(active_conf_cores); + } + + //Update current + G_globalPSCurr = G_globalPSNext; + + for (q = 0; q < MAX_QUADS; q++) + { + if(G_quadState1->fields.requested_active_quad & (0x80 >> q) && + (qcsr.fields.ex_config & (0xC00 >> 2 * q))) + { + G_quadPSCurr[q] = G_quadPSNext[q]; + } + } + + //Update Shared SRAM + G_quadState0->fields.quad0_pstate = G_quadPSCurr[0]; + G_quadState0->fields.quad1_pstate = G_quadPSCurr[1]; + G_quadState0->fields.quad2_pstate = G_quadPSCurr[2]; + G_quadState0->fields.quad3_pstate = G_quadPSCurr[3]; + G_quadState1->fields.quad4_pstate = G_quadPSCurr[4]; + G_quadState1->fields.quad5_pstate = G_quadPSCurr[5]; + + PK_TRACE_DBG("ACT_TH: Step Exit\n"); +} + +// +//p9_pgpe_thread_actuate_updt_ext_volt +// +//Update External VRM to G_eVidNext +void p9_pgpe_thread_actuate_updt_ext_volt(uint32_t tgtEVid) +{ +#if !EPM_P9_TUNING + uint32_t delay_us; + + //Decreasing + if (G_eVidNext < G_eVidCurr) + { + delay_us = (G_eVidCurr - G_eVidNext) * + G_ext_vrm_dec_rate_mult_usperus; + } + //Increasing + else if(G_eVidNext > G_eVidCurr) + { + delay_us = (G_eVidNext - G_eVidCurr) * + G_ext_vrm_inc_rate_mult_usperus; + } + +#endif + + //Update external voltage + external_voltage_control_write(G_eVidNext); + +#if !EPM_P9_TUNING + + //Delay for delay_us + if (delay_us > 0) + { + pk_sleep(PK_MICROSECONDS((delay_us))); + } + + if(G_eVidNext == tgtEVid) + { + pk_sleep(PK_MICROSECONDS((G_gppd->ext_vrm_stabilization_time_us))); + } + +#endif + + G_eVidCurr = G_eVidNext; +} + +// +//Frequency Update +// +//Sends a DB0 to all active CMEs, so that Quad Managers(CMEs) update DPLL +void p9_pgpe_thread_actuate_freq_updt(uint32_t activeCores) +{ + PK_TRACE_DBG("ACT_TH: Freq Updt Enter\n"); + pgpe_db0_glb_bcast_t db0; + db0.value = 0; + db0.fields.msg_id = MSGID_DB0_GLOBAL_ACTUAL_BROADCAST; + db0.fields.global_actual = G_globalPSNext; + db0.fields.quad0_ps = G_quadPSNext[0]; + db0.fields.quad1_ps = G_quadPSNext[1]; + db0.fields.quad2_ps = G_quadPSNext[2]; + db0.fields.quad3_ps = G_quadPSNext[3]; + db0.fields.quad4_ps = G_quadPSNext[4]; + db0.fields.quad5_ps = G_quadPSNext[5]; + p9_dd1_db_multicast_wr(PCB_MUTLICAST_GRP1 | CPPM_CMEDB0, db0.value, activeCores); + p9_pgpe_wait_cme_db_ack(MSGID_DB0_GLOBAL_ACTUAL_BROADCAST, activeCores);//Wait for ACKs from all CMEs + PK_TRACE_DBG("ACT_TH: Freq Updt Exit\n"); +} + + +// +//Wait for CME to ack DB0 +// +void p9_pgpe_wait_cme_db_ack(uint8_t msg_id, uint32_t active_conf_cores) +{ + int32_t c, q; + uint32_t opit4pr; + uint8_t pendingAcks = 0; + uint8_t quadPendDBAck[MAX_QUADS]; + + for (q = 0; q < MAX_QUADS; q++) + { + if (active_conf_cores & (0xF0000000 >> (q * 4))) + { + quadPendDBAck[q] = 1; + } + else + { + quadPendDBAck[q] = 0; + } + } + + //Wait for all the acks to come + pendingAcks = 1; + + while (pendingAcks) + { + //Process acks + opit4pr = in32(OCB_OPIT4PRA); + + for (c = 0; c < MAX_CORES; c++) + { + if (opit4pr & (CCSR_CORE_CONFIG_MASK >> c)) + { + if (quadPendDBAck[QUAD_FROM_CORE(c)]) + { + quadPendDBAck[QUAD_FROM_CORE(c)] = 0; + out32(OCB_OPIT4PRA_CLR, CCSR_CORE_CONFIG_MASK >> c); //Clear out pending bits + } + else + { + pk_halt(); + } + } + } + + //Check if any pending left + pendingAcks = 0; + + for (q = 0; q < MAX_QUADS; q++) + { + if (quadPendDBAck[q]) + { + pendingAcks = 1; + } + } + } +} + + + + +void p9_pgpe_thread_actuate_init_actual_quad() +{ + G_quadState0->fields.quad0_pstate = 0xff; + G_quadState0->fields.quad1_pstate = 0xff; + G_quadState0->fields.quad2_pstate = 0xff; + G_quadState0->fields.quad3_pstate = 0xff; + G_quadState0->fields.core_poweron_state = 0; + + G_quadState1->fields.quad4_pstate = 0xff; + G_quadState1->fields.quad5_pstate = 0xff; + G_quadState1->fields.core_poweron_state = 0x0; + G_quadState1->fields.requested_active_quad = 0x0; +} 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 new file mode 100644 index 00000000..a800ab97 --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_process_requests.c @@ -0,0 +1,574 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_thread_process_requests.c $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2016,2017 */ +/* [+] 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 */ +#include "p9_pgpe.h" +#include "gpehw_common.h" +#include "p9_pgpe_pstate.h" +#include "pstate_pgpe_occ_api.h" +//#include "pstate_pgpe_sgpe_api.h" +#include "ipc_messages.h" +#include "ipc_api.h" +#include "ipc_async_cmd.h" +#include "p9_pgpe_header.h" + +// +//External Global Data +// +extern PgpePstateRecord G_pgpe_pstate_record; +extern pgpe_header_data_t* G_pgpe_header_data; +extern uint8_t G_pstatesEnabled; //pstates_enabled/disable +extern uint8_t G_wofEnabled; //pstates_enabled/disable +extern uint8_t G_wofPending; //wof enable pending +extern VFRT_Hcode_t* G_vfrt_ptr; +extern ipc_req_t G_ipc_pend_tbl[MAX_IPC_PEND_TBL_ENTRIES]; +extern uint8_t G_psClipMax[MAX_QUADS], + G_psClipMin[MAX_QUADS]; //pmin and pmax clips +extern uint8_t G_coresPSRequest[MAX_CORES]; //per core requested pstate +extern uint32_t G_already_sem_posted; +extern quad_state0_t* G_quadState0; +extern quad_state1_t* G_quadState1; +extern pgpe_header_data_t* G_pgpe_header_data; +extern ipc_async_cmd_t G_ipc_msg_pgpe_sgpe; +GPE_BUFFER(extern ipcmsg_p2s_ctrl_stop_updates_t G_sgpe_control_updt); + +// +//Local Function Prototypes +// +void p9_pgpe_process_sgpe_updt_active_cores(); +void p9_pgpe_process_sgpe_updt_active_quads(); +void p9_pgpe_process_clip_updt(); +void p9_pgpe_process_wof_ctrl(); +void p9_pgpe_process_wof_vfrt(); +void p9_pgpe_process_set_pmcr_req(); + +// +//Process Request Thread +// +void p9_pgpe_thread_process_requests(void* arg) +{ + PK_TRACE_DBG("PROCTH:Started\n"); + + uint32_t restore_irq; + PkMachineContext ctx; + + //Initialization + pk_semaphore_create(&(G_pgpe_pstate_record.sem_process_req), 0, 1); + + //IPC Init + p9_pgpe_ipc_init(); + + //Set OCC_FLAG[PGPE_ACTIVE] + out32(OCB_OCCFLG_OR, BIT32(4)); +#if EPM_P9_TUNING + asm volatile ("tw 0, 31, 0"); +#endif + + PK_TRACE_DBG("PROCTH:Inited\n"); + + while(1) + { + //pend on semaphore + pk_semaphore_pend(&(G_pgpe_pstate_record.sem_process_req), PK_WAIT_FOREVER); + wrteei(1); + + G_already_sem_posted = 0; + restore_irq = 1; + + PK_TRACE_DBG("PROCTH: Process Task\n"); + + //Go through IPC Pending Table + if (G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].pending_processing) + { + p9_pgpe_process_sgpe_updt_active_cores(); + + if(G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].pending_ack == 1) + { + restore_irq = 0; + } + } + + if (G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].pending_processing) + { + p9_pgpe_process_sgpe_updt_active_quads(); + + if(G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].pending_ack == 1) + { + restore_irq = 0; + } + } + + if (G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].pending_processing) + { + p9_pgpe_process_clip_updt(); + + if(G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].pending_ack == 1) + { + restore_irq = 0; + } + } + + if (G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].pending_processing) + { + p9_pgpe_process_wof_ctrl(); + + if(G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].pending_ack == 1) + { + restore_irq = 0; + } + } + + if (G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].pending_processing) + { + p9_pgpe_process_wof_vfrt(); + + if(G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].pending_ack == 1) + { + restore_irq = 0; + } + } + + if (G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].pending_processing) + { + p9_pgpe_process_set_pmcr_req(); + + if(G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].pending_ack == 1) + { + restore_irq = 0; + } + } + + //Pstate START/STOP IPCs are processed and acked in actuate thread, + //so don't call pk_irq_vec_restore if they are pending. + if(G_ipc_pend_tbl[IPC_PEND_PSTATE_STOP].pending_ack == 1 || + G_ipc_pend_tbl[IPC_PEND_PSTATE_STOP].pending_ack == 1 ) + { + restore_irq = 0; + } + + //Restore IPC if no pending acks. Otherwise, actuate thread will + //eventuall restore IPC interrupt + if (restore_irq == 1) + { + PK_TRACE_DBG("PROCTH: IRQ Restore\n"); + pk_irq_vec_restore(&ctx); + } + } +} + +// +//p9_pgpe_process_sgpe_updt_active_cores +// +void p9_pgpe_process_sgpe_updt_active_cores() +{ + PK_TRACE_DBG("PROCTH: Core Updt Entry\n"); + + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].cmd; + ipcmsg_s2p_update_active_cores_t* args = (ipcmsg_s2p_update_active_cores_t*)async_cmd->cmd_data; + + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].pending_processing = 0; + + //Active core updates should only be received if both + //Pstate and WOF are enabled + if(G_pstatesEnabled == 0 || G_wofEnabled == 0) + { + if(G_pstatesEnabled == 0) + { + args->fields.return_code = PGPE_RC_PSTATES_DISABLED; + } + else + { + args->fields.return_code = PGPE_WOF_RC_NOT_ENABLED; + } + + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].pending_ack = 0; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].cmd, IPC_RC_SUCCESS); + } + else + { + + //Update Shared Memory Region + G_quadState0->fields.core_poweron_state = (args->fields.active_cores >> 8); + G_quadState1->fields.core_poweron_state = (args->fields.active_cores & 0xFF) << 8; + + //Do auction + p9_pgpe_pstate_do_auction(ALL_QUADS_BIT_MASK); + + //If entry type then send ACK to SGPE immediately + //Otherwise, wait to ACK until WOF Clip has been applied(from actuate_pstate thread) + if (args->fields.update_type == UPDATE_ACTIVE_TYPE_ENTRY) + { + args->fields.return_code = PGPE_RC_SUCCESS; + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].pending_ack = 0; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_CORES_UPDT].cmd, IPC_RC_SUCCESS); + } + + p9_pgpe_pstate_calc_wof(); + } + + PK_TRACE_DBG("PROCTH: Core Updt Exit\n"); +} + +// +//p9_pgpe_process_sgpe_updt_active_quads +// +void p9_pgpe_process_sgpe_updt_active_quads() +{ + PK_TRACE_DBG("PROCTH: Quad Updt Entry\n"); + + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].cmd; + ipcmsg_s2p_update_active_quads_t* args = (ipcmsg_s2p_update_active_quads_t*)async_cmd->cmd_data; + + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].pending_processing = 0; + + //Active quad updates should only be received if Pstates are enabled + if(G_pstatesEnabled == 0) + { + args->fields.return_code = PGPE_RC_PSTATES_DISABLED; + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].pending_ack = 0; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].cmd, IPC_RC_SUCCESS); + } + else + { + //Update Shared Memory Region + G_quadState1->fields.requested_active_quad = args->fields.requested_quads; + + //Do auction + p9_pgpe_pstate_do_auction(ALL_QUADS_BIT_MASK); + + if(G_wofEnabled == 1) + { + //Set OCCFLG[REQUESTED_ACTIVE_QUAD_UPDATE] + GPE_PUTSCOM(OCB_OCCFLG_OR, BIT32(30)); + + //If entry type then send ACK to SGPE immediately + //Otherwise, wait to ACK until WOF-VFRT updated is received from OCC + if (args->fields.update_type == UPDATE_ACTIVE_TYPE_ENTRY) + { + args->fields.return_code = PGPE_RC_SUCCESS; + G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].pending_ack = 0; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_SGPE_ACTIVE_QUADS_UPDT].cmd, IPC_RC_SUCCESS); + } + } + else + { + p9_pgpe_pstate_apply_clips(); + } + } + + PK_TRACE_DBG("PROCTH: Quad Updt Exit\n"); +} + +// +//p9_pgpe_process_clip_updt +// +void p9_pgpe_process_clip_updt() +{ + PK_TRACE_DBG("PROCTH: Clip Updt Entry\n"); + + uint32_t q; + uint32_t rc; + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].cmd; + ipcmsg_clip_update_t* args = (ipcmsg_clip_update_t*)async_cmd->cmd_data; + + G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].pending_processing = 0; + + if(G_pgpe_header_data->pgpeflags & OCC_IPC_IMMEDIATE_RESP) + { + PK_TRACE_DBG("PROCTH: Clip Updt Imme\n"); + G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].pending_ack = 0; + args->msg_cb.rc = PGPE_RC_SUCCESS; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].cmd, IPC_RC_SUCCESS); + } + else + { + + for (q = 0; q < MAX_QUADS; q++) + { + G_psClipMax[q] = args->ps_val_clip_max[q]; + G_psClipMin[q] = args->ps_val_clip_min[q]; + } + + p9_pgpe_pstate_apply_clips(&G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT]); + + if (G_pstatesEnabled == 0) + { + args->msg_cb.rc = PGPE_RC_SUCCESS; + G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].pending_ack = 0; + rc = ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_CLIP_UPDT].cmd, IPC_RC_SUCCESS); + + if (rc != IPC_RC_SUCCESS) + { + pk_halt(); + } + else + { + PK_TRACE_DBG("PROCTH: Clip Upd Acked\n"); + } + } + } + + PK_TRACE_DBG("PROCTH: Clip Upd Exit\n"); +} + +// +//p9_pgpe_process_wof_ctrl +// +void p9_pgpe_process_wof_ctrl() +{ + PK_TRACE_DBG("PROCTH: WOF Ctrl Enter\n"); + + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].cmd; + ipcmsg_wof_control_t* args = (ipcmsg_wof_control_t*)async_cmd->cmd_data; + + G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].pending_processing = 0; + + if(G_pgpe_header_data->pgpeflags & OCC_IPC_IMMEDIATE_RESP) + { + G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].pending_ack = 0; + args->msg_cb.rc = PGPE_RC_SUCCESS; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].cmd, IPC_RC_SUCCESS); + } + else + { + if(G_pstatesEnabled == 0 ) + { + args->msg_cb.rc = PGPE_RC_PSTATES_DISABLED; + G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].pending_ack = 0; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].cmd, IPC_RC_SUCCESS); + } + else + { + //If WOF ON + if (args->action == PGPE_ACTION_WOF_ON) + { + if(G_wofEnabled == 1) + { + G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].pending_ack = 0; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].cmd, IPC_RC_SUCCESS); + } + else + { + G_wofPending = 1; + } + } + else if (args->action == PGPE_ACTION_WOF_OFF) + { + if(G_wofEnabled == 0) + { + G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].pending_ack = 0; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_WOF_CTRL].cmd, IPC_RC_SUCCESS); + } + else + { +#if SGPE_IPC_ENABLED == 1 + uint32_t rc; + PkMachineContext ctx; + //Send "Disable Core Stop Updates" IPC to SGPE + G_sgpe_control_updt.fields.return_code = 0x0; + G_sgpe_control_updt.fields.action = CTRL_STOP_UPDT_DISABLE_CORE; + G_ipc_msg_pgpe_sgpe.cmd_data = &G_sgpe_control_updt; + ipc_init_msg(&G_ipc_msg_pgpe_sgpe.cmd, + IPC_MSGID_PGPE_SGPE_CONTROL_STOP_UPDATES, + p9_pgpe_pstate_ipc_rsp_cb_sem_post, + (void*)&G_pgpe_pstate_record.sem_sgpe_wait); + + //send the command + rc = ipc_send_cmd(&G_ipc_msg_pgpe_sgpe.cmd); + + if(rc) + { + pk_halt(); + } + + //Wait for SGPE ACK with alive Quads + pk_irq_vec_restore(&ctx); + pk_semaphore_pend(&(G_pgpe_pstate_record.sem_actuate), PK_WAIT_FOREVER); + + if (G_sgpe_control_updt.fields.return_code == SGPE_PGPE_IPC_RC_SUCCESS) + { + //Update Shared Memory Region + G_quadState0->fields.core_poweron_state = G_sgpe_control_updt.fields.active_cores >> 8; + G_quadState1->fields.core_poweron_state = G_sgpe_control_updt.fields.active_cores & 0xFF; + G_quadState1->fields.requested_active_quad = G_sgpe_control_updt.fields.active_quads; + } + else + { + pk_halt(); + } + +#endif// _SGPE_IPC_ENABLED_ + } + } + } + } + + PK_TRACE_DBG("PROCTH: WOF Ctrl Exit\n"); +} + +// +//p9_pgpe_process_wof_vfrt +// +void p9_pgpe_process_wof_vfrt() +{ + PK_TRACE_DBG("PROCTH: WOF VFRT Enter\n"); + + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].cmd; + ipcmsg_wof_vfrt_t* args = (ipcmsg_wof_vfrt_t*)async_cmd->cmd_data; + + G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].pending_processing = 0; + + if(G_pgpe_header_data->pgpeflags & OCC_IPC_IMMEDIATE_RESP) + { + G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].pending_ack = 0; + args->msg_cb.rc = PGPE_RC_SUCCESS; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].cmd, IPC_RC_SUCCESS); + } + else + { + if(G_pstatesEnabled == 0 || (G_wofEnabled == 0 && G_wofPending == 0)) + { + G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].pending_ack = 0; + args->msg_cb.rc = PGPE_RC_PSTATES_DISABLED; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].cmd, IPC_RC_SUCCESS); + } + else + { + //Update VFRT pointer + G_vfrt_ptr = args->vfrt_ptr; + + //If active_quads field of this IPC matches requested active quads + //in Shared SRAM, then clear OCCFLG[REQUESTED_ACTIVE_QUAD_UPDATE] + if (args->active_quads == G_quadState1->fields.requested_active_quad) + { + GPE_PUTSCOM(OCB_OCCFLG_CLR, BIT32(30)); + p9_pgpe_pstate_calc_wof(); + } + + if (G_wofPending == 1) + { + G_wofEnabled = 1; + G_wofPending = 0; + +#if SGPE_IPC_ENABLED == 1 + uint32_t rc; + PkMachineContext ctx; + //Send "Disable Core Stop Updates" IPC to SGPE + G_sgpe_control_updt.fields.return_code = 0x0; + G_sgpe_control_updt.fields.action = CTRL_STOP_UPDT_DISABLE_CORE; + G_ipc_msg_pgpe_sgpe.cmd_data = &G_sgpe_control_updt; + ipc_init_msg(&G_ipc_msg_pgpe_sgpe.cmd, + IPC_MSGID_PGPE_SGPE_CONTROL_STOP_UPDATES, + p9_pgpe_pstate_ipc_rsp_cb_sem_post, + (void*)&G_pgpe_pstate_record.sem_sgpe_wait); + + //send the command + rc = ipc_send_cmd(&G_ipc_msg_pgpe_sgpe.cmd); + + if(rc) + { + pk_halt(); + } + + //Wait for SGPE ACK with alive Quads + pk_irq_vec_restore(&ctx); + pk_semaphore_pend(&(G_pgpe_pstate_record.sem_actuate), PK_WAIT_FOREVER); + + if (G_sgpe_control_updt.fields.return_code == SGPE_PGPE_IPC_RC_SUCCESS) + { + //Update Shared Memory Region + G_quadState0->fields.core_poweron_state = G_sgpe_control_updt.fields.active_cores >> 8; + G_quadState1->fields.core_poweron_state = G_sgpe_control_updt.fields.active_cores & 0xFF; + G_quadState1->fields.requested_active_quad = G_sgpe_control_updt.fields.active_quads; + } + else + { + pk_halt(); + } + +#endif// _SGPE_IPC_ENABLED_ + } + + G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].pending_ack = 0; + args->msg_cb.rc = PGPE_RC_SUCCESS; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_WOF_VFRT].cmd, IPC_RC_SUCCESS); + } + } + + PK_TRACE_DBG("PROCTH: WOF VFRT Exit\n"); +} + +// +//p9_pgpe_process_set_pmcr_req +// +void p9_pgpe_process_set_pmcr_req() +{ + PK_TRACE_DBG("PROCTH: Set PMCR Enter\n"); + + uint32_t q, c; + ipc_async_cmd_t* async_cmd = (ipc_async_cmd_t*)G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].cmd; + ipcmsg_set_pmcr_t* args = (ipcmsg_set_pmcr_t*)async_cmd->cmd_data; + + G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].pending_processing = 0; + + if(G_pgpe_header_data->pgpeflags & OCC_IPC_IMMEDIATE_RESP) + { + G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].pending_ack = 0; + args->msg_cb.rc = PGPE_RC_SUCCESS; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].cmd, IPC_RC_SUCCESS); + } + else + { + if (G_pstatesEnabled == 0 ) + { + PK_TRACE_DBG("PROCTH: Pstates Disabled\n"); + args->msg_cb.rc = PGPE_RC_PSTATES_DISABLED; + G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].pending_ack = 0; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].cmd, IPC_RC_SUCCESS); + } + else + { + PK_TRACE_DBG("PROCTH: Upd coresPSReq\n"); + + for (q = 0; q < MAX_QUADS; q++) + { + for (c = (q * CORES_PER_QUAD); c < (q + 1)*CORES_PER_QUAD; c++) + { + G_coresPSRequest[c] = (args->pmcr[q] >> 48) & 0x00FF; + } + + PK_TRACE_DBG("PROCTH: coresPSReq: 0x%x\n", G_coresPSRequest[q * CORES_PER_QUAD]); + } + + p9_pgpe_pstate_do_auction(ALL_QUADS_BIT_MASK); + p9_pgpe_pstate_apply_clips(); + + //Send ACK to OCC + G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].pending_ack = 0; + args->msg_cb.rc = PGPE_RC_SUCCESS; + ipc_send_rsp(G_ipc_pend_tbl[IPC_PEND_SET_PMCR_REQ].cmd, IPC_RC_SUCCESS); + } + } + + PK_TRACE_DBG("PROCTH: Set PMCR Exit\n"); +} diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pk_app_cfg.h b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pk_app_cfg.h index c6e5b84a..818abb00 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pk_app_cfg.h +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/pk_app_cfg.h @@ -38,9 +38,12 @@ #define EPM_P9_TUNING 1 #define SIMICS_TUNING 0 #define GEN_PSTATE_TBL 0 -#define MIMIC_BOOT_TEMP 1 +#define USE_BOOT_TEMP 1 +#define BOOT_TEMP_SET_FULL_OCC_IPC_FUNC 1 #define DEV_DEBUG 1 +#define PGPE_UNIT_TEST 1 #define PK_TRACE_TIMER_OUTPUT 0 +#define SGPE_IPC_ENABLED 0 ///This application uses IPC code #define GLOBAL_CFG_USE_IPC @@ -66,6 +69,29 @@ #endif /* APPCFG_USE_EXT_TIMEBASE */ // -------------------- +#if PK_TRACE_LEVEL == 0 /*No TRACEs*/ + #define PK_TRACE_ENABLE 0 + #define PK_KERNEL_TRACE_ENABLE 0 +#elif PK_TRACE_LEVEL == 1 /*only PK_TRACE_INF*/ + #define PK_TRACE_ENABLE 1 + #define PK_TRACE_DBG_SUPPRESS 1 + #define PK_TRACE_CRIT_ENABLE 1 + #define PK_TRACE_CKPT_ENABLE 0 + #define PK_KERNEL_TRACE_ENABLE 0 +#elif PK_TRACE_LEVEL == 2 /*only PK_TRACE_INF+DBG+KERNEL*/ + #define PK_TRACE_ENABLE 1 + #define PK_TRACE_DBG_SUPPRESS 1 + #define PK_TRACE_CRIT_ENABLE 1 + #define PK_TRACE_CKPT_ENABLE 1 + #define PK_KERNEL_TRACE_ENABLE 1 +#else /*All TRACEs*/ + #define PK_TRACE_ENABLE 1 + #define PK_TRACE_DBG_SUPPRESS 0 + #define PK_TRACE_CRIT_ENABLE 1 + #define PK_TRACE_CKPT_ENABLE 1 + #define PK_KERNEL_TRACE_ENABLE 1 +#endif + // GPE2 is the PGPE and is the route owner for now. // (Change this to #3 when pulling in SGPE) @@ -97,6 +123,6 @@ OCCHW_IRQ_CHECK_STOP_GPE2 OCCHW_IRQ_TYPE_EDGE OCCHW_IRQ_POLARITY_RISING OCCHW_IRQ_MASKED \ OCCHW_IRQ_IPI2_HI_PRIORITY OCCHW_IRQ_TYPE_EDGE OCCHW_IRQ_POLARITY_RISING OCCHW_IRQ_MASKED \ OCCHW_IRQ_IPI2_LO_PRIORITY OCCHW_IRQ_TYPE_EDGE OCCHW_IRQ_POLARITY_RISING OCCHW_IRQ_MASKED \ - OCCHW_IRQ_PMC_PCB_INTR_TYPE1_PENDING OCCHW_IRQ_TYPE_LEVEL OCCHW_IRQ_POLARITY_HI OCCHW_IRQ_MASKED \ + OCCHW_IRQ_PMC_PCB_INTR_TYPE1_PENDING OCCHW_IRQ_TYPE_LEVEL OCCHW_IRQ_POLARITY_HI OCCHW_IRQ_MASKED \ OCCHW_IRQ_PMC_PCB_INTR_TYPE4_PENDING OCCHW_IRQ_TYPE_LEVEL OCCHW_IRQ_POLARITY_HI OCCHW_IRQ_MASKED #endif /*__PK_APP_CFG_H__*/ 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 7fc5607c..73eee021 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 @@ -79,6 +79,11 @@ OBJS+=$(TOP_OBJECTS) $(IMAGE)_TRACE_HASH_PREFIX := $(shell echo $(IMAGE) | md5sum | cut -c1-4 \ | xargs -i printf "%d" 0x{}) +# Options for PK_TRACE +$(IMAGE)_COMMONFLAGS+= -DPK_TRACE_LEVEL=0 +$(IMAGE)_COMMONFLAGS+= -DPK_TRACE_TIMER_OUTPUT=0 + + #Note: Flags are resolved very late - so local variables can't be # used to build them $(IMAGE)_COMMONFLAGS+= -DPK_TIMER_SUPPORT=1 diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/topfiles.mk b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/topfiles.mk index 74711295..a21c605e 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/topfiles.mk +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/topfiles.mk @@ -31,8 +31,12 @@ TOP-C-SOURCES = p9_pgpe_pstate.c \ p9_pgpe_gppb.c \ p9_pgpe_gen_pstate_info.c \ p9_pgpe_header.c \ - p9_pgpe_ipc.c \ - ipc_func_tables.c + ipc_func_tables.c \ + p9_pgpe_thread_actuate_pstates.c \ + p9_pgpe_thread_process_requests.c \ + p9_pgpe_ipc_handlers.c \ + p9_pgpe_irq_handlers.c + TOP-S-SOURCES = TOP_OBJECTS = $(TOP-C-SOURCES:.c=.o) $(TOP-S-SOURCES:.S=.o) -- cgit v1.2.3