Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | #include <linux/init.h> |
| 2 | #include <linux/pci.h> |
| 3 | #include <asm/mpspec.h> |
| 4 | #include <linux/cpumask.h> |
| 5 | |
| 6 | /* |
| 7 | * This discovers the pcibus <-> node mapping on AMD K8. |
| 8 | * |
| 9 | * RED-PEN need to call this again on PCI hotplug |
| 10 | * RED-PEN empty cpus get reported wrong |
| 11 | */ |
| 12 | |
| 13 | #define NODE_ID_REGISTER 0x60 |
| 14 | #define NODE_ID(dword) (dword & 0x07) |
| 15 | #define LDT_BUS_NUMBER_REGISTER_0 0x94 |
| 16 | #define LDT_BUS_NUMBER_REGISTER_1 0xB4 |
| 17 | #define LDT_BUS_NUMBER_REGISTER_2 0xD4 |
| 18 | #define NR_LDT_BUS_NUMBER_REGISTERS 3 |
| 19 | #define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 8) & 0xFF) |
| 20 | #define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF) |
Andi Kleen | 355540f | 2006-07-29 21:42:46 +0200 | [diff] [blame] | 21 | #define PCI_DEVICE_ID_K8HTCONFIG 0x1100 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | { |
Andi Kleen | 355540f | 2006-07-29 21:42:46 +0200 | [diff] [blame] | 31 | struct pci_dev *nb_dev = NULL; |
| 32 | int i, j; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 | u32 ldtbus, nid; |
| 34 | static int lbnr[3] = { |
| 35 | LDT_BUS_NUMBER_REGISTER_0, |
| 36 | LDT_BUS_NUMBER_REGISTER_1, |
| 37 | LDT_BUS_NUMBER_REGISTER_2 |
| 38 | }; |
| 39 | |
Andi Kleen | 355540f | 2006-07-29 21:42:46 +0200 | [diff] [blame] | 40 | while ((nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, |
| 41 | PCI_DEVICE_ID_K8HTCONFIG, nb_dev))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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. |
Andi Kleen | d3813fc | 2005-08-23 03:14:27 +0200 | [diff] [blame] | 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. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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); |
Andi Kleen | d3813fc | 2005-08-23 03:14:27 +0200 | [diff] [blame] | 60 | j++) { |
Andi Kleen | 69e1a33 | 2005-09-12 18:49:24 +0200 | [diff] [blame] | 61 | struct pci_bus *bus; |
Muli Ben-Yehuda | 08f1c19 | 2007-07-22 00:23:39 +0300 | [diff] [blame] | 62 | struct pci_sysdata *sd; |
| 63 | |
Andi Kleen | 69e1a33 | 2005-09-12 18:49:24 +0200 | [diff] [blame] | 64 | long node = NODE_ID(nid); |
| 65 | /* Algorithm a bit dumb, but |
| 66 | it shouldn't matter here */ |
| 67 | bus = pci_find_bus(0, j); |
| 68 | if (!bus) |
| 69 | continue; |
Andi Kleen | d3813fc | 2005-08-23 03:14:27 +0200 | [diff] [blame] | 70 | if (!node_online(node)) |
| 71 | node = 0; |
Muli Ben-Yehuda | 08f1c19 | 2007-07-22 00:23:39 +0300 | [diff] [blame] | 72 | |
| 73 | sd = bus->sysdata; |
| 74 | sd->node = node; |
Andi Kleen | d3813fc | 2005-08-23 03:14:27 +0200 | [diff] [blame] | 75 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 76 | } |
| 77 | } |
| 78 | } |
| 79 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 80 | return 0; |
| 81 | } |
| 82 | |
| 83 | fs_initcall(fill_mp_bus_to_cpumask); |