diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:26:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:26:51 -0400 |
commit | 5f78e4d33945b291d12765cdd7e4304f437b9361 (patch) | |
tree | 113cea729de15a98bb941cc4afb8d13301534ca7 /arch/x86/pci/mmconfig-shared.c | |
parent | 867a89e0b73af48838c7987e80899a1ff26dd6ff (diff) | |
parent | 5f0b2976cb2b62668a076f54419c24b8ab677167 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-pci
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-pci:
x86: add pci=check_enable_amd_mmconf and dmi check
x86: work around io allocation overlap of HT links
acpi: get boot_cpu_id as early for k8_scan_nodes
x86_64: don't need set default res if only have one root bus
x86: double check the multi root bus with fam10h mmconf
x86: multi pci root bus with different io resource range, on 64-bit
x86: use bus conf in NB conf fun1 to get bus range on, on 64-bit
x86: get mp_bus_to_node early
x86 pci: remove checking type for mmconfig probe
x86: remove unneeded check in mmconf reject
driver core: try parent numa_node at first before using default
x86: seperate mmconf for fam10h out from setup_64.c
x86: if acpi=off, force setting the mmconf for fam10h
x86_64: check MSR to get MMCONFIG for AMD Family 10h
x86_64: check and enable MMCONFIG for AMD Family 10h
x86_64: set cfg_size for AMD Family 10h in case MMCONFIG
x86: mmconf enable mcfg early
x86: clear pci_mmcfg_virt when mmcfg get rejected
x86: validate against acpi motherboard resources
Fixed up fairly trivial conflicts in arch/x86/pci/{init.c,pci.h} due to
OLPC support manually.
Diffstat (limited to 'arch/x86/pci/mmconfig-shared.c')
-rw-r--r-- | arch/x86/pci/mmconfig-shared.c | 247 |
1 files changed, 212 insertions, 35 deletions
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 8d54df4dfaad..0cfebecf2a8f 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c | |||
@@ -28,7 +28,7 @@ static int __initdata pci_mmcfg_resources_inserted; | |||
28 | static const char __init *pci_mmcfg_e7520(void) | 28 | static const char __init *pci_mmcfg_e7520(void) |
29 | { | 29 | { |
30 | u32 win; | 30 | u32 win; |
31 | pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win); | 31 | raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win); |
32 | 32 | ||
33 | win = win & 0xf000; | 33 | win = win & 0xf000; |
34 | if(win == 0x0000 || win == 0xf000) | 34 | if(win == 0x0000 || win == 0xf000) |
@@ -53,7 +53,7 @@ static const char __init *pci_mmcfg_intel_945(void) | |||
53 | 53 | ||
54 | pci_mmcfg_config_num = 1; | 54 | pci_mmcfg_config_num = 1; |
55 | 55 | ||
56 | pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar); | 56 | raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar); |
57 | 57 | ||
58 | /* Enable bit */ | 58 | /* Enable bit */ |
59 | if (!(pciexbar & 1)) | 59 | if (!(pciexbar & 1)) |
@@ -100,33 +100,102 @@ static const char __init *pci_mmcfg_intel_945(void) | |||
100 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; | 100 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; |
101 | } | 101 | } |
102 | 102 | ||
103 | static const char __init *pci_mmcfg_amd_fam10h(void) | ||
104 | { | ||
105 | u32 low, high, address; | ||
106 | u64 base, msr; | ||
107 | int i; | ||
108 | unsigned segnbits = 0, busnbits; | ||
109 | |||
110 | if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF)) | ||
111 | return NULL; | ||
112 | |||
113 | address = MSR_FAM10H_MMIO_CONF_BASE; | ||
114 | if (rdmsr_safe(address, &low, &high)) | ||
115 | return NULL; | ||
116 | |||
117 | msr = high; | ||
118 | msr <<= 32; | ||
119 | msr |= low; | ||
120 | |||
121 | /* mmconfig is not enable */ | ||
122 | if (!(msr & FAM10H_MMIO_CONF_ENABLE)) | ||
123 | return NULL; | ||
124 | |||
125 | base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT); | ||
126 | |||
127 | busnbits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) & | ||
128 | FAM10H_MMIO_CONF_BUSRANGE_MASK; | ||
129 | |||
130 | /* | ||
131 | * only handle bus 0 ? | ||
132 | * need to skip it | ||
133 | */ | ||
134 | if (!busnbits) | ||
135 | return NULL; | ||
136 | |||
137 | if (busnbits > 8) { | ||
138 | segnbits = busnbits - 8; | ||
139 | busnbits = 8; | ||
140 | } | ||
141 | |||
142 | pci_mmcfg_config_num = (1 << segnbits); | ||
143 | pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]) * | ||
144 | pci_mmcfg_config_num, GFP_KERNEL); | ||
145 | if (!pci_mmcfg_config) | ||
146 | return NULL; | ||
147 | |||
148 | for (i = 0; i < (1 << segnbits); i++) { | ||
149 | pci_mmcfg_config[i].address = base + (1<<28) * i; | ||
150 | pci_mmcfg_config[i].pci_segment = i; | ||
151 | pci_mmcfg_config[i].start_bus_number = 0; | ||
152 | pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1; | ||
153 | } | ||
154 | |||
155 | return "AMD Family 10h NB"; | ||
156 | } | ||
157 | |||
103 | struct pci_mmcfg_hostbridge_probe { | 158 | struct pci_mmcfg_hostbridge_probe { |
159 | u32 bus; | ||
160 | u32 devfn; | ||
104 | u32 vendor; | 161 | u32 vendor; |
105 | u32 device; | 162 | u32 device; |
106 | const char *(*probe)(void); | 163 | const char *(*probe)(void); |
107 | }; | 164 | }; |
108 | 165 | ||
109 | static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { | 166 | static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { |
110 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, | 167 | { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL, |
111 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, | 168 | PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, |
169 | { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL, | ||
170 | PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, | ||
171 | { 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD, | ||
172 | 0x1200, pci_mmcfg_amd_fam10h }, | ||
173 | { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD, | ||
174 | 0x1200, pci_mmcfg_amd_fam10h }, | ||
112 | }; | 175 | }; |
113 | 176 | ||
114 | static int __init pci_mmcfg_check_hostbridge(void) | 177 | static int __init pci_mmcfg_check_hostbridge(void) |
115 | { | 178 | { |
116 | u32 l; | 179 | u32 l; |
180 | u32 bus, devfn; | ||
117 | u16 vendor, device; | 181 | u16 vendor, device; |
118 | int i; | 182 | int i; |
119 | const char *name; | 183 | const char *name; |
120 | 184 | ||
121 | pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0, 4, &l); | 185 | if (!raw_pci_ops) |
122 | vendor = l & 0xffff; | 186 | return 0; |
123 | device = (l >> 16) & 0xffff; | ||
124 | 187 | ||
125 | pci_mmcfg_config_num = 0; | 188 | pci_mmcfg_config_num = 0; |
126 | pci_mmcfg_config = NULL; | 189 | pci_mmcfg_config = NULL; |
127 | name = NULL; | 190 | name = NULL; |
128 | 191 | ||
129 | for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { | 192 | for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { |
193 | bus = pci_mmcfg_probes[i].bus; | ||
194 | devfn = pci_mmcfg_probes[i].devfn; | ||
195 | raw_pci_ops->read(0, bus, devfn, 0, 4, &l); | ||
196 | vendor = l & 0xffff; | ||
197 | device = (l >> 16) & 0xffff; | ||
198 | |||
130 | if (pci_mmcfg_probes[i].vendor == vendor && | 199 | if (pci_mmcfg_probes[i].vendor == vendor && |
131 | pci_mmcfg_probes[i].device == device) | 200 | pci_mmcfg_probes[i].device == device) |
132 | name = pci_mmcfg_probes[i].probe(); | 201 | name = pci_mmcfg_probes[i].probe(); |
@@ -173,9 +242,78 @@ static void __init pci_mmcfg_insert_resources(unsigned long resource_flags) | |||
173 | pci_mmcfg_resources_inserted = 1; | 242 | pci_mmcfg_resources_inserted = 1; |
174 | } | 243 | } |
175 | 244 | ||
176 | static void __init pci_mmcfg_reject_broken(int type) | 245 | static acpi_status __init check_mcfg_resource(struct acpi_resource *res, |
246 | void *data) | ||
247 | { | ||
248 | struct resource *mcfg_res = data; | ||
249 | struct acpi_resource_address64 address; | ||
250 | acpi_status status; | ||
251 | |||
252 | if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { | ||
253 | struct acpi_resource_fixed_memory32 *fixmem32 = | ||
254 | &res->data.fixed_memory32; | ||
255 | if (!fixmem32) | ||
256 | return AE_OK; | ||
257 | if ((mcfg_res->start >= fixmem32->address) && | ||
258 | (mcfg_res->end < (fixmem32->address + | ||
259 | fixmem32->address_length))) { | ||
260 | mcfg_res->flags = 1; | ||
261 | return AE_CTRL_TERMINATE; | ||
262 | } | ||
263 | } | ||
264 | if ((res->type != ACPI_RESOURCE_TYPE_ADDRESS32) && | ||
265 | (res->type != ACPI_RESOURCE_TYPE_ADDRESS64)) | ||
266 | return AE_OK; | ||
267 | |||
268 | status = acpi_resource_to_address64(res, &address); | ||
269 | if (ACPI_FAILURE(status) || | ||
270 | (address.address_length <= 0) || | ||
271 | (address.resource_type != ACPI_MEMORY_RANGE)) | ||
272 | return AE_OK; | ||
273 | |||
274 | if ((mcfg_res->start >= address.minimum) && | ||
275 | (mcfg_res->end < (address.minimum + address.address_length))) { | ||
276 | mcfg_res->flags = 1; | ||
277 | return AE_CTRL_TERMINATE; | ||
278 | } | ||
279 | return AE_OK; | ||
280 | } | ||
281 | |||
282 | static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl, | ||
283 | void *context, void **rv) | ||
284 | { | ||
285 | struct resource *mcfg_res = context; | ||
286 | |||
287 | acpi_walk_resources(handle, METHOD_NAME__CRS, | ||
288 | check_mcfg_resource, context); | ||
289 | |||
290 | if (mcfg_res->flags) | ||
291 | return AE_CTRL_TERMINATE; | ||
292 | |||
293 | return AE_OK; | ||
294 | } | ||
295 | |||
296 | static int __init is_acpi_reserved(unsigned long start, unsigned long end) | ||
297 | { | ||
298 | struct resource mcfg_res; | ||
299 | |||
300 | mcfg_res.start = start; | ||
301 | mcfg_res.end = end; | ||
302 | mcfg_res.flags = 0; | ||
303 | |||
304 | acpi_get_devices("PNP0C01", find_mboard_resource, &mcfg_res, NULL); | ||
305 | |||
306 | if (!mcfg_res.flags) | ||
307 | acpi_get_devices("PNP0C02", find_mboard_resource, &mcfg_res, | ||
308 | NULL); | ||
309 | |||
310 | return mcfg_res.flags; | ||
311 | } | ||
312 | |||
313 | static void __init pci_mmcfg_reject_broken(int early) | ||
177 | { | 314 | { |
178 | typeof(pci_mmcfg_config[0]) *cfg; | 315 | typeof(pci_mmcfg_config[0]) *cfg; |
316 | int i; | ||
179 | 317 | ||
180 | if ((pci_mmcfg_config_num == 0) || | 318 | if ((pci_mmcfg_config_num == 0) || |
181 | (pci_mmcfg_config == NULL) || | 319 | (pci_mmcfg_config == NULL) || |
@@ -184,51 +322,80 @@ static void __init pci_mmcfg_reject_broken(int type) | |||
184 | 322 | ||
185 | cfg = &pci_mmcfg_config[0]; | 323 | cfg = &pci_mmcfg_config[0]; |
186 | 324 | ||
187 | /* | 325 | for (i = 0; i < pci_mmcfg_config_num; i++) { |
188 | * Handle more broken MCFG tables on Asus etc. | 326 | int valid = 0; |
189 | * They only contain a single entry for bus 0-0. | 327 | u32 size = (cfg->end_bus_number + 1) << 20; |
190 | */ | 328 | cfg = &pci_mmcfg_config[i]; |
191 | if (pci_mmcfg_config_num == 1 && | 329 | printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx " |
192 | cfg->pci_segment == 0 && | 330 | "segment %hu buses %u - %u\n", |
193 | (cfg->start_bus_number | cfg->end_bus_number) == 0) { | 331 | i, (unsigned long)cfg->address, cfg->pci_segment, |
194 | printk(KERN_ERR "PCI: start and end of bus number is 0. " | 332 | (unsigned int)cfg->start_bus_number, |
195 | "Rejected as broken MCFG.\n"); | 333 | (unsigned int)cfg->end_bus_number); |
196 | goto reject; | 334 | |
335 | if (!early && | ||
336 | is_acpi_reserved(cfg->address, cfg->address + size - 1)) { | ||
337 | printk(KERN_NOTICE "PCI: MCFG area at %Lx reserved " | ||
338 | "in ACPI motherboard resources\n", | ||
339 | cfg->address); | ||
340 | valid = 1; | ||
341 | } | ||
342 | |||
343 | if (valid) | ||
344 | continue; | ||
345 | |||
346 | if (!early) | ||
347 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not" | ||
348 | " reserved in ACPI motherboard resources\n", | ||
349 | cfg->address); | ||
350 | /* Don't try to do this check unless configuration | ||
351 | type 1 is available. how about type 2 ?*/ | ||
352 | if (raw_pci_ops && e820_all_mapped(cfg->address, | ||
353 | cfg->address + size - 1, | ||
354 | E820_RESERVED)) { | ||
355 | printk(KERN_NOTICE | ||
356 | "PCI: MCFG area at %Lx reserved in E820\n", | ||
357 | cfg->address); | ||
358 | valid = 1; | ||
359 | } | ||
360 | |||
361 | if (!valid) | ||
362 | goto reject; | ||
197 | } | 363 | } |
198 | 364 | ||
199 | /* | ||
200 | * Only do this check when type 1 works. If it doesn't work | ||
201 | * assume we run on a Mac and always use MCFG | ||
202 | */ | ||
203 | if (type == 1 && !e820_all_mapped(cfg->address, | ||
204 | cfg->address + MMCONFIG_APER_MIN, | ||
205 | E820_RESERVED)) { | ||
206 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not" | ||
207 | " E820-reserved\n", cfg->address); | ||
208 | goto reject; | ||
209 | } | ||
210 | return; | 365 | return; |
211 | 366 | ||
212 | reject: | 367 | reject: |
213 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); | 368 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); |
369 | pci_mmcfg_arch_free(); | ||
214 | kfree(pci_mmcfg_config); | 370 | kfree(pci_mmcfg_config); |
215 | pci_mmcfg_config = NULL; | 371 | pci_mmcfg_config = NULL; |
216 | pci_mmcfg_config_num = 0; | 372 | pci_mmcfg_config_num = 0; |
217 | } | 373 | } |
218 | 374 | ||
219 | void __init pci_mmcfg_init(int type) | 375 | static int __initdata known_bridge; |
220 | { | ||
221 | int known_bridge = 0; | ||
222 | 376 | ||
377 | void __init __pci_mmcfg_init(int early) | ||
378 | { | ||
379 | /* MMCONFIG disabled */ | ||
223 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) | 380 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) |
224 | return; | 381 | return; |
225 | 382 | ||
226 | if (type == 1 && pci_mmcfg_check_hostbridge()) | 383 | /* MMCONFIG already enabled */ |
227 | known_bridge = 1; | 384 | if (!early && !(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF)) |
385 | return; | ||
386 | |||
387 | /* for late to exit */ | ||
388 | if (known_bridge) | ||
389 | return; | ||
390 | |||
391 | if (early) { | ||
392 | if (pci_mmcfg_check_hostbridge()) | ||
393 | known_bridge = 1; | ||
394 | } | ||
228 | 395 | ||
229 | if (!known_bridge) { | 396 | if (!known_bridge) { |
230 | acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); | 397 | acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); |
231 | pci_mmcfg_reject_broken(type); | 398 | pci_mmcfg_reject_broken(early); |
232 | } | 399 | } |
233 | 400 | ||
234 | if ((pci_mmcfg_config_num == 0) || | 401 | if ((pci_mmcfg_config_num == 0) || |
@@ -249,6 +416,16 @@ void __init pci_mmcfg_init(int type) | |||
249 | } | 416 | } |
250 | } | 417 | } |
251 | 418 | ||
419 | void __init pci_mmcfg_early_init(void) | ||
420 | { | ||
421 | __pci_mmcfg_init(1); | ||
422 | } | ||
423 | |||
424 | void __init pci_mmcfg_late_init(void) | ||
425 | { | ||
426 | __pci_mmcfg_init(0); | ||
427 | } | ||
428 | |||
252 | static int __init pci_mmcfg_late_insert_resources(void) | 429 | static int __init pci_mmcfg_late_insert_resources(void) |
253 | { | 430 | { |
254 | /* | 431 | /* |