aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/dma-mapping.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-01-20 02:00:26 -0500
committerJeff Garzik <jeff@garzik.org>2007-02-09 17:39:36 -0500
commit9ac7849e35f705830f7b016ff272b0ff1f7ff759 (patch)
tree7f17cdff87e154937a15cc2ec8da9b4e6018ce8e /drivers/base/dma-mapping.c
parent77a527eadb425b60db3f5f0aae6a4c51c38e35e5 (diff)
devres: device resource management
Implement device resource management, in short, devres. A device driver can allocate arbirary size of devres data which is associated with a release function. On driver detach, release function is invoked on the devres data, then, devres data is freed. devreses are typed by associated release functions. Some devreses are better represented by single instance of the type while others need multiple instances sharing the same release function. Both usages are supported. devreses can be grouped using devres group such that a device driver can easily release acquired resources halfway through initialization or selectively release resources (e.g. resources for port 1 out of 4 ports). This patch adds devres core including documentation and the following managed interfaces. * alloc/free : devm_kzalloc(), devm_kzfree() * IO region : devm_request_region(), devm_release_region() * IRQ : devm_request_irq(), devm_free_irq() * DMA : dmam_alloc_coherent(), dmam_free_coherent(), dmam_declare_coherent_memory(), dmam_pool_create(), dmam_pool_destroy() * PCI : pcim_enable_device(), pcim_pin_device(), pci_is_managed() * iomap : devm_ioport_map(), devm_ioport_unmap(), devm_ioremap(), devm_ioremap_nocache(), devm_iounmap(), pcim_iomap_table(), pcim_iomap(), pcim_iounmap() Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/base/dma-mapping.c')
-rw-r--r--drivers/base/dma-mapping.c218
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 */
15struct dma_devres {
16 size_t size;
17 void *vaddr;
18 dma_addr_t dma_handle;
19};
20
21static 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
28static 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
35static 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 */
60void * 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}
84EXPORT_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 */
95void 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}
104EXPORT_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 */
119void *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}
143EXPORT_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 */
154void 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}
163EXPORT_SYMBOL(dmam_free_noncoherent);
164
165#ifdef ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
166
167static 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 */
185int 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}
204EXPORT_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 */
212void dmam_release_declared_memory(struct device *dev)
213{
214 WARN_ON(devres_destroy(dev, dmam_coherent_decl_release, NULL, NULL));
215}
216EXPORT_SYMBOL(dmam_release_declared_memory);
217
218#endif