diff options
Diffstat (limited to 'drivers/base/dma-mapping.c')
-rw-r--r-- | drivers/base/dma-mapping.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c new file mode 100644 index 000000000000..ca9186f70a69 --- /dev/null +++ b/drivers/base/dma-mapping.c | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
2 | * drivers/base/dma-mapping.c - arch-independent dma-mapping routines | ||
3 | * | ||
4 | * Copyright (c) 2006 SUSE Linux Products GmbH | ||
5 | * Copyright (c) 2006 Tejun Heo <teheo@suse.de> | ||
6 | * | ||
7 | * This file is released under the GPLv2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/dma-mapping.h> | ||
11 | |||
12 | /* | ||
13 | * Managed DMA API | ||
14 | */ | ||
15 | struct dma_devres { | ||
16 | size_t size; | ||
17 | void *vaddr; | ||
18 | dma_addr_t dma_handle; | ||
19 | }; | ||
20 | |||
21 | static void dmam_coherent_release(struct device *dev, void *res) | ||
22 | { | ||
23 | struct dma_devres *this = res; | ||
24 | |||
25 | dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle); | ||
26 | } | ||
27 | |||
28 | static void dmam_noncoherent_release(struct device *dev, void *res) | ||
29 | { | ||
30 | struct dma_devres *this = res; | ||
31 | |||
32 | dma_free_noncoherent(dev, this->size, this->vaddr, this->dma_handle); | ||
33 | } | ||
34 | |||
35 | static int dmam_match(struct device *dev, void *res, void *match_data) | ||
36 | { | ||
37 | struct dma_devres *this = res, *match = match_data; | ||
38 | |||
39 | if (this->vaddr == match->vaddr) { | ||
40 | WARN_ON(this->size != match->size || | ||
41 | this->dma_handle != match->dma_handle); | ||
42 | return 1; | ||
43 | } | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * dmam_alloc_coherent - Managed dma_alloc_coherent() | ||
49 | * @dev: Device to allocate coherent memory for | ||
50 | * @size: Size of allocation | ||
51 | * @dma_handle: Out argument for allocated DMA handle | ||
52 | * @gfp: Allocation flags | ||
53 | * | ||
54 | * Managed dma_alloc_coherent(). Memory allocated using this function | ||
55 | * will be automatically released on driver detach. | ||
56 | * | ||
57 | * RETURNS: | ||
58 | * Pointer to allocated memory on success, NULL on failure. | ||
59 | */ | ||
60 | void * dmam_alloc_coherent(struct device *dev, size_t size, | ||
61 | dma_addr_t *dma_handle, gfp_t gfp) | ||
62 | { | ||
63 | struct dma_devres *dr; | ||
64 | void *vaddr; | ||
65 | |||
66 | dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp); | ||
67 | if (!dr) | ||
68 | return NULL; | ||
69 | |||
70 | vaddr = dma_alloc_coherent(dev, size, dma_handle, gfp); | ||
71 | if (!vaddr) { | ||
72 | devres_free(dr); | ||
73 | return NULL; | ||
74 | } | ||
75 | |||
76 | dr->vaddr = vaddr; | ||
77 | dr->dma_handle = *dma_handle; | ||
78 | dr->size = size; | ||
79 | |||
80 | devres_add(dev, dr); | ||
81 | |||
82 | return vaddr; | ||
83 | } | ||
84 | EXPORT_SYMBOL(dmam_alloc_coherent); | ||
85 | |||
86 | /** | ||
87 | * dmam_free_coherent - Managed dma_free_coherent() | ||
88 | * @dev: Device to free coherent memory for | ||
89 | * @size: Size of allocation | ||
90 | * @vaddr: Virtual address of the memory to free | ||
91 | * @dma_handle: DMA handle of the memory to free | ||
92 | * | ||
93 | * Managed dma_free_coherent(). | ||
94 | */ | ||
95 | void dmam_free_coherent(struct device *dev, size_t size, void *vaddr, | ||
96 | dma_addr_t dma_handle) | ||
97 | { | ||
98 | struct dma_devres match_data = { size, vaddr, dma_handle }; | ||
99 | |||
100 | dma_free_coherent(dev, size, vaddr, dma_handle); | ||
101 | WARN_ON(devres_destroy(dev, dmam_coherent_release, dmam_match, | ||
102 | &match_data)); | ||
103 | } | ||
104 | EXPORT_SYMBOL(dmam_free_coherent); | ||
105 | |||
106 | /** | ||
107 | * dmam_alloc_non_coherent - Managed dma_alloc_non_coherent() | ||
108 | * @dev: Device to allocate non_coherent memory for | ||
109 | * @size: Size of allocation | ||
110 | * @dma_handle: Out argument for allocated DMA handle | ||
111 | * @gfp: Allocation flags | ||
112 | * | ||
113 | * Managed dma_alloc_non_coherent(). Memory allocated using this | ||
114 | * function will be automatically released on driver detach. | ||
115 | * | ||
116 | * RETURNS: | ||
117 | * Pointer to allocated memory on success, NULL on failure. | ||
118 | */ | ||
119 | void *dmam_alloc_noncoherent(struct device *dev, size_t size, | ||
120 | dma_addr_t *dma_handle, gfp_t gfp) | ||
121 | { | ||
122 | struct dma_devres *dr; | ||
123 | void *vaddr; | ||
124 | |||
125 | dr = devres_alloc(dmam_noncoherent_release, sizeof(*dr), gfp); | ||
126 | if (!dr) | ||
127 | return NULL; | ||
128 | |||
129 | vaddr = dma_alloc_noncoherent(dev, size, dma_handle, gfp); | ||
130 | if (!vaddr) { | ||
131 | devres_free(dr); | ||
132 | return NULL; | ||
133 | } | ||
134 | |||
135 | dr->vaddr = vaddr; | ||
136 | dr->dma_handle = *dma_handle; | ||
137 | dr->size = size; | ||
138 | |||
139 | devres_add(dev, dr); | ||
140 | |||
141 | return vaddr; | ||
142 | } | ||
143 | EXPORT_SYMBOL(dmam_alloc_noncoherent); | ||
144 | |||
145 | /** | ||
146 | * dmam_free_coherent - Managed dma_free_noncoherent() | ||
147 | * @dev: Device to free noncoherent memory for | ||
148 | * @size: Size of allocation | ||
149 | * @vaddr: Virtual address of the memory to free | ||
150 | * @dma_handle: DMA handle of the memory to free | ||
151 | * | ||
152 | * Managed dma_free_noncoherent(). | ||
153 | */ | ||
154 | void dmam_free_noncoherent(struct device *dev, size_t size, void *vaddr, | ||
155 | dma_addr_t dma_handle) | ||
156 | { | ||
157 | struct dma_devres match_data = { size, vaddr, dma_handle }; | ||
158 | |||
159 | dma_free_noncoherent(dev, size, vaddr, dma_handle); | ||
160 | WARN_ON(!devres_destroy(dev, dmam_noncoherent_release, dmam_match, | ||
161 | &match_data)); | ||
162 | } | ||
163 | EXPORT_SYMBOL(dmam_free_noncoherent); | ||
164 | |||
165 | #ifdef ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY | ||
166 | |||
167 | static void dmam_coherent_decl_release(struct device *dev, void *res) | ||
168 | { | ||
169 | dma_release_declared_memory(dev); | ||
170 | } | ||
171 | |||
172 | /** | ||
173 | * dmam_declare_coherent_memory - Managed dma_declare_coherent_memory() | ||
174 | * @dev: Device to declare coherent memory for | ||
175 | * @bus_addr: Bus address of coherent memory to be declared | ||
176 | * @device_addr: Device address of coherent memory to be declared | ||
177 | * @size: Size of coherent memory to be declared | ||
178 | * @flags: Flags | ||
179 | * | ||
180 | * Managed dma_declare_coherent_memory(). | ||
181 | * | ||
182 | * RETURNS: | ||
183 | * 0 on success, -errno on failure. | ||
184 | */ | ||
185 | int dmam_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
186 | dma_addr_t device_addr, size_t size, int flags) | ||
187 | { | ||
188 | void *res; | ||
189 | int rc; | ||
190 | |||
191 | res = devres_alloc(dmam_coherent_decl_release, 0, GFP_KERNEL); | ||
192 | if (!res) | ||
193 | return -ENOMEM; | ||
194 | |||
195 | rc = dma_declare_coherent_memory(dev, bus_addr, device_addr, size, | ||
196 | flags); | ||
197 | if (rc == 0) | ||
198 | devres_add(dev, res); | ||
199 | else | ||
200 | devres_free(res); | ||
201 | |||
202 | return rc; | ||
203 | } | ||
204 | EXPORT_SYMBOL(dmam_declare_coherent_memory); | ||
205 | |||
206 | /** | ||
207 | * dmam_release_declared_memory - Managed dma_release_declared_memory(). | ||
208 | * @dev: Device to release declared coherent memory for | ||
209 | * | ||
210 | * Managed dmam_release_declared_memory(). | ||
211 | */ | ||
212 | void dmam_release_declared_memory(struct device *dev) | ||
213 | { | ||
214 | WARN_ON(devres_destroy(dev, dmam_coherent_decl_release, NULL, NULL)); | ||
215 | } | ||
216 | EXPORT_SYMBOL(dmam_release_declared_memory); | ||
217 | |||
218 | #endif | ||