[PATCH v2 8/9] dma-mapping: add persistent streaming mapping flag

David Stevens
2021-08-06T10:35:48Z

Add a DMA_ATTR_PERSISTENT_STREAMING flag which indicates that the
streaming mapping is long lived and that the caller will manage
coherency either through the dma_sync_* functions or via some other
use-case specific mechanism. This flag indicates to the platform that
it should optimize for more efficient syncing at the cost of more
expensive mapping and unmapping.

This flag is used to skip optional bounce buffers when
CONFIG_IOMMU_BOUNCE_BUFFERS is enabled. With respect to these bounce
buffers, in most cases the flag is an optimization. However, callers
which do not use the dma_sync_* calls to manage coherency must use this
flag to work properly when CONFIG_IOMMU_BOUNCE_BUFFERS is enabled.

Signed-off-by: David Stevens <stevensd@chromium.org>
---
drivers/iommu/io-bounce-buffers.c | 14 +++++++++++---
include/linux/dma-mapping.h | 11 +++++++++++
2 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/io-bounce-buffers.c b/drivers/iommu/io-bounce-buffers.c
index af8c2a51eeed..3a0071d5a9ea 100644
--- a/drivers/iommu/io-bounce-buffers.c
+++ b/drivers/iommu/io-bounce-buffers.c
@@ -409,8 +409,16 @@ static bool io_bounce_buffers_map_buffer(struct io_bounce_buffers *buffers,
return mapped >= info->size;
}

-static bool use_bounce_buffer(bool force_bounce, size_t size)
+static bool use_bounce_buffer(struct device *dev, unsigned long attrs,
+ bool force_bounce, size_t size)
{
+ if (attrs & DMA_ATTR_PERSISTENT_STREAMING) {
+ WARN_ONCE(force_bounce,
+ "Skipping bounce buffer for untrusted mapping %s\n",
+ dev_name(dev));
+ return false;
+ }
+
if (IS_ENABLED(CONFIG_IOMMU_BOUNCE_BUFFERS) &&
size <= always_bounce_limit)
return true;
@@ -429,7 +437,7 @@ bool io_bounce_buffers_map_page(struct io_bounce_buffers *buffers,
bool force_bounce = buffers->untrusted &&
iova_offset(buffers->iovad, offset | size);

- if (!use_bounce_buffer(force_bounce, size))
+ if (!use_bounce_buffer(dev, attrs, force_bounce, size))
return false;

*handle = DMA_MAPPING_ERROR;
@@ -476,7 +484,7 @@ bool io_bounce_buffers_map_sg(struct io_bounce_buffers *buffers,
buffers->iovad, iter->offset | iter->length);
}

- if (!use_bounce_buffer(force_bounce, size))
+ if (!use_bounce_buffer(dev, attrs, force_bounce, size))
return false;

*out_nents = 0;
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 183e7103a66d..5d318753bb79 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -61,6 +61,17 @@
*/
#define DMA_ATTR_PRIVILEGED (1UL << 9)

+/*
+ * DMA_ATTR_PERSISTENT_STREAMING: Indicates that the streaming mapping is long
+ * lived, so syncing performance should be prioritized over mapping/unmapping
+ * performance. Platform code will establish a mapping which only requires CPU
+ * cache synchronization.
+ *
+ * Callers that create long lived mappings and directly handle CPU cache
+ * management without calling using dma_sync_* functions must set this flag.
+ */
+#define DMA_ATTR_PERSISTENT_STREAMING (1UL << 10)
+
/*
* A dma_addr_t can hold any valid DMA or bus address for the platform. It can
* be given to a device to use as a DMA source or target. It is specific to a
--
2.32.0.605.g8dce9f2422-goog