~ubuntu-branches/ubuntu/trusty/xserver-xorg-video-geode-lts-utopic/trusty-proposed

« back to all changes in this revision

Viewing changes to src/cim/cim_msr.c

  • Committer: Package Import Robot
  • Author(s): Maarten Lankhorst
  • Date: 2015-01-06 10:39:17 UTC
  • Revision ID: package-import@ubuntu.com-20150106103917-bumwel1243pseqs6
Tags: upstream-2.11.16
ImportĀ upstreamĀ versionĀ 2.11.16

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2006 Advanced Micro Devices, Inc.
 
3
 *
 
4
 * Permission is hereby granted, free of charge, to any person obtaining a
 
5
 * copy of this software and associated documentation files (the "Software"),
 
6
 * to deal in the Software without restriction, including without limitation
 
7
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
8
 * and/or sell copies of the Software, and to permit persons to whom the
 
9
 * Software is furnished to do so, subject to the following conditions:
 
10
 *
 
11
 * The above copyright notice and this permission notice shall be included in
 
12
 * all copies or substantial portions of the Software.
 
13
 *
 
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
15
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
16
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
17
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
18
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
19
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
20
 * DEALINGS IN THE SOFTWARE.
 
21
 *
 
22
 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
 
23
 * contributors may be used to endorse or promote products derived from this
 
24
 * software without specific prior written permission.
 
25
 */
 
26
 
 
27
 /*
 
28
  * Cimarron MSR access routines.  These routines allow the user to query the
 
29
  * state of the GeodeLink Bus and read and write model-specfic registers.
 
30
  */
 
31
 
 
32
/*--------------------------------------------------------------*/
 
33
/* MSR GLOBALS                                                  */
 
34
/* These variables hold a local copy of the GeodeLink mapping   */
 
35
/* as well as a lookup table for easy device addressing.        */
 
36
/*--------------------------------------------------------------*/
 
37
 
 
38
GEODELINK_NODE gliu_nodes[24];
 
39
GEODELINK_NODE msr_dev_lookup[MSR_DEVICE_EMPTY];
 
40
 
 
41
#define GET_DEVICE_ID(macrohigh, macrolow) ((macrolow >> 12) & 0xFF)
 
42
 
 
43
/*---------------------------------------------------------------------------
 
44
 * msr_init_table
 
45
 *
 
46
 * This routine intializes the internal MSR table in Cimarron.  This table is
 
47
 * used for any MSR device accesses.
 
48
 *--------------------------------------------------------------------------*/
 
49
 
 
50
int
 
51
msr_init_table(void)
 
52
{
 
53
    Q_WORD msr_value = { 0, 0 };
 
54
    unsigned int i, j;
 
55
    int return_value = CIM_STATUS_OK;
 
56
 
 
57
    /* CHECK FOR VALID GEODELINK CONFIGURATION
 
58
     * The CPU and the three GLIUs are assumed to be at known static
 
59
     * addresses, so we will check the device IDs at these addresses as proof
 
60
     * of a valid GeodeLink configuration 
 
61
     */
 
62
 
 
63
    MSR_READ(MSR_GEODELINK_CAP, MSR_ADDRESS_VAIL, &msr_value);
 
64
    if (GET_DEVICE_ID(msr_value.high, msr_value.low) != MSR_CLASS_CODE_VAIL)
 
65
        return_value = CIM_STATUS_ERROR;
 
66
 
 
67
    MSR_READ(MSR_GEODELINK_CAP, MSR_ADDRESS_GLIU0, &msr_value);
 
68
    if (GET_DEVICE_ID(msr_value.high, msr_value.low) != MSR_CLASS_CODE_GLIU)
 
69
        return_value = CIM_STATUS_ERROR;
 
70
 
 
71
    MSR_READ(MSR_GEODELINK_CAP, MSR_ADDRESS_GLIU1, &msr_value);
 
72
    if (GET_DEVICE_ID(msr_value.high, msr_value.low) != MSR_CLASS_CODE_GLIU)
 
73
        return_value = CIM_STATUS_ERROR;
 
74
 
 
75
    MSR_READ(MSR_GEODELINK_CAP, MSR_ADDRESS_GLIU2, &msr_value);
 
76
    if (GET_DEVICE_ID(msr_value.high, msr_value.low) != MSR_CLASS_CODE_GLIU)
 
77
        return_value = CIM_STATUS_ERROR;
 
78
 
 
79
    if (return_value == CIM_STATUS_OK) {
 
80
        /* BUILD LOCAL COPY OF THE GEODELINK BUS */
 
81
 
 
82
        msr_create_geodelink_table(gliu_nodes);
 
83
 
 
84
        /* CLEAR TABLE STATUS */
 
85
 
 
86
        for (i = 0; i < MSR_DEVICE_EMPTY; i++)
 
87
            msr_dev_lookup[i].device_id = MSR_DEVICE_NOTFOUND;
 
88
 
 
89
        /* CREATE EASY LOOKUP TABLE FOR FUTURE HARDWARE ACCESS    */
 
90
        /* Note that MSR_DEVICE_EMPTY is the index after the last */
 
91
        /* available device.  Also note that we fill in known     */
 
92
        /* devices before filling in the rest of the table.       */
 
93
 
 
94
        msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU0].address_from_cpu =
 
95
            MSR_ADDRESS_GLIU0;
 
96
        msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU0].device_id = MSR_DEVICE_PRESENT;
 
