IOMMU Fixes for Linux v5.9-rc7
Including: - 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. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEr9jSbILcajRFYWYyK/BELZcBGuMFAl92Iw8ACgkQK/BELZcB GuPI9g//QNQJlLsOVWPVh1es5s3CGA8FJ3INa/SXMCD3q+izsyLX7+MpWhEAO4SN 38F1rFbEkMNKDDuOCzRtBvg8QpJHDrgD5V5IXeK07BDBcVDWO2PgMDAdIx4GGSWL PztJ03swki643vp4fr3eOgkuQlJs+mVRVIbtWh6Xj/ioG/AGaOzVhKehmyjaJ5O9 poQe85/aJ4fkmegNPI4NMxU/QokAi0oY+JBuN5IdkvjbSUiC9JYimisjYGMwthfj UYUuxy7M1OQuO5DMURYth8wJJtU6ipUI4UwQBj16His4SVabTLWDWvNS2R/vmIOt ogqyAx9hbv4xzhMvCbQDvrzmKsvQheEhz2XXPFKJy0zPSKeMghqymOoNrsMSIjVG gd8fYJPgBi6P8O6rYHRPBjqqjdYyoFusu94es9j6/pflRQu4M5edvLv1se+GFhUN UkwN8KyVFQ2RNLoJg07S6PC136xGhb9cW9FX+xmzOVpeiK839pVykWWhqDd0dPCU x6KXnBZGBKMpyHcWLv+FusHIQB2KXhJWYR9q28oZdy06ut9Agw3OBo/fYoR6dRAD 7jwQM/0MIt+3eLPWcSvJgWWl7ivaT7bUDm8qiLSU1SniMv7MtTMAlauqLq7hGnoX kHX5q1xHz56PLS38QpKQWBhky7GHZLBXxqfvuVzggt/lNo8/QAE= =3prr -----END PGP SIGNATURE----- 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()
This commit is contained in:
commit
44b6e23be3
@ -1103,25 +1103,6 @@ static int __init add_early_maps(void)
|
|||||||
return 0;
|
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
|
* Takes a pointer to an AMD IOMMU entry in the ACPI table and
|
||||||
* initializes the hardware and our data structures with it.
|
* 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 */
|
/* called for unity map ACPI definition */
|
||||||
static int __init init_unity_map_range(struct ivmd_header *m)
|
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)
|
if (e == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (m->flags & IVMD_FLAG_EXCL_RANGE)
|
|
||||||
init_exclusion_range(m);
|
|
||||||
|
|
||||||
switch (m->type) {
|
switch (m->type) {
|
||||||
default:
|
default:
|
||||||
kfree(e);
|
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->address_end = e->address_start + PAGE_ALIGN(m->range_length);
|
||||||
e->prot = m->flags >> 1;
|
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"
|
DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x"
|
||||||
" range_start: %016llx range_end: %016llx flags: %x\n", s,
|
" range_start: %016llx range_end: %016llx flags: %x\n", s,
|
||||||
PCI_BUS_NUM(e->devid_start), PCI_SLOT(e->devid_start),
|
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;
|
return -ENODEV;
|
||||||
|
|
||||||
data = platform_get_drvdata(sysmmu);
|
data = platform_get_drvdata(sysmmu);
|
||||||
if (!data)
|
if (!data) {
|
||||||
|
put_device(&sysmmu->dev);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
if (!owner) {
|
if (!owner) {
|
||||||
owner = kzalloc(sizeof(*owner), GFP_KERNEL);
|
owner = kzalloc(sizeof(*owner), GFP_KERNEL);
|
||||||
if (!owner)
|
if (!owner) {
|
||||||
|
put_device(&sysmmu->dev);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
INIT_LIST_HEAD(&owner->controllers);
|
INIT_LIST_HEAD(&owner->controllers);
|
||||||
mutex_init(&owner->rpm_lock);
|
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: */
|
/* 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))
|
if (hw_pass_through && domain_type_is_si(domain))
|
||||||
ret = intel_pasid_setup_pass_through(iommu, domain,
|
ret = intel_pasid_setup_pass_through(iommu, domain,
|
||||||
dev, PASID_RID2PASID);
|
dev, PASID_RID2PASID);
|
||||||
@ -2674,7 +2674,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
|
|||||||
else
|
else
|
||||||
ret = intel_pasid_setup_second_level(iommu, domain,
|
ret = intel_pasid_setup_second_level(iommu, domain,
|
||||||
dev, PASID_RID2PASID);
|
dev, PASID_RID2PASID);
|
||||||
spin_unlock(&iommu->lock);
|
spin_unlock_irqrestore(&iommu->lock, flags);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "Setup RID2PASID failed\n");
|
dev_err(dev, "Setup RID2PASID failed\n");
|
||||||
dmar_remove_one_dev_info(dev);
|
dmar_remove_one_dev_info(dev);
|
||||||
|
Loading…
Reference in New Issue
Block a user