aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/dmar.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/dmar.c')
-rw-r--r--drivers/pci/dmar.c59
1 files changed, 47 insertions, 12 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 0d064d1e840a..525a32487abd 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -175,15 +175,6 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
175 int ret = 0; 175 int ret = 0;
176 176
177 drhd = (struct acpi_dmar_hardware_unit *)header; 177 drhd = (struct acpi_dmar_hardware_unit *)header;
178 if (!drhd->address) {
179 /* Promote an attitude of violence to a BIOS engineer today */
180 WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
181 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
182 dmi_get_system_info(DMI_BIOS_VENDOR),
183 dmi_get_system_info(DMI_BIOS_VERSION),
184 dmi_get_system_info(DMI_PRODUCT_VERSION));
185 return -ENODEV;
186 }
187 dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL); 178 dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
188 if (!dmaru) 179 if (!dmaru)
189 return -ENOMEM; 180 return -ENOMEM;
@@ -622,12 +613,53 @@ int __init dmar_table_init(void)
622 return 0; 613 return 0;
623} 614}
624 615
616int __init check_zero_address(void)
617{
618 struct acpi_table_dmar *dmar;
619 struct acpi_dmar_header *entry_header;
620 struct acpi_dmar_hardware_unit *drhd;
621
622 dmar = (struct acpi_table_dmar *)dmar_tbl;
623 entry_header = (struct acpi_dmar_header *)(dmar + 1);
624
625 while (((unsigned long)entry_header) <
626 (((unsigned long)dmar) + dmar_tbl->length)) {
627 /* Avoid looping forever on bad ACPI tables */
628 if (entry_header->length == 0) {
629 printk(KERN_WARNING PREFIX
630 "Invalid 0-length structure\n");
631 return 0;
632 }
633
634 if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) {
635 drhd = (void *)entry_header;
636 if (!drhd->address) {
637 /* Promote an attitude of violence to a BIOS engineer today */
638 WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
639 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
640 dmi_get_system_info(DMI_BIOS_VENDOR),
641 dmi_get_system_info(DMI_BIOS_VERSION),
642 dmi_get_system_info(DMI_PRODUCT_VERSION));
643#ifdef CONFIG_DMAR
644 dmar_disabled = 1;
645#endif
646 return 0;
647 }
648 break;
649 }
650
651 entry_header = ((void *)entry_header + entry_header->length);
652 }
653 return 1;
654}
655
625void __init detect_intel_iommu(void) 656void __init detect_intel_iommu(void)
626{ 657{
627 int ret; 658 int ret;
628 659
629 ret = dmar_table_detect(); 660 ret = dmar_table_detect();
630 661 if (ret)
662 ret = check_zero_address();
631 { 663 {
632#ifdef CONFIG_INTR_REMAP 664#ifdef CONFIG_INTR_REMAP
633 struct acpi_table_dmar *dmar; 665 struct acpi_table_dmar *dmar;
@@ -644,10 +676,13 @@ void __init detect_intel_iommu(void)
644 "x2apic and Intr-remapping.\n"); 676 "x2apic and Intr-remapping.\n");
645#endif 677#endif
646#ifdef CONFIG_DMAR 678#ifdef CONFIG_DMAR
647 if (ret && !no_iommu && !iommu_detected && !swiotlb && 679 if (ret && !no_iommu && !iommu_detected && !dmar_disabled)
648 !dmar_disabled)
649 iommu_detected = 1; 680 iommu_detected = 1;
650#endif 681#endif
682#ifdef CONFIG_X86
683 if (ret)
684 x86_init.iommu.iommu_init = intel_iommu_init;
685#endif
651 } 686 }
652 early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size); 687 early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size);
653 dmar_tbl = NULL; 688 dmar_tbl = NULL;