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