diff options
| -rw-r--r-- | arch/x86/kernel/pci-dma.c | 2 | ||||
| -rw-r--r-- | drivers/pci/dmar.c | 13 | ||||
| -rw-r--r-- | drivers/pci/intel-iommu.c | 82 | ||||
| -rw-r--r-- | drivers/pci/pci.c | 13 | ||||
| -rw-r--r-- | drivers/pci/quirks.c | 13 |
5 files changed, 103 insertions, 20 deletions
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index d20009b4e6ef..b2a71dca5642 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c | |||
| @@ -311,7 +311,7 @@ void pci_iommu_shutdown(void) | |||
| 311 | amd_iommu_shutdown(); | 311 | amd_iommu_shutdown(); |
| 312 | } | 312 | } |
| 313 | /* Must execute after PCI subsystem */ | 313 | /* Must execute after PCI subsystem */ |
| 314 | fs_initcall(pci_iommu_init); | 314 | rootfs_initcall(pci_iommu_init); |
| 315 | 315 | ||
| 316 | #ifdef CONFIG_PCI | 316 | #ifdef CONFIG_PCI |
| 317 | /* Many VIA bridges seem to corrupt data for DAC. Disable it here */ | 317 | /* Many VIA bridges seem to corrupt data for DAC. Disable it here */ |
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 14bbaa17e2ca..22b02c6df854 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
| @@ -354,6 +354,7 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header) | |||
| 354 | struct acpi_dmar_hardware_unit *drhd; | 354 | struct acpi_dmar_hardware_unit *drhd; |
| 355 | struct acpi_dmar_reserved_memory *rmrr; | 355 | struct acpi_dmar_reserved_memory *rmrr; |
| 356 | struct acpi_dmar_atsr *atsr; | 356 | struct acpi_dmar_atsr *atsr; |
| 357 | struct acpi_dmar_rhsa *rhsa; | ||
| 357 | 358 | ||
| 358 | switch (header->type) { | 359 | switch (header->type) { |
| 359 | case ACPI_DMAR_TYPE_HARDWARE_UNIT: | 360 | case ACPI_DMAR_TYPE_HARDWARE_UNIT: |
| @@ -375,6 +376,12 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header) | |||
| 375 | atsr = container_of(header, struct acpi_dmar_atsr, header); | 376 | atsr = container_of(header, struct acpi_dmar_atsr, header); |
| 376 | printk(KERN_INFO PREFIX "ATSR flags: %#x\n", atsr->flags); | 377 | printk(KERN_INFO PREFIX "ATSR flags: %#x\n", atsr->flags); |
| 377 | break; | 378 | break; |
| 379 | case ACPI_DMAR_HARDWARE_AFFINITY: | ||
| 380 | rhsa = container_of(header, struct acpi_dmar_rhsa, header); | ||
| 381 | printk(KERN_INFO PREFIX "RHSA base: %#016Lx proximity domain: %#x\n", | ||
| 382 | (unsigned long long)rhsa->base_address, | ||
| 383 | rhsa->proximity_domain); | ||
| 384 | break; | ||
| 378 | } | 385 | } |
| 379 | } | 386 | } |
| 380 | 387 | ||
| @@ -459,9 +466,13 @@ parse_dmar_table(void) | |||
| 459 | ret = dmar_parse_one_atsr(entry_header); | 466 | ret = dmar_parse_one_atsr(entry_header); |
| 460 | #endif | 467 | #endif |
| 461 | break; | 468 | break; |
| 469 | case ACPI_DMAR_HARDWARE_AFFINITY: | ||
| 470 | /* We don't do anything with RHSA (yet?) */ | ||
| 471 | break; | ||
| 462 | default: | 472 | default: |
| 463 | printk(KERN_WARNING PREFIX | 473 | printk(KERN_WARNING PREFIX |
| 464 | "Unknown DMAR structure type\n"); | 474 | "Unknown DMAR structure type %d\n", |
| 475 | entry_header->type); | ||
| 465 | ret = 0; /* for forward compatibility */ | 476 | ret = 0; /* for forward compatibility */ |
| 466 | break; | 477 | break; |
| 467 | } | 478 | } |
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 855dd7ca47f3..b1e97e682500 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
| @@ -48,6 +48,7 @@ | |||
| 48 | 48 | ||
| 49 | #define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) | 49 | #define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) |
| 50 | #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) | 50 | #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) |
| 51 | #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) | ||
| 51 | 52 | ||
| 52 | #define IOAPIC_RANGE_START (0xfee00000) | 53 | #define IOAPIC_RANGE_START (0xfee00000) |
| 53 | #define IOAPIC_RANGE_END (0xfeefffff) | 54 | #define IOAPIC_RANGE_END (0xfeefffff) |
| @@ -94,6 +95,7 @@ static inline unsigned long virt_to_dma_pfn(void *p) | |||
| 94 | /* global iommu list, set NULL for ignored DMAR units */ | 95 | /* global iommu list, set NULL for ignored DMAR units */ |
| 95 | static struct intel_iommu **g_iommus; | 96 | static struct intel_iommu **g_iommus; |
| 96 | 97 | ||
| 98 | static void __init check_tylersburg_isoch(void); | ||
| 97 | static int rwbf_quirk; | 99 | static int rwbf_quirk; |
| 98 | 100 | ||
| 99 | /* | 101 | /* |
| @@ -1934,6 +1936,9 @@ error: | |||
| 1934 | } | 1936 | } |
| 1935 | 1937 | ||
| 1936 | static int iommu_identity_mapping; | 1938 | static int iommu_identity_mapping; |
| 1939 | #define IDENTMAP_ALL 1 | ||
| 1940 | #define IDENTMAP_GFX 2 | ||
| 1941 | #define IDENTMAP_AZALIA 4 | ||
| 1937 | 1942 | ||
| 1938 | static int iommu_domain_identity_map(struct dmar_domain *domain, | 1943 | static int iommu_domain_identity_map(struct dmar_domain *domain, |
| 1939 | unsigned long long start, | 1944 | unsigned long long start, |
| @@ -2151,8 +2156,14 @@ static int domain_add_dev_info(struct dmar_domain *domain, | |||
| 2151 | 2156 | ||
| 2152 | static int iommu_should_identity_map(struct pci_dev *pdev, int startup) | 2157 | static int iommu_should_identity_map(struct pci_dev *pdev, int startup) |
| 2153 | { | 2158 | { |
| 2154 | if (iommu_identity_mapping == 2) | 2159 | if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) |
| 2155 | return IS_GFX_DEVICE(pdev); | 2160 | return 1; |
| 2161 | |||
| 2162 | if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev)) | ||
| 2163 | return 1; | ||
| 2164 | |||
| 2165 | if (!(iommu_identity_mapping & IDENTMAP_ALL)) | ||
| 2166 | return 0; | ||
| 2156 | 2167 | ||
| 2157 | /* | 2168 | /* |
| 2158 | * We want to start off with all devices in the 1:1 domain, and | 2169 | * We want to start off with all devices in the 1:1 domain, and |
| @@ -2332,11 +2343,14 @@ int __init init_dmars(void) | |||
| 2332 | } | 2343 | } |
| 2333 | 2344 | ||
| 2334 | if (iommu_pass_through) | 2345 | if (iommu_pass_through) |
| 2335 | iommu_identity_mapping = 1; | 2346 | iommu_identity_mapping |= IDENTMAP_ALL; |
| 2347 | |||
| 2336 | #ifdef CONFIG_DMAR_BROKEN_GFX_WA | 2348 | #ifdef CONFIG_DMAR_BROKEN_GFX_WA |
| 2337 | else | 2349 | iommu_identity_mapping |= IDENTMAP_GFX; |
| 2338 | iommu_identity_mapping = 2; | ||
| 2339 | #endif | 2350 | #endif |
| 2351 | |||
| 2352 | check_tylersburg_isoch(); | ||
| 2353 | |||
| 2340 | /* | 2354 | /* |
| 2341 | * If pass through is not set or not enabled, setup context entries for | 2355 | * If pass through is not set or not enabled, setup context entries for |
| 2342 | * identity mappings for rmrr, gfx, and isa and may fall back to static | 2356 | * identity mappings for rmrr, gfx, and isa and may fall back to static |
| @@ -3670,3 +3684,61 @@ static void __devinit quirk_iommu_rwbf(struct pci_dev *dev) | |||
| 3670 | } | 3684 | } |
| 3671 | 3685 | ||
| 3672 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf); | 3686 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf); |
| 3687 | |||
| 3688 | /* On Tylersburg chipsets, some BIOSes have been known to enable the | ||
| 3689 | ISOCH DMAR unit for the Azalia sound device, but not give it any | ||
| 3690 | TLB entries, which causes it to deadlock. Check for that. We do | ||
| 3691 | this in a function called from init_dmars(), instead of in a PCI | ||
| 3692 | quirk, because we don't want to print the obnoxious "BIOS broken" | ||
| 3693 | message if VT-d is actually disabled. | ||
| 3694 | */ | ||
| 3695 | static void __init check_tylersburg_isoch(void) | ||
| 3696 | { | ||
| 3697 | struct pci_dev *pdev; | ||
| 3698 | uint32_t vtisochctrl; | ||
| 3699 | |||
| 3700 | /* If there's no Azalia in the system anyway, forget it. */ | ||
| 3701 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL); | ||
| 3702 | if (!pdev) | ||
| 3703 | return; | ||
| 3704 | pci_dev_put(pdev); | ||
| 3705 | |||
| 3706 | /* System Management Registers. Might be hidden, in which case | ||
| 3707 | we can't do the sanity check. But that's OK, because the | ||
| 3708 | known-broken BIOSes _don't_ actually hide it, so far. */ | ||
| 3709 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL); | ||
| 3710 | if (!pdev) | ||
| 3711 | return; | ||
| 3712 | |||
| 3713 | if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) { | ||
| 3714 | pci_dev_put(pdev); | ||
| 3715 | return; | ||
| 3716 | } | ||
| 3717 | |||
| 3718 | pci_dev_put(pdev); | ||
| 3719 | |||
| 3720 | /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */ | ||
| 3721 | if (vtisochctrl & 1) | ||
| 3722 | return; | ||
| 3723 | |||
| 3724 | /* Drop all bits other than the number of TLB entries */ | ||
| 3725 | vtisochctrl &= 0x1c; | ||
| 3726 | |||
| 3727 | /* If we have the recommended number of TLB entries (16), fine. */ | ||
| 3728 | if (vtisochctrl == 0x10) | ||
| 3729 | return; | ||
| 3730 | |||
| 3731 | /* Zero TLB entries? You get to ride the short bus to school. */ | ||
| 3732 | if (!vtisochctrl) { | ||
| 3733 | WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n" | ||
| 3734 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | ||
| 3735 | dmi_get_system_info(DMI_BIOS_VENDOR), | ||
| 3736 | dmi_get_system_info(DMI_BIOS_VERSION), | ||
| 3737 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
| 3738 | iommu_identity_mapping |= IDENTMAP_AZALIA; | ||
| 3739 | return; | ||
| 3740 | } | ||
| 3741 | |||
| 3742 | printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n", | ||
| 3743 | vtisochctrl); | ||
| 3744 | } | ||
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 3835871f4832..4e4c295a049f 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
| @@ -2723,17 +2723,6 @@ int __attribute__ ((weak)) pci_ext_cfg_avail(struct pci_dev *dev) | |||
| 2723 | return 1; | 2723 | return 1; |
| 2724 | } | 2724 | } |
| 2725 | 2725 | ||
| 2726 | static int __devinit pci_init(void) | ||
| 2727 | { | ||
| 2728 | struct pci_dev *dev = NULL; | ||
| 2729 | |||
| 2730 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | ||
| 2731 | pci_fixup_device(pci_fixup_final, dev); | ||
| 2732 | } | ||
| 2733 | |||
| 2734 | return 0; | ||
| 2735 | } | ||
| 2736 | |||
| 2737 | static int __init pci_setup(char *str) | 2726 | static int __init pci_setup(char *str) |
| 2738 | { | 2727 | { |
| 2739 | while (str) { | 2728 | while (str) { |
| @@ -2771,8 +2760,6 @@ static int __init pci_setup(char *str) | |||
| 2771 | } | 2760 | } |
| 2772 | early_param("pci", pci_setup); | 2761 | early_param("pci", pci_setup); |
| 2773 | 2762 | ||
| 2774 | device_initcall(pci_init); | ||
| 2775 | |||
| 2776 | EXPORT_SYMBOL(pci_reenable_device); | 2763 | EXPORT_SYMBOL(pci_reenable_device); |
| 2777 | EXPORT_SYMBOL(pci_enable_device_io); | 2764 | EXPORT_SYMBOL(pci_enable_device_io); |
| 2778 | EXPORT_SYMBOL(pci_enable_device_mem); | 2765 | EXPORT_SYMBOL(pci_enable_device_mem); |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index efa6534a6593..a790b1771f9f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
| @@ -2591,6 +2591,19 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) | |||
| 2591 | } | 2591 | } |
| 2592 | pci_do_fixups(dev, start, end); | 2592 | pci_do_fixups(dev, start, end); |
| 2593 | } | 2593 | } |
| 2594 | |||
| 2595 | static int __init pci_apply_final_quirks(void) | ||
| 2596 | { | ||
| 2597 | struct pci_dev *dev = NULL; | ||
| 2598 | |||
| 2599 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | ||
| 2600 | pci_fixup_device(pci_fixup_final, dev); | ||
| 2601 | } | ||
| 2602 | |||
| 2603 | return 0; | ||
| 2604 | } | ||
| 2605 | |||
| 2606 | fs_initcall_sync(pci_apply_final_quirks); | ||
| 2594 | #else | 2607 | #else |
| 2595 | void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {} | 2608 | void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {} |
| 2596 | #endif | 2609 | #endif |
