summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/pm/p9_query_stop_state.C
blob: 02c3a40c1c2e5a1bf952c136c6a49a7730361b1d (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
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_query_stop_state.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016                             */
/* [+] 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 p9_query_stop_state.C
/// @brief Determine the state of cores, L2, and L3 of the targeted EX
///        Set ATTRs to know the scommable/scannable state of the logic
///        Further operations in the dump flow will only operate on scommable
///        portions of the targets.   FW/Platform is responsible for checking these
///        states before calling HWPs
///
// *HWP HWP Owner: Brian Vanderpool <vanderp@us.ibm.com>
// *HWP Backup HWP Owner: Greg Still <stillgs@us.ibm.com>
// *HWP FW Owner:  Sangeetha T S <sangeet2@in.ibm.com>
// *HWP Team: PM
// *HWP Level: 2
// *HWP Consumed by: FSP:HS
///
///
///
/// @verbatim
/// High-level procedure flow:
///     - For each EX, check the PPMC stop state history to know the state
///       of the core.  Check the PPMQ stop state history to know the state of L2/L3
///
///     - Then read the PFETSNS in the C/QPPM and CLOCK_STAT registers in the EPS to determine
///       the actual state of the hardware.   Use the HW values to print out a warning if
///       different, and override the attributes
///
///     - Set ATTRs to know the scommable/scannable state of the logic
///          L2_HASCLOCKS      indicates the L2 region has clocks running and scommable
///          L3_HASCLOCKS      indicates the L3 region has clocks running and scommable
///          C0_EXEC_HASCLOCKS indicates the execution units in core 0 have clocks running and scommable
///          C1_EXEC_HASCLOCKS indicates the execution units in core 1 have clocks running and scommable
///          C0_PC_HASCLOCKS   indicates the core pervasive unit in core 0 has clocks running and scommable
///          C1_PC_HASCLOCKS   indicates the core pervasive unit in core 1 has clocks running and scommable
///          L2_HASPOWER      indicates L2 has power and has valid latch state that could be scanned
///          L3_HASPOWER      indicates L3 has power and has valid latch state that could be scanned
///          C0_HASPOWER      indicates core 0 has power and has valid latch state that could be scanned
///          C1_HASPOWER      indicates core 1 has power and has valid latch state that could be scanned
/// @endverbatim
///
//------------------------------------------------------------------------------


// ----------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------

#include "p9_query_stop_state.H"


// ----------------------------------------------------------------------
// Data Structure Definitions
// ----------------------------------------------------------------------

typedef struct
{
    uint8_t  l2_hasclocks;
    uint8_t  l3_hasclocks;
    uint8_t  c0_exec_hasclocks;   // these could be put in an array, but is broken out since attributes are separate
    uint8_t  c1_exec_hasclocks;
    uint8_t  c0_pc_hasclocks;
    uint8_t  c1_pc_hasclocks;

    uint8_t  l2_haspower;
    uint8_t  l3_haspower;
    uint8_t  c0_haspower;
    uint8_t  c1_haspower;
} stop_attrs_t;

typedef struct
{

    uint8_t  l2_hasclocks;
    uint8_t  l3_hasclocks;
    uint8_t  c_exec_hasclocks[2];
    uint8_t  c_pc_hasclocks[2];

    uint8_t  vdd_pfet_disable_quad;
    uint8_t  vcs_pfet_disable_quad;
    uint8_t  vdd_pfet_disable_core[2];


    bool c0_haspower()
    {
        return !vdd_pfet_disable_core[0];
    }

    bool c1_haspower()
    {
        return !vdd_pfet_disable_core[1];
    }

    bool l2_haspower()
    {
        return (!vdd_pfet_disable_quad && !vcs_pfet_disable_quad);
    }

    bool l3_haspower()
    {
        return (!vdd_pfet_disable_quad && !vcs_pfet_disable_quad);
    }

} hw_state_t;

// Bit positions in the CLOCK_SL register for the L20, L21 and L30, L31 running state
const uint32_t eq_clk_l2_pos[] = {8, 9};
const uint32_t eq_clk_l3_pos[] = {6, 7};

// ----------------------------------------------------------------------
// Procedure Prototypes
// ----------------------------------------------------------------------

void compare_ss_hw(const char* msg, const uint8_t hw_state, uint8_t& stop_state);



// ----------------------------------------------------------------------
// Procedure Function
// ----------------------------------------------------------------------

void compare_ss_hw(const char* msg, const uint8_t hw_state, uint8_t& stop_state)
{

    // Compare the HW (pfet/clock) state with the value the stop state history registers would indicate,
    //  and if there is a mismatch, use the HW value.

    if (hw_state != stop_state)
    {
        FAPI_INF("WARNING: %s mismatch.  HW(%d) StopState(%d).  Using HW value", msg, hw_state, stop_state);
        // Use the HW value
        stop_state = hw_state;
    }
}

fapi2::ReturnCode
p9_query_stop_state(
    const fapi2::Target<fapi2::TARGET_TYPE_EX>& i_ex_target)
{


    fapi2::buffer<uint64_t>  l_qsshsrc, l_csshsrc[2], l_qpfetsense, l_cpfetsense[2];
    fapi2::buffer<uint64_t> l_data64;
    uint8_t  l_chpltNumber = 0;
    uint32_t l_quadStopLevel = 0;
    uint32_t l_exPos = 0;
    uint32_t l_coreStopLevel[2] = {0, 0};

    stop_attrs_t  l_stop_attrs = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; // Initialize all fields to 1
    hw_state_t l_clk_pfet = {0, 0, {0, 0}, {0, 0}, 0, 0, {0, 0}}; // Initialize all fields to 0


    FAPI_INF("> p9_query_stop_state...");


    // Get the parent EQ and core children
    auto l_eq_target    = i_ex_target.getParent<fapi2::TARGET_TYPE_EQ>();
    auto l_coreChiplets = i_ex_target.getChildren<fapi2::TARGET_TYPE_CORE>(fapi2::TARGET_STATE_FUNCTIONAL);


    FAPI_DBG("   Read QPPM Stop State History");
    FAPI_TRY(fapi2::getScom(l_eq_target, EQ_PPM_SSHSRC, l_qsshsrc), "Error reading data from QPPM SSHSRC");


    // Get the status of each SSHSRC in each configured CPPM.
    // Initialize both states to disabled in case one core is deconfigured
    l_csshsrc[0].flush<0>().insertFromRight<0, 12>(0x80F);
    l_csshsrc[1].flush<0>().insertFromRight<0, 12>(0x80F);

    for (auto l_core_chplt : l_coreChiplets)
    {
        // Fetch the position of the Core target
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, l_core_chplt, l_chpltNumber),
                 "ERROR: Failed to get the position of the Core:0x%08X",
                 l_core_chplt);

        //In case a core is deconfigured, figure out if this is the odd or even core and write the appropriate array
        uint32_t l_pos = l_chpltNumber % 2;

        FAPI_DBG("   Read CPPM Stop State History for core %d", l_chpltNumber);
        FAPI_TRY(fapi2::getScom(l_core_chplt, C_PPM_SSHSRC, l_csshsrc[l_pos]), "Error reading data from CPPM SSHSRC");

    }

    // A unit is scomable if clocks are running
    // A unit is scannable if the unit is powered up.

    // Extract the quad and core stop states
    l_qsshsrc.extractToRight<uint32_t>(l_quadStopLevel, 8, 4);
    l_csshsrc[0].extractToRight<uint32_t>(l_coreStopLevel[0], 8, 4);
    l_csshsrc[1].extractToRight<uint32_t>(l_coreStopLevel[1], 8, 4);

    FAPI_INF("EX Stop States: Q(%d) C0(%d) C1(%d)", l_quadStopLevel, l_coreStopLevel[0], l_coreStopLevel[1]);

    // Error check that the core stop states are >= the quad stop state
    FAPI_ASSERT( (l_coreStopLevel[0] >= l_quadStopLevel) && (l_coreStopLevel[1] >= l_quadStopLevel),
                 fapi2::P9_QUERY_STOP_STATE_INCONSISTENT()
                 .set_QSSHSRC(l_quadStopLevel)
                 .set_C0SSHSRC(l_coreStopLevel[0])
                 .set_C1SSHSRC(l_coreStopLevel[1]),
                 "ERROR: Stop States are inconsistent Q(%d) C0(%d) C1(%d)",
                 l_quadStopLevel, l_coreStopLevel[0], l_coreStopLevel[1]);


    //----------------------------------------------------------------------------------
    // Based on the stop state history registers,
    //  Set the attributes for the L2, L3 scanable and scomable
    //----------------------------------------------------------------------------------

    // STOP1 - NAP
    //  VSU, ISU are clocked off
    if (l_coreStopLevel[0] >= 1)
    {
        l_stop_attrs.c0_exec_hasclocks = 0;
    }

    if (l_coreStopLevel[1] >= 1)
    {
        l_stop_attrs.c1_exec_hasclocks = 0;
    }

    // STOP2 - Fast Sleep
    //   VSU, ISU are clocked off
    //   IFU, LSU are clocked off
    //   PC, Core EPS are clocked off
    if (l_coreStopLevel[0] >= 2)
    {
        l_stop_attrs.c0_pc_hasclocks = 0;
    }

    if (l_coreStopLevel[1] >= 2)
    {
        l_stop_attrs.c1_pc_hasclocks = 0;
    }

    // STOP4 - Deep Sleep  (special exception for stop 9 - lab use only)
    //   VSU, ISU are powered off
    //   IFU, LSU are powered off
    //   PC, Core EPS are powered off
    if (l_coreStopLevel[0] >= 4 && l_coreStopLevel[0] != 9)
    {
        l_stop_attrs.c0_haspower = 0;
    }

    if (l_coreStopLevel[1] >= 4 && l_coreStopLevel[1] != 9)
    {
        l_stop_attrs.c1_haspower = 0;
    }


    // STOP8 - Half Quad Deep Sleep
    //   VSU, ISU are powered off
    //   IFU, LSU are powered off
    //   PC, Core EPS are powered off
    //   L20-EX0 is clocked off if both cores are >= 8
    //   L20-EX1 is clocked off if both cores are >= 8
    if (l_quadStopLevel >= 8)
    {

        // The FAPI_ASSERT above ensures both cores are >= the quad stop state
        l_stop_attrs.l2_hasclocks = 0;
    }

    // STOP9 - Fast Winkle (lab use only)
    // Both cores and cache are clocked off
    if (l_quadStopLevel >= 9)
    {
        l_stop_attrs.l3_hasclocks = 0;
    }

    // STOP11 - Deep Winkle
    // Both cores and cache are powered off
    if (l_quadStopLevel >= 11)
    {
        l_stop_attrs.l2_haspower = 0;
        l_stop_attrs.l3_haspower = 0;
    }

    //----------------------------------------------------------------------------------
    // Read clock status and pfet_sense_disabled to confirm stop state history is accurate
    //----------------------------------------------------------------------------------

    // Read voltage state to make sure pfets are enabled.
    FAPI_DBG("   Read QPPM PFETSENSE");
    FAPI_TRY(fapi2::getScom(l_eq_target, EQ_PPM_PFSNS, l_qpfetsense), "Error reading data from QPPM PFSNS");

    // Get the status of each PFSNS in each configured CPPM.
    // Initialize variables as disabled (bits 1 (VDD) and 3 (VCS)) for partial good readiness
    l_cpfetsense[0].flush<0>().insertFromRight<0, 4>(0x5);
    l_cpfetsense[1].flush<0>().insertFromRight<0, 4>(0x5);

    for (auto l_core_chplt : l_coreChiplets)
    {
        // Fetch the position of the Core target
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, l_core_chplt, l_chpltNumber),
                 "ERROR: Failed to get the position of the Core:0x%08X",
                 l_core_chplt);

        FAPI_DBG("   Read CPPM PFETSENSE for core %d", l_chpltNumber);
        //In case a core is deconfigured, figure out if this is the odd or even core and write the appropriate array
        uint32_t l_pos = l_chpltNumber % 2;

        FAPI_TRY(fapi2::getScom(l_core_chplt, C_PPM_PFSNS, l_cpfetsense[l_pos]), "Error reading data from CPPM SSHSRC");

    }

    // Extract out the disabled bits
    l_qpfetsense.extractToRight<uint8_t>(l_clk_pfet.vdd_pfet_disable_quad, 1, 1);
    l_qpfetsense.extractToRight<uint8_t>(l_clk_pfet.vcs_pfet_disable_quad, 3, 1);

    l_cpfetsense[0].extractToRight<uint8_t>(l_clk_pfet.vdd_pfet_disable_core[0], 1, 1);
    l_cpfetsense[1].extractToRight<uint8_t>(l_clk_pfet.vdd_pfet_disable_core[1], 1, 1);


    // Read clocks running registers

    // Determine if this is an odd or even EX for checking EX clock state
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, i_ex_target, l_chpltNumber),
             "ERROR: Failed to get the position of the EX:0x%08X",
             i_ex_target);

    l_exPos = l_chpltNumber % 2;

    FAPI_TRY(fapi2::getScom(l_eq_target, EQ_CLOCK_STAT_SL,  l_data64), "Error reading data from EQ_CLOCK_STAT_SL");


    l_data64.extractToRight<uint8_t>(l_clk_pfet.l2_hasclocks, eq_clk_l2_pos[l_exPos], 1);
    l_data64.extractToRight<uint8_t>(l_clk_pfet.l3_hasclocks, eq_clk_l3_pos[l_exPos], 1);

    for (auto l_core_chplt : l_coreChiplets)
    {
        // Fetch the position of the Core target
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, l_core_chplt, l_chpltNumber),
                 "ERROR: Failed to get the position of the Core:0x%08X",
                 l_core_chplt);

        FAPI_DBG("   Read Core EPS clock status for core %d", l_chpltNumber);
        //In case a core is deconfigured, figure out if this is the odd or even core and write the appropriate array
        uint32_t l_pos = l_chpltNumber % 2;

        FAPI_TRY(fapi2::getScom(l_core_chplt, C_CLOCK_STAT_SL,  l_data64), "Error reading data from C_CLOCK_STAT_SL");

        l_data64.extractToRight<uint8_t>(l_clk_pfet.c_exec_hasclocks[l_pos], 6, 1);
        l_data64.extractToRight<uint8_t>(l_clk_pfet.c_pc_hasclocks[l_pos],   5, 1);

    }

    FAPI_DBG("Comparing Stop State vs Actual HW settings");
    FAPI_DBG("C0_EXEC_HASCLOCKS   ATTR(%d)  HW(%d)", l_stop_attrs.c0_exec_hasclocks, l_clk_pfet.c_exec_hasclocks[0]);
    FAPI_DBG("C1_EXEC_HASCLOCKS   ATTR(%d)  HW(%d)", l_stop_attrs.c1_exec_hasclocks, l_clk_pfet.c_exec_hasclocks[1]);

    FAPI_DBG("C0_PC_HASCLOCKS     ATTR(%d)  HW(%d)", l_stop_attrs.c0_pc_hasclocks, l_clk_pfet.c_pc_hasclocks[0]);
    FAPI_DBG("C1_PC_HASCLOCKS     ATTR(%d)  HW(%d)", l_stop_attrs.c1_pc_hasclocks, l_clk_pfet.c_pc_hasclocks[1]);

    FAPI_DBG("L2_HASCLOCKS        ATTR(%d)  HW(%d)", l_stop_attrs.l2_hasclocks, l_clk_pfet.l2_hasclocks);
    FAPI_DBG("L3_HASCLOCKS        ATTR(%d)  HW(%d)", l_stop_attrs.l3_hasclocks, l_clk_pfet.l3_hasclocks);



    FAPI_DBG("C0_HASPOWER         ATTR(%d)  HW(%d)", l_stop_attrs.c0_haspower, l_clk_pfet.c0_haspower());
    FAPI_DBG("C1_HASPOWER         ATTR(%d)  HW(%d)", l_stop_attrs.c1_haspower, l_clk_pfet.c1_haspower());

    FAPI_DBG("L2_HASPOWER         ATTR(%d)  HW(%d)", l_stop_attrs.l2_haspower, l_clk_pfet.l2_haspower());
    FAPI_DBG("L3_HASPOWER         ATTR(%d)  HW(%d)", l_stop_attrs.l3_haspower, l_clk_pfet.l3_haspower());

    //----------------------------------------------------------------------------------
    // Compare Hardware status vs stop state status.   If there is a mismatch, the HW value overrides the stop state
    //----------------------------------------------------------------------------------

    compare_ss_hw("C0_exec_HASCLOCKS", l_clk_pfet.c_exec_hasclocks[0], l_stop_attrs.c0_exec_hasclocks);
    compare_ss_hw("C1_exec_HASCLOCKS", l_clk_pfet.c_exec_hasclocks[1], l_stop_attrs.c1_exec_hasclocks);
    compare_ss_hw("C0_pc_HASCLOCKS",   l_clk_pfet.c_pc_hasclocks[0],   l_stop_attrs.c0_pc_hasclocks);
    compare_ss_hw("C1_pc_HASCLOCKS",   l_clk_pfet.c_pc_hasclocks[1],   l_stop_attrs.c1_pc_hasclocks);
    compare_ss_hw("L2_HASCLOCKS",      l_clk_pfet.l2_hasclocks,        l_stop_attrs.l2_hasclocks);
    compare_ss_hw("L3_HASCLOCKS",      l_clk_pfet.l3_hasclocks,        l_stop_attrs.l3_hasclocks);

    compare_ss_hw("C0_HASPOWER",       l_clk_pfet.c0_haspower(),       l_stop_attrs.c0_haspower);
    compare_ss_hw("C1_HASPOWER",       l_clk_pfet.c1_haspower(),       l_stop_attrs.c1_haspower);
    compare_ss_hw("L2_HASPOWER",       l_clk_pfet.l2_haspower(),       l_stop_attrs.l2_haspower);
    compare_ss_hw("L3_HASPOWER",       l_clk_pfet.l3_haspower(),       l_stop_attrs.l3_haspower);


    //----------------------------------------------------------------------------------
    // Set the Attributes
    //----------------------------------------------------------------------------------
    FAPI_DBG("Setting attributes\n");
    // HASCLOCKS attributes (scomable)
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_L2_HASCLOCKS,      i_ex_target, l_stop_attrs.l2_hasclocks));
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_L3_HASCLOCKS,      i_ex_target, l_stop_attrs.l3_hasclocks));
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_C0_EXEC_HASCLOCKS, i_ex_target, l_stop_attrs.c0_exec_hasclocks));
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_C1_EXEC_HASCLOCKS, i_ex_target, l_stop_attrs.c1_exec_hasclocks));
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_C0_PC_HASCLOCKS,   i_ex_target, l_stop_attrs.c0_pc_hasclocks));
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_C1_PC_HASCLOCKS,   i_ex_target, l_stop_attrs.c1_pc_hasclocks));

    // HASPOWER attributes (scanable)
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_L2_HASPOWER,      i_ex_target, l_stop_attrs.l2_haspower));
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_L3_HASPOWER,      i_ex_target, l_stop_attrs.l3_haspower));
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_C0_HASPOWER,      i_ex_target, l_stop_attrs.c0_haspower));
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_C1_HASPOWER,      i_ex_target, l_stop_attrs.c1_haspower));

fapi_try_exit:
    FAPI_INF("< p9_query_stop_state...");
    return fapi2::current_err;
}
OpenPOWER on IntegriCloud