Patch available on git.linaro.org feature tree as
version 3: http://git.linaro.org/gitweb?p=people/sumitsemwal/linux-3.x.git%3Ba=shortlog...
Best regards, ~Sumit.
On 30 September 2011 18:12, Sumit Semwal sumit.semwal@ti.com wrote:
[Hopefully the last version to linaro-mm-sig before I send it out to upstream linux lists]
This is the first step in defining a buffer sharing framework. A new dma_buf buffer object is added, with hooks to allow for easy sharing of this buffer object across devices.
The framework allows:
- a new buffer-object to be created with fixed size.
- different devices to 'attach' themselves to this buffer, to facilitate
backing storage negotiation, using dma_buf_attach() API.
- association of a file pointer with each user-buffer and associated allocator-defined operations on that buffer. This operation is called the 'export' operation.
- this exported buffer-object to be shared with the other entity by asking
for its 'file-descriptor (fd)', and sharing the fd across.
- a received fd to get the buffer object back, where it can be accessed
using the associated exporter-defined operations.
- the exporter and user to share the scatterlist using get_scatterlist and put_scatterlist operations.
Atleast one 'dma_buf_attach()' call is required to be made prior to calling the get_scatterlist() operation.
Couple of building blocks in get_scatterlist() are added to ease introduction of sync'ing across exporter and users, and late allocation by the exporter.
mmap() file operation is provided for the associated 'fd', as wrapper over the optional allocator defined mmap(), to be used by devices that might need one.
Please read documentation added in this patch for more details.
The idea was first mooted at the Linaro memory management mini-summit in Budapest in May 2011, as part of multiple things needed for a 'unified memory management framework'. It took a more concrete shape at Linaro memory-management mini-summit in Cambridge, Aug 2011.
This is based on design suggestions from many people at both the mini-summits, most notably from Arnd Bergmann arnd@arndb.de, Rob Clark rob@ti.com and Daniel Vetter daniel@ffwll.ch.
The implementation is inspired from proof-of-concept patch-set from Tomasz Stanislawski t.stanislaws@samsung.com, who demonstrated buffer sharing between two v4l2 devices.
v3:
- added dma_buf to dma_attachment and updated {get,put}_scatterlist
accordingly.
- added locking mechanism in struct dma_buf, and used around attach-detach
APIs.
- dmabuf->ops->attach/detach made optional.
- removed dma_buf_attr_flags and replaced dma_buf_optye with
dma_data_direction.
- made dma_buf->ops const in struct dma_buf.
- updated comments for get_scatterlist.
- added documentation.
v2:
- added attach() / detach() dma_buf_ops, and
dma_buf_attach(),dma_buf_detach().
- added handling of list of attachment in the dma_buf central API itself.
- corrected copyright information.
v1: initial RFC.
Signed-off-by: Sumit Semwal sumit.semwal@linaro.org Signed-off-by: Sumit Semwal sumit.semwal@ti.com
Documentation/dma-buf-sharing.txt | 210 ++++++++++++++++++++++++++++++++ drivers/base/Kconfig | 10 ++ drivers/base/Makefile | 1 + drivers/base/dma-buf.c | 242 +++++++++++++++++++++++++++++++++++++ include/linux/dma-buf.h | 162 +++++++++++++++++++++++++ 5 files changed, 625 insertions(+), 0 deletions(-) create mode 100644 Documentation/dma-buf-sharing.txt create mode 100644 drivers/base/dma-buf.c create mode 100644 include/linux/dma-buf.h
diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt new file mode 100644 index 0000000..4da6644 --- /dev/null +++ b/Documentation/dma-buf-sharing.txt @@ -0,0 +1,210 @@
DMA Buffer Sharing API Guide
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sumit Semwal
<sumit dot semwal at linaro dot org>
<sumit dot semwal at ti dot com>
+This document serves as a guide to device-driver writers on what is the dma-buf +buffer sharing API, how to use it for exporting and using shared buffers.
+Any device driver which wishes to be a part of dma buffer sharing, can do so as +either the 'exporter' of buffers, or the 'user' of buffers.
+Say a driver A wants to use buffers created by driver B, then we call B as the +exporter, and B as buffer-user.
+The exporter +- implements and manages operations[1] for the buffer +- allows other users to share the buffer by using dma_buf sharing APIs, +- manages the details of buffer allocation, +- decides about the actual backing storage where this allocation happens, +- takes care of any migration of scatterlist - for all (shared) users of this
- buffer,
+- optionally, provides mmap capability for drivers that need it.
+The buffer-user +- is one of (many) sharing users of the buffer. +- doesn't need to worry about how the buffer is allocated, or where. +- needs a mechanism to get access to the scatterlist that makes up this buffer
- in memory, mapped into its own address space, so it can access the same
area
- of memory.
+The dma_buf buffer sharing API usage contains the following steps:
+1. Exporter announces that it wishes to export a buffer +2. Userspace gets the file descriptor associated with the exported buffer, and
- passes it around to potential buffer-users based on use case
+3. Each buffer-user 'connects' itself to the buffer +4. When needed, buffer-user requests access to the buffer from exporter +5. When finished with its use, the buffer-user notifies end-of-dma to exporter +6. when buffer-user is done using this buffer completely, it 'disconnects'
- itself from the buffer.
+1. Exporter's announcement of buffer export
- The buffer exporter announces its wish to export a buffer. In this, it
- connects its own private buffer data, provides implementation for
operations
- that can be performed on the exported dma_buf, and flags for the file
- associated with this buffer.
- Interface:
struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
int flags)
- If this succeeds, dma_buf_export allocates a dma_buf structure, and
returns a
- pointer to the same. It also associates an anon file with this buffer,
so it
- can be exported. On failure to allocate the dma_buf object, it returns
NULL.
+2. Userspace gets a handle to pass around to potential buffer-users
- Userspace entity requests for a file-descriptor (fd) which is a handle
to the
- anon file associated with the buffer. It can then share the fd with
other
- drivers and/or processes.
- Interface:
int dma_buf_fd(struct dma_buf *dmabuf)
- This API installs an fd for the anon file associated with this buffer;
- returns either 'fd', or error.
+3. Each buffer-user 'connects' itself to the buffer
- Each buffer-user now gets a reference to the buffer, using the fd
passed to
- it.
- Interface:
struct dma_buf *dma_buf_get(int fd)
- This API will return a reference to the dma_buf, and increment refcount
for
- it.
- After this, the buffer-user needs to attach its device with the buffer,
which
- helps the exporter to know of device buffer constraints.
- Interface:
struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
struct device *dev)
- This API returns reference to an attachment structure, which is then
used
- for scatterlist operations. It will optionally call the 'attach'
dma_buf
- operation, if provided by the exporter.
- The dma-buf sharing framework does the book-keeping bits related to
keeping
- the list of all attachments to a buffer.
+Till this stage, the buffer-exporter has the option to choose not to actually +allocate the backing storage for this buffer, but wait for the first buffer-user +to request use of buffer for allocation.
+4. When needed, buffer-user requests access to the buffer
- Whenever a buffer-user wants to use the buffer for any dma, it asks for
- access to the buffer using dma_buf->ops->get_scatterlist operation.
Atleast
- one attach to the buffer should have happened before get_scatterlist
can be
- called.
- Interface: [member of struct dma_buf_ops]
struct scatterlist * (*get_scatterlist)(struct dma_buf_attachment *,
enum dma_data_direction,
int* nents);
- It is one of the buffer operations that must be implemented by the
exporter.
- It should return the scatterlist for this buffer, mapped into caller's
address
- space.
- If this is being called for the first time, the exporter can now choose
to
- scan through the list of attachments for this buffer, collate the
requirements
- of the attached devices, and choose an appropriate backing storage for
the
- buffer.
- Based on enum dma_data_direction, it might be possible to have multiple
users
- accessing at the same time (for reading, maybe), or any other kind of
sharing
- that the exporter might wish to make available to buffer-users.
+5. When finished, the buffer-user notifies end-of-dma to exporter
- Once the dma for the current buffer-user is over, it signals
'end-of-dma' to
- the exporter using the dma_buf->ops->put_scatterlist() operation.
- Interface:
void (*put_scatterlist)(struct dma_buf_attachment *, struct
scatterlist *,
int nents);
- put_scatterlist signifies the end-of-dma for the attachment provided.
+6. when buffer-user is done using this buffer, it 'disconnects' itself from the
- buffer.
- After the buffer-user has no more interest in using this buffer, it
should
- disconnect itself from the buffer:
- it first detaches itself from the buffer.
- Interface:
void dma_buf_detach(struct dma_buf *dmabuf,
struct dma_buf_attachment *dmabuf_attach);
- This API removes the attachment from the list in dmabuf, and optionally
calls
- dma_buf->ops->detach(), if provided by exporter, for any housekeeping
bits.
- Then, the buffer-user returns the buffer reference to exporter.
- Interface:
void dma_buf_put(struct dma_buf *dmabuf);
- This API then reduces the refcount for this buffer.
- If, as a result of this call, the refcount becomes 0, the 'release'
file
- operation related to this fd is called. It calls the
dmabuf->ops->release()
- operation in turn, and frees the memory allocated for dmabuf when
exported.
+NOTES: +- Importance of attach-detach and {get,put}_scatterlist operation pairs
- The attach-detach calls allow the exporter to figure out
backing-storage
- constraints for the currently-interested devices. This allows
preferential
- allocation, and/or migration of pages across different types of storage
- available, if possible.
- Bracketing of dma access with {get,put}_scatterlist operations is
essential
- to allow just-in-time backing of storage, and migration mid-way through
a
- use-case.
+- Migration of backing storage if needed
- After
- atleast one get_scatterlist has happened,
- and the backing storage has been allocated for this buffer,
- If another new buffer-user intends to attach itself to this buffer, it
might
- be allowed, if possible for the exporter.
- In case it is allowed by the exporter:
- if the new buffer-user has stricter 'backing-storage constraints', and
the
- exporter can handle these constraints, the exporter can just stall on
the
- get_scatterlist till all outstanding access is completed (as signalled
by
- put_scatterlist).
- Once all ongoing access is completed, the exporter could potentially
move
- the buffer to the stricter backing-storage, and then allow further
- {get,put}_scatterlist operations from any buffer-user from the
migrated
- backing-storage.
- If the exporter cannot fulfill the backing-storage constraints of the
new
- buffer-user device as requested, dma_buf_attach() would return an error
to
- denote non-compatibility of the new buffer-sharing request with the
current
- buffer.
- If the exporter chooses not to allow an attach() operation once a
- get_scatterlist has been called, it simply returns an error.
+- mmap file operation
- An mmap() file operation is provided for the fd associated with the
buffer.
- If the exporter defines an mmap operation, the mmap() fop calls this to
allow
- mmap for devices that might need it; if not, it returns an error.
+References: +[1] struct dma_buf_ops in include/linux/dma-buf.h +[2] All interfaces mentioned above defined in include/linux/dma-buf.h diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 21cf46f..07d8095 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -174,4 +174,14 @@ config SYS_HYPERVISOR
source "drivers/base/regmap/Kconfig"
+config DMA_SHARED_BUFFER
bool "Buffer framework to be shared between drivers"
default n
depends on ANON_INODES
help
This option enables the framework for buffer-sharing between
multiple drivers. A buffer is associated with a file using driver
APIs extension; the file's descriptor can then be passed on to
other
driver.
endmenu diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 99a375a..d0df046 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DEVTMPFS) += devtmpfs.o obj-y += power/ obj-$(CONFIG_HAS_DMA) += dma-mapping.o obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o +obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf.o obj-$(CONFIG_ISA) += isa.o obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c new file mode 100644 index 0000000..58c51a0 --- /dev/null +++ b/drivers/base/dma-buf.c @@ -0,0 +1,242 @@ +/*
- Framework for buffer objects that can be shared across
devices/subsystems.
- Copyright(C) 2011 Linaro Limited. All rights reserved.
- Author: Sumit Semwal sumit.semwal@ti.com
- Many thanks to linaro-mm-sig list, and specially
- Arnd Bergmann arnd@arndb.de, Rob Clark rob@ti.com and
- Daniel Vetter daniel@ffwll.ch for their support in creation and
- refining of this idea.
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License version 2 as
published by
- the Free Software Foundation.
- This program is distributed in the hope that it will be useful, but
WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for
- more details.
- You should have received a copy of the GNU General Public License along
with
- this program. If not, see http://www.gnu.org/licenses/.
- */
+#include <linux/fs.h> +#include <linux/slab.h> +#include <linux/dma-buf.h> +#include <linux/anon_inodes.h>
+static inline int is_dma_buf_file(struct file *);
+static int dma_buf_mmap(struct file *file, struct vm_area_struct *vma) +{
struct dma_buf *dmabuf;
if (!is_dma_buf_file(file))
return -EINVAL;
dmabuf = file->private_data;
if (!dmabuf->ops->mmap)
return -EINVAL;
return dmabuf->ops->mmap(dmabuf, vma);
+}
+static int dma_buf_release(struct inode *inode, struct file *file) +{
struct dma_buf *dmabuf;
if (!is_dma_buf_file(file))
return -EINVAL;
dmabuf = file->private_data;
dmabuf->ops->release(dmabuf);
kfree(dmabuf);
return 0;
+}
+static const struct file_operations dma_buf_fops = {
.mmap = dma_buf_mmap,
.release = dma_buf_release,
+};
+/*
- is_dma_buf_file - Check if struct file* is associated with dma_buf
- */
+static inline int is_dma_buf_file(struct file *file) +{
return file->f_op == &dma_buf_fops;
+}
+/**
- dma_buf_export - Creates a new dma_buf, and associates an anon file
- with this buffer,so it can be exported.
- Also connect the allocator specific data and ops to the buffer.
- @priv: [in] Attach private data of allocator to this buffer
- @ops: [in] Attach allocator-defined dma buf ops to the new
buffer.
- @flags: [in] mode flags for the file.
- Returns, on success, a newly created dma_buf object, which wraps the
- supplied private data and operations for dma_buf_ops. On failure to
- allocate the dma_buf object, it can return NULL.
- */
+struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
int flags)
+{
struct dma_buf *dmabuf;
struct file *file;
BUG_ON(!priv || !ops);
dmabuf = kzalloc(sizeof(struct dma_buf), GFP_KERNEL);
if (dmabuf == NULL)
return dmabuf;
dmabuf->priv = priv;
dmabuf->ops = ops;
file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf, flags);
dmabuf->file = file;
mutex_init(&dmabuf->lock);
INIT_LIST_HEAD(&dmabuf->attachments);
return dmabuf;
+} +EXPORT_SYMBOL(dma_buf_export);
+/**
- dma_buf_fd - returns a file descriptor for the given dma_buf
- @dmabuf: [in] pointer to dma_buf for which fd is required.
- On success, returns an associated 'fd'. Else, returns error.
- */
+int dma_buf_fd(struct dma_buf *dmabuf) +{
int error, fd;
if (!dmabuf->file)
return -EINVAL;
error = get_unused_fd_flags(0);
if (error < 0)
return error;
fd = error;
fd_install(fd, dmabuf->file);
return fd;
+} +EXPORT_SYMBOL(dma_buf_fd);
+/**
- dma_buf_get - returns the dma_buf structure related to an fd
- @fd: [in] fd associated with the dma_buf to be returned
- On success, returns the dma_buf structure associated with an fd; uses
- file's refcounting done by fget to increase refcount. returns ERR_PTR
- otherwise.
- */
+struct dma_buf *dma_buf_get(int fd) +{
struct file *file;
file = fget(fd);
if (!file)
return ERR_PTR(-EBADF);
if (!is_dma_buf_file(file)) {
fput(file);
return ERR_PTR(-EINVAL);
}
return file->private_data;
+} +EXPORT_SYMBOL(dma_buf_get);
+/**
- dma_buf_put - decreases refcount of the buffer
- @dmabuf: [in] buffer to reduce refcount of
- Uses file's refcounting done implicitly by fput()
- */
+void dma_buf_put(struct dma_buf *dmabuf) +{
BUG_ON(!dmabuf->file);
fput(dmabuf->file);
return;
+} +EXPORT_SYMBOL(dma_buf_put);
+/**
- dma_buf_attach - Add the device to dma_buf's attachments list;
optionally,
- calls attach() of dma_buf_ops to allow device-specific attach
functionality
- @dmabuf: [in] buffer to attach device to.
- @dev: [in] device to be attached.
- Returns struct dma_buf_attachment * for this attachment; may return
NULL.
- */
+struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
struct device *dev)
+{
struct dma_buf_attachment *attach;
int ret;
BUG_ON(!dmabuf || !dev);
mutex_lock(&dmabuf->lock);
attach = kzalloc(sizeof(struct dma_buf_attachment), GFP_KERNEL);
if (attach == NULL)
goto err_alloc;
attach->dev = dev;
if (dmabuf->ops->attach) {
ret = dmabuf->ops->attach(dmabuf, dev, attach);
if (!ret)
goto err_attach;
}
list_add(&attach->node, &dmabuf->attachments);
+err_alloc:
mutex_unlock(&dmabuf->lock);
return attach;
+err_attach:
kfree(attach);
mutex_unlock(&dmabuf->lock);
return ERR_PTR(ret);
+} +EXPORT_SYMBOL(dma_buf_attach);
+/**
- dma_buf_detach - Remove the given attachment from dmabuf's attachments
list;
- optionally calls detach() of dma_buf_ops for device-specific detach
- @dmabuf: [in] buffer to detach from.
- @attach: [in] attachment to be detached; is free'd after this
call.
- */
+void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) +{
BUG_ON(!dmabuf || !attach);
mutex_lock(&dmabuf->lock);
list_del(&attach->node);
if (dmabuf->ops->detach)
dmabuf->ops->detach(dmabuf, attach);
kfree(attach);
mutex_unlock(&dmabuf->lock);
return;
+} +EXPORT_SYMBOL(dma_buf_detach); diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h new file mode 100644 index 0000000..5bdf16a --- /dev/null +++ b/include/linux/dma-buf.h @@ -0,0 +1,162 @@ +/*
- Header file for dma buffer sharing framework.
- Copyright(C) 2011 Linaro Limited. All rights reserved.
- Author: Sumit Semwal sumit.semwal@ti.com
- Many thanks to linaro-mm-sig list, and specially
- Arnd Bergmann arnd@arndb.de, Rob Clark rob@ti.com and
- Daniel Vetter daniel@ffwll.ch for their support in creation and
- refining of this idea.
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License version 2 as
published by
- the Free Software Foundation.
- This program is distributed in the hope that it will be useful, but
WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for
- more details.
- You should have received a copy of the GNU General Public License along
with
- this program. If not, see http://www.gnu.org/licenses/.
- */
+#ifndef __DMA_BUF_H__ +#define __DMA_BUF_H__
+#include <linux/file.h> +#include <linux/err.h> +#include <linux/device.h> +#include <linux/scatterlist.h> +#include <linux/list.h> +#include <linux/dma-mapping.h>
+struct dma_buf;
+/**
- struct dma_buf_attachment - holds device-buffer attachment data
- @dmabuf: buffer for this attachment.
- @dev: device attached to the buffer.
- @node: list_head to allow manipulation of list of dma_buf_attachment.
- @priv: exporter-specific attachment data.
- */
+struct dma_buf_attachment {
struct dma_buf *dmabuf;
struct device *dev;
struct list_head node;
void *priv;
+};
+/**
- struct dma_buf_ops - operations possible on struct dma_buf
- @create: creates a struct dma_buf of a fixed size. Actual allocation
does not happen here.
- @attach: allows different devices to 'attach' themselves to the given
buffer. It might return -EBUSY to signal that backing storage
is already allocated and incompatible with the requirements
of requesting device. [optional]
- @detach: detach a given device from this buffer. [optional]
- @get_scatterlist: returns list of scatter pages allocated, increases
usecount of the buffer. Requires atleast one attach to
be
called before. Returned sg list should already be
mapped
into _device_ address space.
- @put_scatterlist: decreases usecount of buffer, might deallocate
scatter
pages.
- @mmap: memory map this buffer - optional.
- @release: release this buffer; to be called after the last dma_buf_put.
- @sync_sg_for_cpu: sync the sg list for cpu.
- @sync_sg_for_device: synch the sg list for device.
- */
+struct dma_buf_ops {
int (*attach)(struct dma_buf *, struct device *,
struct dma_buf_attachment *);
void (*detach)(struct dma_buf *, struct dma_buf_attachment *);
/* For {get,put}_scatterlist below, any specific buffer attributes
* required should get added to device_dma_parameters accessible
* via dev->dma_params.
*/
struct scatterlist * (*get_scatterlist)(struct dma_buf_attachment
*,
enum dma_data_direction,
int *nents);
void (*put_scatterlist)(struct dma_buf_attachment *,
struct scatterlist *,
int nents);
/* TODO: Add interruptible and interruptible_timeout versions */
/* allow mmap optionally for devices that need it */
int (*mmap)(struct dma_buf *, struct vm_area_struct *);
/* after final dma_buf_put() */
void (*release)(struct dma_buf *);
/* allow allocator to take care of cache ops */
void (*sync_sg_for_cpu) (struct dma_buf *, struct device *);
void (*sync_sg_for_device)(struct dma_buf *, struct device *);
+};
+/**
- struct dma_buf - shared buffer object
- @file: file pointer used for sharing buffers across, and for
refcounting.
- @attachments: list of dma_buf_attachment that denotes all devices
attached.
- @ops: dma_buf_ops associated with this buffer object
- @priv: user specific private data
- */
+struct dma_buf {
size_t size;
struct file *file;
struct list_head attachments;
const struct dma_buf_ops *ops;
/* mutex to serialize list manipulation and other ops */
struct mutex lock;
void *priv;
+};
+#ifdef CONFIG_DMA_SHARED_BUFFER +struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
struct device
*dev); +void dma_buf_detach(struct dma_buf *dmabuf,
struct dma_buf_attachment *dmabuf_attach);
+struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops, int flags); +int dma_buf_fd(struct dma_buf *dmabuf); +struct dma_buf *dma_buf_get(int fd); +void dma_buf_put(struct dma_buf *dmabuf);
+#else
+static inline struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
struct device *dev)
+{
return ERR_PTR(-ENODEV);
+}
+static inline void dma_buf_detach(struct dma_buf *dmabuf,
struct dma_buf_attachment *dmabuf_attach)
+{
return;
+}
+static inline struct dma_buf *dma_buf_export(void *priv,
struct dma_buf_ops *ops,
int flags)
+{
return ERR_PTR(-ENODEV);
+}
+static inline int dma_buf_fd(struct dma_buf *dmabuf) +{
return -ENODEV;
+}
+static inline struct dma_buf *dma_buf_get(int fd) +{
return ERR_PTR(-ENODEV);
+}
+static inline void dma_buf_put(struct dma_buf *dmabuf) +{
return;
+} +#endif /* CONFIG_DMA_SHARED_BUFFER */
+#endif /* __DMA_BUF_H__ */
1.7.4.1