Skip to content

Commit 86cf898

Browse files
David WoodhouseDavid Woodhouse
authored andcommitted
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>
1 parent 799dd75 commit 86cf898

File tree

1 file changed

+39
-10
lines changed

1 file changed

+39
-10
lines changed

drivers/pci/dmar.c

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -175,15 +175,6 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
175175
int ret = 0;
176176

177177
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-
}
187178
dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
188179
if (!dmaru)
189180
return -ENOMEM;
@@ -591,12 +582,50 @@ int __init dmar_table_init(void)
591582
return 0;
592583
}
593584

585+
int __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+
594622
void __init detect_intel_iommu(void)
595623
{
596624
int ret;
597625

598626
ret = dmar_table_detect();
599-
627+
if (ret)
628+
ret = check_zero_address();
600629
{
601630
#ifdef CONFIG_INTR_REMAP
602631
struct acpi_table_dmar *dmar;

0 commit comments

Comments
 (0)