162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * DMA Pool allocator 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2001 David Brownell 662306a36Sopenharmony_ci * Copyright 2007 Intel Corporation 762306a36Sopenharmony_ci * Author: Matthew Wilcox <willy@linux.intel.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This allocator returns small blocks of a given size which are DMA-able by 1062306a36Sopenharmony_ci * the given device. It uses the dma_alloc_coherent page allocator to get 1162306a36Sopenharmony_ci * new pages, then splits them up into blocks of the required size. 1262306a36Sopenharmony_ci * Many older drivers still have their own code to do this. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The current design of this allocator is fairly simple. The pool is 1562306a36Sopenharmony_ci * represented by the 'struct dma_pool' which keeps a doubly-linked list of 1662306a36Sopenharmony_ci * allocated pages. Each page in the page_list is split into blocks of at 1762306a36Sopenharmony_ci * least 'size' bytes. Free blocks are tracked in an unsorted singly-linked 1862306a36Sopenharmony_ci * list of free blocks across all pages. Used blocks aren't tracked, but we 1962306a36Sopenharmony_ci * keep a count of how many are currently allocated from each page. 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <linux/device.h> 2362306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2462306a36Sopenharmony_ci#include <linux/dmapool.h> 2562306a36Sopenharmony_ci#include <linux/kernel.h> 2662306a36Sopenharmony_ci#include <linux/list.h> 2762306a36Sopenharmony_ci#include <linux/export.h> 2862306a36Sopenharmony_ci#include <linux/mutex.h> 2962306a36Sopenharmony_ci#include <linux/poison.h> 3062306a36Sopenharmony_ci#include <linux/sched.h> 3162306a36Sopenharmony_ci#include <linux/sched/mm.h> 3262306a36Sopenharmony_ci#include <linux/slab.h> 3362306a36Sopenharmony_ci#include <linux/stat.h> 3462306a36Sopenharmony_ci#include <linux/spinlock.h> 3562306a36Sopenharmony_ci#include <linux/string.h> 3662306a36Sopenharmony_ci#include <linux/types.h> 3762306a36Sopenharmony_ci#include <linux/wait.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB_DEBUG_ON) 4062306a36Sopenharmony_ci#define DMAPOOL_DEBUG 1 4162306a36Sopenharmony_ci#endif 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct dma_block { 4462306a36Sopenharmony_ci struct dma_block *next_block; 4562306a36Sopenharmony_ci dma_addr_t dma; 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistruct dma_pool { /* the pool */ 4962306a36Sopenharmony_ci struct list_head page_list; 5062306a36Sopenharmony_ci spinlock_t lock; 5162306a36Sopenharmony_ci struct dma_block *next_block; 5262306a36Sopenharmony_ci size_t nr_blocks; 5362306a36Sopenharmony_ci size_t nr_active; 5462306a36Sopenharmony_ci size_t nr_pages; 5562306a36Sopenharmony_ci struct device *dev; 5662306a36Sopenharmony_ci unsigned int size; 5762306a36Sopenharmony_ci unsigned int allocation; 5862306a36Sopenharmony_ci unsigned int boundary; 5962306a36Sopenharmony_ci char name[32]; 6062306a36Sopenharmony_ci struct list_head pools; 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct dma_page { /* cacheable header for 'allocation' bytes */ 6462306a36Sopenharmony_ci struct list_head page_list; 6562306a36Sopenharmony_ci void *vaddr; 6662306a36Sopenharmony_ci dma_addr_t dma; 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic DEFINE_MUTEX(pools_lock); 7062306a36Sopenharmony_cistatic DEFINE_MUTEX(pools_reg_lock); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic ssize_t pools_show(struct device *dev, struct device_attribute *attr, char *buf) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct dma_pool *pool; 7562306a36Sopenharmony_ci unsigned size; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci size = sysfs_emit(buf, "poolinfo - 0.1\n"); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci mutex_lock(&pools_lock); 8062306a36Sopenharmony_ci list_for_each_entry(pool, &dev->dma_pools, pools) { 8162306a36Sopenharmony_ci /* per-pool info, no real statistics yet */ 8262306a36Sopenharmony_ci size += sysfs_emit_at(buf, size, "%-16s %4zu %4zu %4u %2zu\n", 8362306a36Sopenharmony_ci pool->name, pool->nr_active, 8462306a36Sopenharmony_ci pool->nr_blocks, pool->size, 8562306a36Sopenharmony_ci pool->nr_pages); 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci mutex_unlock(&pools_lock); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci return size; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(pools); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#ifdef DMAPOOL_DEBUG 9562306a36Sopenharmony_cistatic void pool_check_block(struct dma_pool *pool, struct dma_block *block, 9662306a36Sopenharmony_ci gfp_t mem_flags) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci u8 *data = (void *)block; 9962306a36Sopenharmony_ci int i; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci for (i = sizeof(struct dma_block); i < pool->size; i++) { 10262306a36Sopenharmony_ci if (data[i] == POOL_POISON_FREED) 10362306a36Sopenharmony_ci continue; 10462306a36Sopenharmony_ci dev_err(pool->dev, "%s %s, %p (corrupted)\n", __func__, 10562306a36Sopenharmony_ci pool->name, block); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* 10862306a36Sopenharmony_ci * Dump the first 4 bytes even if they are not 10962306a36Sopenharmony_ci * POOL_POISON_FREED 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ci print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 16, 1, 11262306a36Sopenharmony_ci data, pool->size, 1); 11362306a36Sopenharmony_ci break; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (!want_init_on_alloc(mem_flags)) 11762306a36Sopenharmony_ci memset(block, POOL_POISON_ALLOCATED, pool->size); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic struct dma_page *pool_find_page(struct dma_pool *pool, dma_addr_t dma) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct dma_page *page; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci list_for_each_entry(page, &pool->page_list, page_list) { 12562306a36Sopenharmony_ci if (dma < page->dma) 12662306a36Sopenharmony_ci continue; 12762306a36Sopenharmony_ci if ((dma - page->dma) < pool->allocation) 12862306a36Sopenharmony_ci return page; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci return NULL; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic bool pool_block_err(struct dma_pool *pool, void *vaddr, dma_addr_t dma) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct dma_block *block = pool->next_block; 13662306a36Sopenharmony_ci struct dma_page *page; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci page = pool_find_page(pool, dma); 13962306a36Sopenharmony_ci if (!page) { 14062306a36Sopenharmony_ci dev_err(pool->dev, "%s %s, %p/%pad (bad dma)\n", 14162306a36Sopenharmony_ci __func__, pool->name, vaddr, &dma); 14262306a36Sopenharmony_ci return true; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci while (block) { 14662306a36Sopenharmony_ci if (block != vaddr) { 14762306a36Sopenharmony_ci block = block->next_block; 14862306a36Sopenharmony_ci continue; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci dev_err(pool->dev, "%s %s, dma %pad already free\n", 15162306a36Sopenharmony_ci __func__, pool->name, &dma); 15262306a36Sopenharmony_ci return true; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci memset(vaddr, POOL_POISON_FREED, pool->size); 15662306a36Sopenharmony_ci return false; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic void pool_init_page(struct dma_pool *pool, struct dma_page *page) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci memset(page->vaddr, POOL_POISON_FREED, pool->allocation); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci#else 16462306a36Sopenharmony_cistatic void pool_check_block(struct dma_pool *pool, struct dma_block *block, 16562306a36Sopenharmony_ci gfp_t mem_flags) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic bool pool_block_err(struct dma_pool *pool, void *vaddr, dma_addr_t dma) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci if (want_init_on_free()) 17262306a36Sopenharmony_ci memset(vaddr, 0, pool->size); 17362306a36Sopenharmony_ci return false; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic void pool_init_page(struct dma_pool *pool, struct dma_page *page) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci#endif 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic struct dma_block *pool_block_pop(struct dma_pool *pool) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct dma_block *block = pool->next_block; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (block) { 18662306a36Sopenharmony_ci pool->next_block = block->next_block; 18762306a36Sopenharmony_ci pool->nr_active++; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci return block; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic void pool_block_push(struct dma_pool *pool, struct dma_block *block, 19362306a36Sopenharmony_ci dma_addr_t dma) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci block->dma = dma; 19662306a36Sopenharmony_ci block->next_block = pool->next_block; 19762306a36Sopenharmony_ci pool->next_block = block; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/** 20262306a36Sopenharmony_ci * dma_pool_create - Creates a pool of consistent memory blocks, for dma. 20362306a36Sopenharmony_ci * @name: name of pool, for diagnostics 20462306a36Sopenharmony_ci * @dev: device that will be doing the DMA 20562306a36Sopenharmony_ci * @size: size of the blocks in this pool. 20662306a36Sopenharmony_ci * @align: alignment requirement for blocks; must be a power of two 20762306a36Sopenharmony_ci * @boundary: returned blocks won't cross this power of two boundary 20862306a36Sopenharmony_ci * Context: not in_interrupt() 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * Given one of these pools, dma_pool_alloc() 21162306a36Sopenharmony_ci * may be used to allocate memory. Such memory will all have "consistent" 21262306a36Sopenharmony_ci * DMA mappings, accessible by the device and its driver without using 21362306a36Sopenharmony_ci * cache flushing primitives. The actual size of blocks allocated may be 21462306a36Sopenharmony_ci * larger than requested because of alignment. 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * If @boundary is nonzero, objects returned from dma_pool_alloc() won't 21762306a36Sopenharmony_ci * cross that size boundary. This is useful for devices which have 21862306a36Sopenharmony_ci * addressing restrictions on individual DMA transfers, such as not crossing 21962306a36Sopenharmony_ci * boundaries of 4KBytes. 22062306a36Sopenharmony_ci * 22162306a36Sopenharmony_ci * Return: a dma allocation pool with the requested characteristics, or 22262306a36Sopenharmony_ci * %NULL if one can't be created. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_cistruct dma_pool *dma_pool_create(const char *name, struct device *dev, 22562306a36Sopenharmony_ci size_t size, size_t align, size_t boundary) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct dma_pool *retval; 22862306a36Sopenharmony_ci size_t allocation; 22962306a36Sopenharmony_ci bool empty; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (!dev) 23262306a36Sopenharmony_ci return NULL; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (align == 0) 23562306a36Sopenharmony_ci align = 1; 23662306a36Sopenharmony_ci else if (align & (align - 1)) 23762306a36Sopenharmony_ci return NULL; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (size == 0 || size > INT_MAX) 24062306a36Sopenharmony_ci return NULL; 24162306a36Sopenharmony_ci if (size < sizeof(struct dma_block)) 24262306a36Sopenharmony_ci size = sizeof(struct dma_block); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci size = ALIGN(size, align); 24562306a36Sopenharmony_ci allocation = max_t(size_t, size, PAGE_SIZE); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (!boundary) 24862306a36Sopenharmony_ci boundary = allocation; 24962306a36Sopenharmony_ci else if ((boundary < size) || (boundary & (boundary - 1))) 25062306a36Sopenharmony_ci return NULL; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci boundary = min(boundary, allocation); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci retval = kzalloc(sizeof(*retval), GFP_KERNEL); 25562306a36Sopenharmony_ci if (!retval) 25662306a36Sopenharmony_ci return retval; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci strscpy(retval->name, name, sizeof(retval->name)); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci retval->dev = dev; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci INIT_LIST_HEAD(&retval->page_list); 26362306a36Sopenharmony_ci spin_lock_init(&retval->lock); 26462306a36Sopenharmony_ci retval->size = size; 26562306a36Sopenharmony_ci retval->boundary = boundary; 26662306a36Sopenharmony_ci retval->allocation = allocation; 26762306a36Sopenharmony_ci INIT_LIST_HEAD(&retval->pools); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* 27062306a36Sopenharmony_ci * pools_lock ensures that the ->dma_pools list does not get corrupted. 27162306a36Sopenharmony_ci * pools_reg_lock ensures that there is not a race between 27262306a36Sopenharmony_ci * dma_pool_create() and dma_pool_destroy() or within dma_pool_create() 27362306a36Sopenharmony_ci * when the first invocation of dma_pool_create() failed on 27462306a36Sopenharmony_ci * device_create_file() and the second assumes that it has been done (I 27562306a36Sopenharmony_ci * know it is a short window). 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci mutex_lock(&pools_reg_lock); 27862306a36Sopenharmony_ci mutex_lock(&pools_lock); 27962306a36Sopenharmony_ci empty = list_empty(&dev->dma_pools); 28062306a36Sopenharmony_ci list_add(&retval->pools, &dev->dma_pools); 28162306a36Sopenharmony_ci mutex_unlock(&pools_lock); 28262306a36Sopenharmony_ci if (empty) { 28362306a36Sopenharmony_ci int err; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci err = device_create_file(dev, &dev_attr_pools); 28662306a36Sopenharmony_ci if (err) { 28762306a36Sopenharmony_ci mutex_lock(&pools_lock); 28862306a36Sopenharmony_ci list_del(&retval->pools); 28962306a36Sopenharmony_ci mutex_unlock(&pools_lock); 29062306a36Sopenharmony_ci mutex_unlock(&pools_reg_lock); 29162306a36Sopenharmony_ci kfree(retval); 29262306a36Sopenharmony_ci return NULL; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci mutex_unlock(&pools_reg_lock); 29662306a36Sopenharmony_ci return retval; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ciEXPORT_SYMBOL(dma_pool_create); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void pool_initialise_page(struct dma_pool *pool, struct dma_page *page) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci unsigned int next_boundary = pool->boundary, offset = 0; 30362306a36Sopenharmony_ci struct dma_block *block, *first = NULL, *last = NULL; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci pool_init_page(pool, page); 30662306a36Sopenharmony_ci while (offset + pool->size <= pool->allocation) { 30762306a36Sopenharmony_ci if (offset + pool->size > next_boundary) { 30862306a36Sopenharmony_ci offset = next_boundary; 30962306a36Sopenharmony_ci next_boundary += pool->boundary; 31062306a36Sopenharmony_ci continue; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci block = page->vaddr + offset; 31462306a36Sopenharmony_ci block->dma = page->dma + offset; 31562306a36Sopenharmony_ci block->next_block = NULL; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (last) 31862306a36Sopenharmony_ci last->next_block = block; 31962306a36Sopenharmony_ci else 32062306a36Sopenharmony_ci first = block; 32162306a36Sopenharmony_ci last = block; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci offset += pool->size; 32462306a36Sopenharmony_ci pool->nr_blocks++; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci last->next_block = pool->next_block; 32862306a36Sopenharmony_ci pool->next_block = first; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci list_add(&page->page_list, &pool->page_list); 33162306a36Sopenharmony_ci pool->nr_pages++; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct dma_page *page; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci page = kmalloc(sizeof(*page), mem_flags); 33962306a36Sopenharmony_ci if (!page) 34062306a36Sopenharmony_ci return NULL; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci page->vaddr = dma_alloc_coherent(pool->dev, pool->allocation, 34362306a36Sopenharmony_ci &page->dma, mem_flags); 34462306a36Sopenharmony_ci if (!page->vaddr) { 34562306a36Sopenharmony_ci kfree(page); 34662306a36Sopenharmony_ci return NULL; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return page; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci/** 35362306a36Sopenharmony_ci * dma_pool_destroy - destroys a pool of dma memory blocks. 35462306a36Sopenharmony_ci * @pool: dma pool that will be destroyed 35562306a36Sopenharmony_ci * Context: !in_interrupt() 35662306a36Sopenharmony_ci * 35762306a36Sopenharmony_ci * Caller guarantees that no more memory from the pool is in use, 35862306a36Sopenharmony_ci * and that nothing will try to use the pool after this call. 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_civoid dma_pool_destroy(struct dma_pool *pool) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct dma_page *page, *tmp; 36362306a36Sopenharmony_ci bool empty, busy = false; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (unlikely(!pool)) 36662306a36Sopenharmony_ci return; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci mutex_lock(&pools_reg_lock); 36962306a36Sopenharmony_ci mutex_lock(&pools_lock); 37062306a36Sopenharmony_ci list_del(&pool->pools); 37162306a36Sopenharmony_ci empty = list_empty(&pool->dev->dma_pools); 37262306a36Sopenharmony_ci mutex_unlock(&pools_lock); 37362306a36Sopenharmony_ci if (empty) 37462306a36Sopenharmony_ci device_remove_file(pool->dev, &dev_attr_pools); 37562306a36Sopenharmony_ci mutex_unlock(&pools_reg_lock); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (pool->nr_active) { 37862306a36Sopenharmony_ci dev_err(pool->dev, "%s %s busy\n", __func__, pool->name); 37962306a36Sopenharmony_ci busy = true; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci list_for_each_entry_safe(page, tmp, &pool->page_list, page_list) { 38362306a36Sopenharmony_ci if (!busy) 38462306a36Sopenharmony_ci dma_free_coherent(pool->dev, pool->allocation, 38562306a36Sopenharmony_ci page->vaddr, page->dma); 38662306a36Sopenharmony_ci list_del(&page->page_list); 38762306a36Sopenharmony_ci kfree(page); 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci kfree(pool); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ciEXPORT_SYMBOL(dma_pool_destroy); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci/** 39562306a36Sopenharmony_ci * dma_pool_alloc - get a block of consistent memory 39662306a36Sopenharmony_ci * @pool: dma pool that will produce the block 39762306a36Sopenharmony_ci * @mem_flags: GFP_* bitmask 39862306a36Sopenharmony_ci * @handle: pointer to dma address of block 39962306a36Sopenharmony_ci * 40062306a36Sopenharmony_ci * Return: the kernel virtual address of a currently unused block, 40162306a36Sopenharmony_ci * and reports its dma address through the handle. 40262306a36Sopenharmony_ci * If such a memory block can't be allocated, %NULL is returned. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_civoid *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, 40562306a36Sopenharmony_ci dma_addr_t *handle) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct dma_block *block; 40862306a36Sopenharmony_ci struct dma_page *page; 40962306a36Sopenharmony_ci unsigned long flags; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci might_alloc(mem_flags); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci spin_lock_irqsave(&pool->lock, flags); 41462306a36Sopenharmony_ci block = pool_block_pop(pool); 41562306a36Sopenharmony_ci if (!block) { 41662306a36Sopenharmony_ci /* 41762306a36Sopenharmony_ci * pool_alloc_page() might sleep, so temporarily drop 41862306a36Sopenharmony_ci * &pool->lock 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci spin_unlock_irqrestore(&pool->lock, flags); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci page = pool_alloc_page(pool, mem_flags & (~__GFP_ZERO)); 42362306a36Sopenharmony_ci if (!page) 42462306a36Sopenharmony_ci return NULL; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci spin_lock_irqsave(&pool->lock, flags); 42762306a36Sopenharmony_ci pool_initialise_page(pool, page); 42862306a36Sopenharmony_ci block = pool_block_pop(pool); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci spin_unlock_irqrestore(&pool->lock, flags); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci *handle = block->dma; 43362306a36Sopenharmony_ci pool_check_block(pool, block, mem_flags); 43462306a36Sopenharmony_ci if (want_init_on_alloc(mem_flags)) 43562306a36Sopenharmony_ci memset(block, 0, pool->size); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return block; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ciEXPORT_SYMBOL(dma_pool_alloc); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/** 44262306a36Sopenharmony_ci * dma_pool_free - put block back into dma pool 44362306a36Sopenharmony_ci * @pool: the dma pool holding the block 44462306a36Sopenharmony_ci * @vaddr: virtual address of block 44562306a36Sopenharmony_ci * @dma: dma address of block 44662306a36Sopenharmony_ci * 44762306a36Sopenharmony_ci * Caller promises neither device nor driver will again touch this block 44862306a36Sopenharmony_ci * unless it is first re-allocated. 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_civoid dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct dma_block *block = vaddr; 45362306a36Sopenharmony_ci unsigned long flags; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci spin_lock_irqsave(&pool->lock, flags); 45662306a36Sopenharmony_ci if (!pool_block_err(pool, vaddr, dma)) { 45762306a36Sopenharmony_ci pool_block_push(pool, block, dma); 45862306a36Sopenharmony_ci pool->nr_active--; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci spin_unlock_irqrestore(&pool->lock, flags); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ciEXPORT_SYMBOL(dma_pool_free); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci/* 46562306a36Sopenharmony_ci * Managed DMA pool 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_cistatic void dmam_pool_release(struct device *dev, void *res) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct dma_pool *pool = *(struct dma_pool **)res; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci dma_pool_destroy(pool); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic int dmam_pool_match(struct device *dev, void *res, void *match_data) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci return *(struct dma_pool **)res == match_data; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci/** 48062306a36Sopenharmony_ci * dmam_pool_create - Managed dma_pool_create() 48162306a36Sopenharmony_ci * @name: name of pool, for diagnostics 48262306a36Sopenharmony_ci * @dev: device that will be doing the DMA 48362306a36Sopenharmony_ci * @size: size of the blocks in this pool. 48462306a36Sopenharmony_ci * @align: alignment requirement for blocks; must be a power of two 48562306a36Sopenharmony_ci * @allocation: returned blocks won't cross this boundary (or zero) 48662306a36Sopenharmony_ci * 48762306a36Sopenharmony_ci * Managed dma_pool_create(). DMA pool created with this function is 48862306a36Sopenharmony_ci * automatically destroyed on driver detach. 48962306a36Sopenharmony_ci * 49062306a36Sopenharmony_ci * Return: a managed dma allocation pool with the requested 49162306a36Sopenharmony_ci * characteristics, or %NULL if one can't be created. 49262306a36Sopenharmony_ci */ 49362306a36Sopenharmony_cistruct dma_pool *dmam_pool_create(const char *name, struct device *dev, 49462306a36Sopenharmony_ci size_t size, size_t align, size_t allocation) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct dma_pool **ptr, *pool; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL); 49962306a36Sopenharmony_ci if (!ptr) 50062306a36Sopenharmony_ci return NULL; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci pool = *ptr = dma_pool_create(name, dev, size, align, allocation); 50362306a36Sopenharmony_ci if (pool) 50462306a36Sopenharmony_ci devres_add(dev, ptr); 50562306a36Sopenharmony_ci else 50662306a36Sopenharmony_ci devres_free(ptr); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return pool; 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ciEXPORT_SYMBOL(dmam_pool_create); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci/** 51362306a36Sopenharmony_ci * dmam_pool_destroy - Managed dma_pool_destroy() 51462306a36Sopenharmony_ci * @pool: dma pool that will be destroyed 51562306a36Sopenharmony_ci * 51662306a36Sopenharmony_ci * Managed dma_pool_destroy(). 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_civoid dmam_pool_destroy(struct dma_pool *pool) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct device *dev = pool->dev; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci WARN_ON(devres_release(dev, dmam_pool_release, dmam_pool_match, pool)); 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ciEXPORT_SYMBOL(dmam_pool_destroy); 525