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