Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 86cf898e authored by David Woodhouse's avatar David Woodhouse
Browse files

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: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 799dd75b
Loading
Loading
Loading
Loading
+39 −10
Original line number Diff line number Diff line
@@ -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;
@@ -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;