Commit 44b6e23b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'iommu-fixes-v5.9-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu

Pull iommu fixes from Joerg Roedel:

 - Fix a device reference counting bug in the Exynos IOMMU driver.

 - Lockdep fix for the Intel VT-d driver.

 - Fix a bug in the AMD IOMMU driver which caused corruption of the IVRS
   ACPI table and caused IOMMU driver initialization failures in kdump
   kernels.

* tag 'iommu-fixes-v5.9-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
  iommu/vt-d: Fix lockdep splat in iommu_flush_dev_iotlb()
  iommu/amd: Fix the overwritten field in IVMD header
  iommu/exynos: add missing put_device() call in exynos_iommu_of_xlate()
parents eed2ef44 1a3f2fd7
......@@ -1103,25 +1103,6 @@ static int __init add_early_maps(void)
return 0;
}
/*
* Reads the device exclusion range from ACPI and initializes the IOMMU with
* it
*/
static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m)
{
if (!(m->flags & IVMD_FLAG_EXCL_RANGE))
return;
/*
* Treat per-device exclusion ranges as r/w unity-mapped regions
* since some buggy BIOSes might lead to the overwritten exclusion
* range (exclusion_start and exclusion_length members). This
* happens when there are multiple exclusion ranges (IVMD entries)
* defined in ACPI table.
*/
m->flags = (IVMD_FLAG_IW | IVMD_FLAG_IR | IVMD_FLAG_UNITY_MAP);
}
/*
* Takes a pointer to an AMD IOMMU entry in the ACPI table and
* initializes the hardware and our data structures with it.
......@@ -2073,30 +2054,6 @@ static void __init free_unity_maps(void)
}
}
/* called when we find an exclusion range definition in ACPI */
static int __init init_exclusion_range(struct ivmd_header *m)
{
int i;
switch (m->type) {
case ACPI_IVMD_TYPE:
set_device_exclusion_range(m->devid, m);
break;
case ACPI_IVMD_TYPE_ALL:
for (i = 0; i <= amd_iommu_last_bdf; ++i)
set_device_exclusion_range(i, m);
break;
case ACPI_IVMD_TYPE_RANGE:
for (i = m->devid; i <= m->aux; ++i)
set_device_exclusion_range(i, m);
break;
default:
break;
}
return 0;
}
/* called for unity map ACPI definition */
static int __init init_unity_map_range(struct ivmd_header *m)
{
......@@ -2107,9 +2064,6 @@ static int __init init_unity_map_range(struct ivmd_header *m)
if (e == NULL)
return -ENOMEM;
if (m->flags & IVMD_FLAG_EXCL_RANGE)
init_exclusion_range(m);
switch (m->type) {
default:
kfree(e);
......@@ -2133,6 +2087,16 @@ static int __init init_unity_map_range(struct ivmd_header *m)
e->address_end = e->address_start + PAGE_ALIGN(m->range_length);
e->prot = m->flags >> 1;
/*
* Treat per-device exclusion ranges as r/w unity-mapped regions
* since some buggy BIOSes might lead to the overwritten exclusion
* range (exclusion_start and exclusion_length members). This
* happens when there are multiple exclusion ranges (IVMD entries)
* defined in ACPI table.
*/
if (m->flags & IVMD_FLAG_EXCL_RANGE)
e->prot = (IVMD_FLAG_IW | IVMD_FLAG_IR) >> 1;
DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x"
" range_start: %016llx range_end: %016llx flags: %x\n", s,
PCI_BUS_NUM(e->devid_start), PCI_SLOT(e->devid_start),
......
......@@ -1295,13 +1295,17 @@ static int exynos_iommu_of_xlate(struct device *dev,
return -ENODEV;
data = platform_get_drvdata(sysmmu);
if (!data)
if (!data) {
put_device(&sysmmu->dev);
return -ENODEV;
}
if (!owner) {
owner = kzalloc(sizeof(*owner), GFP_KERNEL);
if (!owner)
if (!owner) {
put_device(&sysmmu->dev);
return -ENOMEM;
}
INIT_LIST_HEAD(&owner->controllers);
mutex_init(&owner->rpm_lock);
......
......@@ -2664,7 +2664,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
}
/* Setup the PASID entry for requests without PASID: */
spin_lock(&iommu->lock);
spin_lock_irqsave(&iommu->lock, flags);
if (hw_pass_through && domain_type_is_si(domain))
ret = intel_pasid_setup_pass_through(iommu, domain,
dev, PASID_RID2PASID);
......@@ -2674,7 +2674,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
else
ret = intel_pasid_setup_second_level(iommu, domain,
dev, PASID_RID2PASID);
spin_unlock(&iommu->lock);
spin_unlock_irqrestore(&iommu->lock, flags);
if (ret) {
dev_err(dev, "Setup RID2PASID failed\n");
dmar_remove_one_dev_info(dev);
......
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