ARM's arch_setup_dma_ops / arm_setup_iommu_dma_ops creates a custom IOMMU domain for DMA API usage, and continues to do so when the IOMMU driver doesn't explicitly request a DMA default domain type.
When, however, that DMA default domain is requested and the core owns the domain, we need to skip our own domain management. Add checks to arm_setup/teardown_iommu_dma_ops for these cases. In such a case IOVAs can be allocated from anywhere in the domain's geometry, so also add a check to ensure the device's dma-ranges cover it. Presently, this is the case for all platforms except some OMAP platforms with a non-zero dma-ranges base. Signed-off-by: Mikko Perttunen <[email protected]> --- arch/arm/mm/dma-mapping.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index f2d3e8ec3487..d6315baeddb9 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1761,13 +1761,33 @@ EXPORT_SYMBOL_GPL(arm_iommu_detach_device); static void arm_setup_iommu_dma_ops(struct device *dev) { - struct dma_iommu_mapping *mapping; + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); u64 dma_base = 0, size = 1ULL << 32; if (dev->dma_range_map) { dma_base = dma_range_map_min(dev->dma_range_map); size = dma_range_map_max(dev->dma_range_map) - dma_base; } + + /* + * An existing cookie means the core owns the domain. Only set the + * per-binding DMA ops. IOVAs are allocated from the whole aperture, + * so the device's dma-ranges must cover it. + */ + if (mapping) { + const struct iommu_domain_geometry *geo = + &mapping->domain->geometry; + + if (dma_base > geo->aperture_start || + dma_base + size < geo->aperture_end) { + dev_err(dev, "dma-ranges do not cover the IOMMU aperture\n"); + return; + } + + set_dma_ops(dev, &iommu_ops); + return; + } + mapping = arm_iommu_create_mapping(dev, dma_base, size); if (IS_ERR(mapping)) { pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n", @@ -1792,6 +1812,9 @@ static void arm_teardown_iommu_dma_ops(struct device *dev) if (!mapping) return; + if (!mapping->owns_domain) + return; + arm_iommu_detach_device(dev); arm_iommu_release_mapping(mapping); } -- 2.55.0
