diff options
Diffstat (limited to 'arch/x86/pci/amd_bus.c')
-rw-r--r-- | arch/x86/pci/amd_bus.c | 239 |
1 files changed, 38 insertions, 201 deletions
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index 572ee9782f2a..fc1e8fe07e5c 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c | |||
@@ -2,180 +2,19 @@ | |||
2 | #include <linux/pci.h> | 2 | #include <linux/pci.h> |
3 | #include <linux/topology.h> | 3 | #include <linux/topology.h> |
4 | #include <linux/cpu.h> | 4 | #include <linux/cpu.h> |
5 | #include <linux/range.h> | ||
6 | |||
5 | #include <asm/pci_x86.h> | 7 | #include <asm/pci_x86.h> |
6 | 8 | ||
7 | #ifdef CONFIG_X86_64 | ||
8 | #include <asm/pci-direct.h> | 9 | #include <asm/pci-direct.h> |
9 | #include <asm/mpspec.h> | 10 | |
10 | #include <linux/cpumask.h> | 11 | #include "bus_numa.h" |
11 | #endif | ||
12 | 12 | ||
13 | /* | 13 | /* |
14 | * This discovers the pcibus <-> node mapping on AMD K8. | 14 | * This discovers the pcibus <-> node mapping on AMD K8. |
15 | * also get peer root bus resource for io,mmio | 15 | * also get peer root bus resource for io,mmio |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #ifdef CONFIG_X86_64 | ||
19 | |||
20 | /* | ||
21 | * sub bus (transparent) will use entres from 3 to store extra from root, | ||
22 | * so need to make sure have enought slot there, increase PCI_BUS_NUM_RESOURCES? | ||
23 | */ | ||
24 | #define RES_NUM 16 | ||
25 | struct pci_root_info { | ||
26 | char name[12]; | ||
27 | unsigned int res_num; | ||
28 | struct resource res[RES_NUM]; | ||
29 | int bus_min; | ||
30 | int bus_max; | ||
31 | int node; | ||
32 | int link; | ||
33 | }; | ||
34 | |||
35 | /* 4 at this time, it may become to 32 */ | ||
36 | #define PCI_ROOT_NR 4 | ||
37 | static int pci_root_num; | ||
38 | static struct pci_root_info pci_root_info[PCI_ROOT_NR]; | ||
39 | |||
40 | void x86_pci_root_bus_res_quirks(struct pci_bus *b) | ||
41 | { | ||
42 | int i; | ||
43 | int j; | ||
44 | struct pci_root_info *info; | ||
45 | |||
46 | /* don't go for it if _CRS is used already */ | ||
47 | if (b->resource[0] != &ioport_resource || | ||
48 | b->resource[1] != &iomem_resource) | ||
49 | return; | ||
50 | |||
51 | /* if only one root bus, don't need to anything */ | ||
52 | if (pci_root_num < 2) | ||
53 | return; | ||
54 | |||
55 | for (i = 0; i < pci_root_num; i++) { | ||
56 | if (pci_root_info[i].bus_min == b->number) | ||
57 | break; | ||
58 | } | ||
59 | |||
60 | if (i == pci_root_num) | ||
61 | return; | ||
62 | |||
63 | printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n", | ||
64 | b->number); | ||
65 | |||
66 | info = &pci_root_info[i]; | ||
67 | for (j = 0; j < info->res_num; j++) { | ||
68 | struct resource *res; | ||
69 | struct resource *root; | ||
70 | |||
71 | res = &info->res[j]; | ||
72 | b->resource[j] = res; | ||
73 | if (res->flags & IORESOURCE_IO) | ||
74 | root = &ioport_resource; | ||
75 | else | ||
76 | root = &iomem_resource; | ||
77 | insert_resource(root, res); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | #define RANGE_NUM 16 | ||
82 | |||
83 | struct res_range { | ||
84 | size_t start; | ||
85 | size_t end; | ||
86 | }; | ||
87 | |||
88 | static void __init update_range(struct res_range *range, size_t start, | ||
89 | size_t end) | ||
90 | { | ||
91 | int i; | ||
92 | int j; | ||
93 | |||
94 | for (j = 0; j < RANGE_NUM; j++) { | ||
95 | if (!range[j].end) | ||
96 | continue; | ||
97 | |||
98 | if (start <= range[j].start && end >= range[j].end) { | ||
99 | range[j].start = 0; | ||
100 | range[j].end = 0; | ||
101 | continue; | ||
102 | } | ||
103 | |||
104 | if (start <= range[j].start && end < range[j].end && range[j].start < end + 1) { | ||
105 | range[j].start = end + 1; | ||
106 | continue; | ||
107 | } | ||
108 | |||
109 | |||
110 | if (start > range[j].start && end >= range[j].end && range[j].end > start - 1) { | ||
111 | range[j].end = start - 1; | ||
112 | continue; | ||
113 | } | ||
114 | |||
115 | if (start > range[j].start && end < range[j].end) { | ||
116 | /* find the new spare */ | ||
117 | for (i = 0; i < RANGE_NUM; i++) { | ||
118 | if (range[i].end == 0) | ||
119 | break; | ||
120 | } | ||
121 | if (i < RANGE_NUM) { | ||
122 | range[i].end = range[j].end; | ||
123 | range[i].start = end + 1; | ||
124 | } else { | ||
125 | printk(KERN_ERR "run of slot in ranges\n"); | ||
126 | } | ||
127 | range[j].end = start - 1; | ||
128 | continue; | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static void __init update_res(struct pci_root_info *info, size_t start, | ||
134 | size_t end, unsigned long flags, int merge) | ||
135 | { | ||
136 | int i; | ||
137 | struct resource *res; | ||
138 | |||
139 | if (!merge) | ||
140 | goto addit; | ||
141 | |||
142 | /* try to merge it with old one */ | ||
143 | for (i = 0; i < info->res_num; i++) { | ||
144 | size_t final_start, final_end; | ||
145 | size_t common_start, common_end; | ||
146 | |||
147 | res = &info->res[i]; | ||
148 | if (res->flags != flags) | ||
149 | continue; | ||
150 | |||
151 | common_start = max((size_t)res->start, start); | ||
152 | common_end = min((size_t)res->end, end); | ||
153 | if (common_start > common_end + 1) | ||
154 | continue; | ||
155 | |||
156 | final_start = min((size_t)res->start, start); | ||
157 | final_end = max((size_t)res->end, end); | ||
158 | |||
159 | res->start = final_start; | ||
160 | res->end = final_end; | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | addit: | ||
165 | |||
166 | /* need to add that */ | ||
167 | if (info->res_num >= RES_NUM) | ||
168 | return; | ||
169 | |||
170 | res = &info->res[info->res_num]; | ||
171 | res->name = info->name; | ||
172 | res->flags = flags; | ||
173 | res->start = start; | ||
174 | res->end = end; | ||
175 | res->child = NULL; | ||
176 | info->res_num++; | ||
177 | } | ||
178 | |||
179 | struct pci_hostbridge_probe { | 18 | struct pci_hostbridge_probe { |
180 | u32 bus; | 19 | u32 bus; |
181 | u32 slot; | 20 | u32 slot; |
@@ -218,6 +57,8 @@ static void __init get_pci_mmcfg_amd_fam10h_range(void) | |||
218 | fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1; | 57 | fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1; |
219 | } | 58 | } |
220 | 59 | ||
60 | #define RANGE_NUM 16 | ||
61 | |||
221 | /** | 62 | /** |
222 | * early_fill_mp_bus_to_node() | 63 | * early_fill_mp_bus_to_node() |
223 | * called before pcibios_scan_root and pci_scan_bus | 64 | * called before pcibios_scan_root and pci_scan_bus |
@@ -230,7 +71,6 @@ static int __init early_fill_mp_bus_info(void) | |||
230 | int j; | 71 | int j; |
231 | unsigned bus; | 72 | unsigned bus; |
232 | unsigned slot; | 73 | unsigned slot; |
233 | int found; | ||
234 | int node; | 74 | int node; |
235 | int link; | 75 | int link; |
236 | int def_node; | 76 | int def_node; |
@@ -238,16 +78,17 @@ static int __init early_fill_mp_bus_info(void) | |||
238 | struct pci_root_info *info; | 78 | struct pci_root_info *info; |
239 | u32 reg; | 79 | u32 reg; |
240 | struct resource *res; | 80 | struct resource *res; |
241 | size_t start; | 81 | u64 start; |
242 | size_t end; | 82 | u64 end; |
243 | struct res_range range[RANGE_NUM]; | 83 | struct range range[RANGE_NUM]; |
244 | u64 val; | 84 | u64 val; |
245 | u32 address; | 85 | u32 address; |
86 | bool found; | ||
246 | 87 | ||
247 | if (!early_pci_allowed()) | 88 | if (!early_pci_allowed()) |
248 | return -1; | 89 | return -1; |
249 | 90 | ||
250 | found = 0; | 91 | found = false; |
251 | for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { | 92 | for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { |
252 | u32 id; | 93 | u32 id; |
253 | u16 device; | 94 | u16 device; |
@@ -261,7 +102,7 @@ static int __init early_fill_mp_bus_info(void) | |||
261 | device = (id>>16) & 0xffff; | 102 | device = (id>>16) & 0xffff; |
262 | if (pci_probes[i].vendor == vendor && | 103 | if (pci_probes[i].vendor == vendor && |
263 | pci_probes[i].device == device) { | 104 | pci_probes[i].device == device) { |
264 | found = 1; | 105 | found = true; |
265 | break; | 106 | break; |
266 | } | 107 | } |
267 | } | 108 | } |
@@ -304,7 +145,7 @@ static int __init early_fill_mp_bus_info(void) | |||
304 | def_link = (reg >> 8) & 0x03; | 145 | def_link = (reg >> 8) & 0x03; |
305 | 146 | ||
306 | memset(range, 0, sizeof(range)); | 147 | memset(range, 0, sizeof(range)); |
307 | range[0].end = 0xffff; | 148 | add_range(range, RANGE_NUM, 0, 0, 0xffff + 1); |
308 | /* io port resource */ | 149 | /* io port resource */ |
309 | for (i = 0; i < 4; i++) { | 150 | for (i = 0; i < 4; i++) { |
310 | reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3)); | 151 | reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3)); |
@@ -328,13 +169,13 @@ static int __init early_fill_mp_bus_info(void) | |||
328 | 169 | ||
329 | info = &pci_root_info[j]; | 170 | info = &pci_root_info[j]; |
330 | printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", | 171 | printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", |
331 | node, link, (u64)start, (u64)end); | 172 | node, link, start, end); |
332 | 173 | ||
333 | /* kernel only handle 16 bit only */ | 174 | /* kernel only handle 16 bit only */ |
334 | if (end > 0xffff) | 175 | if (end > 0xffff) |
335 | end = 0xffff; | 176 | end = 0xffff; |
336 | update_res(info, start, end, IORESOURCE_IO, 1); | 177 | update_res(info, start, end, IORESOURCE_IO, 1); |
337 | update_range(range, start, end); | 178 | subtract_range(range, RANGE_NUM, start, end + 1); |
338 | } | 179 | } |
339 | /* add left over io port range to def node/link, [0, 0xffff] */ | 180 | /* add left over io port range to def node/link, [0, 0xffff] */ |
340 | /* find the position */ | 181 | /* find the position */ |
@@ -349,29 +190,32 @@ static int __init early_fill_mp_bus_info(void) | |||
349 | if (!range[i].end) | 190 | if (!range[i].end) |
350 | continue; | 191 | continue; |
351 | 192 | ||
352 | update_res(info, range[i].start, range[i].end, | 193 | update_res(info, range[i].start, range[i].end - 1, |
353 | IORESOURCE_IO, 1); | 194 | IORESOURCE_IO, 1); |
354 | } | 195 | } |
355 | } | 196 | } |
356 | 197 | ||
357 | memset(range, 0, sizeof(range)); | 198 | memset(range, 0, sizeof(range)); |
358 | /* 0xfd00000000-0xffffffffff for HT */ | 199 | /* 0xfd00000000-0xffffffffff for HT */ |
359 | range[0].end = (0xfdULL<<32) - 1; | 200 | end = cap_resource((0xfdULL<<32) - 1); |
201 | end++; | ||
202 | add_range(range, RANGE_NUM, 0, 0, end); | ||
360 | 203 | ||
361 | /* need to take out [0, TOM) for RAM*/ | 204 | /* need to take out [0, TOM) for RAM*/ |
362 | address = MSR_K8_TOP_MEM1; | 205 | address = MSR_K8_TOP_MEM1; |
363 | rdmsrl(address, val); | 206 | rdmsrl(address, val); |
364 | end = (val & 0xffffff800000ULL); | 207 | end = (val & 0xffffff800000ULL); |
365 | printk(KERN_INFO "TOM: %016lx aka %ldM\n", end, end>>20); | 208 | printk(KERN_INFO "TOM: %016llx aka %lldM\n", end, end>>20); |
366 | if (end < (1ULL<<32)) | 209 | if (end < (1ULL<<32)) |
367 | update_range(range, 0, end - 1); | 210 | subtract_range(range, RANGE_NUM, 0, end); |
368 | 211 | ||
369 | /* get mmconfig */ | 212 | /* get mmconfig */ |
370 | get_pci_mmcfg_amd_fam10h_range(); | 213 | get_pci_mmcfg_amd_fam10h_range(); |
371 | /* need to take out mmconf range */ | 214 | /* need to take out mmconf range */ |
372 | if (fam10h_mmconf_end) { | 215 | if (fam10h_mmconf_end) { |
373 | printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end); | 216 | printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end); |
374 | update_range(range, fam10h_mmconf_start, fam10h_mmconf_end); | 217 | subtract_range(range, RANGE_NUM, fam10h_mmconf_start, |
218 | fam10h_mmconf_end + 1); | ||
375 | } | 219 | } |
376 | 220 | ||
377 | /* mmio resource */ | 221 | /* mmio resource */ |
@@ -401,7 +245,7 @@ static int __init early_fill_mp_bus_info(void) | |||
401 | info = &pci_root_info[j]; | 245 | info = &pci_root_info[j]; |
402 | 246 | ||
403 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", | 247 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", |
404 | node, link, (u64)start, (u64)end); | 248 | node, link, start, end); |
405 | /* | 249 | /* |
406 | * some sick allocation would have range overlap with fam10h | 250 | * some sick allocation would have range overlap with fam10h |
407 | * mmconf range, so need to update start and end. | 251 | * mmconf range, so need to update start and end. |
@@ -426,14 +270,15 @@ static int __init early_fill_mp_bus_info(void) | |||
426 | /* we got a hole */ | 270 | /* we got a hole */ |
427 | endx = fam10h_mmconf_start - 1; | 271 | endx = fam10h_mmconf_start - 1; |
428 | update_res(info, start, endx, IORESOURCE_MEM, 0); | 272 | update_res(info, start, endx, IORESOURCE_MEM, 0); |
429 | update_range(range, start, endx); | 273 | subtract_range(range, RANGE_NUM, start, |
430 | printk(KERN_CONT " ==> [%llx, %llx]", (u64)start, endx); | 274 | endx + 1); |
275 | printk(KERN_CONT " ==> [%llx, %llx]", start, endx); | ||
431 | start = fam10h_mmconf_end + 1; | 276 | start = fam10h_mmconf_end + 1; |
432 | changed = 1; | 277 | changed = 1; |
433 | } | 278 | } |
434 | if (changed) { | 279 | if (changed) { |
435 | if (start <= end) { | 280 | if (start <= end) { |
436 | printk(KERN_CONT " %s [%llx, %llx]", endx?"and":"==>", (u64)start, (u64)end); | 281 | printk(KERN_CONT " %s [%llx, %llx]", endx ? "and" : "==>", start, end); |
437 | } else { | 282 | } else { |
438 | printk(KERN_CONT "%s\n", endx?"":" ==> none"); | 283 | printk(KERN_CONT "%s\n", endx?"":" ==> none"); |
439 | continue; | 284 | continue; |
@@ -441,8 +286,9 @@ static int __init early_fill_mp_bus_info(void) | |||
441 | } | 286 | } |
442 | } | 287 | } |
443 | 288 | ||
444 | update_res(info, start, end, IORESOURCE_MEM, 1); | 289 | update_res(info, cap_resource(start), cap_resource(end), |
445 | update_range(range, start, end); | 290 | IORESOURCE_MEM, 1); |
291 | subtract_range(range, RANGE_NUM, start, end + 1); | ||
446 | printk(KERN_CONT "\n"); | 292 | printk(KERN_CONT "\n"); |
447 | } | 293 | } |
448 | 294 | ||
@@ -456,8 +302,8 @@ static int __init early_fill_mp_bus_info(void) | |||
456 | address = MSR_K8_TOP_MEM2; | 302 | address = MSR_K8_TOP_MEM2; |
457 | rdmsrl(address, val); | 303 | rdmsrl(address, val); |
458 | end = (val & 0xffffff800000ULL); | 304 | end = (val & 0xffffff800000ULL); |
459 | printk(KERN_INFO "TOM2: %016lx aka %ldM\n", end, end>>20); | 305 | printk(KERN_INFO "TOM2: %016llx aka %lldM\n", end, end>>20); |
460 | update_range(range, 1ULL<<32, end - 1); | 306 | subtract_range(range, RANGE_NUM, 1ULL<<32, end); |
461 | } | 307 | } |
462 | 308 | ||
463 | /* | 309 | /* |
@@ -476,7 +322,8 @@ static int __init early_fill_mp_bus_info(void) | |||
476 | if (!range[i].end) | 322 | if (!range[i].end) |
477 | continue; | 323 | continue; |
478 | 324 | ||
479 | update_res(info, range[i].start, range[i].end, | 325 | update_res(info, cap_resource(range[i].start), |
326 | cap_resource(range[i].end - 1), | ||
480 | IORESOURCE_MEM, 1); | 327 | IORESOURCE_MEM, 1); |
481 | } | 328 | } |
482 | } | 329 | } |
@@ -488,28 +335,18 @@ static int __init early_fill_mp_bus_info(void) | |||
488 | info = &pci_root_info[i]; | 335 | info = &pci_root_info[i]; |
489 | res_num = info->res_num; | 336 | res_num = info->res_num; |
490 | busnum = info->bus_min; | 337 | busnum = info->bus_min; |
491 | printk(KERN_DEBUG "bus: [%02x,%02x] on node %x link %x\n", | 338 | printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n", |
492 | info->bus_min, info->bus_max, info->node, info->link); | 339 | info->bus_min, info->bus_max, info->node, info->link); |
493 | for (j = 0; j < res_num; j++) { | 340 | for (j = 0; j < res_num; j++) { |
494 | res = &info->res[j]; | 341 | res = &info->res[j]; |
495 | printk(KERN_DEBUG "bus: %02x index %x %s: [%llx, %llx]\n", | 342 | printk(KERN_DEBUG "bus: %02x index %x %pR\n", |
496 | busnum, j, | 343 | busnum, j, res); |
497 | (res->flags & IORESOURCE_IO)?"io port":"mmio", | ||
498 | res->start, res->end); | ||
499 | } | 344 | } |
500 | } | 345 | } |
501 | 346 | ||
502 | return 0; | 347 | return 0; |
503 | } | 348 | } |
504 | 349 | ||
505 | #else /* !CONFIG_X86_64 */ | ||
506 | |||
507 | static int __init early_fill_mp_bus_info(void) { return 0; } | ||
508 | |||
509 | #endif /* !CONFIG_X86_64 */ | ||
510 | |||
511 | /* common 32/64 bit code */ | ||
512 | |||
513 | #define ENABLE_CF8_EXT_CFG (1ULL << 46) | 350 | #define ENABLE_CF8_EXT_CFG (1ULL << 46) |
514 | 351 | ||
515 | static void enable_pci_io_ecs(void *unused) | 352 | static void enable_pci_io_ecs(void *unused) |