blob: 3903efbca535e7cd5c0d5db4118a95362a66fe8a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#include <linux/init.h>
2#include <linux/pci.h>
Yinghai Lu871d5f82008-02-19 03:20:09 -08003#include <asm/pci-direct.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07004#include <asm/mpspec.h>
5#include <linux/cpumask.h>
Yinghai Lu871d5f82008-02-19 03:20:09 -08006#include <linux/topology.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007
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)
Andi Kleen355540f2006-07-29 21:42:46 +020023#define PCI_DEVICE_ID_K8HTCONFIG 0x1100
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Yinghai Lu871d5f82008-02-19 03:20:09 -080025#ifdef CONFIG_NUMA
26
27#define BUS_NR 256
28
29static int mp_bus_to_node[BUS_NR];
30
31void 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
37int 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070058/**
Yinghai Lu871d5f82008-02-19 03:20:09 -080059 * early_fill_mp_bus_to_node()
60 * called before pcibios_scan_root and pci_scan_bus
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 * 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
Yinghai Lu871d5f82008-02-19 03:20:09 -080065early_fill_mp_bus_to_node(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070066{
Yinghai Lu871d5f82008-02-19 03:20:09 -080067#ifdef CONFIG_NUMA
Andi Kleen355540f2006-07-29 21:42:46 +020068 int i, j;
Yinghai Lu871d5f82008-02-19 03:20:09 -080069 unsigned slot;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 u32 ldtbus, nid;
Yinghai Lu871d5f82008-02-19 03:20:09 -080071 u32 id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 static int lbnr[3] = {
73 LDT_BUS_NUMBER_REGISTER_0,
74 LDT_BUS_NUMBER_REGISTER_1,
75 LDT_BUS_NUMBER_REGISTER_2
76 };
77
Yinghai Lu871d5f82008-02-19 03:20:09 -080078 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 for (i = 0; i < NR_LDT_BUS_NUMBER_REGISTERS; i++) {
Yinghai Lu871d5f82008-02-19 03:20:09 -080091 ldtbus = read_pci_config(0, slot, 0, lbnr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 /*
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.
Yinghai Lu871d5f82008-02-19 03:20:09 -080096 *
Andi Kleend3813fc2005-08-23 03:14:27 +020097 * RED-PEN
98 * This is slightly broken because it assumes
Yinghai Lu871d5f82008-02-19 03:20:09 -080099 * HT node IDs == Linux node ids, which is not always
Andi Kleend3813fc2005-08-23 03:14:27 +0200100 * true. However it is probably mostly true.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 */
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);
Yinghai Lu871d5f82008-02-19 03:20:09 -0800106 j++) {
107 int node = NODE_ID(nid);
108 mp_bus_to_node[j] = (unsigned char)node;
109 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 }
111 }
112 }
113
Yinghai Lu871d5f82008-02-19 03:20:09 -0800114 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 return 0;
121}
122
Yinghai Lu871d5f82008-02-19 03:20:09 -0800123postcore_initcall(early_fill_mp_bus_to_node);