diff options
Diffstat (limited to 'import/chips/p9/procedures/ppe_closed/cme')
18 files changed, 2595 insertions, 537 deletions
diff --git a/import/chips/p9/procedures/ppe_closed/cme/link.cmd b/import/chips/p9/procedures/ppe_closed/cme/link.cmd new file mode 100644 index 00000000..10436196 --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/cme/link.cmd @@ -0,0 +1,121 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/cme/link.cmd $ */ +/* */ +/* 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 */ + +// Need to do this so that elf32-powerpc is not modified! +#undef powerpc + +#ifndef INITIAL_STACK_SIZE +#define INITIAL_STACK_SIZE 256 +#endif + +OUTPUT_FORMAT(elf32-powerpc); + +#define SRAM_START 0xffff8000 +#define SRAM_LENGTH 0x8000 +#define PPE_DEBUG_PTRS_OFFSET 0x180 + +MEMORY +{ + sram : ORIGIN = SRAM_START, LENGTH = SRAM_LENGTH +} + +// This symbol is only needed by external debug tools, so add this command +// to ensure that table is pulled in by the linker even though PPE code +// never references it. +EXTERN(pk_debug_ptrs); + +SECTIONS +{ + . = SRAM_START; + + . = ALIGN(512); + + _VECTOR_START = .; + + .vectors _VECTOR_START : { *(.vectors) } > sram + + /////////////////////////////////////////////////////////////////////////// + // Debug Pointers Table + // + // We want the debug pointers table to always appear at + // PPE_DEBUG_PTRS_OFFSET from the IVPR address. + /////////////////////////////////////////////////////////////////////////// + + _DEBUG_PTRS_START = _VECTOR_START + PPE_DEBUG_PTRS_OFFSET; + .debug_ptrs _DEBUG_PTRS_START : { *(.debug_ptrs) } > sram + + //////////////////////////////// + // All non-vector code goes here + //////////////////////////////// + .text : { *(.text) } > sram + + //////////////////////////////// + // Read-only Data + //////////////////////////////// + + . = ALIGN(8); + _RODATA_SECTION_BASE = .; + + // SDA2 constant sections .sdata2 and .sbss2 must be adjacent to each + // other. Our SDATA sections are small so we'll use strictly positive + // offsets. + + _SDA2_BASE_ = .; + .sdata2 . : { *(.sdata2*) } > sram + .sbss2 . : { *(.sbss2*) } > sram + + // Other read-only data. + + .rodata . : { *(.rodata*) *(.got2) } > sram + + _RODATA_SECTION_SIZE = . - _RODATA_SECTION_BASE; + + //////////////////////////////// + // Read-write Data + //////////////////////////////// + + . = ALIGN(8); + _DATA_SECTION_BASE = .; + + // SDA sections .sdata and .sbss must be adjacent to each + // other. Our SDATA sections are small so we'll use strictly positive + // offsets. + + _SDA_BASE_ = .; + .sdata . : { *(.sdata*) } > sram + .sbss . : { *(.sbss*) } > sram + + // Other read-write data + // It's not clear why boot.S is generating empty .glink,.iplt + + .rela . : { *(.rela*) } > sram + .rwdata . : { *(.data*) *(.bss*) } > sram +// .iplt . : { *(.iplt) } > sram + + _PK_INITIAL_STACK_LIMIT = .; + . = . + INITIAL_STACK_SIZE; + _PK_INITIAL_STACK = . - 1; + +} 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 new file mode 100644 index 00000000..92512c7e --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/cme/p9_cme_irq.c @@ -0,0 +1,183 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/cme/p9_cme_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 cme_irq_common.c +/// \brief Shared and global file for CME H-codes. +/// \owner Michael Olsen Email: cmolsen@us.ibm.com +/// \owner David Du Email: daviddu@us.ibm.com +/// + +#include "pk.h" +#include "p9_cme_irq.h" + +//-------------------------------------------------------------------// +// DO NOT modify this file unless you're the owner // +//-------------------------------------------------------------------// + +// Notes: +// The following two lists, +// ext_irq_vectors_cme[][] 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_cme[][] table. + +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_PRTY5_CME | + //IRQ_VEC_PRTY4_CME | + IRQ_VEC_PRTY3_CME | + IRQ_VEC_PRTY2_CME | + IRQ_VEC_PRTY1_CME | + IRQ_VEC_PRTY0_CME + }, + { + IRQ_VEC_PRTY1_CME, + IRQ_VEC_PRTY6_CME | /* 1: IDX_PRTY_LVL_BCE_DB3 */ + IRQ_VEC_PRTY5_CME | + //IRQ_VEC_PRTY4_CME | + IRQ_VEC_PRTY3_CME | + IRQ_VEC_PRTY2_CME | + IRQ_VEC_PRTY1_CME + }, + { + IRQ_VEC_PRTY2_CME, + IRQ_VEC_PRTY6_CME | /* 2: IDX_PRTY_LVL_WAKE_DB2 */ + IRQ_VEC_PRTY5_CME | + //IRQ_VEC_PRTY4_CME | + IRQ_VEC_PRTY3_CME | + IRQ_VEC_PRTY2_CME + }, + { + IRQ_VEC_PRTY3_CME, + IRQ_VEC_PRTY6_CME | /* 3: IDX_PRTY_LVL_STOP */ + 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_PRTY5_CME //| + //IRQ_VEC_PRTY4_CME + }, + { + IRQ_VEC_PRTY5_CME, + IRQ_VEC_PRTY6_CME | /* 5: IDX_PRTY_LVL_PMCR_DB0 */ + IRQ_VEC_PRTY5_CME + }, + { + IRQ_VEC_PRTY6_CME, + IRQ_VEC_PRTY6_CME /* 6: IDX_PRTY_LVL_DISABLED */ + } +}; + +uint8_t g_current_prty_level = NUM_EXT_IRQ_PRTY_LEVELS - 1; +uint8_t g_eimr_stack[NUM_EXT_IRQ_PRTY_LEVELS]; +int g_eimr_stack_ctr = -1; +uint64_t g_eimr_override_stack[NUM_EXT_IRQ_PRTY_LEVELS]; +uint64_t g_eimr_override = 0x0000000000000000; + +// 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 = in64(STD_LCL_EISTR); + bFound = FALSE; + iPrtyLvl = 0; + + do + { + if (ext_irq_vectors_cme[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 EIMR 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_eimr_stack_ctr < NUM_EXT_IRQ_PRTY_LEVELS) + { + // Make a note of present prty level and + // then update tracker to new prty level. + g_eimr_stack[g_eimr_stack_ctr] = g_current_prty_level; + g_current_prty_level = iPrtyLvl; // Update prty level tracker. + g_eimr_override_stack[g_eimr_stack_ctr] = g_eimr_override; + } + else + { + MY_TRACE_ERR("Code bug: EIMR S/R stack counter=%d >= max=%d.", + g_eimr_stack_ctr, NUM_EXT_IRQ_PRTY_LEVELS); + pk_halt(); + } + + // 3. Write the new mask for this priority level. + out64(STD_LCL_EIMR, ext_irq_vectors_cme[iPrtyLvl][IDX_MASK_VEC] | + g_eimr_override); + + } + else + { + MY_TRACE_ERR("A disabled IRQ fired"); + MY_TRACE_ERR("ext_irq_vector_pk=0x%08x%08x", ext_irq_vector_pk); +#if !EPM_P9_TUNING + pk_halt(); +#endif + } + + + // 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"); + + l_vecL = 0; + asm volatile ("lvd %[data], 0(%[addr]) \n" \ + : [data]"=r"(l_vecH) \ + : [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 new file mode 100644 index 00000000..e811e1d6 --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/cme/p9_cme_irq.h @@ -0,0 +1,136 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/cme/p9_cme_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. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file p9_cme_irq_common.h +/// \brief Shared and global definitions for CME H-codes. +/// \owner Michael Olsen Email: cmolsen@us.ibm.com +/// \owner David Du Email: daviddu@us.ibm.com + +//-------------------------------------------------------------------// +// 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)_CME(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 cme_irq_common.c + +// 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 + +// 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) +extern const uint64_t ext_irq_vectors_cme[NUM_EXT_IRQ_PRTY_LEVELS][2]; + +// Group0: Non-task hi-prty IRQs +#define IRQ_VEC_PRTY0_CME (uint64_t)(0xFE00000000000000) +// Group1: DB3 + BCE +#define IRQ_VEC_PRTY1_CME (uint64_t)(0x00F0000000000000) +// Group2: DB2 + WAKEUP +#define IRQ_VEC_PRTY2_CME (uint64_t)(0x000FF00000000000) +// Group3: STOP +#define IRQ_VEC_PRTY3_CME (uint64_t)(0x00000C0000000000) +// 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)(0x010003FFC33FFFFF) + +// This should be 0xFFFFFFFFFFFFFFFF +#define IRQ_VEC_PRTY_CHECK ( IRQ_VEC_PRTY0_CME | \ + IRQ_VEC_PRTY1_CME | \ + IRQ_VEC_PRTY2_CME | \ + IRQ_VEC_PRTY3_CME | \ + IRQ_VEC_PRTY4_CME | \ + IRQ_VEC_PRTY5_CME | \ + IRQ_VEC_PRTY6_CME ) + +extern uint8_t g_current_prty_level; +extern uint8_t g_eimr_stack[NUM_EXT_IRQ_PRTY_LEVELS]; +extern int g_eimr_stack_ctr; +extern uint64_t g_eimr_override_stack[NUM_EXT_IRQ_PRTY_LEVELS]; +extern uint64_t g_eimr_override; + +/// Restore a vector of interrupts by overwriting EIMR. +UNLESS__PPE42_IRQ_CORE_C__(extern) +inline void +pk_irq_vec_restore(PkMachineContext* context) +{ + pk_critical_section_enter(context); + + 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); + // 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 + { + PK_TRACE("Code bug: Messed up EIMR book keeping: g_eimr_stack_ctr=%d", + g_eimr_stack_ctr); + pk_halt(); + } + + pk_critical_section_exit(context); +} 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 new file mode 100644 index 00000000..77333c2e --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/cme/p9_cme_main.c @@ -0,0 +1,229 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/cme/p9_cme_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_cme_irq.h" + +// CME Pstate Header and Structure +#include "p9_cme_pstate.h" + +// CME Stop Header and Structure +#include "p9_cme_stop.h" +CmeStopRecord G_cme_stop_record = {0}; + +// CME Interrupt Handler Table +EXTERNAL_IRQ_TABLE_START +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DEBUGGER +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DEBUG_TRIGGER +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_QUAD_CHECKSTOP +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_DEFAULT //CMEHW_IRQ_BCE_BUSY_HIGH +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_BCE_TIMEOUT +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DOORBELL3_C0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DOORBELL3_C1 +IRQ_HANDLER(p9_cme_stop_event_handler, (void*) & (G_cme_stop_record.sem[1])) +//CMEHW_IRQ_PC_INTR_PENDING_C0 +IRQ_HANDLER(p9_cme_stop_event_handler, (void*) & (G_cme_stop_record.sem[1])) +//CMEHW_IRQ_PC_INTR_PENDING_C1 +IRQ_HANDLER(p9_cme_stop_event_handler, (void*) & (G_cme_stop_record.sem[1])) +//CMEHW_IRQ_REG_WAKEUP_C0 +IRQ_HANDLER(p9_cme_stop_event_handler, (void*) & (G_cme_stop_record.sem[1])) +//CMEHW_IRQ_REG_WAKEUP_C1 +IRQ_HANDLER(p9_cme_stop_event_handler, (void*) & (G_cme_stop_record.sem[1])) +//CMEHW_IRQ_SPECIAL_WAKEUP_C0 +IRQ_HANDLER(p9_cme_stop_event_handler, (void*) & (G_cme_stop_record.sem[1])) +//CMEHW_IRQ_SPECIAL_WAKEUP_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DOORBELL2_C0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DOORBELL2_C1 +IRQ_HANDLER(p9_cme_stop_event_handler, (void*) & (G_cme_stop_record.sem[0])) +//CMEHW_IRQ_PC_PM_STATE_ACTIVE_C0 +IRQ_HANDLER(p9_cme_stop_event_handler, (void*) & (G_cme_stop_record.sem[0])) +//CMEHW_IRQ_PC_PM_STATE_ACTIVE_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_L2_PURGE_DONE +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_NCU_PURGE_DONE +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_CHTM_PURGE_DONE_C0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_CHTM_PURGE_DONE_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_BCE_BUSY_LOW +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_FINAL_VDM_DATA0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_FINAL_VDM_DATA1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_COMM_RECVD +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_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 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_PECE_INTR_DISABLED_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_44 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_45 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_46 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_47 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_48 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_49 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_50 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_51 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_52 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_53 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_54 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_55 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_56 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_57 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_58 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_59 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_60 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_61 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_62 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_63 +EXTERNAL_IRQ_TABLE_END + +#define KERNEL_STACK_SIZE 256 +#define THREAD_STACK_SIZE 256 + +#define CME_THREAD_PRIORITY_STOP_EXIT 1 +#define CME_THREAD_PRIORITY_STOP_ENTRY 2 +#define CME_THREAD_PRIORITY_PSTATE_PMCR 3 + +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]; + +PkThread G_p9_cme_stop_enter_thread; +PkThread G_p9_cme_stop_exit_thread; +PkThread G_p9_cme_pmcr_db0_thread; + +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); + + PK_TRACE("Kernel init completed"); + + // Unified interrupt handler checks + if (IDX_PRTY_LVL_DISABLED != (NUM_EXT_IRQ_PRTY_LEVELS - 1)) + { + MY_TRACE_ERR("Code bug: IDX_PRTY_LVL_DISABLED(=%d)!=NUM_EXT_IRQ_PRTY_LEVELS(=%d)-1", + IDX_PRTY_LVL_DISABLED, NUM_EXT_IRQ_PRTY_LEVELS); + pk_halt(); + } + + if (IRQ_VEC_PRTY_CHECK != 0xFFFFFFFFFFFFFFFF) + { + MY_TRACE_ERR("Code bug: IRQ_VEC_PRTY_CHECK=0x%08x%08x should be all ones", + IRQ_VEC_PRTY_CHECK); + pk_halt(); + } + + //CMO-Temporary setting + // Setup up CME_LCL_FLAGS to indicate whether + // this CME is QMGR master or slave. + // Rules: + // - If even CME then set FLAGS(3)=1. Otherwise =0. + // - Whether in CME or Simics or HW, + // the assumption here is that the even CME in + // a configured Quad is always configured. + uint32_t l_pir; + asm volatile ("mfpir %[data] \n" : [data]"=r"(l_pir) ); + + if ( l_pir & PIR_INSTANCE_EVEN_ODD_MASK ) + { + // Odd: Set slave status + out32(CME_LCL_FLAGS_CLR, CME_FLAGS_QMGR_MASTER); + } + else + { + // Even: Set master status + out32(CME_LCL_FLAGS_OR, CME_FLAGS_QMGR_MASTER); + } + + // 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, + (void*)NULL, + (PkAddress)G_p9_cme_stop_exit_thread_stack, + (size_t)THREAD_STACK_SIZE, + (PkThreadPriority)CME_THREAD_PRIORITY_STOP_EXIT); + + PK_TRACE_BIN("G_p9_cme_stop_exit_thread", + &G_p9_cme_stop_exit_thread, + sizeof(G_p9_cme_stop_exit_thread)); + + // Initialize the thread control block for G_p9_cme_stop_enter_thread + pk_thread_create(&G_p9_cme_stop_enter_thread, + (PkThreadRoutine)p9_cme_stop_enter_thread, + (void*)NULL, + (PkAddress)G_p9_cme_stop_enter_thread_stack, + (size_t)THREAD_STACK_SIZE, + (PkThreadPriority)CME_THREAD_PRIORITY_STOP_ENTRY); + + PK_TRACE_BIN("G_p9_cme_stop_enter_thread", + &G_p9_cme_stop_enter_thread, + 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, + (void*)NULL, + (PkAddress)G_p9_cme_pmcr_db0_thread_stack, + (size_t)THREAD_STACK_SIZE, + (PkThreadPriority)IDX_PRTY_LVL_PMCR_DB0); + + PK_TRACE_BIN("G_p9_cme_pmcr_db0_thread", + &G_p9_cme_pmcr_db0_thread, + sizeof(G_p9_cme_pmcr_db0_thread)); + + // Make G_p9_cme_stop_exit_thread runnable + pk_thread_resume(&G_p9_cme_stop_exit_thread); + + // Make G_p9_cme_stop_enter_thread runnable + 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_TRACE("Launching threads"); + + // Start running the highest priority thread. + // This function never returns + pk_start_threads(); + + return 0; +} diff --git a/import/chips/p9/procedures/ppe_closed/cme/pk_app_cfg.h b/import/chips/p9/procedures/ppe_closed/cme/pk_app_cfg.h new file mode 100644 index 00000000..0bb06884 --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/cme/pk_app_cfg.h @@ -0,0 +1,85 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/cme/pk_app_cfg.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 */ +#ifndef __PK_APP_CFG_H__ +#define __PK_APP_CFG_H__ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file pk_app_cfg.h +/// \brief Application specific overrides go here. +/// + +#define EPM_P9_LEVEL 1 +#define STOP_PRIME 0 +#define SKIP_ABORT 0 +#define SKIP_L2_PURGE_ABORT 0 +#define SKIP_ENTRY_CATCHUP 0 +#define SKIP_EXIT_CATCHUP 1 +#define SKIP_SCAN0 0 +#define SKIP_INITF 0 +#define SKIP_ARY_INIT 0 +#define SKIP_SELF_RESTORE 0 + +// -------------------- + +#define EPM_P9_TUNING 1 +#define SIMICS_TUNING 1 +#define DEV_DEBUG 1 +#define USE_SIMICS_IO 0 +#define PK_TRACE_TIMER_OUTPUT 0 + +// -------------------- + +// Force CME and GPE tasks to use the unified interrupt handler. +#define UNIFIED_IRQ_HANDLER_CME + +// 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 */ + +// -------------------- + +/// This file provides architecture-specific symbol names for each interrupt +#include "cmehw_interrupts.h" + +/// This application will statically initialize it's external interrupt table +/// using the table defined in pk_app_irq_table.c. +#define STATIC_IRQ_TABLE + +#endif /*__PK_APP_CFG_H__*/ diff --git a/import/chips/p9/procedures/ppe_closed/cme/pk_app_irq_table.c b/import/chips/p9/procedures/ppe_closed/cme/pk_app_irq_table.c new file mode 100644 index 00000000..8710a91a --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/cme/pk_app_irq_table.c @@ -0,0 +1,92 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/cme/pk_app_irq_table.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" + +EXTERNAL_IRQ_TABLE_START +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DEBUGGER +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DEBUG_TRIGGER +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_QUAD_CHECKSTOP +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPARE_3 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_OCC_HEARTBEAT_LOST +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_CORE_CHECKSTOP +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_BCE_BUSY_HIGH +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPARE_7 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DOORBELL3_C0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DOORBELL3_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_PC_INTR_PENDING_C0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_PC_INTR_PENDING_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_REG_WAKEUP_C0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_REG_WAKEUP_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPECIAL_WAKEUP_C0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPECIAL_WAKEUP_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPARE_16 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPARE_17 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DOORBELL2_C0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DOORBELL2_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_PC_PM_STATE_ACTIVE_C0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_PC_PM_STATE_ACTIVE_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_L2_PURGE_DONE +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_NCU_PURGE_DONE +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_CHTM_PURGE_DONE_C0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_CHTM_PURGE_DONE_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_BCE_BUSY_LOW +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPARE_27 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_SPARE_28 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_COMM_RECVD +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_DEFAULT //CMEHW_IRQ_DOORBELL1_C0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_DOORBELL1_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_PECE_INTR_DISABLED_C0 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_PECE_INTR_DISABLED_C1 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_44 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_45 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_46 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_47 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_48 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_49 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_50 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_51 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_52 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_53 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_54 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_55 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_56 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_57 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_58 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_59 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_60 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_61 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_62 +IRQ_HANDLER_DEFAULT //CMEHW_IRQ_RESERVED_63 +EXTERNAL_IRQ_TABLE_END 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 new file mode 100644 index 00000000..ed33dfa9 --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.c @@ -0,0 +1,750 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.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 pstate_cme.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. +/// +/// + +#include "pk.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 "qppm_firmware_registers.h" +#include "ppe42_scom.h" +#include "p9_cme_irq.h" +#include "p9_cme_pstate.h" + +// +// HOMER variables updated by PGPE +// +uint32_t ULTRA_TURBO_FREQ_STEPS_PS; + +#define PIG_PAYLOAD_MASK 0x0fff000000000000 +#define PIG_INTR_FIELD_MASK 0x7000000000000000 +#define PIG_INTR_GRANTED_MASK 0x0000000080000000 + +// Type1 specific defines +#define PIG_PAYLOAD_PSTATE_MASK 0x03ff000000000000 +#define PIG_PAYLOAD_PSTATE_SEQ_INCR 0x0400000000000000 // Seq increment value + + +int +register_qcme_with_pgpe(void); + + +void +unified_irq_task_handler(void* arg, PkIrqId irq) +{ + pk_semaphore_post((PkSemaphore*)arg); +} + + +void +unified_irq_nontask_handler(void* arg, PkIrqId irq) +{ + MY_TRACE_ERR("Got an non-task IRQ=%d", irq); + pk_halt(); +} + + +int +send_pig_packet(uint32_t addr, uint64_t data) +{ + int rc = 0; + uint64_t data_tmp; + + // First make sure no interrupt request is currently granted + do + { + // 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(); + } + } + while (((ppm_pig_t)data_tmp).fields.intr_granted); + + // Send PIG packet + rc = putscom(0, addr, data); + + if (rc) + { + MY_TRACE_ERR("putscom(addr=0x%08x) failed w/rc=0x%08x", addr, rc); + pk_halt(); + } + + return rc; +} + + +void +pmcr_db0_thread(void* arg) +{ + int rc = 0, rc_api = API_RC_SUCCESS; + uint8_t bDB0 = FALSE, bPMCR = FALSE; + 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 ); + + 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 ); + + if (rc) + { + PK_TRACE("pk_irq_handler_set(%d) failed w/rc=0x%08x", irqPrty, rc); + pk_halt(); + } + } + + } + + + // + // 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); + + + //------------------------------------------------------------------------------// + // Determine QMGR status and register as QMGR, ie QCME, if CME is QMGR master // + //------------------------------------------------------------------------------// + + // First determine if this CME is a QMRG master, i.e. QCME + // + bQcmeRegister = FALSE; + + asm volatile ("mfpir %[data] \n" : [data]"=r"(l_pir) ); + + thisCmeInstance = (uint8_t)(l_pir & PIR_INSTANCE_NUM_MASK); + + rc = getscom( 0, CME_LCL_FLAGS, &data ); + data32 = (uint32_t)(data >> 32); + + 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 ( l_pir & PIR_INSTANCE_EVEN_ODD_MASK ) // Sanity test that bit31==1 and thus this CME is odd. + { + bQcmeRegister = FALSE; + MY_TRACE_DBG("This [odd] CME#%d is the QMGR slave", thisCmeInstance); + } + 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(); + } + } + + // 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) + { + // 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(); + } + + // Update the unacked registration tracker + if (!fsm_unacked_qcme_registration) + { + fsm_unacked_qcme_registration++; + } + else + { + MY_TRACE_ERR("Code bug: fsm_unacked_qcme_registration (=%d) > 0", + fsm_unacked_qcme_registration); + pk_halt(); + } + } + + + // + // 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); + + + while(1) + { + + // Go to sleep + pk_semaphore_pend(&sem, PK_WAIT_FOREVER); + + + // + // 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. + // + + do + { + bDB0 = bPMCR = FALSE; + + statusIrqDb0C0 = pk_irq_status_get(CMEHW_IRQ_DOORBELL0_C0); + statusIrqDb0C1 = pk_irq_status_get(CMEHW_IRQ_DOORBELL0_C1); + + if (statusIrqDb0C0 && statusIrqDb0C1) + { + // Both fired (We do NOT support this.) + PK_TRACE("Code bug: Both DB0s fired. Probably PGPE problem."); + pk_halt(); + } + else if (statusIrqDb0C0) + { + 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; + } + else if (statusIrqDb0C1) + { + 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; + } + else + { + statusIrqPmcrC0 = pk_irq_status_get(CMEHW_IRQ_PMCR_UPDATE_C0); + statusIrqPmcrC1 = pk_irq_status_get(CMEHW_IRQ_PMCR_UPDATE_C1); + + if (statusIrqPmcrC0 && statusIrqPmcrC1) + { + // Both fired (We support this.) + thisCoreIdx = nextCoreIdx; + nextCoreIdx++; + nextCoreIdx = nextCoreIdx - (nextCoreIdx >> 1) * 2; + + if (thisCoreIdx != 0 && thisCoreIdx != 1) + { + PK_TRACE("Code bug: Illegal value of thisCoreIdx (=%d).", thisCoreIdx); + pk_halt(); + } + } + 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; + } + } + } + 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); + + // Get the payload from DB0 + rc = getscom(0, addr_db0, &cb_from_pgpe_base.value); + + if (rc) + { + 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(); + } + +//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) + { + + 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(); + } + +#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; + + // + // 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; + + // 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); + + if (rc) + { + MY_TRACE_ERR("send_pig_packet(addr=0x%08x) failed w/rc=0x%08x", addr_ppm_pig, rc); + pk_halt(); + } + + // + // 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(); + } + +#if DEV_DEBUG + // Read PPMPIG status + rc = getscom(0, addr_ppm_pig, &data); + + if (rc) + { + PK_TRACE("getscom(addr_ppm_pig%d=0x%08x) failed w/rc=0x%08x", + thisCoreIdx, addr_ppm_pig, rc); + pk_halt(); + } + + PK_TRACE("(After PIG phase 2): data_ppm_pig%d=0x%08x%08x", + thisCoreIdx, (uint32_t)(data >> 32), (uint32_t)data); +#endif + + } + else + { + PK_TRACE("Code bug."); + PK_TRACE("Neither of the {PMCR,DB0}_C0/1 interrupts were selected."); + pk_halt(); + } + + + // 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); + */ + + } +} 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 new file mode 100644 index 00000000..ef8daeed --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.h @@ -0,0 +1,347 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/chips/p9/procedures/ppe_closed/cme/pstate_cme/p9_cme_pstate.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. 2014 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file pstate.h +/// \brief Shared and global definitions for pstate H codes. +/// \owner Michael Olsen Email: cmolsen@us.ibm.com +/// + +void pmcr_db0_thread(void*); + +#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) + +#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 +{ + 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; + +// QCME->PGPE: cb_to_pgpe_ack +// --------------------------- +// Used by QCME to acknowledge DB requests. +// +typedef union comm_block_to_pgpe_ack +{ + 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; + +// +// Return Codes +// +enum API_RETURN_CODES +{ + API_RC_INVALID = 0, // Don't use zero. Not reliable. + API_RC_SUCCESS = 1, + API_RC_FAILURE = 2 +}; diff --git a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop.h b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop.h index 6d8636dc..2378fbed 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop.h +++ b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop.h @@ -44,45 +44,54 @@ #include "cppm_firmware_registers.h" #include "p9_stop_common.h" - +/* +/// Compiler flags +#define EPM_P9_LEVEL 1 +#define SKIP_ABORT 1 +#define SKIP_L2_PURGE_ABORT 1 +#define SKIP_CATCHUP 1 +#define STOP_PRIME 0 +#define SKIP_SCAN0 0 +#define SKIP_INITF 0 +#define SKIP_ARY_INIT 0 +#define SKIP_SELF_RESTORE 0 +*/ /// handcoded addresses TO BE REMOVED -#define THREAD_INFO 0x20010A9B -#define DIRECT_CONTROLS 0x20010A9C -#define RAS_STATUS 0x20010A02 -#define RAM_MODEREG 0x20010A51 -#define RAM_CTRL 0x20010A52 -#define RAM_STATUS 0x20010A53 - -#define C_SYNC_CONFIG 0x20030000 -#define C_OPCG_ALIGN 0x20030001 -#define C_SCAN_REGION_TYPE 0x20030005 -#define C_CLK_REGION 0x20030006 -#define C_CLOCK_STAT_SL 0x20030008 -#define C_CLOCK_STAT_NSL 0x20030009 -#define C_CLOCK_STAT_ARY 0x2003000a -#define C_BIST 0x2003000B - -#define C_SLAVE_CONFIG_REG 0x200F001E -#define C_ERROR_REG 0x200F001F -#define C_HANG_PULSE_1_REG 0x200F0021 -#define C_PPM_CGCR 0x200F0164 - -#define C_CPLT_CTRL0_OR 0x20000010 -#define C_CPLT_CTRL0_CLEAR 0x20000020 -#define C_CPLT_CTRL1_OR 0x20000011 -#define C_CPLT_CTRL1_CLEAR 0x20000021 -#define C_CPLT_STAT0 0x20000100 - -#define PERV_CPLT_CTRL0_OR 0x00000010 -#define PERV_CPLT_CTRL0_CLEAR 0x00000020 -#define PERV_OPCG_REG0 0x00030002 -#define PERV_OPCG_REG1 0x00030003 -#define PERV_CLK_REGION 0x00030006 -#define PERV_BIST 0x0003000B -#define PERV_CPLT_STAT0 0x00000100 - -#define NCU_STATUS_REG 0x1001140F +#define THREAD_INFO 0x20010A9B +#define DIRECT_CONTROLS 0x20010A9C +#define RAS_STATUS 0x20010A02 +#define RAM_MODEREG 0x20010A51 +#define RAM_CTRL 0x20010A52 +#define RAM_STATUS 0x20010A53 + +#define C_SYNC_CONFIG 0x20030000 +#define C_OPCG_ALIGN 0x20030001 +#define C_SCAN_REGION_TYPE 0x20030005 +#define C_CLK_REGION 0x20030006 +#define C_CLOCK_STAT_SL 0x20030008 +#define C_CLOCK_STAT_NSL 0x20030009 +#define C_CLOCK_STAT_ARY 0x2003000a +#define C_BIST 0x2003000B + +#define C_SLAVE_CONFIG_REG 0x200F001E +#define C_ERROR_REG 0x200F001F +#define C_HANG_PULSE_1_REG 0x200F0021 +#define C_PPM_CGCR 0x200F0164 + +#define C_CPLT_CTRL0_OR 0x20000010 +#define C_CPLT_CTRL0_CLEAR 0x20000020 +#define C_CPLT_CTRL1_OR 0x20000011 +#define C_CPLT_CTRL1_CLEAR 0x20000021 +#define C_CPLT_STAT0 0x20000100 + +#define PERV_CPLT_CTRL0_OR 0x00000010 +#define PERV_CPLT_CTRL0_CLEAR 0x00000020 +#define PERV_OPCG_REG0 0x00030002 +#define PERV_OPCG_REG1 0x00030003 +#define PERV_CLK_REGION 0x00030006 +#define PERV_BIST 0x0003000B +#define PERV_CPLT_STAT0 0x00000100 /// Macro to update STOP History #define CME_STOP_UPDATE_HISTORY(core,gated,trans,req_l,act_l,req_e,act_e) \ @@ -94,18 +103,15 @@ hist.fields.act_write_enable = act_e; \ CME_PUTSCOM(PPM_SSHSRC, core, hist.value); - +#define IRQ_VEC_WAKE_C0 (uint64_t)(0x000A800000000000) +#define IRQ_VEC_WAKE_C1 (uint64_t)(0x0005400000000000) +#define IRQ_VEC_STOP_C0 (uint64_t)(0x0000080000000000) +#define IRQ_VEC_STOP_C1 (uint64_t)(0x0000040000000000) /// CME STOP Return Codes enum CME_STOP_RETURN_CODE { - CME_STOP_SUCCESS = 0, - CME_STOP_ENTRY_PM_NOT_ACTIVE = 0x00726301, - CME_STOP_ENTRY_STOP1_SENT_IRQ = 0x00726302, - CME_STOP_ENTRY_VDD_PFET_NOT_IDLE = 0x00726303, - CME_STOP_EXIT_NO_WAKEUP = 0x00726304, - CME_STOP_EXIT_WAKEUP_FROM_STOP1 = 0x00726305, - CME_STOP_EXIT_PCBMUX_LOST_GRANT = 0x00726306 + CME_STOP_SUCCESS = 0 }; /// CME STOP IRQs with shorter names @@ -136,13 +142,23 @@ enum CME_STOP_FLAGS /// Stop Score Board Structure typedef struct { - uint8_t req_stop_c0; - uint8_t req_stop_c1; - uint8_t act_stop_c0; - uint8_t act_stop_c1; - uint8_t active_core; - uint8_t cme_flags; - uint64_t mask_vector; + // requested stop levels are read from pm_state, + // need to be a global state for stop8 detection + uint8_t req_level_c0; + uint8_t req_level_c1; + // actual stop levels are changed through entry, + // need to be a global state for aborting entry + uint8_t act_level_c0; + uint8_t act_level_c1; + // whether core is in running state, + // need to be a global state for aborted entry detection and wakeup masking + uint32_t core_running; + // core stop handoff to sgpe from cme + // need to be a global state for wakeup and pm_active masking + uint32_t core_stopgpe; + // partial good configuration, + // todo: consider partial good changed during stop, + uint32_t core_enabled; PkSemaphore sem[2]; } CmeStopRecord; diff --git a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_enter_marks.h b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_enter_marks.h index deb1a86f..6e411ccd 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_enter_marks.h +++ b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_enter_marks.h @@ -37,22 +37,26 @@ namespace CME_STOP_ENTRY_MARKS enum CME_SE_MARKS { SE_POLL_PCBMUX_GRANT = 0x0, - SE_STOP_CORE_CLKS = 0x8, - SE_DROP_CLK_SYNC = 0x10, - SE_STOP2_DONE = 0x18, - SE_IS0_BEGIN = 0x20, - SE_IS0_END = 0x28, - SE_CORE_VMIN = 0x30, - SE_STOP3_DONE = 0x38, - SE_POWER_OFF_CORE = 0x40, - SE_STOP4_DONE = 0x48, - SE_IS1_BEGIN = 0x50, - SE_IS1_END = 0x68, - SE_PURGE_L2 = 0xe0, - SE_IS2_BEGIN = 0xe8, - SE_IS2_END = 0xf0, - SE_L2_PURGE_DONE = 0xf8, - SE_SGPE_HANDOFF = 0x100, + SE_QUIESCE_CORE_INTF = 0x8, + SE_STOP_CORE_CLKS = 0x10, + SE_STOP_CORE_GRID = 0x18, + SE_STOP2_DONE = 0x20, + SE_IS0_BEGIN = 0x28, + SE_IS0_END = 0x30, + SE_CATCHUP = 0x38, + SE_CORE_VMIN = 0x40, + SE_STOP3_DONE = 0x48, + SE_POWER_OFF_CORE = 0x50, + SE_STOP4_DONE = 0x68, + SE_IS1_BEGIN = 0xe0, + SE_IS1_END = 0xe8, + SE_PURGE_L2 = 0xf0, + SE_IS2_BEGIN = 0xf8, + SE_PURGE_L2_ABORT = 0x100, + SE_PURGE_L2_ABORT_DONE = 0x108, + SE_IS2_END = 0x110, + SE_PURGE_L2_DONE = 0x118, + SE_SGPE_HANDOFF = 0x120, BEGINSCOPE_STOP_ENTRY = 0x1f08, ENDSCOPE_STOP_ENTRY = 0x1f10, STOP_EVENT_HANDLER = 0x1f18, @@ -65,11 +69,13 @@ enum CME_SE_MARKS const std::vector<CME_SE_MARKS> MARKS = { SE_POLL_PCBMUX_GRANT, + SE_QUIESCE_CORE_INTF, SE_STOP_CORE_CLKS, - SE_DROP_CLK_SYNC, + SE_STOP_CORE_GRID, SE_STOP2_DONE, SE_IS0_BEGIN, SE_IS0_END, + SE_CATCHUP, SE_CORE_VMIN, SE_STOP3_DONE, SE_POWER_OFF_CORE, @@ -78,8 +84,10 @@ const std::vector<CME_SE_MARKS> MARKS = SE_IS1_END, SE_PURGE_L2, SE_IS2_BEGIN, + SE_PURGE_L2_ABORT, + SE_PURGE_L2_ABORT_DONE, SE_IS2_END, - SE_L2_PURGE_DONE, + SE_PURGE_L2_DONE, SE_SGPE_HANDOFF, BEGINSCOPE_STOP_ENTRY, ENDSCOPE_STOP_ENTRY, diff --git a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_entry.c b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_entry.c index a41a8edf..a82af15c 100755 --- a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_entry.c +++ b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_entry.c @@ -53,16 +53,19 @@ p9_cme_stop_entry() { int rc = 0; - uint8_t core_aborted = 0; - uint8_t core_catchup = 0; - uint8_t catchup_ongoing = 0; - uint8_t entry_ongoing = 1; + int catchup_ongoing = 0; + int entry_ongoing = 1; uint8_t target_level; uint8_t deeper_level = 0; + uint8_t origin_level = 0; + uint32_t origin_core = 0; uint32_t deeper_core = 0; + uint32_t core_aborted = 0; + uint32_t core_catchup = 0; uint32_t core; uint32_t loop; uint32_t pm_states; + uint32_t lclr_data; uint64_t scom_data; ppm_sshsrc_t hist; ppm_pig_t pig; @@ -77,15 +80,19 @@ p9_cme_stop_entry() // CME will do Daul-cast to both cores at the same time in entry flow. core = (in32(CME_LCL_EISR) & BITS32(20, 2)) >> SHIFT32(21); - // override with partial good core mask - core = core & G_cme_stop_record.cme_flags & CME_MASK_BC; + // filter with partial good and running core mask + // core cannot enter stop if core is already stopped + core = core & G_cme_stop_record.core_enabled & + G_cme_stop_record.core_running; - PK_TRACE("SE0: Core Select[%d]", core); + PK_TRACE("SE0: Core Select[%d] Enabled[%d] Running[%d]", + core, G_cme_stop_record.core_enabled, + G_cme_stop_record.core_running); // Return error if None of both fired if (!core) { - return CME_STOP_ENTRY_PM_NOT_ACTIVE; + pk_halt(); } //=================================== @@ -95,57 +102,64 @@ p9_cme_stop_entry() do // while(0) loop for stop flow control { - //-------------------------------------------------------------------------- + //---------------------------------------------------------------------- // STOP LEVEL 1 (should be done by hardware) - //-------------------------------------------------------------------------- + //---------------------------------------------------------------------- // Read SISR for pm_state_cX pm_states = in32_sh(CME_LCL_SISR); - G_cme_stop_record.req_stop_c0 = (pm_states & BITS32(4, 4)) >> SHIFT32(7); - G_cme_stop_record.req_stop_c1 = (pm_states & BITS32(8, 4)) >> SHIFT32(11); - - // pm_active AND waken_up : pm_state = sisr (new state) - // pm_active AND !waken_up : pm_state = sisr (only with auto promote) - // !pm_active AND waken_up : pm_state = 0 (out dated state) - // !pm_active AND !waken_up : pm_state = sisr (current state) - if (~core & G_cme_stop_record.active_core & CME_MASK_C0) + + // entry: req_level = target stop level + // act_level = current stop level + // running = FALSE, TRUE if aborted + // stopped: req_level = act_level = target and current stop level + // (if<=5) + // running = FALSE + // exit/abort: req_level = requested stop level + // act_level = latest stop level + // running = FALSE + // running: req_level = act_level = 0 + // running = TRUE + // pm_active AND running : req_level = New requested stop level + // pm_active AND !running : req_level = Not possible, + // ignore false re-entry + // !pm_active AND running : req_level = 0 by exit, + // not changing req_level + // !pm_active AND !running : req_level = Current req_level + if (core & CME_MASK_C0) { - G_cme_stop_record.req_stop_c0 = 0; + G_cme_stop_record.req_level_c0 = + (pm_states & BITS32(4, 4)) >> SHIFT32(7); } - if (~core & G_cme_stop_record.active_core & CME_MASK_C1) + if (core & CME_MASK_C1) { - G_cme_stop_record.req_stop_c1 = 0; + G_cme_stop_record.req_level_c1 = + (pm_states & BITS32(8, 4)) >> SHIFT32(11); } - G_cme_stop_record.active_core &= ~core; + G_cme_stop_record.core_running &= ~core; + out32(CME_LCL_LMCR_OR, (core << SHIFT32(15))); PK_TRACE("SE1: Request Stop Levels[%d %d]", - G_cme_stop_record.req_stop_c0, G_cme_stop_record.req_stop_c1); + G_cme_stop_record.req_level_c0, + G_cme_stop_record.req_level_c1); // Return error if target STOP level == 1(Nap) - if((core == CME_MASK_C0 && G_cme_stop_record.req_stop_c0 <= STOP_LEVEL_1) || - (core == CME_MASK_C1 && G_cme_stop_record.req_stop_c1 <= STOP_LEVEL_1) || - (core == CME_MASK_BC && (G_cme_stop_record.req_stop_c0 <= STOP_LEVEL_1 || - G_cme_stop_record.req_stop_c1 <= STOP_LEVEL_1))) + if((core == CME_MASK_C0 && + G_cme_stop_record.req_level_c0 <= STOP_LEVEL_1) || + (core == CME_MASK_C1 && + G_cme_stop_record.req_level_c1 <= STOP_LEVEL_1) || + (core == CME_MASK_BC && + (G_cme_stop_record.req_level_c0 <= STOP_LEVEL_1 || + G_cme_stop_record.req_level_c1 <= STOP_LEVEL_1))) { - return CME_STOP_ENTRY_STOP1_SENT_IRQ; + pk_halt(); } - //-------------------------------------------------------------------------- + //---------------------------------------------------------------------- // STOP LEVEL 2 - //-------------------------------------------------------------------------- - - PK_TRACE("SE2.a"); - // Disable fired Stop and corresponding Wakeup interrupts - out32(CME_LCL_EIMR_OR, (CME_MASK_BC << SHIFT32(21)) | - (core << SHIFT32(13)) | - (core << SHIFT32(15)) | - (core << SHIFT32(17))); - - PK_TRACE("SE2.b"); - // Also clear the status of the currently fired STOP interrupt(s) - out32(CME_LCL_EISR_CLR, core << SHIFT32(21)); + //---------------------------------------------------------------------- PK_TRACE("SE2.c"); // Request PCB Mux @@ -156,29 +170,29 @@ p9_cme_stop_entry() CME_PUTSCOM(CPPM_CPMMR_OR, core, BIT64(0)); // set target_level from pm_state for both cores or just one core - target_level = (core == CME_MASK_C0) ? G_cme_stop_record.req_stop_c0 : - G_cme_stop_record.req_stop_c1; + target_level = (core == CME_MASK_C0) ? G_cme_stop_record.req_level_c0 : + G_cme_stop_record.req_level_c1; // If both cores are going into STOP but targeting different levels, if ((core == CME_MASK_BC) && - (G_cme_stop_record.req_stop_c0 != G_cme_stop_record.req_stop_c1)) + (G_cme_stop_record.req_level_c0 != G_cme_stop_record.req_level_c1)) { // set target_level to the lighter level targeted by one core // set deeper_level to the deeper level targeted by deeper core - deeper_level = G_cme_stop_record.req_stop_c0; + deeper_level = G_cme_stop_record.req_level_c0; deeper_core = CME_MASK_C0; - if (G_cme_stop_record.req_stop_c0 < G_cme_stop_record.req_stop_c1) + if (G_cme_stop_record.req_level_c0 < G_cme_stop_record.req_level_c1) { - target_level = G_cme_stop_record.req_stop_c0; - deeper_level = G_cme_stop_record.req_stop_c1; + target_level = G_cme_stop_record.req_level_c0; + deeper_level = G_cme_stop_record.req_level_c1; deeper_core = CME_MASK_C1; } } PK_TRACE("SE2.e"); // Update STOP History: In Transition of Entry - // Set req_stop_level to target_level of either both or just one core + // Set req_level_level to target_level of either both or just one core CME_STOP_UPDATE_HISTORY(core, STOP_CORE_READY_RUN, STOP_TRANS_ENTRY, @@ -187,7 +201,7 @@ p9_cme_stop_entry() STOP_REQ_ENABLE, STOP_ACT_DISABLE); - // Set req_stop_level to deeper_level for deeper core + // Set req_level_level to deeper_level for deeper core if (deeper_core) { CME_STOP_UPDATE_HISTORY(deeper_core, @@ -214,27 +228,39 @@ p9_cme_stop_entry() PK_TRACE("SE2: PCB Mux Granted"); - //========================== - MARK_TRAP(SE_STOP_CORE_CLKS) - //========================== + //============================= + MARK_TRAP(SE_QUIESCE_CORE_INTF) + //============================= PK_TRACE("SE2.g"); // Acknowledge the STOP Entry to PC with a pulse - out32(CME_LCL_SICR_OR, core << SHIFT32(1)); + out32(CME_LCL_SICR_OR, core << SHIFT32(1)); out32(CME_LCL_SICR_CLR, core << SHIFT32(1)); + /// @todo Set LMCR bits 14 and/or 15 (override disables) + PK_TRACE("SE2.h"); // Raise Core-L2 + Core-CC Quiesces out32(CME_LCL_SICR_OR, (core << SHIFT32(7)) | (core << SHIFT32(9))); PK_TRACE("SE2.i"); + + do + { + lclr_data = in32(CME_LCL_SISR); + } + while((lclr_data & core) != core); + // Waits quiesce done for at least 512 core cycles // MF: verify generate FCB otherwise math is wrong. PPE_WAIT_CORE_CYCLES(loop, 512) + //========================== + MARK_TRAP(SE_STOP_CORE_CLKS) + //========================== + PK_TRACE("SE2.j"); // Raise Core Chiplet Fence - CME_PUTSCOM(C_CPLT_CTRL0_OR, core, BIT64(2)); CME_PUTSCOM(CPPM_NC0INDIR_OR, core, BIT64(18)); PK_TRACE("SE2.k"); @@ -243,7 +269,7 @@ p9_cme_stop_entry() PK_TRACE("SE2.l"); // Stop Core Clocks - CME_PUTSCOM(C_CLK_REGION, core, 0x9FFC00000000E000); + CME_PUTSCOM(C_CLK_REGION, core, 0x8FFC00000000E000); PK_TRACE("SE2.m"); @@ -259,15 +285,14 @@ p9_cme_stop_entry() PK_TRACE("SE2: Core Clock Stopped"); - //========================= - MARK_TRAP(SE_DROP_CLK_SYNC) - //========================= + //============================== + MARK_TRAP(SE_STOP_CORE_GRID) + //============================== PK_TRACE("SE2.n"); // Drop clock sync enable before switch to refclk CME_PUTSCOM(CPPM_CACCR_CLR, core, BIT64(15)); -#if !EPM_P9_TUNING PK_TRACE("SE2.o"); // Poll for clock sync done to drop @@ -277,24 +302,43 @@ p9_cme_stop_entry() } while(scom_data & BIT64(13)); -#endif - PK_TRACE("SE2.p"); // Switch glsmux to refclk to save clock grid power CME_PUTSCOM(C_PPM_CGCR, core, 0); - // Assert PCB Fence - //CME_PUTSCOM(CPPM_NC0INDIR_OR, core, BIT64(25)); // Assert Vital Fence CME_PUTSCOM(C_CPLT_CTRL1_OR, core, BIT64(3)); // Assert Regional Fences CME_PUTSCOM(C_CPLT_CTRL1_OR, core, 0xFFFF700000000000); + PK_TRACE("SE2: Clock Sync Dropped"); + + // Copy PECE CME sample to PPM Shadow + if (core & CME_MASK_C0) + { + scom_data = in64(CME_LCL_PECESR0); + CME_PUTSCOM(CPPM_PECES, core, scom_data); + G_cme_stop_record.act_level_c0 = STOP_LEVEL_2; + } + + if (core & CME_MASK_C1) + { + scom_data = in64(CME_LCL_PECESR1); + CME_PUTSCOM(CPPM_PECES, core, scom_data); + G_cme_stop_record.act_level_c1 = STOP_LEVEL_2; + } + + //=========================== + MARK_TAG(SE_STOP2_DONE, core) + //=========================== + PK_TRACE("SE2.q"); // Update Stop History: In Core Stop Level 2 // Check if STOP level 2 reaches the target for both or one core entry_ongoing = - target_level == STOP_LEVEL_2 ? STOP_TRANS_COMPLETE : STOP_TRANS_ENTRY; + target_level == STOP_LEVEL_2 ? + STOP_TRANS_COMPLETE : STOP_TRANS_ENTRY; + CME_STOP_UPDATE_HISTORY(core, STOP_CORE_IS_GATED, entry_ongoing, @@ -323,27 +367,11 @@ p9_cme_stop_entry() entry_ongoing = 1; } - if (core & CME_MASK_C0) - { - G_cme_stop_record.act_stop_c0 = STOP_LEVEL_2; - } - - if (core & CME_MASK_C1) - { - G_cme_stop_record.act_stop_c1 = STOP_LEVEL_2; - } - - PK_TRACE("SE2: Clock Sync Dropped"); - - //=========================== - MARK_TAG(SE_STOP2_DONE, core) - //=========================== - //=========================== MARK_TRAP(SE_IS0_BEGIN) //=========================== #if !SKIP_ABORT - out32(CME_LCL_EIMR_CLR, /*TODO(core << SHIFT32(13)) |*/ + out32(CME_LCL_EIMR_CLR, (core << SHIFT32(13)) | (core << SHIFT32(15)) | (core << SHIFT32(17))); sync(); @@ -355,36 +383,19 @@ p9_cme_stop_entry() MARK_TRAP(SE_IS0_END) //=================== - core_aborted = 0; + core_aborted = core & G_cme_stop_record.core_running; - if ((core & CME_MASK_C0) && - G_cme_stop_record.act_stop_c0 == STOP_LEVEL_0 && - G_cme_stop_record.req_stop_c0 != STOP_LEVEL_0) + if (core_aborted && deeper_core) { - core_aborted |= CME_MASK_C0; - core -= CME_MASK_C0; - deeper_core = 0; - - if (deeper_core == CME_MASK_C1) + if (core_aborted != deeper_core) { target_level = deeper_level; } + deeper_core = 0; } - if ((core & CME_MASK_C1) && - G_cme_stop_record.act_stop_c1 == STOP_LEVEL_0 && - G_cme_stop_record.req_stop_c1 != STOP_LEVEL_0) - { - core_aborted |= CME_MASK_C1; - core -= CME_MASK_C1; - deeper_core = 0; - - if (deeper_core == CME_MASK_C0) - { - target_level = deeper_level; - } - } + core = core & ~G_cme_stop_record.core_running; if (!core) { @@ -393,22 +404,68 @@ p9_cme_stop_entry() break; } +#if !SKIP_ENTRY_CATCHUP + if (catchup_ongoing) { - core = CME_MASK_BC; + // Y = 2 eo = 0 same if X = 2 + // Y > 2 eo = 1 c=c t=t same if X = 2 + // if X > 2 eo = 1 + // if Y = 2 c=o t=o + // else (Y > 2) c=2 + // if X != Y (X = Y: dl=0 dc=0 t=t) + // dl=o dc=o (X > Y) + // if X < Y + // dl=t dc=c t=o + if (origin_level > STOP_LEVEL_2) + { + if (target_level == STOP_LEVEL_2) + { + core = origin_core; + target_level = origin_level; + } + else + { + if (origin_level != target_level) + { + deeper_core = origin_core; + deeper_level = origin_level; + + if (origin_level < target_level) + { + deeper_core = core; + deeper_level = target_level; + target_level = origin_level; + } + } + + core = CME_MASK_BC; + } + + entry_ongoing = 1; + } + break; } -#if !SKIP_CATCHUP core_catchup = (in32(CME_LCL_EISR) & BITS32(20, 2)) >> SHIFT32(21); -#endif + core_catchup = core_catchup & G_cme_stop_record.core_enabled & + G_cme_stop_record.core_running; - if (core_catchup > core) + if (core_catchup) { - core = core_catchup - core; + origin_core = core; + origin_level = target_level; + core = core_catchup; catchup_ongoing = 1; + + //======================== + MARK_TAG(SE_CATCHUP, core) + //======================== } +#endif + } while(catchup_ongoing); @@ -425,9 +482,9 @@ p9_cme_stop_entry() target_level[%d],deeper_level[%d]", core, deeper_core, target_level, deeper_level); - //-------------------------------------------------------------------------- + //---------------------------------------------------------------------- // STOP LEVEL 3 - //-------------------------------------------------------------------------- + //---------------------------------------------------------------------- if (target_level == 3) { @@ -442,6 +499,20 @@ p9_cme_stop_entry() PK_TRACE("SE3.b"); // Drop to Vmin + if(core & CME_MASK_C0) + { + G_cme_stop_record.act_level_c0 = STOP_LEVEL_3; + } + + if(core & CME_MASK_C1) + { + G_cme_stop_record.act_level_c1 = STOP_LEVEL_3; + } + + //=========================== + MARK_TAG(SE_STOP3_DONE, core) + //=========================== + PK_TRACE("SE3.c"); // Update Stop History: In Core Stop Level 3 CME_STOP_UPDATE_HISTORY(core, @@ -476,20 +547,6 @@ p9_cme_stop_entry() entry_ongoing = 0; } - if(core & CME_MASK_C0) - { - G_cme_stop_record.act_stop_c0 = STOP_LEVEL_3; - } - - if(core & CME_MASK_C1) - { - G_cme_stop_record.act_stop_c1 = STOP_LEVEL_3; - } - - //=========================== - MARK_TAG(SE_STOP3_DONE, core) - //=========================== - // If we are done at STOP level 3 if (!entry_ongoing) { @@ -497,9 +554,9 @@ p9_cme_stop_entry() } } - //-------------------------------------------------------------------------- + //---------------------------------------------------------------------- // STOP LEVEL 4 - //-------------------------------------------------------------------------- + //---------------------------------------------------------------------- //=============================== MARK_TAG(SE_POWER_OFF_CORE, core) @@ -512,18 +569,6 @@ p9_cme_stop_entry() CME_PUTSCOM(CPPM_NC0INDIR_OR, core, BIT64(16)); #if !STOP_PRIME -#if !EPM_P9_TUNING - // Make sure we are not forcing PFET for VDD off - // vdd_pfet_force_state == 00 (Nop) - PK_TRACE("SE4.b"); - CME_GETSCOM(PPM_PFCS, core, CME_SCOM_AND, scom_data); - - if (scom_data & BITS64(0, 2)) - { - return CME_STOP_ENTRY_VDD_PFET_NOT_IDLE; - } - -#endif // Prepare PFET Controls // vdd_pfet_val/sel_override = 0 (disbaled) @@ -545,23 +590,29 @@ p9_cme_stop_entry() } while(!(scom_data & BIT64(42))); -#if !EPM_P9_TUNING - // Optional: Poll for vdd_pg_sel being: 0x8 - PK_TRACE("SE4.f"); - - do - { - CME_GETSCOM(PPM_PFCS, core, CME_SCOM_AND, scom_data); - } - while(!(scom_data & BIT64(46))); - -#endif // Turn Off Force Voff // vdd_pfet_force_state = 00 (Nop) PK_TRACE("SE4.g"); CME_PUTSCOM(PPM_PFCS_CLR, core, BITS64(0, 2)); + #endif + PK_TRACE("SE4: Core Powered Off"); + + if (core & CME_MASK_C0) + { + G_cme_stop_record.act_level_c0 = STOP_LEVEL_4; + } + + if (core & CME_MASK_C1) + { + G_cme_stop_record.act_level_c1 = STOP_LEVEL_4; + } + + //=========================== + MARK_TAG(SE_STOP4_DONE, core) + //=========================== + PK_TRACE("SE4.h"); // Update Stop History: In Core Stop Level 4 // Check if STOP level 4 reaches the target for both or one core @@ -596,27 +647,11 @@ p9_cme_stop_entry() entry_ongoing = 1; } - if (core & CME_MASK_C0) - { - G_cme_stop_record.act_stop_c0 = STOP_LEVEL_4; - } - - if (core & CME_MASK_C1) - { - G_cme_stop_record.act_stop_c1 = STOP_LEVEL_4; - } - - PK_TRACE("SE4: Core Powered Off"); - - //=========================== - MARK_TAG(SE_STOP4_DONE, core) - //=========================== - //=========================== MARK_TRAP(SE_IS1_BEGIN) //=========================== #if !SKIP_ABORT - out32(CME_LCL_EIMR_CLR, /*TODO(core << SHIFT32(13)) |*/ + out32(CME_LCL_EIMR_CLR, (core << SHIFT32(13)) | (core << SHIFT32(15)) | (core << SHIFT32(17))); sync(); @@ -628,39 +663,25 @@ p9_cme_stop_entry() MARK_TRAP(SE_IS1_END) //=================== - if ((core & CME_MASK_C0) && - G_cme_stop_record.act_stop_c0 == STOP_LEVEL_0 && - G_cme_stop_record.req_stop_c0 != STOP_LEVEL_0) - { - core_aborted |= CME_MASK_C0; - core -= CME_MASK_C0; - deeper_core = 0; + core_aborted = core & G_cme_stop_record.core_running; - if (deeper_core == CME_MASK_C1) + if (core_aborted && deeper_core) + { + if (core_aborted != deeper_core) { target_level = deeper_level; } + deeper_core = 0; } - if ((core & CME_MASK_C1) && - G_cme_stop_record.act_stop_c1 == STOP_LEVEL_0 && - G_cme_stop_record.req_stop_c1 != STOP_LEVEL_0) - { - core_aborted |= CME_MASK_C1; - core -= CME_MASK_C1; - deeper_core = 0; - - if (deeper_core == CME_MASK_C0) - { - target_level = deeper_level; - } - } + core = core & ~G_cme_stop_record.core_running; if (!core) { core |= core_aborted; entry_ongoing = 0; + break; } // If we are done at STOP level 4 or aborted @@ -673,16 +694,16 @@ p9_cme_stop_entry() target_level[%d],deeper_level[%d]", core, deeper_core, target_level, deeper_level); - //-------------------------------------------------------------------------- + //---------------------------------------------------------------------- // STOP LEVEL 5 (preparsion of STOP LEVEL 8 and above) - //-------------------------------------------------------------------------- + //---------------------------------------------------------------------- // block all wake up before purge L2, // this is last chance either core can exit - out32(CME_LCL_EIMR_OR, BITS32(12, 6)); + //out32(CME_LCL_EIMR_OR, BITS32(12, 6)); - if ((G_cme_stop_record.req_stop_c0 >= STOP_LEVEL_8) && - (G_cme_stop_record.req_stop_c1 >= STOP_LEVEL_8)) + if ((G_cme_stop_record.req_level_c0 >= STOP_LEVEL_8) && + (G_cme_stop_record.req_level_c1 >= STOP_LEVEL_8)) { //========================= @@ -698,16 +719,21 @@ p9_cme_stop_entry() // Poll for Purged Done PK_TRACE("SE5.1b"); + //=========================== MARK_TRAP(SE_IS2_BEGIN) - //=========================== + do { #if !SKIP_L2_PURGE_ABORT if(in32(CME_LCL_EINR) & BITS32(12, 6)) { + + //=============================== + MARK_TAG(SE_PURGE_L2_ABORT, core) + //=============================== // abort L2+NCU purges out32(CME_LCL_SICR_OR, BIT32(19) | BIT32(23)); } @@ -726,9 +752,9 @@ p9_cme_stop_entry() PK_TRACE("SE5.1: L2/NCU/CHTM Purged"); - //========================= - MARK_TRAP(SE_L2_PURGE_DONE) - //========================= + //============================== + MARK_TAG(SE_PURGE_L2_DONE, core) + //============================== } //============================= @@ -745,30 +771,24 @@ p9_cme_stop_entry() STOP_REQ_DISABLE, STOP_ACT_ENABLE); - if (core & CME_MASK_C0) - { - G_cme_stop_record.act_stop_c0 = STOP_LEVEL_5; - } - - if (core & CME_MASK_C1) - { - G_cme_stop_record.act_stop_c1 = STOP_LEVEL_5; - } - // Send PCB Interrupt per core PK_TRACE("SE5.2b"); pig.fields.req_intr_type = 2; //0b010: STOP State Change if (core & CME_MASK_C0) { - pig.fields.req_intr_payload = G_cme_stop_record.req_stop_c0; + pig.fields.req_intr_payload = G_cme_stop_record.req_level_c0; CME_PUTSCOM(PPM_PIG, CME_MASK_C0, pig.value); + G_cme_stop_record.core_stopgpe |= core; + G_cme_stop_record.act_level_c0 = STOP_LEVEL_5; } if (core & CME_MASK_C1) { - pig.fields.req_intr_payload = G_cme_stop_record.req_stop_c1; + pig.fields.req_intr_payload = G_cme_stop_record.req_level_c1; CME_PUTSCOM(PPM_PIG, CME_MASK_C1, pig.value); + G_cme_stop_record.core_stopgpe |= core; + G_cme_stop_record.act_level_c1 = STOP_LEVEL_5; } // Change PPM Wakeup to STOPGPE @@ -787,21 +807,6 @@ p9_cme_stop_entry() // Release PPM Write Protection CME_PUTSCOM(CPPM_CPMMR_CLR, core, BIT64(0)); - // Enable Wakeup Interrupts of this entry core if no handoff to SGPE - // Otherwise enable Doorbell interrupts of this entry core - out32(CME_LCL_EIMR_CLR, - ((~core & G_cme_stop_record.active_core & CME_MASK_BC) << SHIFT32(21))); - - if (!entry_ongoing) - out32(CME_LCL_EIMR_CLR, - /*TODO((core & ~core_aborted & CME_MASK_BC) << SHIFT32(13)) |*/ - ((core & ~core_aborted & CME_MASK_BC) << SHIFT32(15)) | - ((core & ~core_aborted & CME_MASK_BC) << SHIFT32(17))); - else - { - out32_sh(CME_LCL_EIMR_CLR, (core << SHIFT32((41 - 32)))); - } - //============================ MARK_TRAP(ENDSCOPE_STOP_ENTRY) //============================ diff --git a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_exit.c b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_exit.c index c86574ac..af473ea4 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_exit.c +++ b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_exit.c @@ -31,19 +31,21 @@ extern CmeStopRecord G_cme_stop_record; int p9_cme_stop_exit() { - int rc = 0; - uint8_t d2u4_flag = 0; + int rc = 0; + int d2u4_flag = 0; + int catchup_ongoing = 0; uint8_t target_level; - uint8_t deeper_level = 0; - uint32_t deeper_core = 0; + uint8_t deeper_level = 0; + uint32_t deeper_core = 0; uint32_t wakeup; + uint32_t pcwu; + uint32_t spwu; + uint32_t rgwu; uint32_t core; -#if !SKIP_CATCHUP - uint8_t core_catchup; +#if !SKIP_EXIT_CATCHUP + uint32_t core_catchup; #endif - uint8_t catchup_ongoing = 0; - uint8_t pcwu, spwu, rgwu; - //uint8_t grant; + //uint32_t grant; ppm_sshsrc_t hist; //-------------------------------------------------------------------------- @@ -60,8 +62,8 @@ p9_cme_stop_exit() rgwu = (wakeup >> 0) & CME_MASK_BC; core = pcwu | spwu | rgwu; - // mask wake up interrupts - out32(CME_LCL_EIMR_OR, BITS32(12, 6)); + // override with partial good core mask + core = core & G_cme_stop_record.core_enabled; PK_TRACE("X0: Core Select[%d], pcwu[%d], spwu[%d], rgwu[%d]", core, pcwu, spwu, rgwu); @@ -69,7 +71,7 @@ p9_cme_stop_exit() // Code Error: function should never be entered without wakeup source active if (!core) { - return CME_STOP_EXIT_NO_WAKEUP; + pk_halt(); } //================================== @@ -77,42 +79,42 @@ p9_cme_stop_exit() //================================== PK_TRACE("X0: Actual Stop Levels[%d %d]", - G_cme_stop_record.act_stop_c0, G_cme_stop_record.act_stop_c1); + G_cme_stop_record.act_level_c0, G_cme_stop_record.act_level_c1); // Code Error: by default stop 1 auto wakeup should be enabled - if ((core == CME_MASK_C0 && G_cme_stop_record.act_stop_c0 < 2) || - (core == CME_MASK_C1 && G_cme_stop_record.act_stop_c1 < 2) || - (core == CME_MASK_BC && (G_cme_stop_record.act_stop_c0 < 2 || - G_cme_stop_record.act_stop_c1 < 2))) + if ((core == CME_MASK_C0 && G_cme_stop_record.act_level_c0 < 2) || + (core == CME_MASK_C1 && G_cme_stop_record.act_level_c1 < 2) || + (core == CME_MASK_BC && (G_cme_stop_record.act_level_c0 < 2 || + G_cme_stop_record.act_level_c1 < 2))) { - return CME_STOP_EXIT_WAKEUP_FROM_STOP1; + pk_halt(); } // set target_level to STOP level for c0 // unless c1(also or only) wants to wakeup target_level = deeper_level = - (core == CME_MASK_C0) ? G_cme_stop_record.act_stop_c0 : - G_cme_stop_record.act_stop_c1; + (core == CME_MASK_C0) ? G_cme_stop_record.act_level_c0 : + G_cme_stop_record.act_level_c1; // If both cores want to wakeup but are in different STOP levels, // set deeper_level to the deeper level targeted by deeper core if ((core == CME_MASK_BC) && - (G_cme_stop_record.act_stop_c0 != G_cme_stop_record.act_stop_c1)) + (G_cme_stop_record.act_level_c0 != G_cme_stop_record.act_level_c1)) { // Assume C0 is deeper, target_level is already set to C1 - deeper_level = G_cme_stop_record.act_stop_c0; + deeper_level = G_cme_stop_record.act_level_c0; deeper_core = CME_MASK_C0; // Otherwise correct assumption on which one is in lighter level - if (G_cme_stop_record.act_stop_c0 < G_cme_stop_record.act_stop_c1) + if (G_cme_stop_record.act_level_c0 < G_cme_stop_record.act_level_c1) { - target_level = G_cme_stop_record.act_stop_c0; - deeper_level = G_cme_stop_record.act_stop_c1; + target_level = G_cme_stop_record.act_level_c0; + deeper_level = G_cme_stop_record.act_level_c1; deeper_core = CME_MASK_C1; } } - PK_TRACE("X0: target_lv[%d], deeper_lv[%d], deeper_core[%d]", + PK_TRACE("X0: target_lv[%d], deeper_lv[%d], deeper_c[%d]", target_level, deeper_level, deeper_core); PK_TRACE("X0: Update STOP History: In Transition of Exit"); @@ -132,7 +134,7 @@ p9_cme_stop_exit() // (G_cme_stop_record.pm_state_c0 < 11)) || // ((~grant & CME_MASK_C1 & core) && // (G_cme_stop_record.pm_state_c1 < 11))) - // return CME_STOP_EXIT_PCBMUX_LOST_GRANT; + // pk_halt(); out32(CME_LCL_SICR_OR, core << SHIFT32(11)); while((core & (in32(CME_LCL_SISR) >> SHIFT32(11))) != core); @@ -143,7 +145,9 @@ p9_cme_stop_exit() // STOP LEVEL 4 //-------------------------------------------------------------------------- - MARK_TRAP(SX_WAKEUP_START) + //====================== + MARK_TAG(SX_STOP3, core) + //====================== if (deeper_level >= 4) { @@ -165,18 +169,22 @@ p9_cme_stop_exit() //PK_TRACE("X1: Request PCB Arbiter"); //p9_hcd_core_pcb_arb(core, 1); + //======================== + MARK_TAG(SX_POWERON, core) + //======================== + PK_TRACE("X1: Core Poweron"); - MARK_TRAP(SX_POWERON) p9_hcd_core_poweron(core); - MARK_TRAP(SX_POWERON_END) - PK_TRACE("X2: Core Chiplet Reset"); + //========================= MARK_TRAP(SX_CHIPLET_RESET) + //========================= + + PK_TRACE("X2: Core Chiplet Reset"); p9_hcd_core_chiplet_reset(core); - MARK_TRAP(SX_CHIPLET_RESET_END) #if !STOP_PRIME -#if !SKIP_CATCHUP +#if !SKIP_EXIT_CATCHUP //catchup if (catchup_ongoing) @@ -188,58 +196,61 @@ p9_cme_stop_exit() { wakeup = (in32(CME_LCL_EISR) >> SHIFT32(17)) & 0x3F; out32(CME_LCL_EISR_CLR, wakeup << SHIFT32(17)); - core_catchup = ((wakeup >> 4) | (wakeup >> 2) | (wakeup >> 0)) & - CME_MASK_BC; + core_catchup = + ((wakeup >> 4) | (wakeup >> 2) | (wakeup >> 0)) & + CME_MASK_BC; if (core_catchup && (core_catchup + core) == CME_MASK_BC) { out32(CME_LCL_SICR_OR, core_catchup << SHIFT32(11)); if(((core_catchup & CME_MASK_C0) && - G_cme_stop_record.act_stop_c0 == STOP_LEVEL_2) || + G_cme_stop_record.act_level_c0 == STOP_LEVEL_2) || ((core_catchup & CME_MASK_C1) && - G_cme_stop_record.act_stop_c1 == STOP_LEVEL_2)) + G_cme_stop_record.act_level_c1 == STOP_LEVEL_2)) { deeper_core = core; d2u4_flag = 1; } else if(((core_catchup & CME_MASK_C0) && - G_cme_stop_record.act_stop_c0 == STOP_LEVEL_4) || + G_cme_stop_record.act_level_c0 == STOP_LEVEL_4) || ((core_catchup & CME_MASK_C1) && - G_cme_stop_record.act_stop_c1 == STOP_LEVEL_4)) + G_cme_stop_record.act_level_c1 == STOP_LEVEL_4)) { core = core_catchup; catchup_ongoing = 1; continue; } - while((core_catchup & (in32(CME_LCL_SISR) >> SHIFT32(11))) != - core_catchup); + while((core_catchup & (in32(CME_LCL_SISR) >> + SHIFT32(11))) != core_catchup); } + + //========================== + MARK_TAG(SX_CATCHUP_A, core) + //========================== } #endif #if !SKIP_INITF + //============================== + MARK_TAG(SX_CHIPLET_INITS, core) + //============================== + PK_TRACE("X3: Core GPTR Time Initf"); - MARK_TRAP(SX_GPTR_TIME_INITF) p9_hcd_core_gptr_time_initf(core); - MARK_TRAP(SX_GPTR_TIME_INITF_END) #endif PK_TRACE("X5: Core Chiplet Init"); - MARK_TRAP(SX_CHIPLET_INIT) p9_hcd_core_chiplet_init(core); - MARK_TRAP(SX_CHIPLET_INIT_END) #if !SKIP_INITF PK_TRACE("X6: Core Repair Initf"); - MARK_TRAP(SX_REPAIR_INITF) p9_hcd_core_repair_initf(core); - MARK_TRAP(SX_REPAIR_INITF_END) #endif -#if !SKIP_CATCHUP +#if !SKIP_EXIT_CATCHUP //catchup if (catchup_ongoing) @@ -251,50 +262,59 @@ p9_cme_stop_exit() { wakeup = (in32(CME_LCL_EISR) >> SHIFT32(17)) & 0x3F; out32(CME_LCL_EISR_CLR, wakeup << SHIFT32(17)); - core_catchup = ((wakeup >> 4) | (wakeup >> 2) | (wakeup >> 0)) & - CME_MASK_BC; + core_catchup = + ((wakeup >> 4) | (wakeup >> 2) | (wakeup >> 0)) & + CME_MASK_BC; if (core_catchup && (core_catchup + core) == CME_MASK_BC) { out32(CME_LCL_SICR_OR, core_catchup << SHIFT32(11)); if(((core_catchup & CME_MASK_C0) && - G_cme_stop_record.act_stop_c0 == STOP_LEVEL_2) || + G_cme_stop_record.act_level_c0 == STOP_LEVEL_2) || ((core_catchup & CME_MASK_C1) && - G_cme_stop_record.act_stop_c1 == STOP_LEVEL_2)) + G_cme_stop_record.act_level_c1 == STOP_LEVEL_2)) { deeper_core = core; d2u4_flag = 1; } else if(((core_catchup & CME_MASK_C0) && - G_cme_stop_record.act_stop_c0 == STOP_LEVEL_4) || + G_cme_stop_record.act_level_c0 == STOP_LEVEL_4) || ((core_catchup & CME_MASK_C1) && - G_cme_stop_record.act_stop_c1 == STOP_LEVEL_4)) + G_cme_stop_record.act_level_c1 == STOP_LEVEL_4)) { core = core_catchup; catchup_ongoing = 1; continue; } - while((core_catchup & (in32(CME_LCL_SISR) >> SHIFT32(11))) != - core_catchup); + while((core_catchup & (in32(CME_LCL_SISR) >> + SHIFT32(11))) != core_catchup); } + + //========================== + MARK_TAG(SX_CATCHUP_B, core) + //========================== } #endif #if !SKIP_ARY_INIT + //=========================== + MARK_TAG(SX_ARRAY_INIT, core) + //=========================== + PK_TRACE("X7: Core Array Init"); - MARK_TRAP(SX_ARRAY_INIT) p9_hcd_core_arrayinit(core); - MARK_TRAP(SX_ARRAY_INIT_END) #endif #if !SKIP_INITF + //===================== + MARK_TRAP(SX_FUNC_INIT) + //===================== + PK_TRACE("X8: Core Func Scan"); - MARK_TRAP(SX_INITF) p9_hcd_core_initf(core); - MARK_TRAP(SX_INITF_END) #endif #endif @@ -313,10 +333,15 @@ p9_cme_stop_exit() // STOP LEVEL 2 //-------------------------------------------------------------------------- + //============================ + MARK_TAG(SX_STARTCLOCKS, core) + //============================ + PK_TRACE("X9: Start Core Clock"); - MARK_TRAP(SX_STARTCLOCKS) p9_hcd_core_startclocks(core); - MARK_TRAP(SX_STARTCLOCKS_END) + + // Clear CPPM PECE Shadow + CME_PUTSCOM(CPPM_PECES, core, 0); //-------------------------------------------------------------------------- // STOP LEVEL 4 @@ -332,42 +357,51 @@ p9_cme_stop_exit() } #if !STOP_PRIME - // one example scom fir mask reg maybe + //=========================== + MARK_TAG(SX_SCOM_INITS, core) + //=========================== + PK_TRACE("X10: Image Hardcoded Scoms"); - MARK_TRAP(SX_SCOMINIT) p9_hcd_core_scominit(core); - MARK_TRAP(SX_SCOMINIT_END) + //========================== + MARK_TAG(SX_BCE_CHECK, core) + //========================== // todo PK_TRACE("BCE Runtime Check"); // todo //PK_TRACE("X11: XIP Customized Scoms"); //MARK_TRAP(SX_SCOMCUST) //p9_hcd_core_scomcust(core); - //MARK_TRAP(SX_SCOMCUST_END) + + //============================== + MARK_TAG(SX_RUNTIME_INITS, core) + //============================== // todo //PK_TRACE("X12: RAS Runtime Scom"); - //MARK_TRAP(SX_RAS_RUNTIME_SCOM) //p9_hcd_core_ras_runtime_scom(core); - //MARK_TRAP(SX_RAS_RUNTIME_SCOM_END) // todo //PK_TRACE("X13: OCC Runtime Scom"); - //MARK_TRAP(SX_RAS_RUNTIME_SCOM) //p9_hcd_core_occ_runtime_scom(core); - //MARK_TRAP(SX_RAS_RUNTIME_SCOM_END) #endif + //============================= + MARK_TAG(SX_SELF_RESTORE, core) + //============================= + PK_TRACE("X14: Core Self Restore"); - MARK_TRAP(SX_SELFRESTORE) #if !SKIP_SELF_RESTORE PK_TRACE("Raise block interrupt to PC"); out32(CME_LCL_SICR_OR, core << SHIFT32(3)); - PK_TRACE("RAM HRMOR"); + //===================== MARK_TRAP(SX_RAM_HRMOR) + //===================== + + PK_TRACE("RAM HRMOR"); PK_TRACE("Now Wakeup the Core(pm_exit=1)"); out32(CME_LCL_SICR_OR, core << SHIFT32(5)); @@ -381,7 +415,9 @@ p9_cme_stop_exit() // BIT64(3)|BIT64(11)|BIT64(19)|BIT64(27)); // BIT64(4)|BIT64(12)|BIT64(20)|BIT64(28)); + //========================== MARK_TRAP(SX_SRESET_THREADS) + //========================== PK_TRACE("Allow threads to run(pm_exit=0)"); out32(CME_LCL_SICR_CLR, core << SHIFT32(5)); @@ -390,15 +426,29 @@ p9_cme_stop_exit() while((~(in32(CME_LCL_EINR))) & (core << SHIFT32(21))); + //========================== MARK_TRAP(SX_STOP15_THREADS) + //========================== //PK_TRACE("Restore PSSCR back to actual level"); + //PLS here: + if (core & CME_MASK_C0) + CME_PUTSCOM(DIRECT_CONTROLS, CME_MASK_C0, + (((uint64_t)G_cme_stop_record.act_level_c0 << + SHIFT64(36)) | BIT64(32))); + + if (core & CME_MASK_C1) + CME_PUTSCOM(DIRECT_CONTROLS, CME_MASK_C1, + (((uint64_t)G_cme_stop_record.act_level_c1 << + SHIFT64(36)) | BIT64(32))); PK_TRACE("Drop block interrupt to PC"); out32(CME_LCL_SICR_CLR, core << SHIFT32(3)); #endif - MARK_TRAP(SX_SELFRESTORE_END) + //========================= + MARK_TRAP(SX_ENABLE_ANALOG) + //========================= if (d2u4_flag) { @@ -431,31 +481,29 @@ p9_cme_stop_exit() STOP_REQ_DISABLE, STOP_ACT_DISABLE) - G_cme_stop_record.active_core |= core; + G_cme_stop_record.core_running |= core; + G_cme_stop_record.core_stopgpe &= ~core; + out32(CME_LCL_LMCR_CLR, (core << SHIFT32(15))); if (core & CME_MASK_C0) { - G_cme_stop_record.act_stop_c0 = 0; + G_cme_stop_record.req_level_c0 = 0; + G_cme_stop_record.act_level_c0 = 0; } if (core & CME_MASK_C1) { - G_cme_stop_record.act_stop_c1 = 0; + G_cme_stop_record.req_level_c1 = 0; + G_cme_stop_record.act_level_c1 = 0; } // If not special wakeup, allow core to go back into STOP in the future if (!spwu) { - PK_TRACE("XF: Drop pm_exit if not special wakeup"); + PK_TRACE("XF: Drop pm_exit if special wakeup is not present"); out32(CME_LCL_SICR_CLR, core << SHIFT32(5)); } - // unmask stop interrupts - out32(CME_LCL_EIMR_CLR, ((core << SHIFT32(21)) | - /* ((~core & ~G_cme_stop_record.active_core & CME_MASK_BC)<<SHIFT32(13))| */ - ((~core & ~G_cme_stop_record.active_core & CME_MASK_BC) << SHIFT32(15)) | - ((~core & ~G_cme_stop_record.active_core & CME_MASK_BC) << SHIFT32(17)))); - //=========================== MARK_TRAP(ENDSCOPE_STOP_EXIT) //=========================== diff --git a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_exit_marks.h b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_exit_marks.h index 59c59d5b..30f2121d 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_exit_marks.h +++ b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_exit_marks.h @@ -36,44 +36,31 @@ namespace CME_STOP_EXIT_MARKS enum CME_SX_MARKS { - SX_WAKEUP_START = 0x0, + SX_STOP3 = 0x0, SX_POWERON = 0x8, SX_POWERON_DONE = 0x10, - SX_POWERON_PG_SEL = 0x18, - SX_POWERON_END = 0x20, - SX_CHIPLET_RESET = 0x28, - SX_CHIPLET_RESET_GLSMUX_RESET = 0x30, - SX_CHIPLET_RESET_SCAN0 = 0x38, - SX_CHIPLET_RESET_END = 0x40, - SX_GPTR_TIME_INITF = 0x48, - SX_GPTR_TIME_INITF_END = 0x50, - SX_CHIPLET_INIT = 0x68, - SX_CHIPLET_INIT_SCAN0 = 0xe0, - SX_CHIPLET_INIT_END = 0xe8, - SX_REPAIR_INITF = 0xf0, - SX_REPAIR_INITF_END = 0xf8, - SX_ARRAY_INIT = 0x100, - SX_ARRAY_INIT_SUBMODULE = 0x108, - SX_ARRAY_INIT_SCAN0 = 0x110, - SX_ARRAY_INIT_END = 0x118, - SX_INITF = 0x120, - SX_INITF_END = 0x128, - SX_STARTCLOCKS = 0x130, - SX_STARTCLOCKS_DONE = 0x138, - SX_STARTCLOCKS_END = 0x140, - SX_SCOMINIT = 0x148, - SX_SCOMINIT_END = 0x150, - SX_SCOMCUST = 0x168, - SX_SCOMCUST_END = 0x1e0, - SX_RAS_RUNTIME_SCOM = 0x1e8, - SX_RAS_RUNTIME_SCOM_END = 0x230, - SX_OCC_RUNTIME_SCOM = 0x238, - SX_OCC_RUNTIME_SCOM_END = 0x200, - SX_SELFRESTORE = 0x208, - SX_RAM_HRMOR = 0x210, - SX_SRESET_THREADS = 0x218, - SX_STOP15_THREADS = 0x220, - SX_SELFRESTORE_END = 0x228, + SX_CHIPLET_RESET = 0x18, + SX_CHIPLET_RESET_GLSMUX_RESET = 0x20, + SX_CHIPLET_RESET_SCAN0 = 0x28, + SX_CATCHUP_A = 0x30, + SX_CHIPLET_INITS = 0x38, + SX_CHIPLET_INIT_SCAN0 = 0x40, + SX_CATCHUP_B = 0x48, + SX_ARRAY_INIT = 0x50, + SX_ARRAY_INIT_SUBMODULE = 0x68, + SX_ARRAY_INIT_SCAN0 = 0xe0, + SX_FUNC_INIT = 0xe8, + SX_STARTCLOCKS = 0xf0, + SX_STARTCLOCKS_GRID = 0xf8, + SX_STARTCLOCKS_DONE = 0x100, + SX_SCOM_INITS = 0x108, + SX_BCE_CHECK = 0x110, + SX_RUNTIME_INITS = 0x118, + SX_SELF_RESTORE = 0x120, + SX_RAM_HRMOR = 0x128, + SX_SRESET_THREADS = 0x130, + SX_STOP15_THREADS = 0x138, + SX_ENABLE_ANALOG = 0x140, BEGINSCOPE_STOP_EXIT = 0x1f28, ENDSCOPE_STOP_EXIT = 0x1f30 }; @@ -83,44 +70,31 @@ enum CME_SX_MARKS const std::vector<CME_SX_MARKS> MARKS = { - SX_WAKEUP_START, + SX_STOP3, SX_POWERON, SX_POWERON_DONE, - SX_POWERON_PG_SEL, - SX_POWERON_END, SX_CHIPLET_RESET, SX_CHIPLET_RESET_GLSMUX_RESET, SX_CHIPLET_RESET_SCAN0, - SX_CHIPLET_RESET_END, - SX_GPTR_TIME_INITF, - SX_GPTR_TIME_INITF_END, - SX_CHIPLET_INIT, + SX_CATCHUP_A, + SX_CHIPLET_INITS, SX_CHIPLET_INIT_SCAN0, - SX_CHIPLET_INIT_END, - SX_REPAIR_INITF, - SX_REPAIR_INITF_END, + SX_CATCHUP_B, SX_ARRAY_INIT, SX_ARRAY_INIT_SUBMODULE, SX_ARRAY_INIT_SCAN0, - SX_ARRAY_INIT_END, - SX_INITF, - SX_INITF_END, + SX_FUNC_INIT, SX_STARTCLOCKS, + SX_STARTCLOCKS_GRID, SX_STARTCLOCKS_DONE, - SX_STARTCLOCKS_END, - SX_SCOMINIT, - SX_SCOMINIT_END, - SX_SCOMCUST, - SX_SCOMCUST_END, - SX_RAS_RUNTIME_SCOM, - SX_RAS_RUNTIME_SCOM_END, - SX_OCC_RUNTIME_SCOM, - SX_OCC_RUNTIME_SCOM_END, - SX_SELFRESTORE, + SX_SCOM_INITS, + SX_BCE_CHECK, + SX_RUNTIME_INITS, + SX_SELF_RESTORE, SX_RAM_HRMOR, SX_SRESET_THREADS, SX_STOP15_THREADS, - SX_SELFRESTORE_END, + SX_ENABLE_ANALOG, BEGINSCOPE_STOP_EXIT, ENDSCOPE_STOP_EXIT }; diff --git a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_irq_handlers.c b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_irq_handlers.c index e929ff31..59b95954 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_irq_handlers.c +++ b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_cme_stop_irq_handlers.c @@ -25,6 +25,7 @@ #include "p9_cme_stop.h" #include "p9_cme_stop_enter_marks.h" +#include "p9_cme_irq.h" extern CmeStopRecord G_cme_stop_record; @@ -33,24 +34,34 @@ p9_cme_stop_event_handler(void* arg, PkIrqId irq) { MARK_TRAP(STOP_EVENT_HANDLER) PK_TRACE("SE-IRQ: %d", irq); - - if (irq == IRQ_STOP_C0 || irq == IRQ_STOP_C1) - { - out32(CME_LCL_EIMR_OR, BITS32(20, 2)); - } - - if (irq >= IRQ_PC_C0 && irq <= IRQ_SWU_C1) - { - out32(CME_LCL_EIMR_OR, BITS32(12, 6)); - } - pk_semaphore_post((PkSemaphore*)arg); + + // Important: g_eimr_override at any time should mask wakeup interrupts of + // running core(s), the override vector should change after each + // entry and exit as core state is changed. + // For Entry, mask the following interrupts via unified interrupt handler: + // lower priority interrupts than pm_active, and both pm_active (catchup) + // wakeup interrupts of the entering core(s) should still be masked + // via g_eimr_override (abortion), stopped core can still exit any time + // as their wakeup interrupts should be unmasked + // After Entry, unmask the following interrupts via pk_irq_vec_restore: + // priority group on stack, likely at least both pm_active unmasked + // (stopped core cannot get extra pm_active, untouched core can enter) + // here needs to use g_eimr_override to mask wakeup of running core(s) + // wakeup of the stopped core(s) should be already unmasked by default + // (when restored, previous masked wakeups are being unmasked as well) + // For Exit, mask the following interrupts via unified interrupt handler: + // lower priority interrupts than wakeup, including DB2+pm_active(catchup) + // After Exit, unmask the following interrupts via pk_irq_vec_restore: + // priority group on stack, likely at least wakeup and DB2 unmasked + // here needs to use g_eimr_override to mask wakeup of exited core(s) } void p9_cme_stop_doorbell_handler(void* arg, PkIrqId irq) { - int rc = 0; + int rc = 0; + PkMachineContext ctx; MARK_TRAP(STOP_DOORBELL_HANDLER) PK_TRACE("DB-IRQ: %d", irq); @@ -60,15 +71,16 @@ p9_cme_stop_doorbell_handler(void* arg, PkIrqId irq) if (irq == IRQ_DB1_C0) { CME_PUTSCOM(CPPM_CMEDB1, CME_MASK_C0, 0); - out32(CME_LCL_EIMR_CLR, BIT32(12) | BIT32(14) | BIT32(16)); + g_eimr_override &= ~IRQ_VEC_WAKE_C0; + //out32(CME_LCL_EIMR_CLR, BIT32(12) | BIT32(14) | BIT32(16)); } if (irq == IRQ_DB1_C1) { CME_PUTSCOM(CPPM_CMEDB1, CME_MASK_C1, 0); - out32(CME_LCL_EIMR_CLR, BIT32(13) | BIT32(15) | BIT32(17)); + g_eimr_override &= ~IRQ_VEC_WAKE_C1; + //out32(CME_LCL_EIMR_CLR, BIT32(13) | BIT32(15) | BIT32(17)); } - //TODO mask pc_itr_pending as workaround for double interrupts of pc and rwu - out32(CME_LCL_EIMR_OR, BITS32(12, 2)); + pk_irq_vec_restore(&ctx); } diff --git a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_hcd_core_chiplet_reset.c b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_hcd_core_chiplet_reset.c index ad044dfb..50c0e058 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_hcd_core_chiplet_reset.c +++ b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_hcd_core_chiplet_reset.c @@ -30,43 +30,55 @@ int p9_hcd_core_chiplet_reset(uint32_t core) { int rc = CME_STOP_SUCCESS; - uint64_t data, loop; + //uint64_t scom_data, + uint32_t loop; - PK_TRACE("Init NETWORK_CONTROL0, step needed for hotplug"); + PK_TRACE("Init NET_CTRL0[1-5,12-14,18,22,26],step needed for hotplug"); CME_PUTSCOM(CPPM_NC0INDIR_OR, core, NET_CTRL0_INIT_VECTOR); - PK_TRACE("Assert Core Progdly and DCC Bypass"); + PK_TRACE("Flip core glsmux to refclk via PPM_CGCR[3]"); + CME_PUTSCOM(C_PPM_CGCR, core, BIT64(0)); + + PK_TRACE("Assert core progdly and DCC bypass via NET_CTRL1[1,2]"); CME_PUTSCOM(CPPM_NC1INDIR_OR, core, BITS64(1, 2)); - PK_TRACE("Assert Core DCC Reset"); + PK_TRACE("Assert core DCC reset via NET_CTRL0[2]"); CME_PUTSCOM(CPPM_NC0INDIR_OR, core, BIT64(2)); - PK_TRACE("Assert Vital Thold"); + PK_TRACE("Drop vital thold via NET_CTRL0[16]"); CME_PUTSCOM(CPPM_NC0INDIR_CLR, core, BIT64(16)); - - PK_TRACE("ONLY till TP030: SET VITL_PHASE=1"); - CME_PUTSCOM(CPPM_NC0INDIR_OR, core, BIT64(8)); - PPE_WAIT_CORE_CYCLES(loop, 50); - + /* + PK_TRACE("ONLY till TP030: SET VITL_PHASE=1"); + CME_PUTSCOM(CPPM_NC0INDIR_OR, core, BIT64(8)); + PPE_WAIT_CORE_CYCLES(loop, 50); + */ MARK_TRAP(SX_CHIPLET_RESET_GLSMUX_RESET) - PK_TRACE("Init Core Glitchless Mux Reset/Select via CLOCK_GRID_CTRL[0:3]"); + PK_TRACE("Drop core glsmux reset via PPM_CGCR[0]"); + CME_PUTSCOM(C_PPM_CGCR, core, 0); + PPE_WAIT_CORE_CYCLES(loop, 400); + + PK_TRACE("Flip core glsmux to DPLL via PPM_CGCR[3]"); CME_PUTSCOM(C_PPM_CGCR, core, BIT64(3)); - PK_TRACE("Clear PCB Endpoint Reset via NET_CTRL0[1]"); + PK_TRACE("Assert chiplet enable via NET_CTRL0[0]"); + CME_PUTSCOM(CPPM_NC0INDIR_OR, core, BIT64(0)); + + PK_TRACE("Drop PCB endpoint reset via NET_CTRL0[1]"); CME_PUTSCOM(CPPM_NC0INDIR_CLR, core, BIT64(1)); - PPE_WAIT_CORE_CYCLES(loop, 50); - PK_TRACE("Remove chiplet electrical fence via NET_CTRL0[26]"); + PK_TRACE("Drop chiplet electrical fence via NET_CTRL0[26]"); CME_PUTSCOM(CPPM_NC0INDIR_CLR, core, BIT64(26)); - CME_PUTSCOM(CPPM_NC0INDIR_CLR, core, BIT64(25)); - - PK_TRACE("ONLY till TP030: SET SYNC_PULSE_DELAY=0b0011"); - CME_GETSCOM(C_SYNC_CONFIG, core, CME_SCOM_AND, data); - data = data | 0x3000000000000000; - data = data & 0x3FFFFFFFFFFFFFFF; - CME_PUTSCOM(C_SYNC_CONFIG, core, data); + PK_TRACE("Drop PCB fence via NET_CTRL0[25]"); + CME_PUTSCOM(CPPM_NC0INDIR_CLR, core, BIT64(25)); + /* + PK_TRACE("ONLY till TP030: SET SYNC_PULSE_DELAY=0b0011"); + CME_GETSCOM(C_SYNC_CONFIG, core, CME_SCOM_AND, scom_data); + scom_data = scom_data | 0x3000000000000000; + scom_data = scom_data & 0x3FFFFFFFFFFFFFFF; + CME_PUTSCOM(C_SYNC_CONFIG, core, scom_data); + */ #if !SKIP_SCAN0 // Marker for scan0 MARK_TRAP(SX_CHIPLET_RESET_SCAN0) diff --git a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_hcd_core_poweron.c b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_hcd_core_poweron.c index 7dce5e04..b24a192e 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_hcd_core_poweron.c +++ b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_hcd_core_poweron.c @@ -31,21 +31,23 @@ p9_hcd_core_poweron(uint32_t core) { int rc = CME_STOP_SUCCESS; - PK_TRACE("Set core glsmux reset"); + PK_TRACE("Drop chiplet enable via NET_CTRL0[0]"); + CME_PUTSCOM(CPPM_NC0INDIR_CLR, core, BIT64(0)); + + PK_TRACE("Assert PCB fence via NET_CTRL0[25]"); + CME_PUTSCOM(CPPM_NC0INDIR_OR, core, BIT64(25)); + + PK_TRACE("Assert chiplet electrical fence via NET_CTRL0[26]"); + CME_PUTSCOM(CPPM_NC0INDIR_OR, core, BIT64(26)); + + PK_TRACE("Assert vital thold via NET_CTRL0[16]"); + CME_PUTSCOM(CPPM_NC0INDIR_OR, core, BIT64(16)); + + PK_TRACE("Assert core glsmux reset via PPM_CGCR[0]"); CME_PUTSCOM(C_PPM_CGCR, core, BIT64(0)); + #if !STOP_PRIME uint64_t scom_data; -#if !EPM_P9_TUNNING - // vdd_pfet_force_state == 00 (Nop) - PK_TRACE("Make sure we are not forcing PFET for VDD off"); - CME_GETSCOM(PPM_PFCS, core, CME_SCOM_AND, scom_data); - - if (scom_data & BITS64(0, 2)) - { - return CME_STOP_ENTRY_VDD_PFET_NOT_IDLE; - } - -#endif // vdd_pfet_val/sel_override = 0 (disbaled) // vdd_pfet_regulation_finger_en = 0 (controled by FSM) @@ -66,17 +68,6 @@ p9_hcd_core_poweron(uint32_t core) MARK_TRAP(SX_POWERON_DONE) -#if !EPM_P9_TUNNING - PK_TRACE("Optional: Poll for vdd_pg_sel being: 0x0"); - - do - { - CME_GETSCOM(PPM_PFCS, core, CME_SCOM_AND, scom_data); - } - while(scom_data & BIT64(46)); - - MARK_TRAP(SX_POWERON_PG_SEL) -#endif // vdd_pfet_force_state = 00 (Nop) PK_TRACE("Turn Off Force Von"); CME_PUTSCOM(PPM_PFCS_CLR, core, BITS64(0, 2)); diff --git a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_hcd_core_startclocks.c b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_hcd_core_startclocks.c index 5f383b74..3ab36b7f 100644 --- a/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_hcd_core_startclocks.c +++ b/import/chips/p9/procedures/ppe_closed/cme/stop_cme/p9_hcd_core_startclocks.c @@ -30,84 +30,85 @@ int p9_hcd_core_startclocks(uint32_t core) { int rc = CME_STOP_SUCCESS; - uint64_t data, loop; + uint64_t scom_data, loop; - PK_TRACE("Setup OPCG_ALIGN Register"); - CME_GETSCOM(C_OPCG_ALIGN, core, CME_SCOM_AND, data); - data = data & ~(BITS64(0, 4) & BITS64(12, 8) & BITS64(52, 12)); - data = data | (BIT64(1) | BIT64(3) | BIT64(59)); - CME_PUTSCOM(C_OPCG_ALIGN, core, data); + // do this again here for stop2 in addition to chiplet_reset + PK_TRACE("4S2: Set Core Glitchless Mux to DPLL"); + CME_PUTSCOM(C_PPM_CGCR, core, BIT64(3)); - PK_TRACE("Drop partial good fences via CPLT_CTRL1"); + PK_TRACE("Set inop_align/wait/wait_cycles via OPCG_ALIGN[0-3,12-19,52-63]"); + CME_GETSCOM(C_OPCG_ALIGN, core, CME_SCOM_AND, scom_data); + scom_data = scom_data & ~(BITS64(0, 4) & BITS64(12, 8) & BITS64(52, 12)); + scom_data = scom_data | (BIT64(1) | BIT64(3) | BIT64(59)); + CME_PUTSCOM(C_OPCG_ALIGN, core, scom_data); + + PK_TRACE("Drop partial good fences via CPLT_CTRL1[3-14]"); CME_PUTSCOM(C_CPLT_CTRL1_CLEAR, core, 0xFFFF700000000000); - PK_TRACE("Drop vital fences via CPLT_CTRL1"); + PK_TRACE("Drop vital fences via CPLT_CTRL1[3]"); CME_PUTSCOM(C_CPLT_CTRL1_CLEAR, core, BIT64(3)); - PK_TRACE("Raise core clock sync enable"); + PK_TRACE("Assert core clock sync enable via CPPM_CACCR[15]"); CME_PUTSCOM(CPPM_CACCR_OR, core, BIT64(15)); -#if !EPM_P9_TUNING - PK_TRACE("Poll for core clock sync done to raise"); + PK_TRACE("Poll for core clock sync done via CPPM_CACSR[13]"); do { - CME_GETSCOM(CPPM_CACSR, core, CME_SCOM_AND, data); + CME_GETSCOM(CPPM_CACSR, core, CME_SCOM_AND, scom_data); } - while(~data & BIT64(13)); - -#endif + while(~scom_data & BIT64(13)); PK_TRACE("Reset abstclk & syncclk muxsel(io_clk_sel) via CPLT_CTRL0[0:1]"); CME_PUTSCOM(C_CPLT_CTRL0_CLEAR, core, BITS64(0, 2)); // align_chiplets() - PK_TRACE("Set flushmode_inhibit via CPLT_CTRL0[2]"); + PK_TRACE("Assert flushmode_inhibit via CPLT_CTRL0[2]"); CME_PUTSCOM(C_CPLT_CTRL0_OR, core, BIT64(2)); - PK_TRACE("Set force_align via CPLT_CTRL0[3]"); + PK_TRACE("Assert force_align via CPLT_CTRL0[3]"); CME_PUTSCOM(C_CPLT_CTRL0_OR, core, BIT64(3)); - PK_TRACE("Set/Unset clear_chiplet_is_aligned via SYNC_CONFIG[7]"); - CME_GETSCOM(C_SYNC_CONFIG, core, CME_SCOM_AND, data); - data = data | BIT64(7); - CME_PUTSCOM(C_SYNC_CONFIG, core, data); - data = data & ~BIT64(7); - CME_PUTSCOM(C_SYNC_CONFIG, core, data); + PK_TRACE("Set then unset clear_chiplet_is_aligned via SYNC_CONFIG[7]"); + CME_GETSCOM(C_SYNC_CONFIG, core, CME_SCOM_AND, scom_data); + scom_data = scom_data | BIT64(7); + CME_PUTSCOM(C_SYNC_CONFIG, core, scom_data); + scom_data = scom_data & ~BIT64(7); + CME_PUTSCOM(C_SYNC_CONFIG, core, scom_data); PK_TRACE("Check chiplet_is_aligned"); do { - CME_GETSCOM(C_CPLT_STAT0, core, CME_SCOM_AND, data); + CME_GETSCOM(C_CPLT_STAT0, core, CME_SCOM_AND, scom_data); } - while(~data & BIT64(9)); + while(~scom_data & BIT64(9)); - PK_TRACE("Clear force_align via CPLT_CTRL0[3]"); + PK_TRACE("Drop force_align via CPLT_CTRL0[3]"); CME_PUTSCOM(C_CPLT_CTRL0_CLEAR, core, BIT64(3)); PPE_WAIT_CORE_CYCLES(loop, 450); // clock_start() - PK_TRACE("Set all bits to zero prior clock start via SCAN_REGION_TYPE"); + PK_TRACE("Clear all bits prior start core clocks via SCAN_REGION_TYPE"); CME_PUTSCOM(C_SCAN_REGION_TYPE, core, 0); - PK_TRACE("Start clock(arrays+nsl clock region) via CLK_REGION"); - data = 0x5FFC000000006000; - CME_PUTSCOM(C_CLK_REGION, core, data); + PK_TRACE("Start core clocks(arrays+nsl clock region) via CLK_REGION"); + scom_data = 0x4FFC000000006000; + CME_PUTSCOM(C_CLK_REGION, core, scom_data); - PK_TRACE("Start clock(sl+refresh clock region) via CLK_REGION"); - data = 0x5FFC00000000E000; - CME_PUTSCOM(C_CLK_REGION, core, data); + PK_TRACE("Start core clocks(sl+refresh clock region) via CLK_REGION"); + scom_data = 0x4FFC00000000E000; + CME_PUTSCOM(C_CLK_REGION, core, scom_data); - PK_TRACE("Polling for clocks starting via CLOCK_STAT_SL"); + PK_TRACE("Polling for core clocks running via CLOCK_STAT_SL"); do { - CME_GETSCOM(C_CLOCK_STAT_SL, core, CME_SCOM_AND, data); + CME_GETSCOM(C_CLOCK_STAT_SL, core, CME_SCOM_AND, scom_data); } - while((~data & BITS64(4, 10)) != BITS64(4, 10)); + while((scom_data & BITS64(4, 10)) != 0); PK_TRACE("Core clock is now running"); @@ -116,12 +117,9 @@ p9_hcd_core_startclocks(uint32_t core) PK_TRACE("Drop chiplet fence via NC0INDIR[18]"); CME_PUTSCOM(CPPM_NC0INDIR_CLR, core, BIT64(18)); - //PK_TRACE("Drop fence to allow PCB operations to chiplet via NC0INDIR[26]"); - //CME_PUTSCOM(CPPM_NC0INDIR_CLR, core, BIT64(25)); - // checkstop - PK_TRACE("Clear flushmode_inhibit via CPLT_CTRL0[2]"); + PK_TRACE("Drop flushmode_inhibit via CPLT_CTRL0[2]"); CME_PUTSCOM(C_CPLT_CTRL0_CLEAR, core, BIT64(2)); // check align diff --git a/import/chips/p9/procedures/ppe_closed/cme/topfiles.mk b/import/chips/p9/procedures/ppe_closed/cme/topfiles.mk new file mode 100644 index 00000000..4112e534 --- /dev/null +++ b/import/chips/p9/procedures/ppe_closed/cme/topfiles.mk @@ -0,0 +1,51 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: import/chips/p9/procedures/ppe_closed/cme/topfiles.mk $ +# +# 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 + + +TOP-C-SOURCES = p9_cme_main.c \ + p9_cme_irq.c +PSTATE-C-SOURCES = pstate_cme/p9_cme_pstate.c +STOP-C-SOURCES = stop_cme/p9_cme_stop_irq_handlers.c \ + stop_cme/p9_cme_stop_enter_thread.c \ + stop_cme/p9_cme_stop_exit_thread.c \ + stop_cme/p9_cme_stop_entry.c \ + stop_cme/p9_cme_stop_exit.c \ + stop_cme/p9_hcd_core_poweron.c \ + stop_cme/p9_hcd_core_chiplet_reset.c \ + stop_cme/p9_hcd_core_gptr_time_initf.c \ + stop_cme/p9_hcd_core_chiplet_init.c \ + stop_cme/p9_hcd_core_repair_initf.c \ + stop_cme/p9_hcd_core_arrayinit.c \ + stop_cme/p9_hcd_core_initf.c \ + stop_cme/p9_hcd_core_startclocks.c \ + stop_cme/p9_hcd_core_scominit.c \ + stop_cme/p9_hcd_core_scomcust.c \ + stop_cme/p9_hcd_core_ras_runtime_scom.c \ + stop_cme/p9_hcd_core_occ_runtime_scom.c +TOP-S-SOURCES = + +TOP_OBJECTS = $(TOP-C-SOURCES:.c=.o) $(TOP-S-SOURCES:.S=.o) +PSTATE_OBJECTS = $(PSTATE-C-SOURCES:.c=.o) +STOP_OBJECTS = $(STOP-C-SOURCES:.c=.o) |