summaryrefslogtreecommitdiffstats
path: root/src/usr/diag/attn/common/attnmem.C
blob: dc32055dea5affc0057c7f3ceddfa7d4de05f591 (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
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/diag/attn/common/attnmem.C $                          */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2014,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 attnmem.C
 *
 * @brief HBATTN Memory attention operations function definitions.
 */

#include <errl/errlmanager.H>
#include <targeting/common/targetservice.H>
#include "common/attnmem.H"
#include "common/attnlist.H"
#include "common/attntarget.H"
#include "attntrace.H"
#include <targeting/common/utilFilter.H>

using namespace std;
using namespace PRDF;
using namespace TARGETING;
using namespace ERRORLOG;

namespace ATTN
{

typedef struct
{
    uint32_t              chipletFir;
    uint32_t              chipletFirMask;
    ATTENTION_VALUE_TYPE  attnType;

    // First of four bits to check
    // (2 bits apart)
    uint64_t              intrBitToChk;
} attnMemoryFirs_t;


const attnMemoryFirs_t  ATTN_MEM_CHIPLET_FIRS[] =
{
    { 0x07040009, 0x0704001A,
          HOST_ATTN,   0x4000000000000000ull },  // Host    1,3,5,7
    { 0x07040018, 0x07040019,
          UNIT_CS,     0x4000000000000000ull },  // unit CS  1,3,5,7
    { 0x07040001, 0x07040002,
          RECOVERABLE, 0x0800000000000000ull },  // Recov   4,6,8,10
    { 0x07040000, 0x07040002,
          CHECK_STOP,  0x0800000000000000ull }   // chkstop  4,6,8,10
};

// 4 DMI units per MC
const uint32_t  ATTN_MAX_DMI_INTRS = 4;

// Processor FIR set when MemBuffer raises attention
const uint32_t  ATTN_ADDR_CHIFIR_DATA = 0x07010900;
const uint32_t  ATTN_ADDR_CHIFIR_MASK = 0x07010903;
const uint32_t  ATTN_ADDR_CHIFIR_ACT0 = 0x07010906;
const uint32_t  ATTN_ADDR_CHIFIR_ACT1 = 0x07010907;

// Attention bit positions in CHIFIR 16, 19,20,21
const uint64_t  ATTN_CEN_CHECKSTOP = 0x0000800000000000ull ;
const uint64_t  ATTN_CEN_RECOV     = 0x0000100000000000ull ;
const uint64_t  ATTN_CEN_SPECIAL   = 0x0000080000000000ull ;
const uint64_t  ATTN_CEN_MAINT_CMD = 0x0000040000000000ull ;



// @TODO RTC: 180469
//  Move to target services part and then update all the CXX testing
TargetHandle_t MemOps::attnGetMembuf( const TARGETING::TargetHandle_t &i_mc,
                                      const uint32_t i_dmi,
                                      const ATTENTION_VALUE_TYPE i_attnType )
{
    // where i_dmi is 0:7 value
    TargetHandle_t    membuf   = NULL;
    TargetHandleList  l_dmiList;
    errlHndl_t        l_err = NULL;
    uint64_t          l_chifirData = 0;
    uint64_t          l_chifirMask = 0;
    uint64_t          l_chifirIntr = 0;


    // Get the list of DMI units for MC unit passed in
    getChildChiplets(l_dmiList, i_mc, TYPE_DMI);

    for ( auto  l_dmiTarg : l_dmiList )
    {
        ATTN_TRACE("   MemRes(%d) - DMI:%d chiplet from MC",
                   i_dmi, l_dmiTarg->getAttr<ATTR_CHIP_UNIT>() );

        if ( i_dmi == l_dmiTarg->getAttr<ATTR_CHIP_UNIT>() )
        {
            ATTN_SLOW("    MemOps::resolve - DMI Match:%d",
                      i_dmi  );

            // Get mem buffer associated with the DMI chiplet
            TargetHandleList  l_memBufList;
            getChildAffinityTargets( l_memBufList, l_dmiTarg,
                                     CLASS_CHIP, TYPE_MEMBUF );

            if (l_memBufList.size() == 1)
            {
                // Validate Centaur actually raised attention
                l_err = getScom( l_dmiTarg,
                                 ATTN_ADDR_CHIFIR_DATA,
                                 l_chifirData );

                if (NULL == l_err)
                {
                    l_err = getScom( l_dmiTarg,
                                     ATTN_ADDR_CHIFIR_MASK,
                                     l_chifirMask );
                } // end if no error on getscom CHIFIR

                if (NULL == l_err)
                {
                    // Check for active attention
                    l_chifirIntr = l_chifirData & ~l_chifirMask;

                    ATTN_SLOW("    MemOps::res - CenAttn:%016llx ::%X",
                               l_chifirIntr, i_attnType );

                    // Is it attn we are looking for ?
                    if ( ( (i_attnType == HOST_ATTN) &&
                           ((l_chifirIntr & ATTN_CEN_SPECIAL) ||
                            (l_chifirIntr & ATTN_CEN_MAINT_CMD)
                           )
                         )  ||

                         ( (i_attnType == RECOVERABLE) &&
                           (l_chifirIntr & ATTN_CEN_RECOV)
                         )  ||
                         ( (i_attnType == CHECK_STOP) &&
                           (l_chifirIntr & ATTN_CEN_CHECKSTOP)
                         )  ||

                         ( (i_attnType == UNIT_CS) &&
                           (l_chifirIntr & ATTN_CEN_CHECKSTOP)
                         )
                       )
                    {
                        membuf = l_memBufList[0];
                        // Found right DMI and memory buffer
                        // so stop loooping
                        break;
                    } // end if matching attention in membuf

                } // end if no error on getscom CHIFIR Mask


                // Handle any elog
                if (NULL != l_err)
                {
                    l_err->collectTrace("ATTN_SLOW" , 512 );
                    errlCommit(l_err, ATTN_COMP_ID);
                }  // if elog

            } // end one membuf found

        } // end if correct DMI target

    } // end for on DMI targets


    return(membuf);

} // end attnGetMembuf


uint64_t MemOps::chkMembufAttn( TARGETING::TargetHandle_t  i_memBuf,
                                const ATTENTION_VALUE_TYPE i_attnType )
{
    errlHndl_t  l_err = NULL;
    uint64_t    l_scomData = 0;
    uint64_t    l_scomAddr = 0;


    // Which broadcast FIR should we be checking ?
    switch (i_attnType)
    {
        // These are the same for memBuf
        case  UNIT_CS:
            l_scomAddr = 0x500f001c;
            break;

        case  RECOVERABLE:
            l_scomAddr = 0x500f001b;
            break;

        // These are the same for memBuf
        case  HOST_ATTN:
            l_scomAddr = 0x500f001a;
            break;

        default:
            // invalid attn type
            break;

    } // end switch on attn type


    if (0 != l_scomAddr)
    {
        // Read the global broadcast FIR from memory buffer
        l_err = getScom(i_memBuf, l_scomAddr, l_scomData);
        // Any active bits indicates it has attn pending

        if (NULL != l_err)
        {
            ATTN_SLOW("Failed membuf readAddr:%016llx",
                       l_scomAddr);

            // ensure we don't have anything active
            l_scomData = 0;
            l_err->collectTrace("ATTN_SLOW" , 512 );
            errlCommit(l_err, ATTN_COMP_ID);
        }  // if elog

    } // if valid attn type/valid addr

    return(l_scomData);

} // end chkMembufAttn


bool MemOps::attnCmpAttnType( TARGETING::TargetHandle_t  i_dmiTarg,
                              const ATTENTION_VALUE_TYPE i_attnType )
{
    errlHndl_t  l_err = NULL;
    bool        l_validAttnType = false;
    uint64_t    l_chifirData = 0;
    uint64_t    l_chifirMask = 0;
    uint64_t    l_chifirAct0 = 0;
    uint64_t    l_chifirAct1 = 0;
    uint64_t    l_result = 0;


    // Get the actual CHIFIR data
    l_err = getScom(i_dmiTarg, ATTN_ADDR_CHIFIR_DATA, l_chifirData);

    if (NULL == l_err)
    {
        l_err = getScom(i_dmiTarg, ATTN_ADDR_CHIFIR_MASK, l_chifirMask);
    } // end if no error on getscom CHIFIR data

    if (NULL == l_err)
    {
        l_err = getScom(i_dmiTarg, ATTN_ADDR_CHIFIR_ACT0, l_chifirAct0);
    } // end if no error on getscom CHIFIR mask

    if (NULL == l_err)
    {
        l_err = getScom(i_dmiTarg, ATTN_ADDR_CHIFIR_ACT1, l_chifirAct1);
    } // end if no error on getscom CHIFIR action0

    if (NULL == l_err)
    {
        // Actions:00 CS, 01 REC, 10 SPEC/HOST, 11 UCS

        // Will modify the actions appropriately so we can just
        // AND them with the FIR data.
        switch (i_attnType)
        {
            case CHECK_STOP:
                l_chifirAct0 = ~l_chifirAct0;
                l_chifirAct1 = ~l_chifirAct1;
                break;

            case RECOVERABLE:
                l_chifirAct0 = ~l_chifirAct0;
                break;

            case HOST_ATTN:
            case SPECIAL:
                l_chifirAct1 = ~l_chifirAct1;
                break;

            case UNIT_CS:
                // actions are fine as is ('11')
                break;

            default:
                // Not valid attn type
                // so won't match on anything
                l_chifirAct0 = 0;
                l_chifirAct1 = 0;
                break;

        } // end switch on attnType

        // Validate if specified attention does exist in
        // CHIFIR and it is not masked.
        l_result = l_chifirData & ~l_chifirMask & l_chifirAct0 & l_chifirAct1;

        if (0 != l_result)
        {
            l_validAttnType = true;
        }

    } // end if no error on getscom CHIFIR action1


    if (NULL != l_err)
    {
        ATTN_SLOW("Failed attnCmpAttnType scom");
        l_err->collectTrace("ATTN_SLOW" , 512 );
        errlCommit(l_err, ATTN_COMP_ID);
    }  // if elog


    return(l_validAttnType);

} // end attnCmpAttnType


bool MemOps::resolve(
        PRDF::AttnData &  i_AttnData,
        const uint32_t  i_mcNumber,
        TARGETING::TargetHandle_t  i_procTarg )
{
    errlHndl_t  l_err = 0;
    bool        l_attnFound = false;
    uint64_t    l_firData  = 0;
    uint64_t    l_maskData = 0;
    uint64_t    l_intData  = 0;
    uint32_t    l_mcNum    = 0;
    uint32_t    l_dmi_0to7 = 0;


    TargetHandleList l_mcTargetList;

    // predicate of functional MC units
    PredicateCTM           l_unitMatch(CLASS_UNIT, TYPE_MC);
    PredicateIsFunctional  l_functional;
    PredicatePostfixExpr   l_pred;

    l_pred.push(&l_unitMatch).push(&l_functional).And();

    // Get all MC units associated with input processor
    targetService().getAssociated(
            l_mcTargetList,
            i_procTarg,
            TARGETING::TargetService::CHILD_BY_AFFINITY,
            TARGETING::TargetService::ALL,
            &l_pred);


    // Find correct MC chiplet
    for ( auto  l_mc : l_mcTargetList )
    {
        ATTN_TRACE("MemOps::resolve - MC chiplet:%d", i_mcNumber);
        l_mcNum = l_mc->getAttr<ATTR_CHIP_UNIT>();

        if (l_mcNum == i_mcNumber)
        {
            // Check for attention using chiplet summary registers
            uint32_t  l_numFirs = sizeof(ATTN_MEM_CHIPLET_FIRS) /
                                  sizeof(attnMemoryFirs_t);

            for ( uint32_t l_cFir=0; (l_cFir < l_numFirs); l_cFir++ )
            {
                // Verify the attention type
                if (i_AttnData.attnType ==
                               ATTN_MEM_CHIPLET_FIRS[l_cFir].attnType)
                {
                    // get chiplet FIR data
                    l_err = getScom(l_mc,
                                    ATTN_MEM_CHIPLET_FIRS[l_cFir].chipletFir,
                                    l_firData);

                    if (NULL == l_err)
                    {
                        // Get chiplet MASK
                        l_err = getScom(l_mc,
                                  ATTN_MEM_CHIPLET_FIRS[l_cFir].chipletFirMask,
                                  l_maskData);

                        ATTN_SLOW(
                           "...MemRes:cAddr:%016llx cFir:%016llx cMask:%016llx",
                           ATTN_MEM_CHIPLET_FIRS[l_cFir].chipletFir,
                           l_firData, l_maskData );

                        if (NULL == l_err)
                        {
                            // Recoverable FIR & MASK are 2 bits off
                            // so need to handle this here
                            if (RECOVERABLE == i_AttnData.attnType)
                            {
                                l_firData = l_firData >> 2;
                            } // end if recoverable

                            // Check for active attention
                            l_intData  = l_firData & ~l_maskData;

                            ATTN_TRACE("...resolve - IntrActive::%016llx ",
                                        l_intData );

                            // Interrupts are in various bit positions,
                            // so will shift a mask 2 bit positions for each DMI
                            for ( uint32_t l_intNum=0;
                                   (l_intNum < ATTN_MAX_DMI_INTRS); l_intNum++)
                            {
                                // Check for active DMI interrupt
                                if ( l_intData &
                                     (ATTN_MEM_CHIPLET_FIRS[l_cFir].intrBitToChk
                                                            >> (l_intNum*2)) )
                                {
                                    // Heirarchy:  MC -> MI -> DMI -> Centaur
                                    // Valid active interrupt on DMI Bus
                                    // Need  membuf targ for passing to PRD

                                    // Determine DMI chiplet - 0 thru 7 value
                                    l_dmi_0to7 = (l_mcNum * ATTN_MAX_DMI_INTRS)
                                                  + l_intNum;

                                    AttnData d;
                                    // add membuf target if found
                                    d.targetHndl = attnGetMembuf(l_mc,
                                                          l_dmi_0to7,
                                                          i_AttnData.attnType);

                                    if (NULL != d.targetHndl)
                                    {
                                        ATTN_SLOW(
                                        "     MemOpsRes -Got membuf Attn:%d",
                                        ATTN_MEM_CHIPLET_FIRS[l_cFir].attnType);

                                        i_AttnData.targetHndl = d.targetHndl;
                                        l_attnFound = true;
                                        // handle the one attention
                                        break;
                                    } // end if valid memory buffer target

                                } // end if active DMI Interrupt

                            } // end for loop thru all potential DMI interrupts

                        } // if ok reading mask data
                        else
                        {
                            ATTN_ERR("Mem:Resolve FirMask Fail Addr:%08X",
                                 ATTN_MEM_CHIPLET_FIRS[l_cFir].chipletFirMask);
                        } // end else failed reading mask

                    } // if ok reading FIR data
                    else
                    {
                        ATTN_ERR("Mem:Resolve Fir Fail Addr:%08X",
                                 ATTN_MEM_CHIPLET_FIRS[l_cFir].chipletFir);
                    } // end else failed reading FIR

                    // Handle any elog
                    if (NULL != l_err)
                    {
                        l_err->collectTrace("ATTN_SLOW" , 512 );
                        l_err->collectTrace("ATTN_ERR" , 512 );
                        errlCommit(l_err, ATTN_COMP_ID);
                    }  // if elog

                    // Found attn match so get out
                    break;
                } // end if attention matches

                else if (UNIT_CS == i_AttnData.attnType)
                {
                    // ------------------------------------------------------
                    // The membuf may not be able to set the chkstop bit in
                    // CHIFIR under these circumstances. Hence, we need to
                    // see if there are any unit chkstops present in CHIFIR
                    // and then we'll check if the membuf has one active.
                    // ------------------------------------------------------

                    // We only know the MC chiplet at this point and
                    // so we need to check all DMI chiplets off this MC.
                    TargetHandleList  l_dmiList;
                    getChildChiplets(l_dmiList, l_mc, TYPE_DMI);

                    // Validate CHIFIR with mask/action regs
                    // using our DMI chiplet list.
                    for ( auto  l_dmiTarg : l_dmiList )
                    {
                        if (true == attnCmpAttnType(l_dmiTarg, UNIT_CS))
                        {
                            // Check the membuf to see if it chkstop'd
                            uint64_t          l_attnRaised = 0;
                            TargetHandleList  l_memBufList;
                            getChildAffinityTargets(l_memBufList, l_dmiTarg,
                                                    CLASS_CHIP, TYPE_MEMBUF);

                            if (l_memBufList.size() == 1)
                            {
                                // Check if membuf raised a matching attn
                                l_attnRaised = chkMembufAttn(l_memBufList[0],
                                                             UNIT_CS);

                                if (l_attnRaised)
                                {
                                    ATTN_SLOW(
                                    "   membuf UCS HUID:%08X Data:%016llx",
                                    get_huid(l_memBufList[0]), l_attnRaised );

                                    i_AttnData.targetHndl = l_memBufList[0];
                                    l_attnFound = true;

                                    // Exit loop on DMI targets
                                    break;

                                } // end if attn raised

                             } // end if membuf found

                        } // end if UCS active in CHIFIR

                    } // end for on DMI list

                    if (true == l_attnFound)
                    {
                        // Exit loop thru chiplet FIRs
                        // since we have valid attn to process
                        break;
                    } // end if found valid UCS on membuf

                } // end else no ATTN match but else we have UCS

            } // end for thru chiplet FIRs

            // We handle attns one at a time
            break;
        } // end if found MC chiplet

    } // end for on MC chiplets


    return l_attnFound;
}

MemOps::MemOps()
{

}

MemOps::~MemOps()
{

}
}
OpenPOWER on IntegriCloud