From e3f7d637814b291cf2f95297ba18f947b45f6dc9 Mon Sep 17 00:00:00 2001 From: Brian Silver Date: Fri, 20 Jan 2017 09:53:24 -0600 Subject: Map from Centaur canonical rank numbering to Nimbus Reassigned rank pairs to be DIMM0 ranks first ZCAL config ODT values from VPD Change-Id: If24e74e9e878c24125540e324cad40a7218c59ff Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/35162 Dev-Ready: Louis Stermole Reviewed-by: Brian R. Silver Tested-by: Jenkins Server Tested-by: Hostboot CI Reviewed-by: STEPHEN GLANCY Reviewed-by: JACOB L. HARVEY Reviewed-by: Jennifer A. Stofer Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/35164 Tested-by: FSP CI Jenkins Tested-by: Jenkins OP Build CI Reviewed-by: Christian R. Geddes --- .../chips/p9/procedures/hwp/memory/lib/dimm/rank.C | 76 ++--- .../chips/p9/procedures/hwp/memory/lib/dimm/rank.H | 324 ++++++++++++++++++++- .../chips/p9/procedures/hwp/memory/lib/mc/port.C | 19 +- .../chips/p9/procedures/hwp/memory/lib/mc/port.H | 32 ++ .../p9/procedures/hwp/memory/lib/phy/ddr_phy.C | 180 +++++++----- .../p9/procedures/hwp/memory/lib/phy/ddr_phy.H | 37 ++- 6 files changed, 533 insertions(+), 135 deletions(-) (limited to 'src/import/chips/p9/procedures/hwp') diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C index 13642122e..011f801b5 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -82,7 +82,7 @@ namespace rank { // -// Static table of rank pair assignments. Some of thoem won't be valid depending on +// Static table of rank pair assignments. Some of them won't be valid depending on // the plug rules (which may be OpenPOWER, IBM, etc.) Some also won't make sense // -- 3 rank DIMM? -- but it doesn't take up much space and lord knows stranger things // have happened ... Won't hurt to have this defined JustInCase(tm). @@ -92,11 +92,11 @@ namespace rank // TODO RTC 160869: Review hard coded values, possibly make into traits? static const std::vector< std::vector< std::pair< uint64_t, uint64_t > > > rank_pair_assignments = { - { {0x0000, 0x0000}, {0x1000, 0x0000}, {0x1030, 0x0000}, {0x1030, 0x5000}, {0x1030, 0x5070} }, - { {0x9000, 0x0000}, {0x1090, 0x0000}, {0x1090, 0x3000}, {0x1090, 0x3050}, {0x1090, 0x5730} }, - { {0x90B0, 0x0000}, {0x1090, 0xB000}, {0x1090, 0x30B0}, {0x1390, 0x50B0}, {0x1390, 0x57B0} }, - { {0x90B0, 0xD000}, {0x1090, 0xB0D0}, {0x109B, 0x30D0}, {0x139B, 0x50D0}, {0x139B, 0x57D0} }, - { {0x90B0, 0xD0F0}, {0x1090, 0xB0DF}, {0x109B, 0x30DF}, {0x139B, 0x50DF}, {0x139B, 0x57DF} }, + { {0x0000, 0x0000}, {0x1000, 0x0000}, {0x1030, 0x0000}, {0x1530, 0x0000}, {0x1537, 0x0000} }, + { {0x0000, 0x9000}, {0x1000, 0x9000}, {0x1030, 0x9000}, {0x1530, 0x9000}, {0x1537, 0x9000} }, + { {0x0000, 0x90B0}, {0x1000, 0x90B0}, {0x1030, 0x90B0}, {0x1530, 0x90B0}, {0x1537, 0x90B0} }, + { {0x0000, 0x9DB0}, {0x1000, 0x9DB0}, {0x1030, 0x9DB0}, {0x1530, 0x9DB0}, {0x1537, 0x9DB0} }, + { {0x0000, 0x9DBF}, {0x1000, 0x9DBF}, {0x1030, 0x9DBF}, {0x1530, 0x9DBF}, {0x1537, 0x9DBF} }, }; // @@ -106,11 +106,11 @@ static const std::vector< std::vector< std::pair< uint64_t, uint64_t > > > rank_ // static const std::vector< std::vector< std::vector< uint64_t > > > primary_rank_pairs = { - { {}, {0}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3} }, - { {4}, {0, 4}, {0, 4, 1}, {0, 4, 2, 1}, {0, 4, 2, 1} }, - { {4, 5}, {0, 4, 5}, {0, 4, 1, 5}, {0, 4, 2, 5}, {0, 4, 2, 5} }, - { {4, 5}, {0, 4, 5}, {0, 4, 1, 5}, {0, 4, 2, 5}, {0, 4, 2, 5} }, - { {4, 5, 6, 7}, {0, 4, 5, 6}, {0, 4, 1, 6}, {0, 4, 2, 6}, {0, 4, 2, 6} }, + { {}, {0}, {0, 1}, {0, 1}, {0, 1} }, + { {NO_RANK, NO_RANK, 4}, {0, NO_RANK, 4}, {0, 1, 4}, {0, 1, 4}, {0, 1, 4} }, + { {NO_RANK, NO_RANK, 4, 5}, {0, NO_RANK, 4, 5}, {0, 1, 4, 5}, {0, 1, 4, 5}, {0, 1, 4, 5} }, + { {NO_RANK, NO_RANK, 4, 5}, {0, NO_RANK, 4, 5}, {0, 1, 4, 5}, {0, 1, 4, 5}, {0, 1, 4, 5} }, + { {NO_RANK, NO_RANK, 4, 5}, {0, NO_RANK, 4, 5}, {0, 1, 4, 5}, {0, 1, 4, 5}, {0, 1, 4, 5} }, }; // @@ -123,17 +123,6 @@ static const std::vector< std::vector< std::vector< uint64_t > > > single_dimm_r { {}, {4}, {4, 5}, {4, 5, 6}, {4, 5, 6, 7} }, }; -// These fields represent the rank fields and valid bits from rank_pair_assignments -constexpr uint64_t EVEN_PRIMARY_RANK = 48; -constexpr uint64_t EVEN_SECONDARY_RANK = 52; -constexpr uint64_t ODD_PRIMARY_RANK = 56; -constexpr uint64_t ODD_SECONDARY_RANK = 60; -constexpr uint64_t RANK_LEN = 3; -constexpr uint64_t EVEN_PRIMARY_VALID = 51; -constexpr uint64_t EVEN_SECONDARY_VALID = 55; -constexpr uint64_t ODD_PRIMARY_VALID = 59; -constexpr uint64_t ODD_SECONDARY_VALID = 63; - /// /// @brief Return true iff this rank is on thie DIMM /// @param[in] i_target representing the DIMM @@ -186,7 +175,7 @@ size_t get_dimm_from_rank(const uint64_t i_rank) } /// -/// @brief Return a vector of rank numbers which represent the primary rank pairs for this dimm +/// @brief Return a vector of rank numbers which represent the primary rank pairs for this port /// @tparam T the target type /// @param[in] i_target TARGET_TYPE_MCA /// @param[out] o_rps a vector of rank_pairs @@ -200,13 +189,23 @@ fapi2::ReturnCode primary_ranks( const fapi2::Target& i_target, // Get the count of rank pairs for both DIMM on the port std::vector l_rank_count(MAX_DIMM_PER_PORT, 0); - for (auto d : i_target.getChildren()) + for (const auto d : mss::find_targets(i_target)) { FAPI_TRY( mss::eff_num_master_ranks_per_dimm(d, l_rank_count[mss::index(d)]) ); } FAPI_DBG("ranks: %d, %d", l_rank_count[0], l_rank_count[1]); - o_rps = primary_rank_pairs[l_rank_count[1]][l_rank_count[0]]; + + // Walk through rank pair table and skip empty pairs + o_rps.clear(); + + for (const auto l_rank : primary_rank_pairs[l_rank_count[1]][l_rank_count[0]]) + { + if (l_rank != NO_RANK) + { + o_rps.push_back(l_rank); + } + } fapi_try_exit: return fapi2::current_err; @@ -229,7 +228,7 @@ fapi2::ReturnCode primary_ranks( const fapi2::Target& i_target o_rps.clear(); - for (auto r : l_prs) + for (const auto r : l_prs) { if (is_rank_on_dimm(i_target, r)) { @@ -272,7 +271,7 @@ fapi2::ReturnCode ranks( const fapi2::Target& i_target, std::ve std::vector< uint64_t > l_ranks; o_ranks.clear(); - for (auto d : i_target.getChildren()) + for (const auto d : mss::find_targets(i_target)) { FAPI_TRY( ranks(d, l_ranks) ); o_ranks.insert(o_ranks.end(), l_ranks.begin(), l_ranks.end()); @@ -300,7 +299,7 @@ fapi2::ReturnCode get_rank_pair_assignments(const fapi2::Target // Get the count of rank pairs for all DIMM on the port std::vector l_rank_count(MAX_DIMM_PER_PORT, 0); - for (auto d : i_target.getChildren()) + for (const auto d : mss::find_targets(i_target)) { FAPI_TRY( mss::eff_num_master_ranks_per_dimm(d, l_rank_count[mss::index(d)]) ); } @@ -423,18 +422,29 @@ fapi_try_exit: template<> fapi2::ReturnCode get_rank_pairs(const fapi2::Target& i_target, std::vector& o_pairs) { - std::vector< uint64_t > l_prs; uint64_t l_index = 0; + std::vector l_prs; - FAPI_TRY( primary_ranks(i_target, l_prs) ); + // Get the count of rank pairs for both DIMM on the port + std::vector l_rank_count(MAX_DIMM_PER_PORT, 0); + for (const auto d : mss::find_targets(i_target)) + { + FAPI_TRY( mss::eff_num_master_ranks_per_dimm(d, l_rank_count[mss::index(d)]) ); + } + + // Walk through rank pair table and skip empty pairs o_pairs.clear(); + l_prs = primary_rank_pairs[l_rank_count[1]][l_rank_count[0]]; // Can't use for (auto rp : l_prs) as rp is unused. BRS for (auto rp_iter = l_prs.begin(); rp_iter != l_prs.end(); ++rp_iter) { - o_pairs.push_back(l_index); - l_index += 1; + if (*rp_iter != NO_RANK) + { + o_pairs.push_back(l_index); + l_index += 1; + } } fapi_try_exit: diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H index 74cfbe566..9ae319a16 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/rank.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -42,6 +42,7 @@ #include #include #include +#include namespace mss { @@ -53,6 +54,18 @@ enum TERTIARY = 2, QUATERNARY = 3, NO_RANK = 999, + + // These enums represent the rank fields and valid bits from rank_pair_assignments + EVEN_PRIMARY_RANK = 48, + EVEN_SECONDARY_RANK = 52, + ODD_PRIMARY_RANK = 56, + ODD_SECONDARY_RANK = 60, + RANK_LEN = 3, + EVEN_PRIMARY_VALID = 51, + EVEN_SECONDARY_VALID = 55, + ODD_PRIMARY_VALID = 59, + ODD_SECONDARY_VALID = 63, + }; /// @@ -289,6 +302,284 @@ class rankPairTraits< fapi2::TARGET_TYPE_MCA, 3 > namespace rank { +/// +/// @brief Maps a rank's canonical number to the proper ordinal number for the PHY +/// @param[in] i_count the number of DIMM to be considered +/// @param[in] i_rank the rank number to be mapped +/// @return the mapped value +// i_rank passed by value to save a local variable in the caller +/// +template +inline uint64_t map_rank_ordinal_to_phy( const size_t i_count, const uint64_t i_rank ); + +/// +/// @brief Maps a rank's canonical number to the proper ordinal number for the PHY +/// @param[in] i_count the number of DIMM to be considered +/// @param[in] i_rank the rank number to be mapped +/// @return the mapped value +// i_rank passed by value to save a local +/// +template <> +inline uint64_t map_rank_ordinal_to_phy( const size_t i_count, const uint64_t i_rank ) +{ + if (i_count == 0) + { + FAPI_ERR("seeing 0 DIMM?"); + fapi2::Assert(false); + } + + if ((i_count == MAX_DIMM_PER_PORT) && (i_rank >= RANK_MID_POINT)) + { + return i_rank - MAX_RANKS_DIMM1; + } + + // Nothing to do in the single drop case. Nothing to do for {0,1} on a dual drop either + return i_rank; +} + +/// +/// @brief Maps a rank's canonical number to the proper ordinal number for the PHY +/// @param[in] i_target the fapi2 target of the MCA +/// @param[in] i_rank the rank number to be mapped +/// @return the mapped value +// i_rank passed by value to save a local +/// +inline uint64_t map_rank_ordinal_to_phy( const fapi2::Target& i_target, const uint64_t i_rank ) +{ + return map_rank_ordinal_to_phy(count_dimm(i_target), i_rank); +} + +/// +/// @brief Maps a ranks canonical number to the proper ordinal number +/// for the PHY +/// @param[in] i_target the fapi2 target of the MBA +/// @param[in] i_rank the rank number to be mapped +/// @return the mapped value +// i_rank passed by value to save a local +/// +inline uint64_t map_rank_ordinal_to_phy( const fapi2::Target& i_target, const uint64_t i_rank ) +{ + // NOOP for Centaur + return i_rank; +} + +/// +/// @brief Maps a rank's canonical number from the proper ordinal number for the PHY +/// @param[in] i_count the number of DIMM to be considered +/// @param[in] i_rank the rank number to be mapped +/// @return the mapped value +// i_rank passed by value to save a local +/// +template +inline uint64_t map_rank_ordinal_from_phy( const size_t i_count, const uint64_t i_rank ); + +/// +/// @brief Maps a rank's canonical number from the proper ordinal number for the PHY +/// @param[in] i_count the number of DIMM to be considered +/// @param[in] i_rank the rank number to be mapped +/// @return the mapped value +// i_rank passed by value to save a local +/// +template <> +inline uint64_t map_rank_ordinal_from_phy( const size_t i_count, const uint64_t i_rank ) +{ + if (i_count == 0) + { + FAPI_ERR("seeing 0 DIMM?"); + fapi2::Assert(false); + } + + if ((i_count == MAX_DIMM_PER_PORT) && ((i_rank + MAX_RANKS_DIMM1) >= RANK_MID_POINT)) + { + return i_rank + MAX_RANKS_DIMM1; + } + + // Nothing to do in the single drop case. Nothing to do for {0,1} on a dual drop either + return i_rank; +} + +/// +/// @brief Maps a rank's canonical number from the proper ordinal number for the PHY +/// @param[in] i_target the fapi2 target of the MCA +/// @param[in] i_rank the rank number to be mapped +/// @return the mapped value +// i_rank passed by value to save a local +/// +inline uint64_t map_rank_ordinal_from_phy( const fapi2::Target& i_target, + const uint64_t i_rank ) +{ + return map_rank_ordinal_from_phy(count_dimm(i_target), i_rank); +} + +/// +/// @brief Maps a ranks canonical number to the proper ordinal number +/// for the PHY +/// @param[in] i_target the fapi2 target of the MBA +/// @param[in] i_rank the rank number to be mapped +/// @return the mapped value +// i_rank passed by value to save a local +/// +inline uint64_t map_rank_ordinal_from_phy( const fapi2::Target& i_target, + const uint64_t i_rank ) +{ + // NOOP for Centaur + return i_rank; +} + +/// +/// @brief Convert rank indexes in a rank_pair reg value from MC perspective to PHY perspective +/// @tparam T fapi2 Target Type the type of the MC target +/// @param[in] i_count the number of DIMM to be considered +/// @param[in] i_rp_reg value of RANK_PAIR register +/// @param[in, out] io_data the register value with mapped rank indexes +/// +template< fapi2::TargetType T > +inline void map_rank_pair_to_phy( const size_t i_count, + const fapi2::buffer& i_rp_reg_value, + fapi2::buffer& io_data ); + +/// +/// @brief Convert rank indexes in a rank_pair reg value from MC perspective to PHY perspective +/// Specialization for TARGET_TYPE_MCA +/// @param[in] i_count the number of DIMM to be considered +/// @param[in] i_rp_reg value of RANK_PAIR register +/// @param[in, out] io_data the register value with mapped rank indexes +/// +template<> +inline void map_rank_pair_to_phy( const size_t i_count, + const fapi2::buffer& i_rp_reg_value, + fapi2::buffer& io_data ) +{ + uint64_t l_rank = 0; + + // copy over so we get the valid bits + io_data = i_rp_reg_value; + + // No mapping necessary if single drop + if (i_count != 1) + { + i_rp_reg_value.extractToRight(l_rank); + l_rank = map_rank_ordinal_to_phy(i_count, l_rank); + io_data.insertFromRight(l_rank); + + i_rp_reg_value.extractToRight(l_rank); + l_rank = map_rank_ordinal_to_phy(i_count, l_rank); + io_data.insertFromRight(l_rank); + + i_rp_reg_value.extractToRight(l_rank); + l_rank = map_rank_ordinal_to_phy(i_count, l_rank); + io_data.insertFromRight(l_rank); + + i_rp_reg_value.extractToRight(l_rank); + l_rank = map_rank_ordinal_to_phy(i_count, l_rank); + io_data.insertFromRight(l_rank); + } +} + +/// +/// @brief Convert rank indexes in a rank_pair reg value from MC perspective to PHY perspective +/// @param[in] i_target the fapi2 target of the MCA +/// @param[in] i_rp_reg value of RANK_PAIR register +/// @param[in, out] io_data the register value with mapped rank indexes +/// +inline void map_rank_pair_to_phy( const fapi2::Target& i_target, + const fapi2::buffer& i_rp_reg_value, + fapi2::buffer& io_data ) +{ + map_rank_pair_to_phy(count_dimm(i_target), i_rp_reg_value, io_data); +} + +/// +/// @brief Convert rank indexes in a rank_pair reg value from MC perspective to PHY perspective +/// @param[in] i_target the fapi2 target of the MCA +/// @param[in] i_rp_reg value of RANK_PAIR register +/// @param[in, out] io_data the register value with mapped rank indexes +/// +inline void map_rank_pair_to_phy( const fapi2::Target& i_target, + const fapi2::buffer& i_rp_reg_value, + fapi2::buffer& io_data ) +{ + // NOOP for Centaur + io_data = i_rp_reg_value; +} + +/// +/// @brief Convert rank indexes in a rank_pair reg value from PHY perspective to MC perspective +/// @tparam T fapi2 Target Type the type of the MC target +/// @param[in] i_count the number of DIMM to be considered +/// @param[in] i_rp_reg value of RANK_PAIR register +/// @param[in, out] io_data the register value with mapped rank indexes +/// +template< fapi2::TargetType T > +inline void map_rank_pair_from_phy( const size_t i_count, + const fapi2::buffer& i_rp_reg_value, + fapi2::buffer& io_data ); + +/// +/// @brief Convert rank indexes in a rank_pair reg value from PHY perspective to MC perspective +/// Specialization for TARGET_TYPE_MCA +/// @param[in] i_count the number of DIMM to be considered +/// @param[in] i_rp_reg value of RANK_PAIR register +/// @param[in, out] io_data the register value with mapped rank indexes +/// +template<> +inline void map_rank_pair_from_phy( const size_t i_count, + const fapi2::buffer& i_rp_reg_value, + fapi2::buffer& io_data ) +{ + uint64_t l_rank = 0; + + // copy over so we get the valid bits + io_data = i_rp_reg_value; + + // No mapping necessary if single drop + if (i_count != 1) + { + i_rp_reg_value.extractToRight(l_rank); + l_rank = map_rank_ordinal_from_phy(i_count, l_rank); + io_data.insertFromRight(l_rank); + + i_rp_reg_value.extractToRight(l_rank); + l_rank = map_rank_ordinal_from_phy(i_count, l_rank); + io_data.insertFromRight(l_rank); + + i_rp_reg_value.extractToRight(l_rank); + l_rank = map_rank_ordinal_from_phy(i_count, l_rank); + io_data.insertFromRight(l_rank); + + i_rp_reg_value.extractToRight(l_rank); + l_rank = map_rank_ordinal_from_phy(i_count, l_rank); + io_data.insertFromRight(l_rank); + } +} + +/// +/// @brief Convert rank indexes in a rank_pair reg value from PHY perspective to MC perspective +/// @param[in] i_target the fapi2 target of the MCA +/// @param[in] i_rp_reg value of RANK_PAIR register +/// @param[in, out] io_data the register value with mapped rank indexes +/// +inline void map_rank_pair_from_phy( const fapi2::Target& i_target, + const fapi2::buffer& i_rp_reg_value, + fapi2::buffer& io_data ) +{ + map_rank_pair_from_phy(count_dimm(i_target), i_rp_reg_value, io_data); +} + +/// +/// @brief Convert rank indexes in a rank_pair reg value from PHY perspective to MC perspective +/// @param[in] i_target the fapi2 target of the MCA +/// @param[in] i_rp_reg value of RANK_PAIR register +/// @param[in, out] io_data the register value with mapped rank indexes +/// +inline void map_rank_pair_from_phy( const fapi2::Target& i_target, + const fapi2::buffer& i_rp_reg_value, + fapi2::buffer& io_data ) +{ + // NOOP for Centaur + io_data = i_rp_reg_value; +} + /// /// @brief Return a vector of rank numbers which represent the ranks for this dimm /// @tparam T the target type you'd like the associated ranks for @@ -379,9 +670,11 @@ fapi2::ReturnCode get_pair_from_rank(const fapi2::Target& i_target, const uin template< uint64_t RP, uint64_t N, fapi2::TargetType T, typename TT = rankPairTraits > inline fapi2::ReturnCode read_rank_pair_reg( const fapi2::Target& i_target, fapi2::buffer& o_data ) { + fapi2::buffer l_buf; static_assert((N < TT::NUM_RANK_PAIR_REGS), "Rank pair register index failed range check"); - FAPI_TRY( mss::getScom(i_target, TT::RANK_PAIR_REGS[N], o_data) ); - FAPI_INF("read_rank_pair_reg: 0x%016lx", o_data); + FAPI_TRY( mss::getScom(i_target, TT::RANK_PAIR_REGS[N], l_buf) ); + FAPI_INF("read_rank_pair_reg: 0x%016lx", l_buf); + map_rank_pair_from_phy(i_target, l_buf, o_data); fapi_try_exit: return fapi2::current_err; } @@ -399,9 +692,11 @@ fapi_try_exit: template< uint64_t RP, uint64_t N, fapi2::TargetType T, typename TT = rankPairTraits > inline fapi2::ReturnCode write_rank_pair_reg( const fapi2::Target& i_target, const fapi2::buffer& i_data ) { + fapi2::buffer l_buf; static_assert((N < TT::NUM_RANK_PAIR_REGS), "Rank pair register index failed range check"); - FAPI_TRY( mss::putScom(i_target, TT::RANK_PAIR_REGS[N], i_data) ); - FAPI_INF("write_rank_pair_reg: 0x%016lx", i_data); + map_rank_pair_to_phy(i_target, i_data, l_buf); + FAPI_TRY( mss::putScom(i_target, TT::RANK_PAIR_REGS[N], l_buf) ); + FAPI_INF("write_rank_pair_reg: 0x%016lx", l_buf); fapi_try_exit: return fapi2::current_err; } @@ -730,10 +1025,15 @@ fapi2::ReturnCode set_ranks_in_pair( const fapi2::Target& i_target, } // Read the rank pair register(s) + fapi2::buffer l_reg; std::vector> l_data; uint64_t l_ordinal = 0; - FAPI_TRY( scom_suckah(i_target, TT::RANK_PAIR_REGS, l_data) ); + // Use the reg API here so we get the PHY to MC rank conversion + FAPI_TRY( (mss::rank::read_rank_pair_reg< RP, 0 >(i_target, l_reg)) ); + l_data.push_back(l_reg); + FAPI_TRY( (mss::rank::read_rank_pair_reg< RP, 1 >(i_target, l_reg)) ); + l_data.push_back(l_reg); // Modify for (const auto l_rank : i_ranks) @@ -750,8 +1050,9 @@ fapi2::ReturnCode set_ranks_in_pair( const fapi2::Target& i_target, ++l_ordinal; } - // Write - FAPI_TRY( scom_blastah(i_target, TT::RANK_PAIR_REGS, l_data) ); + // Use the reg API here so we get the MC to PHY rank conversion + FAPI_TRY( (mss::rank::write_rank_pair_reg< RP, 0 >(i_target, l_data[0])) ); + FAPI_TRY( (mss::rank::write_rank_pair_reg< RP, 1 >(i_target, l_data[1])) ); return fapi2::FAPI2_RC_SUCCESS; @@ -776,9 +1077,14 @@ fapi2::ReturnCode get_ranks_in_pair( const fapi2::Target& i_target, o_ranks.clear(); // Read the rank pair register(s) + fapi2::buffer l_reg; std::vector> l_data; - FAPI_TRY( scom_suckah(i_target, TT::RANK_PAIR_REGS, l_data) ); + // Use the reg API here so we get the PHY to MC rank conversion + FAPI_TRY( (mss::rank::read_rank_pair_reg< RP, 0 >(i_target, l_reg)) ); + l_data.push_back(l_reg); + FAPI_TRY( (mss::rank::read_rank_pair_reg< RP, 1 >(i_target, l_reg)) ); + l_data.push_back(l_reg); // Get data for (uint64_t l_ordinal = 0; l_ordinal < TT::NUM_RANKS_IN_PAIR; ++l_ordinal) diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mc/port.C b/src/import/chips/p9/procedures/hwp/memory/lib/mc/port.C index 942e2c8a5..979ca5eb8 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/mc/port.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/mc/port.C @@ -35,7 +35,6 @@ #include #include -#include #include #include @@ -80,14 +79,13 @@ fapi2::ReturnCode enable_periodic_cal( const fapi2::Target l_per_zqcal_mode_options = 0; fapi2::buffer l_periodic_cal_config; - fapi2::buffer l_phy_zqcal_config; std::vector l_pairs; FAPI_INF("Enable periodic cal"); uint8_t is_sim = 0; - FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target(), is_sim) ); + FAPI_TRY( mss::is_simulation(is_sim) ); // Even if we're in sim, do these so that we do the attribute work (even though the values aren't used.) FAPI_TRY( mss::eff_memcal_interval(i_target, l_memcal_interval) ); @@ -128,8 +126,6 @@ fapi2::ReturnCode enable_periodic_cal( const fapi2::Target l_ranks; - // // Configure the controller // @@ -162,20 +158,11 @@ fapi2::ReturnCode enable_periodic_cal( const fapi2::Target(is_sim ? 0 : 1); - // Write the ZQCAL periodic config - FAPI_INF("zcal periodic config: 0x%016lx", l_phy_zqcal_config); - FAPI_TRY( mss::putScom(i_target, TT::PHY_ZQCAL_REG, l_phy_zqcal_config) ); - // Write the ZQCAL timer reload register // # DPHY01_DDRPHY_PC_ZCAL_TIMER_RELOAD_VALUE_P0 0x00A 0x8000c0090301143f // # PHYW.PHYX.SYNTHX.D3SIDEA.PCX.REG09_L2 @@ -210,7 +197,7 @@ fapi2::ReturnCode enable_periodic_cal( const fapi2::Target #include #include +#include namespace mss { @@ -77,7 +78,10 @@ class portTraits static constexpr uint64_t CAL3Q_REG = MCA_MBA_CAL3Q; static constexpr uint64_t DSM0Q_REG = MCA_MBA_DSM0Q; + // Danger Will Robinson MCA_DDRPHY_PC_PER_ZCAL_CONFIG_P0 uses PHY rank ordinal numbers + // which are different between PHYs. So if you're playing with this register, be sure to map rank numbers. static constexpr uint64_t PHY_ZQCAL_REG = MCA_DDRPHY_PC_PER_ZCAL_CONFIG_P0; + static constexpr uint64_t PHY_PERIODIC_CAL_CONFIG_REG = MCA_DDRPHY_PC_PER_CAL_CONFIG_P0; static constexpr uint64_t PHY_PERIODIC_CAL_RELOAD_REG = MCA_DDRPHY_PC_RELOAD_VALUE0_P0; static constexpr uint64_t PHY_CAL_TIMER_RELOAD_REG = MCA_DDRPHY_PC_CAL_TIMER_RELOAD_VALUE_P0; @@ -602,6 +606,34 @@ fapi_try_exit: return fapi2::current_err; } +/// +/// @brief Reset the ZCAL config register. +/// @warning This maps PHY rank numbers per target +/// @tparam T, the fapi2 target type of the target +/// @param[in] i_target A target representing a port +/// @return FAPI2_RC_SUCCESS if and only if ok +/// +template< fapi2::TargetType T, typename TT = portTraits > +fapi2::ReturnCode reset_zqcal_config( const fapi2::Target& i_target ) +{ + fapi2::buffer l_phy_zqcal_config; + std::vector l_ranks; + + FAPI_TRY( mss::rank::ranks(i_target, l_ranks) ); + + for (const auto r : l_ranks) + { + l_phy_zqcal_config.setBit(TT::PER_ZCAL_ENA_RANK + rank::map_rank_ordinal_to_phy(i_target, r)); + } + + // Write the ZQCAL periodic config + FAPI_INF("zcal periodic config: 0x%016lx", l_phy_zqcal_config); + FAPI_TRY( mss::putScom(i_target, TT::PHY_ZQCAL_REG, l_phy_zqcal_config) ); + +fapi_try_exit: + return fapi2::current_err; +} + }// mss #endif diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C index e58ab08ef..f2ee912bf 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.C @@ -960,17 +960,26 @@ fapi2::ReturnCode setup_cal_config( const fapi2::Target& /// /// @brief Setup odt_wr/rd_config -/// @param[in] i_target the MCA target associated with this cal setup +/// @param[in] i_target the MCA target +/// @param[in] i_dimm_count the number of DIMM presently on the target +/// @param[in] i_odt_rd the RD ODT values from VPD +/// @param[in] i_odt_wr the WR ODT values from VPD /// @return FAPI2_RC_SUCCESS iff setup was successful /// template<> -fapi2::ReturnCode reset_odt_config( const fapi2::Target& i_target ) +fapi2::ReturnCode reset_odt_config_helper( + const fapi2::Target& i_target, + const uint64_t i_dimm_count, + const uint8_t i_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM], + const uint8_t i_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM]) { - uint8_t l_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM]; - uint8_t l_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM]; + // The fields in the ODT VPD are 8 bits wide, but we only use the left-most 2 bits + // of each nibble. The encoding for each rank in the VPD is + // [Dimm0 ODT0][Dimm0 ODT1][N/A][N/A][Dimm1 ODT0][Dimm1 ODT1][N/A][N/A] - FAPI_TRY( mss::vpd_mt_odt_rd(i_target, &(l_odt_rd[0][0])) ); - FAPI_TRY( mss::vpd_mt_odt_wr(i_target, &(l_odt_wr[0][0])) ); + constexpr uint64_t BIT_FIELD0_START = 0; + constexpr uint64_t BIT_FIELD1_START = 4; + constexpr uint64_t BIT_FIELD_LENGTH = 2; // Nimbus PHY is more or less hard-wired for 2 DIMM/port 4R/DIMM // So there's not much point in looping over DIMM or ranks. @@ -983,56 +992,57 @@ fapi2::ReturnCode reset_odt_config( const fapi2::Target& // 48:55, ATTR_VPD_ODT_RD[0][0][0]; # when Read of Rank0 // 56:63, ATTR_VPD_ODT_RD[0][0][1]; # when Read of Rank1 fapi2::buffer l_data; + uint8_t l_vpd_0 = 0; + uint8_t l_vpd_1 = 0; - l_data.insertFromRight(l_odt_rd[0][0]); - l_data.insertFromRight(l_odt_rd[0][1]); + // Extract the 2 DIMM0 bits we need from the VPD. + fapi2::buffer(i_odt_rd[0][0]).extract(l_vpd_0); + fapi2::buffer(i_odt_rd[0][1]).extract(l_vpd_1); + // Extract the 2 DIMM1 bits we need from the VPD. + fapi2::buffer(i_odt_rd[0][0]).extract(l_vpd_0); + fapi2::buffer(i_odt_rd[0][1]).extract(l_vpd_1); + + FAPI_DBG("vpd: 0x%02x extract: 0x%02x", i_odt_rd[0][0], l_vpd_0); + FAPI_DBG("vpd: 0x%02x extract: 0x%02x", i_odt_rd[0][1], l_vpd_1); + + l_data.insert(l_vpd_0); + l_data.insert(l_vpd_1); FAPI_INF("odt_rd_config0: 0x%016llx", uint64_t(l_data)); FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG0_P0, l_data) ); } + // Remember Centaur-canonical rank numbering is different from Nimbus numbering. Here, + // we need to lay the canonically defined VPD into the proper subfield based on DIMM config. { - // DPHY01_DDRPHY_SEQ_ODT_RD_CONFIG1_P0 - // 48:55, ATTR_VPD_ODT_RD[0][0][2]; # when Read of Rank2 - // 56:63, ATTR_VPD_ODT_RD[0][0][3]; # when Read of Rank3 - fapi2::buffer l_data; + // "dual drop" which means what is in the VPD as ranks 4/5 go in to 2/3 + fapi2::buffer l_values2 = (i_dimm_count == MAX_DIMM_PER_PORT) ? i_odt_rd[1][0] : i_odt_rd[0][2]; + fapi2::buffer l_values3 = (i_dimm_count == MAX_DIMM_PER_PORT) ? i_odt_rd[1][1] : i_odt_rd[0][3]; - l_data.insertFromRight(l_odt_rd[0][2]); - l_data.insertFromRight(l_odt_rd[0][3]); - FAPI_INF("odt_rd_config1: 0x%016llx", uint64_t(l_data)); - FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0, l_data) ); - } + uint8_t l_vpd_2 = 0; + uint8_t l_vpd_3 = 0; + + // Extract the 2 DIMM0 bits we need from the VPD. + l_values2.extract(l_vpd_2); + l_values3.extract(l_vpd_3); + // Extract the 2 DIMM1 bits we need from the VPD. + l_values2.extract(l_vpd_2); + l_values3.extract(l_vpd_3); + + FAPI_DBG("vpd: 0x%02x extract: 0x%02x", l_values2, l_vpd_2); + FAPI_DBG("vpd: 0x%02x extract: 0x%02x", l_values3, l_vpd_3); - { // DPHY01_DDRPHY_SEQ_ODT_RD_CONFIG2_P0 // 48:55, ATTR_VPD_ODT_RD[0][1][0]; # when Read of Rank4 // 56:63, ATTR_VPD_ODT_RD[0][1][1]; # when Read of Rank5 fapi2::buffer l_data; - l_data.insertFromRight(l_odt_rd[1][0]); - l_data.insertFromRight(l_odt_rd[1][1]); - FAPI_INF("odt_rd_config2: 0x%016llx", uint64_t(l_data)); - FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG2_P0, l_data) ); + l_data.insert(l_vpd_2); + l_data.insert(l_vpd_3); + FAPI_INF("odt_rd_config1: 0x%016llx", uint64_t(l_data)); + FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG1_P0, l_data) ); } - { - // DPHY01_DDRPHY_SEQ_ODT_RD_CONFIG3_P0 - // 48:55, ATTR_VPD_ODT_RD[0][1][2]; # when Read of Rank6 - // 56:63, ATTR_VPD_ODT_RD[0][1][3]; # when Read of Rank7 - fapi2::buffer l_data; - - l_data.insertFromRight(l_odt_rd[1][2]); - l_data.insertFromRight(l_odt_rd[1][3]); - FAPI_INF("odt_rd_config3: 0x%016llx", uint64_t(l_data)); - FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_RD_CONFIG3_P0, l_data) ); - } + // TODO RTC:167929 Can ODT VPD processing be shared between RD and WR? // // ODT Write @@ -1042,56 +1052,76 @@ fapi2::ReturnCode reset_odt_config( const fapi2::Target& // 48:55, ATTR_VPD_ODT_WR[0][0][0]; # when Read of Rank0 // 56:63, ATTR_VPD_ODT_WR[0][0][1]; # when Read of Rank1 fapi2::buffer l_data; + uint8_t l_vpd_0 = 0; + uint8_t l_vpd_1 = 0; + + // Extract the 2 DIMM0 bits we need from the VPD. + fapi2::buffer(i_odt_wr[0][0]).extract(l_vpd_0); + fapi2::buffer(i_odt_wr[0][1]).extract(l_vpd_1); + // Extract the 2 DIMM1 bits we need from the VPD. + fapi2::buffer(i_odt_wr[0][0]).extract(l_vpd_0); + fapi2::buffer(i_odt_wr[0][1]).extract(l_vpd_1); + + FAPI_DBG("vpd: 0x%02x extract: 0x%02x", i_odt_wr[0][0], l_vpd_0); + FAPI_DBG("vpd: 0x%02x extract: 0x%02x", i_odt_wr[0][1], l_vpd_1); - l_data.insertFromRight(l_odt_wr[0][0]); - l_data.insertFromRight(l_odt_wr[0][1]); + l_data.insert(l_vpd_0); + l_data.insert(l_vpd_1); FAPI_INF("odt_wr_config0: 0x%016llx", uint64_t(l_data)); FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG0_P0, l_data) ); } { - // DPHY01_DDRPHY_SEQ_ODT_WR_CONFIG1_P0 - // 48:55, ATTR_VPD_ODT_WR[0][0][2]; # when Read of Rank2 - // 56:63, ATTR_VPD_ODT_WR[0][0][3]; # when Read of Rank3 - fapi2::buffer l_data; + // "dual drop" which means what is in the VPD as ranks 4/5 go in to 2/3 + fapi2::buffer l_values2 = (i_dimm_count == MAX_DIMM_PER_PORT) ? i_odt_wr[1][0] : i_odt_wr[0][2]; + fapi2::buffer l_values3 = (i_dimm_count == MAX_DIMM_PER_PORT) ? i_odt_wr[1][1] : i_odt_wr[0][3]; - l_data.insertFromRight(l_odt_wr[0][2]); - l_data.insertFromRight(l_odt_wr[0][3]); - FAPI_INF("odt_wr_config1: 0x%016llx", uint64_t(l_data)); - FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0, l_data) ); - } + uint8_t l_vpd_2 = 0; + uint8_t l_vpd_3 = 0; + + // Extract the 2 DIMM0 bits we need from the VPD. + l_values2.extract(l_vpd_2); + l_values3.extract(l_vpd_3); + // Extract the 2 DIMM1 bits we need from the VPD. + l_values2.extract(l_vpd_2); + l_values3.extract(l_vpd_3); + + FAPI_DBG("vpd: 0x%02x extract: 0x%02x", l_values2, l_vpd_2); + FAPI_DBG("vpd: 0x%02x extract: 0x%02x", l_values3, l_vpd_3); - { // DPHY01_DDRPHY_SEQ_ODT_WR_CONFIG2_P0 // 48:55, ATTR_VPD_ODT_WR[0][1][0]; # when Read of Rank4 // 56:63, ATTR_VPD_ODT_WR[0][1][1]; # when Read of Rank5 fapi2::buffer l_data; - l_data.insertFromRight(l_odt_wr[1][0]); - l_data.insertFromRight(l_odt_wr[1][1]); - FAPI_INF("odt_wr_config2: 0x%016llx", uint64_t(l_data)); - FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG2_P0, l_data) ); + l_data.insert(l_vpd_2); + l_data.insert(l_vpd_3); + FAPI_INF("odt_wr_config1: 0x%016llx", uint64_t(l_data)); + FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG1_P0, l_data) ); } - { - // DPHY01_DDRPHY_SEQ_ODT_WR_CONFIG3_P0 - // 48:55, ATTR_VPD_ODT_WR[0][1][2]; # when Read of Rank6 - // 56:63, ATTR_VPD_ODT_WR[0][1][3]; # when Read of Rank7 - fapi2::buffer l_data; +fapi_try_exit: + return fapi2::current_err; +} - l_data.insertFromRight(l_odt_wr[1][2]); - l_data.insertFromRight(l_odt_wr[1][3]); - FAPI_INF("odt_wr_config3: 0x%016llx", uint64_t(l_data)); - FAPI_TRY( mss::putScom(i_target, MCA_DDRPHY_SEQ_ODT_WR_CONFIG3_P0, l_data) ); - } +/// +/// @brief Setup odt_wr/rd_config, reads attributes +/// @param[in] i_target the MCA target associated with this cal setup +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template<> +fapi2::ReturnCode reset_odt_config( const fapi2::Target& i_target ) +{ + uint8_t l_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM]; + uint8_t l_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM]; + + uint64_t l_dimm_count = count_dimm(i_target); + + FAPI_TRY( mss::vpd_mt_odt_rd(i_target, &(l_odt_rd[0][0])) ); + FAPI_TRY( mss::vpd_mt_odt_wr(i_target, &(l_odt_wr[0][0])) ); + + return reset_odt_config_helper( + i_target, l_dimm_count, l_odt_rd, l_odt_wr); fapi_try_exit: return fapi2::current_err; diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H index 075db9781..7f0d9042f 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -149,9 +149,42 @@ fapi2::ReturnCode setup_cal_config( const fapi2::Target& const uint64_t i_rank, const fapi2::buffer i_cal_steps_enabled); +// TODO RTC: 157753 tparams P and R can be pulled from an MCA trait once we have it /// /// @brief Setup odt_wr/rd_config /// @tparam T the target type of the MCA/MBA +/// @tparam P the maximum DIMM per T +/// @tparam R the maximum rank per DIMM on T +/// @param[in] i_target the target +/// @param[in] i_dimm_count the number of DIMM presently on the target +/// @param[in] i_odt_rd the RD ODT values from VPD +/// @param[in] i_odt_wr the WR ODT values from VPD +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template< fapi2::TargetType T, uint64_t P, uint64_t R > +fapi2::ReturnCode reset_odt_config_helper( const fapi2::Target& i_target, + const uint64_t i_dimm_count, + const uint8_t i_odt_rd[P][R], + const uint8_t i_odt_wr[P][R] ); + +/// +/// @brief Setup odt_wr/rd_config +/// @param[in] i_target the MCA target +/// @param[in] i_dimm_count the number of DIMM presently on the target +/// @param[in] i_odt_rd the RD ODT values from VPD +/// @param[in] i_odt_wr the WR ODT values from VPD +/// @return FAPI2_RC_SUCCESS iff setup was successful +/// +template<> +fapi2::ReturnCode reset_odt_config_helper( + const fapi2::Target& i_target, + const uint64_t i_dimm_count, + const uint8_t i_odt_rd[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM], + const uint8_t i_odt_wr[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM]); + +/// +/// @brief Setup odt_wr/rd_config, reads attributes +/// @tparam T the target type of the MCA/MBA /// @param[in] i_target the target associated with this cal setup /// @return FAPI2_RC_SUCCESS iff setup was successful /// @@ -159,7 +192,7 @@ template< fapi2::TargetType T > fapi2::ReturnCode reset_odt_config( const fapi2::Target& i_target ); /// -/// @brief Setup odt_wr/rd_config +/// @brief Setup odt_wr/rd_config, reads attributes /// @param[in] i_target the MCA target associated with this cal setup /// @return FAPI2_RC_SUCCESS iff setup was successful /// -- cgit v1.2.1