summaryrefslogtreecommitdiff
path: root/arch/arm64/mm/dma-mapping.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/mm/dma-mapping.c')
-rw-r--r--arch/arm64/mm/dma-mapping.c45
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
+ }
}