diff options
Diffstat (limited to 'arch/arm64/mm/dma-mapping.c')
-rw-r--r-- | arch/arm64/mm/dma-mapping.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index cab3574ab7d9..28d9199aaf8f 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -28,9 +28,14 @@ #include <linux/dma-contiguous.h> #include <linux/vmalloc.h> #include <linux/swiotlb.h> +#include <linux/of.h> #include <asm/cacheflush.h> +EXPORT_SYMBOL(__dma_map_area); +EXPORT_SYMBOL(__dma_unmap_area); +EXPORT_SYMBOL(__dma_flush_area); + static int swiotlb __ro_after_init; static pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot, @@ -359,6 +364,22 @@ static int __swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t addr) return 0; } +/* + * Some 64bit SoCs only support up to 32bit dma capability. + * Do quirk set here. + */ +static int __swiotlb_dma_supported_quirk(struct device *hwdev, u64 mask) +{ + if (mask > DMA_BIT_MASK(32)) { + pr_err("Can't support > 32 bit dma.\n"); + return 0; + } + + if (swiotlb) + return swiotlb_dma_supported(hwdev, mask); + return 1; +} + static struct dma_map_ops swiotlb_dma_ops = { .alloc = __dma_alloc, .free = __dma_free, @@ -961,6 +982,15 @@ void arch_teardown_dma_ops(struct device *dev) dev->archdata.dma_ops = NULL; } +static int iommu_dma_supported_quirk(struct device *dev, u64 mask) +{ + if (mask > DMA_BIT_MASK(32)) { + pr_err("Can't support > 32 bit dma.\n"); + return 0; + } + + return iommu_dma_supported(dev, mask); +} #else static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, @@ -972,9 +1002,24 @@ static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, const struct iommu_ops *iommu, bool coherent) { + u32 mask32; + struct device_node *np; + if (!dev->archdata.dma_ops) dev->archdata.dma_ops = &swiotlb_dma_ops; dev->archdata.dma_coherent = coherent; __iommu_setup_dma_ops(dev, dma_base, size, iommu); + + np = of_find_compatible_node(NULL, NULL, "dma-capability"); + if (np == NULL) + return; + if (of_property_read_u32(np, "only-dma-mask32", &mask32)) + mask32 = 0; + if (mask32) { + swiotlb_dma_ops.dma_supported = __swiotlb_dma_supported_quirk; +#ifdef CONFIG_IOMMU_DMA + iommu_dma_ops.dma_supported = iommu_dma_supported_quirk; +#endif + } } |