Commit 8e369672af8700299ab372bad9397f230b1d591a
Exists in
master
and in
6 other branches
Merge branch 'dma-buf-merge' of git://people.freedesktop.org/~airlied/linux
* 'dma-buf-merge' of git://people.freedesktop.org/~airlied/linux: dma-buf: mark EXPERIMENTAL for 1st release. dma-buf: Documentation for buffer sharing framework dma-buf: Introduce dma buffer sharing mechanism
Showing 5 changed files Side-by-side Diff
Documentation/dma-buf-sharing.txt
1 | + DMA Buffer Sharing API Guide | |
2 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
3 | + | |
4 | + Sumit Semwal | |
5 | + <sumit dot semwal at linaro dot org> | |
6 | + <sumit dot semwal at ti dot com> | |
7 | + | |
8 | +This document serves as a guide to device-driver writers on what is the dma-buf | |
9 | +buffer sharing API, how to use it for exporting and using shared buffers. | |
10 | + | |
11 | +Any device driver which wishes to be a part of DMA buffer sharing, can do so as | |
12 | +either the 'exporter' of buffers, or the 'user' of buffers. | |
13 | + | |
14 | +Say a driver A wants to use buffers created by driver B, then we call B as the | |
15 | +exporter, and A as buffer-user. | |
16 | + | |
17 | +The exporter | |
18 | +- implements and manages operations[1] for the buffer | |
19 | +- allows other users to share the buffer by using dma_buf sharing APIs, | |
20 | +- manages the details of buffer allocation, | |
21 | +- decides about the actual backing storage where this allocation happens, | |
22 | +- takes care of any migration of scatterlist - for all (shared) users of this | |
23 | + buffer, | |
24 | + | |
25 | +The buffer-user | |
26 | +- is one of (many) sharing users of the buffer. | |
27 | +- doesn't need to worry about how the buffer is allocated, or where. | |
28 | +- needs a mechanism to get access to the scatterlist that makes up this buffer | |
29 | + in memory, mapped into its own address space, so it can access the same area | |
30 | + of memory. | |
31 | + | |
32 | +*IMPORTANT*: [see https://lkml.org/lkml/2011/12/20/211 for more details] | |
33 | +For this first version, A buffer shared using the dma_buf sharing API: | |
34 | +- *may* be exported to user space using "mmap" *ONLY* by exporter, outside of | |
35 | + this framework. | |
36 | +- may be used *ONLY* by importers that do not need CPU access to the buffer. | |
37 | + | |
38 | +The dma_buf buffer sharing API usage contains the following steps: | |
39 | + | |
40 | +1. Exporter announces that it wishes to export a buffer | |
41 | +2. Userspace gets the file descriptor associated with the exported buffer, and | |
42 | + passes it around to potential buffer-users based on use case | |
43 | +3. Each buffer-user 'connects' itself to the buffer | |
44 | +4. When needed, buffer-user requests access to the buffer from exporter | |
45 | +5. When finished with its use, the buffer-user notifies end-of-DMA to exporter | |
46 | +6. when buffer-user is done using this buffer completely, it 'disconnects' | |
47 | + itself from the buffer. | |
48 | + | |
49 | + | |
50 | +1. Exporter's announcement of buffer export | |
51 | + | |
52 | + The buffer exporter announces its wish to export a buffer. In this, it | |
53 | + connects its own private buffer data, provides implementation for operations | |
54 | + that can be performed on the exported dma_buf, and flags for the file | |
55 | + associated with this buffer. | |
56 | + | |
57 | + Interface: | |
58 | + struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops, | |
59 | + size_t size, int flags) | |
60 | + | |
61 | + If this succeeds, dma_buf_export allocates a dma_buf structure, and returns a | |
62 | + pointer to the same. It also associates an anonymous file with this buffer, | |
63 | + so it can be exported. On failure to allocate the dma_buf object, it returns | |
64 | + NULL. | |
65 | + | |
66 | +2. Userspace gets a handle to pass around to potential buffer-users | |
67 | + | |
68 | + Userspace entity requests for a file-descriptor (fd) which is a handle to the | |
69 | + anonymous file associated with the buffer. It can then share the fd with other | |
70 | + drivers and/or processes. | |
71 | + | |
72 | + Interface: | |
73 | + int dma_buf_fd(struct dma_buf *dmabuf) | |
74 | + | |
75 | + This API installs an fd for the anonymous file associated with this buffer; | |
76 | + returns either 'fd', or error. | |
77 | + | |
78 | +3. Each buffer-user 'connects' itself to the buffer | |
79 | + | |
80 | + Each buffer-user now gets a reference to the buffer, using the fd passed to | |
81 | + it. | |
82 | + | |
83 | + Interface: | |
84 | + struct dma_buf *dma_buf_get(int fd) | |
85 | + | |
86 | + This API will return a reference to the dma_buf, and increment refcount for | |
87 | + it. | |
88 | + | |
89 | + After this, the buffer-user needs to attach its device with the buffer, which | |
90 | + helps the exporter to know of device buffer constraints. | |
91 | + | |
92 | + Interface: | |
93 | + struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, | |
94 | + struct device *dev) | |
95 | + | |
96 | + This API returns reference to an attachment structure, which is then used | |
97 | + for scatterlist operations. It will optionally call the 'attach' dma_buf | |
98 | + operation, if provided by the exporter. | |
99 | + | |
100 | + The dma-buf sharing framework does the bookkeeping bits related to managing | |
101 | + the list of all attachments to a buffer. | |
102 | + | |
103 | +Until this stage, the buffer-exporter has the option to choose not to actually | |
104 | +allocate the backing storage for this buffer, but wait for the first buffer-user | |
105 | +to request use of buffer for allocation. | |
106 | + | |
107 | + | |
108 | +4. When needed, buffer-user requests access to the buffer | |
109 | + | |
110 | + Whenever a buffer-user wants to use the buffer for any DMA, it asks for | |
111 | + access to the buffer using dma_buf_map_attachment API. At least one attach to | |
112 | + the buffer must have happened before map_dma_buf can be called. | |
113 | + | |
114 | + Interface: | |
115 | + struct sg_table * dma_buf_map_attachment(struct dma_buf_attachment *, | |
116 | + enum dma_data_direction); | |
117 | + | |
118 | + This is a wrapper to dma_buf->ops->map_dma_buf operation, which hides the | |
119 | + "dma_buf->ops->" indirection from the users of this interface. | |
120 | + | |
121 | + In struct dma_buf_ops, map_dma_buf is defined as | |
122 | + struct sg_table * (*map_dma_buf)(struct dma_buf_attachment *, | |
123 | + enum dma_data_direction); | |
124 | + | |
125 | + It is one of the buffer operations that must be implemented by the exporter. | |
126 | + It should return the sg_table containing scatterlist for this buffer, mapped | |
127 | + into caller's address space. | |
128 | + | |
129 | + If this is being called for the first time, the exporter can now choose to | |
130 | + scan through the list of attachments for this buffer, collate the requirements | |
131 | + of the attached devices, and choose an appropriate backing storage for the | |
132 | + buffer. | |
133 | + | |
134 | + Based on enum dma_data_direction, it might be possible to have multiple users | |
135 | + accessing at the same time (for reading, maybe), or any other kind of sharing | |
136 | + that the exporter might wish to make available to buffer-users. | |
137 | + | |
138 | + map_dma_buf() operation can return -EINTR if it is interrupted by a signal. | |
139 | + | |
140 | + | |
141 | +5. When finished, the buffer-user notifies end-of-DMA to exporter | |
142 | + | |
143 | + Once the DMA for the current buffer-user is over, it signals 'end-of-DMA' to | |
144 | + the exporter using the dma_buf_unmap_attachment API. | |
145 | + | |
146 | + Interface: | |
147 | + void dma_buf_unmap_attachment(struct dma_buf_attachment *, | |
148 | + struct sg_table *); | |
149 | + | |
150 | + This is a wrapper to dma_buf->ops->unmap_dma_buf() operation, which hides the | |
151 | + "dma_buf->ops->" indirection from the users of this interface. | |
152 | + | |
153 | + In struct dma_buf_ops, unmap_dma_buf is defined as | |
154 | + void (*unmap_dma_buf)(struct dma_buf_attachment *, struct sg_table *); | |
155 | + | |
156 | + unmap_dma_buf signifies the end-of-DMA for the attachment provided. Like | |
157 | + map_dma_buf, this API also must be implemented by the exporter. | |
158 | + | |
159 | + | |
160 | +6. when buffer-user is done using this buffer, it 'disconnects' itself from the | |
161 | + buffer. | |
162 | + | |
163 | + After the buffer-user has no more interest in using this buffer, it should | |
164 | + disconnect itself from the buffer: | |
165 | + | |
166 | + - it first detaches itself from the buffer. | |
167 | + | |
168 | + Interface: | |
169 | + void dma_buf_detach(struct dma_buf *dmabuf, | |
170 | + struct dma_buf_attachment *dmabuf_attach); | |
171 | + | |
172 | + This API removes the attachment from the list in dmabuf, and optionally calls | |
173 | + dma_buf->ops->detach(), if provided by exporter, for any housekeeping bits. | |
174 | + | |
175 | + - Then, the buffer-user returns the buffer reference to exporter. | |
176 | + | |
177 | + Interface: | |
178 | + void dma_buf_put(struct dma_buf *dmabuf); | |
179 | + | |
180 | + This API then reduces the refcount for this buffer. | |
181 | + | |
182 | + If, as a result of this call, the refcount becomes 0, the 'release' file | |
183 | + operation related to this fd is called. It calls the dmabuf->ops->release() | |
184 | + operation in turn, and frees the memory allocated for dmabuf when exported. | |
185 | + | |
186 | +NOTES: | |
187 | +- Importance of attach-detach and {map,unmap}_dma_buf operation pairs | |
188 | + The attach-detach calls allow the exporter to figure out backing-storage | |
189 | + constraints for the currently-interested devices. This allows preferential | |
190 | + allocation, and/or migration of pages across different types of storage | |
191 | + available, if possible. | |
192 | + | |
193 | + Bracketing of DMA access with {map,unmap}_dma_buf operations is essential | |
194 | + to allow just-in-time backing of storage, and migration mid-way through a | |
195 | + use-case. | |
196 | + | |
197 | +- Migration of backing storage if needed | |
198 | + If after | |
199 | + - at least one map_dma_buf has happened, | |
200 | + - and the backing storage has been allocated for this buffer, | |
201 | + another new buffer-user intends to attach itself to this buffer, it might | |
202 | + be allowed, if possible for the exporter. | |
203 | + | |
204 | + In case it is allowed by the exporter: | |
205 | + if the new buffer-user has stricter 'backing-storage constraints', and the | |
206 | + exporter can handle these constraints, the exporter can just stall on the | |
207 | + map_dma_buf until all outstanding access is completed (as signalled by | |
208 | + unmap_dma_buf). | |
209 | + Once all users have finished accessing and have unmapped this buffer, the | |
210 | + exporter could potentially move the buffer to the stricter backing-storage, | |
211 | + and then allow further {map,unmap}_dma_buf operations from any buffer-user | |
212 | + from the migrated backing-storage. | |
213 | + | |
214 | + If the exporter cannot fulfil the backing-storage constraints of the new | |
215 | + buffer-user device as requested, dma_buf_attach() would return an error to | |
216 | + denote non-compatibility of the new buffer-sharing request with the current | |
217 | + buffer. | |
218 | + | |
219 | + If the exporter chooses not to allow an attach() operation once a | |
220 | + map_dma_buf() API has been called, it simply returns an error. | |
221 | + | |
222 | +References: | |
223 | +[1] struct dma_buf_ops in include/linux/dma-buf.h | |
224 | +[2] All interfaces mentioned above defined in include/linux/dma-buf.h |
drivers/base/Kconfig
... | ... | @@ -174,5 +174,16 @@ |
174 | 174 | |
175 | 175 | source "drivers/base/regmap/Kconfig" |
176 | 176 | |
177 | +config DMA_SHARED_BUFFER | |
178 | + bool "Buffer framework to be shared between drivers" | |
179 | + default n | |
180 | + select ANON_INODES | |
181 | + depends on EXPERIMENTAL | |
182 | + help | |
183 | + This option enables the framework for buffer-sharing between | |
184 | + multiple drivers. A buffer is associated with a file using driver | |
185 | + APIs extension; the file's descriptor can then be passed on to other | |
186 | + driver. | |
187 | + | |
177 | 188 | endmenu |
drivers/base/Makefile
... | ... | @@ -9,6 +9,7 @@ |
9 | 9 | obj-y += power/ |
10 | 10 | obj-$(CONFIG_HAS_DMA) += dma-mapping.o |
11 | 11 | obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o |
12 | +obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf.o | |
12 | 13 | obj-$(CONFIG_ISA) += isa.o |
13 | 14 | obj-$(CONFIG_FW_LOADER) += firmware_class.o |
14 | 15 | obj-$(CONFIG_NUMA) += node.o |
drivers/base/dma-buf.c
1 | +/* | |
2 | + * Framework for buffer objects that can be shared across devices/subsystems. | |
3 | + * | |
4 | + * Copyright(C) 2011 Linaro Limited. All rights reserved. | |
5 | + * Author: Sumit Semwal <sumit.semwal@ti.com> | |
6 | + * | |
7 | + * Many thanks to linaro-mm-sig list, and specially | |
8 | + * Arnd Bergmann <arnd@arndb.de>, Rob Clark <rob@ti.com> and | |
9 | + * Daniel Vetter <daniel@ffwll.ch> for their support in creation and | |
10 | + * refining of this idea. | |
11 | + * | |
12 | + * This program is free software; you can redistribute it and/or modify it | |
13 | + * under the terms of the GNU General Public License version 2 as published by | |
14 | + * the Free Software Foundation. | |
15 | + * | |
16 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
17 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
18 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
19 | + * more details. | |
20 | + * | |
21 | + * You should have received a copy of the GNU General Public License along with | |
22 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
23 | + */ | |
24 | + | |
25 | +#include <linux/fs.h> | |
26 | +#include <linux/slab.h> | |
27 | +#include <linux/dma-buf.h> | |
28 | +#include <linux/anon_inodes.h> | |
29 | +#include <linux/export.h> | |
30 | + | |
31 | +static inline int is_dma_buf_file(struct file *); | |
32 | + | |
33 | +static int dma_buf_release(struct inode *inode, struct file *file) | |
34 | +{ | |
35 | + struct dma_buf *dmabuf; | |
36 | + | |
37 | + if (!is_dma_buf_file(file)) | |
38 | + return -EINVAL; | |
39 | + | |
40 | + dmabuf = file->private_data; | |
41 | + | |
42 | + dmabuf->ops->release(dmabuf); | |
43 | + kfree(dmabuf); | |
44 | + return 0; | |
45 | +} | |
46 | + | |
47 | +static const struct file_operations dma_buf_fops = { | |
48 | + .release = dma_buf_release, | |
49 | +}; | |
50 | + | |
51 | +/* | |
52 | + * is_dma_buf_file - Check if struct file* is associated with dma_buf | |
53 | + */ | |
54 | +static inline int is_dma_buf_file(struct file *file) | |
55 | +{ | |
56 | + return file->f_op == &dma_buf_fops; | |
57 | +} | |
58 | + | |
59 | +/** | |
60 | + * dma_buf_export - Creates a new dma_buf, and associates an anon file | |
61 | + * with this buffer, so it can be exported. | |
62 | + * Also connect the allocator specific data and ops to the buffer. | |
63 | + * | |
64 | + * @priv: [in] Attach private data of allocator to this buffer | |
65 | + * @ops: [in] Attach allocator-defined dma buf ops to the new buffer. | |
66 | + * @size: [in] Size of the buffer | |
67 | + * @flags: [in] mode flags for the file. | |
68 | + * | |
69 | + * Returns, on success, a newly created dma_buf object, which wraps the | |
70 | + * supplied private data and operations for dma_buf_ops. On either missing | |
71 | + * ops, or error in allocating struct dma_buf, will return negative error. | |
72 | + * | |
73 | + */ | |
74 | +struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops, | |
75 | + size_t size, int flags) | |
76 | +{ | |
77 | + struct dma_buf *dmabuf; | |
78 | + struct file *file; | |
79 | + | |
80 | + if (WARN_ON(!priv || !ops | |
81 | + || !ops->map_dma_buf | |
82 | + || !ops->unmap_dma_buf | |
83 | + || !ops->release)) { | |
84 | + return ERR_PTR(-EINVAL); | |
85 | + } | |
86 | + | |
87 | + dmabuf = kzalloc(sizeof(struct dma_buf), GFP_KERNEL); | |
88 | + if (dmabuf == NULL) | |
89 | + return ERR_PTR(-ENOMEM); | |
90 | + | |
91 | + dmabuf->priv = priv; | |
92 | + dmabuf->ops = ops; | |
93 | + dmabuf->size = size; | |
94 | + | |
95 | + file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf, flags); | |
96 | + | |
97 | + dmabuf->file = file; | |
98 | + | |
99 | + mutex_init(&dmabuf->lock); | |
100 | + INIT_LIST_HEAD(&dmabuf->attachments); | |
101 | + | |
102 | + return dmabuf; | |
103 | +} | |
104 | +EXPORT_SYMBOL_GPL(dma_buf_export); | |
105 | + | |
106 | + | |
107 | +/** | |
108 | + * dma_buf_fd - returns a file descriptor for the given dma_buf | |
109 | + * @dmabuf: [in] pointer to dma_buf for which fd is required. | |
110 | + * | |
111 | + * On success, returns an associated 'fd'. Else, returns error. | |
112 | + */ | |
113 | +int dma_buf_fd(struct dma_buf *dmabuf) | |
114 | +{ | |
115 | + int error, fd; | |
116 | + | |
117 | + if (!dmabuf || !dmabuf->file) | |
118 | + return -EINVAL; | |
119 | + | |
120 | + error = get_unused_fd(); | |
121 | + if (error < 0) | |
122 | + return error; | |
123 | + fd = error; | |
124 | + | |
125 | + fd_install(fd, dmabuf->file); | |
126 | + | |
127 | + return fd; | |
128 | +} | |
129 | +EXPORT_SYMBOL_GPL(dma_buf_fd); | |
130 | + | |
131 | +/** | |
132 | + * dma_buf_get - returns the dma_buf structure related to an fd | |
133 | + * @fd: [in] fd associated with the dma_buf to be returned | |
134 | + * | |
135 | + * On success, returns the dma_buf structure associated with an fd; uses | |
136 | + * file's refcounting done by fget to increase refcount. returns ERR_PTR | |
137 | + * otherwise. | |
138 | + */ | |
139 | +struct dma_buf *dma_buf_get(int fd) | |
140 | +{ | |
141 | + struct file *file; | |
142 | + | |
143 | + file = fget(fd); | |
144 | + | |
145 | + if (!file) | |
146 | + return ERR_PTR(-EBADF); | |
147 | + | |
148 | + if (!is_dma_buf_file(file)) { | |
149 | + fput(file); | |
150 | + return ERR_PTR(-EINVAL); | |
151 | + } | |
152 | + | |
153 | + return file->private_data; | |
154 | +} | |
155 | +EXPORT_SYMBOL_GPL(dma_buf_get); | |
156 | + | |
157 | +/** | |
158 | + * dma_buf_put - decreases refcount of the buffer | |
159 | + * @dmabuf: [in] buffer to reduce refcount of | |
160 | + * | |
161 | + * Uses file's refcounting done implicitly by fput() | |
162 | + */ | |
163 | +void dma_buf_put(struct dma_buf *dmabuf) | |
164 | +{ | |
165 | + if (WARN_ON(!dmabuf || !dmabuf->file)) | |
166 | + return; | |
167 | + | |
168 | + fput(dmabuf->file); | |
169 | +} | |
170 | +EXPORT_SYMBOL_GPL(dma_buf_put); | |
171 | + | |
172 | +/** | |
173 | + * dma_buf_attach - Add the device to dma_buf's attachments list; optionally, | |
174 | + * calls attach() of dma_buf_ops to allow device-specific attach functionality | |
175 | + * @dmabuf: [in] buffer to attach device to. | |
176 | + * @dev: [in] device to be attached. | |
177 | + * | |
178 | + * Returns struct dma_buf_attachment * for this attachment; may return negative | |
179 | + * error codes. | |
180 | + * | |
181 | + */ | |
182 | +struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, | |
183 | + struct device *dev) | |
184 | +{ | |
185 | + struct dma_buf_attachment *attach; | |
186 | + int ret; | |
187 | + | |
188 | + if (WARN_ON(!dmabuf || !dev || !dmabuf->ops)) | |
189 | + return ERR_PTR(-EINVAL); | |
190 | + | |
191 | + attach = kzalloc(sizeof(struct dma_buf_attachment), GFP_KERNEL); | |
192 | + if (attach == NULL) | |
193 | + goto err_alloc; | |
194 | + | |
195 | + mutex_lock(&dmabuf->lock); | |
196 | + | |
197 | + attach->dev = dev; | |
198 | + attach->dmabuf = dmabuf; | |
199 | + if (dmabuf->ops->attach) { | |
200 | + ret = dmabuf->ops->attach(dmabuf, dev, attach); | |
201 | + if (ret) | |
202 | + goto err_attach; | |
203 | + } | |
204 | + list_add(&attach->node, &dmabuf->attachments); | |
205 | + | |
206 | + mutex_unlock(&dmabuf->lock); | |
207 | + return attach; | |
208 | + | |
209 | +err_alloc: | |
210 | + return ERR_PTR(-ENOMEM); | |
211 | +err_attach: | |
212 | + kfree(attach); | |
213 | + mutex_unlock(&dmabuf->lock); | |
214 | + return ERR_PTR(ret); | |
215 | +} | |
216 | +EXPORT_SYMBOL_GPL(dma_buf_attach); | |
217 | + | |
218 | +/** | |
219 | + * dma_buf_detach - Remove the given attachment from dmabuf's attachments list; | |
220 | + * optionally calls detach() of dma_buf_ops for device-specific detach | |
221 | + * @dmabuf: [in] buffer to detach from. | |
222 | + * @attach: [in] attachment to be detached; is free'd after this call. | |
223 | + * | |
224 | + */ | |
225 | +void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) | |
226 | +{ | |
227 | + if (WARN_ON(!dmabuf || !attach || !dmabuf->ops)) | |
228 | + return; | |
229 | + | |
230 | + mutex_lock(&dmabuf->lock); | |
231 | + list_del(&attach->node); | |
232 | + if (dmabuf->ops->detach) | |
233 | + dmabuf->ops->detach(dmabuf, attach); | |
234 | + | |
235 | + mutex_unlock(&dmabuf->lock); | |
236 | + kfree(attach); | |
237 | +} | |
238 | +EXPORT_SYMBOL_GPL(dma_buf_detach); | |
239 | + | |
240 | +/** | |
241 | + * dma_buf_map_attachment - Returns the scatterlist table of the attachment; | |
242 | + * mapped into _device_ address space. Is a wrapper for map_dma_buf() of the | |
243 | + * dma_buf_ops. | |
244 | + * @attach: [in] attachment whose scatterlist is to be returned | |
245 | + * @direction: [in] direction of DMA transfer | |
246 | + * | |
247 | + * Returns sg_table containing the scatterlist to be returned; may return NULL | |
248 | + * or ERR_PTR. | |
249 | + * | |
250 | + */ | |
251 | +struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, | |
252 | + enum dma_data_direction direction) | |
253 | +{ | |
254 | + struct sg_table *sg_table = ERR_PTR(-EINVAL); | |
255 | + | |
256 | + might_sleep(); | |
257 | + | |
258 | + if (WARN_ON(!attach || !attach->dmabuf || !attach->dmabuf->ops)) | |
259 | + return ERR_PTR(-EINVAL); | |
260 | + | |
261 | + mutex_lock(&attach->dmabuf->lock); | |
262 | + if (attach->dmabuf->ops->map_dma_buf) | |
263 | + sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction); | |
264 | + mutex_unlock(&attach->dmabuf->lock); | |
265 | + | |
266 | + return sg_table; | |
267 | +} | |
268 | +EXPORT_SYMBOL_GPL(dma_buf_map_attachment); | |
269 | + | |
270 | +/** | |
271 | + * dma_buf_unmap_attachment - unmaps and decreases usecount of the buffer;might | |
272 | + * deallocate the scatterlist associated. Is a wrapper for unmap_dma_buf() of | |
273 | + * dma_buf_ops. | |
274 | + * @attach: [in] attachment to unmap buffer from | |
275 | + * @sg_table: [in] scatterlist info of the buffer to unmap | |
276 | + * | |
277 | + */ | |
278 | +void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, | |
279 | + struct sg_table *sg_table) | |
280 | +{ | |
281 | + if (WARN_ON(!attach || !attach->dmabuf || !sg_table | |
282 | + || !attach->dmabuf->ops)) | |
283 | + return; | |
284 | + | |
285 | + mutex_lock(&attach->dmabuf->lock); | |
286 | + if (attach->dmabuf->ops->unmap_dma_buf) | |
287 | + attach->dmabuf->ops->unmap_dma_buf(attach, sg_table); | |
288 | + mutex_unlock(&attach->dmabuf->lock); | |
289 | + | |
290 | +} | |
291 | +EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment); |
include/linux/dma-buf.h
1 | +/* | |
2 | + * Header file for dma buffer sharing framework. | |
3 | + * | |
4 | + * Copyright(C) 2011 Linaro Limited. All rights reserved. | |
5 | + * Author: Sumit Semwal <sumit.semwal@ti.com> | |
6 | + * | |
7 | + * Many thanks to linaro-mm-sig list, and specially | |
8 | + * Arnd Bergmann <arnd@arndb.de>, Rob Clark <rob@ti.com> and | |
9 | + * Daniel Vetter <daniel@ffwll.ch> for their support in creation and | |
10 | + * refining of this idea. | |
11 | + * | |
12 | + * This program is free software; you can redistribute it and/or modify it | |
13 | + * under the terms of the GNU General Public License version 2 as published by | |
14 | + * the Free Software Foundation. | |
15 | + * | |
16 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
17 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
18 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
19 | + * more details. | |
20 | + * | |
21 | + * You should have received a copy of the GNU General Public License along with | |
22 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
23 | + */ | |
24 | +#ifndef __DMA_BUF_H__ | |
25 | +#define __DMA_BUF_H__ | |
26 | + | |
27 | +#include <linux/file.h> | |
28 | +#include <linux/err.h> | |
29 | +#include <linux/device.h> | |
30 | +#include <linux/scatterlist.h> | |
31 | +#include <linux/list.h> | |
32 | +#include <linux/dma-mapping.h> | |
33 | + | |
34 | +struct dma_buf; | |
35 | +struct dma_buf_attachment; | |
36 | + | |
37 | +/** | |
38 | + * struct dma_buf_ops - operations possible on struct dma_buf | |
39 | + * @attach: [optional] allows different devices to 'attach' themselves to the | |
40 | + * given buffer. It might return -EBUSY to signal that backing storage | |
41 | + * is already allocated and incompatible with the requirements | |
42 | + * of requesting device. | |
43 | + * @detach: [optional] detach a given device from this buffer. | |
44 | + * @map_dma_buf: returns list of scatter pages allocated, increases usecount | |
45 | + * of the buffer. Requires atleast one attach to be called | |
46 | + * before. Returned sg list should already be mapped into | |
47 | + * _device_ address space. This call may sleep. May also return | |
48 | + * -EINTR. Should return -EINVAL if attach hasn't been called yet. | |
49 | + * @unmap_dma_buf: decreases usecount of buffer, might deallocate scatter | |
50 | + * pages. | |
51 | + * @release: release this buffer; to be called after the last dma_buf_put. | |
52 | + */ | |
53 | +struct dma_buf_ops { | |
54 | + int (*attach)(struct dma_buf *, struct device *, | |
55 | + struct dma_buf_attachment *); | |
56 | + | |
57 | + void (*detach)(struct dma_buf *, struct dma_buf_attachment *); | |
58 | + | |
59 | + /* For {map,unmap}_dma_buf below, any specific buffer attributes | |
60 | + * required should get added to device_dma_parameters accessible | |
61 | + * via dev->dma_params. | |
62 | + */ | |
63 | + struct sg_table * (*map_dma_buf)(struct dma_buf_attachment *, | |
64 | + enum dma_data_direction); | |
65 | + void (*unmap_dma_buf)(struct dma_buf_attachment *, | |
66 | + struct sg_table *); | |
67 | + /* TODO: Add try_map_dma_buf version, to return immed with -EBUSY | |
68 | + * if the call would block. | |
69 | + */ | |
70 | + | |
71 | + /* after final dma_buf_put() */ | |
72 | + void (*release)(struct dma_buf *); | |
73 | + | |
74 | +}; | |
75 | + | |
76 | +/** | |
77 | + * struct dma_buf - shared buffer object | |
78 | + * @size: size of the buffer | |
79 | + * @file: file pointer used for sharing buffers across, and for refcounting. | |
80 | + * @attachments: list of dma_buf_attachment that denotes all devices attached. | |
81 | + * @ops: dma_buf_ops associated with this buffer object. | |
82 | + * @priv: exporter specific private data for this buffer object. | |
83 | + */ | |
84 | +struct dma_buf { | |
85 | + size_t size; | |
86 | + struct file *file; | |
87 | + struct list_head attachments; | |
88 | + const struct dma_buf_ops *ops; | |
89 | + /* mutex to serialize list manipulation and other ops */ | |
90 | + struct mutex lock; | |
91 | + void *priv; | |
92 | +}; | |
93 | + | |
94 | +/** | |
95 | + * struct dma_buf_attachment - holds device-buffer attachment data | |
96 | + * @dmabuf: buffer for this attachment. | |
97 | + * @dev: device attached to the buffer. | |
98 | + * @node: list of dma_buf_attachment. | |
99 | + * @priv: exporter specific attachment data. | |
100 | + * | |
101 | + * This structure holds the attachment information between the dma_buf buffer | |
102 | + * and its user device(s). The list contains one attachment struct per device | |
103 | + * attached to the buffer. | |
104 | + */ | |
105 | +struct dma_buf_attachment { | |
106 | + struct dma_buf *dmabuf; | |
107 | + struct device *dev; | |
108 | + struct list_head node; | |
109 | + void *priv; | |
110 | +}; | |
111 | + | |
112 | +#ifdef CONFIG_DMA_SHARED_BUFFER | |
113 | +struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, | |
114 | + struct device *dev); | |
115 | +void dma_buf_detach(struct dma_buf *dmabuf, | |
116 | + struct dma_buf_attachment *dmabuf_attach); | |
117 | +struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops, | |
118 | + size_t size, int flags); | |
119 | +int dma_buf_fd(struct dma_buf *dmabuf); | |
120 | +struct dma_buf *dma_buf_get(int fd); | |
121 | +void dma_buf_put(struct dma_buf *dmabuf); | |
122 | + | |
123 | +struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *, | |
124 | + enum dma_data_direction); | |
125 | +void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *); | |
126 | +#else | |
127 | + | |
128 | +static inline struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, | |
129 | + struct device *dev) | |
130 | +{ | |
131 | + return ERR_PTR(-ENODEV); | |
132 | +} | |
133 | + | |
134 | +static inline void dma_buf_detach(struct dma_buf *dmabuf, | |
135 | + struct dma_buf_attachment *dmabuf_attach) | |
136 | +{ | |
137 | + return; | |
138 | +} | |
139 | + | |
140 | +static inline struct dma_buf *dma_buf_export(void *priv, | |
141 | + struct dma_buf_ops *ops, | |
142 | + size_t size, int flags) | |
143 | +{ | |
144 | + return ERR_PTR(-ENODEV); | |
145 | +} | |
146 | + | |
147 | +static inline int dma_buf_fd(struct dma_buf *dmabuf) | |
148 | +{ | |
149 | + return -ENODEV; | |
150 | +} | |
151 | + | |
152 | +static inline struct dma_buf *dma_buf_get(int fd) | |
153 | +{ | |
154 | + return ERR_PTR(-ENODEV); | |
155 | +} | |
156 | + | |
157 | +static inline void dma_buf_put(struct dma_buf *dmabuf) | |
158 | +{ | |
159 | + return; | |
160 | +} | |
161 | + | |
162 | +static inline struct sg_table *dma_buf_map_attachment( | |
163 | + struct dma_buf_attachment *attach, enum dma_data_direction write) | |
164 | +{ | |
165 | + return ERR_PTR(-ENODEV); | |
166 | +} | |
167 | + | |
168 | +static inline void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, | |
169 | + struct sg_table *sg) | |
170 | +{ | |
171 | + return; | |
172 | +} | |
173 | + | |
174 | +#endif /* CONFIG_DMA_SHARED_BUFFER */ | |
175 | + | |
176 | +#endif /* __DMA_BUF_H__ */ |