iommu/dma: Centralise iommu_setup_dma_ops()
It's somewhat hard to see, but arm64's arch_setup_dma_ops() should only ever call iommu_setup_dma_ops() after a successful iommu_probe_device(), which means there should be no harm in achieving the same order of operations by running it off the back of iommu_probe_device() itself. This then puts it in line with the x86 and s390 .probe_finalize bodges, letting us pull it all into the main flow properly. As a bonus this lets us fold in and de-scope the PCI workaround setup as well. At this point we can also then pull the call up inside the group mutex, and avoid having to think about whether iommu_group_store_type() could theoretically race and free the domain if iommu_setup_dma_ops() ran just *before* iommu_device_use_default_domain() claims it... Furthermore we replace one .probe_finalize call completely, since the only remaining implementations are now one which only needs to run once for the initial boot-time probe, and two which themselves render that path unreachable. This leaves us a big step closer to realistically being able to unpick the variety of different things that iommu_setup_dma_ops() has been muddling together, and further streamline iommu-dma into core API flows in future. Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> # For Intel IOMMU Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Tested-by: Hanjun Guo <guohanjun@huawei.com> Signed-off-by: Robin Murphy <robin.murphy@arm.com> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Link: https://lore.kernel.org/r/bebea331c1d688b34d9862eefd5ede47503961b8.1713523152.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
ad4750b07d
commit
b67483b3c4
9 changed files with 19 additions and 73 deletions
|
@ -58,8 +58,6 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
|
||||||
ARCH_DMA_MINALIGN, cls);
|
ARCH_DMA_MINALIGN, cls);
|
||||||
|
|
||||||
dev->dma_coherent = coherent;
|
dev->dma_coherent = coherent;
|
||||||
if (device_iommu_mapped(dev))
|
|
||||||
iommu_setup_dma_ops(dev, dma_base, dma_base + size - 1);
|
|
||||||
|
|
||||||
xen_setup_dma_ops(dev);
|
xen_setup_dma_ops(dev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2175,13 +2175,6 @@ static struct iommu_device *amd_iommu_probe_device(struct device *dev)
|
||||||
return iommu_dev;
|
return iommu_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void amd_iommu_probe_finalize(struct device *dev)
|
|
||||||
{
|
|
||||||
/* Domains are initialized for this device - have a look what we ended up with */
|
|
||||||
set_dma_ops(dev, NULL);
|
|
||||||
iommu_setup_dma_ops(dev, 0, U64_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void amd_iommu_release_device(struct device *dev)
|
static void amd_iommu_release_device(struct device *dev)
|
||||||
{
|
{
|
||||||
struct amd_iommu *iommu;
|
struct amd_iommu *iommu;
|
||||||
|
@ -2784,7 +2777,6 @@ const struct iommu_ops amd_iommu_ops = {
|
||||||
.domain_alloc_user = amd_iommu_domain_alloc_user,
|
.domain_alloc_user = amd_iommu_domain_alloc_user,
|
||||||
.probe_device = amd_iommu_probe_device,
|
.probe_device = amd_iommu_probe_device,
|
||||||
.release_device = amd_iommu_release_device,
|
.release_device = amd_iommu_release_device,
|
||||||
.probe_finalize = amd_iommu_probe_finalize,
|
|
||||||
.device_group = amd_iommu_device_group,
|
.device_group = amd_iommu_device_group,
|
||||||
.get_resv_regions = amd_iommu_get_resv_regions,
|
.get_resv_regions = amd_iommu_get_resv_regions,
|
||||||
.is_attach_deferred = amd_iommu_is_attach_deferred,
|
.is_attach_deferred = amd_iommu_is_attach_deferred,
|
||||||
|
|
|
@ -1741,25 +1741,20 @@ static const struct dma_map_ops iommu_dma_ops = {
|
||||||
.max_mapping_size = iommu_dma_max_mapping_size,
|
.max_mapping_size = iommu_dma_max_mapping_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
void iommu_setup_dma_ops(struct device *dev)
|
||||||
* The IOMMU core code allocates the default DMA domain, which the underlying
|
|
||||||
* IOMMU driver needs to support via the dma-iommu layer.
|
|
||||||
*/
|
|
||||||
void iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 dma_limit)
|
|
||||||
{
|
{
|
||||||
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
|
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
|
||||||
|
|
||||||
if (!domain)
|
if (dev_is_pci(dev))
|
||||||
goto out_err;
|
dev->iommu->pci_32bit_workaround = !iommu_dma_forcedac;
|
||||||
|
|
||||||
/*
|
|
||||||
* The IOMMU core code allocates the default DMA domain, which the
|
|
||||||
* underlying IOMMU driver needs to support via the dma-iommu layer.
|
|
||||||
*/
|
|
||||||
if (iommu_is_dma_domain(domain)) {
|
if (iommu_is_dma_domain(domain)) {
|
||||||
if (iommu_dma_init_domain(domain, dev))
|
if (iommu_dma_init_domain(domain, dev))
|
||||||
goto out_err;
|
goto out_err;
|
||||||
dev->dma_ops = &iommu_dma_ops;
|
dev->dma_ops = &iommu_dma_ops;
|
||||||
|
} else if (dev->dma_ops == &iommu_dma_ops) {
|
||||||
|
/* Clean up if we've switched *from* a DMA domain */
|
||||||
|
dev->dma_ops = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -1767,7 +1762,6 @@ out_err:
|
||||||
pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
|
pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
|
||||||
dev_name(dev));
|
dev_name(dev));
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(iommu_setup_dma_ops);
|
|
||||||
|
|
||||||
static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
|
static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
|
||||||
phys_addr_t msi_addr, struct iommu_domain *domain)
|
phys_addr_t msi_addr, struct iommu_domain *domain)
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
#ifdef CONFIG_IOMMU_DMA
|
#ifdef CONFIG_IOMMU_DMA
|
||||||
|
|
||||||
|
void iommu_setup_dma_ops(struct device *dev);
|
||||||
|
|
||||||
int iommu_get_dma_cookie(struct iommu_domain *domain);
|
int iommu_get_dma_cookie(struct iommu_domain *domain);
|
||||||
void iommu_put_dma_cookie(struct iommu_domain *domain);
|
void iommu_put_dma_cookie(struct iommu_domain *domain);
|
||||||
|
|
||||||
|
@ -17,13 +19,13 @@ int iommu_dma_init_fq(struct iommu_domain *domain);
|
||||||
void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list);
|
void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list);
|
||||||
|
|
||||||
extern bool iommu_dma_forcedac;
|
extern bool iommu_dma_forcedac;
|
||||||
static inline void iommu_dma_set_pci_32bit_workaround(struct device *dev)
|
|
||||||
{
|
|
||||||
dev->iommu->pci_32bit_workaround = !iommu_dma_forcedac;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* CONFIG_IOMMU_DMA */
|
#else /* CONFIG_IOMMU_DMA */
|
||||||
|
|
||||||
|
static inline void iommu_setup_dma_ops(struct device *dev)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static inline int iommu_dma_init_fq(struct iommu_domain *domain)
|
static inline int iommu_dma_init_fq(struct iommu_domain *domain)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -42,9 +44,5 @@ static inline void iommu_dma_get_resv_regions(struct device *dev, struct list_he
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void iommu_dma_set_pci_32bit_workaround(struct device *dev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* CONFIG_IOMMU_DMA */
|
#endif /* CONFIG_IOMMU_DMA */
|
||||||
#endif /* __DMA_IOMMU_H */
|
#endif /* __DMA_IOMMU_H */
|
||||||
|
|
|
@ -4349,12 +4349,6 @@ static void intel_iommu_release_device(struct device *dev)
|
||||||
set_dma_ops(dev, NULL);
|
set_dma_ops(dev, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void intel_iommu_probe_finalize(struct device *dev)
|
|
||||||
{
|
|
||||||
set_dma_ops(dev, NULL);
|
|
||||||
iommu_setup_dma_ops(dev, 0, U64_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void intel_iommu_get_resv_regions(struct device *device,
|
static void intel_iommu_get_resv_regions(struct device *device,
|
||||||
struct list_head *head)
|
struct list_head *head)
|
||||||
{
|
{
|
||||||
|
@ -4834,7 +4828,6 @@ const struct iommu_ops intel_iommu_ops = {
|
||||||
.domain_alloc = intel_iommu_domain_alloc,
|
.domain_alloc = intel_iommu_domain_alloc,
|
||||||
.domain_alloc_user = intel_iommu_domain_alloc_user,
|
.domain_alloc_user = intel_iommu_domain_alloc_user,
|
||||||
.probe_device = intel_iommu_probe_device,
|
.probe_device = intel_iommu_probe_device,
|
||||||
.probe_finalize = intel_iommu_probe_finalize,
|
|
||||||
.release_device = intel_iommu_release_device,
|
.release_device = intel_iommu_release_device,
|
||||||
.get_resv_regions = intel_iommu_get_resv_regions,
|
.get_resv_regions = intel_iommu_get_resv_regions,
|
||||||
.device_group = intel_iommu_device_group,
|
.device_group = intel_iommu_device_group,
|
||||||
|
|
|
@ -581,10 +581,11 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
|
||||||
if (list_empty(&group->entry))
|
if (list_empty(&group->entry))
|
||||||
list_add_tail(&group->entry, group_list);
|
list_add_tail(&group->entry, group_list);
|
||||||
}
|
}
|
||||||
mutex_unlock(&group->mutex);
|
|
||||||
|
|
||||||
if (dev_is_pci(dev))
|
if (group->default_domain)
|
||||||
iommu_dma_set_pci_32bit_workaround(dev);
|
iommu_setup_dma_ops(dev);
|
||||||
|
|
||||||
|
mutex_unlock(&group->mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1828,6 +1829,8 @@ int bus_iommu_probe(const struct bus_type *bus)
|
||||||
mutex_unlock(&group->mutex);
|
mutex_unlock(&group->mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
for_each_group_device(group, gdev)
|
||||||
|
iommu_setup_dma_ops(gdev->dev);
|
||||||
mutex_unlock(&group->mutex);
|
mutex_unlock(&group->mutex);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3066,18 +3069,9 @@ static ssize_t iommu_group_store_type(struct iommu_group *group,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
/*
|
|
||||||
* Release the mutex here because ops->probe_finalize() call-back of
|
|
||||||
* some vendor IOMMU drivers calls arm_iommu_attach_device() which
|
|
||||||
* in-turn might call back into IOMMU core code, where it tries to take
|
|
||||||
* group->mutex, resulting in a deadlock.
|
|
||||||
*/
|
|
||||||
mutex_unlock(&group->mutex);
|
|
||||||
|
|
||||||
/* Make sure dma_ops is appropriatley set */
|
/* Make sure dma_ops is appropriatley set */
|
||||||
for_each_group_device(group, gdev)
|
for_each_group_device(group, gdev)
|
||||||
iommu_group_do_probe_finalize(gdev->dev);
|
iommu_setup_dma_ops(gdev->dev);
|
||||||
return count;
|
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&group->mutex);
|
mutex_unlock(&group->mutex);
|
||||||
|
|
|
@ -695,11 +695,6 @@ static size_t s390_iommu_unmap_pages(struct iommu_domain *domain,
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s390_iommu_probe_finalize(struct device *dev)
|
|
||||||
{
|
|
||||||
iommu_setup_dma_ops(dev, 0, U64_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct zpci_iommu_ctrs *zpci_get_iommu_ctrs(struct zpci_dev *zdev)
|
struct zpci_iommu_ctrs *zpci_get_iommu_ctrs(struct zpci_dev *zdev)
|
||||||
{
|
{
|
||||||
if (!zdev || !zdev->s390_domain)
|
if (!zdev || !zdev->s390_domain)
|
||||||
|
@ -785,7 +780,6 @@ static const struct iommu_ops s390_iommu_ops = {
|
||||||
.capable = s390_iommu_capable,
|
.capable = s390_iommu_capable,
|
||||||
.domain_alloc_paging = s390_domain_alloc_paging,
|
.domain_alloc_paging = s390_domain_alloc_paging,
|
||||||
.probe_device = s390_iommu_probe_device,
|
.probe_device = s390_iommu_probe_device,
|
||||||
.probe_finalize = s390_iommu_probe_finalize,
|
|
||||||
.release_device = s390_iommu_release_device,
|
.release_device = s390_iommu_release_device,
|
||||||
.device_group = generic_device_group,
|
.device_group = generic_device_group,
|
||||||
.pgsize_bitmap = SZ_4K,
|
.pgsize_bitmap = SZ_4K,
|
||||||
|
|
|
@ -1025,15 +1025,6 @@ err_free_dev:
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void viommu_probe_finalize(struct device *dev)
|
|
||||||
{
|
|
||||||
#ifndef CONFIG_ARCH_HAS_SETUP_DMA_OPS
|
|
||||||
/* First clear the DMA ops in case we're switching from a DMA domain */
|
|
||||||
set_dma_ops(dev, NULL);
|
|
||||||
iommu_setup_dma_ops(dev, 0, U64_MAX);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void viommu_release_device(struct device *dev)
|
static void viommu_release_device(struct device *dev)
|
||||||
{
|
{
|
||||||
struct viommu_endpoint *vdev = dev_iommu_priv_get(dev);
|
struct viommu_endpoint *vdev = dev_iommu_priv_get(dev);
|
||||||
|
@ -1073,7 +1064,6 @@ static struct iommu_ops viommu_ops = {
|
||||||
.capable = viommu_capable,
|
.capable = viommu_capable,
|
||||||
.domain_alloc = viommu_domain_alloc,
|
.domain_alloc = viommu_domain_alloc,
|
||||||
.probe_device = viommu_probe_device,
|
.probe_device = viommu_probe_device,
|
||||||
.probe_finalize = viommu_probe_finalize,
|
|
||||||
.release_device = viommu_release_device,
|
.release_device = viommu_release_device,
|
||||||
.device_group = viommu_device_group,
|
.device_group = viommu_device_group,
|
||||||
.get_resv_regions = viommu_get_resv_regions,
|
.get_resv_regions = viommu_get_resv_regions,
|
||||||
|
|
|
@ -1446,9 +1446,6 @@ static inline void iommu_debugfs_setup(void) {}
|
||||||
#ifdef CONFIG_IOMMU_DMA
|
#ifdef CONFIG_IOMMU_DMA
|
||||||
#include <linux/msi.h>
|
#include <linux/msi.h>
|
||||||
|
|
||||||
/* Setup call for arch DMA mapping code */
|
|
||||||
void iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 dma_limit);
|
|
||||||
|
|
||||||
int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base);
|
int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base);
|
||||||
|
|
||||||
int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr);
|
int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr);
|
||||||
|
@ -1459,10 +1456,6 @@ void iommu_dma_compose_msi_msg(struct msi_desc *desc, struct msi_msg *msg);
|
||||||
struct msi_desc;
|
struct msi_desc;
|
||||||
struct msi_msg;
|
struct msi_msg;
|
||||||
|
|
||||||
static inline void iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 dma_limit)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base)
|
static inline int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base)
|
||||||
{
|
{
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
Loading…
Add table
Reference in a new issue