diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-08 17:05:09 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-08 17:05:09 -0500 |
commit | 8e369672af8700299ab372bad9397f230b1d591a (patch) | |
tree | 8676cfdb7f8c1ac5ee124aef050d541d70f876d0 | |
parent | 6950d76c531671ec389e36183311826597951ac6 (diff) | |
parent | a125a3945c950caef001f22055bf201a36568533 (diff) |
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
-rw-r--r-- | Documentation/dma-buf-sharing.txt | 224 | ||||
-rw-r--r-- | drivers/base/Kconfig | 11 | ||||
-rw-r--r-- | drivers/base/Makefile | 1 | ||||
-rw-r--r-- | drivers/base/dma-buf.c | 291 | ||||
-rw-r--r-- | include/linux/dma-buf.h | 176 |
5 files changed, 703 insertions, 0 deletions
diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt new file mode 100644 index 00000000000..510eab32f39 --- /dev/null +++ b/Documentation/dma-buf-sharing.txt | |||
@@ -0,0 +1,224 @@ | |||
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 | ||
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 21cf46f4524..e95c67edb2c 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig | |||
@@ -174,4 +174,15 @@ config SYS_HYPERVISOR | |||
174 | 174 | ||
175 | source "drivers/base/regmap/Kconfig" | 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 | endmenu | 188 | endmenu |
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 1334d893b56..2c8272dd93c 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile | |||
@@ -9,6 +9,7 @@ obj-$(CONFIG_DEVTMPFS) += devtmpfs.o | |||
9 | obj-y += power/ | 9 | obj-y += power/ |
10 | obj-$(CONFIG_HAS_DMA) += dma-mapping.o | 10 | obj-$(CONFIG_HAS_DMA) += dma-mapping.o |
11 | obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o | 11 | obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o |
12 | obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf.o | ||
12 | obj-$(CONFIG_ISA) += isa.o | 13 | obj-$(CONFIG_ISA) += isa.o |
13 | obj-$(CONFIG_FW_LOADER) += firmware_class.o | 14 | obj-$(CONFIG_FW_LOADER) += firmware_class.o |
14 | obj-$(CONFIG_NUMA) += node.o | 15 | obj-$(CONFIG_NUMA) += node.o |
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c new file mode 100644 index 00000000000..e38ad243b4b --- /dev/null +++ b/drivers/base/dma-buf.c | |||
@@ -0,0 +1,291 @@ | |||
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); | ||
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h new file mode 100644 index 00000000000..f8ac076afa5 --- /dev/null +++ b/include/linux/dma-buf.h | |||
@@ -0,0 +1,176 @@ | |||
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__ */ | ||