blob: 9cc813e29706d3febdd70aacf5b4aa2d6e4940af [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#include <linux/init.h>
2#include <linux/pci.h>
3#include <asm/mpspec.h>
4#include <linux/cpumask.h>
5
6/*
7 * This discovers the pcibus <-> node mapping on AMD K8.
8 *
9 * RED-PEN need to call this again on PCI hotplug
10 * RED-PEN empty cpus get reported wrong
11 */
12
13#define NODE_ID_REGISTER 0x60
14#define NODE_ID(dword) (dword & 0x07)
15#define LDT_BUS_NUMBER_REGISTER_0 0x94
16#define LDT_BUS_NUMBER_REGISTER_1 0xB4
17#define LDT_BUS_NUMBER_REGISTER_2 0xD4
18#define NR_LDT_BUS_NUMBER_REGISTERS 3
19#define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 8) & 0xFF)
20#define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF)
Andi Kleen355540f2006-07-29 21:42:46 +020021#define PCI_DEVICE_ID_K8HTCONFIG 0x1100
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
23/**
24 * fill_mp_bus_to_cpumask()
25 * fills the mp_bus_to_cpumask array based according to the LDT Bus Number
26 * Registers found in the K8 northbridge
27 */
28__init static int
29fill_mp_bus_to_cpumask(void)
30{
Andi Kleen355540f2006-07-29 21:42:46 +020031 struct pci_dev *nb_dev = NULL;
32 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 u32 ldtbus, nid;
34 static int lbnr[3] = {
35 LDT_BUS_NUMBER_REGISTER_0,
36 LDT_BUS_NUMBER_REGISTER_1,
37 LDT_BUS_NUMBER_REGISTER_2
38 };
39
Andi Kleen355540f2006-07-29 21:42:46 +020040 while ((nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
41 PCI_DEVICE_ID_K8HTCONFIG, nb_dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 pci_read_config_dword(nb_dev, NODE_ID_REGISTER, &nid);
43
44 for (i = 0; i < NR_LDT_BUS_NUMBER_REGISTERS; i++) {
45 pci_read_config_dword(nb_dev, lbnr[i], &ldtbus);
46 /*
47 * if there are no busses hanging off of the current
48 * ldt link then both the secondary and subordinate
49 * bus number fields are set to 0.
Andi Kleend3813fc2005-08-23 03:14:27 +020050 *
51 * RED-PEN
52 * This is slightly broken because it assumes
53 * HT node IDs == Linux node ids, which is not always
54 * true. However it is probably mostly true.
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 */
56 if (!(SECONDARY_LDT_BUS_NUMBER(ldtbus) == 0
57 && SUBORDINATE_LDT_BUS_NUMBER(ldtbus) == 0)) {
58 for (j = SECONDARY_LDT_BUS_NUMBER(ldtbus);
59 j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
Andi Kleend3813fc2005-08-23 03:14:27 +020060 j++) {
Andi Kleen69e1a332005-09-12 18:49:24 +020061 struct pci_bus *bus;
Muli Ben-Yehuda08f1c192007-07-22 00:23:39 +030062 struct pci_sysdata *sd;
63
Andi Kleen69e1a332005-09-12 18:49:24 +020064 long node = NODE_ID(nid);
65 /* Algorithm a bit dumb, but
66 it shouldn't matter here */
67 bus = pci_find_bus(0, j);
68 if (!bus)
69 continue;
Andi Kleend3813fc2005-08-23 03:14:27 +020070 if (!node_online(node))
71 node = 0;
Muli Ben-Yehuda08f1c192007-07-22 00:23:39 +030072
73 sd = bus->sysdata;
74 sd->node = node;
Andi Kleend3813fc2005-08-23 03:14:27 +020075 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 }
77 }
78 }
79
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 return 0;
81}
82
83fs_initcall(fill_mp_bus_to_cpumask);