aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wright <chrisw@sous-sol.org>2009-12-02 04:17:13 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-12-08 05:02:15 -0500
commit2c99220810c1c79322034628b993573b088ff2da (patch)
tree0b5e69d0ad7a6da667b752ffd727781c875cccff
parentec208491936d6adb8a70c3dd4a517cdfe54e823d (diff)
intel-iommu: Detect DMAR in hyperspace at probe time.
Many BIOSes will lie to us about the existence of an IOMMU, and claim that there is one at an address which actually returns all 0xFF. We need to detect this early, so that we know we don't have a viable IOMMU and can set up swiotlb before it's too late. Cc: stable@kernel.org Signed-off-by: Chris Wright <chrisw@sous-sol.org> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--drivers/pci/dmar.c34
1 files changed, 29 insertions, 5 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 525a32487abd..56883fc1c7be 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -632,6 +632,9 @@ int __init check_zero_address(void)
632 } 632 }
633 633
634 if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) { 634 if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) {
635 void __iomem *addr;
636 u64 cap, ecap;
637
635 drhd = (void *)entry_header; 638 drhd = (void *)entry_header;
636 if (!drhd->address) { 639 if (!drhd->address) {
637 /* Promote an attitude of violence to a BIOS engineer today */ 640 /* Promote an attitude of violence to a BIOS engineer today */
@@ -640,17 +643,38 @@ int __init check_zero_address(void)
640 dmi_get_system_info(DMI_BIOS_VENDOR), 643 dmi_get_system_info(DMI_BIOS_VENDOR),
641 dmi_get_system_info(DMI_BIOS_VERSION), 644 dmi_get_system_info(DMI_BIOS_VERSION),
642 dmi_get_system_info(DMI_PRODUCT_VERSION)); 645 dmi_get_system_info(DMI_PRODUCT_VERSION));
643#ifdef CONFIG_DMAR 646 goto failed;
644 dmar_disabled = 1; 647 }
645#endif 648
646 return 0; 649 addr = early_ioremap(drhd->address, VTD_PAGE_SIZE);
650 if (!addr ) {
651 printk("IOMMU: can't validate: %llx\n", drhd->address);
652 goto failed;
653 }
654 cap = dmar_readq(addr + DMAR_CAP_REG);
655 ecap = dmar_readq(addr + DMAR_ECAP_REG);
656 early_iounmap(addr, VTD_PAGE_SIZE);
657 if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) {
658 /* Promote an attitude of violence to a BIOS engineer today */
659 WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n"
660 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
661 drhd->address,
662 dmi_get_system_info(DMI_BIOS_VENDOR),
663 dmi_get_system_info(DMI_BIOS_VERSION),
664 dmi_get_system_info(DMI_PRODUCT_VERSION));
665 goto failed;
647 } 666 }
648 break;
649 } 667 }
650 668
651 entry_header = ((void *)entry_header + entry_header->length); 669 entry_header = ((void *)entry_header + entry_header->length);
652 } 670 }
653 return 1; 671 return 1;
672
673failed:
674#ifdef CONFIG_DMAR
675 dmar_disabled = 1;
676#endif
677 return 0;
654} 678}
655 679
656void __init detect_intel_iommu(void) 680void __init detect_intel_iommu(void)