summaryrefslogtreecommitdiffstats
path: root/src/usr/scom/scomtrans.C
blob: eaf42b98be500417863f881d80e691998aeb85a1 (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
//  IBM_PROLOG_BEGIN_TAG
//  This is an automatically generated prolog.
//
//  $Source: src/usr/scom/scomtrans.C $
//
//  IBM CONFIDENTIAL
//
//  COPYRIGHT International Business Machines Corp. 2011
//
//  p1
//
//  Object Code Only (OCO) source materials
//  Licensed Internal Code Source Materials
//  IBM HostBoot Licensed Internal Code
//
//  The source code for this program is not published or other-
//  wise divested of its trade secrets, irrespective of what has
//  been deposited with the U.S. Copyright Office.
//
//  Origin: 30
//
//  IBM_PROLOG_END
/**
 *  @file scomtrans.C
 *
 *  @brief Implementation of SCOM operations
 */

/*****************************************************************************/
// I n c l u d e s
/*****************************************************************************/
#include <assert.h>
#include <devicefw/driverif.H>
#include <trace/interface.H>
#include <errl/errlentry.H>
#include <errl/errlmanager.H>
#include "scom.H"
#include "scomtrans.H"
#include <scom/scomreasoncodes.H>

// Trace definition
extern trace_desc_t* g_trac_scom;

namespace SCOM
{


DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD,
                      DeviceFW::SCOM,
                      TARGETING::TYPE_EX,
                      scomTranslate);

DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD,
                      DeviceFW::SCOM,
                      TARGETING::TYPE_MBS,
                      scomTranslate);

DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD,
                      DeviceFW::SCOM,
                      TARGETING::TYPE_MBA,
                      scomTranslate);

DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD,
                      DeviceFW::SCOM,
                      TARGETING::TYPE_MCS,
                      scomTranslate);

DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD,
                      DeviceFW::SCOM,
                      TARGETING::TYPE_XBUS,
                      scomTranslate);

DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD,
                      DeviceFW::SCOM,
                      TARGETING::TYPE_ABUS,
                      scomTranslate);



///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
errlHndl_t scomTranslate(DeviceFW::OperationType i_opType,
                         TARGETING::Target* i_target,
                         void* io_buffer,
                         size_t& io_buflen,
                         int64_t i_accessType,
                         va_list i_args)

