diff options
author | Benjamin Weisenbeck <bweisenb@us.ibm.com> | 2017-08-23 09:49:12 -0500 |
---|---|---|
committer | Zane C Shelley <zshelle@us.ibm.com> | 2018-02-01 10:52:48 -0500 |
commit | 056c43ed3e5af0977354f80bc313245e65cc4a04 (patch) | |
tree | b7e839bececf6727a4b3895a832de970fc1f6df1 | |
parent | eb4da4cd0830932f4c662eeff7facaaecd4d54d2 (diff) | |
download | talos-hostboot-056c43ed3e5af0977354f80bc313245e65cc4a04.tar.gz talos-hostboot-056c43ed3e5af0977354f80bc313245e65cc4a04.zip |
PRD: Dynamic Memory Deallocation
Change-Id: I4c954b81fa77f7000d6ec4ebbcf51eb19ffc3be9
RTC: 153855
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/48029
Reviewed-by: Zane C. Shelley <zshelle@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/53017
Reviewed-by: Zane C Shelley <zshelle@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
-rw-r--r-- | src/usr/diag/prdf/common/plat/mem/prdfMemAddress.C | 3 | ||||
-rw-r--r-- | src/usr/diag/prdf/common/plat/mem/prdfMemAddress.H | 4 | ||||
-rw-r--r-- | src/usr/diag/prdf/common/plat/p9/p9_mcs_regs.rule | 21 | ||||
-rwxr-xr-x | src/usr/diag/prdf/common/plat/prdfTargetServices.C | 16 | ||||
-rwxr-xr-x | src/usr/diag/prdf/common/plat/prdfTargetServices.H | 7 | ||||
-rw-r--r-- | src/usr/diag/prdf/plat/mem/prdfMemDynDealloc.C | 799 | ||||
-rw-r--r-- | src/usr/diag/prdf/plat/mem/prdfMemDynDealloc.H | 95 | ||||
-rw-r--r-- | src/usr/diag/prdf/plat/mem/prdf_plat_mem_hb_only.mk | 3 | ||||
-rw-r--r-- | src/usr/diag/prdf/plat/prdfPlatServices_rt.C | 37 | ||||
-rw-r--r-- | src/usr/diag/prdf/plat/prdfPlatServices_rt.H | 25 |
10 files changed, 985 insertions, 25 deletions
diff --git a/src/usr/diag/prdf/common/plat/mem/prdfMemAddress.C b/src/usr/diag/prdf/common/plat/mem/prdfMemAddress.C index 8abd09515..0f7eb2b0a 100644 --- a/src/usr/diag/prdf/common/plat/mem/prdfMemAddress.C +++ b/src/usr/diag/prdf/common/plat/mem/prdfMemAddress.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -28,6 +28,7 @@ * registers for Centaur MBA and P9 MCBIST/MCA. */ +#include <prdfPlatServices.H> #include <prdfMemAddress.H> // Framework includes diff --git a/src/usr/diag/prdf/common/plat/mem/prdfMemAddress.H b/src/usr/diag/prdf/common/plat/mem/prdfMemAddress.H index 4d4e0ee2b..788b0da43 100644 --- a/src/usr/diag/prdf/common/plat/mem/prdfMemAddress.H +++ b/src/usr/diag/prdf/common/plat/mem/prdfMemAddress.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -33,7 +33,7 @@ // Platform includes #include <prdfMemRank.H> -#include <prdfPlatServices.H> +#include <prdfTargetServices.H> // External includes #include <vector> diff --git a/src/usr/diag/prdf/common/plat/p9/p9_mcs_regs.rule b/src/usr/diag/prdf/common/plat/p9/p9_mcs_regs.rule index dc35a0a64..339cfb9da 100644 --- a/src/usr/diag/prdf/common/plat/p9/p9_mcs_regs.rule +++ b/src/usr/diag/prdf/common/plat/p9/p9_mcs_regs.rule @@ -5,7 +5,7 @@ # # OpenPOWER HostBoot Project # -# Contributors Listed Below - COPYRIGHT 2017 +# Contributors Listed Below - COPYRIGHT 2017,2018 # [+] International Business Machines Corp. # # @@ -28,6 +28,23 @@ ################################################################################ ############################################################################ + # Address Translation Registers + ############################################################################ + register MC_ADDR_TRANS_0 + { + name "P9 MCS target address translation register 0"; + scomaddr 0x05010820; + capture group default; + }; + + register MC_ADDR_TRANS_1 + { + name "P9 MCS target address translation register 1"; + scomaddr 0x05010830; + capture group default; + }; + + ############################################################################ # P9 MCS target HDCT additions (open power chkstop analysis) ############################################################################ @@ -52,7 +69,7 @@ capture group default; }; - register MEMCFG_REG + register MCFGP { name "P9 MCS target MEMCFG REG"; scomaddr 0x0501080a; diff --git a/src/usr/diag/prdf/common/plat/prdfTargetServices.C b/src/usr/diag/prdf/common/plat/prdfTargetServices.C index 52a762b14..40a15cae8 100755 --- a/src/usr/diag/prdf/common/plat/prdfTargetServices.C +++ b/src/usr/diag/prdf/common/plat/prdfTargetServices.C @@ -1261,9 +1261,21 @@ int32_t getMbaPort( TARGETING::TargetHandle_t i_dimmTarget, uint8_t & o_port ) //------------------------------------------------------------------------------ -int32_t getMbaDimm( TARGETING::TargetHandle_t i_dimmTarget, uint8_t & o_dimm ) +template<> +int32_t getDimmSlct<TYPE_MBA>( TARGETING::TargetHandle_t i_dimmTarget, + uint8_t & o_dimm ) +{ + o_dimm = i_dimmTarget->getAttr<ATTR_MBA_DIMM>(); + return SUCCESS; +} + +template<> +int32_t getDimmSlct<TYPE_MCA>( TARGETING::TargetHandle_t i_dimmTarget, + uint8_t & o_dimm ) { - return i_dimmTarget->tryGetAttr<ATTR_MBA_DIMM>(o_dimm) ? SUCCESS : FAIL; + o_dimm = i_dimmTarget->getAttr<TARGETING::ATTR_FAPI_POS>() % + MAX_DIMM_PER_PORT; + return SUCCESS; } //------------------------------------------------------------------------------ diff --git a/src/usr/diag/prdf/common/plat/prdfTargetServices.H b/src/usr/diag/prdf/common/plat/prdfTargetServices.H index e0df471a2..4821ae885 100755 --- a/src/usr/diag/prdf/common/plat/prdfTargetServices.H +++ b/src/usr/diag/prdf/common/plat/prdfTargetServices.H @@ -372,12 +372,13 @@ int32_t getMbaPort( TARGETING::TargetHandle_t i_dimmTarget, uint8_t & o_port ); /** - * @brief Obtain the MBA Dimm select for the given Dimm. + * @brief Obtain the Dimm select for the given Dimm. * @param i_dimmTarget Dimm. - * @param o_dimm MBA Dimm select. + * @param o_dimm Dimm select. * @return Non-SUCCESS if internal functions fail, SUCCESS otherwise. */ -int32_t getMbaDimm( TARGETING::TargetHandle_t i_dimmTarget, uint8_t & o_dimm ); +template<TARGETING::TYPE T> +int32_t getDimmSlct( TARGETING::TargetHandle_t i_dimmTarget, uint8_t & o_dimm ); /** * @brief checks dram widh ( x4 ) for mba diff --git a/src/usr/diag/prdf/plat/mem/prdfMemDynDealloc.C b/src/usr/diag/prdf/plat/mem/prdfMemDynDealloc.C new file mode 100644 index 000000000..cb3a25a8c --- /dev/null +++ b/src/usr/diag/prdf/plat/mem/prdfMemDynDealloc.C @@ -0,0 +1,799 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/diag/prdf/plat/mem/prdfMemDynDealloc.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017,2018 */ +/* [+] 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 */ +//------------------------------------------------------------------------------ +// Includes +//------------------------------------------------------------------------------ + +#include <iipSystem.h> +#include <prdfGlobal_common.H> +#include <prdfExtensibleChip.H> +#include <prdfMemDynDealloc.H> +#include <prdfTrace.H> +#include <prdfPlatServices.H> +#include <prdfMemAddress.H> + +//------------------------------------------------------------------------------ +// Function Definitions +//------------------------------------------------------------------------------ + +using namespace TARGETING; + +namespace PRDF +{ +using namespace PlatServices; + +namespace MemDealloc +{ + +bool isEnabled() +{ + return ( isHyprRunning() && (isHyprConfigPhyp() || isHyprConfigOpal()) && + !isMfgAvpEnabled() && !isMfgHdatAvpEnabled() ); +} + +int32_t getRowsAndIntrlv( ExtensibleChip * i_chip, uint8_t i_dslct, + uint8_t &o_rows, bool &o_interleaved) +{ + int32_t o_rc = SUCCESS; + o_rows = 0; + o_interleaved = false; + + uint32_t mcaPos = i_chip->getPos() % MAX_MCA_PER_MCS; + + ExtensibleChip * mcs_chip = getConnectedParent( i_chip, TYPE_MCS ); + + SCAN_COMM_REGISTER_CLASS * addrTransReg = mcs_chip->getRegister( + (mcaPos == 0) ? "MC_ADDR_TRANS_0" : "MC_ADDR_TRANS_1"); + + o_rc = addrTransReg->Read(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR("getRows Read failed on addrTransReg: chip=0x%08x", + i_chip->getHuid() ); + return o_rc; + } + + if (addrTransReg->IsBitSet(i_dslct ? 31:15)) + o_rows = 18; + else if (addrTransReg->IsBitSet(i_dslct ? 30:14)) + o_rows = 17; + else if (addrTransReg->IsBitSet(i_dslct ? 29:13)) + o_rows = 16; + else + o_rows = 15; + + if ( addrTransReg->IsBitSet(0) && addrTransReg->IsBitSet(16)) + o_interleaved = true; + + return o_rc; +} + +void setRemainingRowBitsAndDimmSelect(uint8_t i_bit, //bit position in o_addr + uint64_t i_row, //row value from MemAddr + uint8_t i_numRows, //# of row bits + uint64_t i_dsclt, // dimm select + uint64_t &o_addr) // system address +{ + // Write bits R15..R17 followed by dimm select bit + uint8_t rowBit = 15; + while ( i_bit >= 0 && rowBit <= i_numRows ) + { + if (i_numRows == rowBit) + { + // We've finished writing row bits, now write the dimm select + // and we're done + o_addr |= (i_dsclt << (63-i_bit)); + break;; + } + else + { + // Set i_bit to rowBit + o_addr |= (((i_row >> (17-rowBit)) & 0x1) << (63-i_bit)); + ++rowBit; + --i_bit; + } + } + return; +} + +int32_t getMcaPortAddr( ExtensibleChip * i_chip, MemAddr i_addr, + uint64_t & o_addr ) +{ + #define PRDF_FUNC "[MemDealloc::getMcaPortAddr] " + + int32_t o_rc = SUCCESS; + o_addr = 0; + TargetHandle_t tgt = i_chip->GetChipHandle(); + MemRank rnk = i_addr.getRank(); + + // Local vars for address fields + uint64_t col = i_addr.getCol(); // C3 C4 C5 C6 C7 C8 C9 + uint64_t row = i_addr.getRow(); // R0 R1 R2 .. R16 R17 + uint64_t bnk = i_addr.getBank(); // BG0 BG1 B0 B1 B2 + uint64_t srnk = rnk.getSlave(); // S0 S1 S2 + uint64_t mrnk = rnk.getRankSlct(); // M0 M1 + uint64_t dslct = rnk.getDimmSlct(); // 1 bit + + // number of masters and slaves per dimm + uint8_t mstrs = getNumMasterRanksPerDimm<TYPE_MCA>(tgt, dslct); + uint8_t slvs = getNumRanksPerDimm<TYPE_MCA>(tgt, dslct) / mstrs; + + uint8_t rowBits = 0; // Number of row bits used for an addr on this dimm + bool interleaved = false; // Whether dimm slot interleaving is used + o_rc = getRowsAndIntrlv( i_chip, dslct, rowBits, interleaved); + if (o_rc != SUCCESS) + return o_rc; + + // If we're not using 2 dimm slots, the DS bit should always be set to 0 + if (!interleaved) + dslct = 0; + + // Set Bits 33-0 + do { + // Bits 33-30 are common to all configs + // Set bit 33 to C3 + o_addr |= ((col & 0x40) << 24); + // Set bits 31 32 to BG0 BG1 + o_addr |= ((bnk & 0x18) << 28); + // Set bit 30 to B1 + o_addr |= ((bnk & 0x02) << 32); + + // Bit 29 + if ( slvs != 0 ) + { + // Set bit 29 to S2 + o_addr |= ((srnk & 0x01) << 34); + } + else if (mstrs > 1) + { + // Set bit 29 to M1 + o_addr |= ((mrnk & 0x01) << 34); + } + else if (interleaved) + { + // Set bit 29 to D + o_addr |= (dslct << 34); + } + else + { + // Set bit 29 to B0 + o_addr |= ((bnk & 0x04) << 32); + } + + //Bits 28-23 + if ( mstrs == 1 && slvs == 0 && !interleaved ) + { + // Set Bit 28 to C4 + o_addr |= ((col & 0x20) << 30); + // Set bits 23-27 to C9-C5 + o_addr |= ((col & 0x10) << 32); + o_addr |= ((col & 0x08) << 34); + o_addr |= ((col & 0x04) << 36); + o_addr |= ((col & 0x02) << 38); + o_addr |= ((col & 0x01) << 40); + } + else + { + // Set Bit 28 to B0 + o_addr |= ((bnk & 0x04) << 33); + // Set bits 23-27 to C8-C4 + o_addr |= ((col & 0x20) << 31); + o_addr |= ((col & 0x10) << 33); + o_addr |= ((col & 0x08) << 35); + o_addr |= ((col & 0x04) << 37); + o_addr |= ((col & 0x02) << 39); + } + + // Bits 22-8 + o_addr |= ((row & 0x00010) << 37); // R13 -> bit 22 + o_addr |= ((row & 0x20000) << 25); // R0 -> bit 21 + o_addr |= ((row & 0x10000) << 27); // R1 -> bit 20 + o_addr |= ((row & 0x08000) << 29); // R2 -> bit 19 + o_addr |= ((row & 0x04000) << 31); // R3 -> bit 18 + o_addr |= ((row & 0x02000) << 33); // R4 -> bit 17 + o_addr |= ((row & 0x01000) << 35); // R5 -> bit 16 + o_addr |= ((row & 0x00800) << 37); // R6 -> bit 15 + o_addr |= ((row & 0x00400) << 39); // R7 -> bit 14 + o_addr |= ((row & 0x00200) << 41); // R8 -> bit 13 + o_addr |= ((row & 0x00100) << 43); // R9 -> bit 12 + o_addr |= ((row & 0x00080) << 45); // R10 -> bit 11 + o_addr |= ((row & 0x00040) << 47); // R11 -> bit 10 + o_addr |= ((row & 0x00020) << 49); // R12 -> bit 9 + o_addr |= ((row & 0x00008) << 52); // R14 -> bit 8 + + // Bit 7 + if ( mstrs == 1 && slvs == 0 && !interleaved ) + { + // Set remaining row bits starting at bit 7 + setRemainingRowBitsAndDimmSelect(7, row, rowBits, dslct, o_addr); + break; + } + else + { + // Set bit 7 to C9 + o_addr |= ((col & 0x01) << 56); + } + + // Bit 6... + if (slvs >= 4) + { + // set bit 6 to S1 + o_addr |= ((srnk & 0x02) << 56); + } + else if (mstrs == 4 && slvs==0) + { + // set Bit 6 to M0 + o_addr |= ((mrnk & 0x02) << 56); + } + else if (mstrs == 2 && slvs == 2) + { + // Set Bit 6 to M1 + o_addr |= ((mrnk & 0x01) << 57); + } + else + { + // Set remaining bits starting at 6 + setRemainingRowBitsAndDimmSelect(6, row, rowBits, dslct, o_addr); + break; + } + + // Bit 5 + if (slvs >= 8) + { + // Set bit 5 to S0 + o_addr |= ((srnk & 0x04) << 56); + } + else if (mstrs == 2 && slvs == 4) + { + // Set bit 5 to M1 + o_addr |= ((mrnk & 0x01) << 58); + } + else + { + setRemainingRowBitsAndDimmSelect(5, row, rowBits, dslct, o_addr); + break; + } + + // Bit 4 + if (mstrs == 2 && slvs == 8) + { + // Set bit 4 to M1 + o_addr |= ((mrnk & 0x01) << 59); + + // Set remaining row bits + setRemainingRowBitsAndDimmSelect(3, row, rowBits, dslct, o_addr); + break; + } + else + { + setRemainingRowBitsAndDimmSelect(4, row, rowBits, dslct, o_addr); + break; + } + + } while (0); + + return o_rc; + #undef PRDF_FUNC +} + +template<TYPE T> +int32_t getSystemAddr( ExtensibleChip * i_chip, MemAddr i_addr, + uint64_t & o_addr ); +template<> +int32_t getSystemAddr<TYPE_MBA>( ExtensibleChip * i_chip, MemAddr i_addr, + uint64_t & o_addr ) +{ + // TODO - RTC: 157588 + return SUCCESS; +} + +template<> +int32_t getSystemAddr<TYPE_MCA>( ExtensibleChip * i_chip, MemAddr i_addr, + uint64_t & o_addr ) +{ + #define PRDF_FUNC "[MemDealloc::getSystemAddr] " + + int32_t l_rc = SUCCESS; + + do { + // Get 40-bit MCA Port address + l_rc = getMcaPortAddr( i_chip, i_addr, o_addr); + if (l_rc) break; + + // Construct the 56-bit Powerbus address + + // Shift the 40 bit port address in bits 0:39 over to bits 24:63 + o_addr = o_addr >> 24; + + // Get MCA target position + ExtensibleChip * mcs_chip = getConnectedParent( i_chip, TYPE_MCS ); + uint8_t mcaPos = i_chip->getPos() % MAX_MCA_PER_MCS; + + SCAN_COMM_REGISTER_CLASS * mcfgp = mcs_chip->getRegister("MCFGP"); + SCAN_COMM_REGISTER_CLASS * mcfgpm = mcs_chip->getRegister("MCFGPM"); + l_rc = mcfgp->Read(); if (l_rc) break; + l_rc = mcfgpm->Read(); if (l_rc) break; + + // Get the MCS per group + uint8_t mcsPerGrp = mcfgp->GetBitFieldJustified( 1,4 ); + // mcs position / group member id from mcfgp[5:7 or 8:10] + uint8_t mcGrpSel = mcfgp->GetBitFieldJustified( (mcaPos==0) ? 5 : 8, 3); + uint64_t upper33 = o_addr & 0xFFFFFFFF80ull; + uint64_t lower7 = o_addr & 0x000000007full; + uint64_t bar = 0; + + if (mcaPos == 0) // Channel 0 + { + switch (mcsPerGrp) + { + case 0: + case 1: + // 1 MCS per group -- no shift needed + break; + case 4: + case 5: + // 2 MCS per group + // shift physical addr by 1 and set bit 56 to group sel + o_addr = (upper33 << 1) | ((mcGrpSel & 0x1) << 7) | lower7; + break; + case 6: + // 4 MCS per group + // shift physical addr by 2 and set bit 55:56 to group sel + o_addr = (upper33 << 2) | ((mcGrpSel & 0x3) << 7) | lower7; + break; + case 8: + // 8 MCS per group + // shift physical addr by 3 and set bit 54:56 to group sel + o_addr = (upper33 << 3) | ((mcGrpSel & 0x7) << 7) | lower7; + break; + case 2: + case 3: + // 3 MCS per group + // May not be a supported config + case 7: + // 6 MCS per group + // May not be a supported config + default: + // Unsupported MCS per group config + PRDF_ERR( PRDF_FUNC + "Invalid MCS per group value: %x on HUID:0x%08X", + mcsPerGrp, i_chip->GetId() ); + return FAIL; + break; + } + + // Get BAR from MCFGP + bar = mcfgp->GetBitFieldJustified(24, 24); + o_addr |= (bar << 32); + } + else // Channel 1 + { + switch (mcsPerGrp) + { + case 0: + case 2: + // 1 MCS per group -- no shift needed + + // Get BAR from MCFGPM + bar = mcfgpm->GetBitFieldJustified(24, 24); + break; + case 4: + // 2 MCS per group + // shift physical addr by 1 and set bit 56 to group sel + o_addr = (upper33 << 1) | ((mcGrpSel & 0x1) << 7) | lower7; + + // Get BAR from MCFGPM + bar = mcfgpm->GetBitFieldJustified(24, 24); + break; + case 5: + // 2 MCS per group + // shift physical addr by 1 and set bit 56 to group sel + o_addr = (upper33 << 1) | ((mcGrpSel & 0x1) << 7) | lower7; + + // Get BAR from MCFGPM + bar = mcfgp->GetBitFieldJustified(24, 24); + break; + case 6: + // 4 MCS per group + // shift physical addr by 2 and set bit 55:56 to group sel + o_addr = (upper33 << 2) | ((mcGrpSel & 0x3) << 7) | lower7; + + // Get BAR from MCFGP + bar = mcfgp->GetBitFieldJustified(24, 24); + break; + case 8: + // 8 MCS per group + // shift physical addr by 3 and set bit 54:56 to group sel + o_addr = (upper33 << 3) | ((mcGrpSel & 0x7) << 7) | lower7; + + // Get BAR from MCFGP + bar = mcfgp->GetBitFieldJustified(24, 24); + break; + case 1: + case 3: + // 3 MCS per group + // May not be a supported config + + // Get BAR from MCFGPM + case 7: + // 6 MCS per group + // May not be a supported config + + // Get BAR from MCFGP + default: + // Unsupported MCS per group config + PRDF_ERR( PRDF_FUNC + "Invalid MCS per group value: %x on HUID:0x%08X", + mcsPerGrp, i_chip->GetId() ); + return FAIL; + break; + } + + // Insert BAR + o_addr |= (bar << 32); + + } // Channel 1 + + } while (0); + + return l_rc; + #undef PRDF_FUNC +} + + +template<TYPE T> +int32_t page( ExtensibleChip * i_chip, MemAddr i_addr ) +{ + #define PRDF_FUNC "[MemDealloc::page] " + + uint64_t sysAddr = 0; + int32_t o_rc = SUCCESS; + do + { + if ( !isEnabled() ) break; // nothing to do + + o_rc = getSystemAddr<T>( i_chip, i_addr, sysAddr); + if( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "getSystemAddr() failed. HUID:0x%08X", + i_chip->GetId() ); + break; + } + + sendPageGardRequest( sysAddr ); + PRDF_TRAC( PRDF_FUNC "Page dealloc address: 0x%016llX", sysAddr ); + + } while( 0 ); + + return o_rc; + #undef PRDF_FUNC +} + +template<TYPE T> +int32_t rank( ExtensibleChip * i_chip, MemRank i_rank ) +{ + #define PRDF_FUNC "[MemDealloc::rank] " + + int32_t o_rc = SUCCESS; + do + { + MemAddr startAddr, endAddr; + TargetHandle_t tgt = i_chip->GetChipHandle(); + o_rc = getMemAddrRange( tgt, i_rank.getRankSlct(), i_rank.getDimmSlct(), + startAddr, endAddr ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "getMemAddrRange() Failed. HUID:0x%08X", + i_chip->GetId() ); + break; + } + + // Get the system addresses + uint64_t ssAddr = 0; + uint64_t seAddr = 0; + o_rc = getSystemAddr<T>( i_chip, startAddr, ssAddr); + o_rc |= getSystemAddr<T>( i_chip, endAddr, seAddr ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "getSystemAddr() failed. HUID:0x%08X", + i_chip->GetId() ); + break; + } + // Send the address range to HV + sendDynMemDeallocRequest( ssAddr, seAddr ); + PRDF_TRAC( PRDF_FUNC "Rank dealloc for Start Addr: 0x%016llx " + "End Addr: 0x%016llX", ssAddr, seAddr ); + + } while( 0 ); + + return o_rc; + #undef PRDF_FUNC +} + +template<TYPE T> +int32_t port( ExtensibleChip * i_chip ) +{ + #define PRDF_FUNC "[MemDealloc::port] " + int32_t o_rc = SUCCESS; + + do + { + if ( !isEnabled() ) break; // nothing to do + + TargetHandle_t tgt = i_chip->GetChipHandle(); + + // Find the largest address range + uint64_t smallestAddr = 0xffffffffffffffffll; + uint64_t largestAddr = 0; + uint64_t ssAddr = 0; + uint64_t seAddr = 0; + MemAddr startAddr, endAddr; + std::vector<MemRank> masterRanks; + + // Get Master ranks + getMasterRanks<T>( tgt, masterRanks); + + // Iterate all ranks to get start and end address. + for ( std::vector<MemRank>::iterator it = masterRanks.begin(); + it != masterRanks.end(); it++ ) + { + o_rc = getMemAddrRange( tgt, it->getRankSlct(), + it->getDimmSlct(), + startAddr, endAddr ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "getMemAddrRange() Failed. HUID:0x%08X", + i_chip->GetId() ); + break; + } + + // Get the system addresses + o_rc = getSystemAddr<T>( i_chip, startAddr, ssAddr); + o_rc |= getSystemAddr<T>( i_chip, endAddr, seAddr ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "getSystemAddr() failed. HUID:0x%08X", + i_chip->GetId() ); + break; + } + if ( ssAddr < smallestAddr ) smallestAddr = ssAddr; + if ( seAddr > largestAddr ) largestAddr = seAddr; + } + if( SUCCESS != o_rc ) break; + + // Send the address range to PHYP + sendDynMemDeallocRequest( ssAddr, seAddr ); + PRDF_TRAC( PRDF_FUNC "MBA dealloc for Start Addr: 0x%016llx " + "End Addr: 0x%016llX", ssAddr, seAddr ); + + } while (0); + + return o_rc; + #undef PRDF_FUNC +} + +template <TYPE T> +int32_t dimmSlct( TargetHandle_t i_dimm ) +{ + #define PRDF_FUNC "[MemDealloc::dimmSlct] " + int32_t o_rc = SUCCESS; + + do + { + if ( !isEnabled() ) break; // nothing to do + + TargetHandle_t tgt = getConnectedParent( i_dimm, T ); + + if ( tgt == NULL ) + { + PRDF_ERR( PRDF_FUNC "Failed to get parent for dimm 0x%08X", + getHuid( i_dimm ) ); + o_rc = FAIL; break; + } + + ExtensibleChip * chip = (ExtensibleChip *)systemPtr->GetChip( tgt ); + if ( NULL == chip ) + { + PRDF_ERR( PRDF_FUNC "No MBA/MCA chip behind DIMM" ); + o_rc = FAIL; break; + } + // Find the largest address range + uint64_t smallestAddr = 0xffffffffffffffffll; + uint64_t largestAddr = 0; + MemAddr startAddr, endAddr; + std::vector<MemRank> masterRanks; + uint8_t dimmSlct = 0; + + o_rc = getDimmSlct<T>( i_dimm, dimmSlct ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "getDimmSlct failed" ); + break; + } + + getMasterRanks<T>( tgt, masterRanks, dimmSlct ); + + // Iterate all ranks to get start and end address. + for ( std::vector<MemRank>::iterator it = masterRanks.begin(); + it != masterRanks.end(); it++ ) + { + o_rc = getMemAddrRange( tgt, it->getRankSlct(), dimmSlct, + startAddr, endAddr ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "getMemAddrRange() Failed. HUID:0x%08X", + chip->GetId() ); + break; + } + + // Get the system addresses + uint64_t ssAddr = 0; + uint64_t seAddr = 0; + o_rc = getSystemAddr<T>( chip, startAddr, ssAddr); + o_rc |= getSystemAddr<T>( chip, endAddr, seAddr ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "getSystemAddr() failed. HUID:0x%08X", + chip->GetId() ); + break; + } + if ( ssAddr < smallestAddr ) smallestAddr = ssAddr; + if ( seAddr > largestAddr ) largestAddr = seAddr; + } + if( SUCCESS != o_rc ) break; + + // Send the address range to PHYP + sendDynMemDeallocRequest( smallestAddr, largestAddr ); + PRDF_TRAC( PRDF_FUNC "DIMM Slct dealloc for Start Addr: 0x%016llx " + "End Addr: 0x%016llX", smallestAddr, largestAddr ); + + } while (0); + + if( FAIL == o_rc ) + { + PRDF_ERR( PRDF_FUNC "failed. DIMM:0x%08X", getHuid( i_dimm ) ); + } + + return o_rc; + #undef PRDF_FUNC +} + +template <TYPE T> +bool isDimmPair( TargetHandle_t i_dimm1, TargetHandle_t i_dimm2 ) +{ + #define PRDF_FUNC "[MemDealloc::isDimmPair] " + bool isDimmPair = false; + do + { + uint8_t dimm1Slct = 0; + uint8_t dimm2Slct = 0; + + int32_t rc = getDimmSlct<T>( i_dimm1, dimm1Slct ); + rc |= getDimmSlct<T>( i_dimm2, dimm2Slct ); + + if( SUCCESS != rc ) + { + PRDF_ERR( PRDF_FUNC " getDimmSlct() failed" ); + break; + } + isDimmPair = ( ( dimm1Slct == dimm2Slct ) && + ( getConnectedParent( i_dimm1, T ) == + getConnectedParent( i_dimm2, T ))); + } while(0); + return isDimmPair; + #undef PRDF_FUNC +} + +// This function is used for sorting dimms in a list. +template <TYPE T> +bool compareDimms( TargetHandle_t i_dimm1, TargetHandle_t i_dimm2 ) +{ + #define PRDF_FUNC "[MemDealloc::compareDimms] " + bool isSmall = false; + do + { + uint8_t dimm1Slct = 0; + uint8_t dimm2Slct = 0; + + int32_t rc = getDimmSlct<T>( i_dimm1, dimm1Slct ); + rc |= getDimmSlct<T>( i_dimm2, dimm2Slct ); + + if( SUCCESS != rc ) + { + PRDF_ERR( PRDF_FUNC " getDimmSlct() failed" ); + break; + } + TargetHandle_t tgt1 = getConnectedParent( i_dimm1, T ); + TargetHandle_t tgt2 = getConnectedParent( i_dimm2, T ); + + isSmall = ( ( tgt1 < tgt2 ) || + ( ( tgt1 == tgt2) && ( dimm1Slct < dimm2Slct ))); + + } while(0); + + return isSmall; + #undef PRDF_FUNC +} + + +template <TYPE T> +int32_t dimmList( TargetHandleList & i_dimmList ) +{ + #define PRDF_FUNC "[MemDealloc::dimmList] " + int32_t o_rc = SUCCESS; + + // Find unique dimm slct. + std::sort( i_dimmList.begin(), i_dimmList.end(), compareDimms<T> ); + TargetHandleList::iterator uniqueDimmEndIt = + std::unique( i_dimmList.begin(), i_dimmList.end(), + isDimmPair<T> ); + + for( TargetHandleList::iterator it = i_dimmList.begin(); + it != uniqueDimmEndIt; it++ ) + { + int32_t l_rc = dimmSlct<T>( *it ); + if( SUCCESS != l_rc ) + { + PRDF_ERR(PRDF_FUNC "Failed for DIMM 0x:%08X", getHuid( *it ) ); + o_rc |= l_rc; + } + } + return o_rc; + #undef PRDF_FUNC +} + +int32_t dimmList( TargetHandleList & i_dimmList ) +{ + if (i_dimmList.size() == 0) + return SUCCESS; + + // Determine MBA/MCA + TYPE T = TYPE_MCA; + TargetHandle_t dimmTgt = i_dimmList[0]; + TargetHandle_t tgt = getConnectedParent( dimmTgt, T ); + if ( NULL == tgt) + { + T = TYPE_MBA; + tgt = getConnectedParent( dimmTgt, T ); + } + + if (tgt == NULL) + { + PRDF_ERR( "[MemDealloc::dimmList] get parent tgt failed for 0x%08X", + getHuid(dimmTgt)); + return FAIL; + } + + if ( T == TYPE_MCA ) + return dimmList<TYPE_MCA>( i_dimmList ); + else if ( T == TYPE_MBA ) + return dimmList<TYPE_MBA>( i_dimmList ); + else + return FAIL; +} + +} //namespace MemDealloc +} // namespace PRDF + diff --git a/src/usr/diag/prdf/plat/mem/prdfMemDynDealloc.H b/src/usr/diag/prdf/plat/mem/prdfMemDynDealloc.H new file mode 100644 index 000000000..aa65feee9 --- /dev/null +++ b/src/usr/diag/prdf/plat/mem/prdfMemDynDealloc.H @@ -0,0 +1,95 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/diag/prdf/plat/mem/prdfMemDynDealloc.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017,2018 */ +/* [+] 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 __prdfMemDynDealloc_H +#define __prdfMemDynDealloc_H + +/** @file prdfMemDynDealloc.H + * @brief Support functions for Dynamic Memory Deallocation + */ + +namespace PRDF +{ + +class ExtensibleChip; +class MemAddr; + +namespace MemDealloc +{ + +/** + * @return True, if Dynamic Memory Deallocation is enabled. False, otherwise. + */ +bool isEnabled(); + +/** + * @brief Sends message to hypervisor for page dealloc + * @param i_chip MBA/MCA chip + * @param i_addr The address to page dealloc. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ +template<TARGETING::TYPE T> +int32_t page( ExtensibleChip * i_chip, MemAddr i_addr ); + +/** + * @brief Sends message to hypervisor to dealloc all memory on a rank + * @param i_chip MBA/MCA chip + * @param i_addr The address to page dealloc. + * @param i_isFetch TRUE if we are calling this because of FETCH UE, + * FALSE otherwise. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ +template<TARGETING::TYPE T> +int32_t rank( ExtensibleChip * i_chip, MemRank i_rank ); + +/** + * @brief Sends a message to hypervisor to dealloc all memory behind a port + * @param i_chip MBA/MCA chip + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ +template<TARGETING::TYPE T> +int32_t port( ExtensibleChip * i_chip ); + +/** + * @brief Sends a message to hypervisor to dealloc all memory behind dimm List. + * @param i_dimmList DIMM list + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ +int32_t dimmList( TARGETING::TargetHandleList & i_dimmList ); + +/** + * @brief Sends a message to PHYP to dealloc all memory behind dimm slct. + * @param i_dimm Memory DIMM. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ +template<TARGETING::TYPE T> +int32_t dimmSlct( TARGETING::TargetHandle_t i_dimm ); + +} //namespace MemDealloc +} // namespace PRDF +//------------------------------------------------------------------------------ + + +#endif /* __prdfMemDynDealloc_H */ + diff --git a/src/usr/diag/prdf/plat/mem/prdf_plat_mem_hb_only.mk b/src/usr/diag/prdf/plat/mem/prdf_plat_mem_hb_only.mk index 1c7770ee4..fd0f8dd4a 100644 --- a/src/usr/diag/prdf/plat/mem/prdf_plat_mem_hb_only.mk +++ b/src/usr/diag/prdf/plat/mem/prdf_plat_mem_hb_only.mk @@ -5,7 +5,7 @@ # # OpenPOWER HostBoot Project # -# Contributors Listed Below - COPYRIGHT 2016,2017 +# Contributors Listed Below - COPYRIGHT 2016,2018 # [+] International Business Machines Corp. # # @@ -72,6 +72,7 @@ ifeq (${HOSTBOOT_RUNTIME},1) prd_obj += prdfMemTdCtlr_rt.o prd_obj += prdfMemTps_rt.o prd_obj += prdfMemVcm_rt.o +prd_obj += prdfMemDynDealloc.o endif diff --git a/src/usr/diag/prdf/plat/prdfPlatServices_rt.C b/src/usr/diag/prdf/plat/prdfPlatServices_rt.C index 6fb865a57..03b5b2a6f 100644 --- a/src/usr/diag/prdf/plat/prdfPlatServices_rt.C +++ b/src/usr/diag/prdf/plat/prdfPlatServices_rt.C @@ -90,12 +90,6 @@ void sendPageGardRequest( uint64_t i_systemAddress ) //------------------------------------------------------------------------------ -void sendLmbGardRequest( uint64_t i_systemAddress, bool i_isFetchUE ) -{ - //NO-OP for OPAL -} -//------------------------------------------------------------------------------ - void sendDynMemDeallocRequest( uint64_t i_startAddr, uint64_t i_endAddr ) { #define PRDF_FUNC "[PlatServices::sendDynMemDeallocRequest] " @@ -121,6 +115,37 @@ void sendDynMemDeallocRequest( uint64_t i_startAddr, uint64_t i_endAddr ) #undef PRDF_FUNC } +int32_t getMemAddrRange( TargetHandle_t i_tgt, uint8_t i_mrank, + uint8_t i_dimmSlct, MemAddr & o_startAddr, + MemAddr & o_endAddr, uint8_t i_srank, + bool i_slaveOnly ) +{ + ExtensibleChip * i_mcaChip = (ExtensibleChip *)systemPtr->GetChip( i_tgt ); + uint32_t port = i_mcaChip->getPos() % MAX_MCA_PER_MCBIST; + mss::mcbist::address saddr, eaddr; + + if ( i_slaveOnly ) + { + mss::mcbist::address::get_srank_range( port, + i_dimmSlct, + i_mrank, + i_srank, + saddr, eaddr ); + } + else + { + mss::mcbist::address::get_mrank_range( port, + i_dimmSlct, + i_mrank, + saddr, eaddr ); + } + + o_startAddr = MemAddr::fromMaintAddr<TYPE_MCBIST>( (uint64_t) saddr ); + o_endAddr = MemAddr::fromMaintAddr<TYPE_MCBIST>( (uint64_t) eaddr ); + + return SUCCESS; +} + //############################################################################## //## Nimbus Maintenance Command wrappers //############################################################################## diff --git a/src/usr/diag/prdf/plat/prdfPlatServices_rt.H b/src/usr/diag/prdf/plat/prdfPlatServices_rt.H index 2e811344b..f54b166ee 100644 --- a/src/usr/diag/prdf/plat/prdfPlatServices_rt.H +++ b/src/usr/diag/prdf/plat/prdfPlatServices_rt.H @@ -29,6 +29,7 @@ #include <p9_l3err_extract.H> #include <p9_l2err_extract.H> #include <p9_pm_callout.H> +#include <prdfMemAddress.H> namespace PRDF { @@ -47,14 +48,6 @@ namespace PlatServices void sendPageGardRequest( uint64_t i_systemAddress ); /** - * @brief Communicates an LMB gard request to the hypervisor. - * @param i_systemAddress Any address in the target LMB. - * @param i_isFetchUE True if cause attention is a fetch UE. False if cause - * attention is a scrub UE (only applicable to FSP code). - */ -void sendLmbGardRequest( uint64_t i_systemAddress, bool i_isFetchUE ); - -/** * @brief Communicates to the hypervisor a range of address to remove from the * available memory space. * @param i_startAddr First address in the range. @@ -62,6 +55,22 @@ void sendLmbGardRequest( uint64_t i_systemAddress, bool i_isFetchUE ); */ void sendDynMemDeallocRequest( uint64_t i_startAddr, uint64_t i_endAddr ); +/** + * @brief Returns the start and end maintenance address of the given rank. By + * default, will return the address range of the master rank. + * @param i_tgt Target MBA/MCA. + * @param i_rank Target rank. + * @param i_dimmSlct Target dimm select. + * @param o_startAddr The return start address. + * @param o_endAddr The return end address. + * @param i_slaveOnly true = slave rank only, false = master rank (default). + * @return Non-SUCCESS in internal function fails, SUCCESS otherwise. + */ +int32_t getMemAddrRange( TARGETING::TargetHandle_t i_tgt, uint8_t i_mrank, + uint8_t i_dimmSlct, MemAddr & o_startAddr, + MemAddr & o_endAddr, uint8_t i_srank = 0, + bool i_slaveOnly = false ); + //############################################################################## //## Nimbus/Centaur Maintenance Command wrappers //############################################################################## |