diff options
Diffstat (limited to 'drivers/pnp/quirks.c')
-rw-r--r-- | drivers/pnp/quirks.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 258fef272ea7..ebf0d6710b5a 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/pci.h> | ||
18 | #include <linux/string.h> | 19 | #include <linux/string.h> |
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | #include <linux/pnp.h> | 21 | #include <linux/pnp.h> |
@@ -334,6 +335,81 @@ static void quirk_amd_mmconfig_area(struct pnp_dev *dev) | |||
334 | } | 335 | } |
335 | #endif | 336 | #endif |
336 | 337 | ||
338 | #ifdef CONFIG_PCI | ||
339 | /* Device IDs of parts that have 32KB MCH space */ | ||
340 | static const unsigned int mch_quirk_devices[] = { | ||
341 | 0x0154, /* Ivy Bridge */ | ||
342 | 0x0c00, /* Haswell */ | ||
343 | }; | ||
344 | |||
345 | static struct pci_dev *get_intel_host(void) | ||
346 | { | ||
347 | int i; | ||
348 | struct pci_dev *host; | ||
349 | |||
350 | for (i = 0; i < ARRAY_SIZE(mch_quirk_devices); i++) { | ||
351 | host = pci_get_device(PCI_VENDOR_ID_INTEL, mch_quirk_devices[i], | ||
352 | NULL); | ||
353 | if (host) | ||
354 | return host; | ||
355 | } | ||
356 | return NULL; | ||
357 | } | ||
358 | |||
359 | static void quirk_intel_mch(struct pnp_dev *dev) | ||
360 | { | ||
361 | struct pci_dev *host; | ||
362 | u32 addr_lo, addr_hi; | ||
363 | struct pci_bus_region region; | ||
364 | struct resource mch; | ||
365 | struct pnp_resource *pnp_res; | ||
366 | struct resource *res; | ||
367 | |||
368 | host = get_intel_host(); | ||
369 | if (!host) | ||
370 | return; | ||
371 | |||
372 | /* | ||
373 | * MCHBAR is not an architected PCI BAR, so MCH space is usually | ||
374 | * reported as a PNP0C02 resource. The MCH space was originally | ||
375 | * 16KB, but is 32KB in newer parts. Some BIOSes still report a | ||
376 | * PNP0C02 resource that is only 16KB, which means the rest of the | ||
377 | * MCH space is consumed but unreported. | ||
378 | */ | ||
379 | |||
380 | /* | ||
381 | * Read MCHBAR for Host Member Mapped Register Range Base | ||
382 | * https://www-ssl.intel.com/content/www/us/en/processors/core/4th-gen-core-family-desktop-vol-2-datasheet | ||
383 | * Sec 3.1.12. | ||
384 | */ | ||
385 | pci_read_config_dword(host, 0x48, &addr_lo); | ||
386 | region.start = addr_lo & ~0x7fff; | ||
387 | pci_read_config_dword(host, 0x4c, &addr_hi); | ||
388 | region.start |= (u64) addr_hi << 32; | ||
389 | region.end = region.start + 32*1024 - 1; | ||
390 | |||
391 | memset(&mch, 0, sizeof(mch)); | ||
392 | mch.flags = IORESOURCE_MEM; | ||
393 | pcibios_bus_to_resource(host->bus, &mch, ®ion); | ||
394 | |||
395 | list_for_each_entry(pnp_res, &dev->resources, list) { | ||
396 | res = &pnp_res->res; | ||
397 | if (res->end < mch.start || res->start > mch.end) | ||
398 | continue; /* no overlap */ | ||
399 | if (res->start == mch.start && res->end == mch.end) | ||
400 | continue; /* exact match */ | ||
401 | |||
402 | dev_info(&dev->dev, FW_BUG "PNP resource %pR covers only part of %s Intel MCH; extending to %pR\n", | ||
403 | res, pci_name(host), &mch); | ||
404 | res->start = mch.start; | ||
405 | res->end = mch.end; | ||
406 | break; | ||
407 | } | ||
408 | |||
409 | pci_dev_put(host); | ||
410 | } | ||
411 | #endif | ||
412 | |||
337 | /* | 413 | /* |
338 | * PnP Quirks | 414 | * PnP Quirks |
339 | * Cards or devices that need some tweaking due to incomplete resource info | 415 | * Cards or devices that need some tweaking due to incomplete resource info |
@@ -364,6 +440,9 @@ static struct pnp_fixup pnp_fixups[] = { | |||
364 | #ifdef CONFIG_AMD_NB | 440 | #ifdef CONFIG_AMD_NB |
365 | {"PNP0c01", quirk_amd_mmconfig_area}, | 441 | {"PNP0c01", quirk_amd_mmconfig_area}, |
366 | #endif | 442 | #endif |
443 | #ifdef CONFIG_PCI | ||
444 | {"PNP0c02", quirk_intel_mch}, | ||
445 | #endif | ||
367 | {""} | 446 | {""} |
368 | }; | 447 | }; |
369 | 448 | ||