[EARLY RFC][PATCH] dma-buf: Add dma-buf heaps framework

Andrew F. Davis afd at ti.com
Tue Feb 26 14:02:09 UTC 2019


On 2/25/19 6:20 PM, John Stultz wrote:
> On Mon, Feb 25, 2019 at 6:36 AM Andrew F. Davis <afd at ti.com> wrote:
>>
>> This framework allows a unified userspace interface for dma-buf
>> exporters, allowing userland to allocate specific types of memory
>> for use in dma-buf sharing.
>>
>> Each heap is given its own device node, which a user can allocate
>> a dma-buf fd from using the DMA_HEAP_IOC_ALLOC.
>>
>> Signed-off-by: Andrew F. Davis <afd at ti.com>
>> ---
>>
>> Hello all,
>>
>> I had a little less time over the weekend than I thought I would to
>> clean this up more and finish the first set of user heaps, but wanted
>> to get this out anyway.
>>
>> ION in its current form assumes a lot about the memory it exports and
>> these assumptions lead to restrictions on the full range of operations
>> dma-buf's can produce. Due to this if we are to add this as an extension
>> of the core dma-buf then it should only be the user-space advertisement
>> and allocation front-end. All dma-buf exporting and operation need to be
>> placed in the control of the exporting heap. The core becomes rather
>> small, just a few hundred lines you see here. This is not to say we
>> should not provide helpers to make the heap exporters more simple, but
>> they should only be helpers and not enforced by the core framework.
>>
>> Basic use model here is an exporter (dedicated heap memory driver, CMA,
>> System, etc.) registers with the framework by providing a struct
>> dma_heap_info which gives us the needed info to export this heap to
>> userspace as a device node. Next a user will request an allocation,
>> the IOCTL is parsed and the request made to a heap provided alloc() op.
>> The heap should return the filled out struct dma_heap_buffer, including
>> exporting the buffer as a dma-buf. This dma-buf we then return to the
>> user as a fd. Buffer free is still a bit open as we need to update some
>> stats and free some memory, but the release operation is controlled by
>> the heap exporter, so some hook will have to be created.
>>
>> It all needs a bit more work, and I'm sure I'll find missing parts when
>> I add some more heaps, but hopefully this framework is simple enough that
>> it does not impede the implementation of all functionality once provided
>> by ION (shrinker, delayed free), nor any new functionality needed for
>> future heap exporting devices.
>>
>> Thanks,
>> Andrew
>>
>>  drivers/dma-buf/Kconfig       |  12 ++
>>  drivers/dma-buf/Makefile      |   1 +
>>  drivers/dma-buf/dma-heap.c    | 268 ++++++++++++++++++++++++++++++++++
>>  include/linux/dma-heap.h      |  57 ++++++++
>>  include/uapi/linux/dma-heap.h |  54 +++++++
>>  5 files changed, 392 insertions(+)
>>  create mode 100644 drivers/dma-buf/dma-heap.c
>>  create mode 100644 include/linux/dma-heap.h
>>  create mode 100644 include/uapi/linux/dma-heap.h
>>
>> diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig
>> index 2e5a0faa2cb1..30b0d7c83945 100644
>> --- a/drivers/dma-buf/Kconfig
>> +++ b/drivers/dma-buf/Kconfig
>> @@ -39,4 +39,16 @@ 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"
>> +       depends on HAS_DMA && MMU
>> +       select GENERIC_ALLOCATOR
>> +       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.
>> +
>> +source "drivers/dma-buf/heaps/Kconfig"
>> +
>>  endmenu
>> diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
>> index 0913a6ccab5a..b0332f143413 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 000000000000..72ed225fa892
>> --- /dev/null
>> +++ b/drivers/dma-buf/dma-heap.c
>> @@ -0,0 +1,268 @@
>> +// 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;
>> +
>> +/**
>> + * 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
>> + * @num_of_buffers     the number of currently allocated buffers
>> + * @num_of_alloc_bytes the number of allocated bytes
>> + * @alloc_bytes_wm     the number of allocated bytes watermark
>> + * @stat_lock          lock for heap statistics
>> + *
>> + * 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;
>> +
>> +       /* heap statistics */
>> +       u64 num_of_buffers;
>> +       u64 num_of_alloc_bytes;
>> +       u64 alloc_bytes_wm;
>> +       spinlock_t stat_lock;
>> +};
> 
> One issue I've run into here implementing the heaps on top of this:
> 
> So.. you've defined the dma_heap here in the dma-heap.c, but this
> structure needs to be visible to the heap implementations, as their
> allocate functions look like:
>        int (*allocate)(struct dma_heap *heap,
>                        struct dma_heap_buffer *buffer,
>                        unsigned long len,
>                        unsigned long flags);
> 

dma_heap is meant to be an opaque struct pointer, it is passed in as a
token to keep the interface consistent and so the heap can identify
itself (when I had the free() op it also started with dma_heap so the
heaps could track themselves, now with only allocate() it probably
doesn't matter much until we add something else).

> Plus the dma_heap duplicates the the dma_heap_info fields.
> 

Some of them, as above dma_heap is meant to be strictly internal, heaps
provide dma_heap_info into the framework and produce dma_heap_buffers.

> It seems like the dma_heap is what the heap implementation should
> allocate register, so it can traverse via container_of up to its own
> data structure, rather then doing it in dma_heap_add().
> 

Hmm, let me look at how this ended up in the code.

Thanks,
Andrew

> thanks
> -john
> 


More information about the dri-devel mailing list