2005-04-16 18:20:36 -04:00
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/pci.h>
|
|
|
|
#include <asm/mpspec.h>
|
|
|
|
#include <linux/cpumask.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This discovers the pcibus <-> node mapping on AMD K8.
|
|
|
|
*
|
|
|
|
* RED-PEN need to call this again on PCI hotplug
|
|
|
|
* RED-PEN empty cpus get reported wrong
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define NODE_ID_REGISTER 0x60
|
|
|
|
#define NODE_ID(dword) (dword & 0x07)
|
|
|
|
#define LDT_BUS_NUMBER_REGISTER_0 0x94
|
|
|
|
#define LDT_BUS_NUMBER_REGISTER_1 0xB4
|
|
|
|
#define LDT_BUS_NUMBER_REGISTER_2 0xD4
|
|
|
|
#define NR_LDT_BUS_NUMBER_REGISTERS 3
|
|
|
|
#define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 8) & 0xFF)
|
|
|
|
#define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF)
|
2006-07-29 15:42:46 -04:00
|
|
|
#define PCI_DEVICE_ID_K8HTCONFIG 0x1100
|
2005-04-16 18:20:36 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* fill_mp_bus_to_cpumask()
|
|
|
|
* fills the mp_bus_to_cpumask array based according to the LDT Bus Number
|
|
|
|
* Registers found in the K8 northbridge
|
|
|
|
*/
|
|
|
|
__init static int
|
|
|
|
fill_mp_bus_to_cpumask(void)
|
|
|
|
{
|
2006-07-29 15:42:46 -04:00
|
|
|
struct pci_dev *nb_dev = NULL;
|
|
|
|
int i, j;
|
2005-04-16 18:20:36 -04:00
|
|
|
u32 ldtbus, nid;
|
|
|
|
static int lbnr[3] = {
|
|
|
|
LDT_BUS_NUMBER_REGISTER_0,
|
|
|
|
LDT_BUS_NUMBER_REGISTER_1,
|
|
|
|
LDT_BUS_NUMBER_REGISTER_2
|
|
|
|
};
|
|
|
|
|
2006-07-29 15:42:46 -04:00
|
|
|
while ((nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
|
|
|
PCI_DEVICE_ID_K8HTCONFIG, nb_dev))) {
|
2005-04-16 18:20:36 -04:00
|
|
|
pci_read_config_dword(nb_dev, NODE_ID_REGISTER, &nid);
|
|
|
|
|
|
|
|
for (i = 0; i < NR_LDT_BUS_NUMBER_REGISTERS; i++) {
|
|
|
|
pci_read_config_dword(nb_dev, lbnr[i], &ldtbus);
|
|
|
|
/*
|
|
|
|
* if there are no busses hanging off of the current
|
|
|
|
* ldt link then both the secondary and subordinate
|
|
|
|
* bus number fields are set to 0.
|
2005-08-22 21:14:27 -04:00
|
|
|
*
|
|
|
|
* RED-PEN
|
|
|
|
* This is slightly broken because it assumes
|
|
|
|
* HT node IDs == Linux node ids, which is not always
|
|
|
|
* true. However it is probably mostly true.
|
2005-04-16 18:20:36 -04:00
|
|
|
*/
|
|
|
|
if (!(SECONDARY_LDT_BUS_NUMBER(ldtbus) == 0
|
|
|
|
&& SUBORDINATE_LDT_BUS_NUMBER(ldtbus) == 0)) {
|
|
|
|
for (j = SECONDARY_LDT_BUS_NUMBER(ldtbus);
|
|
|
|
j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
|
2005-08-22 21:14:27 -04:00
|
|
|
j++) {
|
2005-09-12 12:49:24 -04:00
|
|
|
struct pci_bus *bus;
|
2007-07-21 17:23:39 -04:00
|
|
|
struct pci_sysdata *sd;
|
|
|
|
|
2005-09-12 12:49:24 -04:00
|
|
|
long node = NODE_ID(nid);
|
|
|
|
/* Algorithm a bit dumb, but
|
|
|
|
it shouldn't matter here */
|
|
|
|
bus = pci_find_bus(0, j);
|
|
|
|
if (!bus)
|
|
|
|
continue;
|
2005-08-22 21:14:27 -04:00
|
|
|
if (!node_online(node))
|
|
|
|
node = 0;
|
2007-07-21 17:23:39 -04:00
|
|
|
|
|
|
|
sd = bus->sysdata;
|
|
|
|
sd->node = node;
|
2005-08-22 21:14:27 -04:00
|
|
|
}
|
2005-04-16 18:20:36 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fs_initcall(fill_mp_bus_to_cpumask);
|