Skip to content

Commit

Permalink
intel-iommu: Detect DMAR in hyperspace at probe time.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Chris Wright authored and David Woodhouse committed Dec 8, 2009
1 parent ec20849 commit 2c99220
Showing 1 changed file with 29 additions and 5 deletions.
34 changes: 29 additions & 5 deletions drivers/pci/dmar.c
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,9 @@ int __init check_zero_address(void)
}

if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) {
void __iomem *addr;
u64 cap, ecap;

drhd = (void *)entry_header;
if (!drhd->address) {
/* Promote an attitude of violence to a BIOS engineer today */
Expand All @@ -640,17 +643,38 @@ int __init check_zero_address(void)
dmi_get_system_info(DMI_BIOS_VENDOR),
dmi_get_system_info(DMI_BIOS_VERSION),
dmi_get_system_info(DMI_PRODUCT_VERSION));
#ifdef CONFIG_DMAR
dmar_disabled = 1;
#endif
return 0;
goto failed;
}

addr = early_ioremap(drhd->address, VTD_PAGE_SIZE);
if (!addr ) {
printk("IOMMU: can't validate: %llx\n", drhd->address);
goto failed;
}
cap = dmar_readq(addr + DMAR_CAP_REG);
ecap = dmar_readq(addr + DMAR_ECAP_REG);
early_iounmap(addr, VTD_PAGE_SIZE);
if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) {
/* Promote an attitude of violence to a BIOS engineer today */
WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n"
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
drhd->address,
dmi_get_system_info(DMI_BIOS_VENDOR),
dmi_get_system_info(DMI_BIOS_VERSION),
dmi_get_system_info(DMI_PRODUCT_VERSION));
goto failed;
}
break;
}

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

failed:
#ifdef CONFIG_DMAR
dmar_disabled = 1;
#endif
return 0;
}

void __init detect_intel_iommu(void)
Expand Down

0 comments on commit 2c99220

Please sign in to comment.