97
        msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU1].address_from_cpu =
 
98
            MSR_ADDRESS_GLIU1;
 
99
        msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU1].device_id = MSR_DEVICE_PRESENT;
 
100
        msr_dev_lookup[MSR_DEVICE_5535_GLIU].address_from_cpu =
 
101
            MSR_ADDRESS_GLIU2;
 
102
        msr_dev_lookup[MSR_DEVICE_5535_GLIU].device_id = MSR_DEVICE_PRESENT;
 
103
        msr_dev_lookup[MSR_DEVICE_GEODELX_VAIL].address_from_cpu =
 
104
            MSR_ADDRESS_VAIL;
 
105
        msr_dev_lookup[MSR_DEVICE_GEODELX_VAIL].device_id = MSR_DEVICE_PRESENT;
 
106
 
 
107
        for (i = 0; i < MSR_DEVICE_EMPTY; i++) {
 
108
            if (msr_dev_lookup[i].device_id == MSR_DEVICE_NOTFOUND) {
 
109
                for (j = 0; j < 24; j++) {
 
110
                    if (gliu_nodes[j].device_id == i)
 
111
                        break;
 
112
                }
 
113
 
 
114
                if (j == 24)
 
115
                    msr_dev_lookup[i].device_id = MSR_DEVICE_NOTFOUND;
 
116
                else {
 
117
                    msr_dev_lookup[i].device_id = MSR_DEVICE_PRESENT;
 
118
                    msr_dev_lookup[i].address_from_cpu =
 
119
                        gliu_nodes[j].address_from_cpu;
 
120
                }
 
121
            }
 
122
        }
 
123
    }
 
124
    else {
 
125
        /* ERROR OUT THE GEODELINK TABLES */
 
126
 
 
127
        for (i = 0; i < 24; i++) {
 
128
            gliu_nodes[i].address_from_cpu = 0xFFFFFFFF;
 
129
            gliu_nodes[i].device_id = MSR_DEVICE_EMPTY;
 
130
        }
 
131
 
 
132
        for (i = 0; i < MSR_DEVICE_EMPTY; i++) {
 
133
            msr_dev_lookup[i].address_from_cpu = 0xFFFFFFFF;
 
134
            msr_dev_lookup[i].device_id = MSR_DEVICE_NOTFOUND;
 
135
        }
 
136
    }
 
137
    return return_value;
 
138
}
 
139
 
 
140
/*---------------------------------------------------------------------------
 
141
 * msr_create_geodelink_table
 
142
 *
 
143
 * This routine dumps the contents of the GeodeLink bus into an array of
 
144
 * 24 GEODELINK_NODE structures.  Indexes 0-7 represent ports 0-7 of GLIU0,
 
145
 * indexes 8-15 represent ports 0-7 of GLIU1 and indexes 16-23 represent
 
146
 * ports 0-7 of GLIU2 (5535).
 
147
 *--------------------------------------------------------------------------*/
 
148
 
 
149
int
 
150
msr_create_geodelink_table(GEODELINK_NODE * gliu_nodes)
 
