3 * Copyright (C) 2005 Advanced Micro Devices, Inc. All Rights Reserved.
10 * Cimarron MSR access routines. These routines allow the user to query the
11 * state of the GeodeLink Bus and read and write model-specfic registers.
16 /*--------------------------------------------------------------*/
18 /* These variables hold a local copy of the GeodeLink mapping */
19 /* as well as a lookup table for easy device addressing. */
20 /*--------------------------------------------------------------*/
22 GEODELINK_NODE gliu_nodes
[24];
23 GEODELINK_NODE msr_dev_lookup
[MSR_DEVICE_EMPTY
];
25 #define GET_DEVICE_ID(macrohigh, macrolow) ((macrolow >> 12) & 0xFF)
27 /*---------------------------------------------------------------------------
30 * This routine intializes the internal MSR table in Cimarron. This table is
31 * used for any MSR device accesses.
32 *---------------------------------------------------------------------------*/
34 int msr_init_table (void)
38 int return_value
= CIM_STATUS_OK
;
40 /* CHECK FOR VALID GEODELINK CONFIGURATION */
41 /* The CPU and the three GLIUs are assumed to be at known static addresses, so */
42 /* we will check the device IDs at these addresses as proof of a valid */
43 /* GeodeLink configuration */
45 MSR_READ (MSR_GEODELINK_CAP
, MSR_ADDRESS_VAIL
, &msr_value
);
46 if (GET_DEVICE_ID (msr_value
.high
, msr_value
.low
) != MSR_CLASS_CODE_VAIL
)
47 return_value
= CIM_STATUS_ERROR
;
49 MSR_READ (MSR_GEODELINK_CAP
, MSR_ADDRESS_GLIU0
, &msr_value
);
50 if (GET_DEVICE_ID (msr_value
.high
, msr_value
.low
) != MSR_CLASS_CODE_GLIU
)
51 return_value
= CIM_STATUS_ERROR
;
53 MSR_READ (MSR_GEODELINK_CAP
, MSR_ADDRESS_GLIU1
, &msr_value
);
54 if (GET_DEVICE_ID (msr_value
.high
, msr_value
.low
) != MSR_CLASS_CODE_GLIU
)
55 return_value
= CIM_STATUS_ERROR
;
57 MSR_READ (MSR_GEODELINK_CAP
, MSR_ADDRESS_GLIU2
, &msr_value
);
58 if (GET_DEVICE_ID (msr_value
.high
, msr_value
.low
) != MSR_CLASS_CODE_GLIU
)
59 return_value
= CIM_STATUS_ERROR
;
61 if (return_value
== CIM_STATUS_OK
)
63 /* BUILD LOCAL COPY OF THE GEODELINK BUS */
65 msr_create_geodelink_table (gliu_nodes
);
67 /* CLEAR TABLE STATUS */
69 for (i
= 0; i
< MSR_DEVICE_EMPTY
; i
++)
70 msr_dev_lookup
[i
].device_id
= MSR_DEVICE_NOTFOUND
;
72 /* CREATE EASY LOOKUP TABLE FOR FUTURE HARDWARE ACCESS */
73 /* Note that MSR_DEVICE_EMPTY is the index after the last */
74 /* available device. Also note that we fill in known */
75 /* devices before filling in the rest of the table. */
77 msr_dev_lookup
[MSR_DEVICE_GEODELX_GLIU0
].address_from_cpu
= MSR_ADDRESS_GLIU0
;
78 msr_dev_lookup
[MSR_DEVICE_GEODELX_GLIU0
].device_id
= MSR_DEVICE_PRESENT
;
79 msr_dev_lookup
[MSR_DEVICE_GEODELX_GLIU1
].address_from_cpu
= MSR_ADDRESS_GLIU1
;
80 msr_dev_lookup
[MSR_DEVICE_GEODELX_GLIU1
].device_id
= MSR_DEVICE_PRESENT
;
81 msr_dev_lookup
[MSR_DEVICE_5535_GLIU
].address_from_cpu
= MSR_ADDRESS_GLIU2
;
82 msr_dev_lookup
[MSR_DEVICE_5535_GLIU
].device_id
= MSR_DEVICE_PRESENT
;
83 msr_dev_lookup
[MSR_DEVICE_GEODELX_VAIL
].address_from_cpu
= MSR_ADDRESS_VAIL
;
84 msr_dev_lookup
[MSR_DEVICE_GEODELX_VAIL
].device_id
= MSR_DEVICE_PRESENT
;
86 for (i
= 0; i
< MSR_DEVICE_EMPTY
; i
++)
88 if (msr_dev_lookup
[i
].device_id
== MSR_DEVICE_NOTFOUND
)
90 for (j
= 0; j
< 24; j
++)
92 if (gliu_nodes
[j
].device_id
== i
)
97 msr_dev_lookup
[i
].device_id
= MSR_DEVICE_NOTFOUND
;
100 msr_dev_lookup
[i
].device_id
= MSR_DEVICE_PRESENT
;
101 msr_dev_lookup
[i
].address_from_cpu
= gliu_nodes
[j
].address_from_cpu
;
108 /* ERROR OUT THE GEODELINK TABLES */
110 for (i
= 0; i
< 24; i
++)
112 gliu_nodes
[i
].address_from_cpu
= 0xFFFFFFFF;
113 gliu_nodes
[i
].device_id
= MSR_DEVICE_EMPTY
;
116 for (i
= 0; i
< MSR_DEVICE_EMPTY
; i
++)
118 msr_dev_lookup
[i
].address_from_cpu
= 0xFFFFFFFF;
119 msr_dev_lookup
[i
].device_id
= MSR_DEVICE_NOTFOUND
;
125 /*---------------------------------------------------------------------------
126 * msr_create_geodelink_table
128 * This routine dumps the contents of the GeodeLink bus into an array of
129 * 24 GEODELINK_NODE structures. Indexes 0-7 represent ports 0-7 of GLIU0,
130 * indexes 8-15 represent ports 0-7 of GLIU1 and indexes 16-23 represent
131 * ports 0-7 of GLIU2 (5535).
132 *---------------------------------------------------------------------------*/
134 int msr_create_geodelink_table (GEODELINK_NODE
*gliu_nodes
)
136 unsigned long mbiu_port_count
, reflective
;
137 unsigned long port
, index
;
138 unsigned long gliu_count
= 0;
144 /* ALL THREE GLIUS ARE IN ONE ARRAY */
145 /* Entries 0-7 contain the port information for GLIU0, entries */
146 /* 8-15 contain GLIU1 and 15-23 contain GLIU2. We perform the */
147 /* enumeration in two passes. The first simply fills in the */
148 /* addresses and class codes at each node. The second pass */
149 /* translates the class codes into indexes into Cimarron's device */
152 /* COUNT GLIU0 PORTS */
154 MSR_READ (MSR_GLIU_CAP
, MSR_ADDRESS_GLIU0
, &msr_value
);
155 mbiu_port_count
= (msr_value
.high
>> NUM_PORTS_SHIFT
) & 7;
157 /* FIND REFLECTIVE PORT */
158 /* Query the GLIU for the port through which we are communicating. */
159 /* We will avoid accesses to this port to avoid a self-reference. */
161 MSR_READ (MSR_GLIU_WHOAMI
, MSR_ADDRESS_GLIU0
, &msr_value
);
162 reflective
= msr_value
.low
& WHOAMI_MASK
;
164 /* SPECIAL CASE FOR PORT 0 */
165 /* GLIU0 port 0 is a special case, as it points back to GLIU0. GLIU0 */
166 /* responds at address 0x10000xxx, which does not equal 0 << 29. */
168 gliu_nodes
[0].address_from_cpu
= MSR_ADDRESS_GLIU0
;
169 gliu_nodes
[0].device_id
= MSR_CLASS_CODE_GLIU
;
171 /* ENUMERATE ALL PORTS */
173 for (port
= 1; port
< 8; port
++)
175 /* FILL IN ADDRESS */
177 gliu_nodes
[port
].address_from_cpu
= port
<< 29;
179 if (port
== reflective
)
180 gliu_nodes
[port
].device_id
= MSR_CLASS_CODE_REFLECTIVE
;
181 else if (port
> mbiu_port_count
)
182 gliu_nodes
[port
].device_id
= MSR_CLASS_CODE_UNPOPULATED
;
185 MSR_READ (MSR_GEODELINK_CAP
, gliu_nodes
[port
].address_from_cpu
, &msr_value
);
186 gliu_nodes
[port
].device_id
= GET_DEVICE_ID (msr_value
.high
, msr_value
.low
);
190 /* COUNT GLIU1 PORTS */
192 MSR_READ (MSR_GLIU_CAP
, MSR_ADDRESS_GLIU1
, &msr_value
);
193 mbiu_port_count
= (msr_value
.high
>> NUM_PORTS_SHIFT
) & 7;
195 /* FIND REFLECTIVE PORT */
197 MSR_READ (MSR_GLIU_WHOAMI
, MSR_ADDRESS_GLIU1
, &msr_value
);
198 reflective
= msr_value
.low
& WHOAMI_MASK
;
200 /* ENUMERATE ALL PORTS */
202 for (port
= 0; port
< 8; port
++)
206 /* FILL IN ADDRESS */
208 gliu_nodes
[index
].address_from_cpu
= (0x02l
<< 29) + (port
<< 26);
210 if (port
== reflective
)
211 gliu_nodes
[index
].device_id
= MSR_CLASS_CODE_REFLECTIVE
;
212 else if (port
> mbiu_port_count
)
213 gliu_nodes
[index
].device_id
= MSR_CLASS_CODE_UNPOPULATED
;
216 MSR_READ (MSR_GEODELINK_CAP
, gliu_nodes
[index
].address_from_cpu
, &msr_value
);
217 gliu_nodes
[index
].device_id
= GET_DEVICE_ID (msr_value
.high
, msr_value
.low
);
221 /* COUNT GLIU2 PORTS */
223 MSR_READ (MSR_GLIU_CAP
, MSR_ADDRESS_GLIU2
, &msr_value
);
224 mbiu_port_count
= (msr_value
.high
>> NUM_PORTS_SHIFT
) & 7;
226 /* FIND REFLECTIVE PORT */
228 MSR_READ (MSR_GLIU_WHOAMI
, MSR_ADDRESS_GLIU2
, &msr_value
);
229 reflective
= msr_value
.low
& WHOAMI_MASK
;
231 /* FILL IN PORT 0 AND 1 */
232 /* Port 0 on 5535 is MBIU2. Port 1 is MPCI, but it is referenced at */
233 /* a special address. */
235 gliu_nodes
[16].address_from_cpu
= MSR_ADDRESS_GLIU2
;
236 gliu_nodes
[16].device_id
= MSR_CLASS_CODE_GLIU
;
238 gliu_nodes
[17].address_from_cpu
= MSR_ADDRESS_5535MPCI
;
239 gliu_nodes
[17].device_id
= MSR_CLASS_CODE_MPCI
;
241 /* ENUMERATE ALL PORTS */
243 for (port
= 2; port
< 8; port
++)
247 /* FILL IN ADDRESS */
249 gliu_nodes
[index
].address_from_cpu
=
250 (0x02l
<< 29) + (0x04l
<< 26) + (0x02l
<< 23) + (port
<< 20);
252 if (port
== reflective
)
253 gliu_nodes
[index
].device_id
= MSR_CLASS_CODE_REFLECTIVE
;
254 else if (port
> mbiu_port_count
)
255 gliu_nodes
[index
].device_id
= MSR_CLASS_CODE_UNPOPULATED
;
258 MSR_READ (MSR_GEODELINK_CAP
, gliu_nodes
[index
].address_from_cpu
, &msr_value
);
259 gliu_nodes
[index
].device_id
= GET_DEVICE_ID (msr_value
.high
, msr_value
.low
);
263 /* SECOND PASS - TRANSLATION */
264 /* Now that the class codes for each device are stored in the */
265 /* array, we walk through the array and translate the class */
266 /* codes to table indexes. For class codes that have multiple */
267 /* instances, the table indexes are sequential. */
269 for (port
= 0; port
< 24; port
++)
271 /* SPECIAL CASE FOR GLIU UNITS */
272 /* A GLIU can be both on another port and on its own port. These */
273 /* end up as the same address, but are shown as duplicate nodes in */
274 /* the GeodeLink table. */
277 gliu_count
= port
>> 3;
279 switch (gliu_nodes
[port
].device_id
)
281 /* UNPOPULATED OR REFLECTIVE NODES */
283 case MSR_CLASS_CODE_UNPOPULATED
: index
= MSR_DEVICE_EMPTY
; break;
284 case MSR_CLASS_CODE_REFLECTIVE
: index
= MSR_DEVICE_REFLECTIVE
; break;
286 /* KNOWN CLASS CODES */
288 case MSR_CLASS_CODE_GLIU
: index
= MSR_DEVICE_GEODELX_GLIU0
+ gliu_count
++; break;
289 case MSR_CLASS_CODE_GLCP
: index
= MSR_DEVICE_GEODELX_GLCP
+ glcp_count
++; break;
290 case MSR_CLASS_CODE_MPCI
: index
= MSR_DEVICE_GEODELX_MPCI
+ mpci_count
++; break;
291 case MSR_CLASS_CODE_USB
: index
= MSR_DEVICE_5535_USB2
+ usb_count
++; break;
292 case MSR_CLASS_CODE_USB2
: index
= MSR_DEVICE_5536_USB_2_0
; break;
293 case MSR_CLASS_CODE_ATAC
: index
= MSR_DEVICE_5535_ATAC
; break;
294 case MSR_CLASS_CODE_MDD
: index
= MSR_DEVICE_5535_MDD
; break;
295 case MSR_CLASS_CODE_ACC
: index
= MSR_DEVICE_5535_ACC
; break;
296 case MSR_CLASS_CODE_MC
: index
= MSR_DEVICE_GEODELX_MC
; break;
297 case MSR_CLASS_CODE_GP
: index
= MSR_DEVICE_GEODELX_GP
; break;
298 case MSR_CLASS_CODE_VG
: index
= MSR_DEVICE_GEODELX_VG
; break;
299 case MSR_CLASS_CODE_DF
: index
= MSR_DEVICE_GEODELX_DF
; break;
300 case MSR_CLASS_CODE_FG
: index
= MSR_DEVICE_GEODELX_FG
; break;
301 case MSR_CLASS_CODE_VIP
: index
= MSR_DEVICE_GEODELX_VIP
; break;
302 case MSR_CLASS_CODE_AES
: index
= MSR_DEVICE_GEODELX_AES
; break;
303 case MSR_CLASS_CODE_VAIL
: index
= MSR_DEVICE_GEODELX_VAIL
; break;
304 default: index
= MSR_DEVICE_EMPTY
; break;
307 gliu_nodes
[port
].device_id
= index
;
310 return CIM_STATUS_OK
;
313 /*---------------------------------------------------------------------------
314 * msr_create_device_list
316 * This routine dumps a list of all known GeodeLX/5535 devices as well as their
317 * respective status and address.
318 *---------------------------------------------------------------------------*/
320 int msr_create_device_list (GEODELINK_NODE
*gliu_nodes
, int max_devices
)
324 if (max_devices
< MSR_DEVICE_EMPTY
) count
= max_devices
;
325 else count
= MSR_DEVICE_EMPTY
;
327 for (i
= 0; i
< count
; i
++)
329 gliu_nodes
[i
].address_from_cpu
= msr_dev_lookup
[i
].address_from_cpu
;
330 gliu_nodes
[i
].device_id
= msr_dev_lookup
[i
].device_id
;
333 return CIM_STATUS_OK
;
336 /*--------------------------------------------------------------------
339 * Performs a 64-bit read from 'msr_register' in device 'device'. 'device' is
340 * an index into Cimarron's table of known GeodeLink devices.
341 *-------------------------------------------------------------------*/
343 int msr_read64 (unsigned long device
, unsigned long msr_register
,
346 if (device
< MSR_DEVICE_EMPTY
)
348 if (msr_dev_lookup
[device
].device_id
== MSR_DEVICE_PRESENT
)
350 MSR_READ (msr_register
, msr_dev_lookup
[device
].address_from_cpu
, msr_value
);
351 return CIM_STATUS_OK
;
355 msr_value
->low
= msr_value
->high
= 0;
356 return CIM_STATUS_DEVNOTFOUND
;
359 /*--------------------------------------------------------------------
362 * Performs a 64-bit write to 'msr_register' in device 'device'. 'device' is
363 * an index into Cimarron's table of known GeodeLink devices.
364 *-------------------------------------------------------------------*/
366 int msr_write64 (unsigned long device
, unsigned long msr_register
,
369 if (device
< MSR_DEVICE_EMPTY
)
371 if (msr_dev_lookup
[device
].device_id
== MSR_DEVICE_PRESENT
)
373 MSR_WRITE (msr_register
, msr_dev_lookup
[device
].address_from_cpu
, msr_value
);
374 return CIM_STATUS_OK
;
377 return CIM_STATUS_DEVNOTFOUND
;