aboutsummaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0008-arm64-do-not-set-dma-masks-that-device-connection-ca.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0008-arm64-do-not-set-dma-masks-that-device-connection-ca.patch')
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0008-arm64-do-not-set-dma-masks-that-device-connection-ca.patch132
1 files changed, 132 insertions, 0 deletions
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0008-arm64-do-not-set-dma-masks-that-device-connection-ca.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0008-arm64-do-not-set-dma-masks-that-device-connection-ca.patch
new file mode 100644
index 0000000..14612cd
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0008-arm64-do-not-set-dma-masks-that-device-connection-ca.patch
@@ -0,0 +1,132 @@
+From e3218ab51b0bf3f193a9f64e5c0dafe74e292ad2 Mon Sep 17 00:00:00 2001
+From: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
+Date: Fri, 6 Jan 2017 17:12:49 +0300
+Subject: [PATCH] arm64: do not set dma masks that device connection can't
+ handle
+
+It is possible that device is capable of 64-bit DMA addresses, and
+device driver tries to set wide DMA mask, but bridge or bus used to
+connect device to the system can't handle wide addresses.
+
+With swiotlb, memory above 4G still can be used by drivers for streaming
+DMA, but *dev->mask and dev->dma_coherent_mask must still keep values
+that hardware handles physically.
+
+This patch enforces that. Based on original version by
+Arnd Bergmann <arnd@arndb.de>, extended with coherent mask hadnling.
+
+Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
+CC: Arnd Bergmann <arnd@arndb.de>
+---
+ arch/arm64/Kconfig | 3 +++
+ arch/arm64/include/asm/device.h | 1 +
+ arch/arm64/mm/dma-mapping.c | 51 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 55 insertions(+)
+
+diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
+index 76747d92bc72..9513d2eb5c8a 100644
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -191,6 +191,9 @@ config NEED_DMA_MAP_STATE
+ config NEED_SG_DMA_LENGTH
+ def_bool y
+
++config ARCH_HAS_DMA_SET_COHERENT_MASK
++ def_bool y
++
+ config SMP
+ def_bool y
+
+diff --git a/arch/arm64/include/asm/device.h b/arch/arm64/include/asm/device.h
+index 243ef256b8c9..a57e7bb10e71 100644
+--- a/arch/arm64/include/asm/device.h
++++ b/arch/arm64/include/asm/device.h
+@@ -22,6 +22,7 @@ struct dev_archdata {
+ void *iommu; /* private IOMMU data */
+ #endif
+ bool dma_coherent;
++ u64 parent_dma_mask;
+ };
+
+ struct pdev_archdata {
+diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
+index 46a4157adc17..04b9bce96f1b 100644
+--- a/arch/arm64/mm/dma-mapping.c
++++ b/arch/arm64/mm/dma-mapping.c
+@@ -351,6 +351,30 @@ static int __swiotlb_dma_supported(struct device *hwdev, u64 mask)
+ return 1;
+ }
+
++static int __swiotlb_set_dma_mask(struct device *dev, u64 mask)
++{
++ /* device is not DMA capable */
++ if (!dev->dma_mask)
++ return -EIO;
++
++ /* mask is below swiotlb bounce buffer, so fail */
++ if (!swiotlb_dma_supported(dev, mask))
++ return -EIO;
++
++ /*
++ * because of the swiotlb, we can return success for
++ * larger masks, but need to ensure that bounce buffers
++ * are used above parent_dma_mask, so set that as
++ * the effective mask.
++ */
++ if (mask > dev->archdata.parent_dma_mask)
++ mask = dev->archdata.parent_dma_mask;
++
++ *dev->dma_mask = mask;
++
++ return 0;
++}
++
+ static struct dma_map_ops swiotlb_dma_ops = {
+ .alloc = __dma_alloc,
+ .free = __dma_free,
+@@ -366,8 +390,23 @@ static struct dma_map_ops swiotlb_dma_ops = {
+ .sync_sg_for_device = __swiotlb_sync_sg_for_device,
+ .dma_supported = __swiotlb_dma_supported,
+ .mapping_error = swiotlb_dma_mapping_error,
++ .set_dma_mask = __swiotlb_set_dma_mask,
+ };
+
++int dma_set_coherent_mask(struct device *dev, u64 mask)
++{
++ if (!dma_supported(dev, mask))
++ return -EIO;
++
++ if (get_dma_ops(dev) == &swiotlb_dma_ops &&
++ mask > dev->archdata.parent_dma_mask)
++ mask = dev->archdata.parent_dma_mask;
++
++ dev->coherent_dma_mask = mask;
++ return 0;
++}
++EXPORT_SYMBOL(dma_set_coherent_mask);
++
+ static int __init atomic_pool_init(void)
+ {
+ pgprot_t prot = __pgprot(PROT_NORMAL_NC);
+@@ -971,6 +1010,18 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
+ if (!dev->archdata.dma_ops)
+ dev->archdata.dma_ops = &swiotlb_dma_ops;
+
++ /*
++ * we don't yet support buses that have a non-zero mapping.
++ * Let's hope we won't need it
++ */
++ WARN_ON(dma_base != 0);
++
++ /*
++ * Whatever the parent bus can set. A device must not set
++ * a DMA mask larger than this.
++ */
++ dev->archdata.parent_dma_mask = size - 1;
++
+ dev->archdata.dma_coherent = coherent;
+ __iommu_setup_dma_ops(dev, dma_base, size, iommu);
+ }
+--
+2.11.0
+