1/*
2 * DMA memory management for framework level HCD code (hc_driver)
3 *
4 * This implementation plugs in through generic "usb_bus" level methods,
5 * and should work with all USB controllers, regardless of bus type.
6 */
7
8#include <linux/module.h>
9#include <linux/kernel.h>
10#include <linux/slab.h>
11#include <linux/device.h>
12#include <linux/mm.h>
13#include <linux/io.h>
14#include <linux/dma-mapping.h>
15#include <linux/dmapool.h>
16#include <linux/usb.h>
17#include <linux/usb/hcd.h>
18
19
20/*
21 * DMA-Coherent Buffers
22 */
23
24/* FIXME tune these based on pool statistics ... */
25static size_t pool_max[HCD_BUFFER_POOLS] = {
26	32, 128, 512, 2048,
27};
28
29void __init usb_init_pool_max(void)
30{
31	/*
32	 * The pool_max values must never be smaller than
33	 * ARCH_KMALLOC_MINALIGN.
34	 */
35	if (ARCH_KMALLOC_MINALIGN <= 32)
36		;			/* Original value is okay */
37	else if (ARCH_KMALLOC_MINALIGN <= 64)
38		pool_max[0] = 64;
39	else if (ARCH_KMALLOC_MINALIGN <= 128)
40		pool_max[0] = 0;	/* Don't use this pool */
41	else
42		BUILD_BUG();		/* We don't allow this */
43}
44
45/* SETUP primitives */
46
47/**
48 * hcd_buffer_create - initialize buffer pools
49 * @hcd: the bus whose buffer pools are to be initialized
50 * Context: !in_interrupt()
51 *
52 * Call this as part of initializing a host controller that uses the dma
53 * memory allocators.  It initializes some pools of dma-coherent memory that
54 * will be shared by all drivers using that controller.
55 *
56 * Call hcd_buffer_destroy() to clean up after using those pools.
57 *
58 * Return: 0 if successful. A negative errno value otherwise.
59 */
60int hcd_buffer_create(struct usb_hcd *hcd)
61{
62	char		name[16];
63	int		i, size;
64
65	if (!hcd->self.controller->dma_mask &&
66	    !(hcd->driver->flags & HCD_LOCAL_MEM))
67		return 0;
68
69	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
70		size = pool_max[i];
71		if (!size)
72			continue;
73		snprintf(name, sizeof name, "buffer-%d", size);
74		hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
75				size, size, 0);
76		if (!hcd->pool[i]) {
77			hcd_buffer_destroy(hcd);
78			return -ENOMEM;
79		}
80	}
81	return 0;
82}
83
84
85/**
86 * hcd_buffer_destroy - deallocate buffer pools
87 * @hcd: the bus whose buffer pools are to be destroyed
88 * Context: !in_interrupt()
89 *
90 * This frees the buffer pools created by hcd_buffer_create().
91 */
92void hcd_buffer_destroy(struct usb_hcd *hcd)
93{
94	int i;
95
96	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
97		struct dma_pool *pool = hcd->pool[i];
98		if (pool) {
99			dma_pool_destroy(pool);
100			hcd->pool[i] = NULL;
101		}
102	}
103}
104
105
106/* sometimes alloc/free could use kmalloc with GFP_DMA, for
107 * better sharing and to leverage mm/slab.c intelligence.
108 */
109
110void *hcd_buffer_alloc(
111	struct usb_bus		*bus,
112	size_t			size,
113	gfp_t			mem_flags,
114	dma_addr_t		*dma
115)
116{
117	struct usb_hcd		*hcd = bus_to_hcd(bus);
118	int			i;
119
120	/* some USB hosts just use PIO */
121	if (!bus->controller->dma_mask &&
122	    !(hcd->driver->flags & HCD_LOCAL_MEM)) {
123		*dma = ~(dma_addr_t) 0;
124		return kmalloc(size, mem_flags);
125	}
126
127	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
128		if (size <= pool_max[i])
129			return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
130	}
131	return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags);
132}
133
134void hcd_buffer_free(
135	struct usb_bus		*bus,
136	size_t			size,
137	void			*addr,
138	dma_addr_t		dma
139)
140{
141	struct usb_hcd		*hcd = bus_to_hcd(bus);
142	int			i;
143
144	if (!addr)
145		return;
146
147	if (!bus->controller->dma_mask &&
148	    !(hcd->driver->flags & HCD_LOCAL_MEM)) {
149		kfree(addr);
150		return;
151	}
152
153	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
154		if (size <= pool_max[i]) {
155			dma_pool_free(hcd->pool[i], addr, dma);
156			return;
157		}
158	}
159	dma_free_coherent(hcd->self.controller, size, addr, dma);
160}
161