diff options
author | Brian Silver <bsilver@us.ibm.com> | 2016-08-16 14:39:25 -0500 |
---|---|---|
committer | Christian R. Geddes <crgeddes@us.ibm.com> | 2016-09-13 13:57:11 -0400 |
commit | e1072794018dc014dfe3f4737021726daecd397a (patch) | |
tree | 6ef83aa84b9a40d351752b18e93c2221d778fe55 /src | |
parent | 69574021bf9f4f45e4dbd5efb3dbe9d6eb3884e9 (diff) | |
download | talos-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')
6 files changed, 454 insertions, 173 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, diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_lib.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_lib.xml index 4b6610fe4..1160515e8 100644 --- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_lib.xml +++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_lib.xml @@ -374,6 +374,21 @@ </callout> </hwpError> -</hwpErrors> - + <hwpError> + <rc>RC_MSS_NO_XLATE_FOR_DIMM</rc> + <description>Indicates there wasn't an address translation defined for the DIMM</description> + <ffdc>MASTER_RANKS</ffdc> + <ffdc>SLAVE_RANKS</ffdc> + <ffdc>DRAM_DENSITY</ffdc> + <ffdc>DRAM_WIDTH</ffdc> + <ffdc>DRAM_GENERATION</ffdc> + <ffdc>DIMM_TYPE</ffdc> + <ffdc>ROWS</ffdc> + <ffdc>SIZE</ffdc> + <callout> + <target>DIMM_IN_ERROR</target> + <priority>HIGH</priority> + </callout> + </hwpError> +</hwpErrors> |