// SPDX-License-Identifier: GPL-2.0-only /* * Dynamic DMA mapping support. * * This implementation is a fallback for platforms that do not support * I/O TLBs (aka DMA address translation hardware). * Copyright (C) 2000 Asit Mallick <Asit.K.Mallick@intel.com> * Copyright (C) 2000 Goutham Rao <goutham.rao@intel.com> * Copyright (C) 2000, 2003 Hewlett-Packard Co * David Mosberger-Tang <davidm@hpl.hp.com> * * 03/05/07 davidm Switch from PCI-DMA to generic device DMA API. * 00/12/13 davidm Rename to swiotlb.c and add mark_clean() to avoid * unnecessary i-cache flushing. * 04/07/.. ak Better overflow handling. Assorted fixes. * 05/09/10 linville Add support for syncing ranges, support syncing for * DMA_BIDIRECTIONAL mappings, miscellaneous cleanup. * 08/12/11 beckyb Add highmem support
*/
/* * Minimum IO TLB size to bother booting with. Systems with mainly * 64bit capable cards will only lightly use the swiotlb. If we can't * allocate a contiguous 1MB, we're probably in trouble anyway.
*/ #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
#define INVALID_PHYS_ADDR (~(phys_addr_t)0)
/** * struct io_tlb_slot - IO TLB slot descriptor * @orig_addr: The original address corresponding to a mapped entry. * @alloc_size: Size of the allocated buffer. * @list: The free list describing the number of free entries available * from each index. * @pad_slots: Number of preceding padding slots. Valid only in the first * allocated non-padding slot.
*/ struct io_tlb_slot {
phys_addr_t orig_addr;
size_t alloc_size; unsignedshort list; unsignedshort pad_slots;
};
/** * struct io_tlb_area - IO TLB memory area descriptor * * This is a single area with a single lock. * * @used: The number of used IO TLB block. * @index: The slot index to start searching in this area for next round. * @lock: The lock to protect the above data structures in the map and * unmap calls.
*/ struct io_tlb_area { unsignedlong used; unsignedint index;
spinlock_t lock;
};
/* * Round up number of slabs to the next power of 2. The last area is going * be smaller than the rest if default_nslabs is not power of two. * The number of slot in an area should be a multiple of IO_TLB_SEGSIZE, * otherwise a segment may span two or more areas. It conflicts with free * contiguous slots tracking: free slots are treated contiguous no matter * whether they cross an area boundary. * * Return true if default_nslabs is rounded up.
*/ staticbool round_up_default_nslabs(void)
{ if (!default_nareas) returnfalse;
/** * swiotlb_adjust_nareas() - adjust the number of areas and slots * @nareas: Desired number of areas. Zero is treated as 1. * * Adjust the default number of areas in a memory pool. * The default size of the memory pool may also change to meet minimum area * size requirements.
*/ staticvoid swiotlb_adjust_nareas(unsignedint nareas)
{ if (!nareas)
nareas = 1; elseif (!is_power_of_2(nareas))
nareas = roundup_pow_of_two(nareas);
default_nareas = nareas;
pr_info("area num %d.\n", nareas); if (round_up_default_nslabs())
pr_info("SWIOTLB bounce buffer size roundup to %luMB",
(default_nslabs << IO_TLB_SHIFT) >> 20);
}
/** * limit_nareas() - get the maximum number of areas for a given memory pool size * @nareas: Desired number of areas. * @nslots: Total number of slots in the memory pool. * * Limit the number of areas to the maximum possible number of areas in * a memory pool of the given size. * * Return: Maximum possible number of areas.
*/ staticunsignedint limit_nareas(unsignedint nareas, unsignedlong nslots)
{ if (nslots < nareas * IO_TLB_SEGSIZE) return nslots / IO_TLB_SEGSIZE; return nareas;
}
staticint __init
setup_io_tlb_npages(char *str)
{ if (isdigit(*str)) { /* avoid tail segment of size < IO_TLB_SEGSIZE */
default_nslabs =
ALIGN(simple_strtoul(str, &str, 0), IO_TLB_SEGSIZE);
} if (*str == ',')
++str; if (isdigit(*str))
swiotlb_adjust_nareas(simple_strtoul(str, &str, 0)); if (*str == ',')
++str; if (!strcmp(str, "force"))
swiotlb_force_bounce = true; elseif (!strcmp(str, "noforce"))
swiotlb_force_disable = true;
void __init swiotlb_adjust_size(unsignedlong size)
{ /* * If swiotlb parameter has not been specified, give a chance to * architectures such as those supporting memory encryption to * adjust/expand SWIOTLB size for their use.
*/ if (default_nslabs != IO_TLB_DEFAULT_SIZE >> IO_TLB_SHIFT) return;
/* * Early SWIOTLB allocation may be too early to allow an architecture to * perform the desired operations. This function allows the architecture to * call SWIOTLB when the operations are possible. It needs to be called * before the SWIOTLB memory is used.
*/ void __init swiotlb_update_mem_attributes(void)
{ struct io_tlb_pool *mem = &io_tlb_default_mem.defpool; unsignedlong bytes;
/* * By default allocate the bounce buffer memory from low memory, but * allow to pick a location everywhere for hypervisors with guest * memory encryption.
*/ if (flags & SWIOTLB_ANY)
tlb = memblock_alloc(bytes, PAGE_SIZE); else
tlb = memblock_alloc_low(bytes, PAGE_SIZE);
if (!tlb) {
pr_warn("%s: Failed to allocate %zu bytes tlb structure\n",
__func__, bytes); return NULL;
}
/* * Systems with larger DMA zones (those that don't support ISA) can * initialize the swiotlb later using the slab allocator if needed. * This should be just like above, but with some error catching.
*/ int swiotlb_init_late(size_t size, gfp_t gfp_mask, int (*remap)(void *tlb, unsignedlong nslabs))
{ struct io_tlb_pool *mem = &io_tlb_default_mem.defpool; unsignedlong nslabs = ALIGN(size >> IO_TLB_SHIFT, IO_TLB_SEGSIZE); unsignedint nareas; unsignedchar *vstart = NULL; unsignedint order, area_order; bool retried = false; int rc = 0;
/** * alloc_dma_pages() - allocate pages to be used for DMA * @gfp: GFP flags for the allocation. * @bytes: Size of the buffer. * @phys_limit: Maximum allowed physical address of the buffer. * * Allocate pages from the buddy allocator. If successful, make the allocated * pages decrypted that they can be used for DMA. * * Return: Decrypted pages, %NULL on allocation failure, or ERR_PTR(-EAGAIN) * if the allocated physical address was above @phys_limit.
*/ staticstruct page *alloc_dma_pages(gfp_t gfp, size_t bytes, u64 phys_limit)
{ unsignedint order = get_order(bytes); struct page *page;
phys_addr_t paddr; void *vaddr;
page = alloc_pages(gfp, order); if (!page) return NULL;
vaddr = phys_to_virt(paddr); if (set_memory_decrypted((unsignedlong)vaddr, PFN_UP(bytes))) goto error; return page;
error: /* Intentional leak if pages cannot be encrypted again. */ if (!set_memory_encrypted((unsignedlong)vaddr, PFN_UP(bytes)))
__free_pages(page, order); return NULL;
}
/** * swiotlb_alloc_tlb() - allocate a dynamic IO TLB buffer * @dev: Device for which a memory pool is allocated. * @bytes: Size of the buffer. * @phys_limit: Maximum allowed physical address of the buffer. * @gfp: GFP flags for the allocation. * * Return: Allocated pages, or %NULL on allocation failure.
*/ staticstruct page *swiotlb_alloc_tlb(struct device *dev, size_t bytes,
u64 phys_limit, gfp_t gfp)
{ struct page *page;
/* * Allocate from the atomic pools if memory is encrypted and * the allocation is atomic, because decrypting may block.
*/ if (!gfpflags_allow_blocking(gfp) && dev && force_dma_unencrypted(dev)) { void *vaddr;
if (!IS_ENABLED(CONFIG_DMA_COHERENT_POOL)) return NULL;
/** * swiotlb_free_tlb() - free a dynamically allocated IO TLB buffer * @vaddr: Virtual address of the buffer. * @bytes: Size of the buffer.
*/ staticvoid swiotlb_free_tlb(void *vaddr, size_t bytes)
{ if (IS_ENABLED(CONFIG_DMA_COHERENT_POOL) &&
dma_free_from_pool(NULL, vaddr, bytes)) return;
/* Intentional leak if pages cannot be encrypted again. */ if (!set_memory_encrypted((unsignedlong)vaddr, PFN_UP(bytes)))
__free_pages(virt_to_page(vaddr), get_order(bytes));
}
/** * swiotlb_alloc_pool() - allocate a new IO TLB memory pool * @dev: Device for which a memory pool is allocated. * @minslabs: Minimum number of slabs. * @nslabs: Desired (maximum) number of slabs. * @nareas: Number of areas. * @phys_limit: Maximum DMA buffer physical address. * @gfp: GFP flags for the allocations. * * Allocate and initialize a new IO TLB memory pool. The actual number of * slabs may be reduced if allocation of @nslabs fails. If even * @minslabs cannot be allocated, this function fails. * * Return: New memory pool, or %NULL on allocation failure.
*/ staticstruct io_tlb_pool *swiotlb_alloc_pool(struct device *dev, unsignedlong minslabs, unsignedlong nslabs, unsignedint nareas, u64 phys_limit, gfp_t gfp)
{ struct io_tlb_pool *pool; unsignedint slot_order; struct page *tlb;
size_t pool_size;
size_t tlb_size;
pool = swiotlb_alloc_pool(NULL, IO_TLB_MIN_SLABS, default_nslabs,
default_nareas, mem->phys_limit, GFP_KERNEL); if (!pool) {
pr_warn_ratelimited("Failed to allocate new pool"); return;
}
add_mem_pool(mem, pool);
}
/** * swiotlb_dyn_free() - RCU callback to free a memory pool * @rcu: RCU head in the corresponding struct io_tlb_pool.
*/ staticvoid swiotlb_dyn_free(struct rcu_head *rcu)
{ struct io_tlb_pool *pool = container_of(rcu, struct io_tlb_pool, rcu);
size_t slots_size = array_size(sizeof(*pool->slots), pool->nslabs);
size_t tlb_size = pool->end - pool->start;
/** * __swiotlb_find_pool() - find the IO TLB pool for a physical address * @dev: Device which has mapped the DMA buffer. * @paddr: Physical address within the DMA buffer. * * Find the IO TLB memory pool descriptor which contains the given physical * address, if any. This function is for use only when the dev is known to * be using swiotlb. Use swiotlb_find_pool() for the more general case * when this condition is not met. * * Return: Memory pool which contains @paddr, or %NULL if none.
*/ struct io_tlb_pool *__swiotlb_find_pool(struct device *dev, phys_addr_t paddr)
{ struct io_tlb_mem *mem = dev->dma_io_tlb_mem; struct io_tlb_pool *pool;
/** * swiotlb_del_pool() - remove an IO TLB pool from a device * @dev: Owning device. * @pool: Memory pool to be removed.
*/ staticvoid swiotlb_del_pool(struct device *dev, struct io_tlb_pool *pool)
{ unsignedlong flags;
/** * swiotlb_align_offset() - Get required offset into an IO TLB allocation. * @dev: Owning device. * @align_mask: Allocation alignment mask. * @addr: DMA address. * * Return the minimum offset from the start of an IO TLB allocation which is * required for a given buffer address and allocation alignment to keep the * device happy. * * First, the address bits covered by min_align_mask must be identical in the * original address and the bounce buffer address. High bits are preserved by * choosing a suitable IO TLB slot, but bits below IO_TLB_SHIFT require extra * padding bytes before the bounce buffer. * * Second, @align_mask specifies which bits of the first allocated slot must * be zero. This may require allocating additional padding slots, and then the * offset (in bytes) from the first such padding slot is returned.
*/ staticunsignedint swiotlb_align_offset(struct device *dev, unsignedint align_mask, u64 addr)
{ return addr & dma_get_min_align_mask(dev) &
(align_mask | (IO_TLB_SIZE - 1));
}
/* * Bounce: copy the swiotlb buffer from or back to the original dma location
*/ staticvoid swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size, enum dma_data_direction dir, struct io_tlb_pool *mem)
{ 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; unsignedlong pfn = PFN_DOWN(orig_addr); unsignedchar *vaddr = mem->vaddr + tlb_addr - mem->start; int tlb_offset;
if (orig_addr == INVALID_PHYS_ADDR) return;
/* * It's valid for tlb_offset to be negative. This can happen when the * "offset" returned by swiotlb_align_offset() is non-zero, and the * tlb_addr is pointing within the first "offset" bytes of the second * or subsequent slots of the allocated swiotlb area. While it's not * valid for tlb_addr to be pointing within the first "offset" bytes * of the first slot, there's no way to check for such an error since * this function can't distinguish the first slot from the second and * subsequent slots.
*/
tlb_offset = (tlb_addr & (IO_TLB_SIZE - 1)) -
swiotlb_align_offset(dev, 0, orig_addr);
/* * Track the total used slots with a global atomic value in order to have * correct information to determine the high water mark. The mem_used() * function gives imprecise results because there's no locking across * multiple areas.
*/ #ifdef CONFIG_DEBUG_FS staticvoid inc_used_and_hiwater(struct io_tlb_mem *mem, unsignedint nslots)
{ unsignedlong old_hiwater, new_used;
new_used = atomic_long_add_return(nslots, &mem->total_used);
old_hiwater = atomic_long_read(&mem->used_hiwater); do { if (new_used <= old_hiwater) break;
} while (!atomic_long_try_cmpxchg(&mem->used_hiwater,
&old_hiwater, new_used));
}
/** * swiotlb_search_pool_area() - search one memory area in one pool * @dev: Device which maps the buffer. * @pool: Memory pool to be searched. * @area_index: Index of the IO TLB memory area to be searched. * @orig_addr: Original (non-bounced) IO buffer address. * @alloc_size: Total requested size of the bounce buffer, * including initial alignment padding. * @alloc_align_mask: Required alignment of the allocated buffer. * * Find a suitable sequence of IO TLB entries for the request and allocate * a buffer from the given IO TLB memory area. * This function takes care of locking. * * Return: Index of the first allocated slot, or -1 on error.
*/ staticint swiotlb_search_pool_area(struct device *dev, struct io_tlb_pool *pool, int area_index, phys_addr_t orig_addr, size_t alloc_size, unsignedint alloc_align_mask)
{ struct io_tlb_area *area = pool->areas + area_index; unsignedlong boundary_mask = dma_get_seg_boundary(dev);
dma_addr_t tbl_dma_addr =
phys_to_dma_unencrypted(dev, pool->start) & boundary_mask; unsignedlong max_slots = get_max_slots(boundary_mask); unsignedint iotlb_align_mask = dma_get_min_align_mask(dev); unsignedint nslots = nr_slots(alloc_size), stride; unsignedint offset = swiotlb_align_offset(dev, 0, orig_addr); unsignedint index, slots_checked, count = 0, i; unsignedlong flags; unsignedint slot_base; unsignedint slot_index;
/* * Historically, swiotlb allocations >= PAGE_SIZE were guaranteed to be * page-aligned in the absence of any other alignment requirements. * 'alloc_align_mask' was later introduced to specify the alignment * explicitly, however this is passed as zero for streaming mappings * and so we preserve the old behaviour there in case any drivers are * relying on it.
*/ if (!alloc_align_mask && !iotlb_align_mask && alloc_size >= PAGE_SIZE)
alloc_align_mask = PAGE_SIZE - 1;
/* * Ensure that the allocation is at least slot-aligned and update * 'iotlb_align_mask' to ignore bits that will be preserved when * offsetting into the allocation.
*/
alloc_align_mask |= (IO_TLB_SIZE - 1);
iotlb_align_mask &= ~alloc_align_mask;
/* * For mappings with an alignment requirement don't bother looping to * unaligned slots once we found an aligned one.
*/
stride = get_max_slots(max(alloc_align_mask, iotlb_align_mask));
spin_lock_irqsave(&area->lock, flags); if (unlikely(nslots > pool->area_nslabs - area->used)) goto not_found;
slot_base = area_index * pool->area_nslabs;
index = area->index;
found: /* * If we find a slot that indicates we have 'nslots' number of * contiguous buffers, we allocate the buffers from that slot onwards * and set the list of free entries to '0' indicating unavailable.
*/ for (i = slot_index; i < slot_index + nslots; i++) {
pool->slots[i].list = 0;
pool->slots[i].alloc_size = alloc_size - (offset +
((i - slot_index) << IO_TLB_SHIFT));
} for (i = slot_index - 1;
io_tlb_offset(i) != IO_TLB_SEGSIZE - 1 &&
pool->slots[i].list; i--)
pool->slots[i].list = ++count;
/* * Update the indices to avoid searching in the next round.
*/
area->index = wrap_area_index(pool, index + nslots);
area->used += nslots;
spin_unlock_irqrestore(&area->lock, flags);
/** * swiotlb_search_area() - search one memory area in all pools * @dev: Device which maps the buffer. * @start_cpu: Start CPU number. * @cpu_offset: Offset from @start_cpu. * @orig_addr: Original (non-bounced) IO buffer address. * @alloc_size: Total requested size of the bounce buffer, * including initial alignment padding. * @alloc_align_mask: Required alignment of the allocated buffer. * @retpool: Used memory pool, updated on return. * * Search one memory area in all pools for a sequence of slots that match the * allocation constraints. * * Return: Index of the first allocated slot, or -1 on error.
*/ staticint swiotlb_search_area(struct device *dev, int start_cpu, int cpu_offset, phys_addr_t orig_addr, size_t alloc_size, unsignedint alloc_align_mask, struct io_tlb_pool **retpool)
{ struct io_tlb_mem *mem = dev->dma_io_tlb_mem; struct io_tlb_pool *pool; int area_index; int index = -1;
/** * swiotlb_find_slots() - search for slots in the whole swiotlb * @dev: Device which maps the buffer. * @orig_addr: Original (non-bounced) IO buffer address. * @alloc_size: Total requested size of the bounce buffer, * including initial alignment padding. * @alloc_align_mask: Required alignment of the allocated buffer. * @retpool: Used memory pool, updated on return. * * Search through the whole software IO TLB to find a sequence of slots that * match the allocation constraints. * * Return: Index of the first allocated slot, or -1 on error.
*/ staticint swiotlb_find_slots(struct device *dev, phys_addr_t orig_addr,
size_t alloc_size, unsignedint alloc_align_mask, struct io_tlb_pool **retpool)
{ struct io_tlb_mem *mem = dev->dma_io_tlb_mem; struct io_tlb_pool *pool; unsignedlong nslabs; unsignedlong flags;
u64 phys_limit; int cpu, i; int index;
if (alloc_size > IO_TLB_SEGSIZE * IO_TLB_SIZE) return -1;
cpu = raw_smp_processor_id(); for (i = 0; i < default_nareas; ++i) {
index = swiotlb_search_area(dev, cpu, i, orig_addr, alloc_size,
alloc_align_mask, &pool); if (index >= 0) goto found;
}
/* * The general barrier orders reads and writes against a presumed store * of the SWIOTLB buffer address by a device driver (to a driver private * data structure). It serves two purposes. * * First, the store to dev->dma_uses_io_tlb must be ordered before the * presumed store. This guarantees that the returned buffer address * cannot be passed to another CPU before updating dev->dma_uses_io_tlb. * * Second, the load from mem->pools must be ordered before the same * presumed store. This guarantees that the returned buffer address * cannot be observed by another CPU before an update of the RCU list * that was made by swiotlb_dyn_alloc() on a third CPU (cf. multicopy * atomicity). * * See also the comment in swiotlb_find_pool().
*/
smp_mb();
*retpool = pool = &dev->dma_io_tlb_mem->defpool;
i = start = raw_smp_processor_id() & (pool->nareas - 1); do {
index = swiotlb_search_pool_area(dev, pool, i, orig_addr,
alloc_size, alloc_align_mask); if (index >= 0) return index; if (++i >= pool->nareas)
i = 0;
} while (i != start); return -1;
}
#endif/* CONFIG_SWIOTLB_DYNAMIC */
#ifdef CONFIG_DEBUG_FS
/** * mem_used() - get number of used slots in an allocator * @mem: Software IO TLB allocator. * * The result is accurate in this version of the function, because an atomic * counter is available if CONFIG_DEBUG_FS is set. * * Return: Number of used slots.
*/ staticunsignedlong mem_used(struct io_tlb_mem *mem)
{ return atomic_long_read(&mem->total_used);
}
#else/* !CONFIG_DEBUG_FS */
/** * mem_pool_used() - get number of used slots in a memory pool * @pool: Software IO TLB memory pool. * * The result is not accurate, see mem_used(). * * Return: Approximate number of used slots.
*/ staticunsignedlong mem_pool_used(struct io_tlb_pool *pool)
{ int i; unsignedlong used = 0;
for (i = 0; i < pool->nareas; i++)
used += pool->areas[i].used; return used;
}
/** * mem_used() - get number of used slots in an allocator * @mem: Software IO TLB allocator. * * The result is not accurate, because there is no locking of individual * areas. * * Return: Approximate number of used slots.
*/ staticunsignedlong mem_used(struct io_tlb_mem *mem)
{ #ifdef CONFIG_SWIOTLB_DYNAMIC struct io_tlb_pool *pool; unsignedlong used = 0;
rcu_read_lock();
list_for_each_entry_rcu(pool, &mem->pools, node)
used += mem_pool_used(pool);
rcu_read_unlock();
/** * swiotlb_tbl_map_single() - bounce buffer map a single contiguous physical area * @dev: Device which maps the buffer. * @orig_addr: Original (non-bounced) physical IO buffer address * @mapping_size: Requested size of the actual bounce buffer, excluding * any pre- or post-padding for alignment * @alloc_align_mask: Required start and end alignment of the allocated buffer * @dir: DMA direction * @attrs: Optional DMA attributes for the map operation * * Find and allocate a suitable sequence of IO TLB slots for the request. * The allocated space starts at an alignment specified by alloc_align_mask, * and the size of the allocated space is rounded up so that the total amount * of allocated space is a multiple of (alloc_align_mask + 1). If * alloc_align_mask is zero, the allocated space may be at any alignment and * the size is not rounded up. * * The returned address is within the allocated space and matches the bits * of orig_addr that are specified in the DMA min_align_mask for the device. As * such, this returned address may be offset from the beginning of the allocated * space. The bounce buffer space starting at the returned address for * mapping_size bytes is initialized to the contents of the original IO buffer * area. Any pre-padding (due to an offset) and any post-padding (due to * rounding-up the size) is not initialized.
*/
phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr,
size_t mapping_size, unsignedint alloc_align_mask, enum dma_data_direction dir, unsignedlong attrs)
{ struct io_tlb_mem *mem = dev->dma_io_tlb_mem; unsignedint offset; struct io_tlb_pool *pool; unsignedint i;
size_t size; int index;
phys_addr_t tlb_addr; unsignedshort pad_slots;
if (!mem || !mem->nslabs) {
dev_warn_ratelimited(dev, "Can not allocate SWIOTLB buffer earlier and can't now provide you with the DMA bounce buffer"); return (phys_addr_t)DMA_MAPPING_ERROR;
}
if (cc_platform_has(CC_ATTR_MEM_ENCRYPT))
pr_warn_once("Memory encryption is active and system is using DMA bounce buffers\n");
/* * The default swiotlb memory pool is allocated with PAGE_SIZE * alignment. If a mapping is requested with larger alignment, * the mapping may be unable to use the initial slot(s) in all * sets of IO_TLB_SEGSIZE slots. In such case, a mapping request * of or near the maximum mapping size would always fail.
*/
dev_WARN_ONCE(dev, alloc_align_mask > ~PAGE_MASK, "Alloc alignment may prevent fulfilling requests with max mapping_size\n");
offset = swiotlb_align_offset(dev, alloc_align_mask, orig_addr);
size = ALIGN(mapping_size + offset, alloc_align_mask + 1);
index = swiotlb_find_slots(dev, orig_addr, size, alloc_align_mask, &pool); if (index == -1) { if (!(attrs & DMA_ATTR_NO_WARN))
dev_warn_ratelimited(dev, "swiotlb buffer is full (sz: %zd bytes), total %lu (slots), used %lu (slots)\n",
size, mem->nslabs, mem_used(mem)); return (phys_addr_t)DMA_MAPPING_ERROR;
}
/* * If dma_skip_sync was set, reset it on first SWIOTLB buffer * mapping to always sync SWIOTLB buffers.
*/
dma_reset_need_sync(dev);
/* * Save away the mapping from the original address to the DMA address. * This is needed when we sync the memory. Then we sync the buffer if * needed.
*/
pad_slots = offset >> IO_TLB_SHIFT;
offset &= (IO_TLB_SIZE - 1);
index += pad_slots;
pool->slots[index].pad_slots = pad_slots; for (i = 0; i < (nr_slots(size) - pad_slots); i++)
pool->slots[index + i].orig_addr = slot_addr(orig_addr, i);
tlb_addr = slot_addr(pool->start, index) + offset; /* * When the device is writing memory, i.e. dir == DMA_FROM_DEVICE, copy * the original buffer to the TLB buffer before initiating DMA in order * to preserve the original's data if the device does a partial write, * i.e. if the device doesn't overwrite the entire buffer. Preserving * the original data, even if it's garbage, is necessary to match * hardware behavior. Use of swiotlb is supposed to be transparent, * i.e. swiotlb must not corrupt memory by clobbering unwritten bytes.
*/
swiotlb_bounce(dev, tlb_addr, mapping_size, DMA_TO_DEVICE, pool); return tlb_addr;
}
index = (tlb_addr - offset - mem->start) >> IO_TLB_SHIFT;
index -= mem->slots[index].pad_slots;
nslots = nr_slots(mem->slots[index].alloc_size + offset);
aindex = index / mem->area_nslabs;
area = &mem->areas[aindex];
/* * Return the buffer to the free list by setting the corresponding * entries to indicate the number of contiguous entries available. * While returning the entries to the free list, we merge the entries * with slots below and above the pool being returned.
*/
BUG_ON(aindex >= mem->nareas);
/* * Step 1: return the slots to the free list, merging the slots with * superceeding slots
*/ for (i = index + nslots - 1; i >= index; i--) {
mem->slots[i].list = ++count;
mem->slots[i].orig_addr = INVALID_PHYS_ADDR;
mem->slots[i].alloc_size = 0;
mem->slots[i].pad_slots = 0;
}
/* * Step 2: merge the returned slots with the preceding slots, if * available (non zero)
*/ for (i = index - 1;
io_tlb_offset(i) != IO_TLB_SEGSIZE - 1 && mem->slots[i].list;
i--)
mem->slots[i].list = ++count;
area->used -= nslots;
spin_unlock_irqrestore(&area->lock, flags);
dec_used(dev->dma_io_tlb_mem, nslots);
}
#ifdef CONFIG_SWIOTLB_DYNAMIC
/** * swiotlb_del_transient() - delete a transient memory pool * @dev: Device which mapped the buffer. * @tlb_addr: Physical address within a bounce buffer. * @pool: Pointer to the transient memory pool to be checked and deleted. * * Check whether the address belongs to a transient SWIOTLB memory pool. * If yes, then delete the pool. * * Return: %true if @tlb_addr belonged to a transient pool that was released.
*/ staticbool swiotlb_del_transient(struct device *dev, phys_addr_t tlb_addr, struct io_tlb_pool *pool)
{ if (!pool->transient) returnfalse;
/* * Create a swiotlb mapping for the buffer at @paddr, and in case of DMAing * to the device copy the data into it as well.
*/
dma_addr_t swiotlb_map(struct device *dev, phys_addr_t paddr, size_t size, enum dma_data_direction dir, unsignedlong attrs)
{
phys_addr_t swiotlb_addr;
dma_addr_t dma_addr;
size_t swiotlb_max_mapping_size(struct device *dev)
{ int min_align_mask = dma_get_min_align_mask(dev); int min_align = 0;
/* * swiotlb_find_slots() skips slots according to * min align mask. This affects max mapping size. * Take it into acount here.
*/ if (min_align_mask)
min_align = roundup(min_align_mask, IO_TLB_SIZE);
/** * default_swiotlb_base() - get the base address of the default SWIOTLB * * Get the lowest physical address used by the default software IO TLB pool.
*/
phys_addr_t default_swiotlb_base(void)
{ #ifdef CONFIG_SWIOTLB_DYNAMIC
io_tlb_default_mem.can_grow = false; #endif return io_tlb_default_mem.defpool.start;
}
/** * default_swiotlb_limit() - get the address limit of the default SWIOTLB * * Get the highest physical address used by the default software IO TLB pool.
*/
phys_addr_t default_swiotlb_limit(void)
{ #ifdef CONFIG_SWIOTLB_DYNAMIC return io_tlb_default_mem.phys_limit; #else return io_tlb_default_mem.defpool.end - 1; #endif
}
/* Set Per-device io tlb area to one */ unsignedint nareas = 1;
if (PageHighMem(pfn_to_page(PHYS_PFN(rmem->base)))) {
dev_err(dev, "Restricted DMA pool must be accessible within the linear mapping."); return -EINVAL;
}
/* * Since multiple devices can share the same pool, the private data, * io_tlb_mem struct, will be initialized by the first device attached * to it.
*/ if (!mem) { struct io_tlb_pool *pool;
mem = kzalloc(sizeof(*mem), GFP_KERNEL); if (!mem) return -ENOMEM;
pool = &mem->defpool;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.