blob: dab38310ee97619fc85f6a42e316c304fb49ebd2 [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
Yinghai Lu35ddd062008-02-19 03:15:08 -080015#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
Andi Kleen355540f2006-07-29 21:42:46 +020024#define PCI_DEVICE_ID_K8HTCONFIG 0x1100
Yinghai Lu35ddd062008-02-19 03:15:08 -080025#define PCI_DEVICE_ID_K8_10H_HTCONFIG 0x1200
26#define PCI_DEVICE_ID_K8_11H_HTCONFIG 0x1300
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
Yinghai Lu871d5f82008-02-19 03:20:09 -080028#ifdef CONFIG_NUMA
29
30#define BUS_NR 256
31
32static int mp_bus_to_node[BUS_NR];
33
34void 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
40int 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070061/**
Yinghai Lu871d5f82008-02-19 03:20:09 -080062 * early_fill_mp_bus_to_node()
63 * called before pcibios_scan_root and pci_scan_bus
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 * 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
Yinghai Lu871d5f82008-02-19 03:20:09 -080068early_fill_mp_bus_to_node(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069{
Yinghai Lu871d5f82008-02-19 03:20:09 -080070#ifdef CONFIG_NUMA
Andi Kleen355540f2006-07-29 21:42:46 +020071 int i, j;
Yinghai Lu871d5f82008-02-19 03:20:09 -080072 unsigned slot;
Yinghai Lu35ddd062008-02-19 03:15:08 -080073 u32 ldtbus;
Yinghai Lu871d5f82008-02-19 03:20:09 -080074 u32 id;
Yinghai Lu35ddd062008-02-19 03:15:08 -080075 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] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 LDT_BUS_NUMBER_REGISTER_0,
83 LDT_BUS_NUMBER_REGISTER_1,
Yinghai Lu35ddd062008-02-19 03:15:08 -080084 LDT_BUS_NUMBER_REGISTER_2,
85 LDT_BUS_NUMBER_REGISTER_3
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 };
87
Yinghai Lu871d5f82008-02-19 03:20:09 -080088 for (i = 0; i < BUS_NR; i++)
89 mp_bus_to_node[i] = -1;
90
91 if (!early_pci_allowed())
92 return -1;
93
Yinghai Lu35ddd062008-02-19 03:15:08 -080094 slot = 0x18;
95 id = read_pci_config(0, slot, 0, PCI_VENDOR_ID);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Yinghai Lu35ddd062008-02-19 03:15:08 -080097 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 }
120
Yinghai Lu35ddd062008-02-19 03:15:08 -0800121out:
Yinghai Lu871d5f82008-02-19 03:20:09 -0800122 for (i = 0; i < BUS_NR; i++) {
Yinghai Lu35ddd062008-02-19 03:15:08 -0800123 node = mp_bus_to_node[i];
Yinghai Lu871d5f82008-02-19 03:20:09 -0800124 if (node >= 0)
125 printk(KERN_DEBUG "bus: %02x to node: %02x\n", i, node);
126 }
127#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 return 0;
129}
130
Yinghai Lu871d5f82008-02-19 03:20:09 -0800131postcore_initcall(early_fill_mp_bus_to_node);