diff options
| author | Rahul Batra <rbatra@us.ibm.com> | 2016-07-15 16:54:45 -0500 |
|---|---|---|
| committer | Joshua Hunsberger <jahunsbe@us.ibm.com> | 2017-10-23 16:30:34 -0500 |
| commit | 336fd618d1bc9daa00d6151ba020966013cf1775 (patch) | |
| tree | e16ddc1e8f28226b0d5280b29ff15a6c0c58e9e5 | |
| parent | 4c7a55edb33fe9198f99f5bcfacf75c8a04b6ca8 (diff) | |
| download | talos-hcode-336fd618d1bc9daa00d6151ba020966013cf1775.tar.gz talos-hcode-336fd618d1bc9daa00d6151ba020966013cf1775.zip | |
PState Initial Drop
Change-Id: I5dedbd16a9ec1d9c698e26e562f833a2c61eb31a
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/27116
Reviewed-by: Douglas R. Gilbert <dgilbert@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Reviewed-by: Gregory S. Still <stillgs@us.ibm.com>
17 files changed, 1789 insertions, 987 deletions
diff --git a/import/chips/p9/procedures/ppe_closed/cme/p9_cme_irq.c b/import/chips/p9/procedures/ppe_closed/cme/p9_cme_irq.c index b670ea59..375724c8 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/p9_cme_irq.c +++ b/import/chips/p9/procedures/ppe_closed/cme/p9_cme_irq.c @@ -52,7 +52,9 @@ const uint64_t ext_irq_vectors_cme[NUM_EXT_IRQ_PRTY_LEVELS][2] = /* 0: IDX_PRTY_VEC 1: IDX_MASK_VEC */ { IRQ_VEC_PRTY0_CME, - IRQ_VEC_PRTY6_CME | /* 0: IDX_PRTY_LVL_HIPRTY */ + IRQ_VEC_PRTY8_CME | /* 0: IDX_PRTY_LVL_HIPRTY */ + IRQ_VEC_PRTY7_CME | + IRQ_VEC_PRTY6_CME | IRQ_VEC_PRTY5_CME | IRQ_VEC_PRTY4_CME | IRQ_VEC_PRTY3_CME | @@ -62,7 +64,9 @@ const uint64_t ext_irq_vectors_cme[NUM_EXT_IRQ_PRTY_LEVELS][2] = }, { IRQ_VEC_PRTY1_CME, - IRQ_VEC_PRTY6_CME | /* 1: IDX_PRTY_LVL_BCE_DB3 */ + IRQ_VEC_PRTY8_CME | /* 1: IDX_PRTY_LVL_BCE_DB3 */ + IRQ_VEC_PRTY7_CME | + IRQ_VEC_PRTY6_CME | IRQ_VEC_PRTY5_CME | IRQ_VEC_PRTY4_CME | IRQ_VEC_PRTY3_CME | @@ -71,7 +75,9 @@ const uint64_t ext_irq_vectors_cme[NUM_EXT_IRQ_PRTY_LEVELS][2] = }, { IRQ_VEC_PRTY2_CME, - IRQ_VEC_PRTY6_CME | /* 2: IDX_PRTY_LVL_WAKE_DB2 */ + IRQ_VEC_PRTY8_CME | /* 2: IDX_PRTY_LVL_WAKE_DB2 */ + IRQ_VEC_PRTY7_CME | + IRQ_VEC_PRTY6_CME | IRQ_VEC_PRTY5_CME | IRQ_VEC_PRTY4_CME | IRQ_VEC_PRTY3_CME | @@ -79,26 +85,44 @@ const uint64_t ext_irq_vectors_cme[NUM_EXT_IRQ_PRTY_LEVELS][2] = }, { IRQ_VEC_PRTY3_CME, - IRQ_VEC_PRTY6_CME | /* 3: IDX_PRTY_LVL_STOP */ + IRQ_VEC_PRTY8_CME | /* 3: IDX_PRTY_LVL_STOP */ + IRQ_VEC_PRTY7_CME | + IRQ_VEC_PRTY6_CME | IRQ_VEC_PRTY5_CME | IRQ_VEC_PRTY4_CME | IRQ_VEC_PRTY3_CME }, { IRQ_VEC_PRTY4_CME, - IRQ_VEC_PRTY6_CME | /* 4: IDX_PRTY_LVL_DB1 */ + IRQ_VEC_PRTY8_CME | /* 4: IDX_PRTY_LVL_DB1 */ + IRQ_VEC_PRTY7_CME | + IRQ_VEC_PRTY6_CME | IRQ_VEC_PRTY5_CME | IRQ_VEC_PRTY4_CME }, { IRQ_VEC_PRTY5_CME, - IRQ_VEC_PRTY6_CME | /* 5: IDX_PRTY_LVL_PMCR_DB0 */ + IRQ_VEC_PRTY8_CME | /* 5: IDX_PRTY_LVL_DB0 */ + IRQ_VEC_PRTY7_CME | + IRQ_VEC_PRTY6_CME | IRQ_VEC_PRTY5_CME }, { IRQ_VEC_PRTY6_CME, - IRQ_VEC_PRTY6_CME /* 6: IDX_PRTY_LVL_DISABLED */ + IRQ_VEC_PRTY8_CME | /* 6: IDX_PRTY_LVL_INTERCME_IN0 */ + IRQ_VEC_PRTY7_CME | + IRQ_VEC_PRTY6_CME + }, + { + IRQ_VEC_PRTY7_CME, + IRQ_VEC_PRTY8_CME | /* 7: IDX_PRTY_LVL_PMCR */ + IRQ_VEC_PRTY7_CME + }, + { + IRQ_VEC_PRTY8_CME, + IRQ_VEC_PRTY8_CME /* 8: IDX_PRTY_LVL_DISABLED */ } + }; uint8_t g_current_prty_level = NUM_EXT_IRQ_PRTY_LEVELS - 1; @@ -178,6 +202,5 @@ void pk_unified_irq_prty_mask_handler(void) //l_vecL = 0; asm volatile ("lvd %[data], 0(%[addr]) \n" \ : [data]"=r"(l_vecH) \ - : [addr]"r"(&ext_irq_vector_pk) ); - + : [addr]"r"(&(ext_irq_vectors_cme[iPrtyLvl][IDX_PRTY_VEC])) ); } diff --git a/import/chips/p9/procedures/ppe_closed/cme/p9_cme_irq.h b/import/chips/p9/procedures/ppe_closed/cme/p9_cme_irq.h index 2a9729fe..45fc7a21 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/p9_cme_irq.h +++ b/import/chips/p9/procedures/ppe_closed/cme/p9_cme_irq.h @@ -64,16 +64,18 @@ #define FALSE 0 // Priority Levels -#define IDX_PRTY_LVL_HIPRTY 0 -#define IDX_PRTY_LVL_BCE_DB3 1 -#define IDX_PRTY_LVL_WAKE_DB2 2 -#define IDX_PRTY_LVL_STOP 3 -#define IDX_PRTY_LVL_DB1 4 -#define IDX_PRTY_LVL_PMCR_DB0 5 -#define IDX_PRTY_LVL_DISABLED 6 -#define IDX_PRTY_VEC 0 -#define IDX_MASK_VEC 1 -#define NUM_EXT_IRQ_PRTY_LEVELS (uint8_t)(7) +#define IDX_PRTY_LVL_HIPRTY 0 +#define IDX_PRTY_LVL_BCE_DB3 1 +#define IDX_PRTY_LVL_WAKE_DB2 2 +#define IDX_PRTY_LVL_STOP 3 +#define IDX_PRTY_LVL_DB1 4 +#define IDX_PRTY_LVL_DB0 5 +#define IDX_PRTY_LVL_INTERCME_IN0 6 +#define IDX_PRTY_LVL_PMCR 7 +#define IDX_PRTY_LVL_DISABLED 8 +#define IDX_PRTY_VEC 0 +#define IDX_MASK_VEC 1 +#define NUM_EXT_IRQ_PRTY_LEVELS (uint8_t)(9) extern const uint64_t ext_irq_vectors_cme[NUM_EXT_IRQ_PRTY_LEVELS][2]; // Group0: Non-task hi-prty IRQs @@ -86,10 +88,14 @@ extern const uint64_t ext_irq_vectors_cme[NUM_EXT_IRQ_PRTY_LEVELS][2]; #define IRQ_VEC_PRTY3_CME (uint64_t)(0x000FCC0000000000) // Group4: DB1 #define IRQ_VEC_PRTY4_CME (uint64_t)(0x0000000000C00000) -// Group5: BD0 + PMCR -#define IRQ_VEC_PRTY5_CME (uint64_t)(0x000000003C000000) -// Group6: We should never detect these -#define IRQ_VEC_PRTY6_CME (uint64_t)(0x01C003FFC33FFFFF) +// Group5: DB0 +#define IRQ_VEC_PRTY5_CME (uint64_t)(0x000000000C000000) +// Group6: INTERCME_IN0 +#define IRQ_VEC_PRTY6_CME (uint64_t)(0x0100000000000000) +// Group7: PMCR +#define IRQ_VEC_PRTY7_CME (uint64_t)(0x0000000030000000) +// Group8: We should never detect these +#define IRQ_VEC_PRTY8_CME (uint64_t)(0x00C003FFC33FFFFF) // This should be 0xFFFFFFFFFFFFFFFF #define IRQ_VEC_PRTY_CHECK ( IRQ_VEC_PRTY0_CME | \ @@ -98,7 +104,9 @@ extern const uint64_t ext_irq_vectors_cme[NUM_EXT_IRQ_PRTY_LEVELS][2]; IRQ_VEC_PRTY3_CME | \ IRQ_VEC_PRTY4_CME | \ IRQ_VEC_PRTY5_CME | \ - IRQ_VEC_PRTY6_CME ) + IRQ_VEC_PRTY6_CME | \ + IRQ_VEC_PRTY7_CME | \ + IRQ_VEC_PRTY8_CME ) extern uint8_t g_current_prty_level; extern uint8_t g_eimr_stack[NUM_EXT_IRQ_PRTY_LEVELS]; diff --git a/import/chips/p9/procedures/ppe_closed/cme/p9_cme_main.c b/import/chips/p9/procedures/ppe_closed/cme/p9_cme_main.c index 77333c2e..81eee16e 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/p9_cme_main.c +++ b/import/chips/p9/procedures/ppe_closed/cme/p9_cme_main.c @@ -25,9 +25,11 @@ #include "pk.h" #include "p9_cme_irq.h" +#include "p9_cme_flags.h" // CME Pstate Header and Structure #include "p9_cme_pstate.h" +CmePstateRecord G_cme_pstate_record; // CME Stop Header and Structure #include "p9_cme_stop.h" @@ -42,7 +44,7 @@ IRQ_HANDLER_DEFAULT //CMEHW_IRQ_PVREF_FAIL IRQ_HANDLER_DEFAULT //CMEHW_IRQ_OCC_HEARTBEAT_LOST IRQ_HANDLER_DEFAULT //CMEHW_IRQ_CORE_CHECKSTOP IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DROPOUT_FAIL -IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPARE_7 +IRQ_HANDLER(p9_cme_pstate_intercme_in0_handler, (void*)NULL) //CMEHW_IRQ_INTERCME_DIRECT_IN0 IRQ_HANDLER_DEFAULT //CMEHW_IRQ_BCE_BUSY_HIGH IRQ_HANDLER_DEFAULT //CMEHW_IRQ_BCE_TIMEOUT IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DOORBELL3_C0 @@ -77,12 +79,16 @@ IRQ_HANDLER_DEFAULT //CMEHW_IRQ_COMM_SEND_ACK IRQ_HANDLER_DEFAULT //CMEHW_IRQ_COMM_SEND_NACK IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPARE_32 IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPARE_33 -IRQ_HANDLER_DEFAULT //CMEHW_IRQ_PMCR_UPDATE_C0 -IRQ_HANDLER_DEFAULT //CMEHW_IRQ_PMCR_UPDATE_C1 -IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DOORBELL0_C0 -IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DOORBELL0_C1 -IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPARE_38 -IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPARE_39 +IRQ_HANDLER(p9_cme_pstate_pmcr_handler, (void*) & (G_cme_pstate_record.sem[0])) +//CMEHW_IRQ_PMCR_UPDATE_C0 +IRQ_HANDLER(p9_cme_pstate_pmcr_handler, (void*) & (G_cme_pstate_record.sem[0])) +//CMEHW_IRQ_PMCR_UPDATE_C1 +IRQ_HANDLER(p9_cme_pstate_db_handler, (void*) & (G_cme_pstate_record.sem[1])) +//CMEHW_IRQ_DOORBELL0_C0 +IRQ_HANDLER(p9_cme_pstate_db_handler, (void*) & (G_cme_pstate_record.sem[1])) +//CMEHW_IRQ_DOORBELL0_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_INTERCME_IN1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_INTERCME_IN2 IRQ_HANDLER(p9_cme_stop_doorbell_handler, 0) //CMEHW_IRQ_DOORBELL1_C0 IRQ_HANDLER(p9_cme_stop_doorbell_handler, 0) //CMEHW_IRQ_DOORBELL1_C1 IRQ_HANDLER_DEFAULT //CMEHW_IRQ_PECE_INTR_DISABLED_C0 @@ -110,21 +116,24 @@ IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_63 EXTERNAL_IRQ_TABLE_END #define KERNEL_STACK_SIZE 256 -#define THREAD_STACK_SIZE 256 +#define THREAD_STACK_SIZE 512 #define CME_THREAD_PRIORITY_STOP_EXIT 1 #define CME_THREAD_PRIORITY_STOP_ENTRY 2 -#define CME_THREAD_PRIORITY_PSTATE_PMCR 3 +#define CME_THREAD_PRIORITY_PSTATE_DB 3 +#define CME_THREAD_PRIORITY_PSTATE_PMCR 4 uint8_t G_kernel_stack[KERNEL_STACK_SIZE]; uint8_t G_p9_cme_stop_enter_thread_stack[THREAD_STACK_SIZE]; uint8_t G_p9_cme_stop_exit_thread_stack[THREAD_STACK_SIZE]; -uint8_t G_p9_cme_pmcr_db0_thread_stack[THREAD_STACK_SIZE]; +uint8_t G_p9_cme_db_thread_stack[THREAD_STACK_SIZE]; +uint8_t G_p9_cme_pmcr_thread_stack[THREAD_STACK_SIZE]; PkThread G_p9_cme_stop_enter_thread; PkThread G_p9_cme_stop_exit_thread; -PkThread G_p9_cme_pmcr_db0_thread; +PkThread G_p9_cme_db_thread; +PkThread G_p9_cme_pmcr_thread; int main(int argc, char** argv) @@ -152,7 +161,14 @@ main(int argc, char** argv) pk_halt(); } - //CMO-Temporary setting + + //Currently, commenting this. + //This shouldn't really be here at all as SGPE will write this register. + //For verification in SIMICS, SOA, EPM currently just write the CME_LCL_FLAGS manually + // + // + // + /* //CMO-Temporary setting // Setup up CME_LCL_FLAGS to indicate whether // this CME is QMGR master or slave. // Rules: @@ -163,6 +179,7 @@ main(int argc, char** argv) uint32_t l_pir; asm volatile ("mfpir %[data] \n" : [data]"=r"(l_pir) ); + #ifndef _SOA_SC_ENVIRONMENT_ if ( l_pir & PIR_INSTANCE_EVEN_ODD_MASK ) { // Odd: Set slave status @@ -174,6 +191,28 @@ main(int argc, char** argv) out32(CME_LCL_FLAGS_OR, CME_FLAGS_QMGR_MASTER); } + #else + + if ( l_pir & PIR_INSTANCE_EVEN_ODD_MASK ) + { + // Odd: Set slave status + out32(CME_LCL_FLAGS_OR, CME_FLAGS_QMGR_MASTER); + } + else + { + // Even: Set master status + out32(CME_LCL_FLAGS_CLR, CME_FLAGS_QMGR_MASTER); + } + + #endif + + //\todo Fix this + #ifndef _SOA_SC_ENVIRONMENT_ + out32(CME_LCL_FLAGS_OR, CME_FLAGS_CORE0_GOOD | CME_FLAGS_CORE1_GOOD | CME_FLAGS_SIBLING_FUNCTIONAL); + #else + out32(CME_LCL_FLAGS_OR, CME_FLAGS_CORE0_GOOD | CME_FLAGS_CORE1_GOOD); + #endif + */ // Initialize the thread control block for G_p9_cme_stop_exit_thread pk_thread_create(&G_p9_cme_stop_exit_thread, (PkThreadRoutine)p9_cme_stop_exit_thread, @@ -199,16 +238,28 @@ main(int argc, char** argv) sizeof(G_p9_cme_stop_enter_thread)); // Initialize thread control blocks for the threads - pk_thread_create( &G_p9_cme_pmcr_db0_thread, - (PkThreadRoutine)pmcr_db0_thread, + pk_thread_create( &G_p9_cme_db_thread, + (PkThreadRoutine)p9_cme_pstate_db_thread, (void*)NULL, - (PkAddress)G_p9_cme_pmcr_db0_thread_stack, + (PkAddress)G_p9_cme_db_thread_stack, (size_t)THREAD_STACK_SIZE, - (PkThreadPriority)IDX_PRTY_LVL_PMCR_DB0); + (PkThreadPriority)CME_THREAD_PRIORITY_PSTATE_DB); - PK_TRACE_BIN("G_p9_cme_pmcr_db0_thread", - &G_p9_cme_pmcr_db0_thread, - sizeof(G_p9_cme_pmcr_db0_thread)); + PK_TRACE_BIN("G_p9_cme_db_thread", + &G_p9_cme_db_thread, + sizeof(G_p9_cme_db_thread)); + + // Initialize thread control blocks for the threads + pk_thread_create( &G_p9_cme_pmcr_thread, + (PkThreadRoutine)p9_cme_pstate_pmcr_thread, + (void*)NULL, + (PkAddress)G_p9_cme_pmcr_thread_stack, + (size_t)THREAD_STACK_SIZE, + (PkThreadPriority)CME_THREAD_PRIORITY_PSTATE_PMCR); + + PK_TRACE_BIN("G_p9_cme_pmcr_thread", + &G_p9_cme_pmcr_thread, + sizeof(G_p9_cme_pmcr_thread)); // Make G_p9_cme_stop_exit_thread runnable pk_thread_resume(&G_p9_cme_stop_exit_thread); @@ -217,10 +268,15 @@ main(int argc, char** argv) pk_thread_resume(&G_p9_cme_stop_enter_thread); // Make G_p9_cme_pstate_thread runnable - pk_thread_resume(&G_p9_cme_pmcr_db0_thread); + pk_thread_resume(&G_p9_cme_db_thread); + + // Make G_p9_cme_pstate_thread runnable + pk_thread_resume(&G_p9_cme_pmcr_thread); PK_TRACE("Launching threads"); + ppe42_app_ctx_set(0); + // Start running the highest priority thread. // This function never returns pk_start_threads(); 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 ed33dfa9..44f93821 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 @@ -28,723 +28,458 @@ // *! *** IBM Confidential *** //----------------------------------------------------------------------------- -/// \file pstate_cme.c +/// \file p9_cme_pstate.c /// \brief CME and QCME codes enforcing the Power protocols for Pstate, DPLL /// actuation, iVRM, resonant clocking, and VDM. -/// \owner Michael Olsen Email: cmolsen@us.ibm.com -/// - -/// Features of this H-code: -/// - The thread works in conjunction with the pstate thread on the PGPE. -/// -/// Assumptions: -/// 1. PGPE is assumed up and running and ready at the time the QCME sends -/// it registration request. -/// +/// \owner Rahul Batra Email: rbatra@us.ibm.com /// #include "pk.h" +#include "ppe42_scom.h" + +#include "cme_firmware_registers.h" #include "cme_register_addresses.h" -#include "ppm_register_addresses.h" -#include "ppm_firmware_registers.h" -#include "cppm_register_addresses.h" #include "cppm_firmware_registers.h" -#include "qppm_register_addresses.h" +#include "cppm_register_addresses.h" +#include "ppm_firmware_registers.h" +#include "ppm_register_addresses.h" #include "qppm_firmware_registers.h" -#include "ppe42_scom.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_pstate_common.h" +#include "p9_pstate_vpd.h" +#include "ppe42_cache.h" + // -// HOMER variables updated by PGPE +//Globals // -uint32_t ULTRA_TURBO_FREQ_STEPS_PS; - -#define PIG_PAYLOAD_MASK 0x0fff000000000000 -#define PIG_INTR_FIELD_MASK 0x7000000000000000 -#define PIG_INTR_GRANTED_MASK 0x0000000080000000 +extern CmePstateRecord G_cme_pstate_record; +cme_pstate_db_data_t G_db_thread_data; +cme_pstate_pmcr_data_t G_pmcr_thread_data; -// Type1 specific defines -#define PIG_PAYLOAD_PSTATE_MASK 0x03ff000000000000 -#define PIG_PAYLOAD_PSTATE_SEQ_INCR 0x0400000000000000 // Seq increment value - - -int -register_qcme_with_pgpe(void); +//\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); -void -unified_irq_task_handler(void* arg, PkIrqId irq) +// +//PMCR Interrupt Handler +// +void p9_cme_pstate_pmcr_handler(void* arg, PkIrqId irq) { pk_semaphore_post((PkSemaphore*)arg); } - -void -unified_irq_nontask_handler(void* arg, PkIrqId irq) +// +//Doorbell0 interrupt handler +// +//Only enabled on QuadManager-CME +void p9_cme_pstate_db_handler(void* arg, PkIrqId irq) { - MY_TRACE_ERR("Got an non-task IRQ=%d", irq); - pk_halt(); + pk_semaphore_post((PkSemaphore*)arg); } - -int -send_pig_packet(uint32_t addr, uint64_t data) +// +//InterCME_IN0 handler +// +void p9_cme_pstate_intercme_in0_handler(void* arg, PkIrqId irq) { - int rc = 0; - uint64_t data_tmp; + pgpe_db0_glb_bcast_t db0C0Data, db0C1Data; + uint8_t localPS = 0; + uint32_t cme_flags = in32(CME_LCL_FLAGS); + uint64_t pmsrData; + PkMachineContext ctx; - // First make sure no interrupt request is currently granted - do + //read DB0 for both cores and update PMSR + if (cme_flags & CME_FLAGS_CORE0_GOOD) { - // Read PPMPIG status - rc = getscom(0, addr, &data_tmp); - - if (rc) - { - MY_TRACE_ERR("getscom(addr=0x%08x) failed w/rc=0x%08x", addr, rc); - pk_halt(); - } + 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 } - while (((ppm_pig_t)data_tmp).fields.intr_granted); - - // Send PIG packet - rc = putscom(0, addr, data); - if (rc) + if (cme_flags & CME_FLAGS_CORE1_GOOD) { - MY_TRACE_ERR("putscom(addr=0x%08x) failed w/rc=0x%08x", addr, rc); - pk_halt(); + 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 } - return rc; -} + 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); +} -void -pmcr_db0_thread(void* arg) +// +//p9_cme_pmcr_thread +// +void p9_cme_pstate_pmcr_thread(void* arg) { - int rc = 0, rc_api = API_RC_SUCCESS; - uint8_t bDB0 = FALSE, bPMCR = FALSE; + int32_t c; PkMachineContext ctx; - PkSemaphore sem; - uint64_t thisIrqPrtyVec; - uint8_t irqPrty; - uint8_t ps_local; - int statusIrqDb0C0; - int statusIrqDb0C1; - int statusIrqPmcrC0; - int statusIrqPmcrC1; - uint8_t thisCoreIdx = 0xff; // Index=0 or =1 - uint8_t nextCoreIdx = 0xff; // Index=0 or =1 - PkIrqId IRQ_THIS = 0xff; - uint8_t seqNum = 0; // Phase message sequence (0,1,2,3,0,..) - uint32_t addr_db0 = 0; - uint32_t addr_db0_0, addr_db0_1; // One for each of the two cores - uint32_t addr_pmcr = 0; - uint32_t addr_pmcr_0, addr_pmcr_1; // One for each of the two cores - uint32_t addr_ppm_pig; - uint32_t addr_ppm_pig_0, addr_ppm_pig_1; // One for each of the two cores - uint64_t data_pmcr; - cb_to_qcme_base_t cb_from_pgpe_base; - cb_to_pgpe_ack_t cb_to_pgpe_ack; - cb_to_pgpe_qcme_t cb_to_pgpe_qcme; - uint32_t addr_ippmr, addr_ippmw, addr_ippmcmd; - qppm_dpll_freq_t qppm_dpll_freq; - cppm_ippmcmd_t cppm_ippmcmd; - ppm_pig_t data_ppm_pig; - uint64_t data; - uint32_t data32; - uint8_t fsm_unacked_qcme_registration; - uint32_t l_pir; - uint8_t bQcmeRegister; - uint8_t thisCmeInstance; - - - PK_TRACE("PMCR_DB0 thread starting..."); - - // Lock this in now to avoid typing mistakes later-on. And make sure you're - // using the correct PRTY level for this task. - thisIrqPrtyVec = ext_irq_vectors_cme[IDX_PRTY_LVL_PMCR_DB0][IDX_PRTY_VEC]; - - - // Calculate anticipated SCOM addresses, or fractions of them up front - // - - // Local PMCR0 used by cores "left" and "right" - addr_pmcr_0 = CME_LCL_PMCRS0; - addr_pmcr_1 = CME_LCL_PMCRS1; - - // CPPM_DB0_0/1 regs used by cores "left" and "right" - addr_db0_0 = CPPM_CMEDB0 | CORE_SEL_LEFT; - addr_db0_1 = CPPM_CMEDB0 | CORE_SEL_RIGHT; - - // PPM_PIG_0/1 belong to cores "left" and "right" - addr_ppm_pig_0 = PPM_PIG | CORE_SEL_LEFT; - addr_ppm_pig_1 = PPM_PIG | CORE_SEL_RIGHT; - - - // Create a semaphore, updated by a single interrupt handler that services - // two PMCR and two DB0 interrupts. Thus, max sem count set to four. - pk_semaphore_create(&sem, 0, 4); - - - //--------------------------------------------// - // Register the unified interrupt handler. // - //--------------------------------------------// - - // Notes: - // - Register the two PMCR and the two DB0 interrupts - // - Never consider IRQs beyond IRQ>=44 because they are reserved and - // permanently firing. - // - Also register high-priority interrupt handlers - // - for (irqPrty = 0; irqPrty < 44; irqPrty++) - { - if ( ext_irq_vectors_cme[IDX_PRTY_LVL_PMCR_DB0][IDX_PRTY_VEC] & - (RIGHT_SHIFT_PTRN_0x8_64BIT >> irqPrty) ) - { - rc = pk_irq_handler_set( irqPrty, - unified_irq_task_handler, - (void*)&sem ); + 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; - if (rc) - { - PK_TRACE("pk_irq_handler_set(%d) failed w/rc=0x%08x", irqPrty, rc); - pk_halt(); - } - } - else if ( ext_irq_vectors_cme[IDX_PRTY_LVL_HIPRTY][IDX_PRTY_VEC] & - (RIGHT_SHIFT_PTRN_0x8_64BIT >> irqPrty) ) - { - rc = pk_irq_handler_set( irqPrty, - unified_irq_nontask_handler, - (void*)&sem ); + G_pmcr_thread_data.seqNum = 0; - if (rc) - { - PK_TRACE("pk_irq_handler_set(%d) failed w/rc=0x%08x", irqPrty, rc); - pk_halt(); - } - } + 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 + } - // - // Clear (until Simics gets fixed) and unmask the [non-task] shared HIPRTY IRQs. - // - pk_irq_vec_status_clear( ext_irq_vectors_cme[IDX_PRTY_LVL_HIPRTY][IDX_PRTY_VEC]); - pk_irq_vec_enable( ext_irq_vectors_cme[IDX_PRTY_LVL_HIPRTY][IDX_PRTY_VEC]); - - // - // Clear and then unmask our interrupts. - // (Note, this must be done BEFORE registering QCME as otherwise race - // condition between EISR clearing and PGPE sending Ack.) - // - pk_irq_vec_status_clear( thisIrqPrtyVec); - pk_irq_vec_enable( thisIrqPrtyVec); - + pk_semaphore_create(&G_cme_pstate_record.sem[0], 0, 1); - //------------------------------------------------------------------------------// - // Determine QMGR status and register as QMGR, ie QCME, if CME is QMGR master // - //------------------------------------------------------------------------------// + while(1) + { + //pend on sempahore + pk_semaphore_pend(&G_cme_pstate_record.sem[0], PK_WAIT_FOREVER); + wrteei(1); - // First determine if this CME is a QMRG master, i.e. QCME - // - bQcmeRegister = FALSE; + //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 - asm volatile ("mfpir %[data] \n" : [data]"=r"(l_pir) ); + 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++; + } + } + } - thisCmeInstance = (uint8_t)(l_pir & PIR_INSTANCE_NUM_MASK); + pk_irq_vec_restore(&ctx); + } +} - rc = getscom( 0, CME_LCL_FLAGS, &data ); - data32 = (uint32_t)(data >> 32); +// +//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. +#ifndef SIMICS_ENVIRONMENT + 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 ( data32 & CME_FLAGS_QMGR_MASTER ) - { - bQcmeRegister = TRUE; - MY_TRACE_DBG("This CME#%d is the QMGR master", thisCmeInstance); - } - else // Sanity check since this CME is NOT a QMGR mstr, that it is an odd CME. Otherwise, error. + if (cme_flags & CME_FLAGS_QMGR_MASTER) { - if ( l_pir & PIR_INSTANCE_EVEN_ODD_MASK ) // Sanity test that bit31==1 and thus this CME is odd. + G_db_thread_data.qmFlag = 1; + + if (cme_flags & CME_FLAGS_SIBLING_FUNCTIONAL) { - bQcmeRegister = FALSE; - MY_TRACE_DBG("This [odd] CME#%d is the QMGR slave", thisCmeInstance); + G_db_thread_data.siblingCMEFlag = 1; } else { - MY_TRACE_ERR("CME_LCL_FLAGS indicate QMGR slave status for even CME."); - MY_TRACE_ERR("This is not allowed. Even CMEs must be QMGR master."); - pk_halt(); + G_db_thread_data.siblingCMEFlag = 0; } } - - // FSM Notes: - // - Register this CME with PGPE if it's the QMGR master. - // - Note that registration MUST be done AFTER clearing and unmasking - // interrupts. - // - fsm_unacked_qcme_registration = 0; - - if (bQcmeRegister) + else { - // Format Type4 PIG message - Populate the CB, then the PIG payload - // - cb_to_pgpe_qcme.value = 0; - cb_to_pgpe_qcme.fields.msg_id = MSGID_T4_REGISTER_QCME; - - data_ppm_pig.value = 0; - data_ppm_pig.fields.req_intr_payload = cb_to_pgpe_qcme.value; - data_ppm_pig.fields.req_intr_type = 4; - -//CMO - TBD - Determine which of the two cores are configured. Pick the smallest -// numbered. We'll assume idx=0 for now. Another RTC story will deal -// with the issue of picking the lowest registered core's PIG. - addr_ppm_pig = addr_ppm_pig_0; - - // Assumption 1: - // Before sending Type4 QCME registration, make sure PGPE is running. - // For now, use pk_sleep. - // Need some kind of handshake here. Or we need to know for sure that - // PGPE is always running before QCME. - pk_sleep(PK_NANOSECONDS(1000)); - rc = send_pig_packet(addr_ppm_pig, data_ppm_pig.value); - - if (rc) - { - MY_TRACE_ERR("send_pig_packet(addr=0x%08x) failed w/rc=0x%08x", addr_ppm_pig, rc); - pk_halt(); - } + G_db_thread_data.qmFlag = 0; + G_db_thread_data.siblingCMEFlag = 0; + } - // Update the unacked registration tracker - if (!fsm_unacked_qcme_registration) + //if quadManager + if (G_db_thread_data.qmFlag) + { + if (cme_flags & CME_FLAGS_CORE0_GOOD) { - fsm_unacked_qcme_registration++; + 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 + else if (cme_flags & CME_FLAGS_CORE1_GOOD) { - MY_TRACE_ERR("Code bug: fsm_unacked_qcme_registration (=%d) > 0", - fsm_unacked_qcme_registration); - pk_halt(); + 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; } - } - - - // - // Reset indices and seq no - // - nextCoreIdx = 0; - thisCoreIdx = 0xff; - seqNum = 0; - -#if EPM_P9_TUNING - asm volatile ( "tw 0, 31, 0" ); -#endif - // FSM: Indicate PMCR thread is ready. - out32(CME_LCL_FLAGS_OR, CME_FLAGS_PMCR_READY); + out64(CME_LCL_EIMR_OR, BIT64(7));//Disable InterCME_IN0 + g_eimr_override |= BIT64(7); - - while(1) + 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); + } - // Go to sleep - pk_semaphore_pend(&sem, PK_WAIT_FOREVER); + //\todo (RTC) Set intial GlobalPS, LocalPS, resClkIdx, etc. + //Most likely will come from SGPE. Need to know precisely - // - // First we need to determine which of the four interrupts fired. - // This incl which of the two cores, "left" (index0) or "right" (index1), - // were used. - // - Give priority to DB0 over PMCR. (More important to wrap up ongoing - // PMCR request than to start a new.) - // - If both of the PMCRs fired by the time we get to this point, alternate - // between them using nextCoreIdx and thisCoreIdx. - // - If both of the DB0s fired, we have an error. - // + //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); - do + while(1) { - bDB0 = bPMCR = FALSE; - - statusIrqDb0C0 = pk_irq_status_get(CMEHW_IRQ_DOORBELL0_C0); - statusIrqDb0C1 = pk_irq_status_get(CMEHW_IRQ_DOORBELL0_C1); + //pend on sempahore + pk_semaphore_pend(&G_cme_pstate_record.sem[1], PK_WAIT_FOREVER); + wrteei(1); - if (statusIrqDb0C0 && statusIrqDb0C1) + if (cme_flags & CME_FLAGS_CORE0_GOOD) { - // Both fired (We do NOT support this.) - PK_TRACE("Code bug: Both DB0s fired. Probably PGPE problem."); - pk_halt(); + 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 (statusIrqDb0C0) + else if (cme_flags & CME_FLAGS_CORE1_GOOD) { - thisCoreIdx = 0; // "left" core idx - IRQ_THIS = CMEHW_IRQ_DOORBELL0_C0; - addr_db0 = addr_db0_0; - addr_ppm_pig = addr_ppm_pig_0; - bDB0 = TRUE; + out32_sh(CME_LCL_EISR_CLR, BIT32(5)); + CME_GETSCOM(CPPM_CMEDB0, CME_MASK_C1, CME_SCOM_EQ, dbData.value); } - else if (statusIrqDb0C1) + + //Update analog + if (G_resclkEnabled) { - thisCoreIdx = 1; // "right" core idx - IRQ_THIS = CMEHW_IRQ_DOORBELL0_C1; - addr_db0 = addr_db0_1; - addr_ppm_pig = addr_ppm_pig_1; - bDB0 = TRUE; + resclk_update(); } - else + +#ifndef SIMICS_ENVIRONMENT + freq_update(dbData.value); +#endif + + //Notify sibling CME(if any) + if (G_db_thread_data.siblingCMEFlag == 1) { - statusIrqPmcrC0 = pk_irq_status_get(CMEHW_IRQ_PMCR_UPDATE_C0); - statusIrqPmcrC1 = pk_irq_status_get(CMEHW_IRQ_PMCR_UPDATE_C1); + //Send interCME interrupt + out32(CME_LCL_ICCR_OR, BIT32(5)); //Send direct InterCME_IN0 + out32(CME_LCL_ICCR_CLR, BIT32(5));//Clear + +#ifndef SIMICS_ENVIRONMENT + //poll on interCME interrupt + intercme_acked = 0; +#else + intercme_acked = 1; +#endif - if (statusIrqPmcrC0 && statusIrqPmcrC1) + while (!intercme_acked) { - // Both fired (We support this.) - thisCoreIdx = nextCoreIdx; - nextCoreIdx++; - nextCoreIdx = nextCoreIdx - (nextCoreIdx >> 1) * 2; + eisr = in64(CME_LCL_EISR); - if (thisCoreIdx != 0 && thisCoreIdx != 1) + if (eisr & 0x0100000000000000) { - PK_TRACE("Code bug: Illegal value of thisCoreIdx (=%d).", thisCoreIdx); - pk_halt(); + intercme_acked = 1; } } - else if (statusIrqPmcrC0) - { - thisCoreIdx = 0; // "left" core idx - } - else if (statusIrqPmcrC1) - { - thisCoreIdx = 1; // "right" core idx - } - else - { - PK_TRACE("Illegal interrupt status."); - PK_TRACE("Neither of the {PMCR,DB0}_C0/1 interrupts are set."); - pk_halt(); - } - - bPMCR = TRUE; - // Set the core specific values for the interrupt, pmcr addr and - // ppmpig addr. Note, we already did this earlier for db0. - if (thisCoreIdx == 0) - { - IRQ_THIS = CMEHW_IRQ_PMCR_UPDATE_C0; - addr_pmcr = addr_pmcr_0; - addr_ppm_pig = addr_ppm_pig_0; - } - else - { - IRQ_THIS = CMEHW_IRQ_PMCR_UPDATE_C1; - addr_pmcr = addr_pmcr_1; - addr_ppm_pig = addr_ppm_pig_1; - } + out32(CME_LCL_EISR_CLR, BIT32(7));//Clear InterCME_IN0 } - } - while(0); - - MY_TRACE_DBG("IRQ_THIS=0x%02x, addr_ppm_pig=0x%08x", - IRQ_THIS, addr_ppm_pig); - - // Clear the status of the currently selected interrupt - pk_irq_status_clear(IRQ_THIS); - - - //------------------------------------------------------------------// - // Do the work // - //------------------------------------------------------------------// - - if (bDB0) - //-------------------------------------------// - // Process DB0 // - //-------------------------------------------// - { - MY_TRACE_DBG("IRQ_THIS=0x%02x, addr_db0=0x%08x, addr_ppm_pig=0x%08x", - IRQ_THIS, addr_db0, addr_ppm_pig); + //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; - // Get the payload from DB0 - rc = getscom(0, addr_db0, &cb_from_pgpe_base.value); - - if (rc) + if (cme_flags & CME_FLAGS_CORE0_GOOD) { - MY_TRACE_ERR("getscom(addr=0x%08x,data=0x%08x%08x) failed w/rc=0x%08x", - addr_db0, cb_from_pgpe_base.value, rc); - pk_halt(); + out64(CME_LCL_PMSRS0, pmsrData); } -//MY_TRACE_DBG("DB0 payload = 0x%08x%08x", -// (uint32_t)(cb_from_pgpe_base.value>>32),(uint32_t)(cb_from_pgpe_base.value)); - - // - // Act on msg_id and do what needs be done - // Note that there's only support for PS_BROADCAST and Ack so far. - // - switch (cb_from_pgpe_base.fields.msg_id) + if (cme_flags & CME_FLAGS_CORE1_GOOD) { - - case MSGID_DB0_PS_BROADCAST: - - if (fsm_unacked_qcme_registration) - { - MY_TRACE_ERR("Code bug: fsm_unacked_qcme_registration (=%d) != 0", - fsm_unacked_qcme_registration); - pk_halt(); - } - - ps_local = ((cb_to_qcme_ps_bc_t)cb_from_pgpe_base.value).fields.ps_local; - - MY_TRACE_DBG("cb_from_pgpe_ps_bc.fields.ps_local=%d", ps_local); - - // Update the DPLL_FREQ register - // - - // In the following setup, - // - use the CPPM that you received the DB0 on - // - use CorePPM1 for the INTERPPM (done from PGPE) - // - if (thisCoreIdx == 0) - { - addr_ippmr = CPPM_IPPMRDATA | CORE_SEL_LEFT; - addr_ippmw = CPPM_IPPMWDATA | CORE_SEL_LEFT; - addr_ippmcmd = CPPM_IPPMCMD | CORE_SEL_LEFT; - } - else - { - addr_ippmr = CPPM_IPPMRDATA | CORE_SEL_RIGHT; - addr_ippmw = CPPM_IPPMWDATA | CORE_SEL_RIGHT; - addr_ippmcmd = CPPM_IPPMCMD | CORE_SEL_RIGHT; - } - - rc = getscom(0, addr_ippmr, &(qppm_dpll_freq.value)); - - if (rc) - { - MY_TRACE_ERR("getscom(CPPM_IPPMRDATA=0x%08x) failed w/rc=0x%08x", - addr_ippmr, rc); - pk_halt(); - //MY_PK_PANIC(SCOM_TROUBLE); - } - - qppm_dpll_freq.fields.fmax = - qppm_dpll_freq.fields.freq_mult = - qppm_dpll_freq.fields.fmin = ULTRA_TURBO_FREQ_STEPS_PS - ps_local; - rc = putscom(0, addr_ippmw, qppm_dpll_freq.value); - - if (rc) - { - MY_TRACE_ERR("putscom(CPPM_IPPMWDATA=0x%08x) failed w/rc=0x%08x", - addr_ippmw, rc); - pk_halt(); - //MY_PK_PANIC(SCOM_TROUBLE); - } - - // Now write the DPLL_FREQ reg through the inter-PPM mechanism - // - cppm_ippmcmd.value = 0; - cppm_ippmcmd.fields.qppm_reg = QPPM_DPLL_FREQ & 0x000000ff; - cppm_ippmcmd.fields.qppm_rnw = 0; // Use CorePPM1 - rc = putscom(0, addr_ippmcmd, cppm_ippmcmd.value); - - if (rc) - { - MY_TRACE_ERR("putscom(CPPM_IPPMCMD=0x%08x) failed w/rc=0x%08x", - addr_ippmcmd, rc); - pk_halt(); - //MY_PK_PANIC(SCOM_TROUBLE); - } - - // - // Send an PIG Type4 ack back to PGPE - // - - cb_to_pgpe_ack.value = 0; - cb_to_pgpe_ack.fields.msg_id = MSGID_T4_ACK; - cb_to_pgpe_ack.fields.msg_id_ref = ((cb_to_qcme_ps_bc_t)cb_from_pgpe_base.value).fields.msg_id; - cb_to_pgpe_ack.fields.rc = rc_api; - - data_ppm_pig.value = 0; - data_ppm_pig.fields.req_intr_payload = cb_to_pgpe_ack.value; - data_ppm_pig.fields.req_intr_type = 4; - - // Send Ack back to PGPE to acknowledge receipt and processing - // of the Pstate broadcast. - rc = send_pig_packet(addr_ppm_pig, data_ppm_pig.value); - - if (rc) - { - MY_TRACE_ERR("send_pig_packet(addr=0x%08x) failed w/rc=0x%08x", addr_ppm_pig, rc); - pk_halt(); - } - - break; - - case MSGID_DB0_ACK: - - MY_TRACE_DBG("Received an DB0 Ack"); - - if (fsm_unacked_qcme_registration == 1) - { - fsm_unacked_qcme_registration--; - } - else - { - MY_TRACE_ERR("Code bug: fsm_unacked_qcme_registration (=%d) != 1", - fsm_unacked_qcme_registration); - pk_halt(); - } - - // FSM: Indicate QMGR master status and QMGR ready in CME FLAGS. - out32(CME_LCL_FLAGS_OR, CME_FLAGS_QMGR_READY); - - break; - - default: - - MY_TRACE_ERR("Unsupported msg_id. Only MSGID_DB0_PS_BROADCAST supported."); - pk_halt(); - - break; - - } // End of switch() - - } - else if (bPMCR) - //-------------------------------------------// - // Process PMCR // - //-------------------------------------------// - { - - MY_TRACE_DBG("IRQ_THIS=0x%02x, addr_pmcr=0x%08x, addr_ppm_pig=0x%08x", - IRQ_THIS, addr_pmcr, addr_ppm_pig); - - // Read PMCRS - rc = getscom(0, addr_pmcr, &data_pmcr); - - if (rc) - { - PK_TRACE("getscom(addr_pmcr%d=0x%08x) failed w/rc=0x%08x", - thisCoreIdx, addr_pmcr, rc); - pk_halt(); + out64(CME_LCL_PMSRS1, pmsrData); } -#if DEV_DEBUG - PK_TRACE("data_pmcr%d=0x%08x%08x", - thisCoreIdx, (uint32_t)(data_pmcr >> 32), (uint32_t)data_pmcr); -#endif - - // Bump/wrap the payload sequence number - seqNum++; - seqNum = seqNum - (seqNum / 4) * 4; + //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); - // - // Phase 1 PIG message - // - - // Format Pstate phase 1 PIG message - Populate intr_type and payload fields - // - // 1) Copy the 10-bit PMCR(6:15) payload to PPMPIG(6:15). - // 2) Mask off all other content. - // 3) Indicate the sequence number in the payload field. - // 4) Indicate the phase 1 (Type0) in the interrupt field. - data_ppm_pig.value = data_pmcr & PIG_PAYLOAD_PSTATE_MASK; - data_ppm_pig.value = data_ppm_pig.value | PIG_PAYLOAD_PSTATE_SEQ_INCR * seqNum; - data_ppm_pig.fields.req_intr_type = 0; + pk_irq_vec_restore(&ctx); + } + } +} - // Send PIG phase 1 message, but only if no intr request is currently granted - rc = send_pig_packet(addr_ppm_pig, data_ppm_pig.value); +// +//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.freq_mult = (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); +} - if (rc) - { - MY_TRACE_ERR("send_pig_packet(addr=0x%08x) failed w/rc=0x%08x", addr_ppm_pig, rc); - pk_halt(); - } +// +//resclk_update +// +void resclk_update() +{ + uint64_t val; + uint8_t tidx, step; + int32_t i; - // - // Phase 2 PIG message - // - - // Format Pstate phase 2 PIG message - Populate intr_type and payload fields - // - // 1) Copy the 10-bit PMCR(22:31) payload to PPMPIG(6:15). - // 2) Mask off all other content. - // 3) Indicate the sequence number in the payload field. - // 4) Indicate the phase 2 (Type1) in the interrupt field. - // in data_ppm_pig. - data_ppm_pig.value = (data_pmcr << 16) & PIG_PAYLOAD_PSTATE_MASK; - data_ppm_pig.value = data_ppm_pig.value | PIG_PAYLOAD_PSTATE_SEQ_INCR * seqNum; - data_ppm_pig.fields.req_intr_type = 1; - - // Send PIG phase 2 message, but only if no intr request is currently granted - rc = send_pig_packet(addr_ppm_pig, data_ppm_pig.value); - - if (rc) - { - MY_TRACE_ERR("send_pig_packet(addr=0x%08x) failed w/rc=0x%08x", addr_ppm_pig, rc); - pk_halt(); - } + //get targetIndex from Table1(ControlIndex) by indexing with localPState + tidx = G_db_thread_data.resClkTblIdx; -#if DEV_DEBUG - // Read PPMPIG status - rc = getscom(0, addr_ppm_pig, &data); + for (i = NUM_FREQ_REGIONS - 1; i >= 0; i--) + { + if (G_freq2idx[i].pstate > G_db_thread_data.localPS) + { + tidx = i; + break; + } + } - if (rc) - { - PK_TRACE("getscom(addr_ppm_pig%d=0x%08x) failed w/rc=0x%08x", - thisCoreIdx, addr_ppm_pig, rc); - pk_halt(); - } + //walk Table2[Resonant Grids Control Data) + if (tidx > G_db_thread_data.resClkTblIdx) + { + step = 1; + } + else + { + step = -1; + } - PK_TRACE("(After PIG phase 2): data_ppm_pig%d=0x%08x%08x", - thisCoreIdx, (uint32_t)(data >> 32), (uint32_t)data); + 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; + +#ifndef SIMICS_ENVIRONMENT + //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 + } +} - } - else - { - PK_TRACE("Code bug."); - PK_TRACE("Neither of the {PMCR,DB0}_C0/1 interrupts were selected."); - pk_halt(); - } +// +//send_pig_packet +// +int send_pig_packet(uint64_t data, uint32_t coreMask) +{ + int rc = 0; + uint64_t data_tmp; + // First make sure no interrupt request is currently granted + do + { + // Read PPMPIG status + CME_GETSCOM(PPM_PIG, coreMask, CME_SCOM_EQ, data_tmp); + } + while (((ppm_pig_t)data_tmp).fields.intr_granted); - // Restore the EIMR to the value it had when the IRQ handler was entered. - // (Note that we've already cleared the EISR earlier.) - // - pk_irq_vec_restore(&ctx); - /* - pk_critical_section_enter(&ctx); - if (g_eimr_stack_ctr>=0) - { - out64( STD_LCL_EIMR, - ext_irq_vectors_cme[g_eimr_stack[g_eimr_stack_ctr]][IDX_MASK_VEC]); - out64( STD_LCL_EIMR_CLR, - g_eimr_override_stack[g_eimr_stack_ctr]); - out64( STD_LCL_EIMR_OR, - g_eimr_override); - //CMO-temporarily commenting following three lines which asap should replace above line. - // but if i do that, then i get a machine check in the timer_bh_handler (which is - // a result of pk_delay kicked of way earlier than this code here!!) right after it - // executes bctrl and jumps to an illegal instruction. Yeah, no make sense!!! - // out64( STD_LCL_EIMR, - // (ext_irq_vectors_cme[g_eimr_stack[g_eimr_stack_ctr]][IDX_MASK_VEC] & - // ~g_eimr_override_stack[g_eimr_stack_ctr]) | g_eimr_override); - // Restore the prty level tracker to the task that was interrupted, if any. - g_current_prty_level = g_eimr_stack[g_eimr_stack_ctr]; - g_eimr_stack_ctr--; - } - else - { - MY_TRACE_ERR("Code bug: Messed up EIMR book keeping: g_eimr_stack_ctr=%d", - g_eimr_stack_ctr); - pk_halt(); - } - pk_critical_section_exit(&ctx); - */ + // Send PIG packet + CME_PUTSCOM(PPM_PIG, coreMask, data); - } + return rc; } 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 ef8daeed..57313ebc 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 @@ -28,320 +28,42 @@ // *! *** IBM Confidential *** //----------------------------------------------------------------------------- -/// \file pstate.h +/// \file p9_cme_pstate.h /// \brief Shared and global definitions for pstate H codes. -/// \owner Michael Olsen Email: cmolsen@us.ibm.com +/// \owner Rahul Batra Email: rbatra@us.ibm.com /// -void pmcr_db0_thread(void*); +#include "pk.h" +#include "p9_pstate_common.h" +#include "gpehw_common.h" -#define MAX_CORES 24 -#define MAX_QUADS 6 -#define MAX_CMES 12 -#define CORES_PER_QUAD (MAX_CORES/MAX_QUADS) -#define CORES_PER_CME (MAX_CORES/MAX_CMES) -#define CMES_PER_QUAD (MAX_CMES/MAX_QUADS) +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); -#define QUAD_SCOM_ADDR_MASK 0x07000000 -#define CME_SCOM_ADDR_MASK 0x00000C00 -#define QUAD_CME_SCOM_ADDR_MASK_CLR ~(QUAD_SCOM_ADDR_MASK|CME_SCOM_ADDR_MASK) - -#define QUAD_SCOM_ADDR_INCR (uint32_t)0x01000000 -#define CME_SCOM_ADDR_OFFSET (uint32_t)0x00000400 -#define CME_SCOM_ADDR_INCR (uint32_t)0x00000400 -#define CORE_SCOM_ADDR_OFFSET (uint32_t)0x20000000 -#define CORE_SCOM_ADDR_INCR (uint32_t)0x01000000 -#define CORE_SEL_LEFT (uint32_t)0x00800000 -#define CORE_SEL_RIGHT (uint32_t)0x00400000 - -//#define TRUE 1 -//#define FALSE 0 - -#define RIGHT_SHIFT_PTRN_0x8_32BIT (uint32_t)0x80000000 -#define RIGHT_SHIFT_PTRN_0xC_32BIT (uint32_t)0xC0000000 -#define RIGHT_SHIFT_PTRN_0xF_32BIT (uint32_t)0xF0000000 -#define RIGHT_SHIFT_PTRN_0x8_64BIT (uint64_t)0x8000000000000000 - -// -// HOMER variables updated by PGPE -// -extern uint32_t ULTRA_TURBO_FREQ_STEPS_PS; - - -#define VEXT_SLEW_RATE_MVPERUS 0x0A0A // Trise=Tfall=10mv/us -#define MAX_POLL_COUNT_AVS 10 -/* -// We define four levels of TRACE outputs: -// _INF: Trace level used for main informational events. -// _DBG: Trace level used for expanded debugging. -// _WARN: Trace level used when suspecious event happens. -// _ERR: Trace level at time of an error that leads to a halt. -#define MY_TRACE_INF(...) PK_TRACE("INF: "__VA_ARGS__); -#ifdef DEV_DEBUG - #define MY_TRACE_DBG(...) PK_TRACE("DBG: "__VA_ARGS__); -#else - #define MY_TRACE_DBG(...) -#endif -#define MY_TRACE_WARN(...) PK_TRACE("WARN: "__VA_ARGS__); -#define MY_TRACE_ERR(...) PK_TRACE("ERR: "__VA_ARGS__); -*/ - -// -// PIR defines -// -#define PIR_INSTANCE_EVEN_ODD_MASK (uint32_t)(0x00000001) -#define PIR_INSTANCE_NUM_MASK (uint32_t)(0x0000001F) - - -// -// CME FLAGS defines -// -#define CME_FLAGS_STOP_READY (uint32_t)(0x80000000) -#define CME_FLAGS_PMCR_READY (uint32_t)(0x40000000) -#define CME_FLAGS_QMGR_READY (uint32_t)(0x20000000) -#define CME_FLAGS_QMGR_MASTER (uint32_t)(0x10000000) -#define CME_FLAGS_RCLK_READY (uint32_t)(0x08000000) -#define CME_FLAGS_IVRM_READY (uint32_t)(0x04000000) -#define CME_FLAGS_VDM_READY (uint32_t)(0x02000000) - - -// -// Pstate defines -// -enum PSTATE_REQUEST_MODE_VALUES // Partially supported in GA1 -{ - PS_REQ_MODE_DEFAULT = 0, - PS_REQ_MODE_RELATIVE = 1, - PS_REQ_MODE_QOS = 2, // Only mode supported in GA1 - PS_REQ_MODE_PERFORMANCE = 3, - PS_REQ_MODE_LAST = 4 -}; - -enum PSTATE_REQUEST_PRIORITY_VALUES // Not supported in GA1 -{ - PS_REQ_PRTY_LOW = 0, - PS_REQ_PRTY_MEDIUM = 1, - PS_REQ_PRTY_HIGH = 2, - PS_REQ_PRTY_OVERRIDE = 3, - PS_REQ_PRTY_LAST = 4 -}; - -typedef union pmcr_pstate_request -{ - - uint32_t value; - struct - { -#ifdef _BIG_ENDIAN - uint32_t reserved1 : 6; - uint32_t mode : 2; // Partialy supported in GA1 - uint32_t ps_upper : 8; // NOT supported in GA1 - uint32_t reserved2 : 6; - uint32_t priority : 2; // NOT supported in GA1 - uint32_t ps_lower : 8; // Only Pstate supported in GA1 -#else - uint32_t ps_lower : 8; - uint32_t priority : 2; - uint32_t reserved2 : 6; - uint32_t ps_upper : 8; - uint32_t mode : 2; - uint32_t reserved1 : 6; -#endif // _BIG_ENDIAN - } fields; - -} pmcr_pstate_request_t; - -typedef struct pstate_actuation_results -{ - - uint32_t freq_quad_last[MAX_QUADS]; - uint32_t freq_quad_avg[MAX_QUADS]; - uint32_t freq_chip_last; - uint32_t freq_chip_avg; - uint32_t vdd_quad_last[MAX_QUADS]; - uint32_t vdd_quad_avg[MAX_QUADS]; - uint32_t vdd_chip_last; - uint32_t vdd_chip_avg; - -} pstate_actuation_results_t; - - -// -// QCME<->PGPE API -// - -enum MESSAGE_ID_DB0 -{ - MSGID_DB0_INVALID = 0, - MSGID_DB0_RESUME = 1, - MSGID_DB0_SUSPEND = 2, - MSGID_DB0_RESET = 3, - MSGID_DB0_PS_BROADCAST = 4, - MSGID_DB0_ACK = 5 -}; - -enum MESSAGE_ID_DB3 -{ - MSGID_DB3_INVALID = 0, - MSGID_DB3_SAFE_MODE = 1, - MSGID_DB3_PS_BROADCAST = 2, - MSGID_DB3_ACK = 3 -}; - -enum MESSAGE_ID_TYPE4 -{ - MSGID_T4_INVALID = 0, - MSGID_T4_REGISTER_QCME = 1, - MSGID_T4_ACK = 2 -}; - -//------------- -// Doorbell0 -//------------- - -// PGPE->QCME: cb_to_qcme_base -// ------------------------------------ -// This CB to decode the msg_id. -// -typedef union comm_block_to_qcme_base -{ - 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 // _BIG_ENDIAN - } fields; -} cb_to_qcme_base_t; - -// PGPE->QCME: cb_to_qcme_ps_bc -// ------------------------------------ -// This CB is used by PGPE to broadcast Pstate requests. -// -typedef union comm_block_to_qcme_ps_bc -{ - uint64_t value; - struct - { -#ifdef _BIG_ENDIAN - uint64_t msg_id : 8; - uint64_t ps_global : 8; - uint64_t ps_local : 8; - uint64_t reserved : 40; -#else - uint64_t reserved : 40; - uint64_t ps_local : 8; - uint64_t ps_global : 8; - uint64_t msg_id : 8; -#endif // _BIG_ENDIAN - } fields; -} cb_to_qcme_ps_bc_t; - -// PGPE->QCME: cb_to_qcme_ack -// --------------------------- -// This CB is used by PGPE to acknowledge CME requests. -// -typedef union comm_block_to_qcme_ack -{ - uint64_t value; - struct - { -#ifdef _BIG_ENDIAN - uint64_t msg_id : 8; - uint64_t msg_id_ref : 8; - uint64_t rc : 8; - uint64_t reserved : 40; -#else - uint64_t reserved : 40; - uint64_t rc : 8; - uint64_t msg_id_ref : 8; - uint64_t msg_id : 8; -#endif // _BIG_ENDIAN - } fields; -} cb_to_qcme_ack_t; - - -//-------------- -// Type4 -//-------------- - -// QCME->PGPE: cb_to_pgpe_base -// ---------------------------- -// Used by PGPE to decode the msg_id. -// -typedef union comm_block_to_pgpe_base -{ - uint16_t value; - struct - { -#ifdef _BIG_ENDIAN - uint16_t do_not_use : 4; - uint16_t msg_id : 3; - uint16_t reserved : 9; -#else - uint16_t reserved : 9; - uint16_t msg_id : 3; - uint16_t do_not_use : 4; -#endif // _BIG_ENDIAN - } fields; -} cb_to_pgpe_base_t; - -// QCME->PGPE: cb_to_pgpe_qcme -// ---------------------------- -// Used by QCME to register itself with the PGPE. -// -typedef union comm_block_to_pgpe_qcme +typedef struct { - uint16_t value; - struct - { -#ifdef _BIG_ENDIAN - uint16_t do_not_use : 4; - uint16_t msg_id : 3; - uint16_t reserved : 9; -#else - uint16_t reserved : 9; - uint16_t msg_id : 3; - uint16_t do_not_use : 4; -#endif // _BIG_ENDIAN - } fields; -} cb_to_pgpe_qcme_t; + PkSemaphore sem[2]; +} CmePstateRecord; -// QCME->PGPE: cb_to_pgpe_ack -// --------------------------- -// Used by QCME to acknowledge DB requests. -// -typedef union comm_block_to_pgpe_ack +typedef struct { - uint16_t value; - struct - { -#ifdef _BIG_ENDIAN - uint16_t do_not_use : 4; - uint16_t msg_id : 3; - uint16_t msg_id_ref : 3; // Put msg_id from PGPE request - uint16_t reserved : 3; - uint16_t rc : 3; -#else - uint16_t rc : 3; - uint16_t reserved : 3; - uint16_t msg_id_ref : 3; - uint16_t msg_id : 3; - uint16_t do_not_use : 4; -#endif // _BIG_ENDIAN - } fields; -} cb_to_pgpe_ack_t; + uint64_t seqNum; + uint32_t cmeFlags; + uint8_t coreGood[CORES_PER_EX]; +} cme_pstate_pmcr_data_t; -// -// Return Codes -// -enum API_RETURN_CODES +typedef struct { - API_RC_INVALID = 0, // Don't use zero. Not reliable. - API_RC_SUCCESS = 1, - API_RC_FAILURE = 2 -}; + uint8_t qmFlag; + uint8_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; +} cme_pstate_db_data_t; diff --git a/import/chips/p9/procedures/ppe_closed/cme/topfiles.mk b/import/chips/p9/procedures/ppe_closed/cme/topfiles.mk index f4254d07..4a8b5ce6 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/topfiles.mk +++ b/import/chips/p9/procedures/ppe_closed/cme/topfiles.mk @@ -29,8 +29,10 @@ 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 + utils/plat_ring_traverse.c + +PSTATE-C-SOURCES = pstate_cme/p9_cme_pstate.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/Makefile b/import/chips/p9/procedures/ppe_closed/pgpe/Makefile index 298bceac..1a291ab7 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/Makefile +++ b/import/chips/p9/procedures/ppe_closed/pgpe/Makefile @@ -30,8 +30,8 @@ ifndef BASE_SRCDIR BASE_SRCDIR = $(abspath ./) endif -CME_OBJDIR = $(abspath ../cme/obj/) -CME_SRCDIR = $(abspath ../cme/) +#CME_OBJDIR = $(abspath ../cme/obj/) +#CME_SRCDIR = $(abspath ../cme/) PGPE_OBJDIR = $(BASE_OBJDIR) PGPE_SRCDIR = $(BASE_SRCDIR) @@ -41,32 +41,35 @@ endif THASH = $(PPETRACEPP_DIR)/tracehash.pl -CME_IMAGE_NAME = cme +#CME_IMAGE_NAME = cme GPE_IMAGE_NAME = pstate_gpe +#NEEDED_IMAGES = \ + # $(CME_OBJDIR)/$(CME_IMAGE_NAME)/$(CME_IMAGE_NAME).out \ + $(PGPE_OBJDIR)/$(GPE_IMAGE_NAME)/$(GPE_IMAGE_NAME).out NEEDED_IMAGES = \ - $(CME_OBJDIR)/$(CME_IMAGE_NAME)/$(CME_IMAGE_NAME).out \ $(PGPE_OBJDIR)/$(GPE_IMAGE_NAME)/$(GPE_IMAGE_NAME).out + #default is to build images needed_images: $(NEEDED_IMAGES) -run: $(NEEDED_IMAGES) - $(SIMICS_WS)/simics \ - -e '$$cme_binary_to_load=$(CME_OBJDIR)/$(CME_IMAGE_NAME)/$(CME_IMAGE_NAME).out' \ - -e '$$gpe_binary_to_load=$(PGPE_OBJDIR)/$(GPE_IMAGE_NAME)/$(GPE_IMAGE_NAME).out' \ - modelsetup.simics +#run: $(NEEDED_IMAGES) +# $(SIMICS_WS)/simics \ +# -e '$$cme_binary_to_load=$(CME_OBJDIR)/$(CME_IMAGE_NAME)/$(CME_IMAGE_NAME).out' \ +# -e '$$gpe_binary_to_load=$(PGPE_OBJDIR)/$(GPE_IMAGE_NAME)/$(GPE_IMAGE_NAME).out' \ +# modelsetup.simics #clean the obj directory clean: - rm -fr $(CME_OBJDIR)/$(CME_IMAGE_NAME) +# rm -fr $(CME_OBJDIR)/$(CME_IMAGE_NAME) rm -fr $(PGPE_OBJDIR)/$(GPE_IMAGE_NAME) #make binary application images -$(CME_OBJDIR)/$(CME_IMAGE_NAME)/$(CME_IMAGE_NAME).out: - (cd $(CME_SRCDIR) && make && make fmode && make tracehash) +#$(CME_OBJDIR)/$(CME_IMAGE_NAME)/$(CME_IMAGE_NAME).out: +# (cd $(CME_SRCDIR) && make && make fmode && make tracehash) $(PGPE_OBJDIR)/$(GPE_IMAGE_NAME)/$(GPE_IMAGE_NAME).out: (cd $(PGPE_SRCDIR)/$(GPE_IMAGE_NAME) && make && make fmode && make tracehash) diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/avs_driver.c b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/avs_driver.c index 909464b3..016b4613 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/avs_driver.c +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/avs_driver.c @@ -37,7 +37,7 @@ #include "pk.h" #include "avs_driver.h" -#include "pstate.h" +//#include "pstate.h" //################################################################################################# diff --git a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/avs_driver.h b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/avs_driver.h index 5060261a..a07b9792 100644 --- a/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/avs_driver.h +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/avs_driver.h @@ -25,9 +25,18 @@ // // Setup and enable the O2S bridge on the AVS bus. // + +#ifndef _AVS_DRIVER_H_ +#define _AVS_DRIVER_H_ + +#define VEXT_SLEW_RATE_MVPERUS 0x0A0A // Trise=Tfall=10mv/us +#define MAX_POLL_COUNT_AVS 10 + void external_voltage_control_init(uint32_t* vext_read_mv); void external_voltage_control_write(uint32_t vext_write_mv); + +#endif //_AVS_DRIVER_H_ 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 new file mode 100644 index 00000000..7b5a21f2 --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe.h @@ -0,0 +1,67 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe.h $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2015,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 */ +/// +/// \file p9_pgpe.h +/// \brief header of p9_cme_stop_enter_thread.c and p9_cme_stop_exit.c +/// + +#ifndef _P9_PGPE_H_ +#define _P9_PGPE_H_ + +#include "pk.h" +#include "ppe42.h" +#include "ppe42_scom.h" + +#include "ppehw_common.h" +#include "gpehw_common.h" +#include "occhw_interrupts.h" + +#include "ocb_register_addresses.h" +#include "cme_register_addresses.h" +#include "ppm_register_addresses.h" +#include "cppm_register_addresses.h" +#include "qppm_register_addresses.h" + +#include "ocb_firmware_registers.h" +#include "cme_firmware_registers.h" +#include "ppm_firmware_registers.h" +#include "cppm_firmware_registers.h" +#include "qppm_firmware_registers.h" + +#include "p9_pgpe_irq.h" +#include "p9_pstate_common.h" + + +/// PGPE PState +typedef struct +{ + PkSemaphore sem[1]; +} PgpePstateRecord; + +/// PGPE PState +void p9_pgpe_pstate_pig_handler(void* arg, PkIrqId irq); +void p9_pgpe_pstate_thread(void* arg); + +#endif //_P9_PGPE_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 new file mode 100644 index 00000000..6ab938dc --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.c @@ -0,0 +1,199 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.c $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2015,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 */ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file p9_pgpe_irq.c +/// \brief Shared and global file for PGPE (GPE2) H-codes. +/// + +#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_<task_abbr>, +// must match. IDX_PRTY_LVL_<task_abbr> is the tasks priority level and serves +// as the index into the ext_irq_vectors_gpe[][] table. + +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_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_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_PRTY3_GPE2, IRQ_VEC_PRTY3_GPE2 } , /* 3: IDX_PRTY_LVL_TYPE1 */ + + { IRQ_VEC_PRTY4_GPE2, IRQ_VEC_PRTY4_GPE2 } /* 4: IDX_PRTY_LVL_DISABLED */ + + /* 0: IDX_PRTY_VEC 1: IDX_MASK_VEC */ +}; + +/*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; + +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; +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. +// +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 | + // (uint64_t)in32(OCB_OISR1); + //CMO-swap above lines comments when we've defined the HI PRTY interrupts correctly, i.e. + // right now they fire all the time because by default they are defined as LEVEL + // SENSITIVE and ACTIVE LOW. + bFound = FALSE; + iPrtyLvl = 0; + + do + { + if ( ext_irq_vectors_gpe[iPrtyLvl][IDX_PRTY_VEC] & ext_irq_vector_pk ) + { + bFound = TRUE; + break; + } + } + 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. + // + 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) ); + + } + else + { + MY_TRACE_ERR("A disabled IRQ fired"); + MY_TRACE_ERR("ext_irq_vector_pk=0x%08x%08x", ext_irq_vector_pk); + 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. + // + + 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]) ); + +} 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 new file mode 100644 index 00000000..4f9e6eb1 --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.h @@ -0,0 +1,144 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_irq.h $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2015,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 */ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2015 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file p9_pgpe_irq.h +/// \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 +// in this file are: +// - IRQ_VEC_PRTY(n>0)_GPE(x) +// - 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_ + +// We define four levels of TRACE outputs: +// _INF: Trace level used for main informational events. +// _DBG: Trace level used for expanded debugging. +// _WARN: Trace level used when suspecious event happens. +// _ERR: Trace level at time of an error that leads to a halt. +#define MY_TRACE_INF(...) PK_TRACE("INF: "__VA_ARGS__); +#ifdef DEV_DEBUG + #define MY_TRACE_DBG(...) PK_TRACE("DBG: "__VA_ARGS__); +#else + #define MY_TRACE_DBG(...) +#endif +#define MY_TRACE_WARN(...) PK_TRACE("WARN: "__VA_ARGS__); +#define MY_TRACE_ERR(...) PK_TRACE("ERR: "__VA_ARGS__); + +#define TRUE 1 +#define FALSE 0 + +#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_DISABLED 4 +#define IDX_PRTY_VEC 0 +#define IDX_MASK_VEC 1 +#define NUM_EXT_IRQ_PRTY_LEVELS (uint8_t)(5) +extern const uint64_t ext_irq_vectors_gpe[NUM_EXT_IRQ_PRTY_LEVELS][2]; + +#define IRQ_VEC_PRTY0_GPE (uint64_t)(0xFFD1690000000000) // Non-task hi-prty IRQs +// Shared between all instances +#define IRQ_VEC_PRTY1_GPE2 (uint64_t)(0x0020000000000000) // 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)(0x000E96EFFFFDBFFF) // 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! + +#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;*/ + +extern uint8_t g_current_prty_level; +extern uint8_t g_oimr_stack[NUM_EXT_IRQ_PRTY_LEVELS]; +extern int g_oimr_stack_ctr; +extern uint64_t g_oimr_override_stack[NUM_EXT_IRQ_PRTY_LEVELS]; +extern uint64_t g_oimr_override; + + +/// Restore a vector of interrupts by overwriting OIMR. +UNLESS__PPE42_IRQ_CORE_C__(extern) +inline void +pk_irq_vec_restore( PkMachineContext* context) +{ + pk_critical_section_enter(context); + + if (g_oimr_stack_ctr >= 0) + { + out32( OCB_OIMR0_CLR, (uint32_t)((IRQ_VEC_ALL_OUR_IRQS | + g_oimr_override_stack[g_oimr_stack_ctr]) >> 32)); + out32( OCB_OIMR1_CLR, (uint32_t)(IRQ_VEC_ALL_OUR_IRQS | + g_oimr_override_stack[g_oimr_stack_ctr])); + out32( OCB_OIMR0_OR, + (uint32_t)((ext_irq_vectors_gpe[g_oimr_stack[g_oimr_stack_ctr]][IDX_MASK_VEC] | + g_oimr_override) >> 32)); + out32( OCB_OIMR1_OR, + (uint32_t)(ext_irq_vectors_gpe[g_oimr_stack[g_oimr_stack_ctr]][IDX_MASK_VEC] | + g_oimr_override)); + // Restore the prty level tracker to the task that was interrupted, if any. + g_current_prty_level = g_oimr_stack[g_oimr_stack_ctr]; + g_oimr_stack_ctr--; + } + else + { + PK_TRACE("ERR: Code bug: Messed up OIMR book keeping: g_oimr_stack_ctr=%d", + g_oimr_stack_ctr); + pk_halt(); + } + + pk_critical_section_exit(context); +} + +#endif // _P9_PGPE_IRQ_H_ 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 new file mode 100644 index 00000000..865edf3c --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_main.c @@ -0,0 +1,142 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_main.c $ */ +/* */ +/* OpenPOWER HCODE Project */ +/* */ +/* COPYRIGHT 2015,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" + +PgpePstateRecord G_pgpe_pstate_record; + +EXTERNAL_IRQ_TABLE_START +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_DEBUGGER +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_TRACE_TRIGGER +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_OCC_ERROR +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PBA_ERROR +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_SRT_ERROR +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_GPE0_HALT +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_GPE1_HALT +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_GPE2_HALT +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_GPE3_HALT +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PPC405_HALT +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_OCB_ERROR +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_SPIPSS_ERROR +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_CHECK_STOP_PPC405 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_CHECK_STOP_GPE0 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_CHECK_STOP_GPE1 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_CHECK_STOP_GPE2 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_CHECK_STOP_GPE3 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_OCC_MALF_ALERT +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_ADU_MALF_ALERT +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_EXTERNAL_TRAP +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_IVRM_PVREF_ERROR +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_OCC_TIMER0 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_OCC_TIMER1 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_AVS_SLAVE0 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_AVS_SLAVE1 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_IPI0_HI_PRIORITY +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_IPI1_HI_PRIORITY +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_IPI2_HI_PRIORITY +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_IPI3_HI_PRIORITY +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_IPI4_HI_PRIORITY +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_ADCFSM_ONGOING +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_RESERVED_31 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PBAX_OCC_SEND +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PBAX_OCC_PUSH0 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PBAX_OCC_PUSH1 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PBA_BCDE_ATTN +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PBA_BCUE_ATTN +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_STRM0_PULL +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_STRM0_PUSH +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_STRM1_PULL +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_STRM1_PUSH +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_STRM2_PULL +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]) +//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 +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PMC_PCB_INTR_TYPE4_PENDING +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PMC_PCB_INTR_TYPE5_PENDING +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PMC_PCB_INTR_TYPE6_PENDING +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PMC_PCB_INTR_TYPE7_PENDING +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PMC_O2S_0A_ONGOING +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PMC_O2S_0B_ONGOING +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PMC_O2S_1A_ONGOING +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PMC_O2S_1B_ONGOING +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_PSSBRIDGE_ONGOING +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_IPI0_LO_PRIORITY +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_IPI1_LO_PRIORITY +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_IPI2_LO_PRIORITY +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_IPI3_LO_PRIORITY +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_IPI4_LO_PRIORITY +IRQ_HANDLER_DEFAULT //OCCHW_IRQ_RESERVED_63 +EXTERNAL_IRQ_TABLE_END + +#define KERNEL_STACK_SIZE 512 +#define THREAD_STACK_SIZE 512 + +#define PGPE_THREAD_PRIORITY_PSTATE 1 + +uint8_t G_kernel_stack[KERNEL_STACK_SIZE]; + +uint8_t G_p9_pgpe_pstate_thread_stack[THREAD_STACK_SIZE]; + +PkThread G_p9_pgpe_pstate_thread; + +void __eabi() +{ +} + +int +main(int argc, char** argv) +{ + // 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_stop_enter_thread + pk_thread_create(&G_p9_pgpe_pstate_thread, + (PkThreadRoutine)p9_pgpe_pstate_thread, + (void*)NULL, + (PkAddress)G_p9_pgpe_pstate_thread_stack, + (size_t)THREAD_STACK_SIZE, + (PkThreadPriority)PGPE_THREAD_PRIORITY_PSTATE); + + PK_TRACE_BIN("G_p9_pgpe_pstate_thread", + &G_p9_pgpe_pstate_thread, + sizeof(G_p9_pgpe_pstate_thread)); + + // Make G_p9_sgpe_stop_exit_thread runnable + pk_thread_resume(&G_p9_pgpe_pstate_thread); + + // Start running the highest priority thread. + // This function never returns + pk_start_threads(); + + return 0; +} 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 new file mode 100644 index 00000000..b28a9dfe --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.c @@ -0,0 +1,663 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/pgpe/pstate_gpe/p9_pgpe_pstate.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_pstate_vpd.h" //\todo Temporary +#include "p9_pstate_common.h" +#include "p9_pgpe.h" +#include "avs_driver.h" + +#define EVID_SLOPE_FP_SHIFT 13 +#define CCSR_CORE_CONFIG_MASK 0xC0000000 + +enum quadManager +{ + QUAD_MANAGER_NONE = -1, + QUAD_MANAGER_CME0 = 0, + QUAD_MANAGER_CME1 = 1 +}; + +//Data derived from VPD(PPB) +uint16_t G_FVSlopes[VPD_PV_POINTS - 1]; +uint16_t G_invFVSlopes[VPD_PV_POINTS - 1]; + +//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]; +uint8_t G_coreConf[MAX_CORES]; +extern PgpePstateRecord G_pgpe_pstate_record; +extern global_pstate_table_t G_gpst; + +// +//Function Prototypes +// +void p9_pgpe_pstate_init_derived_data(); +void p9_pgpe_pstate_get_config(); +uint32_t p9_pgpe_pstate_get_evid_from_pstate(uint8_t pstate); +uint8_t p9_pgpe_pstate_get_pstate_from_evid(uint16_t evid); +void p9_pgpe_pstate_update_ext_volt(); +void p9_pgpe_pstate_freq_update(); + +// +//PIG Interrupt Handler +// +void p9_pgpe_pstate_pig_handler(void* arg, PkIrqId irq) +{ + //Read OCC_FLAG[PGPE_STARTNOTSTOP]] + uint32_t occFlag = in32(OCB_OCCFLG); + + if (occFlag & BIT32(0)) + { + pk_semaphore_post((PkSemaphore*)arg); + } + +} + +// +//PState Thread +// +void p9_pgpe_pstate_thread(void* arg) +{ + 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; + + //Initialization + + //todo Read this data from HOMER/PPMR. RTC 159902 + p9_pstate_vpd_init(); + + //\todo Set initial eVid, Global PState, Local PState, Max/Mins PStateClip for PGPE. RTC. 159900 + psClipMax = 0; + psClipMin = 140; + coresPendPSReq = 0; + G_eVidCurr = G_gpst.infPT[POWERSAVE].evid; + G_eVidNext = G_gpst.infPT[POWERSAVE].evid; + G_globalCurrPS = G_globalNextPS = G_gpst.infPT[POWERSAVE].pstate; + + for (q = 0; q < MAX_QUADS; q++) + { + G_localPSCurr[q] = G_gpst.infPT[POWERSAVE].pstate; + G_localPSNext[q] = G_gpst.infPT[POWERSAVE].pstate; + G_localPSTgt[q] = G_gpst.infPT[POWERSAVE].pstate; + G_quadPendPSReq[q] = 0; + } + + for (c = 0; c < MAX_CORES; c++) + { + G_coresPendPSReqData[c] = G_gpst.infPT[POWERSAVE].pstate; + } + + //Initialization + external_voltage_control_init(&G_eVidCurr); + G_eVidCurr = G_gpst.infPT[POWERSAVE].evid; //\todo RTC 159900. Remove this + p9_pgpe_pstate_init_derived_data(); + 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); + + //Set OCC_FLAG[PGPE_ACTIVE] + out32(OCB_OCCFLG_OR, BIT32(4)); +#if EPM_P9_TUNING + asm volatile ("tw 0, 31, 0"); +#endif + + //Thread Loop + while (1) + { + //pend on semaphore + pk_semaphore_pend(&(G_pgpe_pstate_record.sem[0]), PK_WAIT_FOREVER); + + done = 0; + + while (done == 0) + { + //Snapshot + coresPendPSReq = in32(OCB_OPIT1PRA); + + //Make sure clips aren't below or above VPD points + if (psClipMax < G_gpst.infPT[ULTRA].pstate) + { + effPSClipMax = G_gpst.infPT[ULTRA].pstate; + } + else + { + effPSClipMax = psClipMax; + } + + if (psClipMin > G_gpst.infPT[POWERSAVE].pstate) + { + effPSClipMin = G_gpst.infPT[POWERSAVE].pstate; + } + else + { + effPSClipMin = psClipMin; + } + + 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_type_a_core_n; + uint16_t op1 = opit1cn.fields.pcb_intr_type_a_core_n; + + //make sure seq number matches for both phases + //otherwise, ignore the request + if (((op0 >> 10) && 0x3) == + ((op1 >> 10) && 0x3)) + { + //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 + } + } + } + + //Local PStates + 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_gpst.infPT[POWERSAVE].pstate; + + for (c = (q * CORES_PER_QUAD); c < (q + 1)*CORES_PER_QUAD; c++) + { + if (G_coreConf[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; + } + } + + //Global PState + G_globalPSTgt = G_gpst.infPT[POWERSAVE].pstate; + + for (q = 0; q < MAX_QUADS; q++) + { + if ((G_quadManagerCME[q] != QUAD_MANAGER_NONE)) + { + if (G_globalPSTgt > G_localPSTgt[q]) + { + G_globalPSTgt = G_localPSTgt[q]; + } + } + } + + +#if EPM_P9_TUNING + asm volatile ("tw 0, 31, 0"); +#endif + + //Determine targetVoltage + G_tgtEVid = p9_pgpe_pstate_get_evid_from_pstate(G_globalPSTgt); + + //Higher number PState + if (((int16_t)(G_globalPSTgt) - (int16_t)(G_globalCurrPS)) > 0) + { + if ((G_eVidCurr - G_tgtEVid) <= G_gpst.evid_step_size) + { + 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_gpst.evid_step_size; + G_globalNextPS = p9_pgpe_pstate_get_pstate_from_evid(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_freq_update(); + p9_pgpe_pstate_update_ext_volt(); + } + //Lower number PState + else if (((int16_t)(G_globalPSTgt) - (int16_t)(G_globalCurrPS)) < 0) + { + if ((G_tgtEVid - G_eVidCurr) <= G_gpst.evid_step_size) + { + 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_gpst.evid_step_size; + G_globalNextPS = p9_pgpe_pstate_get_pstate_from_evid(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(); + } + else + { + for (q = 0; q < MAX_QUADS; q++) + { + G_localPSNext[q] = G_localPSTgt[q]; + } + + p9_pgpe_pstate_freq_update(); + done = 1; + } + } + + pk_irq_vec_restore(&ctx);//Restore interrupts + }//Thread Loop +} + +// +//init_vpd_derived_data +// +void p9_pgpe_pstate_init_derived_data() +{ + int32_t i; + uint32_t eVidFP[VPD_PV_POINTS]; + + //convert to fixed-point number + for (i = 0; i < VPD_PV_POINTS; i++) + { + eVidFP[i] = (G_gpst.infPT[i].evid << EVID_SLOPE_FP_SHIFT); + } + + //PState(Frequency) on y-axis, Voltage is on x-axis for VF curve + //Interpolation formula: (y-y0)/(x-x0) = (y1-y0)/(x1-x0) + //m = (x1-x0)/(y1-y0), then use this to calculate voltage, x = (y-y0)*m + x0 + //1/m = (y1-y0)/(x1-x0) here, then use this to calculate pstate(frequency), y = (x-x0)*m + y0 + //Region 0 is b/w POWERSAVE and NOMINAL + //Region 1 is b/w NOMINAL and TURBO + //Region 2 is between TURBO and ULTRA_TURBO + // + //Inflection Point 3 is ULTRA_TURBO + //Inflection Point 2 is TURBO + //Inflection Point 1 is NOMINAL + //Inflection Point 0 is POWERSAVE + // + for (i = 0; i < VPD_PV_POINTS - 1; i++) + { + //Note: Since PState number decrease with frequency, + //we flip the sign(add a minus) + uint32_t tmp = (uint32_t)(eVidFP[i + 1] - eVidFP[i]) / + (uint32_t)(-G_gpst.infPT[i + 1].pstate + G_gpst.infPT[i].pstate); + G_FVSlopes[i] = tmp; + + tmp = (uint32_t)((-G_gpst.infPT[i + 1].pstate + G_gpst.infPT[i].pstate) << EVID_SLOPE_FP_SHIFT) + / (uint32_t) (G_gpst.infPT[i + 1].evid - G_gpst.infPT[i].evid); + G_invFVSlopes[i] = tmp; + } +} + +// +//p9_pgpe_pstate_get_evid_from_pstate +// +uint32_t p9_pgpe_pstate_get_evid_from_pstate(uint8_t pstate) +{ + uint32_t ret_evid; + + //Interpolate voltage based on the region PState falls under + if (pstate > G_gpst.infPT[ULTRA].pstate + && pstate < G_gpst.infPT[TURBO].pstate) + { + ret_evid = (((G_FVSlopes[REGION_TURBO_ULTRA]) * + (-pstate + G_gpst.infPT[TURBO].pstate)) >> EVID_SLOPE_FP_SHIFT) + + G_gpst.infPT[TURBO].evid; + } + else if (pstate > G_gpst.infPT[TURBO].pstate + && pstate < G_gpst.infPT[NOMINAL].pstate) + { + ret_evid = (((G_FVSlopes[REGION_NOMINAL_TURBO]) * + (-pstate + G_gpst.infPT[NOMINAL].pstate)) >> EVID_SLOPE_FP_SHIFT) + + G_gpst.infPT[NOMINAL].evid; + } + else if (pstate > G_gpst.infPT[NOMINAL].pstate + && pstate < G_gpst.infPT[POWERSAVE].pstate) + { + ret_evid = (((G_FVSlopes[REGION_POWERSAVE_NOMINAL]) * + (- pstate + G_gpst.infPT[POWERSAVE].pstate)) >> EVID_SLOPE_FP_SHIFT) + + G_gpst.infPT[POWERSAVE].evid; + } + else + { + if (pstate == G_gpst.infPT[ULTRA].pstate) + { + ret_evid = G_gpst.infPT[ULTRA].evid; + } + else if (pstate == G_gpst.infPT[TURBO].pstate) + { + ret_evid = G_gpst.infPT[TURBO].evid; + } + else if (pstate == G_gpst.infPT[NOMINAL].pstate) + { + ret_evid = G_gpst.infPT[NOMINAL].evid; + } + else if (pstate == G_gpst.infPT[POWERSAVE].pstate) + { + ret_evid = G_gpst.infPT[POWERSAVE].evid; + } + else + { + pk_halt(); + } + } + + return (ret_evid); +} + + +// +//p9_pgpe_pstate_get_pstate_from_evid +// +uint8_t p9_pgpe_pstate_get_pstate_from_evid(uint16_t evid) +{ + uint32_t ret_ps; + + //Interpolate pstate based on the region voltage falls under + if (evid < G_gpst.infPT[ULTRA].evid + && evid > G_gpst.infPT[TURBO].evid) + { + ret_ps = -(((G_invFVSlopes[REGION_TURBO_ULTRA]) * + (evid - G_gpst.infPT[TURBO].evid)) >> EVID_SLOPE_FP_SHIFT) + + G_gpst.infPT[TURBO].pstate; + } + else if (evid < G_gpst.infPT[TURBO].evid + && evid > G_gpst.infPT[NOMINAL].evid) + { + ret_ps = -(((G_invFVSlopes[REGION_NOMINAL_TURBO]) * + (evid - G_gpst.infPT[NOMINAL].evid)) >> EVID_SLOPE_FP_SHIFT) + + G_gpst.infPT[NOMINAL].pstate; + } + else if (evid < G_gpst.infPT[NOMINAL].evid + && evid > G_gpst.infPT[POWERSAVE].evid) + { + ret_ps = -(((G_invFVSlopes[REGION_POWERSAVE_NOMINAL]) * + (evid - G_gpst.infPT[POWERSAVE].evid)) >> EVID_SLOPE_FP_SHIFT) + + G_gpst.infPT[POWERSAVE].pstate; + } + else + { + if (evid == G_gpst.infPT[ULTRA].evid) + { + ret_ps = G_gpst.infPT[ULTRA].pstate; + } + else if (evid == G_gpst.infPT[TURBO].evid) + { + ret_ps = G_gpst.infPT[TURBO].pstate; + } + else if (evid == G_gpst.infPT[NOMINAL].evid) + { + ret_ps = G_gpst.infPT[NOMINAL].pstate; + } + else if (evid == G_gpst.infPT[POWERSAVE].evid) + { + ret_ps = G_gpst.infPT[POWERSAVE].pstate; + } + else + { + pk_halt(); + } + } + + return ret_ps; +} + +uint8_t p9_pgpe_pstate_get_evid_region(uint32_t evid) +{ + if (evid > G_gpst.infPT[TURBO].evid) + { + return REGION_TURBO_ULTRA; + } + else if (evid < G_gpst.infPT[NOMINAL].evid) + { + return REGION_POWERSAVE_NOMINAL; + } + else + { + return REGION_NOMINAL_TURBO; + } +} + +// +//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]; + 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; + } + } + + //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 & (0x80000000 >> c)) + { + 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; + } + } + } + + //Update Current Global and Local PState + G_globalCurrPS = G_globalNextPS; + + for (q = 0; q < MAX_QUADS; q++) + { + G_localPSCurr[q] = G_localPSNext[q]; + } +} + +// +//Determine which CMEs are quad manager +// +void p9_pgpe_pstate_get_config() +{ + int32_t q, c; + ocb_ccsr_t ccsr; + ccsr.value = in32(OCB_CCSR); + + for (c = 0; c < MAX_CORES; c++) + { + if (ccsr.value & (0x80000000 >> c)) + { + G_coreConf[c] = 1; + } + else + { + G_coreConf[c] = 0; + } + } + + 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; + } + } +} 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 ea182c15..aefd2684 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 @@ -33,8 +33,37 @@ /// \file pk_app_cfg.h /// \brief Application specific overrides go here. /// -#include "occ_app_cfg.h" -#include "global_app_cfg.h" + +// -------------------- +#define EPM_P9_TUNING 1 +#define SIMICS_TUNING 1 +#define DEV_DEBUG 1 +#define PK_TRACE_TIMER_OUTPUT 0 + +// Force CME and GPE tasks to use the unified interrupt handler. +#define UNIFIED_IRQ_HANDLER_GPE + +// This application will use the external timebase register +// (comment this line out to use the decrementer as timebase) +#define APPCFG_USE_EXT_TIMEBASE + + +// If we are using the external timebase then assume +// a frequency of 37.5Mhz. Otherwise, the default is to use +// the decrementer as a timebase and assume a frequency of +// 600MHz +// In product code, this value will be IPL-time configurable. +#ifdef APPCFG_USE_EXT_TIMEBASE + #define PPE_TIMEBASE_HZ 37500000 +#else + #define PPE_TIMEBASE_HZ 600000000 +#endif /* APPCFG_USE_EXT_TIMEBASE */ + +// -------------------- + +// GPE2 is the PGPE and is the route owner for now. +// (Change this to #3 when pulling in SGPE) +#define OCCHW_IRQ_ROUTE_OWNER 2 /// The Instance ID of the OCC processor that this application is intended to run on ///// 0-3 -> GPE, 4 -> 405 @@ -60,6 +89,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_TYPE4_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 f19d3907..212a8bde 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 @@ -30,7 +30,7 @@ EKB_BUILD = 1 ## Set _TARGET = PPC2PPE to use the 405 compiler with PPE backend or # set _TARGET = PPE to use the new native compiler -$(IMAGE)_TARGET=PPC2PPE +$(IMAGE)_TARGET=PPE ## PPE_TYPE can be std or gpe _PPE_TYPE=gpe 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 414acd71..ca6f0a31 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 @@ -22,7 +22,7 @@ # permissions and limitations under the License. # # IBM_PROLOG_END_TAG -TOP-C-SOURCES = pstate_gpe.c gpe2_irq_common.c pk_app_irq_table.c avs_driver.c +TOP-C-SOURCES = p9_pgpe_pstate.c p9_pgpe_main.c p9_pgpe_irq.c avs_driver.c p9_pstate_vpd.c TOP-S-SOURCES = TOP_OBJECTS = $(TOP-C-SOURCES:.c=.o) $(TOP-S-SOURCES:.S=.o) |

