diff options
Diffstat (limited to 'arch/x86/pci/amd_bus.c')
-rw-r--r-- | arch/x86/pci/amd_bus.c | 127 |
1 files changed, 36 insertions, 91 deletions
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index 95ecbd495955..fc1e8fe07e5c 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c | |||
@@ -2,11 +2,11 @@ | |||
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 | #endif | ||
10 | 10 | ||
11 | #include "bus_numa.h" | 11 | #include "bus_numa.h" |
12 | 12 | ||
@@ -15,60 +15,6 @@ | |||
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 | #define RANGE_NUM 16 | ||
21 | |||
22 | struct res_range { | ||
23 | size_t start; | ||
24 | size_t end; | ||
25 | }; | ||
26 | |||
27 | static void __init update_range(struct res_range *range, size_t start, | ||
28 | size_t end) | ||
29 | { | ||
30 | int i; | ||
31 | int j; | ||
32 | |||
33 | for (j = 0; j < RANGE_NUM; j++) { | ||
34 | if (!range[j].end) | ||
35 | continue; | ||
36 | |||
37 | if (start <= range[j].start && end >= range[j].end) { | ||
38 | range[j].start = 0; | ||
39 | range[j].end = 0; | ||
40 | continue; | ||
41 | } | ||
42 | |||
43 | if (start <= range[j].start && end < range[j].end && range[j].start < end + 1) { | ||
44 | range[j].start = end + 1; | ||
45 | continue; | ||
46 | } | ||
47 | |||
48 | |||
49 | if (start > range[j].start && end >= range[j].end && range[j].end > start - 1) { | ||
50 | range[j].end = start - 1; | ||
51 | continue; | ||
52 | } | ||
53 | |||
54 | if (start > range[j].start && end < range[j].end) { | ||
55 | /* find the new spare */ | ||
56 | for (i = 0; i < RANGE_NUM; i++) { | ||
57 | if (range[i].end == 0) | ||
58 | break; | ||
59 | } | ||
60 | if (i < RANGE_NUM) { | ||
61 | range[i].end = range[j].end; | ||
62 | range[i].start = end + 1; | ||
63 | } else { | ||
64 | printk(KERN_ERR "run of slot in ranges\n"); | ||
65 | } | ||
66 | range[j].end = start - 1; | ||
67 | continue; | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | |||
72 | struct pci_hostbridge_probe { | 18 | struct pci_hostbridge_probe { |
73 | u32 bus; | 19 | u32 bus; |
74 | u32 slot; | 20 | u32 slot; |
@@ -111,6 +57,8 @@ static void __init get_pci_mmcfg_amd_fam10h_range(void) | |||
111 | fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1; | 57 | fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1; |
112 | } | 58 | } |
113 | 59 | ||
60 | #define RANGE_NUM 16 | ||
61 | |||
114 | /** | 62 | /** |
115 | * early_fill_mp_bus_to_node() | 63 | * early_fill_mp_bus_to_node() |
116 | * called before pcibios_scan_root and pci_scan_bus | 64 | * called before pcibios_scan_root and pci_scan_bus |
@@ -130,16 +78,17 @@ static int __init early_fill_mp_bus_info(void) | |||
130 | struct pci_root_info *info; | 78 | struct pci_root_info *info; |
131 | u32 reg; | 79 | u32 reg; |
132 | struct resource *res; | 80 | struct resource *res; |
133 | size_t start; | 81 | u64 start; |
134 | size_t end; | 82 | u64 end; |
135 | struct res_range range[RANGE_NUM]; | 83 | struct range range[RANGE_NUM]; |
136 | u64 val; | 84 | u64 val; |
137 | u32 address; | 85 | u32 address; |
86 | bool found; | ||
138 | 87 | ||
139 | if (!early_pci_allowed()) | 88 | if (!early_pci_allowed()) |
140 | return -1; | 89 | return -1; |
141 | 90 | ||
142 | found_all_numa_early = 0; | 91 | found = false; |
143 | for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { | 92 | for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { |
144 | u32 id; | 93 | u32 id; |
145 | u16 device; | 94 | u16 device; |
@@ -153,12 +102,12 @@ static int __init early_fill_mp_bus_info(void) | |||
153 | device = (id>>16) & 0xffff; | 102 | device = (id>>16) & 0xffff; |
154 | if (pci_probes[i].vendor == vendor && | 103 | if (pci_probes[i].vendor == vendor && |
155 | pci_probes[i].device == device) { | 104 | pci_probes[i].device == device) { |
156 | found_all_numa_early = 1; | 105 | found = true; |
157 | break; | 106 | break; |
158 | } | 107 | } |
159 | } | 108 | } |
160 | 109 | ||
161 | if (!found_all_numa_early) | 110 | if (!found) |
162 | return 0; | 111 | return 0; |
163 | 112 | ||
164 | pci_root_num = 0; | 113 | pci_root_num = 0; |
@@ -196,7 +145,7 @@ static int __init early_fill_mp_bus_info(void) | |||
196 | def_link = (reg >> 8) & 0x03; | 145 | def_link = (reg >> 8) & 0x03; |
197 | 146 | ||
198 | memset(range, 0, sizeof(range)); | 147 | memset(range, 0, sizeof(range)); |
199 | range[0].end = 0xffff; | 148 | add_range(range, RANGE_NUM, 0, 0, 0xffff + 1); |
200 | /* io port resource */ | 149 | /* io port resource */ |
201 | for (i = 0; i < 4; i++) { | 150 | for (i = 0; i < 4; i++) { |
202 | reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3)); | 151 | reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3)); |
@@ -220,13 +169,13 @@ static int __init early_fill_mp_bus_info(void) | |||
220 | 169 | ||
221 | info = &pci_root_info[j]; | 170 | info = &pci_root_info[j]; |
222 | 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", |
223 | node, link, (u64)start, (u64)end); | 172 | node, link, start, end); |
224 | 173 | ||
225 | /* kernel only handle 16 bit only */ | 174 | /* kernel only handle 16 bit only */ |
226 | if (end > 0xffff) | 175 | if (end > 0xffff) |
227 | end = 0xffff; | 176 | end = 0xffff; |
228 | update_res(info, start, end, IORESOURCE_IO, 1); | 177 | update_res(info, start, end, IORESOURCE_IO, 1); |
229 | update_range(range, start, end); | 178 | subtract_range(range, RANGE_NUM, start, end + 1); |
230 | } | 179 | } |
231 | /* 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] */ |
232 | /* find the position */ | 181 | /* find the position */ |
@@ -241,29 +190,32 @@ static int __init early_fill_mp_bus_info(void) | |||
241 | if (!range[i].end) | 190 | if (!range[i].end) |
242 | continue; | 191 | continue; |
243 | 192 | ||
244 | update_res(info, range[i].start, range[i].end, | 193 | update_res(info, range[i].start, range[i].end - 1, |
245 | IORESOURCE_IO, 1); | 194 | IORESOURCE_IO, 1); |
246 | } | 195 | } |
247 | } | 196 | } |
248 | 197 | ||
249 | memset(range, 0, sizeof(range)); | 198 | memset(range, 0, sizeof(range)); |
250 | /* 0xfd00000000-0xffffffffff for HT */ | 199 | /* 0xfd00000000-0xffffffffff for HT */ |
251 | range[0].end = (0xfdULL<<32) - 1; | 200 | end = cap_resource((0xfdULL<<32) - 1); |
201 | end++; | ||
202 | add_range(range, RANGE_NUM, 0, 0, end); | ||
252 | 203 | ||
253 | /* need to take out [0, TOM) for RAM*/ | 204 | /* need to take out [0, TOM) for RAM*/ |
254 | address = MSR_K8_TOP_MEM1; | 205 | address = MSR_K8_TOP_MEM1; |
255 | rdmsrl(address, val); | 206 | rdmsrl(address, val); |
256 | end = (val & 0xffffff800000ULL); | 207 | end = (val & 0xffffff800000ULL); |
257 | printk(KERN_INFO "TOM: %016lx aka %ldM\n", end, end>>20); | 208 | printk(KERN_INFO "TOM: %016llx aka %lldM\n", end, end>>20); |
258 | if (end < (1ULL<<32)) | 209 | if (end < (1ULL<<32)) |
259 | update_range(range, 0, end - 1); | 210 | subtract_range(range, RANGE_NUM, 0, end); |
260 | 211 | ||
261 | /* get mmconfig */ | 212 | /* get mmconfig */ |
262 | get_pci_mmcfg_amd_fam10h_range(); | 213 | get_pci_mmcfg_amd_fam10h_range(); |
263 | /* need to take out mmconf range */ | 214 | /* need to take out mmconf range */ |
264 | if (fam10h_mmconf_end) { | 215 | if (fam10h_mmconf_end) { |
265 | 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); |
266 | update_range(range, fam10h_mmconf_start, fam10h_mmconf_end); | 217 | subtract_range(range, RANGE_NUM, fam10h_mmconf_start, |
218 | fam10h_mmconf_end + 1); | ||
267 | } | 219 | } |
268 | 220 | ||
269 | /* mmio resource */ | 221 | /* mmio resource */ |
@@ -293,7 +245,7 @@ static int __init early_fill_mp_bus_info(void) | |||
293 | info = &pci_root_info[j]; | 245 | info = &pci_root_info[j]; |
294 | 246 | ||
295 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", | 247 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", |
296 | node, link, (u64)start, (u64)end); | 248 | node, link, start, end); |
297 | /* | 249 | /* |
298 | * some sick allocation would have range overlap with fam10h | 250 | * some sick allocation would have range overlap with fam10h |
299 | * mmconf range, so need to update start and end. | 251 | * mmconf range, so need to update start and end. |
@@ -318,14 +270,15 @@ static int __init early_fill_mp_bus_info(void) | |||
318 | /* we got a hole */ | 270 | /* we got a hole */ |
319 | endx = fam10h_mmconf_start - 1; | 271 | endx = fam10h_mmconf_start - 1; |
320 | update_res(info, start, endx, IORESOURCE_MEM, 0); | 272 | update_res(info, start, endx, IORESOURCE_MEM, 0); |
321 | update_range(range, start, endx); | 273 | subtract_range(range, RANGE_NUM, start, |
322 | printk(KERN_CONT " ==> [%llx, %llx]", (u64)start, endx); | 274 | endx + 1); |
275 | printk(KERN_CONT " ==> [%llx, %llx]", start, endx); | ||
323 | start = fam10h_mmconf_end + 1; | 276 | start = fam10h_mmconf_end + 1; |
324 | changed = 1; | 277 | changed = 1; |
325 | } | 278 | } |
326 | if (changed) { | 279 | if (changed) { |
327 | if (start <= end) { | 280 | if (start <= end) { |
328 | printk(KERN_CONT " %s [%llx, %llx]", endx?"and":"==>", (u64)start, (u64)end); | 281 | printk(KERN_CONT " %s [%llx, %llx]", endx ? "and" : "==>", start, end); |
329 | } else { | 282 | } else { |
330 | printk(KERN_CONT "%s\n", endx?"":" ==> none"); | 283 | printk(KERN_CONT "%s\n", endx?"":" ==> none"); |
331 | continue; | 284 | continue; |
@@ -333,8 +286,9 @@ static int __init early_fill_mp_bus_info(void) | |||
333 | } | 286 | } |
334 | } | 287 | } |
335 | 288 | ||
336 | update_res(info, start, end, IORESOURCE_MEM, 1); | 289 | update_res(info, cap_resource(start), cap_resource(end), |
337 | update_range(range, start, end); | 290 | IORESOURCE_MEM, 1); |
291 | subtract_range(range, RANGE_NUM, start, end + 1); | ||
338 | printk(KERN_CONT "\n"); | 292 | printk(KERN_CONT "\n"); |
339 | } | 293 | } |
340 | 294 | ||
@@ -348,8 +302,8 @@ static int __init early_fill_mp_bus_info(void) | |||
348 | address = MSR_K8_TOP_MEM2; | 302 | address = MSR_K8_TOP_MEM2; |
349 | rdmsrl(address, val); | 303 | rdmsrl(address, val); |
350 | end = (val & 0xffffff800000ULL); | 304 | end = (val & 0xffffff800000ULL); |
351 | printk(KERN_INFO "TOM2: %016lx aka %ldM\n", end, end>>20); | 305 | printk(KERN_INFO "TOM2: %016llx aka %lldM\n", end, end>>20); |
352 | update_range(range, 1ULL<<32, end - 1); | 306 | subtract_range(range, RANGE_NUM, 1ULL<<32, end); |
353 | } | 307 | } |
354 | 308 | ||
355 | /* | 309 | /* |
@@ -368,7 +322,8 @@ static int __init early_fill_mp_bus_info(void) | |||
368 | if (!range[i].end) | 322 | if (!range[i].end) |
369 | continue; | 323 | continue; |
370 | 324 | ||
371 | 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), | ||
372 | IORESOURCE_MEM, 1); | 327 | IORESOURCE_MEM, 1); |
373 | } | 328 | } |
374 | } | 329 | } |
@@ -384,24 +339,14 @@ static int __init early_fill_mp_bus_info(void) | |||
384 | info->bus_min, info->bus_max, info->node, info->link); | 339 | info->bus_min, info->bus_max, info->node, info->link); |
385 | for (j = 0; j < res_num; j++) { | 340 | for (j = 0; j < res_num; j++) { |
386 | res = &info->res[j]; | 341 | res = &info->res[j]; |
387 | printk(KERN_DEBUG "bus: %02x index %x %s: [%llx, %llx]\n", | 342 | printk(KERN_DEBUG "bus: %02x index %x %pR\n", |
388 | busnum, j, | 343 | busnum, j, res); |
389 | (res->flags & IORESOURCE_IO)?"io port":"mmio", | ||
390 | res->start, res->end); | ||
391 | } | 344 | } |
392 | } | 345 | } |
393 | 346 | ||
394 | return 0; | 347 | return 0; |
395 | } | 348 | } |
396 | 349 | ||
397 | #else /* !CONFIG_X86_64 */ | ||
398 | |||
399 | static int __init early_fill_mp_bus_info(void) { return 0; } | ||
400 | |||
401 | #endif /* !CONFIG_X86_64 */ | ||
402 | |||
403 | /* common 32/64 bit code */ | ||
404 | |||
405 | #define ENABLE_CF8_EXT_CFG (1ULL << 46) | 350 | #define ENABLE_CF8_EXT_CFG (1ULL << 46) |
406 | 351 | ||
407 | static void enable_pci_io_ecs(void *unused) | 352 | static void enable_pci_io_ecs(void *unused) |