/* * The DMA API is built upon the notion of "buffer ownership". A buffer * is either exclusively owned by the CPU (and therefore may be accessed * by it) or exclusively owned by the DMA device. These helper functions * represent the transitions between these two ownership states. * * Note, however, that on later ARMs, this notion does not work due to * speculative prefetches. We model our approach on the assumption that * the CPU does do speculative prefetches, which means we clean caches * before transfers and delay cache invalidation until transfer completion. *
*/
staticvoid __dma_clear_buffer(struct page *page, size_t size, int coherent_flag)
{ /* * Ensure that the allocated pages are zeroed, and that any data * lurking in the kernel direct-mapped region is invalidated.
*/ if (PageHighMem(page)) {
phys_addr_t base = __pfn_to_phys(page_to_pfn(page));
phys_addr_t end = base + size; while (size > 0) { void *ptr = kmap_atomic(page);
memset(ptr, 0, PAGE_SIZE); if (coherent_flag != COHERENT)
dmac_flush_range(ptr, ptr + PAGE_SIZE);
kunmap_atomic(ptr);
page++;
size -= PAGE_SIZE;
} if (coherent_flag != COHERENT)
outer_flush_range(base, end);
} else { void *ptr = page_address(page);
memset(ptr, 0, size); if (coherent_flag != COHERENT) {
dmac_flush_range(ptr, ptr + size);
outer_flush_range(__pa(ptr), __pa(ptr) + size);
}
}
}
/* * Allocate a DMA buffer for 'dev' of size 'size' using the * specified gfp mask. Note that 'size' must be page aligned.
*/ staticstruct page *__dma_alloc_buffer(struct device *dev, size_t size,
gfp_t gfp, int coherent_flag)
{ unsignedlong order = get_order(size); struct page *page, *p, *e;
page = alloc_pages(gfp, order); if (!page) return NULL;
/* * Now split the huge page and free the excess pages
*/
split_page(page, order); for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++)
__free_page(p);
__dma_clear_buffer(page, size, coherent_flag);
return page;
}
/* * Free a DMA buffer. 'size' must be page aligned.
*/ staticvoid __dma_free_buffer(struct page *page, size_t size)
{ struct page *e = page + (size >> PAGE_SHIFT);
/* * Initialise the coherent pool for atomic allocations.
*/ staticint __init atomic_pool_init(void)
{
pgprot_t prot = pgprot_dmacoherent(PAGE_KERNEL);
gfp_t gfp = GFP_KERNEL | GFP_DMA; struct page *page; void *ptr;
atomic_pool = gen_pool_create(PAGE_SHIFT, -1); if (!atomic_pool) goto out; /* * The atomic pool is only used for non-coherent allocations * so we must pass NORMAL for coherent_flag.
*/ if (dev_get_cma_area(NULL))
ptr = __alloc_from_contiguous(NULL, atomic_pool_size, prot,
&page, atomic_pool_init, true, NORMAL,
GFP_KERNEL); else
ptr = __alloc_remap_buffer(NULL, atomic_pool_size, gfp, prot,
&page, atomic_pool_init, true); if (ptr) { int ret;
ret = gen_pool_add_virt(atomic_pool, (unsignedlong)ptr,
page_to_phys(page),
atomic_pool_size, -1); if (ret) goto destroy_genpool;
gen_pool_set_algo(atomic_pool,
gen_pool_first_fit_order_align,
NULL);
pr_info("DMA: preallocated %zu KiB pool for atomic coherent allocations\n",
atomic_pool_size / 1024); return 0;
}
destroy_genpool:
gen_pool_destroy(atomic_pool);
atomic_pool = NULL;
out:
pr_err("DMA: failed to allocate %zu KiB pool for atomic coherent allocation\n",
atomic_pool_size / 1024); return -ENOMEM;
} /* * CMA is activated by core_initcall, so we must be called after it.
*/
postcore_initcall(atomic_pool_init);
/* * Clear previous low-memory mapping to ensure that the * TLB does not see any conflicting entries, then flush * the TLB of the old entries before creating new mappings. * * This ensures that any speculatively loaded TLB entries * (even though they may be rare) can not cause any problems, * and ensures that this code is architecturally compliant.
*/ for (addr = __phys_to_virt(start); addr < __phys_to_virt(end);
addr += PMD_SIZE)
pmd_clear(pmd_off_k(addr));
/* * A single sg entry may refer to multiple physically contiguous * pages. But we still need to process highmem pages individually. * If highmem is not configured then the bulk of this loop gets * optimized out.
*/ do {
size_t len = left; void *vaddr;
page = pfn_to_page(pfn);
if (PageHighMem(page)) { if (len + offset > PAGE_SIZE)
len = PAGE_SIZE - offset;
/* * Make an area consistent for devices. * Note: Drivers should NOT use this function directly. * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
*/ staticvoid __dma_page_cpu_to_dev(struct page *page, unsignedlong off,
size_t size, enum dma_data_direction dir)
{
phys_addr_t paddr;
/* FIXME: non-speculating: not required */ /* in any case, don't bother invalidating if DMA to device */ if (dir != DMA_TO_DEVICE) {
outer_inv_range(paddr, paddr + size);
/* * Mark the D-cache clean for these pages to avoid extra flushing.
*/ if (dir != DMA_TO_DEVICE && size >= PAGE_SIZE) { struct folio *folio = pfn_folio(paddr / PAGE_SIZE);
size_t offset = offset_in_folio(folio, paddr);
for (;;) {
size_t sz = folio_size(folio) - offset;
if (size < sz) break; if (!offset)
set_bit(PG_dcache_clean, &folio->flags);
offset = 0;
size -= sz; if (!size) break;
folio = folio_next(folio);
}
}
}
/* * No unused range found. Try to extend the existing mapping * and perform a second attempt to reserve an IO virtual * address range of size bytes.
*/ if (i == mapping->nr_bitmaps) { if (extend_iommu_mapping(mapping)) {
spin_unlock_irqrestore(&mapping->lock, flags); return DMA_MAPPING_ERROR;
}
if (addr + size > bitmap_base + mapping_size) { /* * The address range to be freed reaches into the iova * range of the next bitmap. This should not happen as * we don't allow this in __alloc_iova (at the * moment).
*/
BUG();
} else
count = size >> PAGE_SHIFT;
/* Go straight to 4K chunks if caller says it's OK. */ if (attrs & DMA_ATTR_ALLOC_SINGLE_PAGES)
order_idx = ARRAY_SIZE(iommu_order_array) - 1;
/* * IOMMU can map any pages, so himem can also be used here
*/
gfp |= __GFP_NOWARN | __GFP_HIGHMEM;
while (count) { int j, order;
order = iommu_order_array[order_idx];
/* Drop down when we get small */ if (__fls(count) < order) {
order_idx++; continue;
}
if (order) { /* See if it's easy to allocate a high-order chunk */
pages[i] = alloc_pages(gfp | __GFP_NORETRY, order);
/* Go down a notch at first sign of pressure */ if (!pages[i]) {
order_idx++; continue;
}
} else {
pages[i] = alloc_pages(gfp, 0); if (!pages[i]) goto error;
}
if (order) {
split_page(pages[i], order);
j = 1 << order; while (--j)
pages[i + j] = pages[i] + j;
}
return pages;
error: while (i--) if (pages[i])
__free_pages(pages[i], 0);
kvfree(pages); return NULL;
}
staticint __iommu_free_buffer(struct device *dev, struct page **pages,
size_t size, unsignedlong attrs)
{ int count = size >> PAGE_SHIFT; int i;
if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
dma_release_from_contiguous(dev, pages[0], count);
} else { for (i = 0; i < count; i++) if (pages[i])
__free_pages(pages[i], 0);
}
kvfree(pages); return 0;
}
/* * Create a mapping in device IO address space for specified pages
*/ static dma_addr_t
__iommu_create_mapping(struct device *dev, struct page **pages, size_t size, unsignedlong attrs)
{ struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); unsignedint count = PAGE_ALIGN(size) >> PAGE_SHIFT;
dma_addr_t dma_addr, iova; int i;
dma_addr = __alloc_iova(mapping, size); if (dma_addr == DMA_MAPPING_ERROR) return dma_addr;
iova = dma_addr; for (i = 0; i < count; ) { int ret;
/* * free a page as defined by the above mapping. * Must not be called with IRQs disabled.
*/ staticvoid arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t handle, unsignedlong attrs)
{ int coherent_flag = dev->dma_coherent ? COHERENT : NORMAL; struct page **pages;
size = PAGE_ALIGN(size);
/** * arm_iommu_map_sg - map a set of SG buffers for streaming mode DMA * @dev: valid struct device pointer * @sg: list of buffers * @nents: number of buffers to map * @dir: DMA transfer direction * * Map a set of buffers described by scatterlist in streaming mode for DMA. * The scatter gather list elements are merged together (if possible) and * tagged with the appropriate dma address and length. They are obtained via * sg_dma_{address,length}.
*/ staticint arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, unsignedlong attrs)
{ struct scatterlist *s = sg, *dma = sg, *start = sg; int i, count = 0, ret; unsignedint offset = s->offset; unsignedint size = s->offset + s->length; unsignedint max = dma_get_max_seg_size(dev);
for (i = 1; i < nents; i++) {
s = sg_next(s);
s->dma_length = 0;
if (s->offset || (size & ~PAGE_MASK) || size + s->length > max) {
ret = __map_sg_chunk(dev, start, size,
&dma->dma_address, dir, attrs); if (ret < 0) goto bad_mapping;
/** * arm_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg * @dev: valid struct device pointer * @sg: list of buffers * @nents: number of buffers to unmap (same as was passed to dma_map_sg) * @dir: DMA transfer direction (same as was passed to dma_map_sg) * * Unmap a set of streaming mode DMA translations. Again, CPU access * rules concerning calls here are the same as for dma_unmap_single().
*/ staticvoid arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, unsignedlong attrs)
{ struct scatterlist *s; int i;
/** * arm_iommu_sync_sg_for_cpu * @dev: valid struct device pointer * @sg: list of buffers * @nents: number of buffers to map (returned from dma_map_sg) * @dir: DMA transfer direction (same as was passed to dma_map_sg)
*/ staticvoid arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir)
{ struct scatterlist *s; int i;
/** * arm_iommu_sync_sg_for_device * @dev: valid struct device pointer * @sg: list of buffers * @nents: number of buffers to map (returned from dma_map_sg) * @dir: DMA transfer direction (same as was passed to dma_map_sg)
*/ staticvoid arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir)
{ struct scatterlist *s; int i;
/** * arm_iommu_create_mapping * @dev: pointer to the client device (for IOMMU calls) * @base: start address of the valid IO address space * @size: maximum size of the valid IO address space * * Creates a mapping structure which holds information about used/unused * IO address ranges, which is required to perform memory allocation and * mapping with IOMMU aware functions. * * The client device need to be attached to the mapping with * arm_iommu_attach_device function.
*/ struct dma_iommu_mapping *
arm_iommu_create_mapping(struct device *dev, dma_addr_t base, u64 size)
{ unsignedint bits = size >> PAGE_SHIFT; unsignedint bitmap_size = BITS_TO_LONGS(bits) * sizeof(long); struct dma_iommu_mapping *mapping; int extensions = 1; int err = -ENOMEM;
/* currently only 32-bit DMA address space is supported */ if (size > DMA_BIT_MASK(32) + 1) return ERR_PTR(-ERANGE);
pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev)); return 0;
}
/** * arm_iommu_attach_device * @dev: valid struct device pointer * @mapping: io address space mapping structure (returned from * arm_iommu_create_mapping) * * Attaches specified io address space mapping to the provided device. * This replaces the dma operations (dma_map_ops pointer) with the * IOMMU aware version. * * More than one client might be attached to the same io address space * mapping.
*/ int arm_iommu_attach_device(struct device *dev, struct dma_iommu_mapping *mapping)
{ int err;
err = __arm_iommu_attach_device(dev, mapping); if (err) return err;
if (dev->dma_range_map) {
dma_base = dma_range_map_min(dev->dma_range_map);
size = dma_range_map_max(dev->dma_range_map) - dma_base;
}
mapping = arm_iommu_create_mapping(dev, dma_base, size); if (IS_ERR(mapping)) {
pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n",
size, dev_name(dev)); return;
}
if (__arm_iommu_attach_device(dev, mapping)) {
pr_warn("Failed to attached device %s to IOMMU_mapping\n",
dev_name(dev));
arm_iommu_release_mapping(mapping); return;
}
void arch_setup_dma_ops(struct device *dev, bool coherent)
{ /* * Due to legacy code that sets the ->dma_coherent flag from a bus * notifier we can't just assign coherent to the ->dma_coherent flag * here, but instead have to make sure we only set but never clear it * for now.
*/ if (coherent)
dev->dma_coherent = true;
/* * Don't override the dma_ops if they have already been set. Ideally * this should be the only location where dma_ops are set, remove this * check when all other callers of set_dma_ops will have disappeared.
*/ if (dev->dma_ops) return;
if (device_iommu_mapped(dev))
arm_setup_iommu_dma_ops(dev);
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.