aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/amdtopology_64.c
diff options
context:
space:
mode:
authorHans Rosenfeld <hans.rosenfeld@amd.com>2010-10-29 11:14:30 -0400
committerBorislav Petkov <borislav.petkov@amd.com>2010-11-18 09:53:04 -0500
commiteec1d4fa00c6552ae2fdf71d59f1eded7c88dd89 (patch)
treeee2c918694e1a01e0826e98c89b703916488bedd /arch/x86/mm/amdtopology_64.c
parente53beacd23d9cb47590da6a7a7f6d417b941a994 (diff)
x86, amd-nb: Complete the rename of AMD NB and related code
Not only the naming of the files was confusing, it was even more so for the function and variable names. Renamed the K8 NB and NUMA stuff that is also used on other AMD platforms. This also renames the CONFIG_K8_NUMA option to CONFIG_AMD_NUMA and the related file k8topology_64.c to amdtopology_64.c. No functional changes intended. Signed-off-by: Hans Rosenfeld <hans.rosenfeld@amd.com> Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
Diffstat (limited to 'arch/x86/mm/amdtopology_64.c')
-rw-r--r--arch/x86/mm/amdtopology_64.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/arch/x86/mm/amdtopology_64.c b/arch/x86/mm/amdtopology_64.c
new file mode 100644
index 000000000000..51fae9cfdecb
--- /dev/null
+++ b/arch/x86/mm/amdtopology_64.c
@@ -0,0 +1,237 @@
1/*
2 * AMD NUMA support.
3 * Discover the memory map and associated nodes.
4 *
5 * This version reads it directly from the AMD northbridge.
6 *
7 * Copyright 2002,2003 Andi Kleen, SuSE Labs.
8 */
9#include <linux/kernel.h>
10#include <linux/init.h>
11#include <linux/string.h>
12#include <linux/module.h>
13#include <linux/nodemask.h>
14#include <linux/memblock.h>
15
16#include <asm/io.h>
17#include <linux/pci_ids.h>
18#include <linux/acpi.h>
19#include <asm/types.h>
20#include <asm/mmzone.h>
21#include <asm/proto.h>
22#include <asm/e820.h>
23#include <asm/pci-direct.h>
24#include <asm/numa.h>
25#include <asm/mpspec.h>
26#include <asm/apic.h>
27#include <asm/amd_nb.h>
28
29static struct bootnode __initdata nodes[8];
30static nodemask_t __initdata nodes_parsed = NODE_MASK_NONE;
31
32static __init int find_northbridge(void)
33{
34 int num;
35
36 for (num = 0; num < 32; num++) {
37 u32 header;
38
39 header = read_pci_config(0, num, 0, 0x00);
40 if (header != (PCI_VENDOR_ID_AMD | (0x1100<<16)) &&
41 header != (PCI_VENDOR_ID_AMD | (0x1200<<16)) &&
42 header != (PCI_VENDOR_ID_AMD | (0x1300<<16)))
43 continue;
44
45 header = read_pci_config(0, num, 1, 0x00);
46 if (header != (PCI_VENDOR_ID_AMD | (0x1101<<16)) &&
47 header != (PCI_VENDOR_ID_AMD | (0x1201<<16)) &&
48 header != (PCI_VENDOR_ID_AMD | (0x1301<<16)))
49 continue;
50 return num;
51 }
52
53 return -1;
54}
55
56static __init void early_get_boot_cpu_id(void)
57{
58 /*
59 * need to get the APIC ID of the BSP so can use that to
60 * create apicid_to_node in amd_scan_nodes()
61 */
62#ifdef CONFIG_X86_MPPARSE
63 /*
64 * get boot-time SMP configuration:
65 */
66 if (smp_found_config)
67 early_get_smp_config();
68#endif
69 early_init_lapic_mapping();
70}
71
72int __init amd_get_nodes(struct bootnode *physnodes)
73{
74 int i;
75 int ret = 0;
76
77 for_each_node_mask(i, nodes_parsed) {
78 physnodes[ret].start = nodes[i].start;
79 physnodes[ret].end = nodes[i].end;
80 ret++;
81 }
82 return ret;
83}
84
85int __init amd_numa_init(unsigned long start_pfn, unsigned long end_pfn)
86{
87 unsigned long start = PFN_PHYS(start_pfn);
88 unsigned long end = PFN_PHYS(end_pfn);
89 unsigned numnodes;
90 unsigned long prevbase;
91 int i, nb, found = 0;
92 u32 nodeid, reg;
93
94 if (!early_pci_allowed())
95 return -1;
96
97 nb = find_northbridge();
98 if (nb < 0)
99 return nb;
100
101 pr_info("Scanning NUMA topology in Northbridge %d\n", nb);
102
103 reg = read_pci_config(0, nb, 0, 0x60);
104 numnodes = ((reg >> 4) & 0xF) + 1;
105 if (numnodes <= 1)
106 return -1;
107
108 pr_info("Number of physical nodes %d\n", numnodes);
109
110 prevbase = 0;
111 for (i = 0; i < 8; i++) {
112 unsigned long base, limit;
113
114 base = read_pci_config(0, nb, 1, 0x40 + i*8);
115 limit = read_pci_config(0, nb, 1, 0x44 + i*8);
116
117 nodeid = limit & 7;
118 if ((base & 3) == 0) {
119 if (i < numnodes)
120 pr_info("Skipping disabled node %d\n", i);
121 continue;
122 }
123 if (nodeid >= numnodes) {
124 pr_info("Ignoring excess node %d (%lx:%lx)\n", nodeid,
125 base, limit);
126 continue;
127 }
128
129 if (!limit) {
130 pr_info("Skipping node entry %d (base %lx)\n",
131 i, base);
132 continue;
133 }
134 if ((base >> 8) & 3 || (limit >> 8) & 3) {
135 pr_err("Node %d using interleaving mode %lx/%lx\n",
136 nodeid, (base >> 8) & 3, (limit >> 8) & 3);
137 return -1;
138 }
139 if (node_isset(nodeid, nodes_parsed)) {
140 pr_info("Node %d already present, skipping\n",
141 nodeid);
142 continue;
143 }
144
145 limit >>= 16;
146 limit <<= 24;
147 limit |= (1<<24)-1;
148 limit++;
149
150 if (limit > end)
151 limit = end;
152 if (limit <= base)
153 continue;
154
155 base >>= 16;
156 base <<= 24;
157
158 if (base < start)
159 base = start;
160 if (limit > end)
161 limit = end;
162 if (limit == base) {
163 pr_err("Empty node %d\n", nodeid);
164 continue;
165 }
166 if (limit < base) {
167 pr_err("Node %d bogus settings %lx-%lx.\n",
168 nodeid, base, limit);
169 continue;
170 }
171
172 /* Could sort here, but pun for now. Should not happen anyroads. */
173 if (prevbase > base) {
174 pr_err("Node map not sorted %lx,%lx\n",
175 prevbase, base);
176 return -1;
177 }
178
179 pr_info("Node %d MemBase %016lx Limit %016lx\n",
180 nodeid, base, limit);
181
182 found++;
183
184 nodes[nodeid].start = base;
185 nodes[nodeid].end = limit;
186
187 prevbase = base;
188
189 node_set(nodeid, nodes_parsed);
190 }
191
192 if (!found)
193 return -1;
194 return 0;
195}
196
197int __init amd_scan_nodes(void)
198{
199 unsigned int bits;
200 unsigned int cores;
201 unsigned int apicid_base;
202 int i;
203
204 BUG_ON(nodes_empty(nodes_parsed));
205 node_possible_map = nodes_parsed;
206 memnode_shift = compute_hash_shift(nodes, 8, NULL);
207 if (memnode_shift < 0) {
208 pr_err("No NUMA node hash function found. Contact maintainer\n");
209 return -1;
210 }
211 pr_info("Using node hash shift of %d\n", memnode_shift);
212
213 /* use the coreid bits from early_identify_cpu */
214 bits = boot_cpu_data.x86_coreid_bits;
215 cores = (1<<bits);
216 apicid_base = 0;
217 /* get the APIC ID of the BSP early for systems with apicid lifting */
218 early_get_boot_cpu_id();
219 if (boot_cpu_physical_apicid > 0) {
220 pr_info("BSP APIC ID: %02x\n", boot_cpu_physical_apicid);
221 apicid_base = boot_cpu_physical_apicid;
222 }
223
224 for_each_node_mask(i, node_possible_map) {
225 int j;
226
227 memblock_x86_register_active_regions(i,
228 nodes[i].start >> PAGE_SHIFT,
229 nodes[i].end >> PAGE_SHIFT);
230 for (j = apicid_base; j < cores + apicid_base; j++)
231 apicid_to_node[(i << bits) + j] = i;
232 setup_node_bootmem(i, nodes[i].start, nodes[i].end);
233 }
234
235 numa_init_array();
236 return 0;
237}