Blame view
arch/x86/mm/amdtopology.c
4.28 KB
3aa88cdf6 x86: clean up k8t... |
1 |
/* |
eec1d4fa0 x86, amd-nb: Comp... |
2 |
* AMD NUMA support. |
1da177e4c Linux-2.6.12-rc2 |
3 |
* Discover the memory map and associated nodes. |
3aa88cdf6 x86: clean up k8t... |
4 |
* |
eec1d4fa0 x86, amd-nb: Comp... |
5 |
* This version reads it directly from the AMD northbridge. |
3aa88cdf6 x86: clean up k8t... |
6 |
* |
1da177e4c Linux-2.6.12-rc2 |
7 8 9 10 11 12 13 |
* Copyright 2002,2003 Andi Kleen, SuSE Labs. */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> #include <linux/module.h> #include <linux/nodemask.h> |
a9ce6bc15 x86, memblock: Re... |
14 |
#include <linux/memblock.h> |
2706a0bf7 x86, NUMA: Enable... |
15 |
#include <linux/bootmem.h> |
a9ce6bc15 x86, memblock: Re... |
16 |
|
1da177e4c Linux-2.6.12-rc2 |
17 18 |
#include <asm/io.h> #include <linux/pci_ids.h> |
cbf9bd603 acpi: get boot_cp... |
19 |
#include <linux/acpi.h> |
1da177e4c Linux-2.6.12-rc2 |
20 21 22 23 24 25 |
#include <asm/types.h> #include <asm/mmzone.h> #include <asm/proto.h> #include <asm/e820.h> #include <asm/pci-direct.h> #include <asm/numa.h> |
cbf9bd603 acpi: get boot_cp... |
26 27 |
#include <asm/mpspec.h> #include <asm/apic.h> |
23ac4ae82 x86, k8: Rename k... |
28 |
#include <asm/amd_nb.h> |
1da177e4c Linux-2.6.12-rc2 |
29 |
|
f51bf3073 x86, numa: Fake a... |
30 |
static unsigned char __initdata nodeids[8]; |
8ee2debce x86: Export k8 ph... |
31 |
|
1da177e4c Linux-2.6.12-rc2 |
32 33 |
static __init int find_northbridge(void) { |
3aa88cdf6 x86: clean up k8t... |
34 |
int num; |
1da177e4c Linux-2.6.12-rc2 |
35 |
|
3aa88cdf6 x86: clean up k8t... |
36 |
for (num = 0; num < 32; num++) { |
1da177e4c Linux-2.6.12-rc2 |
37 |
u32 header; |
3aa88cdf6 x86: clean up k8t... |
38 39 |
header = read_pci_config(0, num, 0, 0x00); |
bb4a1d644 x86: add PCI IDs ... |
40 41 42 |
if (header != (PCI_VENDOR_ID_AMD | (0x1100<<16)) && header != (PCI_VENDOR_ID_AMD | (0x1200<<16)) && header != (PCI_VENDOR_ID_AMD | (0x1300<<16))) |
3aa88cdf6 x86: clean up k8t... |
43 |
continue; |
1da177e4c Linux-2.6.12-rc2 |
44 |
|
3aa88cdf6 x86: clean up k8t... |
45 |
header = read_pci_config(0, num, 1, 0x00); |
bb4a1d644 x86: add PCI IDs ... |
46 47 48 |
if (header != (PCI_VENDOR_ID_AMD | (0x1101<<16)) && header != (PCI_VENDOR_ID_AMD | (0x1201<<16)) && header != (PCI_VENDOR_ID_AMD | (0x1301<<16))) |
3aa88cdf6 x86: clean up k8t... |
49 50 51 |
continue; return num; } |
1da177e4c Linux-2.6.12-rc2 |
52 |
|
940fed2e7 x86-64, NUMA: Uni... |
53 |
return -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
54 |
} |
cbf9bd603 acpi: get boot_cp... |
55 56 57 |
static __init void early_get_boot_cpu_id(void) { /* |
f6e9456c9 x86, cleanup: Rem... |
58 |
* need to get the APIC ID of the BSP so can use that to |
eec1d4fa0 x86, amd-nb: Comp... |
59 |
* create apicid_to_node in amd_scan_nodes() |
cbf9bd603 acpi: get boot_cp... |
60 |
*/ |
a4caa18ef x86: fix compilin... |
61 |
#ifdef CONFIG_X86_MPPARSE |
cbf9bd603 acpi: get boot_cp... |
62 63 64 65 66 |
/* * get boot-time SMP configuration: */ if (smp_found_config) early_get_smp_config(); |
a4caa18ef x86: fix compilin... |
67 |
#endif |
8ee2debce x86: Export k8 ph... |
68 |
} |
940fed2e7 x86-64, NUMA: Uni... |
69 |
int __init amd_numa_init(void) |
8ee2debce x86: Export k8 ph... |
70 |
{ |
2706a0bf7 x86, NUMA: Enable... |
71 72 |
u64 start = PFN_PHYS(0); u64 end = PFN_PHYS(max_pfn); |
8ee2debce x86: Export k8 ph... |
73 |
unsigned numnodes; |
2706a0bf7 x86, NUMA: Enable... |
74 |
u64 prevbase; |
45fe6c78c x86-64, NUMA: Mov... |
75 |
int i, j, nb; |
d34c08958 x86: k8topology f... |
76 |
u32 nodeid, reg; |
45fe6c78c x86-64, NUMA: Mov... |
77 |
unsigned int bits, cores, apicid_base; |
1da177e4c Linux-2.6.12-rc2 |
78 |
|
0637a70a5 [PATCH] x86: Allo... |
79 |
if (!early_pci_allowed()) |
940fed2e7 x86-64, NUMA: Uni... |
80 |
return -EINVAL; |
0637a70a5 [PATCH] x86: Allo... |
81 |
|
3aa88cdf6 x86: clean up k8t... |
82 83 |
nb = find_northbridge(); if (nb < 0) |
1da177e4c Linux-2.6.12-rc2 |
84 |
return nb; |
1af5ba514 x86: Clean up and... |
85 86 |
pr_info("Scanning NUMA topology in Northbridge %d ", nb); |
1da177e4c Linux-2.6.12-rc2 |
87 |
|
3aa88cdf6 x86: clean up k8t... |
88 |
reg = read_pci_config(0, nb, 0, 0x60); |
1da177e4c Linux-2.6.12-rc2 |
89 |
numnodes = ((reg >> 4) & 0xF) + 1; |
3bea9c979 [PATCH] x86-64: D... |
90 |
if (numnodes <= 1) |
940fed2e7 x86-64, NUMA: Uni... |
91 |
return -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
92 |
|
8ee2debce x86: Export k8 ph... |
93 94 |
pr_info("Number of physical nodes %d ", numnodes); |
1da177e4c Linux-2.6.12-rc2 |
95 |
|
1da177e4c Linux-2.6.12-rc2 |
96 |
prevbase = 0; |
3aa88cdf6 x86: clean up k8t... |
97 |
for (i = 0; i < 8; i++) { |
2706a0bf7 x86, NUMA: Enable... |
98 |
u64 base, limit; |
3aa88cdf6 x86: clean up k8t... |
99 |
|
1da177e4c Linux-2.6.12-rc2 |
100 101 |
base = read_pci_config(0, nb, 1, 0x40 + i*8); limit = read_pci_config(0, nb, 1, 0x44 + i*8); |
f51bf3073 x86, numa: Fake a... |
102 |
nodeids[i] = nodeid = limit & 7; |
3aa88cdf6 x86: clean up k8t... |
103 |
if ((base & 3) == 0) { |
1da177e4c Linux-2.6.12-rc2 |
104 |
if (i < numnodes) |
1af5ba514 x86: Clean up and... |
105 106 |
pr_info("Skipping disabled node %d ", i); |
1da177e4c Linux-2.6.12-rc2 |
107 |
continue; |
3aa88cdf6 x86: clean up k8t... |
108 |
} |
1da177e4c Linux-2.6.12-rc2 |
109 |
if (nodeid >= numnodes) { |
2706a0bf7 x86, NUMA: Enable... |
110 111 |
pr_info("Ignoring excess node %d (%Lx:%Lx) ", nodeid, |
1af5ba514 x86: Clean up and... |
112 |
base, limit); |
1da177e4c Linux-2.6.12-rc2 |
113 |
continue; |
3aa88cdf6 x86: clean up k8t... |
114 |
} |
1da177e4c Linux-2.6.12-rc2 |
115 |
|
3aa88cdf6 x86: clean up k8t... |
116 |
if (!limit) { |
2706a0bf7 x86, NUMA: Enable... |
117 118 |
pr_info("Skipping node entry %d (base %Lx) ", |
1af5ba514 x86: Clean up and... |
119 |
i, base); |
1da177e4c Linux-2.6.12-rc2 |
120 121 122 |
continue; } if ((base >> 8) & 3 || (limit >> 8) & 3) { |
2706a0bf7 x86, NUMA: Enable... |
123 124 |
pr_err("Node %d using interleaving mode %Lx/%Lx ", |
1af5ba514 x86: Clean up and... |
125 |
nodeid, (base >> 8) & 3, (limit >> 8) & 3); |
940fed2e7 x86-64, NUMA: Uni... |
126 |
return -EINVAL; |
3aa88cdf6 x86: clean up k8t... |
127 |
} |
4697bdcc9 x86-64, NUMA: Kil... |
128 |
if (node_isset(nodeid, numa_nodes_parsed)) { |
1af5ba514 x86: Clean up and... |
129 130 131 |
pr_info("Node %d already present, skipping ", nodeid); |
1da177e4c Linux-2.6.12-rc2 |
132 133 |
continue; } |
3aa88cdf6 x86: clean up k8t... |
134 135 |
limit >>= 16; limit <<= 24; |
1da177e4c Linux-2.6.12-rc2 |
136 |
limit |= (1<<24)-1; |
ffd10a2b7 [PATCH] x86_64: M... |
137 |
limit++; |
1da177e4c Linux-2.6.12-rc2 |
138 |
|
8ee2debce x86: Export k8 ph... |
139 140 |
if (limit > end) limit = end; |
1da177e4c Linux-2.6.12-rc2 |
141 |
if (limit <= base) |
3aa88cdf6 x86: clean up k8t... |
142 |
continue; |
1da177e4c Linux-2.6.12-rc2 |
143 |
base >>= 16; |
3aa88cdf6 x86: clean up k8t... |
144 145 146 147 148 149 150 |
base <<= 24; if (base < start) base = start; if (limit > end) limit = end; if (limit == base) { |
1af5ba514 x86: Clean up and... |
151 152 |
pr_err("Empty node %d ", nodeid); |
3aa88cdf6 x86: clean up k8t... |
153 |
continue; |
1da177e4c Linux-2.6.12-rc2 |
154 |
} |
3aa88cdf6 x86: clean up k8t... |
155 |
if (limit < base) { |
2706a0bf7 x86, NUMA: Enable... |
156 157 |
pr_err("Node %d bogus settings %Lx-%Lx. ", |
3aa88cdf6 x86: clean up k8t... |
158 |
nodeid, base, limit); |
1da177e4c Linux-2.6.12-rc2 |
159 |
continue; |
3aa88cdf6 x86: clean up k8t... |
160 |
} |
1da177e4c Linux-2.6.12-rc2 |
161 |
/* Could sort here, but pun for now. Should not happen anyroads. */ |
3aa88cdf6 x86: clean up k8t... |
162 |
if (prevbase > base) { |
2706a0bf7 x86, NUMA: Enable... |
163 164 |
pr_err("Node map not sorted %Lx,%Lx ", |
3aa88cdf6 x86: clean up k8t... |
165 |
prevbase, base); |
940fed2e7 x86-64, NUMA: Uni... |
166 |
return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
167 |
} |
3aa88cdf6 x86: clean up k8t... |
168 |
|
2706a0bf7 x86, NUMA: Enable... |
169 170 |
pr_info("Node %d MemBase %016Lx Limit %016Lx ", |
1af5ba514 x86: Clean up and... |
171 |
nodeid, base, limit); |
3aa88cdf6 x86: clean up k8t... |
172 |
|
1da177e4c Linux-2.6.12-rc2 |
173 |
prevbase = base; |
91556237e x86-64, NUMA: Kil... |
174 |
numa_add_memblk(nodeid, base, limit); |
92d4a4371 x86-64, NUMA: Ren... |
175 |
node_set(nodeid, numa_nodes_parsed); |
3aa88cdf6 x86: clean up k8t... |
176 |
} |
1da177e4c Linux-2.6.12-rc2 |
177 |
|
4697bdcc9 x86-64, NUMA: Kil... |
178 |
if (!nodes_weight(numa_nodes_parsed)) |
940fed2e7 x86-64, NUMA: Uni... |
179 |
return -ENOENT; |
45fe6c78c x86-64, NUMA: Mov... |
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
/* * We seem to have valid NUMA configuration. Map apicids to nodes * using the coreid bits from early_identify_cpu. */ bits = boot_cpu_data.x86_coreid_bits; cores = 1 << bits; apicid_base = 0; /* get the APIC ID of the BSP early for systems with apicid lifting */ early_get_boot_cpu_id(); if (boot_cpu_physical_apicid > 0) { pr_info("BSP APIC ID: %02x ", boot_cpu_physical_apicid); apicid_base = boot_cpu_physical_apicid; } |
92d4a4371 x86-64, NUMA: Ren... |
196 |
for_each_node_mask(i, numa_nodes_parsed) |
45fe6c78c x86-64, NUMA: Mov... |
197 198 |
for (j = apicid_base; j < cores + apicid_base; j++) set_apicid_to_node((i << bits) + j, i); |
8ee2debce x86: Export k8 ph... |
199 200 |
return 0; } |