]> err.no Git - linux-2.6/blob - arch/x86/pci/k8-bus_64.c
x86: use bus conf in NB conf fun1 to get bus range on, on 64-bit
[linux-2.6] / 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(dword) ((dword>>4) & 0x07)
16 #define LDT_BUS_NUMBER_REGISTER_0 0xE0
17 #define LDT_BUS_NUMBER_REGISTER_1 0xE4
18 #define LDT_BUS_NUMBER_REGISTER_2 0xE8
19 #define LDT_BUS_NUMBER_REGISTER_3 0xEC
20 #define NR_LDT_BUS_NUMBER_REGISTERS 4
21 #define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF)
22 #define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 24) & 0xFF)
23
24 #define PCI_DEVICE_ID_K8HTCONFIG 0x1100
25 #define PCI_DEVICE_ID_K8_10H_HTCONFIG 0x1200
26 #define PCI_DEVICE_ID_K8_11H_HTCONFIG 0x1300
27
28 #ifdef CONFIG_NUMA
29
30 #define BUS_NR 256
31
32 static int mp_bus_to_node[BUS_NR];
33
34 void set_mp_bus_to_node(int busnum, int node)
35 {
36         if (busnum >= 0 &&  busnum < BUS_NR)
37                 mp_bus_to_node[busnum] = node;
38 }
39
40 int get_mp_bus_to_node(int busnum)
41 {
42         int node = -1;
43
44         if (busnum < 0 || busnum > (BUS_NR - 1))
45                 return node;
46
47         node = mp_bus_to_node[busnum];
48
49         /*
50          * let numa_node_id to decide it later in dma_alloc_pages
51          * if there is no ram on that node
52          */
53         if (node != -1 && !node_online(node))
54                 node = -1;
55
56         return node;
57 }
58
59 #endif
60
61 /**
62  * early_fill_mp_bus_to_node()
63  * called before pcibios_scan_root and pci_scan_bus
64  * fills the mp_bus_to_cpumask array based according to the LDT Bus Number
65  * Registers found in the K8 northbridge
66  */
67 __init static int
68 early_fill_mp_bus_to_node(void)
69 {
70 #ifdef CONFIG_NUMA
71         int i, j;
72         unsigned slot;
73         u32 ldtbus;
74         u32 id;
75         int node;
76         u16 deviceid;
77         u16 vendorid;
78         int min_bus;
79         int max_bus;
80
81         static int lbnr[NR_LDT_BUS_NUMBER_REGISTERS] = {
82                 LDT_BUS_NUMBER_REGISTER_0,
83                 LDT_BUS_NUMBER_REGISTER_1,
84                 LDT_BUS_NUMBER_REGISTER_2,
85                 LDT_BUS_NUMBER_REGISTER_3
86         };
87
88         for (i = 0; i < BUS_NR; i++)
89                 mp_bus_to_node[i] = -1;
90
91         if (!early_pci_allowed())
92                 return -1;
93
94         slot = 0x18;
95         id = read_pci_config(0, slot, 0, PCI_VENDOR_ID);
96
97         vendorid = id & 0xffff;
98         if (vendorid != PCI_VENDOR_ID_AMD)
99                 goto out;
100
101         deviceid = (id>>16) & 0xffff;
102         if ((deviceid != PCI_DEVICE_ID_K8HTCONFIG) &&
103             (deviceid != PCI_DEVICE_ID_K8_10H_HTCONFIG) &&
104             (deviceid != PCI_DEVICE_ID_K8_11H_HTCONFIG))
105                 goto out;
106
107         for (i = 0; i < NR_LDT_BUS_NUMBER_REGISTERS; i++) {
108                 ldtbus = read_pci_config(0, slot, 1, lbnr[i]);
109
110                 /* Check if that register is enabled for bus range */
111                 if ((ldtbus & 7) != 3)
112                         continue;
113
114                 min_bus = SECONDARY_LDT_BUS_NUMBER(ldtbus);
115                 max_bus = SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
116                 node = NODE_ID(ldtbus);
117                 for (j = min_bus; j <= max_bus; j++)
118                         mp_bus_to_node[j] = (unsigned char) node;
119         }
120
121 out:
122         for (i = 0; i < BUS_NR; i++) {
123                 node = mp_bus_to_node[i];
124                 if (node >= 0)
125                         printk(KERN_DEBUG "bus: %02x to node: %02x\n", i, node);
126         }
127 #endif
128         return 0;
129 }
130
131 postcore_initcall(early_fill_mp_bus_to_node);