summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H
blob: b18eb9b506fc7f538d65b501140001aa0753f919 (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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/utils/conversions.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2017                        */
/* [+] 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 <lib/mss_attribute_accessors.H>
#include <lib/shared/mss_const.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
{


///
/// @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 )
{
    switch(i_speed_grade)
    {
        case fapi2::ENUM_ATTR_MSS_FREQ_MT1866:
            o_tCK_in_ps = 1071;
            break;

        case fapi2::ENUM_ATTR_MSS_FREQ_MT2133:
            o_tCK_in_ps = 937;
            break;

        case fapi2::ENUM_ATTR_MSS_FREQ_MT2400:
            o_tCK_in_ps = 833;
            break;

        case fapi2::ENUM_ATTR_MSS_FREQ_MT2666:
            o_tCK_in_ps = 750;
            break;

        default:
            FAPI_ERR("Invalid dimm speed grade (MT/s) - %d - provided", i_speed_grade);
            return fapi2::FAPI2_RC_INVALID_PARAMETER;
            break;
    }

    return fapi2::FAPI2_RC_SUCCESS;
}

///
/// @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)
{
    switch(i_time_in_ps)
    {
        case 750:
            o_speed_grade = fapi2::ENUM_ATTR_MSS_FREQ_MT2666;
            break;

        case 833:
            o_speed_grade = fapi2::ENUM_ATTR_MSS_FREQ_MT2400;
            break;

        case 937:
            o_speed_grade = fapi2::ENUM_ATTR_MSS_FREQ_MT2133;
            break;

        case 1071:
            o_speed_grade = fapi2::ENUM_ATTR_MSS_FREQ_MT1866;
            break;

        default:
            FAPI_ERR("Invalid clock period (tCK) - %d - provided", i_time_in_ps);
            return fapi2::FAPI2_RC_INVALID_PARAMETER;
            break;
    }

    return fapi2::FAPI2_RC_SUCCESS;

}

///
/// @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 the target type from which to get the mt/s
/// @tparam OT the output type, derrived from the parameters
/// @param[in] i_target target for the frequency attribute
/// @param[in] i_ps the number of picoseconds to convert
/// @return uint64_t, the number of cycles
///
template< fapi2::TargetType T, typename OT >
inline OT ps_to_cycles(const fapi2::Target<T>& i_target, const OT i_ps)
{
    // The frequency in MT/s
    uint64_t l_freq = 0;
    OT l_divisor = 0;
    OT l_quotient = 0;
    OT l_remainder = 0;
    OT l_rounder = (i_ps < 0) ? -1 : 1;

    FAPI_TRY( mss::freq( find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq) );

    // No time if MT/s is 0 (well, infinite really but shut up)
    if (l_freq == 0)
    {
        return 0;
    }

    // Hoping the compiler figures out how to do these together.
    FAPI_TRY( freq_to_ps(l_freq, l_divisor) );
    l_quotient = i_ps / ((l_divisor == 0) ? l_rounder : l_divisor);
    l_remainder = i_ps % 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);

fapi_try_exit:
    // We simply can't work if we can't get the frequency or
    // if we get an unsupported value that can't be converted to a valid tCK (clock period)
    // ...so this should be ok
    FAPI_ERR("Can't get MSS_FREQ or obtained an invalid MSS_FREQ (%d) - stopping", l_freq);
    fapi2::Assert(false);

    // Keeps compiler happy
    return 0;
}

///
/// @brief Return the number of ps contained in a count of cycles
/// @param[in] i_target target for the frequency attribute
/// @param[in] i_cycles the number of cycles to convert
/// @return uint64_t, the number of picoseconds
///
template< fapi2::TargetType T >
inline uint64_t cycles_to_ps(const fapi2::Target<T>& i_target, const uint64_t i_cycles)
{
    // The frequency in mHZ
    uint64_t l_freq = 0;
    uint64_t l_clock_period = 0;

    FAPI_TRY( mss::freq( find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq) );
    FAPI_TRY( freq_to_ps(l_freq, l_clock_period) );
    FAPI_INF("converting %llu cycles to %llups", i_cycles, i_cycles * l_clock_period );
    return i_cycles * l_clock_period;

fapi_try_exit:

    // We simply can't work if we can't get the frequency or
    // if we get an unsupported value that can't be converted to a valid tCK (clock period)
    // ...so this should be ok
    FAPI_ERR("Can't get MSS_FREQ or obtained an invalid MSS_FREQ (%d) - stopping", l_freq);
    fapi2::Assert(false);

    // Keeps compiler happy
    return 0;
}

///
/// @brief Return the number of cycles contained in a count of microseconds
/// @param[in] i_target target for the frequency attribute
/// @param[in] i_us the number of microseconds to convert
/// @return uint64_t, the number of cycles
///
template< fapi2::TargetType T >
inline uint64_t us_to_cycles(const fapi2::Target<T>& i_target, const uint64_t i_us)
{
    return ps_to_cycles(i_target, i_us * CONVERT_PS_IN_A_US);
}

///
/// @brief Return the number of cycles contained in a count of nanoseconds
/// @param[in] i_target target for the frequency attribute
/// @param[in] i_ps the number of nanoseconds to convert
/// @return uint64_t, the number of cycles
///
template< fapi2::TargetType T >
inline uint64_t ns_to_cycles(const fapi2::Target<T>& i_target, const uint64_t i_ns)
{
    return ps_to_cycles(i_target, i_ns * CONVERT_PS_IN_A_NS);
}

///
/// @brief Return the number of microseconds contained in a count of cycles
/// @tparam T the target type
/// @tparam D the time conversion (NS_IN_PS, etc)
/// @param[in] i_target target for the frequency attribute
/// @param[in] i_cycles the number of cycles to convert
/// @return uint64_t, the number of microseconds
///
template< fapi2::TargetType T, uint64_t D >
inline uint64_t cycles_to_time(const fapi2::Target<T>& i_target, const uint64_t i_cycles)
{
    // Hoping the compiler figures out how to do these together.
    uint64_t l_dividend = cycles_to_ps(i_target, i_cycles);
    uint64_t l_quotient = l_dividend / ((D == 0) ? 1 : D);
    uint64_t l_remainder = l_dividend % D;

    // 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
/// @param[in] i_target target for the frequency attribute
/// @param[in] i_cycles the number of cycles to convert
/// @return uint64_t, the number of nanoseconds
///
template< fapi2::TargetType T >
inline uint64_t cycles_to_ns(const fapi2::Target<T>& i_target, const uint64_t i_cycles)
{
    uint64_t l_ns = cycles_to_time<T, CONVERT_PS_IN_A_NS>(i_target, 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_target target for the frequency attribute
/// @param[in] i_cycles the number of cycles to convert
/// @return uint64_t, the number of microseconds
///
template< fapi2::TargetType T >
inline uint64_t cycles_to_us(const fapi2::Target<T>& i_target, const uint64_t i_cycles)
{
    uint64_t l_us = cycles_to_time<T, CONVERT_PS_IN_A_US>(i_target, 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
/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
/// @param[in] i_clocks a value in clocks
/// @param[in] i_time a value in nanoseconds
/// @return max( iclocks nCK, i_time ) in clocks
///
template< fapi2::TargetType T >
inline uint64_t max_ck_ns(const fapi2::Target<T>& i_target, const uint64_t i_clocks, const uint64_t i_time)
{
    return std::max( i_clocks, ns_to_cycles(i_target, i_time) );
}

///
/// @brief Return and estimated time an MCBIST subtest will take to complete
/// Useful for initial polling delays, probably isn't accurate for much else
/// as it doesn't take refresh in to account (which will necessarily slow down
/// the program.)
/// @param[in] i_target the target from which to gather memory frequency
/// @param[in] i_bytes number of *bytes* in the address range
/// @param[in] i_64B_per mss::YES if the command is 64B, mss::NO if it's 128B. Defaults to mss::YES
/// @return the initial polling delay for this program in ns
///
template< fapi2::TargetType T >
inline uint64_t calculate_initial_delay(const fapi2::Target<T>& i_target,
                                        const uint64_t i_bytes,
                                        const bool i_64B_per = mss::YES)
{
    // TODO RTC: 164104 Update MCBIST delay calculator. As we learn more about what
    // the lab really needs, we can probably make this function better.
    const uint64_t l_bytes_per_cmd = (i_64B_per == mss::YES) ? 64 : 128;

    // Best case is a command takes 4 cycles. Given the number of commands and address space size
    // we can get some idea of how long to wait before we start polling.
    return cycles_to_ns(i_target, (i_bytes / l_bytes_per_cmd) * mss::CYCLES_PER_CMD);
}

};// mss namespace

#endif
OpenPOWER on IntegriCloud