summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory
diff options
context:
space:
mode:
authorBrian Silver <bsilver@us.ibm.com>2016-08-16 14:39:25 -0500
committerChristian R. Geddes <crgeddes@us.ibm.com>2016-09-13 13:57:11 -0400
commite1072794018dc014dfe3f4737021726daecd397a (patch)
tree6ef83aa84b9a40d351752b18e93c2221d778fe55 /src/import/chips/p9/procedures/hwp/memory
parent69574021bf9f4f45e4dbd5efb3dbe9d6eb3884e9 (diff)
downloadtalos-hostboot-e1072794018dc014dfe3f4737021726daecd397a.tar.gz
talos-hostboot-e1072794018dc014dfe3f4737021726daecd397a.zip
Update memory library for 1R 4gbx4 DIMM
Add SPD to ekb, including Hynix power-on DIMM and 4R VBU DIMM Update SPD blobs to match recent changes to VBU SPD Change-Id: I1ea6be55858a3bd8ec206624294a3a2accd81136 CMVC-Prereq: 1005769 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/28349 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Reviewed-by: Louis Stermole <stermole@us.ibm.com> Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com> Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com> Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/28358 Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H120
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/kind.H2
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mc/xlate.C388
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mc/xlate.H96
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H2
5 files changed, 437 insertions, 171 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H b/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H
index 501c50031..832c22a82 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H
@@ -198,86 +198,89 @@ class instruction_t
/// @param[in] i_arr1 the initial value for arr1, defaults to 0
///
instruction_t( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target = fapi2::Target<fapi2::TARGET_TYPE_DIMM>(),
- uint64_t i_rank = 0xFF,
+ uint64_t i_rank = NO_CHIP_SELECT_ACTIVE,
const fapi2::buffer<uint64_t> i_arr0 = 0,
const fapi2::buffer<uint64_t> i_arr1 = 0):
arr0(i_arr0),
arr1(i_arr1)
{
-
- static const uint64_t CS_N[mss::MAX_RANK_PER_DIMM] =
+ // For DIMM0 .first is the CSN_0_1 setting, .second is the CSN_2_3 setting.
+ // For DIMM1 .first is the CSN_2_3 setting, .second is the CSN_0_1 setting.
+ static const std::pair<uint64_t, uint64_t> CS_N[mss::MAX_RANK_PER_DIMM] =
{
- // DCS0 L DCS1 H => Rank 0
- 0b01,
- // DCS0 H DCS1 L => Rank 1
- 0b10,
- };
+ // CS0 L CS1 H => CS2 => H CS3 => H Rank 0
+ { 0b01, 0b11 },
+
+ // CS0 H CS1 L => CS2 => H CS3 => H Rank 1
+ { 0b10, 0b11 },
- // Start be deselcting everything and we'll clear the bits we want.
- arr0.insertFromRight<TT::ARR0_DDR_CSN_0_1, TT::ARR0_DDR_CSN_0_1_LEN>(0b11);
- arr0.insertFromRight<TT::ARR0_DDR_CSN_2_3, TT::ARR0_DDR_CSN_2_3_LEN>(0b11);
+ // CS0 H CS1 H => CS2 => L CS3 => H Rank 2
+ { 0b11, 0b01 },
+
+ // CS0 H CS1 H => CS2 => H CS3 => L Rank 3
+ { 0b11, 0b10 },
+ };
// If the rank indicates nothing selected (active low) then we're done.
- if (i_rank == 0xFF)
+ if (i_rank == NO_CHIP_SELECT_ACTIVE)
{
+ arr0.insertFromRight<TT::ARR0_DDR_CSN_0_1, TT::ARR0_DDR_CSN_0_1_LEN>(0b11);
+ arr0.insertFromRight<TT::ARR0_DDR_CSN_2_3, TT::ARR0_DDR_CSN_2_3_LEN>(0b11);
return;
}
//
- // Note: This needs to be able to handle all DIMM, stacked, encoded CS_n, etc. This
- // ain't gonna cut it. Turn this in to a dispatched funtion like c_str() and rcd_load() BRS
+ // Note: This likely needs to be able to handle all DIMM, stacked, encoded CS_n, etc. This
+ // might not cut it. Turn this in to a dispatched funtion like c_str() and rcd_load() BRS
//
// Direct CS mode - just clear the CS_N you're interested in.
// Setup the chip select based on which dimm in the slot and the rank
if (mss::index(i_target) == 0)
{
+ // Sanity check the incoming rank. It has to be 0-3 since we're DIMM0
+ // Assert since this is a programming error
+ if (i_rank >= MAX_RANK_PER_DIMM)
+ {
+ FAPI_ERR("DIMM0 %s CCS instruction looking for bad rank/chip select (%d)",
+ mss::c_str(i_target), i_rank);
+ fapi2::Assert(false);
+ // Not reached but fapi2::Assert isn't [[no return]] so the compiler thinks we're going
+ // to run off the array but we're not so this makes the compiler happy.
+ return;
+ }
+
arr0.insertFromRight<TT::ARR0_DDR_CSN_0_1,
- TT::ARR0_DDR_CSN_0_1_LEN>(CS_N[i_rank]);
- }
- else
- {
+ TT::ARR0_DDR_CSN_0_1_LEN>(CS_N[i_rank].first);
arr0.insertFromRight<TT::ARR0_DDR_CSN_2_3,
- TT::ARR0_DDR_CSN_2_3_LEN>(CS_N[i_rank]);
- }
-
-#ifdef QUAD_ENCODED_CS
- // Implement the Encoded QuadCS Mode DCS, DC mapping and stuff the resulting
- // bits in to the proper location for the CCS instruction (perhaps we need
- // to be a template - p9n CCS is different from Centaur ... make initializing
- // the instruction a policy of the ccsTraits ... BRS)
-
- // Lookup table for CS_N and CID indexed by rank for Quad encoded CS modee
- // First bits 0:1 is DCS1_n:DCS2_n. Second bits 0:1 are CID 0:1 bit 2 is CID 2
- static const std::pair< uint8_t, uint8_t > CS_CID[mss::MAX_RANK_PER_DIMM] =
- {
- // DCS0 L DCS1 H CID L:L => Rank 0
- { 0b01000000, 0b00000000 },
- // DCS0 L DCS1 H CID H:H => Rank 1
- { 0b01000000, 0b11000000 },
- // DCS0 H DCS1 L CID L:L => Rank 2
- { 0b10000000, 0b00000000 },
- // DCS0 H DCS1 L CID H:H => Rank 3
- { 0b10000000, 0b11000000 },
- };
-
- // Setup the chip select based on which dimm in the slot and the rank
- if (mss::index(i_target) == 0)
- {
- arr0.insert<TT::ARR0_DDR_CSN_0_1,
- TT::ARR0_DDR_CSN_0_1_LEN>(CS_CID[i_rank].first);
+ TT::ARR0_DDR_CSN_2_3_LEN>(CS_N[i_rank].second);
}
else
{
- arr0.insert<TT::ARR0_DDR_CSN_2_3,
- TT::ARR0_DDR_CSN_2_3_LEN>(CS_CID[i_rank].first);
+ // DIMM1's ranks are {4,5,6,7} so we subract the mid-point rank to normalize i_rank for DIMM1
+ const uint64_t l_effective_rank = i_rank - RANK_MID_POINT;
+
+ // Sanity check that we don't have more than 2 ranks on DIMM1. Effective Config
+ // should have caught this with the plug rules, but we will select the rank in the
+ // wrong DIMM with this CCS instruction if we blew it, so lets check ... We can assert
+ // our way out of this as this is a code bug in Effective Config, so they should have
+ // reported a real error long ago ...
+ if (l_effective_rank >= MAX_RANKS_DIMM1)
+ {
+ FAPI_ERR("DIMM1 %s CCS instruction looking for bad rank/chip select (%d, %d)",
+ mss::c_str(i_target), i_rank, l_effective_rank);
+ fapi2::Assert(false);
+ // Not reached but fapi2::Assert isn't [[no return]] so the compiler thinks we're going
+ // to run off the array but we're not so this makes the compiler happy.
+ return;
+ }
+
+ // Deselect ranks on DIMM0
+ arr0.insertFromRight<TT::ARR0_DDR_CSN_0_1,
+ TT::ARR0_DDR_CSN_0_1_LEN>(CS_N[l_effective_rank].second);
+ arr0.insertFromRight<TT::ARR0_DDR_CSN_2_3,
+ TT::ARR0_DDR_CSN_2_3_LEN>(CS_N[l_effective_rank].first);
}
-
- arr0.insert<TT::ARR0_DDR_CID_0_1,
- TT::ARR0_DDR_CID_0_1_LEN>(CS_CID[i_rank].second);
- arr0.writeBit<TT::ARR0_DDR_CID_2>(
- fapi2::buffer<uint8_t>(CS_CID[i_rank].second).getBit<2>());
-#endif
}
};
@@ -358,8 +361,8 @@ inline instruction_t<T> rcd_command( const fapi2::Target<fapi2::TARGET_TYPE_DIMM
rcd_boilerplate_arr0.insertFromRight<TT::ARR0_DDR_BANK_0_1, TT::ARR0_DDR_BANK_0_1_LEN>(0b11);
rcd_boilerplate_arr0.setBit<TT::ARR0_DDR_BANK_GROUP_0>();
- // RCD always goes to rank 0. All we need to know is which DIMM we are on the port
- return instruction_t<T>(i_target, 0, rcd_boilerplate_arr0, rcd_boilerplate_arr1);
+ // RCD always goes to the 0th rank on the DIMM; either 0 or 4.
+ return instruction_t<T>(i_target, (mss::index(i_target) == 0) ? 0 : 4, rcd_boilerplate_arr0, rcd_boilerplate_arr1);
}
///
@@ -422,8 +425,9 @@ inline instruction_t<T> des_command()
// ACT is high no-care
// RAS, CAS, WE no-care
- // Device Deslect wants CS_n always high (select nothing using rank 0xFF)
- return instruction_t<T>(fapi2::Target<fapi2::TARGET_TYPE_DIMM>(), 0xFF, rcd_boilerplate_arr0, rcd_boilerplate_arr1);
+ // Device Deslect wants CS_n always high (select nothing using rank NO_CHIP_SELECT_ACTIVE)
+ return instruction_t<T>(fapi2::Target<fapi2::TARGET_TYPE_DIMM>(), NO_CHIP_SELECT_ACTIVE,
+ rcd_boilerplate_arr0, rcd_boilerplate_arr1);
}
///
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/kind.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/kind.H
index ed38644f2..42c355ce1 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/kind.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/kind.H
@@ -94,7 +94,7 @@ class kind
///
/// @brief operator==() - are two kinds the same?
/// @param[in] i_rhs the right hand side of the comparison statement
- /// @return boll true iff the two kind are of the same kind
+ /// @return bool true iff the two kind are of the same kind
/// @warning this does not compare the targets (iv_target,) just the values
///
inline bool operator==(const kind& i_rhs) const
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mc/xlate.C b/src/import/chips/p9/procedures/hwp/memory/lib/mc/xlate.C
index 123bb10c6..1f7342e46 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/mc/xlate.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mc/xlate.C
@@ -41,174 +41,337 @@
#include <lib/mss_attribute_accessors.H>
#include <lib/mc/mc.H>
+#include <lib/mc/xlate.H>
#include <lib/utils/scom.H>
+#include <lib/utils/find.H>
#include <lib/dimm/kind.H>
-using fapi2::TARGET_TYPE_MCBIST;
-using fapi2::TARGET_TYPE_PROC_CHIP;
-using fapi2::TARGET_TYPE_SYSTEM;
using fapi2::TARGET_TYPE_MCA;
-using fapi2::TARGET_TYPE_MCS;
using fapi2::TARGET_TYPE_DIMM;
-using fapi2::FAPI2_RC_SUCCESS;
-
namespace mss
{
namespace mc
{
+/// A little vector of translators. We have one of these for each DIMM we support
+static const std::vector<xlate_setup> xlate_map =
+{
+ // 2R4Gbx4 DDR4 RDIMM
+ {
+ dimm::kind(2, 0, 4, 4, fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR4, fapi2::ENUM_ATTR_EFF_DIMM_TYPE_RDIMM, 16, 16),
+ xlate_dimm_2R4Gbx4
+ },
+ {
+ dimm::kind(1, 0, 4, 4, fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR4, fapi2::ENUM_ATTR_EFF_DIMM_TYPE_RDIMM, 16, 8),
+ xlate_dimm_1R4Gbx4
+ },
+
+};
+
///
-/// @brief Perform initializations of the MC translation
-/// @tparm P the fapi2::TargetType of the port
-/// @tparm TT the typename of the traits
-/// @param[in] i_target, the target which has the MCA to map
-/// @return FAPI2_RC_SUCCESS iff ok
+/// @brief Helper to lay down the col and bank mappings.
+/// @param[in] o_xlate1 a buffer representing the xlate register to modify
+/// @param[in] o_xlate2 a buffer representing the xlate register to modify
+/// @note This is for 16 bank DIMM, 32 bank DIMM will be different
///
-template<>
-fapi2::ReturnCode setup_xlate_map(const fapi2::Target<TARGET_TYPE_MCA>& i_target)
+static void column_and_16bank_helper(fapi2::buffer<uint64_t>& l_xlate1, fapi2::buffer<uint64_t>& l_xlate2)
{
- fapi2::buffer<uint64_t> l_xlate;
- fapi2::buffer<uint64_t> l_xlate1;
- fapi2::buffer<uint64_t> l_xlate2;
+ // These are compile time freebies, so there's no need to bother putting them in a pre-defined
+ // constant and or-ing them in. Keeps things much more clear when the performance team wants to muck
+ // around with the settings. Mappings taken directly from the Nimbus Workbook. The magic numbers
+ // aren't; they're settings as defined in the scomdef
- const auto l_dimms = i_target.getChildren<TARGET_TYPE_DIMM>();
+ l_xlate1.insertFromRight<MCS_PORT02_MCP0XLT1_COL4_BIT_MAP,
+ MCS_PORT02_MCP0XLT1_COL4_BIT_MAP_LEN>(0b01101);
- FAPI_INF("Setting up xlate registers for MCA%d (%d)", mss::pos(i_target), mss::index(i_target));
+ l_xlate1.insertFromRight<MCS_PORT02_MCP0XLT1_COL5_BIT_MAP,
+ MCS_PORT02_MCP0XLT1_COL5_BIT_MAP_LEN>(0b01100);
- // We enable the DIMM select bit for slot1 if we have two DIMM installed
- l_xlate.writeBit<MCS_PORT13_MCP0XLT0_SLOT1_D_VALUE>(l_dimms.size() == 2);
+ l_xlate1.insertFromRight<MCS_PORT02_MCP0XLT1_COL6_BIT_MAP,
+ MCS_PORT02_MCP0XLT1_COL6_BIT_MAP_LEN>(0b01011);
- // Get the functional DIMM on this port.
- for (auto d : l_dimms)
- {
- // Our slot (0, 1) is the same as our general index.
- const uint64_t l_slot = mss::index(d);
+ l_xlate1.insertFromRight<MCS_PORT02_MCP0XLT1_COL7_BIT_MAP,
+ MCS_PORT02_MCP0XLT1_COL7_BIT_MAP_LEN>(0b01010);
- // Our slot offset tells us which 16 bit section in the xlt register to use for this DIMM
- // We'll either use the left most bits (slot 0) or move 16 bits to the right for slot 1.
- const uint64_t l_slot_offset = l_slot * 16;
+ l_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_COL8_BIT_MAP,
+ MCS_PORT02_MCP0XLT2_COL8_BIT_MAP_LEN>(0b01001);
+
+ l_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_COL9_BIT_MAP,
+ MCS_PORT02_MCP0XLT2_COL9_BIT_MAP_LEN>(0b00111);
+
+ l_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_BANK0_BIT_MAP,
+ MCS_PORT02_MCP0XLT2_BANK0_BIT_MAP_LEN>(0b01110);
- // Get the translation array, based on this specific DIMM's config
- dimm::kind l_dimm(d);
+ l_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_BANK1_BIT_MAP,
+ MCS_PORT02_MCP0XLT2_BANK1_BIT_MAP_LEN>(0b10000);
- FAPI_DBG("address translation for DIMM %s %dR %dgbx%d in slot %d",
- mss::c_str(d), l_dimm.iv_master_ranks, l_dimm.iv_dram_density, l_dimm.iv_dram_width, l_slot);
+ l_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_BANK_GROUP0_BIT_MAP,
+ MCS_PORT02_MCP0XLT2_BANK_GROUP0_BIT_MAP_LEN>(0b10001);
+ l_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_BANK_GROUP1_BIT_MAP,
+ MCS_PORT02_MCP0XLT2_BANK_GROUP1_BIT_MAP_LEN>(0b10010);
+}
- // Set the proper bit if there is a DIMM in this slot. If there wasn't, we wouldn't see
- // this DIMM in the vector, so this is always safe.
- l_xlate.setBit(MCS_PORT02_MCP0XLT0_SLOT0_VALID + l_slot_offset);
+///
+/// @brief Perform initializations of the MC translation
+/// @param[in] i_kind the DIMM to map
+/// @param[in] i_offset the offset; whether the DIMM ins slot 0 or slot 1
+/// @param[in] i_largest whether or not we're the largest DIMM on the port.
+/// @param[in] o_xlate a buffer representing the xlate register to modify
+/// @param[in] o_xlate1 a buffer representing the xlate register to modify
+/// @param[in] o_xlate2 a buffer representing the xlate register to modify
+/// @note Called for 2R4Gbx4 DDR4 RDIMM
+///
+void xlate_dimm_2R4Gbx4( const dimm::kind& i_kind,
+ const uint64_t i_offset,
+ const bool i_largest,
+ fapi2::buffer<uint64_t>& o_xlate,
+ fapi2::buffer<uint64_t>& o_xlate1,
+ fapi2::buffer<uint64_t>& o_xlate2 )
+{
+ // Set the proper bit if there is a DIMM in this slot. If there wasn't, we wouldn't see
+ // this DIMM in the vector, so this is always safe.
+ o_xlate.setBit(MCS_PORT02_MCP0XLT0_SLOT0_VALID + i_offset);
+
+ // Check our master ranks, and enable the proper bits.
+ // Note this seems a little backward. M0 is the left most bit, M1 the right most.
+ // So, M1 changes for ranks 0,1 and M0 changes for ranks 3,4
+ // 2 rank DIMM, so master bit 1 (least significant) bit needs to be mapped.
+ o_xlate.setBit(MCS_PORT13_MCP0XLT0_SLOT0_M1_VALID + i_offset);
+ o_xlate.insertFromRight<MCS_PORT02_MCP0XLT0_M1_BIT_MAP, MCS_PORT02_MCP0XLT0_M1_BIT_MAP_LEN>(0b01111);
+
+ // Tell the MC which of the row bits are valid, and map the DIMM selector
+ // We're a 16 row DIMM, so ROW15 is valid.
+ o_xlate.setBit(MCS_PORT02_MCP0XLT0_SLOT0_ROW15_VALID + i_offset);
+ o_xlate.insertFromRight<MCS_PORT02_MCP0XLT0_R15_BIT_MAP, MCS_PORT02_MCP0XLT0_R15_BIT_MAP_LEN>(0b00110);
+ // Drop down the column assignments
+ column_and_16bank_helper(o_xlate1, o_xlate2);
- // Set the 12G DIMM bit if either DIMM is 12G
- // Is this correct? BRS
- l_xlate.writeBit<MCS_PORT13_MCP0XLT0_12GB_ENABLE>(l_dimm.iv_size == 12);
+ // Setup the D-bit. If we're the largest DIMM, it is our mapping which maters.
+ // Notice tht we don't care if the D-value bit has been set; this mapping needs to be setup regardless (SJ Powell says so)
+ if (i_largest)
+ {
+ FAPI_INF("setting d-bit mapping (am largest) for %s", mss::c_str(i_kind.iv_target));
+ o_xlate.insertFromRight(0b00101, MCS_PORT02_MCP0XLT0_D_BIT_MAP + i_offset, MCS_PORT02_MCP0XLT0_D_BIT_MAP_LEN);
+ }
+}
- // Check our master ranks, and enable the proper bits.
- // Note this seems a little backward. M0 is the left most bit, M1 the right most.
- // So, M1 changes for ranks 0,1 and M0 changes for ranks 3,4
- if (l_dimm.iv_master_ranks > 0)
- {
- l_xlate.setBit(MCS_PORT13_MCP0XLT0_SLOT0_M1_VALID + l_slot_offset);
- }
- if (l_dimm.iv_master_ranks > 2)
- {
- l_xlate.setBit(MCS_PORT13_MCP0XLT0_SLOT0_M0_VALID + l_slot_offset);
- }
+///
+/// @brief Perform initializations of the MC translation
+/// @param[in] i_kind the DIMM to map
+/// @param[in] i_offset the offset; whether the DIMM ins slot 0 or slot 1
+/// @param[in] i_largest whether or not we're the largest DIMM on the port.
+/// @param[in] o_xlate a buffer representing the xlate register to modify
+/// @param[in] o_xlate1 a buffer representing the xlate register to modify
+/// @param[in] o_xlate2 a buffer representing the xlate register to modify
+/// @note Called for 1R4Gbx4 DDR4 RDIMM
+///
+void xlate_dimm_1R4Gbx4( const dimm::kind& i_kind,
+ const uint64_t i_offset,
+ const bool i_largest,
+ fapi2::buffer<uint64_t>& o_xlate,
+ fapi2::buffer<uint64_t>& o_xlate1,
+ fapi2::buffer<uint64_t>& o_xlate2 )
+{
+ // 1R DIMM are special. We need to handle 2 1R DIMM on a port as a special case - kind of make them look like
+ // a single 2R DIMM. So we have to do a little dance here to get our partners configuration.
+ const auto& l_mca = mss::find_target<TARGET_TYPE_MCA>(i_kind.iv_target);
+ const auto& l_dimms = mss::find_targets<TARGET_TYPE_DIMM>(l_mca);
+ const std::vector<dimm::kind> l_dimm_kinds = dimm::kind::vector(l_dimms);
+ bool l_all_slots_1R = false;
- // Check slave ranks
- // Note this sems a little backward. S0 is the left-most slave bit. So,
- // if there are more than 0 slave ranks, S2 will increment first.
- if (l_dimm.iv_slave_ranks > 0)
- {
- l_xlate.setBit(MCS_PORT13_MCP0XLT0_SLOT0_S2_VALID + l_slot_offset);
- }
+ // If we only have 1 DIMM, we don't have two slots with 1R DIMM. If we need to check, iterate
+ // over the DIMM kinds and make sure all the DIMM have one master and zero slaves.
+ if (l_dimms.size() > 1)
+ {
+ l_all_slots_1R = true;
- if (l_dimm.iv_slave_ranks > 2)
+ for (const auto& k : l_dimm_kinds)
{
- l_xlate.setBit(MCS_PORT13_MCP0XLT0_SLOT0_S1_VALID + l_slot_offset);
+ l_all_slots_1R &= (k.iv_master_ranks == 1) && (k.iv_slave_ranks == 0);
}
- if (l_dimm.iv_slave_ranks > 4)
- {
- l_xlate.setBit(MCS_PORT13_MCP0XLT0_SLOT0_S0_VALID + l_slot_offset);
- }
+ FAPI_INF("We have a 1R DIMM and more than one DIMM installed; all 1R? %s",
+ (l_all_slots_1R == true ? "yes" : "no") );
+ }
+ // Set the proper bit if there is a DIMM in this slot. If there wasn't, we wouldn't see
+ // this DIMM in the vector, so this is always safe.
+ o_xlate.setBit(MCS_PORT02_MCP0XLT0_SLOT0_VALID + i_offset);
+ // If we have all the slots filled in with 1R/0 slave DIMM, we build a very differnt mapping.
+ if (l_all_slots_1R)
+ {
// Tell the MC which of the row bits are valid, and map the DIMM selector
- if (l_dimm.iv_rows >= 16)
- {
- l_xlate.setBit(MCS_PORT02_MCP0XLT0_SLOT0_ROW15_VALID + l_slot_offset);
- l_xlate.insertFromRight<MCS_PORT02_MCP0XLT0_R15_BIT_MAP, MCS_PORT02_MCP0XLT0_R15_BIT_MAP_LEN>(0b00110);
- l_xlate.insertFromRight<MCS_PORT02_MCP0XLT0_D_BIT_MAP, MCS_PORT02_MCP0XLT0_D_BIT_MAP_LEN>(0b00101);
- }
+ // We're a 16 row DIMM, so ROW15 is valid.
+ o_xlate.setBit(MCS_PORT02_MCP0XLT0_SLOT0_ROW15_VALID + i_offset);
+ o_xlate.insertFromRight<MCS_PORT02_MCP0XLT0_R15_BIT_MAP, MCS_PORT02_MCP0XLT0_R15_BIT_MAP_LEN>(0b00110);
- if (l_dimm.iv_rows >= 17)
- {
- l_xlate.setBit(MCS_PORT02_MCP0XLT0_SLOT0_ROW16_VALID + l_slot_offset);
- l_xlate.insertFromRight<MCS_PORT02_MCP0XLT0_R16_BIT_MAP, MCS_PORT02_MCP0XLT0_R16_BIT_MAP_LEN>(0b00101);
- l_xlate.insertFromRight<MCS_PORT02_MCP0XLT0_D_BIT_MAP, MCS_PORT02_MCP0XLT0_D_BIT_MAP_LEN>(0b00100);
- }
+ // Drop down the column assignments.
+ column_and_16bank_helper(o_xlate1, o_xlate2);
- if (l_dimm.iv_rows >= 18)
- {
- l_xlate.setBit(MCS_PORT02_MCP0XLT0_SLOT0_ROW17_VALID + l_slot_offset);
- l_xlate.insertFromRight<MCS_PORT02_MCP0XLT0_R17_BIT_MAP, MCS_PORT02_MCP0XLT0_R17_BIT_MAP_LEN>(0b00100);
- l_xlate.insertFromRight<MCS_PORT02_MCP0XLT0_D_BIT_MAP, MCS_PORT02_MCP0XLT0_D_BIT_MAP_LEN>(0b00011);
- }
+ // Setup the D-bit. Since both DIMM are identical, we just need to setup the map
+ FAPI_INF("setting d-bit mapping (all 1R DIMM) for %s", mss::c_str(i_kind.iv_target));
+ o_xlate.insertFromRight<MCS_PORT02_MCP0XLT0_D_BIT_MAP, MCS_PORT02_MCP0XLT0_D_BIT_MAP_LEN>(0b01111);
+ return;
}
- // TK: remove and make general in the loop above BRS
+ // So if we're here we have only 1 1R DIMM installed. This translation is different.
- // Two rank DIMM, so master bit 1 (least significant) bit needs to be mapped.
- l_xlate.insertFromRight<MCS_PORT02_MCP0XLT0_M1_BIT_MAP, MCS_PORT02_MCP0XLT0_M1_BIT_MAP_LEN>(0b01111);
+ // Tell the MC which of the row bits are valid, and map the DIMM selector
+ // We're a 16 row DIMM, so ROW15 is valid.
+ o_xlate.setBit(MCS_PORT02_MCP0XLT0_SLOT0_ROW15_VALID + i_offset);
+ o_xlate.insertFromRight<MCS_PORT02_MCP0XLT0_R15_BIT_MAP, MCS_PORT02_MCP0XLT0_R15_BIT_MAP_LEN>(0b00111);
- // Slot 1 isn't populated, so forget those bits for now.
+ // We don't just drop down the col and bank assignments, they're different.
+ o_xlate1.insertFromRight<MCS_PORT02_MCP0XLT1_COL4_BIT_MAP,
+ MCS_PORT02_MCP0XLT1_COL4_BIT_MAP_LEN>(0b01110);
- // DIMM bit map isn't exactly ignored for only one populated slot. It still needs to be
- // set in the map. Per S. Powell.
- // Master rank 0, 1 bit maps are ignored.
- // Row 16,17 bit maps are ignored.
- // Row 15 maps to Port Address bit 6
+ o_xlate1.insertFromRight<MCS_PORT02_MCP0XLT1_COL5_BIT_MAP,
+ MCS_PORT02_MCP0XLT1_COL5_BIT_MAP_LEN>(0b01101);
- // Drop down the column assignments
- l_xlate1.insertFromRight<MCS_PORT02_MCP0XLT1_COL4_BIT_MAP,
- MCS_PORT02_MCP0XLT1_COL4_BIT_MAP_LEN>(0b01101);
+ o_xlate1.insertFromRight<MCS_PORT02_MCP0XLT1_COL6_BIT_MAP,
+ MCS_PORT02_MCP0XLT1_COL6_BIT_MAP_LEN>(0b01100);
- l_xlate1.insertFromRight<MCS_PORT02_MCP0XLT1_COL5_BIT_MAP,
- MCS_PORT02_MCP0XLT1_COL5_BIT_MAP_LEN>(0b01100);
+ o_xlate1.insertFromRight<MCS_PORT02_MCP0XLT1_COL7_BIT_MAP,
+ MCS_PORT02_MCP0XLT1_COL7_BIT_MAP_LEN>(0b01011);
- l_xlate1.insertFromRight<MCS_PORT02_MCP0XLT1_COL6_BIT_MAP,
- MCS_PORT02_MCP0XLT1_COL6_BIT_MAP_LEN>(0b01011);
+ o_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_COL8_BIT_MAP,
+ MCS_PORT02_MCP0XLT2_COL8_BIT_MAP_LEN>(0b01010);
- l_xlate1.insertFromRight<MCS_PORT02_MCP0XLT1_COL7_BIT_MAP,
- MCS_PORT02_MCP0XLT1_COL7_BIT_MAP_LEN>(0b01010);
+ o_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_COL9_BIT_MAP,
+ MCS_PORT02_MCP0XLT2_COL9_BIT_MAP_LEN>(0b01001);
- l_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_COL8_BIT_MAP,
- MCS_PORT02_MCP0XLT2_COL8_BIT_MAP_LEN>(0b01001);
+ o_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_BANK0_BIT_MAP,
+ MCS_PORT02_MCP0XLT2_BANK0_BIT_MAP_LEN>(0b01111);
- l_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_COL9_BIT_MAP,
- MCS_PORT02_MCP0XLT2_COL9_BIT_MAP_LEN>(0b00111);
-
- l_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_BANK0_BIT_MAP,
- MCS_PORT02_MCP0XLT2_BANK0_BIT_MAP_LEN>(0b01110);
-
- l_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_BANK1_BIT_MAP,
+ o_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_BANK1_BIT_MAP,
MCS_PORT02_MCP0XLT2_BANK1_BIT_MAP_LEN>(0b10000);
- l_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_BANK_GROUP0_BIT_MAP,
+ o_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_BANK_GROUP0_BIT_MAP,
MCS_PORT02_MCP0XLT2_BANK_GROUP0_BIT_MAP_LEN>(0b10001);
- l_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_BANK_GROUP1_BIT_MAP,
+ o_xlate2.insertFromRight<MCS_PORT02_MCP0XLT2_BANK_GROUP1_BIT_MAP,
MCS_PORT02_MCP0XLT2_BANK_GROUP1_BIT_MAP_LEN>(0b10010);
- FAPI_DBG("HACK: Cramming 0x%016lx in for MCP0XLT0", l_xlate);
- FAPI_DBG("HACK: Cramming 0x%016lx in for MCP0XLT1", l_xlate1);
- FAPI_DBG("HACK: Cramming 0x%016lx in for MCP0XLT2", l_xlate2);
+ // There's nothing to do for the D-bit. We're either not the largest DIMM, in which case the lrgest DIMM
+ // will fix up our D-bit mapping, or we're the only DIMM in the port. If we're the only DIMM in the port,
+ // there is no D-bit mapping for a 1 slot 1R DIMM.
+ return;
+}
+
+///
+/// @brief Perform initializations of the MC translation - MCA specialization
+/// @param[in] i_target, the target which has the MCA to map
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode setup_xlate_map(const fapi2::Target<TARGET_TYPE_MCA>& i_target)
+{
+ fapi2::buffer<uint64_t> l_xlate;
+ fapi2::buffer<uint64_t> l_xlate1;
+ fapi2::buffer<uint64_t> l_xlate2;
+
+ const auto l_dimms = i_target.getChildren<TARGET_TYPE_DIMM>();
+
+ // We need to keep around specifications of both DIMM as we set the D bit based on the sizes of the DIMM
+ std::vector<dimm::kind> l_dimm_kinds = dimm::kind::vector(l_dimms);
+
+ FAPI_INF("Setting up xlate registers for MCA%d (%d)", mss::pos(i_target), mss::index(i_target));
+
+ // Considering the DIMM, record who gets the D bit. We make sure the *smallest* DIMM has the highest address
+ // range by setting it's D bit to 1. This eliminates, or reduces, holes in the memory map.
+ // However, we need to set that DIMM's D bit in the location of the largest DIMM's D-bit map (I know that's
+ // hard to grok - set the D bit in the smallest DIMM but in the location mapped for the largest.) So we
+ // keep track of the largest DIMM so when we set it up, we make sure to set the D-bit in the other.
+ std::sort(l_dimm_kinds.begin(), l_dimm_kinds.end(), [](const dimm::kind & a, const dimm::kind & b) -> bool
+ {
+ return a.iv_size > b.iv_size;
+ });
+
+ FAPI_INF("DIMM with the largest size on this port is %s %dR %dgbx%d (%dG)",
+ mss::c_str(l_dimm_kinds[0].iv_target),
+ l_dimm_kinds[0].iv_master_ranks, l_dimm_kinds[0].iv_dram_density,
+ l_dimm_kinds[0].iv_dram_width, l_dimm_kinds[0].iv_size);
+
+ const auto l_d_bit_target = l_dimm_kinds[0].iv_target;
+
+ // Get the functional DIMM on this port.
+ for (const auto& d : l_dimms)
+ {
+ // Our slot (0, 1) is the same as our general index.
+ const uint64_t l_slot = mss::index(d);
+
+ // Our slot offset tells us which 16 bit section in the xlt register to use for this DIMM
+ // We'll either use the left most bits (slot 0) or move 16 bits to the right for slot 1.
+ const uint64_t l_slot_offset = l_slot * 16;
+
+ // Grab our kind out of the vector
+ auto l_kind = std::find_if(l_dimm_kinds.begin(), l_dimm_kinds.end(), [&l_slot](const dimm::kind & k) -> bool
+ {
+ return mss::index(k.iv_target) == l_slot;
+ });
+
+ // If we don't find the fellow, we have a programming bug as we made the kind vector from the
+ // vector we're iterating over.
+ if (l_kind == l_dimm_kinds.end())
+ {
+ FAPI_ERR("can't find our dimm in the kind vector: l_slot %d %s", l_slot, mss::c_str(d));
+ fapi2::Assert(false);
+ }
+
+ FAPI_DBG("address translation for DIMM %s %dR %dgbx%d (%dG) in slot %d",
+ mss::c_str(d), l_kind->iv_master_ranks, l_kind->iv_dram_density,
+ l_kind->iv_dram_width, l_kind->iv_size, l_slot);
+
+ // Set the proper bit if there is a DIMM in this slot. If there wasn't, we wouldn't see
+ // this DIMM in the vector, so this is always safe.
+ l_xlate.setBit(MCS_PORT02_MCP0XLT0_SLOT0_VALID + l_slot_offset);
+
+ // Find the proper set function based on this DIMM kind.
+ const auto l_setup = std::find_if( xlate_map.begin(), xlate_map.end(), [l_kind](const xlate_setup & x) -> bool
+ {
+ return x.iv_kind == *l_kind;
+ } );
+
+ // If we're the smallest DIMM in the port and we have more than one DIMM, we set our D-bit.
+ if( (l_d_bit_target != d) && (l_dimms.size() > 1) )
+ {
+ FAPI_INF("noting d-bit of 1 for %s", mss::c_str(d));
+ l_xlate.setBit(MCS_PORT13_MCP0XLT0_SLOT0_D_VALUE + l_slot_offset);
+ }
+
+ // If we didn't find it, raise a stink.
+ FAPI_ASSERT( l_setup != xlate_map.end(),
+ fapi2::MSS_NO_XLATE_FOR_DIMM().
+ set_DIMM_IN_ERROR(d).
+ set_MASTER_RANKS(l_kind->iv_master_ranks).
+ set_SLAVE_RANKS(l_kind->iv_slave_ranks).
+ set_DRAM_DENSITY(l_kind->iv_dram_density).
+ set_DRAM_WIDTH(l_kind->iv_dram_width).
+ set_DRAM_GENERATION(l_kind->iv_dram_generation).
+ set_DIMM_TYPE(l_kind->iv_dimm_type).
+ set_ROWS(l_kind->iv_rows).
+ set_SIZE(l_kind->iv_size),
+ "no address translation funtion for DIMM %s %dR %dgbx%d (%dG) in slot %d",
+ mss::c_str(d), l_kind->iv_master_ranks, l_kind->iv_dram_density,
+ l_kind->iv_dram_width, l_kind->iv_size, l_slot );
+
+ // If we did find it, call the translation function to fill in the blanks.
+ // The conditional argument tells the setup function whether this setup sould set the D bit, as we're
+ // the largest DIMM on the port.
+ l_setup->iv_func(*l_kind, l_slot_offset, (l_kind->iv_target == l_d_bit_target), l_xlate, l_xlate1, l_xlate2);
+ }
+
+
+ FAPI_INF("cramming 0x%016lx in for MCP0XLT0", l_xlate);
+ FAPI_INF("cramming 0x%016lx in for MCP0XLT1", l_xlate1);
+ FAPI_INF("cramming 0x%016lx in for MCP0XLT2", l_xlate2);
FAPI_TRY( mss::putScom(i_target, MCA_MBA_MCP0XLT0, l_xlate) );
FAPI_TRY( mss::putScom(i_target, MCA_MBA_MCP0XLT1, l_xlate1) );
@@ -217,5 +380,6 @@ fapi2::ReturnCode setup_xlate_map(const fapi2::Target<TARGET_TYPE_MCA>& i_target
fapi_try_exit:
return fapi2::current_err;
}
+
} // namespace mc
} // namespace mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mc/xlate.H b/src/import/chips/p9/procedures/hwp/memory/lib/mc/xlate.H
index 0046b9155..0ea2e75ca 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/mc/xlate.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mc/xlate.H
@@ -22,3 +22,99 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+///
+/// @file xmalte.H
+/// @brief Definitions for translation registers
+///
+// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
+// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_XLT_H_
+#define _MSS_XLT_H_
+
+#include <fapi2.H>
+
+#include <p9_mc_scom_addresses.H>
+#include <p9_mc_scom_addresses_fld.H>
+
+#include <lib/shared/mss_const.H>
+#include <lib/utils/scom.H>
+#include <lib/utils/c_str.H>
+#include <lib/dimm/kind.H>
+
+namespace mss
+{
+
+namespace mc
+{
+
+///
+/// @brief A small class to represent the setup of a translation register based on DIMM characteristics
+///
+struct xlate_setup
+{
+ ///
+ /// @brief Constructor to make a translation register setup structure.
+ /// @param[in] i_kind a DIMM kind structure representing the ... err... kind of DIMM
+ /// @param[in] i_func a function pointer to a function which does the configuring
+ ///
+ xlate_setup( const dimm::kind i_kind,
+ void (*i_func)( const dimm::kind&, const uint64_t, const bool,
+ fapi2::buffer<uint64_t>&, fapi2::buffer<uint64_t>&, fapi2::buffer<uint64_t>& ) ):
+ iv_kind(i_kind),
+ iv_func(i_func)
+ {
+ }
+
+ // Keep around the kind of DIMM this nugget represents
+ dimm::kind iv_kind;
+
+ // The function to call to setup the translation registers to setup for our DIMM kind.
+ void (*iv_func)( const dimm::kind&, const uint64_t, const bool,
+ fapi2::buffer<uint64_t>&, fapi2::buffer<uint64_t>&, fapi2::buffer<uint64_t>& );
+};
+
+
+///
+/// @brief Perform initializations of the MC translation
+/// @param[in] i_kind the DIMM to map
+/// @param[in] i_offset the offset; whether the DIMM ins slot 0 or slot 1
+/// @param[in] i_largest whether or not we're the largest DIMM on the port.
+/// @param[in] o_xlate a buffer representing the xlate register to modify
+/// @param[in] o_xlate1 a buffer representing the xlate register to modify
+/// @param[in] o_xlate2 a buffer representing the xlate register to modify
+/// @note Called for 2R4Gbx4 DDR4 RDIMM
+///
+void xlate_dimm_2R4Gbx4( const dimm::kind& i_kind,
+ const uint64_t i_offset,
+ const bool i_largest,
+ fapi2::buffer<uint64_t>& o_xlate,
+ fapi2::buffer<uint64_t>& o_xlate1,
+ fapi2::buffer<uint64_t>& o_xlate2 );
+
+///
+/// @brief Perform initializations of the MC translation
+/// @param[in] i_kind the DIMM to map
+/// @param[in] i_offset the offset; whether the DIMM ins slot 0 or slot 1
+/// @param[in] i_largest whether or not we're the largest DIMM on the port.
+/// @param[in] o_xlate a buffer representing the xlate register to modify
+/// @param[in] o_xlate1 a buffer representing the xlate register to modify
+/// @param[in] o_xlate2 a buffer representing the xlate register to modify
+/// @note Called for 1R4Gbx4 DDR4 RDIMM
+///
+void xlate_dimm_1R4Gbx4( const dimm::kind& i_kind,
+ const uint64_t i_offset,
+ const bool i_largest,
+ fapi2::buffer<uint64_t>& o_xlate,
+ fapi2::buffer<uint64_t>& o_xlate1,
+ fapi2::buffer<uint64_t>& o_xlate2 );
+
+} // ns mc
+
+} // ns mss
+
+#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
index 9d7e98c38..000534086 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
@@ -50,6 +50,7 @@ enum sizes
MCBIST_PER_MC = 1,
MAX_DIMM_PER_PORT = 2,
MAX_RANK_PER_DIMM = 4,
+ MAX_RANKS_DIMM1 = 2, ///< DIMM1 (inner DIMM) can't be a 4R DIMM
MAX_PRIMARY_RANKS_PER_PORT = 4,
MAX_MRANK_PER_PORT = MAX_DIMM_PER_PORT * MAX_RANK_PER_DIMM,
RANK_MID_POINT = 4, ///< Which rank number indicates the switch to the other DIMM
@@ -116,6 +117,7 @@ enum states
YES_N = 0,
NO_N = 1,
INVALID = 0xFF,
+ NO_CHIP_SELECT_ACTIVE = 0xFF,
// This needs to be an attribute I think - BRS. Used as a boolean.
CAL_ABORT_ON_ERROR = 1,
OpenPOWER on IntegriCloud