151
{
 
152
    unsigned long mbiu_port_count, reflective;
 
153
    unsigned long port, index;
 
154
    unsigned long gliu_count = 0;
 
155
    int glcp_count = 0;
 
156
    int usb_count = 0;
 
157
    int mpci_count = 0;
 
158
    Q_WORD msr_value = { 0, 0 };
 
159
 
 
160
    /* ALL THREE GLIUS ARE IN ONE ARRAY                               */
 
161
    /* Entries 0-7 contain the port information for GLIU0, entries    */
 
162
    /* 8-15 contain GLIU1 and 15-23 contain GLIU2.  We perform the    */
 
163
    /* enumeration in two passes.  The first simply fills in the      */
 
164
    /* addresses and class codes at each node.  The second pass       */
 
165
    /* translates the class codes into indexes into Cimarron's device */
 
166
    /* lookup table.                                                  */
 
167
 
 
168
    /* COUNT GLIU0 PORTS */
 
169
 
 
170
    MSR_READ(MSR_GLIU_CAP, MSR_ADDRESS_GLIU0, &msr_value);
 
171
    mbiu_port_count = (msr_value.high >> NUM_PORTS_SHIFT) & 7;
 
172
 
 
173
    /* FIND REFLECTIVE PORT */
 
174
    /* Query the GLIU for the port through which we are communicating. */
 
175
    /* We will avoid accesses to this port to avoid a self-reference.  */
 
176
 
 
177
    MSR_READ(MSR_GLIU_WHOAMI, MSR_ADDRESS_GLIU0, &msr_value);
 
178
    reflective = msr_value.low & WHOAMI_MASK;
 
179
 
 
180
    /* SPECIAL CASE FOR PORT 0 */
 
181
    /* GLIU0 port 0 is a special case, as it points back to GLIU0.  GLIU0 */
 
182
    /* responds at address 0x10000xxx, which does not equal 0 << 29.      */
 
183
 
 
184
    gliu_nodes[0].address_from_cpu = MSR_ADDRESS_GLIU0;
 
185
    gliu_nodes[0].device_id = MSR_CLASS_CODE_GLIU;
 
186
 
 
187
    /* ENUMERATE ALL PORTS */
 
188
 
 
189
    for (port = 1; port < 8; port++) {
 
190
        /* FILL IN ADDRESS */
 
191
 
 
192
        gliu_nodes[port].address_from_cpu = port << 29;
 
193
 
 
194
        if (port == reflective)
 
195
            gliu_nodes[port].device_id = MSR_CLASS_CODE_REFLECTIVE;
 
196
        else if (port > mbiu_port_count)
 
197
            gliu_nodes[port].device_id = MSR_CLASS_CODE_UNPOPULATED;
 
198
        else {
 
199
            MSR_READ(MSR_GEODELINK_CAP, gliu_nodes[port].address_from_cpu,
 
200
                     &msr_value);
 
201
            gliu_nodes[port].device_id =
 
202
                GET_DEVICE_ID(msr_value.high, msr_value.low);
 
203
        }
 
204
    }
 
205
 
 
206
    /* COUNT GLIU1 PORTS */
 
207
 
 
208
    MSR_READ(MSR_GLIU_CAP, MSR_ADDRESS_GLIU1, &msr_value);
 
209
    mbiu_port_count = (msr_value.high >> NUM_PORTS_SHIFT) & 7;
 
210
 
 
211
    /* FIND REFLECTIVE PORT */
 
212
 
 
213
    MSR_READ(MSR_GLIU_WHOAMI, MSR_ADDRESS_GLIU1, &msr_value);
 
214
    reflective = msr_value.low & WHOAMI_MASK;
 
215
 
 
216
    /* ENUMERATE ALL PORTS */
 
217
 
 
218
    for (port = 0; port < 8; port++) {
 
219
        index = port + 8;
 
220
 
 
221
        /* FILL IN ADDRESS */
 
222
 
 
223
        gliu_nodes[index].address_from_cpu = (0x02l << 29) + (port << 26);
 
224
 
 
225
        if (port == reflective)
 
226
            gliu_nodes[index].device_id = MSR_CLASS_CODE_REFLECTIVE;
 
227
        else if (port > mbiu_port_count)
 
228
            gliu_nodes[index].device_id = MSR_CLASS_CODE_UNPOPULATED;
 
229
        else {
 
230
            MSR_READ(MSR_GEODELINK_CAP, gliu_nodes[index].address_from_cpu,
 
231
                     &msr_value);
 
232
            gliu_nodes[index].device_id =
 
233
                GET_DEVICE_ID(msr_value.high, msr_value.low);
 
234
        }
 
235
    }
 
236
 
 
237
    /* COUNT GLIU2 PORTS */
 
238
 
 
239
    MSR_READ(MSR_GLIU_CAP, MSR_ADDRESS_GLIU2, &msr_value);
 
240
    mbiu_port_count = (msr_value.high >> NUM_PORTS_SHIFT) & 7;
 
241
 
 
242
    /* FIND REFLECTIVE PORT */
 
243
 
 
244
    MSR_READ(MSR_GLIU_WHOAMI, MSR_ADDRESS_GLIU2, &msr_value);
 
245
    reflective = msr_value.low & WHOAMI_MASK;
 
246
 
 
247
    /* FILL IN PORT 0 AND 1 */
 
248
    /* Port 0 on 5535 is MBIU2.  Port 1 is MPCI, but it is referenced at */
 
249
    /* a special address.                                                */
 
250
 
 
251
    gliu_nodes[16].address_from_cpu = MSR_ADDRESS_GLIU2;
 
252
    gliu_nodes[16].device_id = MSR_CLASS_CODE_GLIU;
 
253
 
 
254
    gliu_nodes[17].address_from_cpu = MSR_ADDRESS_5535MPCI;
 
255
    gliu_nodes[17].device_id = MSR_CLASS_CODE_MPCI;
 
256
 
 
257
    /* ENUMERATE ALL PORTS */
 
258
 
 
259
    for (port = 2; port < 8; port++) {
 
260
        index = port + 16;
 
261
 
 
262
        /* FILL IN ADDRESS */
 
263
 
 
264
        gliu_nodes[index].address_from_cpu =
 
265
            (0x02l << 29) + (0x04l << 26) + (0x02l << 23) + (port << 20);
 
266
 
 
267
        if (port == reflective)
 
268
            gliu_nodes[index].device_id = MSR_CLASS_CODE_REFLECTIVE;
 
269
        else if (port > mbiu_port_count)
 
270
            gliu_nodes[index].device_id = MSR_CLASS_CODE_UNPOPULATED;
 
271
        else {
 
272
            MSR_READ(MSR_GEODELINK_CAP, gliu_nodes[index].address_from_cpu,
 
273
                     &msr_value);
 
274
            gliu_nodes[index].device_id =
 
275
                GET_DEVICE_ID(msr_value.high, msr_value.low);
 
276
        }
 
277
    }
 
278
 
 
279
    /* SECOND PASS - TRANSLATION */
 
280
    /* Now that the class codes for each device are stored in the  */
 
281
    /* array, we walk through the array and translate the class    */
 
282
    /* codes to table indexes.  For class codes that have multiple */
 
283
    /* instances, the table indexes are sequential.                */
 
284
 
 
285
    for (port = 0; port < 24; port++) {
 
286
        /* SPECIAL CASE FOR GLIU UNITS */
 
287
        /* A GLIU can be both on another port and on its own port.  These  */
 
288
        /* end up as the same address, but are shown as duplicate nodes in */
 
289
        /* the GeodeLink table.                                            */
 
290
 
 
291
        if ((port & 7) == 0)
 
292
            gliu_count = port >> 3;
 
293
 
 
294
        switch (gliu_nodes[port].device_id) {
 
295
            /* UNPOPULATED OR REFLECTIVE NODES */
 
296
 
 
297
        case MSR_CLASS_CODE_UNPOPULATED:
 
298
            index = MSR_DEVICE_EMPTY;
 
299
            break;
 
300
        case MSR_CLASS_CODE_REFLECTIVE:
 
301
            index = MSR_DEVICE_REFLECTIVE;
 
302
            break;
 
303
 
 
304
            /* KNOWN CLASS CODES */
 
305
 
 
306
        case MSR_CLASS_CODE_GLIU:
 
307
            index = MSR_DEVICE_GEODELX_GLIU0 + gliu_count++;
 
308
            break;
 
309
        case MSR_CLASS_CODE_GLCP:
 
310
            index = MSR_DEVICE_GEODELX_GLCP + glcp_count++;
 
311
            break;
 
312
        case MSR_CLASS_CODE_MPCI:
 
313
            index = MSR_DEVICE_GEODELX_MPCI + mpci_count++;
 
314
            break;
 
315
        case MSR_CLASS_CODE_USB:
 
316
            index = MSR_DEVICE_5535_USB2 + usb_count++;
 
317
            break;
 
318
        case MSR_CLASS_CODE_USB2:
 
319
            index = MSR_DEVICE_5536_USB_2_0;
 
320
            break;
 
321
        case MSR_CLASS_CODE_ATAC:
 
322
            index = MSR_DEVICE_5535_ATAC;
 
323
            break;
 
324
        case MSR_CLASS_CODE_MDD:
 
325
            index = MSR_DEVICE_5535_MDD;
 
326
            break;
 
327
        case MSR_CLASS_CODE_ACC:
 
328
            index = MSR_DEVICE_5535_ACC;
 
329
            break;
 
330
        case MSR_CLASS_CODE_MC:
 
331
            index = MSR_DEVICE_GEODELX_MC;
 
332
            break;
 
333
        case MSR_CLASS_CODE_GP:
 
334
            index = MSR_DEVICE_GEODELX_GP;
 
335
            break;
 
336
        case MSR_CLASS_CODE_VG:
 
337
            index = MSR_DEVICE_GEODELX_VG;
 
338
            break;
 
339
        case MSR_CLASS_CODE_DF:
 
340
            index = MSR_DEVICE_GEODELX_DF;
 
341
            break;
 
342
        case MSR_CLASS_CODE_FG:
 
343
            index = MSR_DEVICE_GEODELX_FG;
 
344
            break;
 
345
        case MSR_CLASS_CODE_VIP:
 
346
            index = MSR_DEVICE_GEODELX_VIP;
 
347
            break;
 
348
        case MSR_CLASS_CODE_AES:
 
349
            index = MSR_DEVICE_GEODELX_AES;
 
350
            break;
 
351
        case MSR_CLASS_CODE_VAIL:
 
352
            index = MSR_DEVICE_GEODELX_VAIL;
 
353
            break;
 
354
        default:
 
355
            index = MSR_DEVICE_EMPTY;
 
356
            break;
 
357
        }
 
358
 
 
359
        gliu_nodes[port].device_id = index;
 
360
    }
 
361
 
 
362
    return CIM_STATUS_OK;
 
363
}
 
