x86: get mp_bus_to_node early
[linux-3.10.git] / arch / x86 / pci / k8-bus_64.c
1 #include <linux/init.h>
2 #include <linux/pci.h>
3 #include <asm/pci-direct.h>
4 #include <asm/mpspec.h>
5 #include <linux/cpumask.h>
6 #include <linux/topology.h>
7
8 /*
9  * This discovers the pcibus <-> node mapping on AMD K8.
10  *
11  * RED-PEN need to call this again on PCI hotplug
12  * RED-PEN empty cpus get reported wrong
13  */
14
15 #define NODE_ID_REGISTER 0x60
16 #define NODE_ID(dword) (dword & 0x07)
17 #define LDT_BUS_NUMBER_REGISTER_0 0x94
18 #define LDT_BUS_NUMBER_REGISTER_1 0xB4
19 #define LDT_BUS_NUMBER_REGISTER_2 0xD4
20 #define NR_LDT_BUS_NUMBER_REGISTERS 3
21 #define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 8) & 0xFF)
22 #define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF)
23 #define PCI_DEVICE_ID_K8HTCONFIG 0x1100
24
25 #ifdef CONFIG_NUMA
26
27 #define BUS_NR 256
28
29 static int mp_bus_to_node[BUS_NR];
30
31 void set_mp_bus_to_node(int busnum, int node)
32 {
33         if (busnum >= 0 &&  busnum < BUS_NR)
34                 mp_bus_to_node[busnum] = node;
35 }
36
37 int get_mp_bus_to_node(int busnum)
38 {
39         int node = -1;
40
41         if (busnum < 0 || busnum > (BUS_NR - 1))
42                 return node;
43
44         node = mp_bus_to_node[busnum];
45
46         /*
47          * let numa_node_id to decide it later in dma_alloc_pages
48          * if there is no ram on that node
49          */
50         if (node != -1 && !node_online(node))
51                 node = -1;
52
53         return node;
54 }
55
56 #endif
57
58 /**
59  * early_fill_mp_bus_to_node()
60  * called before pcibios_scan_root and pci_scan_bus
61  * fills the mp_bus_to_cpumask array based according to the LDT Bus Number
62  * Registers found in the K8 northbridge
63  */
64 __init static int
65 early_fill_mp_bus_to_node(void)
66 {
67 #ifdef CONFIG_NUMA
68         int i, j;
69         unsigned slot;
70         u32 ldtbus, nid;
71         u32 id;
72         static int lbnr[3] = {
73                 LDT_BUS_NUMBER_REGISTER_0,
74                 LDT_BUS_NUMBER_REGISTER_1,
75                 LDT_BUS_NUMBER_REGISTER_2
76         };
77
78         for (i = 0; i < BUS_NR; i++)
79                 mp_bus_to_node[i] = -1;
80
81         if (!early_pci_allowed())
82                 return -1;
83
84         for (slot = 0x18; slot < 0x20; slot++) {
85                 id = read_pci_config(0, slot, 0, PCI_VENDOR_ID);
86                 if (id != (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_K8HTCONFIG<<16)))
87                         break;
88                 nid = read_pci_config(0, slot, 0, NODE_ID_REGISTER);
89
90                 for (i = 0; i < NR_LDT_BUS_NUMBER_REGISTERS; i++) {
91                         ldtbus = read_pci_config(0, slot, 0, lbnr[i]);
92                         /*
93                          * if there are no busses hanging off of the current
94                          * ldt link then both the secondary and subordinate
95                          * bus number fields are set to 0.
96                          *
97                          * RED-PEN
98                          * This is slightly broken because it assumes
99                          * HT node IDs == Linux node ids, which is not always
100                          * true. However it is probably mostly true.
101                          */
102                         if (!(SECONDARY_LDT_BUS_NUMBER(ldtbus) == 0
103                                 && SUBORDINATE_LDT_BUS_NUMBER(ldtbus) == 0)) {
104                                 for (j = SECONDARY_LDT_BUS_NUMBER(ldtbus);
105                                      j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
106                                      j++) {
107                                         int node = NODE_ID(nid);
108                                         mp_bus_to_node[j] = (unsigned char)node;
109                                 }
110                         }
111                 }
112         }
113
114         for (i = 0; i < BUS_NR; i++) {
115                 int node = mp_bus_to_node[i];
116                 if (node >= 0)
117                         printk(KERN_DEBUG "bus: %02x to node: %02x\n", i, node);
118         }
119 #endif
120         return 0;
121 }
122
123 postcore_initcall(early_fill_mp_bus_to_node);