162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * DMA memory management for framework level HCD code (hc_driver) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This implementation plugs in through generic "usb_bus" level methods, 662306a36Sopenharmony_ci * and should work with all USB controllers, regardless of bus type. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Released under the GPLv2 only. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/device.h> 1562306a36Sopenharmony_ci#include <linux/mm.h> 1662306a36Sopenharmony_ci#include <linux/io.h> 1762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1862306a36Sopenharmony_ci#include <linux/dmapool.h> 1962306a36Sopenharmony_ci#include <linux/genalloc.h> 2062306a36Sopenharmony_ci#include <linux/usb.h> 2162306a36Sopenharmony_ci#include <linux/usb/hcd.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * DMA-Coherent Buffers 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* FIXME tune these based on pool statistics ... */ 2962306a36Sopenharmony_cistatic size_t pool_max[HCD_BUFFER_POOLS] = { 3062306a36Sopenharmony_ci 32, 128, 512, 2048, 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_civoid __init usb_init_pool_max(void) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci /* 3662306a36Sopenharmony_ci * The pool_max values must never be smaller than 3762306a36Sopenharmony_ci * ARCH_DMA_MINALIGN. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci if (ARCH_DMA_MINALIGN <= 32) 4062306a36Sopenharmony_ci ; /* Original value is okay */ 4162306a36Sopenharmony_ci else if (ARCH_DMA_MINALIGN <= 64) 4262306a36Sopenharmony_ci pool_max[0] = 64; 4362306a36Sopenharmony_ci else if (ARCH_DMA_MINALIGN <= 128) 4462306a36Sopenharmony_ci pool_max[0] = 0; /* Don't use this pool */ 4562306a36Sopenharmony_ci else 4662306a36Sopenharmony_ci BUILD_BUG(); /* We don't allow this */ 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* SETUP primitives */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/** 5262306a36Sopenharmony_ci * hcd_buffer_create - initialize buffer pools 5362306a36Sopenharmony_ci * @hcd: the bus whose buffer pools are to be initialized 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * Context: task context, might sleep 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * Call this as part of initializing a host controller that uses the dma 5862306a36Sopenharmony_ci * memory allocators. It initializes some pools of dma-coherent memory that 5962306a36Sopenharmony_ci * will be shared by all drivers using that controller. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * Call hcd_buffer_destroy() to clean up after using those pools. 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * Return: 0 if successful. A negative errno value otherwise. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ciint hcd_buffer_create(struct usb_hcd *hcd) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci char name[16]; 6862306a36Sopenharmony_ci int i, size; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (hcd->localmem_pool || !hcd_uses_dma(hcd)) 7162306a36Sopenharmony_ci return 0; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci for (i = 0; i < HCD_BUFFER_POOLS; i++) { 7462306a36Sopenharmony_ci size = pool_max[i]; 7562306a36Sopenharmony_ci if (!size) 7662306a36Sopenharmony_ci continue; 7762306a36Sopenharmony_ci snprintf(name, sizeof(name), "buffer-%d", size); 7862306a36Sopenharmony_ci hcd->pool[i] = dma_pool_create(name, hcd->self.sysdev, 7962306a36Sopenharmony_ci size, size, 0); 8062306a36Sopenharmony_ci if (!hcd->pool[i]) { 8162306a36Sopenharmony_ci hcd_buffer_destroy(hcd); 8262306a36Sopenharmony_ci return -ENOMEM; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci return 0; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/** 9062306a36Sopenharmony_ci * hcd_buffer_destroy - deallocate buffer pools 9162306a36Sopenharmony_ci * @hcd: the bus whose buffer pools are to be destroyed 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * Context: task context, might sleep 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * This frees the buffer pools created by hcd_buffer_create(). 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_civoid hcd_buffer_destroy(struct usb_hcd *hcd) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci int i; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_HAS_DMA)) 10262306a36Sopenharmony_ci return; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci for (i = 0; i < HCD_BUFFER_POOLS; i++) { 10562306a36Sopenharmony_ci dma_pool_destroy(hcd->pool[i]); 10662306a36Sopenharmony_ci hcd->pool[i] = NULL; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* sometimes alloc/free could use kmalloc with GFP_DMA, for 11262306a36Sopenharmony_ci * better sharing and to leverage mm/slab.c intelligence. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_civoid *hcd_buffer_alloc( 11662306a36Sopenharmony_ci struct usb_bus *bus, 11762306a36Sopenharmony_ci size_t size, 11862306a36Sopenharmony_ci gfp_t mem_flags, 11962306a36Sopenharmony_ci dma_addr_t *dma 12062306a36Sopenharmony_ci) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct usb_hcd *hcd = bus_to_hcd(bus); 12362306a36Sopenharmony_ci int i; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (size == 0) 12662306a36Sopenharmony_ci return NULL; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (hcd->localmem_pool) 12962306a36Sopenharmony_ci return gen_pool_dma_alloc(hcd->localmem_pool, size, dma); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* some USB hosts just use PIO */ 13262306a36Sopenharmony_ci if (!hcd_uses_dma(hcd)) { 13362306a36Sopenharmony_ci *dma = ~(dma_addr_t) 0; 13462306a36Sopenharmony_ci return kmalloc(size, mem_flags); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci for (i = 0; i < HCD_BUFFER_POOLS; i++) { 13862306a36Sopenharmony_ci if (size <= pool_max[i]) 13962306a36Sopenharmony_ci return dma_pool_alloc(hcd->pool[i], mem_flags, dma); 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci return dma_alloc_coherent(hcd->self.sysdev, size, dma, mem_flags); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_civoid hcd_buffer_free( 14562306a36Sopenharmony_ci struct usb_bus *bus, 14662306a36Sopenharmony_ci size_t size, 14762306a36Sopenharmony_ci void *addr, 14862306a36Sopenharmony_ci dma_addr_t dma 14962306a36Sopenharmony_ci) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct usb_hcd *hcd = bus_to_hcd(bus); 15262306a36Sopenharmony_ci int i; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (!addr) 15562306a36Sopenharmony_ci return; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (hcd->localmem_pool) { 15862306a36Sopenharmony_ci gen_pool_free(hcd->localmem_pool, (unsigned long)addr, size); 15962306a36Sopenharmony_ci return; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (!hcd_uses_dma(hcd)) { 16362306a36Sopenharmony_ci kfree(addr); 16462306a36Sopenharmony_ci return; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci for (i = 0; i < HCD_BUFFER_POOLS; i++) { 16862306a36Sopenharmony_ci if (size <= pool_max[i]) { 16962306a36Sopenharmony_ci dma_pool_free(hcd->pool[i], addr, dma); 17062306a36Sopenharmony_ci return; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci dma_free_coherent(hcd->self.sysdev, size, addr, dma); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_civoid *hcd_buffer_alloc_pages(struct usb_hcd *hcd, 17762306a36Sopenharmony_ci size_t size, gfp_t mem_flags, dma_addr_t *dma) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci if (size == 0) 18062306a36Sopenharmony_ci return NULL; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (hcd->localmem_pool) 18362306a36Sopenharmony_ci return gen_pool_dma_alloc_align(hcd->localmem_pool, 18462306a36Sopenharmony_ci size, dma, PAGE_SIZE); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* some USB hosts just use PIO */ 18762306a36Sopenharmony_ci if (!hcd_uses_dma(hcd)) { 18862306a36Sopenharmony_ci *dma = DMA_MAPPING_ERROR; 18962306a36Sopenharmony_ci return (void *)__get_free_pages(mem_flags, 19062306a36Sopenharmony_ci get_order(size)); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return dma_alloc_coherent(hcd->self.sysdev, 19462306a36Sopenharmony_ci size, dma, mem_flags); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_civoid hcd_buffer_free_pages(struct usb_hcd *hcd, 19862306a36Sopenharmony_ci size_t size, void *addr, dma_addr_t dma) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci if (!addr) 20162306a36Sopenharmony_ci return; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (hcd->localmem_pool) { 20462306a36Sopenharmony_ci gen_pool_free(hcd->localmem_pool, 20562306a36Sopenharmony_ci (unsigned long)addr, size); 20662306a36Sopenharmony_ci return; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (!hcd_uses_dma(hcd)) { 21062306a36Sopenharmony_ci free_pages((unsigned long)addr, get_order(size)); 21162306a36Sopenharmony_ci return; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci dma_free_coherent(hcd->self.sysdev, size, addr, dma); 21562306a36Sopenharmony_ci} 216