364
 
 
365
/*---------------------------------------------------------------------------
 
366
 * msr_create_device_list
 
367
 *
 
368
 * This routine dumps a list of all known GeodeLX/5535 devices as well as their
 
369
 * respective status and address.
 
370
 *--------------------------------------------------------------------------*/
 
371
 
 
372
int
 
373
msr_create_device_list(GEODELINK_NODE * gliu_nodes, int max_devices)
 
374
{
 
375
    int i, count;
 
376
 
 
377
    if (max_devices < MSR_DEVICE_EMPTY)
 
378
        count = max_devices;
 
379
    else
 
380
        count = MSR_DEVICE_EMPTY;
 
381
 
 
382
    for (i = 0; i < count; i++) {
 
383
        gliu_nodes[i].address_from_cpu = msr_dev_lookup[i].address_from_cpu;
 
384
        gliu_nodes[i].device_id = msr_dev_lookup[i].device_id;
 
385
    }
 
386
 
 
387
    return CIM_STATUS_OK;
 
388
}
 
389
 
 
390
/*--------------------------------------------------------------------
 
391
 * msr_read64
 
392
 *
 
393
 * Performs a 64-bit read from 'msr_register' in device 'device'.  'device' is
 
394
 * an index into Cimarron's table of known GeodeLink devices.
 
395
 *-------------------------------------------------------------------*/
 
