#include <linux/vmalloc.h>
#include <linux/swiotlb.h>
#include <linux/pci.h>
+#include <linux/of.h>
#include <asm/cacheflush.h>
return 0;
}
-static const struct dma_map_ops arm64_swiotlb_dma_ops = {
+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 arm64_swiotlb_dma_ops = {
.alloc = __dma_alloc,
.free = __dma_free,
.mmap = __swiotlb_mmap,
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,
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,
#endif /* CONFIG_IOMMU_DMA */
+/*
+ * Some 64bit SoCs only support up to 32bit dma capability.
+ * Do quirk set here.
+ */
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 = &arm64_swiotlb_dma_ops;
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) {
+ arm64_swiotlb_dma_ops.dma_supported = __swiotlb_dma_supported_quirk;
+#ifdef CONFIG_IOMMU_DMA
+ iommu_dma_ops.dma_supported = iommu_dma_supported_quirk;
+#endif
+ }
}