--- v12
+++ v7
@@ -1,71 +1,123 @@
-Add a new function, swiotlb_release_slots, to make the code reusable for
-supporting different bounce buffer pools.
+Regardless of swiotlb setting, the restricted DMA pool is preferred if
+available.
+
+The restricted DMA pools provide a basic level of protection against the
+DMA overwriting buffer contents at unexpected times. However, to protect
+against general data leakage and system memory corruption, the system
+needs to provide a way to lock down the memory access, e.g., MPU.
+
+Note that is_dev_swiotlb_force doesn't check if
+swiotlb_force == SWIOTLB_FORCE. Otherwise the memory allocation behavior
+with default swiotlb will be changed by the following patche
+("dma-direct: Allocate memory from restricted DMA pool if available").
Signed-off-by: Claire Chang <tientzu@chromium.org>
-Reviewed-by: Christoph Hellwig <hch@lst.de>
---
- kernel/dma/swiotlb.c | 35 ++++++++++++++++++++---------------
- 1 file changed, 20 insertions(+), 15 deletions(-)
+ include/linux/swiotlb.h | 13 +++++++++++++
+ kernel/dma/direct.c | 3 ++-
+ kernel/dma/direct.h | 3 ++-
+ kernel/dma/swiotlb.c | 8 ++++----
+ 4 files changed, 21 insertions(+), 6 deletions(-)
+diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
+index c530c976d18b..0c5a18d9cf89 100644
+--- a/include/linux/swiotlb.h
++++ b/include/linux/swiotlb.h
+@@ -120,6 +120,15 @@ static inline bool is_swiotlb_buffer(struct device *dev, phys_addr_t paddr)
+ return mem && paddr >= mem->start && paddr < mem->end;
+ }
+
++static inline bool is_dev_swiotlb_force(struct device *dev)
++{
++#ifdef CONFIG_DMA_RESTRICTED_POOL
++ if (dev->dma_io_tlb_mem)
++ return true;
++#endif /* CONFIG_DMA_RESTRICTED_POOL */
++ return false;
++}
++
+ void __init swiotlb_exit(void);
+ unsigned int swiotlb_max_segment(void);
+ size_t swiotlb_max_mapping_size(struct device *dev);
+@@ -131,6 +140,10 @@ static inline bool is_swiotlb_buffer(struct device *dev, phys_addr_t paddr)
+ {
+ return false;
+ }
++static inline bool is_dev_swiotlb_force(struct device *dev)
++{
++ return false;
++}
+ static inline void swiotlb_exit(void)
+ {
+ }
+diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
+index 7a88c34d0867..078f7087e466 100644
+--- a/kernel/dma/direct.c
++++ b/kernel/dma/direct.c
+@@ -496,7 +496,8 @@ size_t dma_direct_max_mapping_size(struct device *dev)
+ {
+ /* If SWIOTLB is active, use its maximum mapping size */
+ if (is_swiotlb_active(dev) &&
+- (dma_addressing_limited(dev) || swiotlb_force == SWIOTLB_FORCE))
++ (dma_addressing_limited(dev) || swiotlb_force == SWIOTLB_FORCE ||
++ is_dev_swiotlb_force(dev)))
+ return swiotlb_max_mapping_size(dev);
+ return SIZE_MAX;
+ }
+diff --git a/kernel/dma/direct.h b/kernel/dma/direct.h
+index 13e9e7158d94..f94813674e23 100644
+--- a/kernel/dma/direct.h
++++ b/kernel/dma/direct.h
+@@ -87,7 +87,8 @@ static inline dma_addr_t dma_direct_map_page(struct device *dev,
+ phys_addr_t phys = page_to_phys(page) + offset;
+ dma_addr_t dma_addr = phys_to_dma(dev, phys);
+
+- if (unlikely(swiotlb_force == SWIOTLB_FORCE))
++ if (unlikely(swiotlb_force == SWIOTLB_FORCE) ||
++ is_dev_swiotlb_force(dev))
+ return swiotlb_map(dev, phys, size, dir, attrs);
+
+ if (unlikely(!dma_capable(dev, dma_addr, size, true))) {
diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
-index b59e689aa79d..688c6e0c43ff 100644
+index 68e7633f11fe..95f482c4408c 100644
--- a/kernel/dma/swiotlb.c
+++ b/kernel/dma/swiotlb.c
-@@ -555,27 +555,15 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr,
- return tlb_addr;
- }
-
--/*
-- * tlb_addr is the physical address of the bounce buffer to unmap.
-- */
--void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
-- size_t mapping_size, enum dma_data_direction dir,
-- unsigned long attrs)
-+static void swiotlb_release_slots(struct device *dev, phys_addr_t tlb_addr)
+@@ -347,7 +347,7 @@ void __init swiotlb_exit(void)
+ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size,
+ enum dma_data_direction dir)
{
-- struct io_tlb_mem *mem = hwdev->dma_io_tlb_mem;
-+ struct io_tlb_mem *mem = dev->dma_io_tlb_mem;
+- struct io_tlb_mem *mem = io_tlb_default_mem;
++ struct io_tlb_mem *mem = get_io_tlb_mem(dev);
+ int index = (tlb_addr - mem->start) >> IO_TLB_SHIFT;
+ phys_addr_t orig_addr = mem->slots[index].orig_addr;
+ size_t alloc_size = mem->slots[index].alloc_size;
+@@ -429,7 +429,7 @@ static unsigned int wrap_index(struct io_tlb_mem *mem, unsigned int index)
+ static int find_slots(struct device *dev, phys_addr_t orig_addr,
+ size_t alloc_size)
+ {
+- struct io_tlb_mem *mem = io_tlb_default_mem;
++ struct io_tlb_mem *mem = get_io_tlb_mem(dev);
+ unsigned long boundary_mask = dma_get_seg_boundary(dev);
+ dma_addr_t tbl_dma_addr =
+ phys_to_dma_unencrypted(dev, mem->start) & boundary_mask;
+@@ -506,7 +506,7 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr,
+ size_t mapping_size, size_t alloc_size,
+ enum dma_data_direction dir, unsigned long attrs)
+ {
+- struct io_tlb_mem *mem = io_tlb_default_mem;
++ struct io_tlb_mem *mem = get_io_tlb_mem(dev);
+ unsigned int offset = swiotlb_align_offset(dev, orig_addr);
+ unsigned int i;
+ int index;
+@@ -557,7 +557,7 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
+ size_t mapping_size, enum dma_data_direction dir,
+ unsigned long attrs)
+ {
+- struct io_tlb_mem *mem = io_tlb_default_mem;
++ struct io_tlb_mem *mem = get_io_tlb_mem(hwdev);
unsigned long flags;
-- unsigned int offset = swiotlb_align_offset(hwdev, tlb_addr);
-+ unsigned int offset = swiotlb_align_offset(dev, tlb_addr);
+ unsigned int offset = swiotlb_align_offset(hwdev, tlb_addr);
int index = (tlb_addr - offset - mem->start) >> IO_TLB_SHIFT;
- int nslots = nr_slots(mem->slots[index].alloc_size + offset);
- int count, i;
-
-- /*
-- * First, sync the memory before unmapping the entry
-- */
-- if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
-- (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
-- swiotlb_bounce(hwdev, tlb_addr, mapping_size, DMA_FROM_DEVICE);
--
- /*
- * Return the buffer to the free list by setting the corresponding
- * entries to indicate the number of contiguous entries available.
-@@ -610,6 +598,23 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
- spin_unlock_irqrestore(&mem->lock, flags);
- }
-
-+/*
-+ * tlb_addr is the physical address of the bounce buffer to unmap.
-+ */
-+void swiotlb_tbl_unmap_single(struct device *dev, phys_addr_t tlb_addr,
-+ size_t mapping_size, enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ /*
-+ * First, sync the memory before unmapping the entry
-+ */
-+ if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
-+ (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
-+ swiotlb_bounce(dev, tlb_addr, mapping_size, DMA_FROM_DEVICE);
-+
-+ swiotlb_release_slots(dev, tlb_addr);
-+}
-+
- void swiotlb_sync_single_for_device(struct device *dev, phys_addr_t tlb_addr,
- size_t size, enum dma_data_direction dir)
- {
--
-2.32.0.272.g935e593368-goog
+2.31.1.751.gd2f1c929bd-goog