396
 
 
397
int
 
398
msr_read64(unsigned long device, unsigned long msr_register, Q_WORD * msr_value)
 
399
{
 
400
    if (device < MSR_DEVICE_EMPTY) {
 
401
        if (msr_dev_lookup[device].device_id == MSR_DEVICE_PRESENT) {
 
402
            MSR_READ(msr_register, msr_dev_lookup[device].address_from_cpu,
 
403
                     msr_value);
 
404
            return CIM_STATUS_OK;
 
405
        }
 
406
    }
 
407
 
 
408
    msr_value->low = msr_value->high = 0;
 
409
    return CIM_STATUS_DEVNOTFOUND;
 
410
}
 
411
 
 
412
/*--------------------------------------------------------------------
 
413
 * msr_write64
 
414
 *
 
415
 * Performs a 64-bit write to 'msr_register' in device 'device'.  'device' is
 
416
 * an index into Cimarron's table of known GeodeLink devices.
 
417
 *-------------------------------------------------------------------*/
 
418
 
 
419
int
 
420
msr_write64(unsigned long device, unsigned long msr_register,
 
421
            Q_WORD * msr_value)
 
422
{
 
423
    if (device < MSR_DEVICE_EMPTY) {
 
424
        if (msr_dev_lookup[device].device_id == MSR_DEVICE_PRESENT) {
 
425
            MSR_WRITE(msr_register, msr_dev_lookup[device].address_from_cpu,
 
426
                      msr_value);
 
427
            return CIM_STATUS_OK;
 
428
        }
 
429
    }
 
430
    return CIM_STATUS_DEVNOTFOUND;
 
431
}