1
/* Copyright (c) 2005 Advanced Micro Devices, Inc.
3
* Permission is hereby granted, free of charge, to any person obtaining a copy
4
* of this software and associated documentation files (the "Software"), to
5
* deal in the Software without restriction, including without limitation the
6
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
* sell copies of the Software, and to permit persons to whom the Software is
8
* furnished to do so, subject to the following conditions:
10
* The above copyright notice and this permission notice shall be included in
11
* all copies or substantial portions of the Software.
13
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
* Neither the name of the Advanced Micro Devices, Inc. nor the names of its
22
* contributors may be used to endorse or promote products derived from this
23
* software without specific prior written permission.
27
* This file contains MSR access routines for Redcloud.
30
void redcloud_build_mbus_tree(void); /* private routine definition */
31
int redcloud_init_msr_devices(MSR aDev[], unsigned int array_size);
33
/* private routine definition */
34
DEV_STATUS redcloud_find_msr_device(MSR * pDev);
36
/* private routine definition */
38
/* REDCLOUD MSR BITMASKS */
40
#define MBD_MSR_CAP 0x2000
41
#define MSR_CAP_ID_MASK 0xFF000
42
#define MSR_CAP_ID_SHIFT 12
43
#define MSR_CAP_REV_MASK 0x0F
45
#define NUM_PORTS_MASK 0x00380000
46
#define NUM_PORTS_SHIFT 19
47
#define MBIU_WHOAMI 0x8B
48
#define WHOAMI_MASK 0x07
50
/* REDCLOUD and CS5535 MSR DEVICES */
53
{FOUND, RC_CC_MBIU, RC_MB0_MBIU0},
54
{FOUND, RC_CC_MBIU, RC_MB0_MBIU1},
55
{NOT_KNOWN, RC_CC_MCP, FAKE_ADDRESS},
56
{NOT_KNOWN, RC_CC_MPCI, FAKE_ADDRESS},
57
{NOT_KNOWN, RC_CC_MC, FAKE_ADDRESS},
58
{NOT_KNOWN, RC_CC_GP, FAKE_ADDRESS},
59
{NOT_KNOWN, RC_CC_VG, FAKE_ADDRESS},
60
{NOT_KNOWN, RC_CC_DF, FAKE_ADDRESS},
61
{NOT_KNOWN, RC_CC_FG, FAKE_ADDRESS},
62
{FOUND, RC_CC_VA, RC_MB0_CPU},
63
{FOUND, CP_CC_MBIU, CP_MB0_MBIU0},
64
{NOT_KNOWN, CP_CC_MPCI, FAKE_ADDRESS},
65
{NOT_KNOWN, CP_CC_USB2, FAKE_ADDRESS},
66
{NOT_KNOWN, CP_CC_ATAC, FAKE_ADDRESS},
67
{NOT_KNOWN, CP_CC_MDD, FAKE_ADDRESS},
68
{NOT_KNOWN, CP_CC_ACC, FAKE_ADDRESS},
69
{NOT_KNOWN, CP_CC_USB1, FAKE_ADDRESS},
70
{NOT_KNOWN, CP_CC_MCP, FAKE_ADDRESS},
73
#define NUM_DEVS sizeof(msrDev) / sizeof(struct msr)
75
/* CAPISTRANO DEVICE INDEX LIMITS */
76
/* These defines represent the start and stop indexes into the device array
77
* for all Capistrano devices. These should be updated whenever a device is
78
* added or removed to the Capistrano list.
81
#define CP_INDEX_START CP_ID_MBIU
82
#define CP_INDEX_STOP CP_ID_MCP
84
/* GLOBAL MBUS CACHE STRUCTURES */
85
/* These structures contain a "cached" copy of the MBUS topology */
86
/* for easy future lookup. */
88
MBUS_NODE MBIU0[8], MBIU1[8], MBIU2[8];
92
#define GET_DEVICE_ID( CAPABILITIES_HIGH, CAPABILITIES_LOW ) \
93
((unsigned int)(( (CAPABILITIES_LOW) & MSR_CAP_ID_MASK ) >> MSR_CAP_ID_SHIFT ))
95
#define GET_NUM_PORTS( MBIU_CAP_HIGH, MBIU_CAP_LOW ) (((MBIU_CAP_HIGH) & NUM_PORTS_MASK ) >> NUM_PORTS_SHIFT)
97
/*----------------------------------------------------------------------------
100
* This routine initializes the base addresses of all known MBUS devices.
101
*----------------------------------------------------------------------------
105
redcloud_msr_init(void)
112
int return_value = 1;
114
/* CHECK FOR VALID MBUS CONFIGURATION */
115
/* The CPU and the two MBIUs are assumed to be at known static addresses,
116
* so we will check the device IDs at these addresses as proof of a valid
117
* mbus configuration.
120
MSR_READ(MBD_MSR_CAP, RC_MB0_CPU, &(msrValue.high), &(msrValue.low));
121
if (GET_DEVICE_ID(msrValue.high, msrValue.low) != RC_CC_VA)
124
MSR_READ(MBD_MSR_CAP, RC_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
125
if (GET_DEVICE_ID(msrValue.high, msrValue.low) != RC_CC_MBIU)
128
MSR_READ(MBD_MSR_CAP, RC_MB0_MBIU1, &(msrValue.high), &(msrValue.low));
129
if (GET_DEVICE_ID(msrValue.high, msrValue.low) != RC_CC_MBIU)
132
/* ENUMERATE VALID BUS */
133
/* If all static devices were identified, continue with the enumeration */
137
/* Build a local copy of the MBUS topology. This allows us to */
138
/* quickly search the entire MBUS for a given device ID without */
139
/* repeated MSR accesses. */
141
redcloud_build_mbus_tree();
143
/* INITIALIZE MSR DEVICES */
145
return_value = redcloud_init_msr_devices(msrDev, NUM_DEVS);
153
/*--------------------------------------------------------------------------
154
* void redcloud_build_mbus_tree() (PRIVATE ROUTINE - NOT PART OF DURANGO API)
156
* This routine walks through the MBUS and records the address value and
157
* device ID found at each node. If a node (aka port) is not populated,
158
* that node returns '0'. The deviceID for that node is set to '0'
159
* (NOT_POPULATED) to reflect this. If the node being queried points back to
160
* Vail or MBIU0, the deviceID for that node is set to 'REFLECTIVE'.
161
* Reflective nodes are nodes that forward the given MBUS address BACK to the
163
*----------------------------------------------------------------------------
166
redcloud_build_mbus_tree(void)
168
unsigned long mbiu_port_count, reflective;
173
/* ENUMERATE MBIU0 */
176
/* COUNT MBIU PORTS */
178
MSR_READ(MBIU_CAP, RC_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
179
mbiu_port_count = GET_NUM_PORTS(msrValue.high, msrValue.low);
181
/* FIND REFLECTIVE PORT */
182
/* Query the MBIU for the port through which we are communicating. */
183
/* We will avoid accesses to this port to avoid a self-reference. */
185
MSR_READ(MBIU_WHOAMI, RC_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
186
reflective = msrValue.low & WHOAMI_MASK;
188
/* ENUMERATE ALL PORTS */
189
/* For every possible port, set the MBIU.deviceId to something. */
191
for (port = 0; port < 8; port++) {
192
/* FILL IN CLAIMED FIELD */
193
/* All MBIU ports can only be assigned to one device from the */
196
MBIU0[port].claimed = 0;
198
/* MBIU0 PORT NUMBERS ARE IN ADDRESS BITS 31:29 */
200
MBIU0[port].address = port << 29;
202
/* SPECIAL CASE FOR MBIU0 */
203
/* MBIU0 port 0 is a special case, as it points back to MBIU0. MBIU0
204
* responds at address 0x40000xxx, which does not equal 0 << 29.
208
MBIU0[port].deviceId = RC_CC_MBIU;
209
else if (port == reflective)
210
MBIU0[port].deviceId = REFLECTIVE;
211
else if (port > mbiu_port_count)
212
MBIU0[port].deviceId = NOT_POPULATED;
214
MSR_READ(MBD_MSR_CAP, MBIU0[port].address, &(msrValue.high),
216
MBIU0[port].deviceId = GET_DEVICE_ID(msrValue.high, msrValue.low);
221
/* ENUMERATE MBIU1 */
224
/* COUNT MBIU PORTS */
226
MSR_READ(MBIU_CAP, RC_MB0_MBIU1, &(msrValue.high), &(msrValue.low));
227
mbiu_port_count = GET_NUM_PORTS(msrValue.high, msrValue.low);
229
/* FIND REFLECTIVE PORT */
230
/* Query the MBIU for the port through which we are communicating. */
231
/* We will avoid accesses to this port to avoid a self-reference. */
233
MSR_READ(MBIU_WHOAMI, RC_MB0_MBIU1, &(msrValue.high), &(msrValue.low));
234
reflective = msrValue.low & WHOAMI_MASK;
236
/* ENUMERATE ALL PORTS */
237
/* For every possible port, set the MBIU.deviceId to something. */
239
for (port = 0; port < 8; port++) {
240
/* FILL IN CLAIMED FIELD */
241
/* All MBIU ports can only be assigned to one device from the */
244
MBIU1[port].claimed = 0;
246
/* MBIU1 PORT NUMBERS ARE IN 28:26 AND 31:29 = 010B */
248
MBIU1[port].address = (0x02l << 29) + (port << 26);
250
if (port == reflective)
251
MBIU1[port].deviceId = REFLECTIVE;
252
else if (port > mbiu_port_count)
253
MBIU1[port].deviceId = NOT_POPULATED;
255
MSR_READ(MBD_MSR_CAP, MBIU1[port].address, &(msrValue.high),
257
MBIU1[port].deviceId = GET_DEVICE_ID(msrValue.high, msrValue.low);
262
/* ENUMERATE MBIU2 (CS5535) */
265
MSR_READ(MBD_MSR_CAP, CP_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
266
if (GET_DEVICE_ID(msrValue.high, msrValue.low) == CP_CC_MBIU) {
267
/* COUNT MBIU PORTS */
269
MSR_READ(MBIU_CAP, CP_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
270
mbiu_port_count = GET_NUM_PORTS(msrValue.high, msrValue.low);
272
/* FIND REFLECTIVE PORT */
273
/* Query the MBIU for the port through which we are communicating. */
274
/* We will avoid accesses to this port to avoid a self-reference. */
276
MSR_READ(MBIU_WHOAMI, CP_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
277
reflective = msrValue.low & WHOAMI_MASK;
279
/* ENUMERATE ALL PORTS */
280
/* For every possible port, set the MBIU.deviceId to something. */
282
for (port = 0; port < 8; port++) {
283
/* FILL IN CLAIMED FIELD */
284
/* All MBIU ports can only be assigned to one device from the */
287
MBIU2[port].claimed = 0;
289
/* MBIU2 PORT NUMBERS ARE IN 22:20 AND 31:23 = 010100010B */
291
MBIU2[port].address =
292
(0x02l << 29) + (0x04l << 26) + (0x02l << 23) + (port << 20);
294
if (port == reflective)
295
MBIU2[port].deviceId = REFLECTIVE;
296
else if (port > mbiu_port_count)
297
MBIU2[port].deviceId = NOT_POPULATED;
299
MSR_READ(MBD_MSR_CAP, MBIU2[port].address, &(msrValue.high),
301
MBIU2[port].deviceId =
302
GET_DEVICE_ID(msrValue.high, msrValue.low);
308
/* If the CS5535 is not installed, fill in the cached table */
309
/* with the 'NOT_INSTALLED' flag. Also, fill in the device */
310
/* status from NOT_KNOWN to REQ_NOT_INSTALLED. */
312
for (port = 0; port < 8; port++) {
313
MBIU2[port].claimed = 0;
314
MBIU2[port].deviceId = NOT_INSTALLED;
315
MBIU2[port].address =
316
(0x02l << 29) + (0x04l << 26) + (0x02l << 23) + (port << 20);
318
for (port = CP_INDEX_START; port <= CP_INDEX_STOP; port++) {
319
msrDev[port].Present = REQ_NOT_INSTALLED;
324
/*------------------------------------------------------------------
325
* redcloud_init_msr_devices (PRIVATE ROUTINE - NOT PART OF DURANGO API)
327
* Handles the details of finding each possible device on the MBUS.
328
* If a given device is not found, its structure is left uninitialized.
329
* If a given device is found, its structure is updated.
331
* This init routine only checks for devices in aDev[].
334
* aDev - is a pointer to the array of MBUS devices.
335
* arraySize - number of elements in aDev.
338
* 1 - If, for every device, its address was found.
339
* 0 - If, for any device, an error was encountered.
340
*------------------------------------------------------------------
343
redcloud_init_msr_devices(MSR aDev[], unsigned int array_size)
345
unsigned int i, issues = 0;
347
/* TRY TO FIND EACH ITEM IN THE ARRAY */
349
for (i = 0; i < array_size; i++) {
350
/* IGNORE DEVICES THAT ARE ALREADY FOUND */
351
/* The addresses for "found" devices are already known. */
353
if (aDev[i].Present == FOUND || aDev[i].Present == REQ_NOT_INSTALLED)
356
/* TRY TO FIND THE DEVICE ON THE MBUS */
358
aDev[i].Present = redcloud_find_msr_device(&aDev[i]);
360
/* INCREMENT ERROR COUNT IF DEVICE NOT FOUND */
362
if (aDev[i].Present != FOUND)
366
return (issues == 0);
369
/*------------------------------------------------------------------
370
* redcloud_find_msr_device (PRIVATE ROUTINE - NOT PART OF DURANGO API)
373
* pDev - is a pointer to one element in the array of MBUS devices
376
* FOUND - Device was found and pDev->Address has been updated.
378
* REQ_NOT_FOUND - Device was not found and pDev->Address has not
381
*------------------------------------------------------------------
384
redcloud_find_msr_device(MSR * pDev)
388
/* SEARCH DURANGO'S CACHED MBUS TOPOLOGY */
389
/* This gets a little tricky. As the only identifier we have for each
390
* device is the device ID and we have multiple devices of the same type
391
* MCP, MPCI, USB, etc. we need to make some assumptions based on table
392
* order. These are as follows:
393
* 1. All Redcloud nodes are searched first, as we assume that they
394
* are first in the table.
395
* 2. If two devices have the same device ID and are found on the same
396
* device (GX2, CS5535, etc.) we assume that they are listed such
397
* that the first device in the table with this device ID has a lower
399
* 3. After a device ID has been matched, the port is marked as
400
* 'claimed', such that future enumerations continue searching the
401
* GeodeLink topology.
406
for (i = 0; i < 8; i++) {
407
if (MBIU0[i].deviceId == pDev->Id && !(MBIU0[i].claimed)) {
408
MBIU0[i].claimed = 1;
409
pDev->Address = MBIU0[i].address;
416
for (i = 0; i < 8; i++) {
417
if (MBIU1[i].deviceId == pDev->Id && !(MBIU1[i].claimed)) {
418
MBIU1[i].claimed = 1;
419
pDev->Address = MBIU1[i].address;
426
for (i = 0; i < 8; i++) {
427
if (MBIU2[i].deviceId == pDev->Id && !(MBIU2[i].claimed)) {
428
MBIU2[i].claimed = 1;
429
pDev->Address = MBIU2[i].address;
434
return REQ_NOT_FOUND;
437
/*--------------------------------------------------------------------
440
* This routine handles reading the capabilities MSR register (typically
441
* 0x2000) and checking if the 'id' field matchs pDev.Id. This routine is
442
* used by applications/drivers that need to extend the list of known
443
* MBUS devices beyond those known by Durango.
446
* pDev - Pointer to MSR structure containing the device's ID.
447
* address - device address.
450
* FOUND - The IDs do match.
451
* REQ_NOT_FOUND - There was not a match.
453
*--------------------------------------------------------------------
457
redcloud_id_msr_device(MSR * pDev, unsigned long address)
460
gfx_id_msr_device(MSR * pDev, unsigned long address)
465
MSR_READ(MBD_MSR_CAP, address, &(msrValue.high), &(msrValue.low));
467
if (GET_DEVICE_ID(msrValue.high, msrValue.low) == pDev->Id)
470
return REQ_NOT_FOUND;
473
/*--------------------------------------------------------------------
474
* gfx_get_msr_dev_address
476
* This function returns the 32-bit address of the requested device.
477
* The device must be a known MBUS device. (It must be in Durango's
478
* device table.) DEV_STATUS should be checked to verify that the address
483
* device - device index of the device in question.
484
* *address - ptr to location where address should be stored.
487
* DEV_STATUS of device in question. (NOT_KNOWN if device is out of range.)
488
* *address - updated if 'device' is within range
491
* This function should only be called after gfx_msr_init
493
*--------------------------------------------------------------------
497
redcloud_get_msr_dev_address(unsigned int device, unsigned long *address)
500
gfx_get_msr_dev_address(unsigned int device, unsigned long *address)
503
if (device < NUM_DEVS) {
504
if (msrDev[device].Present == FOUND)
505
*address = msrDev[device].Address;
507
return msrDev[device].Present;
513
/*--------------------------------------------------------------------
514
* gfx_get_glink_id_at_address
516
* This function returns the 16-bit deviceId at the requested address.
517
* DEV_STATUS should be checked to make sure that device was updated.
520
* device - ptr to location where device ID should be stored.
521
* address - address of desired device ID.
524
* FOUND if address is a valid address, NOT_KNOWN if address cannot be
526
* *device - updated with device Id info.
529
* This function should be called after gfx_msr_init
531
*--------------------------------------------------------------------
535
redcloud_get_glink_id_at_address(unsigned int *device, unsigned long address)
538
gfx_get_glink_id_at_address(unsigned int *device, unsigned long address)
543
for (port = 0; port < 8; port++) {
544
if (MBIU0[port].address == address) {
545
*device = MBIU0[port].deviceId;
548
else if (MBIU1[port].address == address) {
549
*device = MBIU1[port].deviceId;
552
else if (MBIU2[port].address == address) {
553
*device = MBIU2[port].deviceId;
562
/*--------------------------------------------------------------------
565
* Performs a 64-bit read from 'msrRegister' in device 'device'. 'device' is
566
* an index into Durango's table of known MBUS devices.
569
* FOUND - if no errors were detected and msrValue has been
571
* NOT_KNOWN - an error was detected. msrValue is not updated.
572
* REQ_NOT_FOUND - 'msrAddress' for 'devID' is unknown. Caller
573
* should call msrInit() first. msrValue is not
576
* This function should be called after gfx_msr_init
577
*--------------------------------------------------------------------
581
redcloud_msr_read(unsigned int device, unsigned int msrRegister,
585
gfx_msr_read(unsigned int device, unsigned int msrRegister, Q_WORD * msrValue)
588
if (device < NUM_DEVS) {
589
if (msrDev[device].Present == FOUND)
590
MSR_READ(msrRegister, msrDev[device].Address, &(msrValue->high),
593
return msrDev[device].Present;
598
/*--------------------------------------------------------------------
601
* Performs a 64-bit write to 'msrRegister' in device 'devID'.
604
* FOUND - if no errors were detected and msrValue has been
606
* NOT_KNOWN - an error was detected. msrValue is not updated.
607
* REQ_NOT_FOUND - 'msrAddress' for 'devID' is unknown. Caller
608
* should call msrInit() first. msrValue is not
612
* This function is valid to call after initMSR_API()
614
*--------------------------------------------------------------------
618
redcloud_msr_write(unsigned int device, unsigned int msrRegister,
622
gfx_msr_write(unsigned int device, unsigned int msrRegister, Q_WORD * msrValue)
625
if (device < NUM_DEVS) {
626
if (msrDev[device].Present == FOUND)
627
MSR_WRITE(msrRegister, msrDev[device].Address, &(msrValue->high),
630
return msrDev[device].Present;