summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.H
blob: 06345713c624fc2f9790fe0553adb917e9aa53ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2019                             */
/* [+] 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 axone_sync.H
/// @brief Synchronous function implementations for Axone
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: HB:FSP

#ifndef _MSS_SYNC_H_
#define _MSS_SYNC_H_

#include <map>
#include <vector>

#include <fapi2.H>
#include <mss_generic_attribute_getters.H>
#include <generic/memory/lib/utils/shared/mss_generic_consts.H>
#include <lib/shared/axone_consts.H>
#include <generic/memory/lib/utils/freq/mss_freq_scoreboard.H>
#include <generic/memory/lib/utils/c_str.H>
#include <generic/memory/lib/utils/mss_math.H>

namespace mss
{

// List of the OMI frequencies for Axone
// Note: these need to be sorted so binary search works
static const std::vector<uint64_t> AXONE_OMI_FREQS =
{
    21330, // fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_21_33GBPS,
    23460, // fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_23_46GBPS,
    25600, // fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_25_60GBPS,
};

///
/// @brief Converts an OMI frequency attribute enum to the corresponding OMI frequency
/// @param[in] i_omi_enum a frequency enum value that is to be converted
/// @return the corresponding OMI frequency
///
inline uint64_t convert_omi_freq_attr_to_freq(const fapi2::ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_Type
        i_omi_enum)
{
    switch (i_omi_enum)
    {
        case fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_21_33GBPS:
            return 21330;

        case fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_23_46GBPS:
            return 23460;

        case fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_25_60GBPS:
            return 25600;

        default:
            FAPI_ASSERT( false,
                         fapi2::P9A_MSS_UNSUPPORTED_OMI_FREQ()
                         .set_OMI_FREQ_ENUM(i_omi_enum),
                         "freq system saw an unsupported OMI frequency with enum value: %d",
                         i_omi_enum );
    }

fapi_try_exit:
    return 0;
}

///
/// @brief Converts a DDR frequency to the corresponding OMI frequency
/// @param[in] i_target the port target
/// @param[in] i_ddr_freq a frequency value that is to be converted
/// @param[out] o_omi_freq the corresponding OMI frequency
/// @return FAPI2_RC_SUCCESS iff successful
///
inline fapi2::ReturnCode convert_ddr_freq_to_omi_freq(const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
        const uint64_t i_ddr_freq,
        uint64_t& o_omi_freq)
{
    using TT = mss::frequency_traits<mss::proc_type::AXONE>;
    constexpr uint64_t ROUND_UNITS = 10;

    // Get the OMI to DDR freq ratio
    uint8_t l_ratio[TT::MAX_DIMM_PER_PORT] = {0};
    FAPI_TRY(mss::attr::get_host_to_ddr_speed_ratio(i_target, l_ratio));

    // Multiply by the ratio and round to the nearest 10GBPS
    FAPI_TRY(mss::divide_and_round((i_ddr_freq * l_ratio[0]), ROUND_UNITS, o_omi_freq));
    o_omi_freq *= ROUND_UNITS;
    FAPI_DBG("For ratio %d and DDR freq %d, corresponding OMI freq is %d", l_ratio[0], i_ddr_freq, o_omi_freq);

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Converts an OMI frequency to the corresponding DDR frequency
/// @param[in] i_target the port target
/// @param[in] i_omi_freq a frequency value that is to be converted
/// @param[out] o_ddr_freq the corresponding DDR frequency
/// @return FAPI2_RC_SUCCESS iff successful
///
inline fapi2::ReturnCode convert_omi_freq_to_ddr_freq(const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
        const uint64_t i_omi_freq,
        uint64_t& o_ddr_freq)
{
    using TT = mss::frequency_traits<mss::proc_type::AXONE>;

    // Get the OMI to DDR freq ratio
    uint8_t l_ratio[TT::MAX_DIMM_PER_PORT] = {0};
    FAPI_TRY(mss::attr::get_host_to_ddr_speed_ratio(i_target, l_ratio));

    FAPI_TRY(mss::divide_and_round(i_omi_freq, static_cast<uint64_t>(l_ratio[0]), o_ddr_freq),
             "%s freq system saw a zero Host (OMI) to DDR frequency ratio", mss::c_str(i_target));
    FAPI_DBG( "For ratio %d and OMI freq %d, corresponding DDR freq is %d", l_ratio[0], i_omi_freq, o_ddr_freq);

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Checks to see if a passed in value could be a valid OMI frequency
/// @param[in] i_target the port target
/// @param[in] i_proposed_freq a frequency value that is to be checked
/// @param[out] o_valid boolean whether the value is a valid OMI frequency
/// @return FAPI2_RC_SUCCESS iff successful
///
inline fapi2::ReturnCode is_omi_freq_valid (const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
        const uint64_t i_proposed_freq,
        uint64_t& o_valid)
{
    uint64_t l_proposed_omi_freq = 0;
    FAPI_TRY(convert_ddr_freq_to_omi_freq(i_target, i_proposed_freq, l_proposed_omi_freq));

    o_valid = std::binary_search(AXONE_OMI_FREQS.begin(), AXONE_OMI_FREQS.end(), l_proposed_omi_freq);

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Retrieves a mapping of MSS frequency values per port target
/// @param[in] i_targets vector of port targets
/// @param[out] o_freq_map dimm speed map <key, value> = (port target, frequency)
/// @param[out] o_is_speed_equal holds whether map dimm speed is equal
/// @return FAPI2_RC_SUCCESS iff successful
///
fapi2::ReturnCode dimm_speed_map(const std::vector< fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT> >& i_targets,
                                 std::map< fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>, uint64_t >& o_freq_map,
                                 speed_equality& o_is_speed_equal);

///
/// @brief Helper function to deconfigure MEM_PORT target
/// @param[in] i_target the port target
/// @param[in] i_dimm_speed dimm speed in MT/s
/// @param[in] i_omi_freq OMI freq in MHz
/// @return true if hardware was deconfigured
///
bool deconfigure(const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
                 const uint64_t i_dimm_speed,
                 const uint32_t i_omi_freq);

///
/// @brief Selects synchronous mode and performs requirements enforced by selected port frequency
/// @param[in] i_freq_map dimm speed mapping
/// @param[in] i_equal_dimm_speed tracks whether map has equal dimm speeds
/// @param[in] i_omi_freq OMI frequency
/// @param[out] o_selected_sync_mode final synchronous mode
/// @param[out] o_selected_omi_freq final freq selected, only valid if final sync mode is in-sync
/// @return FAPI2_RC_SUCCESS iff successful
///
fapi2::ReturnCode select_sync_mode(const std::map< fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>, uint64_t >& i_freq_map,
                                   const speed_equality i_equal_dimm_speed,
                                   const uint32_t i_omi_freq,
                                   uint8_t& o_selected_sync_mode,
                                   uint64_t& o_selected_omi_freq);

}// mss

#endif
OpenPOWER on IntegriCloud