summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Weisenbeck <bweisenb@us.ibm.com>2017-08-23 09:49:12 -0500
committerZane C Shelley <zshelle@us.ibm.com>2018-02-01 10:52:48 -0500
commit056c43ed3e5af0977354f80bc313245e65cc4a04 (patch)
treeb7e839bececf6727a4b3895a832de970fc1f6df1
parenteb4da4cd0830932f4c662eeff7facaaecd4d54d2 (diff)
downloadtalos-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.C3
-rw-r--r--src/usr/diag/prdf/common/plat/mem/prdfMemAddress.H4
-rw-r--r--src/usr/diag/prdf/common/plat/p9/p9_mcs_regs.rule21
-rwxr-xr-xsrc/usr/diag/prdf/common/plat/prdfTargetServices.C16
-rwxr-xr-xsrc/usr/diag/prdf/common/plat/prdfTargetServices.H7
-rw-r--r--src/usr/diag/prdf/plat/mem/prdfMemDynDealloc.C799
-rw-r--r--src/usr/diag/prdf/plat/mem/prdfMemDynDealloc.H95
-rw-r--r--src/usr/diag/prdf/plat/mem/prdf_plat_mem_hb_only.mk3
-rw-r--r--src/usr/diag/prdf/plat/prdfPlatServices_rt.C37
-rw-r--r--src/usr/diag/prdf/plat/prdfPlatServices_rt.H25
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
//##############################################################################
OpenPOWER on IntegriCloud