2
* Copyright (c) 2006 Advanced Micro Devices, Inc.
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:
11
* The above copyright notice and this permission notice shall be included in
12
* all copies or substantial portions of the Software.
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.
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.
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.
32
/*--------------------------------------------------------------*/
34
/* These variables hold a local copy of the GeodeLink mapping */
35
/* as well as a lookup table for easy device addressing. */
36
/*--------------------------------------------------------------*/
38
GEODELINK_NODE gliu_nodes[24];
39
GEODELINK_NODE msr_dev_lookup[MSR_DEVICE_EMPTY];
41
#define GET_DEVICE_ID(macrohigh, macrolow) ((macrolow >> 12) & 0xFF)
43
/*---------------------------------------------------------------------------
46
* This routine intializes the internal MSR table in Cimarron. This table is
47
* used for any MSR device accesses.
48
*--------------------------------------------------------------------------*/
53
Q_WORD msr_value = { 0, 0 };
55
int return_value = CIM_STATUS_OK;
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
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;
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;
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;
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;
79
if (return_value == CIM_STATUS_OK) {
80
/* BUILD LOCAL COPY OF THE GEODELINK BUS */
82
msr_create_geodelink_table(gliu_nodes);
84
/* CLEAR TABLE STATUS */
86
for (i = 0; i < MSR_DEVICE_EMPTY; i++)
87
msr_dev_lookup[i].device_id = MSR_DEVICE_NOTFOUND;
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. */
94
msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU0].address_from_cpu =
96
msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU0].device_id = MSR_DEVICE_PRESENT;
97
msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU1].address_from_cpu =
99
msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU1].device_id = MSR_DEVICE_PRESENT;
100
msr_dev_lookup[MSR_DEVICE_5535_GLIU].address_from_cpu =
102
msr_dev_lookup[MSR_DEVICE_5535_GLIU].device_id = MSR_DEVICE_PRESENT;
103
msr_dev_lookup[MSR_DEVICE_GEODELX_VAIL].address_from_cpu =
105
msr_dev_lookup[MSR_DEVICE_GEODELX_VAIL].device_id = MSR_DEVICE_PRESENT;
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)
115
msr_dev_lookup[i].device_id = MSR_DEVICE_NOTFOUND;
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;
125
/* ERROR OUT THE GEODELINK TABLES */
127
for (i = 0; i < 24; i++) {
128
gliu_nodes[i].address_from_cpu = 0xFFFFFFFF;
129
gliu_nodes[i].device_id = MSR_DEVICE_EMPTY;
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;
140
/*---------------------------------------------------------------------------
141
* msr_create_geodelink_table
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
*--------------------------------------------------------------------------*/
150
msr_create_geodelink_table(GEODELINK_NODE * gliu_nodes)
152
unsigned long mbiu_port_count, reflective;
153
unsigned long port, index;
154
unsigned long gliu_count = 0;
158
Q_WORD msr_value = { 0, 0 };
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 */
168
/* COUNT GLIU0 PORTS */
170
MSR_READ(MSR_GLIU_CAP, MSR_ADDRESS_GLIU0, &msr_value);
171
mbiu_port_count = (msr_value.high >> NUM_PORTS_SHIFT) & 7;
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. */
177
MSR_READ(MSR_GLIU_WHOAMI, MSR_ADDRESS_GLIU0, &msr_value);
178
reflective = msr_value.low & WHOAMI_MASK;
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. */
184
gliu_nodes[0].address_from_cpu = MSR_ADDRESS_GLIU0;
185
gliu_nodes[0].device_id = MSR_CLASS_CODE_GLIU;
187
/* ENUMERATE ALL PORTS */
189
for (port = 1; port < 8; port++) {
190
/* FILL IN ADDRESS */
192
gliu_nodes[port].address_from_cpu = port << 29;
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;
199
MSR_READ(MSR_GEODELINK_CAP, gliu_nodes[port].address_from_cpu,
201
gliu_nodes[port].device_id =
202
GET_DEVICE_ID(msr_value.high, msr_value.low);
206
/* COUNT GLIU1 PORTS */
208
MSR_READ(MSR_GLIU_CAP, MSR_ADDRESS_GLIU1, &msr_value);
209
mbiu_port_count = (msr_value.high >> NUM_PORTS_SHIFT) & 7;
211
/* FIND REFLECTIVE PORT */
213
MSR_READ(MSR_GLIU_WHOAMI, MSR_ADDRESS_GLIU1, &msr_value);
214
reflective = msr_value.low & WHOAMI_MASK;
216
/* ENUMERATE ALL PORTS */
218
for (port = 0; port < 8; port++) {
221
/* FILL IN ADDRESS */
223
gliu_nodes[index].address_from_cpu = (0x02l << 29) + (port << 26);
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;
230
MSR_READ(MSR_GEODELINK_CAP, gliu_nodes[index].address_from_cpu,
232
gliu_nodes[index].device_id =
233
GET_DEVICE_ID(msr_value.high, msr_value.low);
237
/* COUNT GLIU2 PORTS */
239
MSR_READ(MSR_GLIU_CAP, MSR_ADDRESS_GLIU2, &msr_value);
240
mbiu_port_count = (msr_value.high >> NUM_PORTS_SHIFT) & 7;
242
/* FIND REFLECTIVE PORT */
244
MSR_READ(MSR_GLIU_WHOAMI, MSR_ADDRESS_GLIU2, &msr_value);
245
reflective = msr_value.low & WHOAMI_MASK;
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. */
251
gliu_nodes[16].address_from_cpu = MSR_ADDRESS_GLIU2;
252
gliu_nodes[16].device_id = MSR_CLASS_CODE_GLIU;
254
gliu_nodes[17].address_from_cpu = MSR_ADDRESS_5535MPCI;
255
gliu_nodes[17].device_id = MSR_CLASS_CODE_MPCI;
257
/* ENUMERATE ALL PORTS */
259
for (port = 2; port < 8; port++) {
262
/* FILL IN ADDRESS */
264
gliu_nodes[index].address_from_cpu =
265
(0x02l << 29) + (0x04l << 26) + (0x02l << 23) + (port << 20);
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;
272
MSR_READ(MSR_GEODELINK_CAP, gliu_nodes[index].address_from_cpu,
274
gliu_nodes[index].device_id =
275
GET_DEVICE_ID(msr_value.high, msr_value.low);
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. */
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. */
292
gliu_count = port >> 3;
294
switch (gliu_nodes[port].device_id) {
295
/* UNPOPULATED OR REFLECTIVE NODES */
297
case MSR_CLASS_CODE_UNPOPULATED:
298
index = MSR_DEVICE_EMPTY;
300
case MSR_CLASS_CODE_REFLECTIVE:
301
index = MSR_DEVICE_REFLECTIVE;
304
/* KNOWN CLASS CODES */
306
case MSR_CLASS_CODE_GLIU:
307
index = MSR_DEVICE_GEODELX_GLIU0 + gliu_count++;
309
case MSR_CLASS_CODE_GLCP:
310
index = MSR_DEVICE_GEODELX_GLCP + glcp_count++;
312
case MSR_CLASS_CODE_MPCI:
313
index = MSR_DEVICE_GEODELX_MPCI + mpci_count++;
315
case MSR_CLASS_CODE_USB:
316
index = MSR_DEVICE_5535_USB2 + usb_count++;
318
case MSR_CLASS_CODE_USB2:
319
index = MSR_DEVICE_5536_USB_2_0;
321
case MSR_CLASS_CODE_ATAC:
322
index = MSR_DEVICE_5535_ATAC;
324
case MSR_CLASS_CODE_MDD:
325
index = MSR_DEVICE_5535_MDD;
327
case MSR_CLASS_CODE_ACC:
328
index = MSR_DEVICE_5535_ACC;
330
case MSR_CLASS_CODE_MC:
331
index = MSR_DEVICE_GEODELX_MC;
333
case MSR_CLASS_CODE_GP:
334
index = MSR_DEVICE_GEODELX_GP;
336
case MSR_CLASS_CODE_VG:
337
index = MSR_DEVICE_GEODELX_VG;
339
case MSR_CLASS_CODE_DF:
340
index = MSR_DEVICE_GEODELX_DF;
342
case MSR_CLASS_CODE_FG:
343
index = MSR_DEVICE_GEODELX_FG;
345
case MSR_CLASS_CODE_VIP:
346
index = MSR_DEVICE_GEODELX_VIP;
348
case MSR_CLASS_CODE_AES:
349
index = MSR_DEVICE_GEODELX_AES;
351
case MSR_CLASS_CODE_VAIL:
352
index = MSR_DEVICE_GEODELX_VAIL;
355
index = MSR_DEVICE_EMPTY;
359
gliu_nodes[port].device_id = index;
362
return CIM_STATUS_OK;
365
/*---------------------------------------------------------------------------
366
* msr_create_device_list
368
* This routine dumps a list of all known GeodeLX/5535 devices as well as their
369
* respective status and address.
370
*--------------------------------------------------------------------------*/
373
msr_create_device_list(GEODELINK_NODE * gliu_nodes, int max_devices)
377
if (max_devices < MSR_DEVICE_EMPTY)
380
count = MSR_DEVICE_EMPTY;
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;
387
return CIM_STATUS_OK;
390
/*--------------------------------------------------------------------
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
*-------------------------------------------------------------------*/
398
msr_read64(unsigned long device, unsigned long msr_register, Q_WORD * msr_value)
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,
404
return CIM_STATUS_OK;
408
msr_value->low = msr_value->high = 0;
409
return CIM_STATUS_DEVNOTFOUND;
412
/*--------------------------------------------------------------------
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
*-------------------------------------------------------------------*/
420
msr_write64(unsigned long device, unsigned long msr_register,
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,
427
return CIM_STATUS_OK;
430
return CIM_STATUS_DEVNOTFOUND;