xref: /linux/drivers/usb/core/buffer.c (revision 14b42963f64b98ab61fa9723c03d71aa5ef4f862)
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, regardles 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 <asm/io.h>
14 #include <asm/scatterlist.h>
15 #include <linux/dma-mapping.h>
16 #include <linux/dmapool.h>
17 #include <linux/usb.h>
18 #include "hcd.h"
19 
20 
21 /*
22  * DMA-Coherent Buffers
23  */
24 
25 /* FIXME tune these based on pool statistics ... */
26 static const size_t	pool_max [HCD_BUFFER_POOLS] = {
27 	/* platforms without dma-friendly caches might need to
28 	 * prevent cacheline sharing...
29 	 */
30 	32,
31 	128,
32 	512,
33 	PAGE_SIZE / 2
34 	/* bigger --> allocate pages */
35 };
36 
37 
38 /* SETUP primitives */
39 
40 /**
41  * hcd_buffer_create - initialize buffer pools
42  * @hcd: the bus whose buffer pools are to be initialized
43  * Context: !in_interrupt()
44  *
45  * Call this as part of initializing a host controller that uses the dma
46  * memory allocators.  It initializes some pools of dma-coherent memory that
47  * will be shared by all drivers using that controller, or returns a negative
48  * errno value on error.
49  *
50  * Call hcd_buffer_destroy() to clean up after using those pools.
51  */
52 int hcd_buffer_create (struct usb_hcd *hcd)
53 {
54 	char		name [16];
55 	int 		i, size;
56 
57 	if (!hcd->self.controller->dma_mask)
58 		return 0;
59 
60 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
61 		if (!(size = pool_max [i]))
62 			continue;
63 		snprintf (name, sizeof name, "buffer-%d", size);
64 		hcd->pool [i] = dma_pool_create (name, hcd->self.controller,
65 				size, size, 0);
66 		if (!hcd->pool [i]) {
67 			hcd_buffer_destroy (hcd);
68 			return -ENOMEM;
69 		}
70 	}
71 	return 0;
72 }
73 
74 
75 /**
76  * hcd_buffer_destroy - deallocate buffer pools
77  * @hcd: the bus whose buffer pools are to be destroyed
78  * Context: !in_interrupt()
79  *
80  * This frees the buffer pools created by hcd_buffer_create().
81  */
82 void hcd_buffer_destroy (struct usb_hcd *hcd)
83 {
84 	int		i;
85 
86 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
87 		struct dma_pool		*pool = hcd->pool [i];
88 		if (pool) {
89 			dma_pool_destroy (pool);
90 			hcd->pool[i] = NULL;
91 		}
92 	}
93 }
94 
95 
96 /* sometimes alloc/free could use kmalloc with SLAB_DMA, for
97  * better sharing and to leverage mm/slab.c intelligence.
98  */
99 
100 void *hcd_buffer_alloc (
101 	struct usb_bus 		*bus,
102 	size_t			size,
103 	gfp_t			mem_flags,
104 	dma_addr_t		*dma
105 )
106 {
107 	struct usb_hcd		*hcd = bus->hcpriv;
108 	int 			i;
109 
110 	/* some USB hosts just use PIO */
111 	if (!bus->controller->dma_mask) {
112 		*dma = ~(dma_addr_t) 0;
113 		return kmalloc (size, mem_flags);
114 	}
115 
116 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
117 		if (size <= pool_max [i])
118 			return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
119 	}
120 	return dma_alloc_coherent (hcd->self.controller, size, dma, 0);
121 }
122 
123 void hcd_buffer_free (
124 	struct usb_bus 		*bus,
125 	size_t			size,
126 	void 			*addr,
127 	dma_addr_t		dma
128 )
129 {
130 	struct usb_hcd		*hcd = bus->hcpriv;
131 	int 			i;
132 
133 	if (!addr)
134 		return;
135 
136 	if (!bus->controller->dma_mask) {
137 		kfree (addr);
138 		return;
139 	}
140 
141 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
142 		if (size <= pool_max [i]) {
143 			dma_pool_free (hcd->pool [i], addr, dma);
144 			return;
145 		}
146 	}
147 	dma_free_coherent (hcd->self.controller, size, addr, dma);
148 }
149