summaryrefslogtreecommitdiff
path: root/arch/arm64/mm
diff options
context:
space:
mode:
authorRichard Zhu <hongxing.zhu@nxp.com>2016-09-19 16:39:44 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:26:57 +0800
commit9e7f775e8a800c966b945da5ae407888232ae051 (patch)
tree4824698462db1208ead257daffcbb80d002ebed6 /arch/arm64/mm
parentd5b25b71c142449af7f4d18acac68a32f0dd5268 (diff)
MLK-15064-2 ARM64: DMA: limit the dma mask to be 32bit
Limit the dma mask to be 32bit, because that the imx8 doesn't have the 64bit dma capapbility although it is 64bit soc. Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com> Reviewed-by: Frank Li <frank.li@nxp.com>
Diffstat (limited to 'arch/arm64/mm')
-rw-r--r--arch/arm64/mm/dma-mapping.c45
1 files changed, 43 insertions, 2 deletions
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 358aa8cb1cc0..7015d3ed55c7 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -29,6 +29,7 @@
#include <linux/vmalloc.h>
#include <linux/swiotlb.h>
#include <linux/pci.h>
+#include <linux/of.h>
#include <asm/cacheflush.h>
@@ -373,7 +374,23 @@ static int __swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t addr)
return 0;
}
-static const struct dma_map_ops swiotlb_dma_ops = {
+/*
+ * 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,
.mmap = __swiotlb_mmap,
@@ -857,7 +874,7 @@ static void __iommu_unmap_sg_attrs(struct device *dev,
iommu_dma_unmap_sg(dev, sgl, nelems, dir, attrs);
}
-static const struct dma_map_ops iommu_dma_ops = {
+static struct dma_map_ops iommu_dma_ops = {
.alloc = __iommu_alloc_attrs,
.free = __iommu_free_attrs,
.mmap = __iommu_mmap_attrs,
@@ -917,6 +934,15 @@ void arch_teardown_dma_ops(struct device *dev)
dev->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 1;
+}
#else
static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
@@ -928,6 +954,9 @@ 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->dma_ops)
dev->dma_ops = &swiotlb_dma_ops;
@@ -940,4 +969,16 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
dev->dma_ops = xen_dma_ops;
}
#endif
+
+ 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
+ }
}