|
48 | 48 |
|
49 | 49 | #define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
|
50 | 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 | 53 | #define IOAPIC_RANGE_START (0xfee00000)
|
53 | 54 | #define IOAPIC_RANGE_END (0xfeefffff)
|
@@ -94,6 +95,7 @@ static inline unsigned long virt_to_dma_pfn(void *p)
|
94 | 95 | /* global iommu list, set NULL for ignored DMAR units */
|
95 | 96 | static struct intel_iommu **g_iommus;
|
96 | 97 |
|
| 98 | +static void __init check_tylersburg_isoch(void); |
97 | 99 | static int rwbf_quirk;
|
98 | 100 |
|
99 | 101 | /*
|
@@ -1934,6 +1936,9 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
|
1934 | 1936 | }
|
1935 | 1937 |
|
1936 | 1938 | static int iommu_identity_mapping;
|
| 1939 | +#define IDENTMAP_ALL 1 |
| 1940 | +#define IDENTMAP_GFX 2 |
| 1941 | +#define IDENTMAP_AZALIA 4 |
1937 | 1942 |
|
1938 | 1943 | static int iommu_domain_identity_map(struct dmar_domain *domain,
|
1939 | 1944 | unsigned long long start,
|
@@ -2151,8 +2156,14 @@ static int domain_add_dev_info(struct dmar_domain *domain,
|
2151 | 2156 |
|
2152 | 2157 | static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
|
2153 | 2158 | {
|
2154 |
| - if (iommu_identity_mapping == 2) |
2155 |
| - return IS_GFX_DEVICE(pdev); |
| 2159 | + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(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 | 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 | 2345 | if (iommu_pass_through)
|
2335 |
| - iommu_identity_mapping = 1; |
| 2346 | + iommu_identity_mapping |= IDENTMAP_ALL; |
| 2347 | + |
2336 | 2348 | #ifdef CONFIG_DMAR_BROKEN_GFX_WA
|
2337 |
| - else |
2338 |
| - iommu_identity_mapping = 2; |
| 2349 | + iommu_identity_mapping |= IDENTMAP_GFX; |
2339 | 2350 | #endif
|
| 2351 | + |
| 2352 | + check_tylersburg_isoch(); |
| 2353 | + |
2340 | 2354 | /*
|
2341 | 2355 | * If pass through is not set or not enabled, setup context entries for
|
2342 | 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 | 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 | +} |
0 commit comments