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.
This commit is contained in:
commit
a9366e61b0
2 changed files with 77 additions and 11 deletions
|
@ -175,15 +175,6 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
drhd = (struct acpi_dmar_hardware_unit *)header;
|
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);
|
dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
|
||||||
if (!dmaru)
|
if (!dmaru)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -591,12 +582,50 @@ int __init dmar_table_init(void)
|
||||||
return 0;
|
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)
|
void __init detect_intel_iommu(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = dmar_table_detect();
|
ret = dmar_table_detect();
|
||||||
|
if (ret)
|
||||||
|
ret = check_zero_address();
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_INTR_REMAP
|
#ifdef CONFIG_INTR_REMAP
|
||||||
struct acpi_table_dmar *dmar;
|
struct acpi_table_dmar *dmar;
|
||||||
|
|
|
@ -2767,7 +2767,15 @@ static void *intel_alloc_coherent(struct device *hwdev, size_t size,
|
||||||
|
|
||||||
size = PAGE_ALIGN(size);
|
size = PAGE_ALIGN(size);
|
||||||
order = get_order(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);
|
vaddr = (void *)__get_free_pages(flags, order);
|
||||||
if (!vaddr)
|
if (!vaddr)
|
||||||
|
@ -3207,6 +3215,33 @@ static int __init init_iommu_sysfs(void)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM */
|
#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 __init intel_iommu_init(void)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -3259,6 +3294,8 @@ int __init intel_iommu_init(void)
|
||||||
|
|
||||||
register_iommu(&intel_iommu_ops);
|
register_iommu(&intel_iommu_ops);
|
||||||
|
|
||||||
|
bus_register_notifier(&pci_bus_type, &device_nb);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue