From patchwork Wed Jan 4 13:34:39 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Noralf_Tr=C3=B8nnes?= X-Patchwork-Id: 9496959 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id F395A60237 for ; Wed, 4 Jan 2017 14:10:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E680627F93 for ; Wed, 4 Jan 2017 14:10:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DB82727FA6; Wed, 4 Jan 2017 14:10:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D9D2A2807B for ; Wed, 4 Jan 2017 14:10:29 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id ECADC6E727; Wed, 4 Jan 2017 14:10:10 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from smtp.domeneshop.no (smtp.domeneshop.no [IPv6:2a01:5b40:0:3005::1]) by gabe.freedesktop.org (Postfix) with ESMTPS id 406F56E726 for ; Wed, 4 Jan 2017 14:10:08 +0000 (UTC) Received: from 211.81-166-168.customer.lyse.net ([81.166.168.211]:42458 helo=localhost.localdomain) by smtp.domeneshop.no with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1cOlij-00006b-Qi; Wed, 04 Jan 2017 14:35:13 +0100 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= To: dri-devel@lists.freedesktop.org Subject: [RFC 3/6] dma-buf: Support generic userspace allocations Date: Wed, 4 Jan 2017 14:34:39 +0100 Message-Id: <20170104133442.4534-4-noralf@tronnes.org> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20170104133442.4534-1-noralf@tronnes.org> References: <20170104133442.4534-1-noralf@tronnes.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP Add a generic way for userspace to allocate dma-buf's for SPI transfers. Signed-off-by: Noralf Trønnes --- 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 +#include +#include +#include +#include + +#include + +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); + 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 + +/** + * 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