CoCo shared memory may need to be allocated and transitioned in units larger than the requested object. Before this change, users handled the resulting capacity as follows:
User Rounded capacity reused dma-buf system heap no DMA-direct no regular GIC tables no small GIC ITTs yes, through a gen_pool early SWIOTLB pool no late SWIOTLB pool yes persistent dynamic SWIOTLB no transient dynamic SWIOTLB no, one mapping only atomic DMA pools yes, through a gen_pool restricted SWIOTLB pool no additional padding
Improve the early and persistent dynamic SWIOTLB pools. They already own and transition backing rounded to the shared granule size, and SWIOTLB is itself a suballocator. Advertise the rounded extent as slots, size the slot metadata to match. This makes the extra capacity available without reserving more backing memory.
Keep transient dynamic pools unchanged. A transient pool belongs to one DMA mapping and is destroyed when that mapping is unmapped, so its spare backing cannot satisfy a later request without changing the lifetime model.
Do not attempt the same optimization for dma-buf, DMA-direct or regular GIC objects. Those allocations have independent caller-visible sizes and lifetimes. Reusing their padding requires a shared-granule suballocator with reference counting, per-object mappings and accounting.
Note: For the current 64 KiB CCA shared granule size, SWIOTLB pool sizes are already multiples of the 256 KiB IO_TLB segment size. Consequently, the rounding does not change any runtime values on current CCA systems. It instead makes the code express the intended invariant that pool metadata describes the complete shared-granule-aligned backing allocation.
Signed-off-by: Aneesh Kumar K.V (Arm) aneesh.kumar@kernel.org --- kernel/dma/swiotlb.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index cb67105b8812..9577a8807b07 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -330,6 +330,14 @@ static inline unsigned long nr_slots(u64 val) return DIV_ROUND_UP(val, IO_TLB_SIZE); }
+static unsigned long swiotlb_align_nslabs(unsigned long nslabs) +{ + unsigned long granule_nslabs; + + granule_nslabs = cc_shared_granule_size() >> IO_TLB_SHIFT; + return ALIGN(nslabs, granule_nslabs); +} + static void swiotlb_mark_pool_used(struct io_tlb_pool *pool) { unsigned long i; @@ -435,11 +443,12 @@ static void add_mem_pool(struct io_tlb_mem *mem, struct io_tlb_pool *pool) }
static void __init *swiotlb_memblock_alloc(unsigned long nslabs, - unsigned int flags, + unsigned long *alloc_nslabs, unsigned int flags, int (*remap)(void *tlb, unsigned long nslabs)) { + unsigned long aligned_nslabs = swiotlb_align_nslabs(nslabs); + size_t bytes = aligned_nslabs << IO_TLB_SHIFT; void *tlb; - size_t bytes = ALIGN(nslabs << IO_TLB_SHIFT, cc_shared_granule_size());
/* * By default allocate the bounce buffer memory from low memory, but @@ -457,12 +466,13 @@ static void __init *swiotlb_memblock_alloc(unsigned long nslabs, return NULL; }
- if (remap && remap(tlb, nslabs) < 0) { + if (remap && remap(tlb, aligned_nslabs) < 0) { memblock_free(tlb, bytes); pr_warn("%s: Failed to remap %zu bytes\n", __func__, bytes); return NULL; }
+ *alloc_nslabs = aligned_nslabs; return tlb; }
@@ -475,6 +485,7 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags, { struct io_tlb_pool *mem = &io_tlb_default_mem.defpool; unsigned long nslabs; + unsigned long alloc_nslabs; unsigned int nareas; size_t alloc_size; void *tlb; @@ -499,13 +510,14 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags, swiotlb_adjust_nareas(num_possible_cpus());
nslabs = default_nslabs; - nareas = limit_nareas(default_nareas, nslabs); - while ((tlb = swiotlb_memblock_alloc(nslabs, flags, remap)) == NULL) { + while ((tlb = swiotlb_memblock_alloc(nslabs, &alloc_nslabs, flags, + remap)) == NULL) { if (nslabs <= IO_TLB_MIN_SLABS) return; nslabs = ALIGN(nslabs >> 1, IO_TLB_SEGSIZE); - nareas = limit_nareas(nareas, nslabs); } + nslabs = alloc_nslabs; + nareas = limit_nareas(default_nareas, nslabs);
if (default_nslabs != nslabs) { pr_info("SWIOTLB bounce buffer size adjusted %lu -> %lu slabs", @@ -871,6 +883,12 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev, tlb_size = nslabs << IO_TLB_SHIFT; }
+ /* Transient pools are tied to one mapping and cannot reuse padding. */ + if (mem->cc_shared && !dev) { + nslabs = swiotlb_align_nslabs(nslabs); + tlb_size = nslabs << IO_TLB_SHIFT; + } + slot_order = get_order(array_size(sizeof(*pool->slots), nslabs)); pool->slots = (struct io_tlb_slot *) __get_free_pages(gfp, slot_order);