/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/usr/diag/prdf/occ_firdata/prdfWriteHomerFirData.C $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] 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 #include #include #include #include #include #include #include #include // for getMasterCore() using namespace TARGETING; namespace PRDF { using namespace PlatServices; //------------------------------------------------------------------------------ // Register lists //------------------------------------------------------------------------------ // TODO RTC 124849: Auto-generate this list from rule code. // although HDCT plays a role // currently have a mix from HDCT, P8->P9 manual conversion // and some other chiplet attn regs // For Creating list of registers typedef std::vector AddrList_t; typedef std::map RegMap_t; typedef std::map TrgtMap_t; /** * @fn void getAddresses( TrgtMap_t & io_targMap ) * * @brief Fills in the SCOM addresses we need for all targets * and for all register types. */ void getAddresses( TrgtMap_t & io_targMap ) { io_targMap[TRGT_PROC][REG_GLBL] = { 0x500F001C, // GLOBAL_CS_FIR 0x500F001B, // GLOBAL_RE_FIR 0x50040018, // GLOBAL_UNIT_CS_FIR // NOTE: The SPA/HOST_ATTN global/chiplet registers will not be captured // because those attention types are not used for checkstop // analysis. }; io_targMap[TRGT_PHB][REG_FIR] = { 0x04010C40, // PHBNFIR 0x0D010840, // PCIFIR 0x0D010908, // ETUFIR }; io_targMap[TRGT_PHB][REG_REG] = { // c_err_rpt registers 0x0D01084B, // PBAIB CERR Report Hold Reg }; io_targMap[TRGT_CAPP][REG_FIR] = { 0x02010800, // CXAFIR }; io_targMap[TRGT_CAPP][REG_REG] = { // c_err_rpt registers 0x0201080a, // Snoop Error Report Reg 0x0201080b, // APC CERR Hold 0x0201080c, // XPT Error Report 0x0201080d, // TLBI Error Report 0x0201080e, // Capp Error Status and Ctrl Reg }; io_targMap[TRGT_XBUS][REG_FIR] = { 0x06010c00, // IOXBFIR 0x06011800, // IOELFIR }; io_targMap[TRGT_XBUS][REG_REG] = { // c_err_rpt registers 0x06011816, // PB ELL Link0 ErrStatus 0x06011817, // PB ELL Link1 ErrStatus }; io_targMap[TRGT_OBUS][REG_GLBL] = { 0x09040000, // OB_CHIPLET_CS_FIR 0x09040001, // OB_CHIPLET_RE_FIR 0x09040018, // OB_CHIPLET_UCS_FIR }; io_targMap[TRGT_OBUS][REG_FIR] = { 0x0904000a, // OB LFIR 0x09010800, // IOOLFIR 0x09010C00, // IOOBFIR 0x09011040, // OBPPEFIR }; io_targMap[TRGT_OBUS][REG_REG] = { // Chiplet FIRs 0x09040002, // OB_CHIPLET_FIR_MASK 0x09040019, // OB_CHIPLET_UCS_FIR_MASK // PLL registers 0x090F001E, // OBUS_CONFIG_REG 0x090F001F, // OBUS_ERROR_REG // c_err_rpt registers 0x09010816, // PB OLL Link0 ErrStatus 0x09010817, // PB OLL Link1 ErrStatus }; io_targMap[TRGT_PEC][REG_FIR] = { 0x0D04000a, // PCI_LFIR 0x0D010C00, // IOPCIFIR }; io_targMap[TRGT_PEC][REG_REG] = { // PLL registers 0x0D0F001E, // PCI_CONFIG_REG 0x0D0F001F, // PCI_ERROR_REG }; io_targMap[TRGT_MCS][REG_FIR] = { 0x05010800, // MCIFIR }; io_targMap[TRGT_MCS][REG_REG] = { // c_err_rpt registers 0x0501081a, // MC Error Report 2 0x0501081e, // MC Error Report 0 0x0501081f, // MC Error Report 1 // Memory config registers 0x0501080a, // Primary MemCfg Reg 0x0501080b, // MCFGPA 0x0501080c, // MCFGPM 0x0501080d, // MCFGPMA }; io_targMap[TRGT_MCBIST][REG_GLBL] = { 0x07040000, // MC_CHIPLET_CS_FIR 0x07040001, // MC_CHIPLET_RE_FIR 0x07040018, // MC_CHIPLET_UCS_FIR }; io_targMap[TRGT_MCBIST][REG_FIR] = { 0x0704000A, // MC_LFIR 0x07012300, // MCBISTFIR }; io_targMap[TRGT_MCA][REG_FIR] = { 0x07010900, // MCACALFIR 0x07010A00, // MCAECCFIR 0x07011000, // DDRPHYFIR }; io_targMap[TRGT_MCBIST][REG_REG] = { // Chiplet FIRs 0x07040002, // MC_CHIPLET_FIR_MASK 0x07040019, // MC_CHIPLET_UCS_FIR_MASK // PLL registers 0x070F001E, // MC_CONFIG_REG 0x070F001F, // MC_ERROR_REG // AUE/IAUE analysis 0x0701236D, // MCB0_MBUER 0x0701236E, // MCB0_MBAUER 0x07012372, // MCB1_MBUER 0x07012373, // MCB1_MBAUER 0x07012377, // MCB2_MBUER 0x07012378, // MCB2_MBAUER 0x0701237C, // MCB3_MBUER 0x0701237D, // MCB3_MBAUER 0x070123D7, // MCBMCAT }; io_targMap[TRGT_EQ][REG_GLBL] = { 0x10040000, // EQ_CHIPLET_CS_FIR 0x10040001, // EQ_CHIPLET_RE_FIR }; io_targMap[TRGT_EQ][REG_FIR] = { 0x1004000A, // EQ_LFIR }; io_targMap[TRGT_EQ][REG_REG] = { // Chiplet FIRs 0x10040002, // EQ_CHIPLET_FIR_MASK // PLL registers 0x100F001E, // EQ_CONFIG_REG 0x100F001F, // EQ_ERROR_REG }; io_targMap[TRGT_PROC][REG_FIR] = { 0x0104000a, // TP_LFIR 0x01010800, // OCCFIR 0x0204000a, // N0_LFIR 0x02011080, // NXCQFIR 0x02011100, // NXDMAENGFIR 0x0304000a, // N1_LFIR 0x03011000, // MCDFIR_0 0x03011400, // MCDFIR_1 0x03011800, // VASFIR 0x0404000a, // N2_LFIR 0x04011800, // PSIFIR 0x0504000a, // N3_LFIR 0x05011800, // PBWESTFIR 0x05011C00, // PBCENTFIR 0x05012000, // PBEASTFIR 0x05012400, // PBPPEFIR 0x05012840, // PBAFIR 0x05012900, // PSIHBFIR 0x05012940, // ENHCAFIR 0x050129C0, // PBAMFIR 0x05012C00, // NMMUCQFIR 0x05012C40, // NMMUFIR 0x05013030, // INTCQFIR 0x05013400, // PBIOEFIR 0x05013800, // PBIOOFIR 0x05013C00, // NPU0FIR 0x05013C40, // NPU1FIR 0x05013C80, // NPU2FIR 0x0604000a, // XBUS_LFIR 0x06010840, // XBPPEFIR }; io_targMap[TRGT_PROC][REG_REG] = { // Global FIRs 0x500F001A, // GLOBAL_SPA (FFDC only, in case there was a TI) // Chiplet FIRs 0x01040000, // TP_CHIPLET_CS_FIR 0x01040001, // TP_CHIPLET_RE_FIR 0x01040002, // TP_CHIPLET_FIR_MASK 0x02040000, // N0_CHIPLET_CS_FIR 0x02040001, // N0_CHIPLET_RE_FIR 0x02040002, // N0_CHIPLET_FIR_MASK 0x02040018, // N0_CHIPLET_UCS_FIR 0x02040019, // N0_CHIPLET_UCS_FIR_MASK 0x03040000, // N1_CHIPLET_CS_FIR 0x03040001, // N1_CHIPLET_RE_FIR 0x03040002, // N1_CHIPLET_FIR_MASK 0x03040018, // N1_CHIPLET_UCS_FIR 0x03040019, // N1_CHIPLET_UCS_FIR_MASK 0x04040000, // N2_CHIPLET_CS_FIR 0x04040001, // N2_CHIPLET_RE_FIR 0x04040002, // N2_CHIPLET_FIR_MASK 0x04040018, // N2_CHIPLET_UCS_FIR 0x04040019, // N2_CHIPLET_UCS_FIR_MASK // There are over 90 registers captured for NPU0FIR, but that is too // much for the limited space in the OP checkstop analysis design. The // hardware team agreed this was the minimum set of registers needed // for a checkstop. We have also been told most of these should have a // zero value so they should not take up too much space. 0x05011018, // NPU_S0_CS_SM0_CERR_1 0x05011019, // NPU_S0_CS_SM0_CERR_2 0x05011048, // NPU_S0_CS_SM1_CERR_1 0x05011049, // NPU_S0_CS_SM1_CERR_2 0x05011078, // NPU_S0_CS_SM2_CERR_1 0x05011079, // NPU_S0_CS_SM2_CERR_2 0x050110A8, // NPU_S0_CS_SM3_CERR_1 0x050110A9, // NPU_S0_CS_SM3_CERR_2 0x050110DB, // NPU_S0_CS_CTL_CERR_1 0x050110FA, // NPU_S0_DAT_CERR_LOG_HOLD 0x050110FD, // NPU_S0_DAT_REM0 0x050110FE, // NPU_S0_DAT_REM1 0x05011218, // NPU_S1_CS_SM0_CERR_1 0x05011219, // NPU_S1_CS_SM0_CERR_2 0x05011248, // NPU_S1_CS_SM1_CERR_1 0x05011249, // NPU_S1_CS_SM1_CERR_2 0x05011278, // NPU_S1_CS_SM2_CERR_1 0x05011279, // NPU_S1_CS_SM2_CERR_2 0x050112A8, // NPU_S1_CS_SM3_CERR_1 0x050112A9, // NPU_S1_CS_SM3_CERR_2 0x050112DB, // NPU_S1_CS_CTL_CERR_1 0x050112FA, // NPU_S1_DAT_CERR_LOG_HOLD 0x050112FD, // NPU_S1_DAT_REM0 0x050112FE, // NPU_S1_DAT_REM1 0x05011418, // NPU_S2_CS_SM0_CERR_1 0x05011419, // NPU_S2_CS_SM0_CERR_2 0x05011448, // NPU_S2_CS_SM1_CERR_1 0x05011449, // NPU_S2_CS_SM1_CERR_2 0x05011478, // NPU_S2_CS_SM2_CERR_1 0x05011479, // NPU_S2_CS_SM2_CERR_2 0x050114A8, // NPU_S2_CS_SM3_CERR_1 0x050114A9, // NPU_S2_CS_SM3_CERR_2 0x050114DB, // NPU_S2_CS_CTL_CERR_1 0x050114FA, // NPU_S2_DAT_CERR_LOG_HOLD 0x050114FD, // NPU_S2_DAT_REM0 0x050114FE, // NPU_S2_DAT_REM1 0x05040000, // N3_CHIPLET_CS_FIR 0x05040001, // N3_CHIPLET_RE_FIR 0x05040002, // N3_CHIPLET_FIR_MASK 0x05040018, // N3_CHIPLET_UCS_FIR 0x05040019, // N3_CHIPLET_UCS_FIR_MASK 0x06040000, // XB_CHIPLET_CS_FIR 0x06040001, // XB_CHIPLET_RE_FIR 0x06040002, // XB_CHIPLET_FIR_MASK 0x06040018, // XB_CHIPLET_UCS_FIR 0x06040019, // XB_CHIPLET_UCS_FIR_MASK // Chiplet FIRs 0x0D040000, // PCI0_CHIPLET_CS_FIR 0x0D040001, // PCI0_CHIPLET_RE_FIR 0x0D040002, // PCI0_CHIPLET_FIR_MASK 0x0E040000, // PCI1_CHIPLET_CS_FIR 0x0E040001, // PCI1_CHIPLET_RE_FIR 0x0E040002, // PCI1_CHIPLET_FIR_MASK 0x0F040000, // PCI2_CHIPLET_CS_FIR 0x0F040001, // PCI2_CHIPLET_RE_FIR 0x0F040002, // PCI2_CHIPLET_FIR_MASK // Misc registers needed for PRD analysis 0x05011C2E, // PBEXTFIR (does not raise attn, used for fabric sorting) 0x05011C0A, // PB_CENT_MODE 0x00040020, // TODWOF // PLL registers 0x010F001E, // TP_CONFIG_REG 0x010F001F, // TP_ERROR_REG 0x060F001E, // XBUS_CONFIG_REG 0x060F001F, // XBUS_ERROR_REG // c_err_rpt registers 0x0101080a, // OCC Error Report Reg 0x020110a1, // PB Error Report 0x020110a2, // PB Pty Error Report 0x02011057, // DMA CERR 0 0x02011058, // DMA CERR 1 0x05011c2c, // PB Cent CR ERROR 0x0501284c, // PBA Err Report0 0x0501284d, // PBA Err Report1 0x0501284e, // PBA Err Report2 0x05012C22, // PB Pty Error Report // TOD registers 0x00040005, // TOD: Slave path ctrl reg 0x00040006, // TOD: Internal path ctrl reg 0x00040007, // TOD: primary/secondary config ctrl 0x00040008, // TOD: PSS MSS Status Reg 0x00040009, // TOD: Master Path Status Reg 0x0004000E, // TOD: Master Path0 Step Steering 0x0004000F, // TOD: Master Path1 Step Steering 0x0004001D, // TOD: Trace dataset 1 0x0004001E, // TOD: Trace dataset 2 0x0004001F, // TOD: Trace dataset 3 0x01020019, // OSC Error Hold 0x0102001A, // OSC Error Mask 0x0102001B, // OSC Error Mode 0x00040024, // TOD:FSM Register 0x00040027, // TOD: TX TType Ctrl reg 0x00040029, // TOD: RX TType Ctrl reg 0x00040030, // TOD: Error and Interrupts 0x00040032, // TOD: C_Err_Rpt 0x00040033, // TOD: Route Errors to Core/FIR // INTCQFIR c_err_rpt registers 0x05013038, // INT_CQ_WOF 0x05013039, // INT_CQ_ERROR_HOLD_OUT 0x0501303A, // INT_CQ_ERR_INFO0 0x0501303B, // INT_CQ_ERR_INFO1 0x0501303C, // INT_CQ_ERR_INFO2 0x0501303D, // INT_CQ_ERR_INFO3 0x05013142, // INT_PC_ERR0_WOF 0x05013143, // INT_PC_ERR0_WOF_DETAIL 0x05013144, // INT_PC_ERR0_FATAL 0x05013145, // INT_PC_ERR0_RECOV 0x05013146, // INT_PC_ERR0_INFO 0x0501314A, // INT_PC_ERR1_WOF 0x0501314B, // INT_PC_ERR1_WOF_DETAIL 0x0501314C, // INT_PC_ERR1_FATAL 0x0501314D, // INT_PC_ERR1_RECOV 0x0501314E, // INT_PC_ERR1_INFO 0x0501317A, // INT_PC_VPC_ERR1_WOF 0x0501317B, // INT_PC_VPC_ERR1_WOF_DETAIL 0x0501317C, // INT_PC_VPC_FATAL_ERR 0x0501317D, // INT_PC_VPC_RECOV_ERR 0x0501317E, // INT_PC_VPC_INFO_ERR 0x05013274, // INT_VC_WOF_ERR_G0 0x05013275, // INT_VC_WOF_ERR_G0_DETAIL 0x05013276, // INT_VC_WOF_ERR_G1 0x05013277, // INT_VC_WOF_ERR_G1_DETAIL 0x05013278, // INT_VC_FATAL_ERR_G0 0x05013279, // INT_VC_RECOV_ERR_G0 0x0501327A, // INT_VC_INFO_ERR_G0 0x0501327B, // INT_VC_FATAL_ERR_G1 0x0501327C, // INT_VC_RECOV_ERR_G1 0x0501327D, // INT_VC_INFO_ERR_G1 }; io_targMap[TRGT_EC][REG_GLBL] = { 0x20040000, // EC_CHIPLET_CS_FIR 0x20040001, // EC_CHIPLET_RE_FIR 0x20040018, // EC_CHIPLET_UCS_FIR }; io_targMap[TRGT_EC][REG_FIR] = { 0x2004000A, // EC_LFIR 0x20010A40, // COREFIR }; io_targMap[TRGT_EC][REG_REG] = { // Chiplet FIRs 0x20040002, // EC_CHIPLET_FIR_MASK 0x20040019, // EC_CHIPLET_UCS_FIR_MASK // Local FIRs 0x20010A48, // COREFIR_WOF (required for analysis) // PLL registers 0x200F001E, // EC_CONFIG_REG 0x200F001F, // EC_ERROR_REG // Misc 0x20010A96, // HOMER_ENABLE 0x20010A99, // SPEC_ATTN_REASON 0x20010A9A, // SPEC_ATTN_REASON_MASK // c_err_rpt registers 0x20010AB5, // SPR Core Error Report Hold Out Reg 0x20010AB6, // PMU Error Report Hold Out Register 0x20010AB7, // TFAC Error Report Hold Out Register 0x20010AB8, // SPR Common Error Report Hold Out Register 0x20010C00, // IFU Error Report Hold Out 0 Register 0x20010C01, // IFU Error Report Hold Out 1 Register 0x20010C02, // IFU Error Report Hold Out 2 Register 0x20010C03, // IFU Error Report Hold Out 3 Register 0x20010C40, // ISU error report hold_out register 0 0x20010C41, // ISU error report hold_out register 1 0x20010C42, // ISU error report hold_out register 2 0x20010C43, // ISU error report hold_out register 3 0x20010C44, // ISU error report hold_out register 4 0x20010C45, // ISU error report hold_out register 5 0x20010C80, // LSU error report hold_out register 0 0x20010C81, // LSU error report hold_out register 1 0x20010C82, // LSU error report hold_out register 2 0x20010C83, // LSU error report hold_out register 3 0x20010A51, // FIR/RECOV Error Report Hold Out Register 0x20010A03, // Thread Control Error Report Hold Out Register 0x200F0110, // PPM STOP_STATE_HIST_SRC_REG }; io_targMap[TRGT_EX][REG_FIR] = { 0x10010800, // L2FIR 0x10011000, // NCUFIR 0x10011800, // L3FIR 0x10012000, // CMEFIR }; io_targMap[TRGT_EX][REG_REG] = { // c_err_rpt registers 0x10010812, // ERROR REPORT REGISTER0 0x10010813, // ERROR REPORT REGISTER1 0x1001100E, // NCU error rpt register 0x1001180E, // L3 PRD Purge Register 0x10011810, // L3 Error Report Reg 0 0x10011817, // L3 Error Report Reg 1 0x10011819, // L3 eDRAM RD Err Stat Reg0 0x1001181A, // L3 eDRAM RD Err Stat Reg1 0x1001181B, // L3 Edram Bank Fail }; io_targMap[TRGT_NPU][REG_FIR] = { 0x05013C00, // NPU0FIR 0x05013C40, // NPU1FIR 0x05013C80, // NPU2FIR }; io_targMap[TRGT_NPU][REG_REG] = { // There are over 90 registers captured for NPU0FIR, but that is too // much for the limited space in the OP checkstop analysis design. The // hardware team agreed this was the minimum set of registers needed // for a checkstop. We have also been told most of these should have a // zero value so they should not take up too much space. 0x05011018, // NPU_S0_CS_SM0_CERR_1 0x05011019, // NPU_S0_CS_SM0_CERR_2 0x05011048, // NPU_S0_CS_SM1_CERR_1 0x05011049, // NPU_S0_CS_SM1_CERR_2 0x05011078, // NPU_S0_CS_SM2_CERR_1 0x05011079, // NPU_S0_CS_SM2_CERR_2 0x050110A8, // NPU_S0_CS_SM3_CERR_1 0x050110A9, // NPU_S0_CS_SM3_CERR_2 0x050110DB, // NPU_S0_CS_CTL_CERR_1 0x050110FA, // NPU_S0_DAT_CERR_LOG_HOLD 0x050110FD, // NPU_S0_DAT_REM0 0x050110FE, // NPU_S0_DAT_REM1 0x05011218, // NPU_S1_CS_SM0_CERR_1 0x05011219, // NPU_S1_CS_SM0_CERR_2 0x05011248, // NPU_S1_CS_SM1_CERR_1 0x05011249, // NPU_S1_CS_SM1_CERR_2 0x05011278, // NPU_S1_CS_SM2_CERR_1 0x05011279, // NPU_S1_CS_SM2_CERR_2 0x050112A8, // NPU_S1_CS_SM3_CERR_1 0x050112A9, // NPU_S1_CS_SM3_CERR_2 0x050112DB, // NPU_S1_CS_CTL_CERR_1 0x050112FA, // NPU_S1_DAT_CERR_LOG_HOLD 0x050112FD, // NPU_S1_DAT_REM0 0x050112FE, // NPU_S1_DAT_REM1 0x05011418, // NPU_S2_CS_SM0_CERR_1 0x05011419, // NPU_S2_CS_SM0_CERR_2 0x05011448, // NPU_S2_CS_SM1_CERR_1 0x05011449, // NPU_S2_CS_SM1_CERR_2 0x05011478, // NPU_S2_CS_SM2_CERR_1 0x05011479, // NPU_S2_CS_SM2_CERR_2 0x050114A8, // NPU_S2_CS_SM3_CERR_1 0x050114A9, // NPU_S2_CS_SM3_CERR_2 0x050114DB, // NPU_S2_CS_CTL_CERR_1 0x050114FA, // NPU_S2_DAT_CERR_LOG_HOLD 0x050114FD, // NPU_S2_DAT_REM0 0x050114FE, // NPU_S2_DAT_REM1 }; io_targMap[TRGT_MC][REG_GLBL] = { 0x07040000, // MC_CHIPLET_CS_FIR 0x07040001, // MC_CHIPLET_RE_FIR 0x07040018, // MC_CHIPLET_UCS_FIR }; io_targMap[TRGT_MC][REG_FIR] = { 0x07012300, // MCBISTFIR }; io_targMap[TRGT_MI][REG_FIR] = { 0x05010800, // MCFIR }; io_targMap[TRGT_MI][REG_REG] = { // c_err_rpt registers 0x0501081E, // MCERPT0 0x0501081F, // MCERPT1 0x0501081A, // MCERPT2 0x0501080A, // MCFGP 0x0501080C, // MCFGPM }; io_targMap[TRGT_MCC][REG_FIR] = { 0x07010900, // DSTLFIR 0x07010a00, // USTLFIR }; io_targMap[TRGT_OMIC][REG_FIR] = { 0x07011000, // IOOMIFIR 0x07012440, // MCPPEFIR 0x07013340, // OMIDLFIR }; io_targMap[TRGT_OMIC][REG_REG] = { 0x07013353, // DL0_ERROR_HOLD 0x07013363, // DL1_ERROR_HOLD 0x07013373, // DL2_ERROR_HOLD }; // EC level handling will be done with a // structure and separate register count field. } // end getAddresses //------------------------------------------------------------------------------ errlHndl_t getPnorInfo( HOMER_Data_t & o_data ) { #define FUNC "[PRDF::getPnorInfo] " errlHndl_t errl = NULL; //---------------------------------------------------------------------- // Get the PNOR information. //---------------------------------------------------------------------- do { PNOR::SectionInfo_t sectionInfo; errl = PNOR::getSectionInfo( PNOR::FIRDATA, sectionInfo ); if ( NULL != errl ) { PRDF_ERR( FUNC "getSectionInfo() failed" ); break; } PNOR::PnorInfo_t pnorInfo; PNOR::getPnorInfo( pnorInfo ); // Saving the flash workarounds in an attribute for when we // call getPnorInfo() in the runtime code. // Using sys target Target* sys = NULL; targetService().getTopLevelTarget( sys ); assert(sys != NULL); sys->setAttr(pnorInfo.norWorkarounds); o_data.pnorInfo.pnorOffset = sectionInfo.flashAddr; o_data.pnorInfo.pnorSize = sectionInfo.size; o_data.pnorInfo.mmioOffset = pnorInfo.mmioOffset; o_data.pnorInfo.norWorkarounds = pnorInfo.norWorkarounds; }while(0); return errl; #undef FUNC } //------------------------------------------------------------------------------ /* Helper struct for chip information inserted into HOMER data section after the * header. There is basically an array of these after the initial HOMER section * (HOMER_Data_t). The register info then follows. */ typedef struct __attribute__((packed)) { HOMER_Chip_t hChipType; /* Nimbus, Axone, EC Level, etc...*/ union { HOMER_ChipNimbus_t hChipN; HOMER_ChipAxone_t hChipA; }; } HOMER_ChipInfo_t; //------------------------------------------------------------------------------ void __initChipInfo( TargetHandle_t i_chip, HOMER_ChipType_t i_chipModel, uint32_t i_maxChipsPerNode, HOMER_ChipInfo_t & o_chipInfo ) { // Determine the chip position. uint32_t chipPos = getTargetPosition( i_chip ); PRDF_ASSERT( chipPos < i_maxChipsPerNode ); // Fill in the HOMER chip info. o_chipInfo.hChipType = HOMER_getChip( i_chipModel ); o_chipInfo.hChipType.chipPos = chipPos; o_chipInfo.hChipType.chipEcLevel = i_chip->getAttr(); if( HOMER_CHIP_EXPLORER == i_chipModel ) { //@todo - RTC:201781 - Add i2c information } else { // Get the chip FSI address. FSI::FsiLinkInfo_t fsiInfo; FSI::getFsiLinkInfo( i_chip, fsiInfo ); o_chipInfo.hChipType.fsiBaseAddr = fsiInfo.baseAddr; } } // Returns a right justified config mask of the unit uint32_t __getUnitMask( TargetHandle_t i_chip, TARGETING::TYPE i_unitType, const HwInitialized_t i_curHw ) { #define FUNC "[PRDF::__getUnitMask] " uint32_t o_mask = 0; uint32_t maxPos = 0; // default invalid if ( TYPE_PROC == getTargetType(i_chip) ) { switch ( i_unitType ) { case TYPE_CAPP: maxPos = TrgtPos_t::MAX_CAPP_PER_PROC; break; case TYPE_XBUS: maxPos = TrgtPos_t::MAX_XBUS_PER_PROC; break; case TYPE_OBUS: maxPos = TrgtPos_t::MAX_OBUS_PER_PROC; break; case TYPE_PEC: maxPos = TrgtPos_t::MAX_PEC_PER_PROC; break; case TYPE_PHB: maxPos = TrgtPos_t::MAX_PHB_PER_PROC; break; case TYPE_EQ: maxPos = TrgtPos_t::MAX_EQ_PER_PROC; break; case TYPE_EX: maxPos = TrgtPos_t::MAX_EX_PER_PROC; break; case TYPE_CORE: maxPos = TrgtPos_t::MAX_EC_PER_PROC; break; case TYPE_MCBIST: maxPos = TrgtPos_t::MAX_MCBIST_PER_PROC; break; case TYPE_MCS: maxPos = TrgtPos_t::MAX_MCS_PER_PROC; break; case TYPE_MCA: maxPos = TrgtPos_t::MAX_MCA_PER_PROC; break; case TYPE_MC: maxPos = TrgtPos_t::MAX_MC_PER_PROC; break; case TYPE_MI: maxPos = TrgtPos_t::MAX_MI_PER_PROC; break; case TYPE_MCC: maxPos = TrgtPos_t::MAX_MCC_PER_PROC; break; case TYPE_OMIC: maxPos = TrgtPos_t::MAX_OMIC_PER_PROC; break; case TYPE_NPU: maxPos = TrgtPos_t::MAX_NPU_PER_PROC; break; default: ; } } // If maxPos is still zero, then this function was passed invalid parameters if ( 0 == maxPos ) { PRDF_ERR( FUNC "Unsupported chip 0x%08x or unit type %u", getHuid(i_chip), i_unitType ); PRDF_ASSERT( false ); } // Get the unit list for this chip. TargetHandleList unitList = getConnected( i_chip, i_unitType ); // Initially this variable will be null. It will only be set to a non-null // value if the hardware config indicates we only want the master core. ConstTargetHandle_t masterCore = nullptr; // Special handling for specific configs. switch ( i_unitType ) { case TYPE_CORE: if ( MASTER_PROC_CORE == i_curHw || ALL_PROC_MASTER_CORE == i_curHw || ALL_PROC_MEM_MASTER_CORE == i_curHw ) { #ifndef __HOSTBOOT_RUNTIME // only supported during IPL masterCore = TARGETING::getMasterCore(); #endif PRDF_ASSERT( nullptr != masterCore ); } break; case TYPE_MCBIST: case TYPE_MCS: case TYPE_MCA: case TYPE_MC: case TYPE_MI: case TYPE_MCC: case TYPE_OMIC: if ( ALL_PROC_MEM_MASTER_CORE != i_curHw && ALL_HARDWARE != i_curHw ) { // Clear out the list because we don't want any memory units. unitList.clear(); } break; default: ; } // Get the config mask for all units of this type. for ( auto & unit : unitList ) { // Special handling for master-core-only configs. if ( nullptr != masterCore && unit != masterCore ) { // At this point, we only want the master core, but this is not it. // So continue onto the next target. continue; } uint32_t chipPos = getTargetPosition( unit ); PRDF_ASSERT( chipPos < maxPos ); o_mask |= (1 << (maxPos - chipPos - 1)); } return o_mask; #undef FUNC } //------------------------------------------------------------------------------ errlHndl_t getHwConfig( std::vector & o_chipInfVector, const HwInitialized_t i_curHw ) { #define FUNC "[PRDF::getHwConfig] " errlHndl_t errl = nullptr; o_chipInfVector.clear(); do { // Get the master PROC. This is used in several locations. TargetHandle_t masterProc = PlatServices::getMasterProc(); PRDF_ASSERT( nullptr != masterProc ); // Get the complete PROC list. TargetHandleList procList; if ( MASTER_PROC_CORE == i_curHw ) { // Get just the master PROC. procList.push_back( masterProc ); } else { // Get all configured PROCs. procList = getFunctionalTargetList( TYPE_PROC ); } // Iterate the list of functional PROCs. for ( auto & proc : procList ) { // Get the PROC model type. HOMER_ChipType_t procModelType = HOMER_CHIP_INVALID; switch ( getChipModel(proc) ) { case MODEL_NIMBUS: procModelType = HOMER_CHIP_NIMBUS; break; case MODEL_AXONE: procModelType = HOMER_CHIP_AXONE; break; default: PRDF_ERR( FUNC "Unsupported chip model %d on 0x%08x", procModelType, getHuid(proc) ); PRDF_ASSERT( false ); } // Init the chip info. HOMER_ChipInfo_t ci; __initChipInfo( proc, procModelType, MAX_PROC_PER_NODE, ci ); // Set the chip specific data. if ( HOMER_CHIP_NIMBUS == procModelType ) { // Init the chiplet masks ci.hChipN = HOMER_initChipNimbus(); // Check for master processor ci.hChipN.isMaster = (proc == masterProc) ? 1 : 0; // Set all of the unit masks. ci.hChipN.cappMask = __getUnitMask(proc, TYPE_CAPP, i_curHw); ci.hChipN.xbusMask = __getUnitMask(proc, TYPE_XBUS, i_curHw); ci.hChipN.obusMask = __getUnitMask(proc, TYPE_OBUS, i_curHw); ci.hChipN.pecMask = __getUnitMask(proc, TYPE_PEC, i_curHw); ci.hChipN.phbMask = __getUnitMask(proc, TYPE_PHB, i_curHw); ci.hChipN.eqMask = __getUnitMask(proc, TYPE_EQ, i_curHw); ci.hChipN.exMask = __getUnitMask(proc, TYPE_EX, i_curHw); ci.hChipN.ecMask = __getUnitMask(proc, TYPE_CORE, i_curHw); ci.hChipN.mcbistMask = __getUnitMask(proc, TYPE_MCBIST,i_curHw); ci.hChipN.mcsMask = __getUnitMask(proc, TYPE_MCS, i_curHw); ci.hChipN.mcaMask = __getUnitMask(proc, TYPE_MCA, i_curHw); } else if ( HOMER_CHIP_AXONE == procModelType ) { // Init the chiplet masks ci.hChipA = HOMER_initChipAxone(); // Check for master processor ci.hChipA.isMaster = (proc == masterProc) ? 1 : 0; // Set all of the unit masks. ci.hChipA.cappMask = __getUnitMask(proc, TYPE_CAPP, i_curHw); ci.hChipA.xbusMask = __getUnitMask(proc, TYPE_XBUS, i_curHw); ci.hChipA.obusMask = __getUnitMask(proc, TYPE_OBUS, i_curHw); ci.hChipA.pecMask = __getUnitMask(proc, TYPE_PEC, i_curHw); ci.hChipA.phbMask = __getUnitMask(proc, TYPE_PHB, i_curHw); ci.hChipA.eqMask = __getUnitMask(proc, TYPE_EQ, i_curHw); ci.hChipA.exMask = __getUnitMask(proc, TYPE_EX, i_curHw); ci.hChipA.ecMask = __getUnitMask(proc, TYPE_CORE, i_curHw); ci.hChipA.npuMask = __getUnitMask(proc, TYPE_NPU, i_curHw); ci.hChipA.mcMask = __getUnitMask(proc, TYPE_MC, i_curHw); ci.hChipA.miMask = __getUnitMask(proc, TYPE_MI, i_curHw); ci.hChipA.mccMask = __getUnitMask(proc, TYPE_MCC, i_curHw); ci.hChipA.omicMask = __getUnitMask(proc, TYPE_OMIC, i_curHw); } // Save the chip info we collected. o_chipInfVector.push_back( ci ); } // Only continue with the memory subsystem if the config allows. if ( ALL_PROC_MEM_MASTER_CORE != i_curHw && ALL_HARDWARE != i_curHw ) break; // Iterate all of the OCMB chips. for ( auto & ocmb : getFunctionalTargetList(TYPE_OCMB_CHIP) ) { // Get the OCMB chip type. HOMER_ChipType_t ocmbType = HOMER_CHIP_INVALID; switch ( getChipId(ocmb) ) { case POWER_CHIPID::GEMINI_16: // Skip Gemini OCMBs. They can exist, but PRD won't support // them (set invalid). ocmbType = HOMER_CHIP_INVALID; break; case POWER_CHIPID::EXPLORER_16: ocmbType = HOMER_CHIP_EXPLORER; break; default: PRDF_ERR( FUNC "Unsupported chip ID 0x%08x on 0x%08x", getChipId(ocmb), getHuid(ocmb) ); PRDF_ASSERT( false ); } if ( HOMER_CHIP_INVALID == ocmbType ) continue; // Init the chip info. HOMER_ChipInfo_t ci; __initChipInfo( ocmb, ocmbType, MAX_OCMB_PER_NODE, ci ); // NOTE: Explorer does not have any unit data. // Save the chip info we collected. o_chipInfVector.push_back( ci ); } } while (0); return errl; #undef FUNC } //------------------------------------------------------------------------------ /***************************************************/ /* Define EC level dependent registers here */ /* chipType Target RegType EC level */ /* Unused - scomAddress */ /***************************************************/ static HOMER_ChipSpecAddr_t s_ecDepProcRegisters[] { /* EXAMPLE: { HOMER_CHIP_NIMBUS, TRGT_PROC, REG_FIR, 0x10, 0, 0x05011400ll }, // DD1 { HOMER_CHIP_NIMBUS, TRGT_PROC, REG_FIR, 0x20, 0, 0x05013C00ll }, // DD2 */ }; //------------------------------------------------------------------------------ errlHndl_t homerVerifySizeFits( const size_t i_maxSize, const size_t i_currentSize ) { errlHndl_t l_errl = NULL; // Verify we haven't exceeded max size if ( i_currentSize > i_maxSize ) { PRDF_ERR( "HOMER SIZE issue: curDataSize %d is greater than max " "HOMER data %d", i_currentSize, i_maxSize ); /*@ * @errortype * @reasoncode PRDF_INVALID_CONFIG * @severity ERRL_SEV_UNRECOVERABLE * @moduleid PRDF_CS_FIRDATA_WRITE * @userdata1 Size needed * @userdata2 Size available * @devdesc Invalid configuration in CS FIR Data handling. */ l_errl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PRDF_CS_FIRDATA_WRITE, PRDF_INVALID_CONFIG, i_currentSize, i_maxSize ); } // end if too big of size return(l_errl); } // end routine homerVerifySizeFits //------------------------------------------------------------------------------ errlHndl_t writeData( uint8_t * i_hBuf, size_t i_hBufSize, const HwInitialized_t i_curHw, std::vector &i_chipVector, HOMER_Data_t &io_homerData ) { #define FUNC "[PRDF::writeData] " errlHndl_t errl = NULL; TrgtMap_t l_targMap; const size_t u32 = sizeof(uint32_t); const size_t u64 = sizeof(uint64_t); do { size_t sz_hBuf = 0; // Grab size of all the registers being collected size_t sz_data = sizeof(io_homerData); sz_hBuf += sz_data; // The HOMER_Data_t struct may have an uneven size. Add some padding to // ensure the subsequent HOMER_Chip_t structs are word aligned. */ const size_t padding = (u32 - (sizeof(HOMER_Data_t) % u32)) % u32; sz_hBuf += padding; // Add register counts to the data. // initialize SCOM addresses for all targets & regs getAddresses(l_targMap); // loop thru targets to get register counts for ( auto & t : l_targMap ) { // loop thru register types for ( auto & r : t.second ) { // Want all proc chiplets but only include // memory when asked for if ( (ALL_PROC_MEM_MASTER_CORE == i_curHw) || (ALL_HARDWARE == i_curHw) || ( (TRGT_MCBIST != t.first) && (TRGT_MCS != t.first) && (TRGT_MCA != t.first) && (TRGT_MC != t.first) && (TRGT_MI != t.first) && (TRGT_MCC != t.first) && (TRGT_OMIC != t.first) ) ) { // save the number of regs for target/regType io_homerData.regCounts[t.first][r.first] = r.second.size(); } // end if need this target included } // end for on regTypes } // end for on Targets // Setup EC level dependent register counts // (currently just proc has some) io_homerData.ecDepCounts = sizeof(s_ecDepProcRegisters) / sizeof(HOMER_ChipSpecAddr_t); // Add everything to the buffer. uint32_t idx = 0; // Fill in the header & number of chips io_homerData.header = HOMER_FIR2; io_homerData.chipCount = i_chipVector.size(); // Fill the input buffer with chipcount, regcount, pnor info memcpy( &i_hBuf[idx], &io_homerData, sz_data ); idx += sz_data; // Add the padding at the end of the HOMER_Data_t struct. idx += padding; // We want a list of chips next if (0 != io_homerData.chipCount) { // Roll thru the chips we have std::vector::iterator l_chipItr; uint32_t l_chipTypeSize = sizeof(HOMER_Chip_t); for ( l_chipItr = i_chipVector.begin(); (l_chipItr < i_chipVector.end()); l_chipItr++ ) { // Ensure we won't copy beyond space allowed sz_hBuf += l_chipTypeSize; errl = homerVerifySizeFits(i_hBufSize, sz_hBuf); if (NULL != errl) { break; } // place the CHIP information memcpy( &i_hBuf[idx], &(l_chipItr->hChipType), l_chipTypeSize ); idx += l_chipTypeSize; // Place the configured chiplet information. if ( HOMER_CHIP_NIMBUS == l_chipItr->hChipType.chipType ) { // Ensure we won't copy beyond space allowed sz_hBuf += sizeof(HOMER_ChipNimbus_t); errl = homerVerifySizeFits(i_hBufSize, sz_hBuf); if (NULL != errl) { break; } memcpy( &i_hBuf[idx], &(l_chipItr->hChipN), sizeof(HOMER_ChipNimbus_t) ); idx += sizeof(HOMER_ChipNimbus_t); } else if ( HOMER_CHIP_AXONE == l_chipItr->hChipType.chipType ) { // Ensure we won't copy beyond space allowed sz_hBuf += sizeof(HOMER_ChipAxone_t); errl = homerVerifySizeFits(i_hBufSize, sz_hBuf); if (NULL != errl) { break; } memcpy( &i_hBuf[idx], &(l_chipItr->hChipA), sizeof(HOMER_ChipAxone_t) ); idx += sizeof(HOMER_ChipAxone_t); } else if ( HOMER_CHIP_EXPLORER == l_chipItr->hChipType.chipType ) { // NOTE: Explorer does not have any unit data. } } // end for loop on chip vector // ensure size is ok before any other copy if (NULL != errl) { break; } // Verify registers will fit before copying them uint32_t l_reg32Count = 0; uint32_t l_reg64Count = 0; // Count number of 32 bit addresses first for ( uint32_t l_regIdx = REG_FIRST; (l_regIdx < REG_IDFIR); l_regIdx++ ) { for ( uint32_t l_tgtIndex = TRGT_FIRST; (l_tgtIndex < TRGT_MAX); l_tgtIndex++ ) { l_reg32Count +=io_homerData.regCounts[l_tgtIndex][l_regIdx]; } // end for on target index } // end for on register index // Count number of 64 bit addresses now for ( uint32_t l_regIdx = REG_IDFIR; (l_regIdx < REG_MAX); l_regIdx++ ) { for ( uint32_t l_tgtIndex = TRGT_FIRST; (l_tgtIndex < TRGT_MAX); l_tgtIndex++ ) { l_reg64Count +=io_homerData.regCounts[l_tgtIndex][l_regIdx]; } // end for on target index } // end for on register index // Calculate additional size we need from the counts. // We have 32 bit addrs, 64 bit addrs, then EC level structures. sz_hBuf +=(l_reg32Count * sizeof(uint32_t)) + (l_reg64Count * sizeof(uint64_t)) + (io_homerData.ecDepCounts * sizeof(HOMER_ChipSpecAddr_t)); // ensure we fit in HOMER before doing register copies errl = homerVerifySizeFits(i_hBufSize, sz_hBuf); if (NULL != errl) { break; } // loop thru targets for ( auto & t : l_targMap ) { if ( (ALL_PROC_MEM_MASTER_CORE == i_curHw) || (ALL_HARDWARE == i_curHw) || ( (TRGT_MCBIST != t.first) && (TRGT_MCS != t.first) && (TRGT_MCA != t.first) && (TRGT_MC != t.first) && (TRGT_MI != t.first) && (TRGT_MCC != t.first) && (TRGT_OMIC != t.first) ) ) { // loop thru register types for ( auto & r : t.second ) { // loop thru SCOM addresses for reg type for ( auto & rAddr : r.second ) { if ( (REG_IDFIR == r.first) || (REG_IDREG == r.first) ) { memcpy( &i_hBuf[idx], &rAddr, u64 ); idx += u64; } else { uint32_t tempAddr = (uint32_t)rAddr; memcpy( &i_hBuf[idx], &tempAddr, u32 ); idx += u32; } } // end for on register addresses } // end for on regs } // end if we need this target } // end for on targets // Add EC Level dependencies at the end uint8_t *l_ecDepSourceRegs = (uint8_t *)(s_ecDepProcRegisters); memcpy( &i_hBuf[idx], l_ecDepSourceRegs, sizeof(s_ecDepProcRegisters) ); } // end if chipCount non-zero } while(0); return errl; #undef FUNC } //------------------------------------------------------------------------------ errlHndl_t writeHomerFirData( uint8_t * i_hBuf, size_t i_hBufSize, const HwInitialized_t i_curHw ) { #define FUNC "[PRDF::writeHomerFirData] " errlHndl_t errl = NULL; do { // FIRDATA not supported on Cumulus based systems. So do nothing. if ( MODEL_CUMULUS == getChipModel(getMasterProc()) ) break; HOMER_Data_t l_homerData = HOMER_getData(); // Initializes data // Set flag indicating if IPL or runtime situation. l_homerData.iplState = (ALL_HARDWARE == i_curHw) ? FIRDATA_STATE_RUNTIME : FIRDATA_STATE_IPL; // Get the PNOR information errl = getPnorInfo( l_homerData ); if ( NULL != errl ) { PRDF_ERR( FUNC "getPnorInfo() failed" ); break; } // Hardware present gets pushed into this vector // (one element per chip) std::vector l_chipInfVector; // Get the hardware configuration errl = getHwConfig( l_chipInfVector, i_curHw ); if ( NULL != errl ) { PRDF_ERR( FUNC "getHwConfig() failed" ); break; } // Write the HOMER data errl = writeData( i_hBuf, i_hBufSize, i_curHw, l_chipInfVector, l_homerData ); if ( NULL != errl ) { PRDF_ERR( FUNC "writeData() failed" ); break; } } while (0); if ( NULL != errl ) { errl->collectTrace( PRDF_COMP_NAME, 512 ); } return errl; #undef FUNC } }; // end namespace PRDF