Commit a9366e61 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.infradead.org/users/dwmw2/iommu-2.6.32

* 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
......@@ -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;
......
......@@ -2767,7 +2767,15 @@ static void *intel_alloc_coherent(struct device *hwdev, size_t size,
size = PAGE_ALIGN(size);
order = get_order(size);
flags &= ~(GFP_DMA | GFP_DMA32);
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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment