1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/init.h> |
3 | #include <linux/pci.h> |
4 | #include <linux/topology.h> |
5 | #include <linux/cpu.h> |
6 | #include <linux/range.h> |
7 | |
8 | #include <asm/amd_nb.h> |
9 | #include <asm/pci_x86.h> |
10 | |
11 | #include <asm/pci-direct.h> |
12 | |
13 | #include "bus_numa.h" |
14 | |
15 | #define AMD_NB_F0_NODE_ID 0x60 |
16 | #define AMD_NB_F0_UNIT_ID 0x64 |
17 | #define AMD_NB_F1_CONFIG_MAP_REG 0xe0 |
18 | |
19 | #define RANGE_NUM 16 |
20 | #define AMD_NB_F1_CONFIG_MAP_RANGES 4 |
21 | |
22 | struct amd_hostbridge { |
23 | u32 bus; |
24 | u32 slot; |
25 | u32 device; |
26 | }; |
27 | |
28 | /* |
29 | * IMPORTANT NOTE: |
30 | * hb_probes[] and early_root_info_init() is in maintenance mode. |
31 | * It only supports K8, Fam10h, Fam11h, and Fam15h_00h-0fh . |
32 | * Future processor will rely on information in ACPI. |
33 | */ |
34 | static struct amd_hostbridge hb_probes[] __initdata = { |
35 | { 0, 0x18, 0x1100 }, /* K8 */ |
36 | { 0, 0x18, 0x1200 }, /* Family10h */ |
37 | { 0xff, 0, 0x1200 }, /* Family10h */ |
38 | { 0, 0x18, 0x1300 }, /* Family11h */ |
39 | { 0, 0x18, 0x1600 }, /* Family15h */ |
40 | }; |
41 | |
42 | static struct pci_root_info __init *find_pci_root_info(int node, int link) |
43 | { |
44 | struct pci_root_info *info; |
45 | |
46 | /* find the position */ |
47 | list_for_each_entry(info, &pci_root_infos, list) |
48 | if (info->node == node && info->link == link) |
49 | return info; |
50 | |
51 | return NULL; |
52 | } |
53 | |
54 | static inline resource_size_t cap_resource(u64 val) |
55 | { |
56 | if (val > RESOURCE_SIZE_MAX) |
57 | return RESOURCE_SIZE_MAX; |
58 | |
59 | return val; |
60 | } |
61 | |
62 | /** |
63 | * early_root_info_init() |
64 | * called before pcibios_scan_root and pci_scan_bus |
65 | * fills the mp_bus_to_cpumask array based according |
66 | * to the LDT Bus Number Registers found in the northbridge. |
67 | */ |
68 | static int __init early_root_info_init(void) |
69 | { |
70 | int i; |
71 | unsigned bus; |
72 | unsigned slot; |
73 | int node; |
74 | int link; |
75 | int def_node; |
76 | int def_link; |
77 | struct pci_root_info *info; |
78 | u32 reg; |
79 | u64 start; |
80 | u64 end; |
81 | struct range range[RANGE_NUM]; |
82 | u64 val; |
83 | u32 address; |
84 | bool found; |
85 | struct resource fam10h_mmconf_res, *fam10h_mmconf; |
86 | u64 fam10h_mmconf_start; |
87 | u64 fam10h_mmconf_end; |
88 | |
89 | if (!early_pci_allowed()) |
90 | return -1; |
91 | |
92 | found = false; |
93 | for (i = 0; i < ARRAY_SIZE(hb_probes); i++) { |
94 | u32 id; |
95 | u16 device; |
96 | u16 vendor; |
97 | |
98 | bus = hb_probes[i].bus; |
99 | slot = hb_probes[i].slot; |
100 | id = read_pci_config(bus, slot, func: 0, PCI_VENDOR_ID); |
101 | vendor = id & 0xffff; |
102 | device = (id>>16) & 0xffff; |
103 | |
104 | if (vendor != PCI_VENDOR_ID_AMD && |
105 | vendor != PCI_VENDOR_ID_HYGON) |
106 | continue; |
107 | |
108 | if (hb_probes[i].device == device) { |
109 | found = true; |
110 | break; |
111 | } |
112 | } |
113 | |
114 | if (!found) |
115 | return 0; |
116 | |
117 | /* |
118 | * We should learn topology and routing information from _PXM and |
119 | * _CRS methods in the ACPI namespace. We extract node numbers |
120 | * here to work around BIOSes that don't supply _PXM. |
121 | */ |
122 | for (i = 0; i < AMD_NB_F1_CONFIG_MAP_RANGES; i++) { |
123 | int min_bus; |
124 | int max_bus; |
125 | reg = read_pci_config(bus, slot, func: 1, |
126 | AMD_NB_F1_CONFIG_MAP_REG + (i << 2)); |
127 | |
128 | /* Check if that register is enabled for bus range */ |
129 | if ((reg & 7) != 3) |
130 | continue; |
131 | |
132 | min_bus = (reg >> 16) & 0xff; |
133 | max_bus = (reg >> 24) & 0xff; |
134 | node = (reg >> 4) & 0x07; |
135 | link = (reg >> 8) & 0x03; |
136 | |
137 | alloc_pci_root_info(bus_min: min_bus, bus_max: max_bus, node, link); |
138 | } |
139 | |
140 | /* |
141 | * The following code extracts routing information for use on old |
142 | * systems where Linux doesn't automatically use host bridge _CRS |
143 | * methods (or when the user specifies "pci=nocrs"). |
144 | * |
145 | * We only do this through Fam11h, because _CRS should be enough on |
146 | * newer systems. |
147 | */ |
148 | if (boot_cpu_data.x86 > 0x11) |
149 | return 0; |
150 | |
151 | /* get the default node and link for left over res */ |
152 | reg = read_pci_config(bus, slot, func: 0, AMD_NB_F0_NODE_ID); |
153 | def_node = (reg >> 8) & 0x07; |
154 | reg = read_pci_config(bus, slot, func: 0, AMD_NB_F0_UNIT_ID); |
155 | def_link = (reg >> 8) & 0x03; |
156 | |
157 | memset(range, 0, sizeof(range)); |
158 | add_range(range, RANGE_NUM, nr_range: 0, start: 0, end: 0xffff + 1); |
159 | /* io port resource */ |
160 | for (i = 0; i < 4; i++) { |
161 | reg = read_pci_config(bus, slot, func: 1, offset: 0xc0 + (i << 3)); |
162 | if (!(reg & 3)) |
163 | continue; |
164 | |
165 | start = reg & 0xfff000; |
166 | reg = read_pci_config(bus, slot, func: 1, offset: 0xc4 + (i << 3)); |
167 | node = reg & 0x07; |
168 | link = (reg >> 4) & 0x03; |
169 | end = (reg & 0xfff000) | 0xfff; |
170 | |
171 | info = find_pci_root_info(node, link); |
172 | if (!info) |
173 | continue; /* not found */ |
174 | |
175 | printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n" , |
176 | node, link, start, end); |
177 | |
178 | /* kernel only handle 16 bit only */ |
179 | if (end > 0xffff) |
180 | end = 0xffff; |
181 | update_res(info, start, end, IORESOURCE_IO, merge: 1); |
182 | subtract_range(range, RANGE_NUM, start, end: end + 1); |
183 | } |
184 | /* add left over io port range to def node/link, [0, 0xffff] */ |
185 | /* find the position */ |
186 | info = find_pci_root_info(node: def_node, link: def_link); |
187 | if (info) { |
188 | for (i = 0; i < RANGE_NUM; i++) { |
189 | if (!range[i].end) |
190 | continue; |
191 | |
192 | update_res(info, start: range[i].start, end: range[i].end - 1, |
193 | IORESOURCE_IO, merge: 1); |
194 | } |
195 | } |
196 | |
197 | memset(range, 0, sizeof(range)); |
198 | /* 0xfd00000000-0xffffffffff for HT */ |
199 | end = cap_resource(val: (0xfdULL<<32) - 1); |
200 | end++; |
201 | add_range(range, RANGE_NUM, nr_range: 0, start: 0, end); |
202 | |
203 | /* need to take out [0, TOM) for RAM*/ |
204 | address = MSR_K8_TOP_MEM1; |
205 | rdmsrl(address, val); |
206 | end = (val & 0xffffff800000ULL); |
207 | printk(KERN_INFO "TOM: %016llx aka %lldM\n" , end, end>>20); |
208 | if (end < (1ULL<<32)) |
209 | subtract_range(range, RANGE_NUM, start: 0, end); |
210 | |
211 | /* get mmconfig */ |
212 | fam10h_mmconf = amd_get_mmconfig_range(res: &fam10h_mmconf_res); |
213 | /* need to take out mmconf range */ |
214 | if (fam10h_mmconf) { |
215 | printk(KERN_DEBUG "Fam 10h mmconf %pR\n" , fam10h_mmconf); |
216 | fam10h_mmconf_start = fam10h_mmconf->start; |
217 | fam10h_mmconf_end = fam10h_mmconf->end; |
218 | subtract_range(range, RANGE_NUM, start: fam10h_mmconf_start, |
219 | end: fam10h_mmconf_end + 1); |
220 | } else { |
221 | fam10h_mmconf_start = 0; |
222 | fam10h_mmconf_end = 0; |
223 | } |
224 | |
225 | /* mmio resource */ |
226 | for (i = 0; i < 8; i++) { |
227 | reg = read_pci_config(bus, slot, func: 1, offset: 0x80 + (i << 3)); |
228 | if (!(reg & 3)) |
229 | continue; |
230 | |
231 | start = reg & 0xffffff00; /* 39:16 on 31:8*/ |
232 | start <<= 8; |
233 | reg = read_pci_config(bus, slot, func: 1, offset: 0x84 + (i << 3)); |
234 | node = reg & 0x07; |
235 | link = (reg >> 4) & 0x03; |
236 | end = (reg & 0xffffff00); |
237 | end <<= 8; |
238 | end |= 0xffff; |
239 | |
240 | info = find_pci_root_info(node, link); |
241 | |
242 | if (!info) |
243 | continue; |
244 | |
245 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]" , |
246 | node, link, start, end); |
247 | /* |
248 | * some sick allocation would have range overlap with fam10h |
249 | * mmconf range, so need to update start and end. |
250 | */ |
251 | if (fam10h_mmconf_end) { |
252 | int changed = 0; |
253 | u64 endx = 0; |
254 | if (start >= fam10h_mmconf_start && |
255 | start <= fam10h_mmconf_end) { |
256 | start = fam10h_mmconf_end + 1; |
257 | changed = 1; |
258 | } |
259 | |
260 | if (end >= fam10h_mmconf_start && |
261 | end <= fam10h_mmconf_end) { |
262 | end = fam10h_mmconf_start - 1; |
263 | changed = 1; |
264 | } |
265 | |
266 | if (start < fam10h_mmconf_start && |
267 | end > fam10h_mmconf_end) { |
268 | /* we got a hole */ |
269 | endx = fam10h_mmconf_start - 1; |
270 | update_res(info, start, end: endx, IORESOURCE_MEM, merge: 0); |
271 | subtract_range(range, RANGE_NUM, start, |
272 | end: endx + 1); |
273 | printk(KERN_CONT " ==> [%llx, %llx]" , start, endx); |
274 | start = fam10h_mmconf_end + 1; |
275 | changed = 1; |
276 | } |
277 | if (changed) { |
278 | if (start <= end) { |
279 | printk(KERN_CONT " %s [%llx, %llx]" , endx ? "and" : "==>" , start, end); |
280 | } else { |
281 | printk(KERN_CONT "%s\n" , endx?"" :" ==> none" ); |
282 | continue; |
283 | } |
284 | } |
285 | } |
286 | |
287 | update_res(info, start: cap_resource(val: start), end: cap_resource(val: end), |
288 | IORESOURCE_MEM, merge: 1); |
289 | subtract_range(range, RANGE_NUM, start, end: end + 1); |
290 | printk(KERN_CONT "\n" ); |
291 | } |
292 | |
293 | /* need to take out [4G, TOM2) for RAM*/ |
294 | /* SYS_CFG */ |
295 | address = MSR_AMD64_SYSCFG; |
296 | rdmsrl(address, val); |
297 | /* TOP_MEM2 is enabled? */ |
298 | if (val & (1<<21)) { |
299 | /* TOP_MEM2 */ |
300 | address = MSR_K8_TOP_MEM2; |
301 | rdmsrl(address, val); |
302 | end = (val & 0xffffff800000ULL); |
303 | printk(KERN_INFO "TOM2: %016llx aka %lldM\n" , end, end>>20); |
304 | subtract_range(range, RANGE_NUM, start: 1ULL<<32, end); |
305 | } |
306 | |
307 | /* |
308 | * add left over mmio range to def node/link ? |
309 | * that is tricky, just record range in from start_min to 4G |
310 | */ |
311 | info = find_pci_root_info(node: def_node, link: def_link); |
312 | if (info) { |
313 | for (i = 0; i < RANGE_NUM; i++) { |
314 | if (!range[i].end) |
315 | continue; |
316 | |
317 | update_res(info, start: cap_resource(val: range[i].start), |
318 | end: cap_resource(val: range[i].end - 1), |
319 | IORESOURCE_MEM, merge: 1); |
320 | } |
321 | } |
322 | |
323 | list_for_each_entry(info, &pci_root_infos, list) { |
324 | int busnum; |
325 | struct pci_root_res *root_res; |
326 | |
327 | busnum = info->busn.start; |
328 | printk(KERN_DEBUG "bus: %pR on node %x link %x\n" , |
329 | &info->busn, info->node, info->link); |
330 | list_for_each_entry(root_res, &info->resources, list) |
331 | printk(KERN_DEBUG "bus: %02x %pR\n" , |
332 | busnum, &root_res->res); |
333 | } |
334 | |
335 | return 0; |
336 | } |
337 | |
338 | #define ENABLE_CF8_EXT_CFG (1ULL << 46) |
339 | |
340 | static int amd_bus_cpu_online(unsigned int cpu) |
341 | { |
342 | u64 reg; |
343 | |
344 | rdmsrl(MSR_AMD64_NB_CFG, reg); |
345 | if (!(reg & ENABLE_CF8_EXT_CFG)) { |
346 | reg |= ENABLE_CF8_EXT_CFG; |
347 | wrmsrl(MSR_AMD64_NB_CFG, val: reg); |
348 | } |
349 | return 0; |
350 | } |
351 | |
352 | static void __init pci_enable_pci_io_ecs(void) |
353 | { |
354 | #ifdef CONFIG_AMD_NB |
355 | unsigned int i, n; |
356 | |
357 | for (n = i = 0; !n && amd_nb_bus_dev_ranges[i].dev_limit; ++i) { |
358 | u8 bus = amd_nb_bus_dev_ranges[i].bus; |
359 | u8 slot = amd_nb_bus_dev_ranges[i].dev_base; |
360 | u8 limit = amd_nb_bus_dev_ranges[i].dev_limit; |
361 | |
362 | for (; slot < limit; ++slot) { |
363 | u32 val = read_pci_config(bus, slot, func: 3, offset: 0); |
364 | |
365 | if (!early_is_amd_nb(value: val)) |
366 | continue; |
367 | |
368 | val = read_pci_config(bus, slot, func: 3, offset: 0x8c); |
369 | if (!(val & (ENABLE_CF8_EXT_CFG >> 32))) { |
370 | val |= ENABLE_CF8_EXT_CFG >> 32; |
371 | write_pci_config(bus, slot, func: 3, offset: 0x8c, val); |
372 | } |
373 | ++n; |
374 | } |
375 | } |
376 | #endif |
377 | } |
378 | |
379 | static int __init pci_io_ecs_init(void) |
380 | { |
381 | int ret; |
382 | |
383 | /* assume all cpus from fam10h have IO ECS */ |
384 | if (boot_cpu_data.x86 < 0x10) |
385 | return 0; |
386 | |
387 | /* Try the PCI method first. */ |
388 | if (early_pci_allowed()) |
389 | pci_enable_pci_io_ecs(); |
390 | |
391 | ret = cpuhp_setup_state(state: CPUHP_AP_ONLINE_DYN, name: "pci/amd_bus:online" , |
392 | startup: amd_bus_cpu_online, NULL); |
393 | WARN_ON(ret < 0); |
394 | |
395 | pci_probe |= PCI_HAS_IO_ECS; |
396 | |
397 | return 0; |
398 | } |
399 | |
400 | static int __init amd_postcore_init(void) |
401 | { |
402 | if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && |
403 | boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) |
404 | return 0; |
405 | |
406 | early_root_info_init(); |
407 | pci_io_ecs_init(); |
408 | |
409 | return 0; |
410 | } |
411 | |
412 | postcore_initcall(amd_postcore_init); |
413 | |