Hi JFD, Thanks for reporting the issue.
On Mon, 2019-07-08 at 09:01:03 -0700, Jean-Francois Dagenais wrote: > Anyone tried that? I get: > > WARNING: modpost: missing MODULE_LICENSE() in drivers/uio/uio_dmabuf.o > see include/linux/module.h for more information > ERROR: "uio_dmabuf_map" [drivers/uio/uio.ko] undefined! > ERROR: "uio_dmabuf_unmap" [drivers/uio/uio.ko] undefined! > ERROR: "uio_dmabuf_cleanup" [drivers/uio/uio.ko] undefined! > > uio/Makefile shows: > obj-$(CONFIG_UIO) += uio.o uio_dmabuf.o > > I got it to compile by hacking uio.c to #include uio_dmabuf.c instead of the > .h but that's probably not the correct way to fix this. > The easiest fix would be to merge uio_dmabuf.c into uio.c. Please see the attached patch and let me know if you see any other better way. Thanks, -hyun >From 84cbe02cf2775dca911c2b734dded794150698a8 Mon Sep 17 00:00:00 2001 From: Hyun Kwon <[email protected]> Date: Mon, 8 Jul 2019 11:37:03 -0700 Subject: [PATCH 1/1] uio: dmabuf: Merge the dmabuf functions into uio.c With a separate uio_dmabuf.c, it's tricky to build the uio as a separate kernel module. Reported-by: Jean-Francois Dagenais <[email protected]> Signed-off-by: Hyun Kwon <[email protected]> --- drivers/uio/Makefile | 2 +- drivers/uio/uio.c | 191 ++++++++++++++++++++++++++++++++++++++++++ drivers/uio/uio_dmabuf.c | 210 ----------------------------------------------- 3 files changed, 192 insertions(+), 211 deletions(-) delete mode 100644 drivers/uio/uio_dmabuf.c diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index 7af888a..aea3e17 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_UIO) += uio.o uio_dmabuf.o +obj-$(CONFIG_UIO) += uio.o obj-$(CONFIG_UIO_CIF) += uio_cif.o obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o obj-$(CONFIG_UIO_DMEM_GENIRQ) += uio_dmem_genirq.o diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index e054fa7..175fb6b 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -26,6 +26,7 @@ #include <linux/uio_driver.h> #include <linux/list.h> #include <linux/mutex.h> +#include <linux/dma-buf.h> #include <uapi/linux/uio/uio.h> @@ -455,6 +456,196 @@ static irqreturn_t uio_interrupt(int irq, void *dev_id) return ret; } +struct uio_dmabuf_mem { + int dbuf_fd; + struct dma_buf *dbuf; + struct dma_buf_attachment *dbuf_attach; + struct sg_table *sgt; + enum dma_data_direction dir; + struct list_head list; +}; + +long uio_dmabuf_map(struct uio_device *dev, struct list_head *dbufs, + struct mutex *dbufs_lock, void __user *user_args) +{ + struct uio_dmabuf_args args; + struct uio_dmabuf_mem *dbuf_mem; + struct dma_buf *dbuf; + struct dma_buf_attachment *dbuf_attach; + enum dma_data_direction dir; + struct sg_table *sgt; + long ret; + + if (copy_from_user(&args, user_args, sizeof(args))) { + ret = -EFAULT; + dev_err(dev->dev.parent, "failed to copy from user\n"); + goto err; + } + + dbuf = dma_buf_get(args.dbuf_fd); + if (IS_ERR(dbuf)) { + dev_err(dev->dev.parent, "failed to get dmabuf\n"); + return PTR_ERR(dbuf); + } + + dbuf_attach = dma_buf_attach(dbuf, dev->dev.parent); + if (IS_ERR(dbuf_attach)) { + dev_err(dev->dev.parent, "failed to attach dmabuf\n"); + ret = PTR_ERR(dbuf_attach); + goto err_put; + } + + switch (args.dir) { + case UIO_DMABUF_DIR_BIDIR: + dir = DMA_BIDIRECTIONAL; + break; + case UIO_DMABUF_DIR_TO_DEV: + dir = DMA_TO_DEVICE; + break; + case UIO_DMABUF_DIR_FROM_DEV: + dir = DMA_FROM_DEVICE; + break; + default: + /* Not needed with check. Just here for any future change */ + dev_err(dev->dev.parent, "invalid direction\n"); + ret = -EINVAL; + goto err_detach; + } + + sgt = dma_buf_map_attachment(dbuf_attach, dir); + if (IS_ERR(sgt)) { + dev_err(dev->dev.parent, "failed to get dmabuf scatterlist\n"); + ret = PTR_ERR(sgt); + goto err_detach; + } + + /* Accept only contiguous one */ + if (sgt->nents != 1) { + dma_addr_t next_addr = sg_dma_address(sgt->sgl); + struct scatterlist *s; + unsigned int i; + + for_each_sg(sgt->sgl, s, sgt->nents, i) { + if (!sg_dma_len(s)) + continue; + + if (sg_dma_address(s) != next_addr) { + dev_err(dev->dev.parent, + "dmabuf not contiguous\n"); + ret = -EINVAL; + goto err_unmap; + } + + next_addr = sg_dma_address(s) + sg_dma_len(s); + } + } + + dbuf_mem = kzalloc(sizeof(*dbuf_mem), GFP_KERNEL); + if (!dbuf_mem) { + ret = -ENOMEM; + goto err_unmap; + } + + dbuf_mem->dbuf_fd = args.dbuf_fd; + dbuf_mem->dbuf = dbuf; + dbuf_mem->dbuf_attach = dbuf_attach; + dbuf_mem->sgt = sgt; + dbuf_mem->dir = dir; + args.dma_addr = sg_dma_address(sgt->sgl); + args.size = dbuf->size; + + if (copy_to_user(user_args, &args, sizeof(args))) { + ret = -EFAULT; + dev_err(dev->dev.parent, "failed to copy to user\n"); + goto err_free; + } + + mutex_lock(dbufs_lock); + list_add(&dbuf_mem->list, dbufs); + mutex_unlock(dbufs_lock); + + return 0; + +err_free: + kfree(dbuf_mem); +err_unmap: + dma_buf_unmap_attachment(dbuf_attach, sgt, dir); +err_detach: + dma_buf_detach(dbuf, dbuf_attach); +err_put: + dma_buf_put(dbuf); +err: + return ret; +} + +long uio_dmabuf_unmap(struct uio_device *dev, struct list_head *dbufs, + struct mutex *dbufs_lock, void __user *user_args) + +{ + struct uio_dmabuf_args args; + struct uio_dmabuf_mem *dbuf_mem; + long ret; + + if (copy_from_user(&args, user_args, sizeof(args))) { + ret = -EFAULT; + goto err; + } + + mutex_lock(dbufs_lock); + list_for_each_entry(dbuf_mem, dbufs, list) { + if (dbuf_mem->dbuf_fd == args.dbuf_fd) + break; + } + + if (dbuf_mem->dbuf_fd != args.dbuf_fd) { + dev_err(dev->dev.parent, "failed to find the dmabuf (%d)\n", + args.dbuf_fd); + ret = -EINVAL; + goto err_unlock; + } + list_del(&dbuf_mem->list); + mutex_unlock(dbufs_lock); + + dma_buf_unmap_attachment(dbuf_mem->dbuf_attach, dbuf_mem->sgt, + dbuf_mem->dir); + dma_buf_detach(dbuf_mem->dbuf, dbuf_mem->dbuf_attach); + dma_buf_put(dbuf_mem->dbuf); + kfree(dbuf_mem); + + memset(&args, 0x0, sizeof(args)); + + if (copy_to_user(user_args, &args, sizeof(args))) { + ret = -EFAULT; + goto err; + } + + return 0; + +err_unlock: + mutex_unlock(dbufs_lock); +err: + return ret; +} + +int uio_dmabuf_cleanup(struct uio_device *dev, struct list_head *dbufs, + struct mutex *dbufs_lock) +{ + struct uio_dmabuf_mem *dbuf_mem, *next; + + mutex_lock(dbufs_lock); + list_for_each_entry_safe(dbuf_mem, next, dbufs, list) { + list_del(&dbuf_mem->list); + dma_buf_unmap_attachment(dbuf_mem->dbuf_attach, dbuf_mem->sgt, + dbuf_mem->dir); + dma_buf_detach(dbuf_mem->dbuf, dbuf_mem->dbuf_attach); + dma_buf_put(dbuf_mem->dbuf); + kfree(dbuf_mem); + } + mutex_unlock(dbufs_lock); + + return 0; +} + struct uio_listener { struct uio_device *dev; s32 event_count; diff --git a/drivers/uio/uio_dmabuf.c b/drivers/uio/uio_dmabuf.c deleted file mode 100644 index b18f146..0000000 --- a/drivers/uio/uio_dmabuf.c +++ /dev/null @@ -1,210 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2019 Xilinx, Inc. - * - * Author: Hyun Woo Kwon <[email protected]> - * - * DMA buf support for UIO device - * - */ - -#include <linux/dma-buf.h> -#include <linux/list.h> -#include <linux/mutex.h> -#include <linux/uaccess.h> -#include <linux/uio_driver.h> -#include <linux/slab.h> - -#include <uapi/linux/uio/uio.h> - -#include "uio_dmabuf.h" - -struct uio_dmabuf_mem { - int dbuf_fd; - struct dma_buf *dbuf; - struct dma_buf_attachment *dbuf_attach; - struct sg_table *sgt; - enum dma_data_direction dir; - struct list_head list; -}; - -long uio_dmabuf_map(struct uio_device *dev, struct list_head *dbufs, - struct mutex *dbufs_lock, void __user *user_args) -{ - struct uio_dmabuf_args args; - struct uio_dmabuf_mem *dbuf_mem; - struct dma_buf *dbuf; - struct dma_buf_attachment *dbuf_attach; - enum dma_data_direction dir; - struct sg_table *sgt; - long ret; - - if (copy_from_user(&args, user_args, sizeof(args))) { - ret = -EFAULT; - dev_err(dev->dev.parent, "failed to copy from user\n"); - goto err; - } - - dbuf = dma_buf_get(args.dbuf_fd); - if (IS_ERR(dbuf)) { - dev_err(dev->dev.parent, "failed to get dmabuf\n"); - return PTR_ERR(dbuf); - } - - dbuf_attach = dma_buf_attach(dbuf, dev->dev.parent); - if (IS_ERR(dbuf_attach)) { - dev_err(dev->dev.parent, "failed to attach dmabuf\n"); - ret = PTR_ERR(dbuf_attach); - goto err_put; - } - - switch (args.dir) { - case UIO_DMABUF_DIR_BIDIR: - dir = DMA_BIDIRECTIONAL; - break; - case UIO_DMABUF_DIR_TO_DEV: - dir = DMA_TO_DEVICE; - break; - case UIO_DMABUF_DIR_FROM_DEV: - dir = DMA_FROM_DEVICE; - break; - default: - /* Not needed with check. Just here for any future change */ - dev_err(dev->dev.parent, "invalid direction\n"); - ret = -EINVAL; - goto err_detach; - } - - sgt = dma_buf_map_attachment(dbuf_attach, dir); - if (IS_ERR(sgt)) { - dev_err(dev->dev.parent, "failed to get dmabuf scatterlist\n"); - ret = PTR_ERR(sgt); - goto err_detach; - } - - /* Accept only contiguous one */ - if (sgt->nents != 1) { - dma_addr_t next_addr = sg_dma_address(sgt->sgl); - struct scatterlist *s; - unsigned int i; - - for_each_sg(sgt->sgl, s, sgt->nents, i) { - if (!sg_dma_len(s)) - continue; - - if (sg_dma_address(s) != next_addr) { - dev_err(dev->dev.parent, - "dmabuf not contiguous\n"); - ret = -EINVAL; - goto err_unmap; - } - - next_addr = sg_dma_address(s) + sg_dma_len(s); - } - } - - dbuf_mem = kzalloc(sizeof(*dbuf_mem), GFP_KERNEL); - if (!dbuf_mem) { - ret = -ENOMEM; - goto err_unmap; - } - - dbuf_mem->dbuf_fd = args.dbuf_fd; - dbuf_mem->dbuf = dbuf; - dbuf_mem->dbuf_attach = dbuf_attach; - dbuf_mem->sgt = sgt; - dbuf_mem->dir = dir; - args.dma_addr = sg_dma_address(sgt->sgl); - args.size = dbuf->size; - - if (copy_to_user(user_args, &args, sizeof(args))) { - ret = -EFAULT; - dev_err(dev->dev.parent, "failed to copy to user\n"); - goto err_free; - } - - mutex_lock(dbufs_lock); - list_add(&dbuf_mem->list, dbufs); - mutex_unlock(dbufs_lock); - - return 0; - -err_free: - kfree(dbuf_mem); -err_unmap: - dma_buf_unmap_attachment(dbuf_attach, sgt, dir); -err_detach: - dma_buf_detach(dbuf, dbuf_attach); -err_put: - dma_buf_put(dbuf); -err: - return ret; -} - -long uio_dmabuf_unmap(struct uio_device *dev, struct list_head *dbufs, - struct mutex *dbufs_lock, void __user *user_args) - -{ - struct uio_dmabuf_args args; - struct uio_dmabuf_mem *dbuf_mem; - long ret; - - if (copy_from_user(&args, user_args, sizeof(args))) { - ret = -EFAULT; - goto err; - } - - mutex_lock(dbufs_lock); - list_for_each_entry(dbuf_mem, dbufs, list) { - if (dbuf_mem->dbuf_fd == args.dbuf_fd) - break; - } - - if (dbuf_mem->dbuf_fd != args.dbuf_fd) { - dev_err(dev->dev.parent, "failed to find the dmabuf (%d)\n", - args.dbuf_fd); - ret = -EINVAL; - goto err_unlock; - } - list_del(&dbuf_mem->list); - mutex_unlock(dbufs_lock); - - dma_buf_unmap_attachment(dbuf_mem->dbuf_attach, dbuf_mem->sgt, - dbuf_mem->dir); - dma_buf_detach(dbuf_mem->dbuf, dbuf_mem->dbuf_attach); - dma_buf_put(dbuf_mem->dbuf); - kfree(dbuf_mem); - - memset(&args, 0x0, sizeof(args)); - - if (copy_to_user(user_args, &args, sizeof(args))) { - ret = -EFAULT; - goto err; - } - - return 0; - -err_unlock: - mutex_unlock(dbufs_lock); -err: - return ret; -} - -int uio_dmabuf_cleanup(struct uio_device *dev, struct list_head *dbufs, - struct mutex *dbufs_lock) -{ - struct uio_dmabuf_mem *dbuf_mem, *next; - - mutex_lock(dbufs_lock); - list_for_each_entry_safe(dbuf_mem, next, dbufs, list) { - list_del(&dbuf_mem->list); - dma_buf_unmap_attachment(dbuf_mem->dbuf_attach, dbuf_mem->sgt, - dbuf_mem->dir); - dma_buf_detach(dbuf_mem->dbuf, dbuf_mem->dbuf_attach); - dma_buf_put(dbuf_mem->dbuf); - kfree(dbuf_mem); - } - mutex_unlock(dbufs_lock); - - return 0; -} -- 2.7.4
>From 84cbe02cf2775dca911c2b734dded794150698a8 Mon Sep 17 00:00:00 2001 From: Hyun Kwon <[email protected]> Date: Mon, 8 Jul 2019 11:37:03 -0700 Subject: [PATCH 1/1] uio: dmabuf: Merge the dmabuf functions into uio.c With a separate uio_dmabuf.c, it's tricky to build the uio as a separate kernel module. Reported-by: Jean-Francois Dagenais <[email protected]> Signed-off-by: Hyun Kwon <[email protected]> --- drivers/uio/Makefile | 2 +- drivers/uio/uio.c | 191 ++++++++++++++++++++++++++++++++++++++++++ drivers/uio/uio_dmabuf.c | 210 ----------------------------------------------- 3 files changed, 192 insertions(+), 211 deletions(-) delete mode 100644 drivers/uio/uio_dmabuf.c diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index 7af888a..aea3e17 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_UIO) += uio.o uio_dmabuf.o +obj-$(CONFIG_UIO) += uio.o obj-$(CONFIG_UIO_CIF) += uio_cif.o obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o obj-$(CONFIG_UIO_DMEM_GENIRQ) += uio_dmem_genirq.o diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index e054fa7..175fb6b 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -26,6 +26,7 @@ #include <linux/uio_driver.h> #include <linux/list.h> #include <linux/mutex.h> +#include <linux/dma-buf.h> #include <uapi/linux/uio/uio.h> @@ -455,6 +456,196 @@ static irqreturn_t uio_interrupt(int irq, void *dev_id) return ret; } +struct uio_dmabuf_mem { + int dbuf_fd; + struct dma_buf *dbuf; + struct dma_buf_attachment *dbuf_attach; + struct sg_table *sgt; + enum dma_data_direction dir; + struct list_head list; +}; + +long uio_dmabuf_map(struct uio_device *dev, struct list_head *dbufs, + struct mutex *dbufs_lock, void __user *user_args) +{ + struct uio_dmabuf_args args; + struct uio_dmabuf_mem *dbuf_mem; + struct dma_buf *dbuf; + struct dma_buf_attachment *dbuf_attach; + enum dma_data_direction dir; + struct sg_table *sgt; + long ret; + + if (copy_from_user(&args, user_args, sizeof(args))) { + ret = -EFAULT; + dev_err(dev->dev.parent, "failed to copy from user\n"); + goto err; + } + + dbuf = dma_buf_get(args.dbuf_fd); + if (IS_ERR(dbuf)) { + dev_err(dev->dev.parent, "failed to get dmabuf\n"); + return PTR_ERR(dbuf); + } + + dbuf_attach = dma_buf_attach(dbuf, dev->dev.parent); + if (IS_ERR(dbuf_attach)) { + dev_err(dev->dev.parent, "failed to attach dmabuf\n"); + ret = PTR_ERR(dbuf_attach); + goto err_put; + } + + switch (args.dir) { + case UIO_DMABUF_DIR_BIDIR: + dir = DMA_BIDIRECTIONAL; + break; + case UIO_DMABUF_DIR_TO_DEV: + dir = DMA_TO_DEVICE; + break; + case UIO_DMABUF_DIR_FROM_DEV: + dir = DMA_FROM_DEVICE; + break; + default: + /* Not needed with check. Just here for any future change */ + dev_err(dev->dev.parent, "invalid direction\n"); + ret = -EINVAL; + goto err_detach; + } + + sgt = dma_buf_map_attachment(dbuf_attach, dir); + if (IS_ERR(sgt)) { + dev_err(dev->dev.parent, "failed to get dmabuf scatterlist\n"); + ret = PTR_ERR(sgt); + goto err_detach; + } + + /* Accept only contiguous one */ + if (sgt->nents != 1) { + dma_addr_t next_addr = sg_dma_address(sgt->sgl); + struct scatterlist *s; + unsigned int i; + + for_each_sg(sgt->sgl, s, sgt->nents, i) { + if (!sg_dma_len(s)) + continue; + + if (sg_dma_address(s) != next_addr) { + dev_err(dev->dev.parent, + "dmabuf not contiguous\n"); + ret = -EINVAL; + goto err_unmap; + } + + next_addr = sg_dma_address(s) + sg_dma_len(s); + } + } + + dbuf_mem = kzalloc(sizeof(*dbuf_mem), GFP_KERNEL); + if (!dbuf_mem) { + ret = -ENOMEM; + goto err_unmap; + } + + dbuf_mem->dbuf_fd = args.dbuf_fd; + dbuf_mem->dbuf = dbuf; + dbuf_mem->dbuf_attach = dbuf_attach; + dbuf_mem->sgt = sgt; + dbuf_mem->dir = dir; + args.dma_addr = sg_dma_address(sgt->sgl); + args.size = dbuf->size; + + if (copy_to_user(user_args, &args, sizeof(args))) { + ret = -EFAULT; + dev_err(dev->dev.parent, "failed to copy to user\n"); + goto err_free; + } + + mutex_lock(dbufs_lock); + list_add(&dbuf_mem->list, dbufs); + mutex_unlock(dbufs_lock); + + return 0; + +err_free: + kfree(dbuf_mem); +err_unmap: + dma_buf_unmap_attachment(dbuf_attach, sgt, dir); +err_detach: + dma_buf_detach(dbuf, dbuf_attach); +err_put: + dma_buf_put(dbuf); +err: + return ret; +} + +long uio_dmabuf_unmap(struct uio_device *dev, struct list_head *dbufs, + struct mutex *dbufs_lock, void __user *user_args) + +{ + struct uio_dmabuf_args args; + struct uio_dmabuf_mem *dbuf_mem; + long ret; + + if (copy_from_user(&args, user_args, sizeof(args))) { + ret = -EFAULT; + goto err; + } + + mutex_lock(dbufs_lock); + list_for_each_entry(dbuf_mem, dbufs, list) { + if (dbuf_mem->dbuf_fd == args.dbuf_fd) + break; + } + + if (dbuf_mem->dbuf_fd != args.dbuf_fd) { + dev_err(dev->dev.parent, "failed to find the dmabuf (%d)\n", + args.dbuf_fd); + ret = -EINVAL; + goto err_unlock; + } + list_del(&dbuf_mem->list); + mutex_unlock(dbufs_lock); + + dma_buf_unmap_attachment(dbuf_mem->dbuf_attach, dbuf_mem->sgt, + dbuf_mem->dir); + dma_buf_detach(dbuf_mem->dbuf, dbuf_mem->dbuf_attach); + dma_buf_put(dbuf_mem->dbuf); + kfree(dbuf_mem); + + memset(&args, 0x0, sizeof(args)); + + if (copy_to_user(user_args, &args, sizeof(args))) { + ret = -EFAULT; + goto err; + } + + return 0; + +err_unlock: + mutex_unlock(dbufs_lock); +err: + return ret; +} + +int uio_dmabuf_cleanup(struct uio_device *dev, struct list_head *dbufs, + struct mutex *dbufs_lock) +{ + struct uio_dmabuf_mem *dbuf_mem, *next; + + mutex_lock(dbufs_lock); + list_for_each_entry_safe(dbuf_mem, next, dbufs, list) { + list_del(&dbuf_mem->list); + dma_buf_unmap_attachment(dbuf_mem->dbuf_attach, dbuf_mem->sgt, + dbuf_mem->dir); + dma_buf_detach(dbuf_mem->dbuf, dbuf_mem->dbuf_attach); + dma_buf_put(dbuf_mem->dbuf); + kfree(dbuf_mem); + } + mutex_unlock(dbufs_lock); + + return 0; +} + struct uio_listener { struct uio_device *dev; s32 event_count; diff --git a/drivers/uio/uio_dmabuf.c b/drivers/uio/uio_dmabuf.c deleted file mode 100644 index b18f146..0000000 --- a/drivers/uio/uio_dmabuf.c +++ /dev/null @@ -1,210 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2019 Xilinx, Inc. - * - * Author: Hyun Woo Kwon <[email protected]> - * - * DMA buf support for UIO device - * - */ - -#include <linux/dma-buf.h> -#include <linux/list.h> -#include <linux/mutex.h> -#include <linux/uaccess.h> -#include <linux/uio_driver.h> -#include <linux/slab.h> - -#include <uapi/linux/uio/uio.h> - -#include "uio_dmabuf.h" - -struct uio_dmabuf_mem { - int dbuf_fd; - struct dma_buf *dbuf; - struct dma_buf_attachment *dbuf_attach; - struct sg_table *sgt; - enum dma_data_direction dir; - struct list_head list; -}; - -long uio_dmabuf_map(struct uio_device *dev, struct list_head *dbufs, - struct mutex *dbufs_lock, void __user *user_args) -{ - struct uio_dmabuf_args args; - struct uio_dmabuf_mem *dbuf_mem; - struct dma_buf *dbuf; - struct dma_buf_attachment *dbuf_attach; - enum dma_data_direction dir; - struct sg_table *sgt; - long ret; - - if (copy_from_user(&args, user_args, sizeof(args))) { - ret = -EFAULT; - dev_err(dev->dev.parent, "failed to copy from user\n"); - goto err; - } - - dbuf = dma_buf_get(args.dbuf_fd); - if (IS_ERR(dbuf)) { - dev_err(dev->dev.parent, "failed to get dmabuf\n"); - return PTR_ERR(dbuf); - } - - dbuf_attach = dma_buf_attach(dbuf, dev->dev.parent); - if (IS_ERR(dbuf_attach)) { - dev_err(dev->dev.parent, "failed to attach dmabuf\n"); - ret = PTR_ERR(dbuf_attach); - goto err_put; - } - - switch (args.dir) { - case UIO_DMABUF_DIR_BIDIR: - dir = DMA_BIDIRECTIONAL; - break; - case UIO_DMABUF_DIR_TO_DEV: - dir = DMA_TO_DEVICE; - break; - case UIO_DMABUF_DIR_FROM_DEV: - dir = DMA_FROM_DEVICE; - break; - default: - /* Not needed with check. Just here for any future change */ - dev_err(dev->dev.parent, "invalid direction\n"); - ret = -EINVAL; - goto err_detach; - } - - sgt = dma_buf_map_attachment(dbuf_attach, dir); - if (IS_ERR(sgt)) { - dev_err(dev->dev.parent, "failed to get dmabuf scatterlist\n"); - ret = PTR_ERR(sgt); - goto err_detach; - } - - /* Accept only contiguous one */ - if (sgt->nents != 1) { - dma_addr_t next_addr = sg_dma_address(sgt->sgl); - struct scatterlist *s; - unsigned int i; - - for_each_sg(sgt->sgl, s, sgt->nents, i) { - if (!sg_dma_len(s)) - continue; - - if (sg_dma_address(s) != next_addr) { - dev_err(dev->dev.parent, - "dmabuf not contiguous\n"); - ret = -EINVAL; - goto err_unmap; - } - - next_addr = sg_dma_address(s) + sg_dma_len(s); - } - } - - dbuf_mem = kzalloc(sizeof(*dbuf_mem), GFP_KERNEL); - if (!dbuf_mem) { - ret = -ENOMEM; - goto err_unmap; - } - - dbuf_mem->dbuf_fd = args.dbuf_fd; - dbuf_mem->dbuf = dbuf; - dbuf_mem->dbuf_attach = dbuf_attach; - dbuf_mem->sgt = sgt; - dbuf_mem->dir = dir; - args.dma_addr = sg_dma_address(sgt->sgl); - args.size = dbuf->size; - - if (copy_to_user(user_args, &args, sizeof(args))) { - ret = -EFAULT; - dev_err(dev->dev.parent, "failed to copy to user\n"); - goto err_free; - } - - mutex_lock(dbufs_lock); - list_add(&dbuf_mem->list, dbufs); - mutex_unlock(dbufs_lock); - - return 0; - -err_free: - kfree(dbuf_mem); -err_unmap: - dma_buf_unmap_attachment(dbuf_attach, sgt, dir); -err_detach: - dma_buf_detach(dbuf, dbuf_attach); -err_put: - dma_buf_put(dbuf); -err: - return ret; -} - -long uio_dmabuf_unmap(struct uio_device *dev, struct list_head *dbufs, - struct mutex *dbufs_lock, void __user *user_args) - -{ - struct uio_dmabuf_args args; - struct uio_dmabuf_mem *dbuf_mem; - long ret; - - if (copy_from_user(&args, user_args, sizeof(args))) { - ret = -EFAULT; - goto err; - } - - mutex_lock(dbufs_lock); - list_for_each_entry(dbuf_mem, dbufs, list) { - if (dbuf_mem->dbuf_fd == args.dbuf_fd) - break; - } - - if (dbuf_mem->dbuf_fd != args.dbuf_fd) { - dev_err(dev->dev.parent, "failed to find the dmabuf (%d)\n", - args.dbuf_fd); - ret = -EINVAL; - goto err_unlock; - } - list_del(&dbuf_mem->list); - mutex_unlock(dbufs_lock); - - dma_buf_unmap_attachment(dbuf_mem->dbuf_attach, dbuf_mem->sgt, - dbuf_mem->dir); - dma_buf_detach(dbuf_mem->dbuf, dbuf_mem->dbuf_attach); - dma_buf_put(dbuf_mem->dbuf); - kfree(dbuf_mem); - - memset(&args, 0x0, sizeof(args)); - - if (copy_to_user(user_args, &args, sizeof(args))) { - ret = -EFAULT; - goto err; - } - - return 0; - -err_unlock: - mutex_unlock(dbufs_lock); -err: - return ret; -} - -int uio_dmabuf_cleanup(struct uio_device *dev, struct list_head *dbufs, - struct mutex *dbufs_lock) -{ - struct uio_dmabuf_mem *dbuf_mem, *next; - - mutex_lock(dbufs_lock); - list_for_each_entry_safe(dbuf_mem, next, dbufs, list) { - list_del(&dbuf_mem->list); - dma_buf_unmap_attachment(dbuf_mem->dbuf_attach, dbuf_mem->sgt, - dbuf_mem->dir); - dma_buf_detach(dbuf_mem->dbuf, dbuf_mem->dbuf_attach); - dma_buf_put(dbuf_mem->dbuf); - kfree(dbuf_mem); - } - mutex_unlock(dbufs_lock); - - return 0; -} -- 2.7.4
-- _______________________________________________ meta-xilinx mailing list [email protected] https://lists.yoctoproject.org/listinfo/meta-xilinx
