Skip to content

Commit

Permalink
intel-iommu: Check for 'DMAR at zero' BIOS error earlier.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Nov 9, 2009
1 parent 799dd75 commit 86cf898
Showing 1 changed file with 39 additions and 10 deletions.
49 changes: 39 additions & 10 deletions drivers/pci/dmar.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,6 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
int ret = 0;

drhd = (struct acpi_dmar_hardware_unit *)header;
if (!drhd->address) {
/* Promote an attitude of violence to a BIOS engineer today */
WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
dmi_get_system_info(DMI_BIOS_VENDOR),
dmi_get_system_info(DMI_BIOS_VERSION),
dmi_get_system_info(DMI_PRODUCT_VERSION));
return -ENODEV;
}
dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
if (!dmaru)
return -ENOMEM;
Expand Down Expand Up @@ -591,12 +582,50 @@ int __init dmar_table_init(void)
return 0;
}

int __init check_zero_address(void)
{
struct acpi_table_dmar *dmar;
struct acpi_dmar_header *entry_header;
struct acpi_dmar_hardware_unit *drhd;

dmar = (struct acpi_table_dmar *)dmar_tbl;
entry_header = (struct acpi_dmar_header *)(dmar + 1);

while (((unsigned long)entry_header) <
(((unsigned long)dmar) + dmar_tbl->length)) {
/* Avoid looping forever on bad ACPI tables */
if (entry_header->length == 0) {
printk(KERN_WARNING PREFIX
"Invalid 0-length structure\n");
return 0;
}

if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) {
drhd = (void *)entry_header;
if (!drhd->address) {
/* Promote an attitude of violence to a BIOS engineer today */
WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
dmi_get_system_info(DMI_BIOS_VENDOR),
dmi_get_system_info(DMI_BIOS_VERSION),
dmi_get_system_info(DMI_PRODUCT_VERSION));
return 0;
}
break;
}

entry_header = ((void *)entry_header + entry_header->length);
}
return 1;
}

void __init detect_intel_iommu(void)
{
int ret;

ret = dmar_table_detect();

if (ret)
ret = check_zero_address();
{
#ifdef CONFIG_INTR_REMAP
struct acpi_table_dmar *dmar;
Expand Down

0 comments on commit 86cf898

Please sign in to comment.