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

Commit a9366e61 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.infradead.org/users/dwmw2/iommu-2.6.32:
  intel-iommu: Support PCIe hot-plug
  intel-iommu: Obey coherent_dma_mask for alloc_coherent on passthrough
  intel-iommu: Check for 'DMAR at zero' BIOS error earlier.
parents 24dfb2b5 99dcaded
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;
+38 −1
Original line number Diff line number Diff line
@@ -2767,7 +2767,15 @@ static void *intel_alloc_coherent(struct device *hwdev, size_t size,

	size = PAGE_ALIGN(size);
	order = get_order(size);

	if (!iommu_no_mapping(hwdev))
		flags &= ~(GFP_DMA | GFP_DMA32);
	else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
		if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
			flags |= GFP_DMA;
		else
			flags |= GFP_DMA32;
	}

	vaddr = (void *)__get_free_pages(flags, order);
	if (!vaddr)
@@ -3207,6 +3215,33 @@ static int __init init_iommu_sysfs(void)
}
#endif	/* CONFIG_PM */

/*
 * Here we only respond to action of unbound device from driver.
 *
 * Added device is not attached to its DMAR domain here yet. That will happen
 * when mapping the device to iova.
 */
static int device_notifier(struct notifier_block *nb,
				  unsigned long action, void *data)
{
	struct device *dev = data;
	struct pci_dev *pdev = to_pci_dev(dev);
	struct dmar_domain *domain;

	domain = find_domain(pdev);
	if (!domain)
		return 0;

	if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through)
		domain_remove_one_dev_info(domain, pdev);

	return 0;
}

static struct notifier_block device_nb = {
	.notifier_call = device_notifier,
};

int __init intel_iommu_init(void)
{
	int ret = 0;
@@ -3259,6 +3294,8 @@ int __init intel_iommu_init(void)

	register_iommu(&intel_iommu_ops);

	bus_register_notifier(&pci_bus_type, &device_nb);

	return 0;
}