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