11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DMA memory management for framework level HCD code (hc_driver) 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This implementation plugs in through generic "usb_bus" level methods, 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and should work with all USB controllers, regardles of bus type. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 130828376deadb93f2e839900065f536ddc1190e73Tobias Ollmann#include <linux/io.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dmapool.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 1727729aadd31dafddaaf64c24f8ef6d0ff750f3aaEric Lescouet#include <linux/usb/hcd.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DMA-Coherent Buffers 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* FIXME tune these based on pool statistics ... */ 250828376deadb93f2e839900065f536ddc1190e73Tobias Ollmannstatic const size_t pool_max[HCD_BUFFER_POOLS] = { 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* platforms without dma-friendly caches might need to 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prevent cacheline sharing... 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32, 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 128, 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 512, 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PAGE_SIZE / 2 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bigger --> allocate pages */ 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SETUP primitives */ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hcd_buffer_create - initialize buffer pools 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @hcd: the bus whose buffer pools are to be initialized 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Context: !in_interrupt() 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Call this as part of initializing a host controller that uses the dma 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * memory allocators. It initializes some pools of dma-coherent memory that 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will be shared by all drivers using that controller, or returns a negative 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * errno value on error. 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Call hcd_buffer_destroy() to clean up after using those pools. 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 511a68f71d4fe71426a5c9703591e068241c03f896Oliver Neukumint hcd_buffer_create(struct usb_hcd *hcd) 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 531a68f71d4fe71426a5c9703591e068241c03f896Oliver Neukum char name[16]; 540828376deadb93f2e839900065f536ddc1190e73Tobias Ollmann int i, size; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56b3476675320eda83cf061a686cdc80b76f2bfdc4Magnus Damm if (!hcd->self.controller->dma_mask && 57b3476675320eda83cf061a686cdc80b76f2bfdc4Magnus Damm !(hcd->driver->flags & HCD_LOCAL_MEM)) 58bd39b7f195e5a780a3c6710eb1c1450f158a1f31Chris Humbert return 0; 59bd39b7f195e5a780a3c6710eb1c1450f158a1f31Chris Humbert 602c044a4803804708984931bcbd03314732e995d5Greg Kroah-Hartman for (i = 0; i < HCD_BUFFER_POOLS; i++) { 612c044a4803804708984931bcbd03314732e995d5Greg Kroah-Hartman size = pool_max[i]; 622c044a4803804708984931bcbd03314732e995d5Greg Kroah-Hartman if (!size) 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 641a68f71d4fe71426a5c9703591e068241c03f896Oliver Neukum snprintf(name, sizeof name, "buffer-%d", size); 651a68f71d4fe71426a5c9703591e068241c03f896Oliver Neukum hcd->pool[i] = dma_pool_create(name, hcd->self.controller, 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size, size, 0); 670828376deadb93f2e839900065f536ddc1190e73Tobias Ollmann if (!hcd->pool[i]) { 681a68f71d4fe71426a5c9703591e068241c03f896Oliver Neukum hcd_buffer_destroy(hcd); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hcd_buffer_destroy - deallocate buffer pools 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @hcd: the bus whose buffer pools are to be destroyed 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Context: !in_interrupt() 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This frees the buffer pools created by hcd_buffer_create(). 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 831a68f71d4fe71426a5c9703591e068241c03f896Oliver Neukumvoid hcd_buffer_destroy(struct usb_hcd *hcd) 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 852c044a4803804708984931bcbd03314732e995d5Greg Kroah-Hartman int i; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 872c044a4803804708984931bcbd03314732e995d5Greg Kroah-Hartman for (i = 0; i < HCD_BUFFER_POOLS; i++) { 882c044a4803804708984931bcbd03314732e995d5Greg Kroah-Hartman struct dma_pool *pool = hcd->pool[i]; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pool) { 901a68f71d4fe71426a5c9703591e068241c03f896Oliver Neukum dma_pool_destroy(pool); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hcd->pool[i] = NULL; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 97441e143e95f5aa1e04026cb0aa71c801ba53982fChristoph Lameter/* sometimes alloc/free could use kmalloc with GFP_DMA, for 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * better sharing and to leverage mm/slab.c intelligence. 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011a68f71d4fe71426a5c9703591e068241c03f896Oliver Neukumvoid *hcd_buffer_alloc( 1020828376deadb93f2e839900065f536ddc1190e73Tobias Ollmann struct usb_bus *bus, 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size, 10455016f10e31bb15b85d8c500f979dfdceb37d548Al Viro gfp_t mem_flags, 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t *dma 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1081720058343fa43a1a25bfad9e62ea06e7e9743b6Alan Stern struct usb_hcd *hcd = bus_to_hcd(bus); 1090828376deadb93f2e839900065f536ddc1190e73Tobias Ollmann int i; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* some USB hosts just use PIO */ 112b3476675320eda83cf061a686cdc80b76f2bfdc4Magnus Damm if (!bus->controller->dma_mask && 113b3476675320eda83cf061a686cdc80b76f2bfdc4Magnus Damm !(hcd->driver->flags & HCD_LOCAL_MEM)) { 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dma = ~(dma_addr_t) 0; 1151a68f71d4fe71426a5c9703591e068241c03f896Oliver Neukum return kmalloc(size, mem_flags); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < HCD_BUFFER_POOLS; i++) { 1190828376deadb93f2e839900065f536ddc1190e73Tobias Ollmann if (size <= pool_max[i]) 1200828376deadb93f2e839900065f536ddc1190e73Tobias Ollmann return dma_pool_alloc(hcd->pool[i], mem_flags, dma); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 122a8aa401f38cfb5fa26e970b48e93fb851d68fe64Johannes Berg return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags); 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251a68f71d4fe71426a5c9703591e068241c03f896Oliver Neukumvoid hcd_buffer_free( 1260828376deadb93f2e839900065f536ddc1190e73Tobias Ollmann struct usb_bus *bus, 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size, 1280828376deadb93f2e839900065f536ddc1190e73Tobias Ollmann void *addr, 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t dma 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1321720058343fa43a1a25bfad9e62ea06e7e9743b6Alan Stern struct usb_hcd *hcd = bus_to_hcd(bus); 1330828376deadb93f2e839900065f536ddc1190e73Tobias Ollmann int i; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!addr) 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 138b3476675320eda83cf061a686cdc80b76f2bfdc4Magnus Damm if (!bus->controller->dma_mask && 139b3476675320eda83cf061a686cdc80b76f2bfdc4Magnus Damm !(hcd->driver->flags & HCD_LOCAL_MEM)) { 1401a68f71d4fe71426a5c9703591e068241c03f896Oliver Neukum kfree(addr); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < HCD_BUFFER_POOLS; i++) { 1450828376deadb93f2e839900065f536ddc1190e73Tobias Ollmann if (size <= pool_max[i]) { 1460828376deadb93f2e839900065f536ddc1190e73Tobias Ollmann dma_pool_free(hcd->pool[i], addr, dma); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1501a68f71d4fe71426a5c9703591e068241c03f896Oliver Neukum dma_free_coherent(hcd->self.controller, size, addr, dma); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 152