{
    errlHndl_t l_err = NULL;

    bool l_invalidAddr = false;

    uint64_t i_addr = va_arg(i_args,uint64_t);

    // Get the attribute type.
    TARGETING::TYPE l_type = i_target->getAttr<TARGETING::ATTR_TYPE>();

    // get the specific entry to determine the address. 
    TARGETING::EntityPath epath;

    if (i_target->tryGetAttr<TARGETING::ATTR_PHYS_PATH>(epath))
    {
        if (l_type == TARGETING::TYPE_EX)
        {
 
        // Below are the assumptions used for the EX translate
        /*EX
         Mask		:  0x1F00_0000
         Range 1	:  0x1000_0000 -  0x10FF_FFFF
         ...
         ...
         bits 3:7 correspond to what EX chiplet is targeted.
         where 0x10XXXXXX is for EX0
         ...
         where 0x13XXXXXX is for EX3
         where 0x14XXXXXX is for EX4
         ...
         where 0x1CXXXXXX is for EX12


         original mask = 0x000000001F000000
         change that to be 0x7F000000 to catch other chiplets.*/

            // check to see that the Address is in the correct range
            if ((i_addr & SCOM_TRANS_EX_MASK) ==  SCOM_TRANS_EX_BASEADDR)
            {
                // Call the function that performs the translate
	        l_err = scomPerformTranslate(epath,
                                             TARGETING::TYPE_EX,
                                             TARGETING::TYPE_PROC,
                                             24,
                                             SCOM_TRANS_EX_MASK,
                                             i_target,
                                             i_addr );
            }
            else
            {
	        // set invalid addr to true.. and create errorlog below.
                l_invalidAddr = true;
            }
        }
        else if (l_type == TARGETING::TYPE_MCS)
        {
        /* ring  6 = MCL
                     MC0 MCS0   = 0x02011800   MCS-0    range 0
                     MC0 MCS1   = 0x02011880   MCS-1    range 0 + remainder
                     MC1 MCS0   = 0x02011900   MCS-2    range 1
                     MC1 MCS0   = 0x02011980   MCS-3    range 1 + remainder
                     IOMC0      = 0x02011A00  -NOT targeting this range..
           ring  7 = MCR
                     MC2 MCS0   = 0x02011C00   MCS-4     range 2
                     MC2 MCS1   = 0x02011C80   MCS-5     range 2 + remainder
                     MC3 MCS0   = 0x02011D00   MCS-6     range 3
                     MC3 MCS1   = 0x02011D80   MCS-7     range 3 + remainder

            original mask = 0x0000000002011D80
            Need the mask to be   0x7FFFFF80*/


            uint64_t l_instance;

            // Check that we are working with the correct address range
            if ((i_addr & SCOM_TRANS_MCS_MASK) == SCOM_TRANS_MCS_BASEADDR )
            {

                // Need to extract what instance of the entity we are at
                l_instance =
                   epath.pathElementOfType(TARGETING::TYPE_MCS).instance;

                // based on the instance, update the address

                // range 1 - add 0x100 to the addr
                if( (l_instance / 2) == 1)
                {
                    i_addr += 0x100;
                }
                // range 2 - add 0x400 to the addr
                else if( (l_instance / 2) == 2)
                {
                    i_addr += 0x400;
                }
                // range 3 - add 0x500 to the addr
                else if( (l_instance / 2) == 3)
                {
                    i_addr += 0x500;
                }

                // add 0x80 if the instance%2 is nonzero.
                if (l_instance % 2)
                {
                    i_addr += 0x80;
                }

                // Call to set the target to the parent target type
                l_err = scomfindParentTarget(epath,
                                             TARGETING::TYPE_PROC,
                                             i_target);
            }
            else
            {
                 l_invalidAddr = true;
            }
        }
        else if (l_type == TARGETING::TYPE_XBUS)
        {
          //*** temporarily put an error log indicating not supported until we
          // have info from the hardware team

            TRACFCOMP(g_trac_scom, "SCOM_TRANSLATE-unsupported target type=0x%X", l_type);

            /*@
             * @errortype
             * @moduleid     SCOM::SCOM_TRANSLATE
             * @reasoncode   SCOM::SCOM_TRANS_UNSUPPORTED
             * @userdata1    Address
             * @userdata2    Target Type that failed
             * @devdesc      Scom Translate not supported for this type
             */
             l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                             SCOM_TRANSLATE,
                                             SCOM_TRANS_UNSUPPORTED,
                                             i_addr,
                                             l_type);

        }
        else if (l_type == TARGETING::TYPE_ABUS)
        {
          //*** temporarily put an error log indicating not supported until we have info
          // from the hardware team
            TRACFCOMP(g_trac_scom, "SCOM_TRANSLATE-unsupported target type=0x%X", l_type);

            /*@
             * @errortype
             * @moduleid     SCOM::SCOM_TRANSLATE
             * @reasoncode   SCOM::SCOM_TRANS_UNSUPPORTED
             * @userdata1    Address
             * @userdata2    Target Type that failed
             * @devdesc      Scom Translate not supported for this type
             */
             l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                             SCOM_TRANSLATE,
                                             SCOM_TRANS_UNSUPPORTED,
                                             i_addr,
                                             l_type);


        }
        else if (l_type == TARGETING::TYPE_MBS)
        {
           /*
            MBS
            Mask 		: NA
            Range 1	: 0x02010000 - 0x0201FFFF

            default>physical:sys-0/node-0/membuf-10/mbs-0</default>

            */
            // NO address shifting required.. no mask..
            // just get parent.
            l_err = scomfindParentTarget(epath,
                                         TARGETING::TYPE_MEMBUF,
                                         i_target);

        }
        else if (l_type == TARGETING::TYPE_MBA)
        {
            /*
               MBA
               Mask 		: 0x03010800
               Range	1	: 0x03010400 - 0301043F  # MBA01
               Range	2	: 0x03010600 - 030106FF  # MBA01 MCBIST
               Range	4	: 0x03010C00 - 03010C3F  # MBA23
               Range	5	: 0x03010E00 - 03010EFF  # MBA23 MCBIST

               Original mask from hdw team is: 03010800
               The mask needs to be 0x7FFFF800 in order make sure we
               don't have any other valid address bits on for another
               chiplet.

               bits 20 correspond to what MBA chiplet is targeted.
               where 0x03010000 is for MBA01
               where 0x03010800 is for MBA23

               In the XML.. the
              <default>physical:sys-0/node-0/membuf-10/mbs-0/mba-1</default>

               Assuming the MBA we are accessing is under the Centaur
               not the processor.. for now.
               */
            // check to see that the Address is in the correct range
            if ((i_addr & SCOM_TRANS_MBA_MASK) == SCOM_TRANS_MBA_BASEADDR)
            {

                l_err = scomPerformTranslate(epath,
                                             TARGETING::TYPE_MBA,
                                             TARGETING::TYPE_MEMBUF,
                                             11,
                                             SCOM_TRANS_MBA_MASK,
                                             i_target,
                                             i_addr );
            }
            else
            {
                // got and error.. bad address.. write an errorlog..
                l_invalidAddr = true;
            }
	}
        else
	{
            //*** temporarily put an error log indicating not supported until we have info
            // from the hardware team
            TRACFCOMP(g_trac_scom, "SCOM_TRANSLATE.. Invalid target type=0x%X", l_type);

            /*@
             * @errortype
             * @moduleid     SCOM::SCOM_TRANSLATE
             * @reasoncode   SCOM::SCOM_TRANS_INVALID_TYPE
             * @userdata1    Address
             * @userdata2    Target Type that failed
             * @devdesc      Scom Translate not supported for this type
             */
             l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                             SCOM_TRANSLATE,
                                             SCOM_TRANS_INVALID_TYPE,
                                             i_addr,
                                             l_type);


	}
    }

    if (l_invalidAddr)
    {

        TRACFCOMP(g_trac_scom, "scomTranslate-Invalid Address i_addr=0x%X", i_addr);

       /*@
       * @errortype
       * @moduleid     SCOM::SCOM_TRANSLATE
       * @reasoncode   SCOM::SCOM_INVALID_ADDR
       * @userdata1    Address
       * @userdata2    Unit type that failed
       * @devdesc      Invalid address for that unit
       */
       l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                       SCOM_TRANSLATE,
                                       SCOM_INVALID_ADDR,
                                       i_addr,
                                       l_type);
       l_err->collectTrace("SCOM",1024);

    }

    if (l_err == NULL)
    {

       // call the routine that will do the indirect scom
       // and then call the correct device driver.
       l_err = SCOM::checkIndirectAndDoScom(i_opType,
                                            i_target,
                                            io_buffer,
                                            io_buflen,
                                            i_accessType,
                                            i_addr);
    }
    return l_err;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
