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