📄 cim_msr.c
字号:
/*
* <LIC_AMD_STD>
* Copyright (C) 2005 Advanced Micro Devices, Inc. All Rights Reserved.
* </LIC_AMD_STD>
*
* <CTL_AMD_STD>
* </CTL_AMD_STD>
*
* <DOC_AMD_STD>
* Cimarron MSR access routines. These routines allow the user to query the
* state of the GeodeLink Bus and read and write model-specfic registers.
* </DOC_AMD_STD>
*
*/
/*--------------------------------------------------------------*/
/* MSR GLOBALS */
/* These variables hold a local copy of the GeodeLink mapping */
/* as well as a lookup table for easy device addressing. */
/*--------------------------------------------------------------*/
GEODELINK_NODE gliu_nodes[24];
GEODELINK_NODE msr_dev_lookup[MSR_DEVICE_EMPTY];
#define GET_DEVICE_ID(macrohigh, macrolow) ((macrolow >> 12) & 0xFF)
/*---------------------------------------------------------------------------
* msr_init_table
*
* This routine intializes the internal MSR table in Cimarron. This table is
* used for any MSR device accesses.
*---------------------------------------------------------------------------*/
int msr_init_table (void)
{
Q_WORD msr_value;
unsigned int i, j;
int return_value = CIM_STATUS_OK;
/* CHECK FOR VALID GEODELINK CONFIGURATION */
/* The CPU and the three GLIUs are assumed to be at known static addresses, so */
/* we will check the device IDs at these addresses as proof of a valid */
/* GeodeLink configuration */
MSR_READ (MSR_GEODELINK_CAP, MSR_ADDRESS_VAIL, &msr_value);
if (GET_DEVICE_ID (msr_value.high, msr_value.low) != MSR_CLASS_CODE_VAIL)
return_value = CIM_STATUS_ERROR;
MSR_READ (MSR_GEODELINK_CAP, MSR_ADDRESS_GLIU0, &msr_value);
if (GET_DEVICE_ID (msr_value.high, msr_value.low) != MSR_CLASS_CODE_GLIU)
return_value = CIM_STATUS_ERROR;
MSR_READ (MSR_GEODELINK_CAP, MSR_ADDRESS_GLIU1, &msr_value);
if (GET_DEVICE_ID (msr_value.high, msr_value.low) != MSR_CLASS_CODE_GLIU)
return_value = CIM_STATUS_ERROR;
MSR_READ (MSR_GEODELINK_CAP, MSR_ADDRESS_GLIU2, &msr_value);
if (GET_DEVICE_ID (msr_value.high, msr_value.low) != MSR_CLASS_CODE_GLIU)
return_value = CIM_STATUS_ERROR;
if (return_value == CIM_STATUS_OK)
{
/* BUILD LOCAL COPY OF THE GEODELINK BUS */
msr_create_geodelink_table (gliu_nodes);
/* CLEAR TABLE STATUS */
for (i = 0; i < MSR_DEVICE_EMPTY; i++)
msr_dev_lookup[i].device_id = MSR_DEVICE_NOTFOUND;
/* CREATE EASY LOOKUP TABLE FOR FUTURE HARDWARE ACCESS */
/* Note that MSR_DEVICE_EMPTY is the index after the last */
/* available device. Also note that we fill in known */
/* devices before filling in the rest of the table. */
msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU0].address_from_cpu = MSR_ADDRESS_GLIU0;
msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU0].device_id = MSR_DEVICE_PRESENT;
msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU1].address_from_cpu = MSR_ADDRESS_GLIU1;
msr_dev_lookup[MSR_DEVICE_GEODELX_GLIU1].device_id = MSR_DEVICE_PRESENT;
msr_dev_lookup[MSR_DEVICE_5535_GLIU].address_from_cpu = MSR_ADDRESS_GLIU2;
msr_dev_lookup[MSR_DEVICE_5535_GLIU].device_id = MSR_DEVICE_PRESENT;
msr_dev_lookup[MSR_DEVICE_GEODELX_VAIL].address_from_cpu = MSR_ADDRESS_VAIL;
msr_dev_lookup[MSR_DEVICE_GEODELX_VAIL].device_id = MSR_DEVICE_PRESENT;
for (i = 0; i < MSR_DEVICE_EMPTY; i++)
{
if (msr_dev_lookup[i].device_id == MSR_DEVICE_NOTFOUND)
{
for (j = 0; j < 24; j++)
{
if (gliu_nodes[j].device_id == i)
break;
}
if (j == 24)
msr_dev_lookup[i].device_id = MSR_DEVICE_NOTFOUND;
else
{
msr_dev_lookup[i].device_id = MSR_DEVICE_PRESENT;
msr_dev_lookup[i].address_from_cpu = gliu_nodes[j].address_from_cpu;
}
}
}
}
else
{
/* ERROR OUT THE GEODELINK TABLES */
for (i = 0; i < 24; i++)
{
gliu_nodes[i].address_from_cpu = 0xFFFFFFFF;
gliu_nodes[i].device_id = MSR_DEVICE_EMPTY;
}
for (i = 0; i < MSR_DEVICE_EMPTY; i++)
{
msr_dev_lookup[i].address_from_cpu = 0xFFFFFFFF;
msr_dev_lookup[i].device_id = MSR_DEVICE_NOTFOUND;
}
}
return return_value;
}
/*---------------------------------------------------------------------------
* msr_create_geodelink_table
*
* This routine dumps the contents of the GeodeLink bus into an array of
* 24 GEODELINK_NODE structures. Indexes 0-7 represent ports 0-7 of GLIU0,
* indexes 8-15 represent ports 0-7 of GLIU1 and indexes 16-23 represent
* ports 0-7 of GLIU2 (5535).
*---------------------------------------------------------------------------*/
int msr_create_geodelink_table (GEODELINK_NODE *gliu_nodes)
{
unsigned long mbiu_port_count, reflective;
unsigned long port, index;
unsigned long gliu_count = 0;
int glcp_count = 0;
int usb_count = 0;
int mpci_count = 0;
Q_WORD msr_value;
/* ALL THREE GLIUS ARE IN ONE ARRAY */
/* Entries 0-7 contain the port information for GLIU0, entries */
/* 8-15 contain GLIU1 and 15-23 contain GLIU2. We perform the */
/* enumeration in two passes. The first simply fills in the */
/* addresses and class codes at each node. The second pass */
/* translates the class codes into indexes into Cimarron's device */
/* lookup table. */
/* COUNT GLIU0 PORTS */
MSR_READ (MSR_GLIU_CAP, MSR_ADDRESS_GLIU0, &msr_value);
mbiu_port_count = (msr_value.high >> NUM_PORTS_SHIFT) & 7;
/* FIND REFLECTIVE PORT */
/* Query the GLIU for the port through which we are communicating. */
/* We will avoid accesses to this port to avoid a self-reference. */
MSR_READ (MSR_GLIU_WHOAMI, MSR_ADDRESS_GLIU0, &msr_value);
reflective = msr_value.low & WHOAMI_MASK;
/* SPECIAL CASE FOR PORT 0 */
/* GLIU0 port 0 is a special case, as it points back to GLIU0. GLIU0 */
/* responds at address 0x10000xxx, which does not equal 0 << 29. */
gliu_nodes[0].address_from_cpu = MSR_ADDRESS_GLIU0;
gliu_nodes[0].device_id = MSR_CLASS_CODE_GLIU;
/* ENUMERATE ALL PORTS */
for (port = 1; port < 8; port++)
{
/* FILL IN ADDRESS */
gliu_nodes[port].address_from_cpu = port << 29;
if (port == reflective)
gliu_nodes[port].device_id = MSR_CLASS_CODE_REFLECTIVE;
else if (port > mbiu_port_count)
gliu_nodes[port].device_id = MSR_CLASS_CODE_UNPOPULATED;
else
{
MSR_READ (MSR_GEODELINK_CAP, gliu_nodes[port].address_from_cpu, &msr_value);
gliu_nodes[port].device_id = GET_DEVICE_ID (msr_value.high, msr_value.low);
}
}
/* COUNT GLIU1 PORTS */
MSR_READ (MSR_GLIU_CAP, MSR_ADDRESS_GLIU1, &msr_value);
mbiu_port_count = (msr_value.high >> NUM_PORTS_SHIFT) & 7;
/* FIND REFLECTIVE PORT */
MSR_READ (MSR_GLIU_WHOAMI, MSR_ADDRESS_GLIU1, &msr_value);
reflective = msr_value.low & WHOAMI_MASK;
/* ENUMERATE ALL PORTS */
for (port = 0; port < 8; port++)
{
index = port + 8;
/* FILL IN ADDRESS */
gliu_nodes[index].address_from_cpu = (0x02l << 29) + (port << 26);
if (port == reflective)
gliu_nodes[index].device_id = MSR_CLASS_CODE_REFLECTIVE;
else if (port > mbiu_port_count)
gliu_nodes[index].device_id = MSR_CLASS_CODE_UNPOPULATED;
else
{
MSR_READ (MSR_GEODELINK_CAP, gliu_nodes[index].address_from_cpu, &msr_value);
gliu_nodes[index].device_id = GET_DEVICE_ID (msr_value.high, msr_value.low);
}
}
/* COUNT GLIU2 PORTS */
MSR_READ (MSR_GLIU_CAP, MSR_ADDRESS_GLIU2, &msr_value);
mbiu_port_count = (msr_value.high >> NUM_PORTS_SHIFT) & 7;
/* FIND REFLECTIVE PORT */
MSR_READ (MSR_GLIU_WHOAMI, MSR_ADDRESS_GLIU2, &msr_value);
reflective = msr_value.low & WHOAMI_MASK;
/* FILL IN PORT 0 AND 1 */
/* Port 0 on 5535 is MBIU2. Port 1 is MPCI, but it is referenced at */
/* a special address. */
gliu_nodes[16].address_from_cpu = MSR_ADDRESS_GLIU2;
gliu_nodes[16].device_id = MSR_CLASS_CODE_GLIU;
gliu_nodes[17].address_from_cpu = MSR_ADDRESS_5535MPCI;
gliu_nodes[17].device_id = MSR_CLASS_CODE_MPCI;
/* ENUMERATE ALL PORTS */
for (port = 2; port < 8; port++)
{
index = port + 16;
/* FILL IN ADDRESS */
gliu_nodes[index].address_from_cpu =
(0x02l << 29) + (0x04l << 26) + (0x02l << 23) + (port << 20);
if (port == reflective)
gliu_nodes[index].device_id = MSR_CLASS_CODE_REFLECTIVE;
else if (port > mbiu_port_count)
gliu_nodes[index].device_id = MSR_CLASS_CODE_UNPOPULATED;
else
{
MSR_READ (MSR_GEODELINK_CAP, gliu_nodes[index].address_from_cpu, &msr_value);
gliu_nodes[index].device_id = GET_DEVICE_ID (msr_value.high, msr_value.low);
}
}
/* SECOND PASS - TRANSLATION */
/* Now that the class codes for each device are stored in the */
/* array, we walk through the array and translate the class */
/* codes to table indexes. For class codes that have multiple */
/* instances, the table indexes are sequential. */
for (port = 0; port < 24; port++)
{
/* SPECIAL CASE FOR GLIU UNITS */
/* A GLIU can be both on another port and on its own port. These */
/* end up as the same address, but are shown as duplicate nodes in */
/* the GeodeLink table. */
if ((port & 7) == 0)
gliu_count = port >> 3;
switch (gliu_nodes[port].device_id)
{
/* UNPOPULATED OR REFLECTIVE NODES */
case MSR_CLASS_CODE_UNPOPULATED: index = MSR_DEVICE_EMPTY; break;
case MSR_CLASS_CODE_REFLECTIVE: index = MSR_DEVICE_REFLECTIVE; break;
/* KNOWN CLASS CODES */
case MSR_CLASS_CODE_GLIU: index = MSR_DEVICE_GEODELX_GLIU0 + gliu_count++; break;
case MSR_CLASS_CODE_GLCP: index = MSR_DEVICE_GEODELX_GLCP + glcp_count++; break;
case MSR_CLASS_CODE_MPCI: index = MSR_DEVICE_GEODELX_MPCI + mpci_count++; break;
case MSR_CLASS_CODE_USB: index = MSR_DEVICE_5535_USB2 + usb_count++; break;
case MSR_CLASS_CODE_USB2: index = MSR_DEVICE_5536_USB_2_0; break;
case MSR_CLASS_CODE_ATAC: index = MSR_DEVICE_5535_ATAC; break;
case MSR_CLASS_CODE_MDD: index = MSR_DEVICE_5535_MDD; break;
case MSR_CLASS_CODE_ACC: index = MSR_DEVICE_5535_ACC; break;
case MSR_CLASS_CODE_MC: index = MSR_DEVICE_GEODELX_MC; break;
case MSR_CLASS_CODE_GP: index = MSR_DEVICE_GEODELX_GP; break;
case MSR_CLASS_CODE_VG: index = MSR_DEVICE_GEODELX_VG; break;
case MSR_CLASS_CODE_DF: index = MSR_DEVICE_GEODELX_DF; break;
case MSR_CLASS_CODE_FG: index = MSR_DEVICE_GEODELX_FG; break;
case MSR_CLASS_CODE_VIP: index = MSR_DEVICE_GEODELX_VIP; break;
case MSR_CLASS_CODE_AES: index = MSR_DEVICE_GEODELX_AES; break;
case MSR_CLASS_CODE_VAIL: index = MSR_DEVICE_GEODELX_VAIL; break;
default: index = MSR_DEVICE_EMPTY; break;
}
gliu_nodes[port].device_id = index;
}
return CIM_STATUS_OK;
}
/*---------------------------------------------------------------------------
* msr_create_device_list
*
* This routine dumps a list of all known GeodeLX/5535 devices as well as their
* respective status and address.
*---------------------------------------------------------------------------*/
int msr_create_device_list (GEODELINK_NODE *gliu_nodes, int max_devices)
{
int i, count;
if (max_devices < MSR_DEVICE_EMPTY) count = max_devices;
else count = MSR_DEVICE_EMPTY;
for (i = 0; i < count; i++)
{
gliu_nodes[i].address_from_cpu = msr_dev_lookup[i].address_from_cpu;
gliu_nodes[i].device_id = msr_dev_lookup[i].device_id;
}
return CIM_STATUS_OK;
}
/*--------------------------------------------------------------------
* msr_read64
*
* Performs a 64-bit read from 'msr_register' in device 'device'. 'device' is
* an index into Cimarron's table of known GeodeLink devices.
*-------------------------------------------------------------------*/
int msr_read64 (unsigned long device, unsigned long msr_register,
Q_WORD *msr_value)
{
if (device < MSR_DEVICE_EMPTY)
{
if (msr_dev_lookup[device].device_id == MSR_DEVICE_PRESENT)
{
MSR_READ (msr_register, msr_dev_lookup[device].address_from_cpu, msr_value);
return CIM_STATUS_OK;
}
}
msr_value->low = msr_value->high = 0;
return CIM_STATUS_DEVNOTFOUND;
}
/*--------------------------------------------------------------------
* msr_write64
*
* Performs a 64-bit write to 'msr_register' in device 'device'. 'device' is
* an index into Cimarron's table of known GeodeLink devices.
*-------------------------------------------------------------------*/
int msr_write64 (unsigned long device, unsigned long msr_register,
Q_WORD *msr_value)
{
if (device < MSR_DEVICE_EMPTY)
{
if (msr_dev_lookup[device].device_id == MSR_DEVICE_PRESENT)
{
MSR_WRITE (msr_register, msr_dev_lookup[device].address_from_cpu, msr_value);
return CIM_STATUS_OK;
}
}
return CIM_STATUS_DEVNOTFOUND;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -