Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | #include <linux/init.h> |
| 2 | #include <linux/pci.h> |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 3 | #include <asm/pci-direct.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4 | #include <asm/mpspec.h> |
| 5 | #include <linux/cpumask.h> |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 6 | #include <linux/topology.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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) |
Andi Kleen | 355540f | 2006-07-29 21:42:46 +0200 | [diff] [blame] | 23 | #define PCI_DEVICE_ID_K8HTCONFIG 0x1100 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 24 | |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 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 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 58 | /** |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 59 | * early_fill_mp_bus_to_node() |
| 60 | * called before pcibios_scan_root and pci_scan_bus |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 65 | early_fill_mp_bus_to_node(void) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 66 | { |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 67 | #ifdef CONFIG_NUMA |
Andi Kleen | 355540f | 2006-07-29 21:42:46 +0200 | [diff] [blame] | 68 | int i, j; |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 69 | unsigned slot; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 70 | u32 ldtbus, nid; |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 71 | u32 id; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 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); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 89 | |
| 90 | for (i = 0; i < NR_LDT_BUS_NUMBER_REGISTERS; i++) { |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 91 | ldtbus = read_pci_config(0, slot, 0, lbnr[i]); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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. |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 96 | * |
Andi Kleen | d3813fc | 2005-08-23 03:14:27 +0200 | [diff] [blame] | 97 | * RED-PEN |
| 98 | * This is slightly broken because it assumes |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 99 | * HT node IDs == Linux node ids, which is not always |
Andi Kleen | d3813fc | 2005-08-23 03:14:27 +0200 | [diff] [blame] | 100 | * true. However it is probably mostly true. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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); |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 106 | j++) { |
| 107 | int node = NODE_ID(nid); |
| 108 | mp_bus_to_node[j] = (unsigned char)node; |
| 109 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 110 | } |
| 111 | } |
| 112 | } |
| 113 | |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 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 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 120 | return 0; |
| 121 | } |
| 122 | |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame^] | 123 | postcore_initcall(early_fill_mp_bus_to_node); |