From patchwork Fri Jan 20 15:32:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Gaignard X-Patchwork-Id: 92090 Delivered-To: patch@linaro.org Received: by 10.182.3.34 with SMTP id 2csp118770obz; Fri, 20 Jan 2017 07:32:47 -0800 (PST) X-Received: by 10.98.14.84 with SMTP id w81mr17410212pfi.168.1484926367548; Fri, 20 Jan 2017 07:32:47 -0800 (PST) Return-Path: Received: from gabe.freedesktop.org (gabe.freedesktop.org. [131.252.210.177]) by mx.google.com with ESMTPS id z21si7136663pgh.174.2017.01.20.07.32.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 20 Jan 2017 07:32:47 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) client-ip=131.252.210.177; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4F20D6EBD5; Fri, 20 Jan 2017 15:32:45 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-wm0-x236.google.com (mail-wm0-x236.google.com [IPv6:2a00:1450:400c:c09::236]) by gabe.freedesktop.org (Postfix) with ESMTPS id 110846EBD5 for ; Fri, 20 Jan 2017 15:32:44 +0000 (UTC) Received: by mail-wm0-x236.google.com with SMTP id r144so49090778wme.1 for ; Fri, 20 Jan 2017 07:32:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=jI/W0y7SthttXGX2kyMTy7GrgT9p0Y7VY6S93KWIG+c=; b=g9pDkZrPyn5TQKgQuMmmvfANwZEzv7KMqyznjDokUvOrI437VBdQB4tSpHFWkRR3lk osAkbRoFe+AtvMXo2zvBl7ObyFOluGAQIVKZ2q7fK/wWIeBarqTGomzPGD1AmL4asCIn J9yYf6A3gS2q4O7NfM7FyqAtdxK36oQYFLCoI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=jI/W0y7SthttXGX2kyMTy7GrgT9p0Y7VY6S93KWIG+c=; b=eCNa4jefurHyIhxlUUiJOtwNahZ1POGXdDS9S37nYM8/jmKpIh7R3FFgev56xAwuQM yCfIpuBNca/heTQFTHa08BPbhmZA1I9wsHlCA1ZGw6MqtH4r6PF+IbSTksOcrPEuJ3iT ABRQpU2NCF8iL/l3/S/Fb+QVRu4g+2huohxutcxjTCpHyQGUviBJxgc22zw7QOxE726o wx+9RgNa4DCIaruxEQkvxg7JqHC+i/n9dHWwwbir8zRFBMZz71Ue5uQsbeZGA5koePUN C10tjBkAIGJVfKKSlK/LAhJ6L79HKcHS/aCI9odPCICD19NBgJj5M4wiIBNEetlKHsWz Qm1A== X-Gm-Message-State: AIkVDXL66Uu5Jc3jxVfyBVn36m/YzxzP0JtRsOmxpJnZmKYhh0pFeFGEnSYjBNHgJSW+A+7M X-Received: by 10.28.26.203 with SMTP id a194mr4322028wma.84.1484926362422; Fri, 20 Jan 2017 07:32:42 -0800 (PST) Received: from lmenx321.st.com. ([80.214.31.157]) by smtp.gmail.com with ESMTPSA id 61sm252981wrs.29.2017.01.20.07.32.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 20 Jan 2017 07:32:41 -0800 (PST) From: Benjamin Gaignard To: linaro-kernel@lists.linaro.org, arnd@arndb.de, labbott@redhat.com, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, daniel.vetter@ffwll.ch, laurent.pinchart@ideasonboard.com, robdclark@gmail.com Subject: [RFC simple allocator v1 1/2] Create Simple Allocator module Date: Fri, 20 Jan 2017 16:32:30 +0100 Message-Id: <1484926351-30185-2-git-send-email-benjamin.gaignard@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1484926351-30185-1-git-send-email-benjamin.gaignard@linaro.org> References: <1484926351-30185-1-git-send-email-benjamin.gaignard@linaro.org> Cc: broonie@kernel.org 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: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" This is the core of simple allocator module. It aim to offert one common ioctl to allocate specific memory. Signed-off-by: Benjamin Gaignard --- Documentation/simple-allocator.txt | 81 +++++++++++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/simpleallocator/Kconfig | 10 ++ drivers/simpleallocator/Makefile | 1 + drivers/simpleallocator/simple-allocator-priv.h | 33 +++++ drivers/simpleallocator/simple-allocator.c | 180 ++++++++++++++++++++++++ include/uapi/linux/simple-allocator.h | 35 +++++ 8 files changed, 343 insertions(+) create mode 100644 Documentation/simple-allocator.txt create mode 100644 drivers/simpleallocator/Kconfig create mode 100644 drivers/simpleallocator/Makefile create mode 100644 drivers/simpleallocator/simple-allocator-priv.h create mode 100644 drivers/simpleallocator/simple-allocator.c create mode 100644 include/uapi/linux/simple-allocator.h diff --git a/Documentation/simple-allocator.txt b/Documentation/simple-allocator.txt new file mode 100644 index 0000000..89ba883 --- /dev/null +++ b/Documentation/simple-allocator.txt @@ -0,0 +1,81 @@ +Simple Allocator Framework + +Simple Allocator offer a single ioctl SA_IOC_ALLOC to allocate buffers +on dedicated memory regions and export them as a dmabuf file descriptor. +Using dmabuf file descriptor allow to share this memory between processes +and/or import it into other frameworks like v4l2 or drm/kms (prime). +When userland wants to free the memory only a call to close() in needed +so it could done even without knowing that buffer has been allocated by +simple allocator ioctl. + +Each memory regions will be seen as a filein /dev/. +For example CMA regions will exposed has /dev/cmaX. + +Implementing a simple allocator +------------------------------- + +Simple Allocator provide helpers functions to register/unregister an +allocator: +- simple_allocator_register(struct sa_device *sadev) + Register simple_allocator_device using sa_device structure where name, + owner and allocate fields must be set. + +- simple_allocator_unregister(struct sa_device *sadev) + Unregister a simple allocator device. + +Using Simple Allocator /dev interface example +--------------------------------------------- + +This example of code allocate a buffer on the first CMA region (/dev/cma0) +before mmap and close it. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "simple-allocator.h" + +#define LENGTH 1024*16 + +void main (void) +{ + struct simple_allocate_data data; + int fd = open("/dev/cma0", O_RDWR, 0); + int ret; + void *mem; + + if (fd < 0) { + printf("Can't open /dev/cma0\n"); + return; + } + + memset(&data, 0, sizeof(data)); + + data.length = LENGTH; + data.flags = O_RDWR | O_CLOEXEC; + + ret = ioctl(fd, SA_IOC_ALLOC, &data); + if (ret) { + printf("Buffer allocation failed\n"); + goto end; + } + + mem = mmap(0, LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, data.fd, 0); + if (mem == MAP_FAILED) { + printf("mmap failed\n"); + } + + memset(mem, 0xFF, LENGTH); + munmap(mem, LENGTH); + + printf("test simple allocator CMA OK\n"); +end: + close(fd); +} diff --git a/drivers/Kconfig b/drivers/Kconfig index e1e2066..a6d8828 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -202,4 +202,6 @@ source "drivers/hwtracing/intel_th/Kconfig" source "drivers/fpga/Kconfig" +source "drivers/simpleallocator/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 060026a..5081eb8 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -173,3 +173,4 @@ obj-$(CONFIG_STM) += hwtracing/stm/ obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_NVMEM) += nvmem/ obj-$(CONFIG_FPGA) += fpga/ +obj-$(CONFIG_SIMPLE_ALLOCATOR) += simpleallocator/ diff --git a/drivers/simpleallocator/Kconfig b/drivers/simpleallocator/Kconfig new file mode 100644 index 0000000..c6fc2e3 --- /dev/null +++ b/drivers/simpleallocator/Kconfig @@ -0,0 +1,10 @@ +menu "Simple Allocator" + +config SIMPLE_ALLOCATOR + tristate "Simple Alllocator Framework" + select DMA_SHARED_BUFFER + ---help--- + The Simple Allocator Framework adds an API to allocate and share + memory in userland. + +endmenu diff --git a/drivers/simpleallocator/Makefile b/drivers/simpleallocator/Makefile new file mode 100644 index 0000000..e27c6ad --- /dev/null +++ b/drivers/simpleallocator/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SIMPLE_ALLOCATOR) += simple-allocator.o diff --git a/drivers/simpleallocator/simple-allocator-priv.h b/drivers/simpleallocator/simple-allocator-priv.h new file mode 100644 index 0000000..33f5a33 --- /dev/null +++ b/drivers/simpleallocator/simple-allocator-priv.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) Linaro 2016 + * + * Author: Benjamin Gaignard + * + * License terms: GNU General Public License (GPL) + */ + +#ifndef _SIMPLE_ALLOCATOR_PRIV_H_ +#define _SIMPLE_ALLOCATOR_PRIV_H_ + +#include +#include +#include + +/** + * struct sa_device - simple allocator device + * @owner: module owner, must be set to THIS_MODULE + * @name: name of the allocator + * @allocate: callabck for memory allocation + */ +struct sa_device { + struct device dev; + struct cdev chrdev; + struct module *owner; + const char *name; + struct dma_buf *(*allocate)(struct sa_device *, u64 length, u32 flags); +}; + +int simple_allocator_register(struct sa_device *sadev); +void simple_allocator_unregister(struct sa_device *sadev); + +#endif diff --git a/drivers/simpleallocator/simple-allocator.c b/drivers/simpleallocator/simple-allocator.c new file mode 100644 index 0000000..2f82396 --- /dev/null +++ b/drivers/simpleallocator/simple-allocator.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) Linaro 2016 + * + * Author: Benjamin Gaignard + * + * License terms: GNU General Public License (GPL) + */ + +#include +#include +#include + +#include "simple-allocator-priv.h" + +#define SA_MAJOR 222 +#define SA_NUM_DEVICES 256 +#define SA_NAME "simple_allocator" + +static int sa_minor; + +static struct class sa_class = { + .name = SA_NAME, +}; + +static long sa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct sa_device *sadev = filp->private_data; + int ret = -ENODEV; + + switch (cmd) { + case SA_IOC_ALLOC: + { + struct simple_allocate_data data; + struct dma_buf *dmabuf; + + if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd))) + return -EFAULT; + + if (data.version != 0) + return -EINVAL; + + dmabuf = sadev->allocate(sadev, data.length, data.flags); + if (!dmabuf) + return -EINVAL; + + data.fd = dma_buf_fd(dmabuf, data.flags); + if (data.fd < 0) { + dma_buf_put(dmabuf); + return -EINVAL; + } + + data.length = dmabuf->size; + + if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) { + dma_buf_put(dmabuf); + return -EFAULT; + } + + return 0; + } + } + return ret; +} + +static int sa_open(struct inode *inode, struct file *filp) +{ + struct sa_device *sadev = container_of(inode->i_cdev, + struct sa_device, chrdev); + + if (!sadev) + return -ENODEV; + + get_device(&sadev->dev); + filp->private_data = sadev; + return 0; +} + +static int sa_release(struct inode *inode, struct file *filp) +{ + struct sa_device *sadev = container_of(inode->i_cdev, + struct sa_device, chrdev); + + if (!sadev) + return -ENODEV; + + put_device(&sadev->dev); + return 0; +} + +static const struct file_operations sa_fops = { + .owner = THIS_MODULE, + .open = sa_open, + .release = sa_release, + .unlocked_ioctl = sa_ioctl, +}; + +/** + * simple_allocator_register - register a simple allocator + * @sadev: simple allocator structure to be registered + * + * Return 0 if allocator has been regsitered, either a negative value. + */ +int simple_allocator_register(struct sa_device *sadev) +{ + int ret; + + if (!sadev->name || !sadev->allocate || !sadev->owner) + return -EINVAL; + + cdev_init(&sadev->chrdev, &sa_fops); + sadev->chrdev.owner = sadev->owner; + + ret = cdev_add(&sadev->chrdev, MKDEV(SA_MAJOR, sa_minor), 1); + if (ret < 0) + return ret; + + sadev->dev.class = &sa_class; + sadev->dev.devt = MKDEV(SA_MAJOR, sa_minor); + dev_set_name(&sadev->dev, "%s%d", sadev->name, sa_minor); + ret = device_register(&sadev->dev); + if (ret < 0) + goto cleanup; + + sa_minor++; + return 0; + +cleanup: + cdev_del(&sadev->chrdev); + return ret; +} +EXPORT_SYMBOL_GPL(simple_allocator_register); + +/** + * simple_allocator_unregister - unregister a simple allocator + * @sadev: simple allocator device to be unregistered + */ +void simple_allocator_unregister(struct sa_device *sadev) +{ + if (!sadev) + return; + + cdev_del(&sadev->chrdev); + device_del(&sadev->dev); + put_device(&sadev->dev); +} +EXPORT_SYMBOL_GPL(simple_allocator_unregister); + +static int __init sa_init(void) +{ + dev_t dev = MKDEV(SA_MAJOR, 0); + int ret; + + ret = register_chrdev_region(dev, SA_NUM_DEVICES, SA_NAME); + if (ret < 0) + return ret; + + ret = class_register(&sa_class); + if (ret < 0) { + unregister_chrdev_region(dev, SA_NUM_DEVICES); + return -EIO; + } + + return 0; +} + +static void __exit sa_exit(void) +{ + dev_t dev = MKDEV(SA_MAJOR, 0); + + class_unregister(&sa_class); + unregister_chrdev_region(dev, SA_NUM_DEVICES); +} + +subsys_initcall(sa_init); +module_exit(sa_exit); + +MODULE_AUTHOR("Benjamin Gaignard "); +MODULE_DESCRIPTION("Simple allocator"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(SA_MAJOR); diff --git a/include/uapi/linux/simple-allocator.h b/include/uapi/linux/simple-allocator.h new file mode 100644 index 0000000..5520a85 --- /dev/null +++ b/include/uapi/linux/simple-allocator.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) Linaro 2016 + * + * Author: Benjamin Gaignard + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _SIMPLE_ALLOCATOR_H_ +#define _SIMPLE_ALLOCATOR_H_ + +#include +#include + +/** + * struct simple_allocate_data - allocation parameters + * @version: structure version (must be set to 0) + * @length: size of the requested buffer + * @flags: mode flags for the file like O_RDWR or O_CLOEXEC + * @fd: returned file descriptor + */ +struct simple_allocate_data { + __u64 version; + __u64 length; + __u32 flags; + __u32 reserved1; + __s32 fd; + __u32 reserved2; +}; + +#define SA_IOC_MAGIC 'S' + +#define SA_IOC_ALLOC _IOWR(SA_IOC_MAGIC, 0, struct simple_allocate_data) + +#endif