1
2
3
4
5
6
7
8
9
10
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/slab.h>
14#include <linux/device.h>
15#include <linux/mm.h>
16#include <linux/io.h>
17#include <linux/dma-mapping.h>
18#include <linux/dmapool.h>
19#include <linux/usb.h>
20#include <linux/usb/hcd.h>
21
22
23
24
25
26
27
28static size_t pool_max[HCD_BUFFER_POOLS] = {
29 32, 128, 512, 2048,
30};
31
32void __init usb_init_pool_max(void)
33{
34
35
36
37
38 if (ARCH_KMALLOC_MINALIGN <= 32)
39 ;
40 else if (ARCH_KMALLOC_MINALIGN <= 64)
41 pool_max[0] = 64;
42 else if (ARCH_KMALLOC_MINALIGN <= 128)
43 pool_max[0] = 0;
44 else
45 BUILD_BUG();
46}
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63int hcd_buffer_create(struct usb_hcd *hcd)
64{
65 char name[16];
66 int i, size;
67
68 if (!IS_ENABLED(CONFIG_HAS_DMA) ||
69 (!is_device_dma_capable(hcd->self.sysdev) &&
70 !(hcd->driver->flags & HCD_LOCAL_MEM)))
71 return 0;
72
73 for (i = 0; i < HCD_BUFFER_POOLS; i++) {
74 size = pool_max[i];
75 if (!size)
76 continue;
77 snprintf(name, sizeof(name), "buffer-%d", size);
78 hcd->pool[i] = dma_pool_create(name, hcd->self.sysdev,
79 size, size, 0);
80 if (!hcd->pool[i]) {
81 hcd_buffer_destroy(hcd);
82 return -ENOMEM;
83 }
84 }
85 return 0;
86}
87
88
89
90
91
92
93
94
95
96void hcd_buffer_destroy(struct usb_hcd *hcd)
97{
98 int i;
99
100 if (!IS_ENABLED(CONFIG_HAS_DMA))
101 return;
102
103 for (i = 0; i < HCD_BUFFER_POOLS; i++) {
104 struct dma_pool *pool = hcd->pool[i];
105
106 if (pool) {
107 dma_pool_destroy(pool);
108 hcd->pool[i] = NULL;
109 }
110 }
111}
112
113
114
115
116
117
118void *hcd_buffer_alloc(
119 struct usb_bus *bus,
120 size_t size,
121 gfp_t mem_flags,
122 dma_addr_t *dma
123)
124{
125 struct usb_hcd *hcd = bus_to_hcd(bus);
126 int i;
127
128 if (size == 0)
129 return NULL;
130
131
132 if (!IS_ENABLED(CONFIG_HAS_DMA) ||
133 (!is_device_dma_capable(bus->sysdev) &&
134 !(hcd->driver->flags & HCD_LOCAL_MEM))) {
135 *dma = ~(dma_addr_t) 0;
136 return kmalloc(size, mem_flags);
137 }
138
139 for (i = 0; i < HCD_BUFFER_POOLS; i++) {
140 if (size <= pool_max[i])
141 return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
142 }
143 return dma_alloc_coherent(hcd->self.sysdev, size, dma, mem_flags);
144}
145
146void hcd_buffer_free(
147 struct usb_bus *bus,
148 size_t size,
149 void *addr,
150 dma_addr_t dma
151)
152{
153 struct usb_hcd *hcd = bus_to_hcd(bus);
154 int i;
155
156 if (!addr)
157 return;
158
159 if (!IS_ENABLED(CONFIG_HAS_DMA) ||
160 (!is_device_dma_capable(bus->sysdev) &&
161 !(hcd->driver->flags & HCD_LOCAL_MEM))) {
162 kfree(addr);
163 return;
164 }
165
166 for (i = 0; i < HCD_BUFFER_POOLS; i++) {
167 if (size <= pool_max[i]) {
168 dma_pool_free(hcd->pool[i], addr, dma);
169 return;
170 }
171 }
172 dma_free_coherent(hcd->self.sysdev, size, addr, dma);
173}
174