Message ID | 1551819273-640-2-git-send-email-john.stultz@linaro.org |
---|---|
State | New |
Headers | show |
Series | DMA-BUF Heaps (destaging ION) | expand |
On Wed, Mar 6, 2019 at 8:12 AM Benjamin Gaignard <benjamin.gaignard@linaro.org> wrote: > Le mar. 5 mars 2019 à 21:54, John Stultz <john.stultz@linaro.org> a écrit : > > +/** > > + * DOC: DMABUF Heaps Userspace API > > + * > > + */ > > + > > +/* Currently no flags */ > > +#define DMA_HEAP_VALID_FLAGS (0) > > I think here you need to allow flags like O_RDWR or O_CLOEXEC else > mmap will fail. > Hm. So I meant for these to be just the bitmask of valid flags for the allocate IOCTL (used to make sure no one is passing junk flags accidentally), rather then valid flags for the heap open call. But this probably suggests I should call it something like DMA_HEAP_ALLOC_VALID_FLAGS instead? thanks -john
> +static int dma_heap_release(struct inode *inode, struct file *filp) > +{ > + filp->private_data = NULL; > + > + return 0; > +} No point in clearing ->private_data, the file is about to be freed. > + > +static long dma_heap_ioctl(struct file *filp, unsigned int cmd, > + unsigned long arg) Pleae don't use the weird legacy filp naming, file is a perfectly valid and readable default name for struct file pointers. > +{ > + switch (cmd) { > + case DMA_HEAP_IOC_ALLOC: > + { > + struct dma_heap_allocation_data heap_allocation; > + struct dma_heap *heap = filp->private_data; > + int fd; Please split each ioctl into a separate function from the very start, otherwise this will grow into a spaghetty mess sooner than you can see cheese. > + dev_ret = device_create(dma_heap_class, > + NULL, > + heap->heap_devt, > + NULL, > + heap->name); No need this weird argument alignment.
Hi Benjamin, please fix your mailer to avoid completely pointless full quotes. Thank you!
On 3/5/19 12:54 PM, John Stultz wrote: > +DMA-BUF HEAPS FRAMEWORK > +M: Laura Abbott<labbott@redhat.com> > +R: Liam Mark<lmark@codeaurora.org> > +R: Brian Starkey<Brian.Starkey@arm.com> > +R: "Andrew F. Davis"<afd@ti.com> > +R: John Stultz<john.stultz@linaro.org> > +S: Maintained > +L: linux-media@vger.kernel.org > +L: dri-devel@lists.freedesktop.org > +L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers) > +F: include/uapi/linux/dma-heap.h > +F: include/linux/dma-heap.h > +F: drivers/dma-buf/dma-heap.c > +F: drivers/dma-buf/heaps/* > +T: git git://anongit.freedesktop.org/drm/drm-misc So I talked about this with Sumit privately but I think it might make sense to have me step down as maintainer when this goes out of staging. I mostly worked on Ion at my previous position and anything I do now is mostly a side project. I still want to see it succeed which is why I took on the maintainer role but I don't want to become blocking for people who have a stronger vision about where this needs to go (see also, I'm not working with this on a daily basis). If you just want someone to help review or take patches to be pulled, I'm happy to do so but I'd hate to become the bottleneck on getting things done for people who are attempting to do real work. Thanks, Laura
On Fri, Mar 15, 2019 at 1:18 PM Laura Abbott <labbott@redhat.com> wrote: > > On 3/5/19 12:54 PM, John Stultz wrote: > > +DMA-BUF HEAPS FRAMEWORK > > +M: Laura Abbott<labbott@redhat.com> > > +R: Liam Mark<lmark@codeaurora.org> > > +R: Brian Starkey<Brian.Starkey@arm.com> > > +R: "Andrew F. Davis"<afd@ti.com> > > +R: John Stultz<john.stultz@linaro.org> > > +S: Maintained > > +L: linux-media@vger.kernel.org > > +L: dri-devel@lists.freedesktop.org > > +L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers) > > +F: include/uapi/linux/dma-heap.h > > +F: include/linux/dma-heap.h > > +F: drivers/dma-buf/dma-heap.c > > +F: drivers/dma-buf/heaps/* > > +T: git git://anongit.freedesktop.org/drm/drm-misc > > So I talked about this with Sumit privately but I think > it might make sense to have me step down as maintainer when > this goes out of staging. I mostly worked on Ion at my > previous position and anything I do now is mostly a side > project. I still want to see it succeed which is why I > took on the maintainer role but I don't want to become blocking > for people who have a stronger vision about where this needs > to go (see also, I'm not working with this on a daily basis). > > If you just want someone to help review or take patches > to be pulled, I'm happy to do so but I'd hate to become > the bottleneck on getting things done for people who > are attempting to do real work. I worry this will make everyone to touch the side of their nose and yell "NOT IT!" :) First of all, thank you so much for your efforts maintaining ION along with your attempts to drag out requirements from interested parties and the numerous attempts to get collaborative discussion going at countless conferences! Your persistence and continual nudging in the face of apathetic private users of the code probably cannot be appreciated enough! Your past practical experience with ION and active work with the upstream community made you a stand out pick for this, but I understand not wanting to be eternally stuck with a maintainership if your not active in the area. I'm happy to volunteer as a neutral party, but I worry my limited experience with some of the more complicated usage would make my opinions less informed then they probably need to be. Further, as a neutral party, Sumit would probably be a better pick since he's already maintaining the dmabuf core. So I'd nominate Andrew, Liam or Benjamin (or all three?) as they all have more practical experience enabling past ION heaps on real devices and have demonstrated active interest in working in the community. So, in other words... NOT IT! :) -john
On 3/15/19 2:29 PM, John Stultz wrote: > On Fri, Mar 15, 2019 at 1:18 PM Laura Abbott <labbott@redhat.com> wrote: >> >> On 3/5/19 12:54 PM, John Stultz wrote: >>> +DMA-BUF HEAPS FRAMEWORK >>> +M: Laura Abbott<labbott@redhat.com> >>> +R: Liam Mark<lmark@codeaurora.org> >>> +R: Brian Starkey<Brian.Starkey@arm.com> >>> +R: "Andrew F. Davis"<afd@ti.com> >>> +R: John Stultz<john.stultz@linaro.org> >>> +S: Maintained >>> +L: linux-media@vger.kernel.org >>> +L: dri-devel@lists.freedesktop.org >>> +L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers) >>> +F: include/uapi/linux/dma-heap.h >>> +F: include/linux/dma-heap.h >>> +F: drivers/dma-buf/dma-heap.c >>> +F: drivers/dma-buf/heaps/* >>> +T: git git://anongit.freedesktop.org/drm/drm-misc >> >> So I talked about this with Sumit privately but I think >> it might make sense to have me step down as maintainer when >> this goes out of staging. I mostly worked on Ion at my >> previous position and anything I do now is mostly a side >> project. I still want to see it succeed which is why I >> took on the maintainer role but I don't want to become blocking >> for people who have a stronger vision about where this needs >> to go (see also, I'm not working with this on a daily basis). >> >> If you just want someone to help review or take patches >> to be pulled, I'm happy to do so but I'd hate to become >> the bottleneck on getting things done for people who >> are attempting to do real work. > > I worry this will make everyone to touch the side of their nose and > yell "NOT IT!" :) > > First of all, thank you so much for your efforts maintaining ION along > with your attempts to drag out requirements from interested parties > and the numerous attempts to get collaborative discussion going at > countless conferences! Your persistence and continual nudging in the > face of apathetic private users of the code probably cannot be > appreciated enough! > > Your past practical experience with ION and active work with the > upstream community made you a stand out pick for this, but I > understand not wanting to be eternally stuck with a maintainership if > your not active in the area. I'm happy to volunteer as a neutral > party, but I worry my limited experience with some of the more > complicated usage would make my opinions less informed then they > probably need to be. Further, as a neutral party, Sumit would > probably be a better pick since he's already maintaining the dmabuf > core. > Honestly if you're doing the work to re-write everything, I think you're more than qualified to be the maintainer. I would also support Sumit as well. > So I'd nominate Andrew, Liam or Benjamin (or all three?) as they all > have more practical experience enabling past ION heaps on real devices > and have demonstrated active interest in working in the community. > I do think this would benefit both from multiple maintainers and from maintainers who are actively using the framework. Like I said, I can still be a maintainer but I think having some comaintainers would be very helpful (and I'd support any of the names you've suggested) > So, in other words... NOT IT! :) I think you have to shout "Noes goes" first. :) > -john > Thanks, Laura P.S. For the benefit of anyone who's confused, https://en.wikipedia.org/wiki/Nose_goes
On Tue, Mar 19, 2019 at 5:08 AM Brian Starkey <Brian.Starkey@arm.com> wrote: > > Hi John, > > On Tue, Mar 05, 2019 at 12:54:29PM -0800, John Stultz wrote: > > From: "Andrew F. Davis" <afd@ti.com> > > [snip] > > > + > > +#define NUM_HEAP_MINORS 128 > > +static DEFINE_IDR(dma_heap_idr); > > +static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */ > > I saw that Matthew Wilcox is trying to nuke idr: > https://patchwork.freedesktop.org/series/57073/ > > Perhaps a different data structure could be considered? (I don't have > an informed opinion on which). Thanks for pointing this out! I've just switched to using the Xarray implementation in my tree. > > +static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len, > > + unsigned int flags) > > +{ > > + len = PAGE_ALIGN(len); > > + if (!len) > > + return -EINVAL; > > I think aligning len to pages only makes sense if heaps are going to > allocate aligned to pages too. Perhaps that's an implicit assumption? > If so, lets document it. I've added a comment as such (or do you have more thoughts on where it should be documented?), and for consistency removed the PAGE_ALIGN usage in the heap allocator hooks. > Why not let the heaps take care of aligning len however they want > though? As Andrew already said, It seems page granularity would have to be the finest allocation granularity for dmabufs. If heaps want to implement their own larger granularity alignment, I don't see any reason they would be limited there. And for me, its mostly because I stubbed my toe implementing the heap code w/ the first patch that didn't have the page alignment in the generic code. :) > > + /* Create device */ > > + heap->heap_devt = MKDEV(MAJOR(dma_heap_devt), heap->minor); > > + dev_ret = device_create(dma_heap_class, > > + NULL, > > + heap->heap_devt, > > + NULL, > > + heap->name); > > + if (IS_ERR(dev_ret)) { > > + pr_err("dma_heap: Unable to create char device\n"); > > + return PTR_ERR(dev_ret); > > + } > > + > > + /* Add device */ > > + cdev_init(&heap->heap_cdev, &dma_heap_fops); > > + ret = cdev_add(&heap->heap_cdev, dma_heap_devt, NUM_HEAP_MINORS); > > Shouldn't this be s/dma_heap_devt/heap->heap_devt/ and a count of 1? > > Also would it be better to have cdev_add/device_create the other way > around? First create the char device, then once it's all set up > register it with sysfs. Thanks for catching that! Much appreciated! Reworked as suggested. Though I realized last week I have not figured out a consistent way to have the heaps show up in /dev/dma_heaps/<device> on both Android and classic Linux environments. I need to go stare at the /dev/input/ setup code some more. > > + if (ret < 0) { > > + device_destroy(dma_heap_class, heap->heap_devt); > > + pr_err("dma_heap: Unable to add char device\n"); > > + return ret; > > + } > > + > > + return 0; > > +} > > +EXPORT_SYMBOL(dma_heap_add); > > Until we've figured out how modules are going to work, I still think > it would be a good idea to not export this. Done! thanks -john
diff --git a/MAINTAINERS b/MAINTAINERS index ac2e518..a661e19 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4621,6 +4621,22 @@ F: include/linux/*fence.h F: Documentation/driver-api/dma-buf.rst T: git git://anongit.freedesktop.org/drm/drm-misc +DMA-BUF HEAPS FRAMEWORK +M: Laura Abbott <labbott@redhat.com> +R: Liam Mark <lmark@codeaurora.org> +R: Brian Starkey <Brian.Starkey@arm.com> +R: "Andrew F. Davis" <afd@ti.com> +R: John Stultz <john.stultz@linaro.org> +S: Maintained +L: linux-media@vger.kernel.org +L: dri-devel@lists.freedesktop.org +L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers) +F: include/uapi/linux/dma-heap.h +F: include/linux/dma-heap.h +F: drivers/dma-buf/dma-heap.c +F: drivers/dma-buf/heaps/* +T: git git://anongit.freedesktop.org/drm/drm-misc + DMA GENERIC OFFLOAD ENGINE SUBSYSTEM M: Vinod Koul <vkoul@kernel.org> L: dmaengine@vger.kernel.org diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index 2e5a0fa..09c61db 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -39,4 +39,12 @@ config UDMABUF A driver to let userspace turn memfd regions into dma-bufs. Qemu can use this to create host dmabufs for guest framebuffers. +menuconfig DMABUF_HEAPS + bool "DMA-BUF Userland Memory Heaps" + select DMA_SHARED_BUFFER + help + Choose this option to enable the DMA-BUF userland memory heaps, + this allows userspace to allocate dma-bufs that can be shared between + drivers. + endmenu diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 0913a6c..b0332f1 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -1,4 +1,5 @@ obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o seqno-fence.o +obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o obj-$(CONFIG_SYNC_FILE) += sync_file.o obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o obj-$(CONFIG_UDMABUF) += udmabuf.o diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c new file mode 100644 index 0000000..14b3975 --- /dev/null +++ b/drivers/dma-buf/dma-heap.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Framework for userspace DMA-BUF allocations + * + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2019 Linaro Ltd. + */ + +#include <linux/cdev.h> +#include <linux/debugfs.h> +#include <linux/device.h> +#include <linux/dma-buf.h> +#include <linux/err.h> +#include <linux/idr.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/uaccess.h> + +#include <linux/dma-heap.h> +#include <uapi/linux/dma-heap.h> + +#define DEVNAME "dma_heap" + +#define NUM_HEAP_MINORS 128 +static DEFINE_IDR(dma_heap_idr); +static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */ + +dev_t dma_heap_devt; +struct class *dma_heap_class; +struct list_head dma_heap_list; +struct dentry *dma_heap_debug_root; + +static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len, + unsigned int flags) +{ + len = PAGE_ALIGN(len); + if (!len) + return -EINVAL; + + return heap->ops->allocate(heap, len, flags); +} + +static int dma_heap_open(struct inode *inode, struct file *filp) +{ + struct dma_heap *heap; + + mutex_lock(&minor_lock); + heap = idr_find(&dma_heap_idr, iminor(inode)); + mutex_unlock(&minor_lock); + if (!heap) { + pr_err("dma_heap: minor %d unknown.\n", iminor(inode)); + return -ENODEV; + } + + /* instance data as context */ + filp->private_data = heap; + nonseekable_open(inode, filp); + + return 0; +} + +static int dma_heap_release(struct inode *inode, struct file *filp) +{ + filp->private_data = NULL; + + return 0; +} + +static long dma_heap_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case DMA_HEAP_IOC_ALLOC: + { + struct dma_heap_allocation_data heap_allocation; + struct dma_heap *heap = filp->private_data; + int fd; + + if (copy_from_user(&heap_allocation, (void __user *)arg, + sizeof(heap_allocation))) + return -EFAULT; + + if (heap_allocation.fd || + heap_allocation.reserved0 || + heap_allocation.reserved1 || + heap_allocation.reserved2) { + pr_warn_once("dma_heap: ioctl data not valid\n"); + return -EINVAL; + } + if (heap_allocation.flags & ~DMA_HEAP_VALID_FLAGS) { + pr_warn_once("dma_heap: flags has invalid or unsupported flags set\n"); + return -EINVAL; + } + + fd = dma_heap_buffer_alloc(heap, heap_allocation.len, + heap_allocation.flags); + if (fd < 0) + return fd; + + heap_allocation.fd = fd; + + if (copy_to_user((void __user *)arg, &heap_allocation, + sizeof(heap_allocation))) + return -EFAULT; + + break; + } + default: + return -ENOTTY; + } + + return 0; +} + +static const struct file_operations dma_heap_fops = { + .owner = THIS_MODULE, + .open = dma_heap_open, + .release = dma_heap_release, + .unlocked_ioctl = dma_heap_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = dma_heap_ioctl, +#endif +}; + +int dma_heap_add(struct dma_heap *heap) +{ + struct device *dev_ret; + int ret; + + if (!heap->name || !strcmp(heap->name, "")) { + pr_err("dma_heap: Cannot add heap without a name\n"); + return -EINVAL; + } + + if (!heap->ops || !heap->ops->allocate) { + pr_err("dma_heap: Cannot add heap with invalid ops struct\n"); + return -EINVAL; + } + + /* Find unused minor number */ + mutex_lock(&minor_lock); + ret = idr_alloc(&dma_heap_idr, heap, 0, NUM_HEAP_MINORS, GFP_KERNEL); + mutex_unlock(&minor_lock); + if (ret < 0) { + pr_err("dma_heap: Unable to get minor number for heap\n"); + return ret; + } + heap->minor = ret; + + /* Create device */ + heap->heap_devt = MKDEV(MAJOR(dma_heap_devt), heap->minor); + dev_ret = device_create(dma_heap_class, + NULL, + heap->heap_devt, + NULL, + heap->name); + if (IS_ERR(dev_ret)) { + pr_err("dma_heap: Unable to create char device\n"); + return PTR_ERR(dev_ret); + } + + /* Add device */ + cdev_init(&heap->heap_cdev, &dma_heap_fops); + ret = cdev_add(&heap->heap_cdev, dma_heap_devt, NUM_HEAP_MINORS); + if (ret < 0) { + device_destroy(dma_heap_class, heap->heap_devt); + pr_err("dma_heap: Unable to add char device\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL(dma_heap_add); + +static int dma_heap_init(void) +{ + int ret; + + ret = alloc_chrdev_region(&dma_heap_devt, 0, NUM_HEAP_MINORS, DEVNAME); + if (ret) + return ret; + + dma_heap_class = class_create(THIS_MODULE, DEVNAME); + if (IS_ERR(dma_heap_class)) { + unregister_chrdev_region(dma_heap_devt, NUM_HEAP_MINORS); + return PTR_ERR(dma_heap_class); + } + + return 0; +} +subsys_initcall(dma_heap_init); diff --git a/include/linux/dma-heap.h b/include/linux/dma-heap.h new file mode 100644 index 0000000..ed86a8e --- /dev/null +++ b/include/linux/dma-heap.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DMABUF Heaps Allocation Infrastructure + * + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2019 Linaro Ltd. + */ + +#ifndef _DMA_HEAPS_H +#define _DMA_HEAPS_H + +#include <linux/cdev.h> +#include <linux/types.h> + +/** + * struct dma_heap_buffer - metadata for a particular buffer + * @heap: back pointer to the heap the buffer came from + * @dmabuf: backing dma-buf for this buffer + * @size: size of the buffer + * @flags: buffer specific flags + */ +struct dma_heap_buffer { + struct dma_heap *heap; + struct dma_buf *dmabuf; + size_t size; + unsigned long flags; +}; + +/** + * struct dma_heap - represents a dmabuf heap in the system + * @name: used for debugging/device-node name + * @ops: ops struct for this heap + * @minor minor number of this heap device + * @heap_devt heap device node + * @heap_cdev heap char device + * + * Represents a heap of memory from which buffers can be made. + */ +struct dma_heap { + const char *name; + struct dma_heap_ops *ops; + unsigned int minor; + dev_t heap_devt; + struct cdev heap_cdev; +}; + +/** + * struct dma_heap_ops - ops to operate on a given heap + * @allocate: allocate dmabuf and return fd + * + * allocate returns dmabuf fd on success, -errno on error. + */ +struct dma_heap_ops { + int (*allocate)(struct dma_heap *heap, + unsigned long len, + unsigned long flags); +}; + +/** + * dma_heap_add - adds a heap to dmabuf heaps + * @heap: the heap to add + */ +int dma_heap_add(struct dma_heap *heap); + +#endif /* _DMA_HEAPS_H */ diff --git a/include/uapi/linux/dma-heap.h b/include/uapi/linux/dma-heap.h new file mode 100644 index 0000000..75c5d3f --- /dev/null +++ b/include/uapi/linux/dma-heap.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DMABUF Heaps Userspace API + * + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2019 Linaro Ltd. + */ +#ifndef _UAPI_LINUX_DMABUF_POOL_H +#define _UAPI_LINUX_DMABUF_POOL_H + +#include <linux/ioctl.h> +#include <linux/types.h> + +/** + * DOC: DMABUF Heaps Userspace API + * + */ + +/* Currently no flags */ +#define DMA_HEAP_VALID_FLAGS (0) + +/** + * struct dma_heap_allocation_data - metadata passed from userspace for + * allocations + * @len: size of the allocation + * @flags: flags passed to pool + * @fd: will be populated with a fd which provdes the + * handle to the allocated dma-buf + * + * Provided by userspace as an argument to the ioctl + */ +struct dma_heap_allocation_data { + __u64 len; + __u64 flags; + __u32 fd; + __u32 reserved0; + __u32 reserved1; + __u32 reserved2; +}; + +#define DMA_HEAP_IOC_MAGIC 'H' + +/** + * DOC: DMA_HEAP_IOC_ALLOC - allocate memory from pool + * + * Takes an dma_heap_allocation_data struct and returns it with the fd field + * populated with the dmabuf handle of the allocation. + */ +#define DMA_HEAP_IOC_ALLOC _IOWR(DMA_HEAP_IOC_MAGIC, 0, \ + struct dma_heap_allocation_data) + +#endif /* _UAPI_LINUX_DMABUF_POOL_H */