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> | |
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 |