aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2009-11-09 17:15:15 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-11-09 17:15:15 -0500
commit86cf898e1d0fca245173980e3897580db38569a8 (patch)
treefe9ba4ed67ef8e5ae430f0d7d69fba68f70869d7 /drivers
parent799dd75b1a8380a967c929a4551895788c374b31 (diff)
intel-iommu: Check for 'DMAR at zero' BIOS error earlier.
Chris Wright has some patches which let us fall back to swiotlb nicely if IOMMU initialisation fails. But those are a bit much for 2.6.32. Instead, let's shift the check for the biggest problem, the HP and Acer BIOS bug which reports a DMAR at physical address zero. That one can actually be checked much earlier -- before we even admit to having detected an IOMMU in the first place. So the swiotlb init goes ahead as we want. Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/dmar.c49
1 files changed, 39 insertions, 10 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 22b02c6df854..e5f8fc164fd3 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;
@@ -591,12 +582,50 @@ int __init dmar_table_init(void)
591 return 0; 582 return 0;
592} 583}
593 584
585int __init check_zero_address(void)
586{
587 struct acpi_table_dmar *dmar;
588 struct acpi_dmar_header *entry_header;
589 struct acpi_dmar_hardware_unit *drhd;
590
591 dmar = (struct acpi_table_dmar *)dmar_tbl;
592 entry_header = (struct acpi_dmar_header *)(dmar + 1);
593
594 while (((unsigned long)entry_header) <
595 (((unsigned long)dmar) + dmar_tbl->length)) {
596 /* Avoid looping forever on bad ACPI tables */
597 if (entry_header->length == 0) {
598 printk(KERN_WARNING PREFIX
599 "Invalid 0-length structure\n");
600 return 0;
601 }
602
603 if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) {
604 drhd = (void *)entry_header;
605 if (!drhd->address) {
606 /* Promote an attitude of violence to a BIOS engineer today */
607 WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
608 "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
609 dmi_get_system_info(DMI_BIOS_VENDOR),
610 dmi_get_system_info(DMI_BIOS_VERSION),
611 dmi_get_system_info(DMI_PRODUCT_VERSION));
612 return 0;
613 }
614 break;
615 }
616
617 entry_header = ((void *)entry_header + entry_header->length);
618 }
619 return 1;
620}
621
594void __init detect_intel_iommu(void) 622void __init detect_intel_iommu(void)
595{ 623{
596 int ret; 624 int ret;
597 625
598 ret = dmar_table_detect(); 626 ret = dmar_table_detect();
599 627 if (ret)
628 ret = check_zero_address();
600 { 629 {
601#ifdef CONFIG_INTR_REMAP 630#ifdef CONFIG_INTR_REMAP
602 struct acpi_table_dmar *dmar; 631 struct acpi_table_dmar *dmar;