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
99		if (pool) {
100			dma_pool_destroy(pool);
101			hcd->pool[i] = NULL;
102		}
103	}
104}
105
106
107/* sometimes alloc/free could use kmalloc with GFP_DMA, for
108 * better sharing and to leverage mm/slab.c intelligence.
109 */
110
111void *hcd_buffer_alloc(
112	struct usb_bus		*bus,
113	size_t			size,
114	gfp_t			mem_flags,
115	dma_addr_t		*dma
116)
117{
118	struct usb_hcd		*hcd = bus_to_hcd(bus);
119	int			i;
120
121	/* some USB hosts just use PIO */
122	if (!bus->controller->dma_mask &&
123	    !(hcd->driver->flags & HCD_LOCAL_MEM)) {
124		*dma = ~(dma_addr_t) 0;
125		return kmalloc(size, mem_flags);
126	}
127
128	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
129		if (size <= pool_max[i])
130			return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
131	}
132	return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags);
133}
134
135void hcd_buffer_free(
136	struct usb_bus		*bus,
137	size_t			size,
138	void			*addr,
139	dma_addr_t		dma
140)
141{
142	struct usb_hcd		*hcd = bus_to_hcd(bus);
143	int			i;
144
145	if (!addr)
146		return;
147
148	if (!bus->controller->dma_mask &&
149	    !(hcd->driver->flags & HCD_LOCAL_MEM)) {
150		kfree(addr);
151		return;
152	}
153
154	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
155		if (size <= pool_max[i]) {
156			dma_pool_free(hcd->pool[i], addr, dma);
157			return;
158		}
159	}
160	dma_free_coherent(hcd->self.controller, size, addr, dma);
161}
162