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 | |
Yinghai Lu | 35ddd06 | 2008-02-19 03:15:08 -0800 | [diff] [blame^] | 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 | |
Andi Kleen | 355540f | 2006-07-29 21:42:46 +0200 | [diff] [blame] | 24 | #define PCI_DEVICE_ID_K8HTCONFIG 0x1100 |
Yinghai Lu | 35ddd06 | 2008-02-19 03:15:08 -0800 | [diff] [blame^] | 25 | #define PCI_DEVICE_ID_K8_10H_HTCONFIG 0x1200 |
| 26 | #define PCI_DEVICE_ID_K8_11H_HTCONFIG 0x1300 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 27 | |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame] | 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 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 61 | /** |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame] | 62 | * early_fill_mp_bus_to_node() |
| 63 | * called before pcibios_scan_root and pci_scan_bus |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame] | 68 | early_fill_mp_bus_to_node(void) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 | { |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame] | 70 | #ifdef CONFIG_NUMA |
Andi Kleen | 355540f | 2006-07-29 21:42:46 +0200 | [diff] [blame] | 71 | int i, j; |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame] | 72 | unsigned slot; |
Yinghai Lu | 35ddd06 | 2008-02-19 03:15:08 -0800 | [diff] [blame^] | 73 | u32 ldtbus; |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame] | 74 | u32 id; |
Yinghai Lu | 35ddd06 | 2008-02-19 03:15:08 -0800 | [diff] [blame^] | 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] = { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 82 | LDT_BUS_NUMBER_REGISTER_0, |
| 83 | LDT_BUS_NUMBER_REGISTER_1, |
Yinghai Lu | 35ddd06 | 2008-02-19 03:15:08 -0800 | [diff] [blame^] | 84 | LDT_BUS_NUMBER_REGISTER_2, |
| 85 | LDT_BUS_NUMBER_REGISTER_3 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 86 | }; |
| 87 | |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame] | 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 | |
Yinghai Lu | 35ddd06 | 2008-02-19 03:15:08 -0800 | [diff] [blame^] | 94 | slot = 0x18; |
| 95 | id = read_pci_config(0, slot, 0, PCI_VENDOR_ID); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 96 | |
Yinghai Lu | 35ddd06 | 2008-02-19 03:15:08 -0800 | [diff] [blame^] | 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; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 119 | } |
| 120 | |
Yinghai Lu | 35ddd06 | 2008-02-19 03:15:08 -0800 | [diff] [blame^] | 121 | out: |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame] | 122 | for (i = 0; i < BUS_NR; i++) { |
Yinghai Lu | 35ddd06 | 2008-02-19 03:15:08 -0800 | [diff] [blame^] | 123 | node = mp_bus_to_node[i]; |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame] | 124 | if (node >= 0) |
| 125 | printk(KERN_DEBUG "bus: %02x to node: %02x\n", i, node); |
| 126 | } |
| 127 | #endif |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 128 | return 0; |
| 129 | } |
| 130 | |
Yinghai Lu | 871d5f8 | 2008-02-19 03:20:09 -0800 | [diff] [blame] | 131 | postcore_initcall(early_fill_mp_bus_to_node); |