errlHndl_t scomPerformTranslate(TARGETING::EntityPath i_epath,
                                TARGETING::TYPE i_ctype,
                                TARGETING::TYPE i_ptype,
                                int i_shift,
                                int i_mask,
                                TARGETING::Target * &o_target,
                                uint64_t &i_addr )
{

    errlHndl_t l_err = NULL;

    uint64_t l_instance;

    // Need to extract what instance of the entity we are at we are
    // for this target.
    l_instance = i_epath.pathElementOfType(i_ctype).instance;

    // shift the instance variable over specificed number of
    // bits with the chiplet area
    l_instance = l_instance << i_shift;

    // Check the address against the mask
    if (i_addr & i_mask)
    {
       // add the instance of this target to the address
       i_addr = i_addr | l_instance;
    }
    else
    {
        /*@
         * @errortype
         * @moduleid     SCOM::SCOM_PERFORM_TRANSLATE
         * @reasoncode   SCOM::SCOM_INVALID_ADDR
         * @userdata1    Address
         * @userdata2    Unit type that failed
         * @devdesc      Invalid Address for the mask passed in.
         */
        l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                        SCOM_PERFORM_TRANSLATE,
                                        SCOM_INVALID_ADDR,
                                        i_addr,
                                        o_target->getAttr<TARGETING::ATTR_TYPE>());

        l_err->collectTrace("SCOM",1024);

        TRACFCOMP(g_trac_scom,"SCOMPERFORMTRANSLATE Invalid Address.i_addr =0x%X for mask = 0x%X", i_addr, i_mask);

        return (l_err);
    }


    l_err = scomfindParentTarget(i_epath,
                                 i_ptype,
                                 o_target);

    return l_err;

}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
errlHndl_t scomfindParentTarget( TARGETING::EntityPath i_epath,
                                 TARGETING::TYPE i_ptype,
                                 TARGETING::Target * &o_target)
{

    errlHndl_t l_err = NULL;

    bool foundParent = false;

    // This routine passes in a given target.. the goal is to find its parent
    // target that matches the passed in parent type.

    // This loop takes the last item off the entity path and
    // checks to see if it matches the parent type.. If it does
    // we exit.. it continues to loop until it either finds
    // a match, or runs out of elements. 
    do
    {
       // remove the last entry from the entity path.. 
        i_epath.removeLast();

        int lastEntry = i_epath.size() - 1;

        // if the type equals the type passed in. then create the target
        if (i_epath[lastEntry].type == i_ptype)
        {
             // return the target to be the parent type.
             o_target = TARGETING::targetService().toTarget(i_epath);

             foundParent = true;

             break;
        }
    }
    while (i_epath.size() != 0);

    if (!foundParent)
    {
        // got and error.. bad address.. write an errorlog..
        /*@
         * @errortype
         * @moduleid     SCOM::SCOM_PERFORM_TRANSLATE
         * @reasoncode   SCOM::SCOM_NO_MATCHING_PARENT
         * @userdata1    Parent type requested
         * @userdata2    Unit type that failed
         * @devdesc      Did not find parent type requested
         */
        l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                     SCOM_FIND_PARENT_TARGET,
                                     SCOM_NO_MATCHING_PARENT,
                                     i_ptype,
                                     o_target->getAttr<TARGETING::ATTR_TYPE>());

        l_err->collectTrace("SCOM",1024);

        // Need to write and errorlog and return..
        TRACFCOMP(g_trac_scom, "TRANSLATE..Did not find parent type=0x%X ", i_ptype);
    }

    return l_err;
}


} // end namespace
OpenPOWER on IntegriCloud