On Wed, Jan 04, 2017 at 02:34:39PM +0100, Noralf Trønnes wrote: > Add a generic way for userspace to allocate dma-buf's for SPI transfers. > > Signed-off-by: Noralf Trønnes <noralf@xxxxxxxxxxx> Having a central dma-buf allocator is a common thing, there's already ION in drivers/staging/android. If we need one I think it's better to accelarate ION destaging than creating yet another one. > --- > drivers/dma-buf/Makefile | 2 +- > drivers/dma-buf/dev.c | 211 +++++++++++++++++++++++++++++++++++++++ > include/uapi/linux/dma-buf-dev.h | 35 +++++++ > 3 files changed, 247 insertions(+), 1 deletion(-) > create mode 100644 drivers/dma-buf/dev.c > create mode 100644 include/uapi/linux/dma-buf-dev.h > > diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile > index 210a10b..ec867f7 100644 > --- a/drivers/dma-buf/Makefile > +++ b/drivers/dma-buf/Makefile > @@ -1,3 +1,3 @@ > -obj-y := dma-buf.o fence.o reservation.o seqno-fence.o fence-array.o > +obj-y := dma-buf.o fence.o reservation.o seqno-fence.o fence-array.o dev.o > obj-$(CONFIG_SYNC_FILE) += sync_file.o > obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o > diff --git a/drivers/dma-buf/dev.c b/drivers/dma-buf/dev.c > new file mode 100644 > index 0000000..536d9bf > --- /dev/null > +++ b/drivers/dma-buf/dev.c > @@ -0,0 +1,211 @@ > +/* > + * Copyright (C) 2016 Noralf Trønnes > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + */ > + > +#include <linux/dma-buf.h> > +#include <linux/miscdevice.h> > +#include <linux/module.h> > +#include <linux/slab.h> > +#include <linux/uaccess.h> > + > +#include <uapi/linux/dma-buf-dev.h> > + > +struct dma_buf_dev_object { > + struct device *dev; > + unsigned long attrs; > + dma_addr_t dma_addr; > + void *vaddr; > + size_t size; > +}; > + > +static struct sg_table * > +dma_buf_dev_map_dma_buf(struct dma_buf_attachment *attach, > + enum dma_data_direction dir) > +{ > + struct dma_buf_dev_object *obj = attach->dmabuf->priv; > + struct sg_table *sgt; > + int ret; > + > + sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); > + if (!sgt) > + return ERR_PTR(-ENOMEM); > + > + ret = dma_get_sgtable(obj->dev, sgt, obj->vaddr, > + obj->dma_addr, obj->size); > + if (ret < 0) > + goto err_free; > + > + if (!dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir)) { > + ret = -ENOMEM; > + goto err_free_table; > + } > + > + return sgt; > + > +err_free_table: > + sg_free_table(sgt); > +err_free: > + kfree(sgt); > + > + return ERR_PTR(ret); > +} > + > +static void dma_buf_dev_unmap_dma_buf(struct dma_buf_attachment *attach, > + struct sg_table *sgt, > + enum dma_data_direction dir) > +{ > + dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir); > + sg_free_table(sgt); > + kfree(sgt); > +} > + > +static void dma_buf_dev_release(struct dma_buf *dma_buf) > +{ > + struct dma_buf_dev_object *obj = dma_buf->priv; > + > +/* FIXME remove */ > +pr_info("%s()\n", __func__); > + dma_free_attrs(obj->dev, obj->size, obj->vaddr, obj->dma_addr, > + obj->attrs); > + kfree(obj); > +} > + > +static void *dma_buf_dev_kmap(struct dma_buf *dma_buf, unsigned long page_num) > +{ > + struct dma_buf_dev_object *obj = dma_buf->priv; > + > + return obj->vaddr + page_num * PAGE_SIZE; > +} > + > +static void *dma_buf_dev_vmap(struct dma_buf *dma_buf) > +{ > + struct dma_buf_dev_object *obj = dma_buf->priv; > + > + return obj->vaddr; > +} > + > +static int dma_buf_dev_mmap(struct dma_buf *dma_buf, > + struct vm_area_struct *vma) > +{ > + struct dma_buf_dev_object *obj = dma_buf->priv; > + int ret; > + > + vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; > + > + ret = dma_mmap_attrs(obj->dev, vma, obj->vaddr, obj->dma_addr, > + vma->vm_end - vma->vm_start, obj->attrs); > + > + return ret; > +} > + > +static const struct dma_buf_ops dma_buf_dev_ops = { > + .map_dma_buf = dma_buf_dev_map_dma_buf, > + .unmap_dma_buf = dma_buf_dev_unmap_dma_buf, > + .release = dma_buf_dev_release, > + .kmap_atomic = dma_buf_dev_kmap, > + .kmap = dma_buf_dev_kmap, > + .vmap = dma_buf_dev_vmap, > + .mmap = dma_buf_dev_mmap, > +}; > + > +struct dma_buf *dma_buf_dev_alloc_attrs(struct device *dev, size_t size, > + unsigned long attrs, int flags) > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct dma_buf_dev_object *obj; > + struct dma_buf *dmabuf; > + int ret; > + > + if (flags & ~(O_CLOEXEC | O_ACCMODE)) > + return ERR_PTR(-EINVAL); > + > + obj = kzalloc(sizeof(*obj), GFP_KERNEL); > + if (!obj) > + return ERR_PTR(-ENOMEM); > + > + obj->dev = dev; > + obj->size = size; > + obj->attrs = attrs; > + > + obj->vaddr = dma_alloc_attrs(dev, size, &obj->dma_addr, GFP_KERNEL, attrs); Hm, does dma_alloc reall always work with dev == NULL? I had no idea this was possible ... Cheers, Daniel > + if (!obj->vaddr) { > + ret = -ENOMEM; > + goto err_free_obj; > + } > + > + exp_info.ops = &dma_buf_dev_ops; > + exp_info.size = obj->size; > + exp_info.flags = flags; > + exp_info.priv = obj; > + > + dmabuf = dma_buf_export(&exp_info); > + if (IS_ERR(dmabuf)) { > + ret = PTR_ERR(dmabuf); > + goto err_free_buf; > + } > + > + return dmabuf; > + > +err_free_buf: > + dma_free_attrs(dev, size, obj->vaddr, obj->dma_addr, attrs); > +err_free_obj: > + kfree(obj); > + > + return ERR_PTR(ret); > +} > + > +static long dma_buf_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) > +{ > + struct dma_buf_dev_create create; > + struct dma_buf *dmabuf; > + > + switch (cmd) { > + case DMA_BUF_DEV_IOCTL_CREATE: > + > + if (copy_from_user(&create, (void __user *)arg, sizeof(create))) > + return -EFAULT; > + > + if (!create.size) > + return -EINVAL; > + > + dmabuf = dma_buf_dev_alloc_attrs(NULL, create.size, > + create.attrs, create.flags); > + if (IS_ERR(dmabuf)) > + return PTR_ERR(dmabuf); > + > + create.fd = dma_buf_fd(dmabuf, create.flags); > + if (create.fd < 0) { > + dma_buf_put(dmabuf); > + return create.fd; > + } > + > + if (copy_to_user((void __user *)arg, &create, sizeof(create))) > + return -EFAULT; > + > + return 0; > + default: > + return -ENOTTY; > + } > +} > + > +static const struct file_operations dma_buf_dev_fops = { > + .owner = THIS_MODULE, > + .unlocked_ioctl = dma_buf_dev_ioctl, > + .compat_ioctl = dma_buf_dev_ioctl, > +}; > + > +static struct miscdevice dma_buf_dev_misc = { > + .fops = &dma_buf_dev_fops, > + .minor = MISC_DYNAMIC_MINOR, > + .name = "dma-buf", > +}; > +module_misc_device(dma_buf_dev_misc); > + > +MODULE_AUTHOR("Noralf Trønnes"); > +MODULE_DESCRIPTION("User mode dma-buf creation"); > +MODULE_LICENSE("GPL"); > diff --git a/include/uapi/linux/dma-buf-dev.h b/include/uapi/linux/dma-buf-dev.h > new file mode 100644 > index 0000000..fddbe04 > --- /dev/null > +++ b/include/uapi/linux/dma-buf-dev.h > @@ -0,0 +1,35 @@ > +/* > + * Copyright (C) 2016 Noralf Trønnes > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + */ > + > +#ifndef _DMA_BUF_DEV_UAPI_H_ > +#define _DMA_BUF_DEV_UAPI_H_ > + > +#include <linux/types.h> > + > +/** > + * struct dma_buf_dev_create - > + * @attrs: Attributes of mapping properties requested in dma_alloc_attrs > + * @size: Buffer size > + * @flags: Mode flags for the dma-buf file > + * @fd: Returned dma-buf file descriptor > + */ > +struct dma_buf_dev_create { > + __u64 attrs; > +#define DMA_BUF_DEV_ATTR_WRITE_COMBINE BIT(2) > + __u64 size; > + __u64 flags; > + > + __s64 fd; > +}; > + > +/* FIXME: Update Documentation/ioctl/ioctl-number.txt */ > +#define DMA_BUF_DEV_BASE 0xB6 > +#define DMA_BUF_DEV_IOCTL_CREATE _IOWR(DMA_BUF_DEV_BASE, 0, struct dma_buf_dev_create) > + > +#endif > -- > 2.10.2 > > _______________________________________________ > dri-devel mailing list > dri-devel@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/dri-devel -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel