diff options
author | Stephen Glancy <sglancy@us.ibm.com> | 2018-08-02 16:35:37 -0500 |
---|---|---|
committer | Christian R. Geddes <crgeddes@us.ibm.com> | 2018-08-20 16:15:21 -0500 |
commit | 28b83673a11719bac517edb613f01a6ee9bfe566 (patch) | |
tree | 9da5c5789c907854829b13ad2800bfbabd318eb4 /src/import/generic/memory/lib/utils | |
parent | 1b5a02cab7f8c7f0de2536a46ae8c8448023e484 (diff) | |
download | talos-hostboot-28b83673a11719bac517edb613f01a6ee9bfe566.tar.gz talos-hostboot-28b83673a11719bac517edb613f01a6ee9bfe566.zip |
Moves conversions to be in the generic code space
Change-Id: Id0270a97066a06615b165ccd8c84e444d134394e
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/63845
Dev-Ready: STEPHEN GLANCY <sglancy@us.ibm.com>
Reviewed-by: Louis Stermole <stermole@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: HWSV CI <hwsv-ci+hostboot@us.ibm.com>
Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com>
Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com>
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/64048
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Diffstat (limited to 'src/import/generic/memory/lib/utils')
-rw-r--r-- | src/import/generic/memory/lib/utils/conversions.H | 337 | ||||
-rw-r--r-- | src/import/generic/memory/lib/utils/find.H | 30 | ||||
-rw-r--r-- | src/import/generic/memory/lib/utils/poll.H | 1 | ||||
-rw-r--r-- | src/import/generic/memory/lib/utils/shared/mss_generic_consts.H | 66 |
4 files changed, 401 insertions, 33 deletions
diff --git a/src/import/generic/memory/lib/utils/conversions.H b/src/import/generic/memory/lib/utils/conversions.H new file mode 100644 index 000000000..efbb53a47 --- /dev/null +++ b/src/import/generic/memory/lib/utils/conversions.H @@ -0,0 +1,337 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/import/generic/memory/lib/utils/conversions.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// +/// @file conversions.H +/// @brief Functions to convert units +/// +// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com> +// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 3 +// *HWP Consumed by: HB:FSP + +#ifndef _MSS_CONVERSIONS_H_ +#define _MSS_CONVERSIONS_H_ + +#include <vector> +#include <fapi2.H> +#include <generic/memory/lib/utils/shared/mss_generic_consts.H> +#include <generic/memory/lib/utils/find.H> + +/// +/// @brief Dereferences pointer of the vector's underlying data +// and casts it to uint8_t[Y] that FAPI_ATTR_SET is expecting by deduction +/// @param[in] X is the input vector +/// @param[in] Y is the size of the vector +/// @warn compiler doesn't like the use of vector method size() for the second param +/// +#define UINT8_VECTOR_TO_1D_ARRAY(X, Y)\ + reinterpret_cast<uint8_t(&)[Y]>(*X.data()) + +/// +/// @brief Dereferences pointer of the vector's underlying data +// and casts it to uint16_t[Y] that FAPI_ATTR_SET is expecting by deduction +/// @param[in] X is the input vector +/// @param[in] Y is the size of the vector +/// @warn compiler doesn't like the use of vector method size() for the second param +/// +#define UINT16_VECTOR_TO_1D_ARRAY(X, Y)\ + reinterpret_cast<uint16_t(&)[Y]>(*X.data()) + +/// +/// @brief Dereferences pointer of the vector's underlying data +// and casts it to uint32_t[Y] that FAPI_ATTR_SET is expecting by deduction +/// @param[in] X is the input vector +/// @param[in] Y is the size of the vector +/// @warn compiler doesn't like the use of vector method size() for the second param +/// +#define UINT32_VECTOR_TO_1D_ARRAY(X, Y)\ + reinterpret_cast<uint32_t(&)[Y]>(*X.data()) + + +// Mutiplication factor to go from clocks to simcycles. +// Is this just 2400 speed or does this hold for all? BRS +static const uint64_t SIM_CYCLES_PER_CYCLE = 8; + +namespace mss +{ + +namespace dram_freq +{ +// +// DRAM clock and frequency information +// +static const std::vector<std::pair<uint64_t, uint64_t>> FREQ_TO_CLOCK_PERIOD = +{ + {DIMM_SPEED_1600, 1250}, // DDR4 + {DIMM_SPEED_1866, 1071}, // DDR4 + {DIMM_SPEED_2133, 937}, // DDR4 + {DIMM_SPEED_2400, 833}, // DDR4 + {DIMM_SPEED_2666, 750}, // DDR4 + {DIMM_SPEED_2933, 682}, // DDR4 + {DIMM_SPEED_3200, 625}, // DDR4/5 + {DIMM_SPEED_3600, 555}, // DDR5 + {DIMM_SPEED_4000, 500}, // DDR5 + {DIMM_SPEED_4400, 454}, // DDR5 + {DIMM_SPEED_4800, 416}, // DDR5 +}; +} + +/// +/// @brief Return the number of picoseconds +/// @tparam T input type +/// @tparam OT output type +/// @param[in] i_speed_grade input in MegaTransfers per second (MT/s) +/// @param[out] o_tCK_in_ps +/// @return FAPI2_RC_SUCCESS if okay +/// +template<typename T, typename OT> +inline fapi2::ReturnCode freq_to_ps(const T i_speed_grade, OT& o_tCK_in_ps ) +{ + // We need to have at least two bytes of data, due to the sizes of the frequencies and clock periods + constexpr size_t MIN_BYTE_SIZE = 2; + static_assert(sizeof(T) >= MIN_BYTE_SIZE && sizeof(OT) >= MIN_BYTE_SIZE, + "Input and output must be at least 2 bytes in length"); + + // Temporary variables to help with the conversion + const uint64_t l_input = static_cast<uint64_t>(i_speed_grade); + uint64_t l_output = 0; + + FAPI_ASSERT(find_value_from_key(dram_freq::FREQ_TO_CLOCK_PERIOD, l_input, l_output), + fapi2::MSS_INVALID_FREQUENCY() + .set_FREQ(l_input), + "Frequency %u does not have an associated clock period", l_input); + + // Cast the output type + o_tCK_in_ps = static_cast<OT>(l_output); + + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Return the number in MT/s +/// @tparam T input type +/// @tparam OT output type +/// @param[in] i_time_in_ps time in picoseconds +/// @param[out] o_speed_grade transfer rate in MT/s +/// @return FAPI2_RC_SUCCESS if okay +/// +template<typename T, typename OT> +fapi2::ReturnCode ps_to_freq(const T i_time_in_ps, OT& o_speed_grade) +{ + // We need to have at least two bytes of data, due to the sizes of the frequencies and clock periods + constexpr size_t MIN_BYTE_SIZE = 2; + static_assert(sizeof(T) >= MIN_BYTE_SIZE && sizeof(OT) >= MIN_BYTE_SIZE, + "Input and output must be at least 2 bytes in length"); + + // Temporary variables to help with the conversion + const uint64_t l_input = static_cast<uint64_t>(i_time_in_ps); + uint64_t l_output = 0; + + FAPI_ASSERT(find_key_from_value(dram_freq::FREQ_TO_CLOCK_PERIOD, l_input, l_output), + fapi2::MSS_INVALID_CLOCK_PERIOD() + .set_CLOCK_PERIOD(l_input), + "Clock period %u does not have an associated frequency", l_input); + + // Cast the output type + o_speed_grade = static_cast<OT>(l_output); + + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; + +} + +/// +/// @brief Translate from cycles to sim cycles +/// @param[in] i_cycles the cycles to translate +/// @return uint64_t, the number of sim cycles. +/// +inline uint64_t cycles_to_simcycles( const uint64_t i_cycles ) +{ + // Is this always the case or do we need the freq to really figure this out? + return i_cycles * SIM_CYCLES_PER_CYCLE; +} + +/// +/// @brief Return the number of cycles contained in a count of picoseconds +/// @tparam T clock period input type +/// @tparam OT the output type, derrived from the parameters +/// @param[in] i_clock_period clock period in PS +/// @param[in] i_ps the number of picoseconds to convert +/// @return the number of cycles +/// +template< typename T, typename OT > +inline OT ps_to_cycles(const T i_clock_period, const OT i_ps) +{ + // Casts the clock period to be in OT type to avoid any weird math issues + const auto l_divisor = static_cast<OT>(i_clock_period); + + const OT l_rounder = (i_ps < 0) ? -1 : 1; + + // Ensure we don't divide by 0 + const OT l_quotient = i_ps / ((i_clock_period == 0) ? l_rounder : l_divisor); + const OT l_remainder = i_ps % ((i_clock_period == 0) ? 1 : l_divisor); + + // Make sure we add a cycle if there wasn't an even number of cycles in the input + FAPI_INF("converting %llups to %llu cycles", i_ps, l_quotient + (l_remainder == 0 ? 0 : l_rounder)); + + return l_quotient + (l_remainder == 0 ? 0 : l_rounder); +} + +/// +/// @brief Return the number of ps contained in a count of cycles +/// @param[in] i_clock_period +/// @param[in] i_cycles the number of cycles to convert +/// @return uint64_t, the number of picoseconds +/// +inline uint64_t cycles_to_ps(const uint64_t i_clock_period, const uint64_t i_cycles) +{ + const auto l_ps = i_cycles * i_clock_period; + FAPI_INF("converting %llu cycles to %llups", i_cycles, l_ps ); + return l_ps; +} + +/// +/// @brief Return the number of cycles contained in a count of microseconds +/// @param[in] i_clock_period the clock period in PS +/// @param[in] i_us the number of microseconds to convert +/// @return uint64_t, the number of cycles +/// +inline uint64_t us_to_cycles(const uint64_t i_clock_period, const uint64_t i_us) +{ + return ps_to_cycles(i_clock_period, i_us * CONVERT_PS_IN_A_US); +} + +/// +/// @brief Return the number of cycles contained in a count of nanoseconds +/// @param[in] i_clock_period the clock period in PS +/// @param[in] i_ps the number of nanoseconds to convert +/// @return uint64_t, the number of cycles +/// +inline uint64_t ns_to_cycles(const uint64_t i_clock_period, const uint64_t i_ns) +{ + return ps_to_cycles(i_clock_period, i_ns * CONVERT_PS_IN_A_NS); +} + +/// +/// @brief Return the number of microseconds contained in a count of cycles +/// @tparam D the time conversion (NS_IN_PS, etc) +/// @param[in] i_clock_period the clock period in PS +/// @param[in] i_cycles the number of cycles to convert +/// @return uint64_t, the number of microseconds +/// +template< uint64_t D > +inline uint64_t cycles_to_time(const uint64_t i_clock_period, const uint64_t i_cycles) +{ + // Hoping the compiler figures out how to do these together. + const auto l_dividend = cycles_to_ps(i_clock_period, i_cycles); + constexpr uint64_t DIVISOR = ((D == 0) ? 1 : D); + const uint64_t l_quotient = l_dividend / DIVISOR; + const uint64_t l_remainder = l_dividend % DIVISOR; + + // Make sure we add time if there wasn't an even number of cycles + return l_quotient + (l_remainder == 0 ? 0 : 1); +} + +/// +/// @brief Return the number of nanoseconds contained in a count of cycles +/// @tparam T the target type +/// @tparam MC memory controller type +/// @param[in] i_clock_period the clock period in PS +/// @param[in] i_cycles the number of cycles to convert +/// @return uint64_t, the number of nanoseconds +/// +inline uint64_t cycles_to_ns(const uint64_t i_clock_period, const uint64_t i_cycles) +{ + const uint64_t l_ns = cycles_to_time<CONVERT_PS_IN_A_NS>(i_clock_period, i_cycles); + FAPI_INF("converting %llu cycles to %lluns", i_cycles, l_ns); + + return l_ns; +} + +/// +/// @brief Return the number of microseconds contained in a count of cycles +/// @param[in] i_clock_period the clock period in PS +/// @param[in] i_cycles the number of cycles to convert +/// @return uint64_t, the number of microseconds +/// +inline uint64_t cycles_to_us(const uint64_t i_clock_period, const uint64_t i_cycles) +{ + const uint64_t l_us = cycles_to_time<CONVERT_PS_IN_A_US>(i_clock_period, i_cycles); + FAPI_INF("converting %llu cycles to %lluus", i_cycles, l_us); + + return l_us; +} + +/// +/// @brief Convert nanoseconds to picoseconds +/// @tparam T input and output type +/// @param[in] i_time_in_ns time in nanoseconds +/// @return time in picoseconds +/// +template<typename T> +inline T ns_to_ps(const T i_time_in_ns) +{ + return i_time_in_ns * CONVERT_PS_IN_A_NS; +} + +/// +/// @brief Convert nanoseconds to picoseconds +/// @tparam T input and output type +/// @param[in] i_time_in_ps time in picoseconds +/// @return time in nanoseconds +/// @note rounds up +/// +template<typename T> +inline T ps_to_ns(const T i_time_in_ps) +{ + T remainder = i_time_in_ps % CONVERT_PS_IN_A_NS; + T l_time_in_ns = i_time_in_ps / CONVERT_PS_IN_A_NS; + + // Round up if remainder isn't even + return l_time_in_ns + ( remainder == 0 ? 0 : 1 ); +} + +/// +/// @brief Return the maximum of two values *in clocks*, the first in clocks the second in ns +/// @param[in] i_clock_period the clock period in PS +/// @param[in] i_clocks a value in clocks +/// @param[in] i_time a value in nanoseconds +/// @return max( iclocks nCK, i_time ) in clocks +/// +inline uint64_t max_ck_ns(const uint64_t i_clock_period, const uint64_t i_clocks, const uint64_t i_time) +{ + return std::max( i_clocks, ns_to_cycles(i_clock_period, i_time) ); +} + +} // mss namespace + +#endif diff --git a/src/import/generic/memory/lib/utils/find.H b/src/import/generic/memory/lib/utils/find.H index b8d6c7976..cb0ffab15 100644 --- a/src/import/generic/memory/lib/utils/find.H +++ b/src/import/generic/memory/lib/utils/find.H @@ -535,7 +535,8 @@ bool find_value_from_key(const std::vector<std::pair<T, OT> >& i_vector_of_pairs // Did you find it? Let me know. if( (l_value_iterator == i_vector_of_pairs.end()) || (i_key != l_value_iterator->first) ) { - FAPI_INF("Did not find a mapping value to key: %d", i_key); + // Static cast ensures that the below print will not fail at compile time + FAPI_INF("Did not find a mapping value to key: %d", static_cast<uint64_t>(i_key)); return false; } @@ -551,12 +552,12 @@ bool find_value_from_key(const std::vector<std::pair<T, OT> >& i_vector_of_pairs /// @param[in] i_vector_of_pairs the input vector of pairs /// @param[in] i_value the "map" value, the second entry in the pairs /// @param[out] o_key the first entry in the pair -/// @return fapi2 ReturnCode fapi2::RC_SUCCESS if value found +/// @return true if value is found, false otherwise /// template<typename T, typename OT> -fapi2::ReturnCode find_key_from_value(const std::vector<std::pair<T, OT> >& i_vector_of_pairs, - const OT& i_value, - T& o_key) +bool find_key_from_value(const std::vector<std::pair<T, OT> >& i_vector_of_pairs, + const OT& i_value, + T& o_key) { // Comparator lambda expression const auto compare = [&i_value](const std::pair<T, OT>& i_lhs) @@ -572,12 +573,13 @@ fapi2::ReturnCode find_key_from_value(const std::vector<std::pair<T, OT> >& i_ve // Did you find it? Let me know. if( (l_value_iterator == i_vector_of_pairs.end()) || (i_value != l_value_iterator->second) ) { - FAPI_ERR("Did not find a mapping key to value: %d", i_value); - return fapi2::FAPI2_RC_INVALID_PARAMETER; + // Static cast ensures that the below print will not fail at compile time + FAPI_INF("Did not find a mapping key to value: %d", static_cast<uint64_t>(i_value)); + return false; } o_key = l_value_iterator->first; - return fapi2::FAPI2_RC_SUCCESS; + return true; }// find_value_from_key @@ -589,13 +591,13 @@ fapi2::ReturnCode find_key_from_value(const std::vector<std::pair<T, OT> >& i_ve /// @param[in] i_array the input array of pairs /// @param[in] i_key the "map" key /// @param[in] o_value the value found from given key -/// @return fapi2 ReturnCode fapi2::RC_SUCCESS if key found +/// @return true if value is found, false otherwise /// @note To use on short arrays. O(N), simple search /// template<typename T, typename OT, size_t N> -fapi2::ReturnCode find_value_from_key( const std::pair<T, OT> (&i_array)[N], - const T& i_key, - OT& o_value) +bool find_value_from_key( const std::pair<T, OT> (&i_array)[N], + const T& i_key, + OT& o_value) { // TK Use sort and binary search for larger arrays for (size_t i = 0; i < N; i++) @@ -603,12 +605,12 @@ fapi2::ReturnCode find_value_from_key( const std::pair<T, OT> (&i_array)[N], if (i_array[i].first == i_key) { o_value = i_array[i].second; - return fapi2::FAPI2_RC_SUCCESS; + return true; } } FAPI_ERR ("No match found for find_value_from_key"); - return fapi2::FAPI2_RC_INVALID_PARAMETER; + return false; } /// diff --git a/src/import/generic/memory/lib/utils/poll.H b/src/import/generic/memory/lib/utils/poll.H index 60322724e..061e462ae 100644 --- a/src/import/generic/memory/lib/utils/poll.H +++ b/src/import/generic/memory/lib/utils/poll.H @@ -40,7 +40,6 @@ #include <generic/memory/lib/utils/scom.H> #include <lib/shared/mss_const.H> -#include <lib/utils/conversions.H> namespace mss { diff --git a/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H b/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H index 9952519c8..ac7b104bd 100644 --- a/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H +++ b/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H @@ -43,20 +43,6 @@ namespace mss { /// -/// @brief Common conversions -/// -enum conversions -{ - CONVERT_PS_IN_A_NS = 1000, ///< 1000 pico in an nano - CONVERT_PS_IN_A_US = 1000000, ///< 1000000 picos in a micro - MHZ_TO_KHZ = 1000, - SEC_IN_HOUR = 60 * 60, ///< seconds in an hour, used for scrub times - NIBBLES_PER_BYTE = 2, - BITS_PER_NIBBLE = 4, - BITS_PER_BYTE = 8, -}; - -/// /// @brief FFDC generic codes /// enum generic_ffdc_codes @@ -93,8 +79,8 @@ enum generic_ffdc_codes TWTR_L_MIN = 0x101A, DEVICE_TYPE = 0x101B, BASE_MODULE_TYPE = 0x101C, - BAD_SPD_DATA = 0x101C, - SET_FIELD = 0x101D, + BAD_SPD_DATA = 0x101D, + SET_FIELD = 0x101E, }; /// @@ -107,10 +93,22 @@ enum proc_type }; /// -/// @brief JEDEC supported DDR4 speeds +/// @brief Supported memory controller types +/// +enum class mc_type +{ + NIMBUS, + CENTAUR, + EXPLORER, +}; + +/// +/// @brief JEDEC supported DDR speeds +/// @note Includes DDR4 and DDR5 only /// -enum ddr4_dimm_speeds +enum ddr_dimm_speeds { + // Supported frequencies DIMM_SPEED_1600 = 1600, DIMM_SPEED_1866 = 1866, DIMM_SPEED_2133 = 2133, @@ -118,6 +116,16 @@ enum ddr4_dimm_speeds DIMM_SPEED_2666 = 2666, DIMM_SPEED_2933 = 2933, DIMM_SPEED_3200 = 3200, + DIMM_SPEED_3600 = 3600, + DIMM_SPEED_4000 = 4000, + DIMM_SPEED_4400 = 4400, + DIMM_SPEED_4800 = 4800, + + // Max/Mins for specific generations here + DDR4_MIN_SPEED = 1600, + DDR4_MAX_SPEED = 3200, + DDR5_MIN_SPEED = 3200, + DDR5_MAX_SPEED = 4800, }; namespace spd @@ -182,6 +190,28 @@ enum guard_band : uint16_t }; }// spd + +enum conversions +{ + NIBBLES_PER_BYTE = 2, + BITS_PER_NIBBLE = 4, + BITS_PER_BYTE = 8, + + CONVERT_PS_IN_A_NS = 1000, ///< 1000 pico in an nano + CONVERT_PS_IN_A_US = 1000000, ///< 1000000 picos in a micro + + DELAY_1NS = 1, + DELAY_10NS = 10 , ///< general purpose 10 ns delay for HW mode + DELAY_100NS = 100, ///< general purpose 100 ns delay for HW mode + DELAY_1US = 1000, ///< general purpose 1 usec delay for HW mode + DELAY_10US = 10000, ///< general purpose 1 usec delay for HW mode + DELAY_100US = 100000, ///< general purpose 100 usec delay for HW mode + DELAY_1MS = 1000000, ///< general purpose 1 ms delay for HW mode + + MHZ_TO_KHZ = 1000, + SEC_IN_HOUR = 60 * 60, ///< seconds in an hour, used for scrub times +}; + }// mss #endif |