[PATCH] x86_64: Clean and enhance up K8 northbridge access code
[linux-2.6] / arch / x86_64 / pci / k8-bus.c
1 #include <linux/init.h>
2 #include <linux/pci.h>
3 #include <asm/mpspec.h>
4 #include <linux/cpumask.h>
5 #include <asm/k8.h>
6
7 /*
8  * This discovers the pcibus <-> node mapping on AMD K8.
9  *
10  * RED-PEN need to call this again on PCI hotplug
11  * RED-PEN empty cpus get reported wrong
12  */
13
14 #define NODE_ID_REGISTER 0x60
15 #define NODE_ID(dword) (dword & 0x07)
16 #define LDT_BUS_NUMBER_REGISTER_0 0x94
17 #define LDT_BUS_NUMBER_REGISTER_1 0xB4
18 #define LDT_BUS_NUMBER_REGISTER_2 0xD4
19 #define NR_LDT_BUS_NUMBER_REGISTERS 3
20 #define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 8) & 0xFF)
21 #define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF)
22
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
29 fill_mp_bus_to_cpumask(void)
30 {
31         int i, j, k;
32         u32 ldtbus, nid;
33         static int lbnr[3] = {
34                 LDT_BUS_NUMBER_REGISTER_0,
35                 LDT_BUS_NUMBER_REGISTER_1,
36                 LDT_BUS_NUMBER_REGISTER_2
37         };
38
39         cache_k8_northbridges();
40         for (k = 0; k < num_k8_northbridges; k++) {
41                 struct pci_dev *nb_dev = k8_northbridges[k];
42                 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.
50                          * 
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.
55                          */
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);
60                                      j++) { 
61                                         struct pci_bus *bus;
62                                         long node = NODE_ID(nid);
63                                         /* Algorithm a bit dumb, but
64                                            it shouldn't matter here */
65                                         bus = pci_find_bus(0, j);
66                                         if (!bus)
67                                                 continue;
68                                         if (!node_online(node))
69                                                 node = 0;
70                                         bus->sysdata = (void *)node;
71                                 }               
72                         }
73                 }
74         }
75
76         return 0;
77 }
78
79 fs_initcall(fill_mp_bus_to_cpumask);