On Wed, Dec 09, 2020 at 03:25:24PM +0100, Thomas Zimmermann wrote:
> Implementations of the vmap/vunmap GEM callbacks may perform pinning
> of the BO and may acquire the associated reservation object's lock.
> Callers that only require a mapping of the contained memory can thus
> interfere with other tasks that require exact pinning, such as scanout.
> This is less of an issue with private CMA buffers, but may happen
> with imported ones.
>
> Therefore provide the new interface drm_gem_cma_vmap_local(), which only
> performs the vmap operations. Callers have to hold the reservation lock
> while the mapping persists.
>
> This patch also connects GEM CMA helpers to the GEM object function with
> equivalent functionality.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann(a)suse.de>
> ---
> drivers/gpu/drm/drm_gem_cma_helper.c | 35 ++++++++++++++++++++++++++++
> drivers/gpu/drm/vc4/vc4_bo.c | 13 +++++++++++
> drivers/gpu/drm/vc4/vc4_drv.h | 1 +
> include/drm/drm_gem_cma_helper.h | 1 +
> 4 files changed, 50 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c
> index 7942cf05cd93..40b3e8e3fc42 100644
> --- a/drivers/gpu/drm/drm_gem_cma_helper.c
> +++ b/drivers/gpu/drm/drm_gem_cma_helper.c
> @@ -38,6 +38,7 @@ static const struct drm_gem_object_funcs drm_gem_cma_default_funcs = {
> .print_info = drm_gem_cma_print_info,
> .get_sg_table = drm_gem_cma_get_sg_table,
> .vmap = drm_gem_cma_vmap,
> + .vmap_local = drm_gem_cma_vmap_local,
> .mmap = drm_gem_cma_mmap,
> .vm_ops = &drm_gem_cma_vm_ops,
> };
> @@ -471,6 +472,40 @@ int drm_gem_cma_vmap(struct drm_gem_object *obj, struct dma_buf_map *map)
> }
> EXPORT_SYMBOL_GPL(drm_gem_cma_vmap);
>
> +/**
> + * drm_gem_cma_vmap_local - map a CMA GEM object into the kernel's virtual
> + * address space
> + * @obj: GEM object
> + * @map: Returns the kernel virtual address of the CMA GEM object's backing
> + * store.
> + *
> + * This function maps a buffer into the kernel's
> + * virtual address space. Since the CMA buffers are already mapped into the
> + * kernel virtual address space this simply returns the cached virtual
> + * address. Drivers using the CMA helpers should set this as their DRM
> + * driver's &drm_gem_object_funcs.vmap_local callback.
> + *
> + * Returns:
> + * 0 on success, or a negative error code otherwise.
> + */
> +int drm_gem_cma_vmap_local(struct drm_gem_object *obj, struct dma_buf_map *map)
> +{
> + struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj);
> +
> + /*
> + * TODO: The code in drm_gem_cma_prime_import_sg_table_vmap()
> + * establishes this mapping. The correct solution would
> + * be to call dma_buf_vmap_local() here.
> + *
> + * If we find a case where we absolutely have to call
> + * dma_buf_vmap_local(), the code needs to be restructured.
dma_buf_vmap_local is only relevant for dynamic importers, pinning at
import time is actually what you get anyway. That's what Christian meant
with his comments for the ->pin hook. So the TODO here doesn't make sense
imo, just delete it. We're very far away from making cma dynamic :-)
> + */
> + dma_buf_map_set_vaddr(map, cma_obj->vaddr);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(drm_gem_cma_vmap_local);
> +
> /**
> * drm_gem_cma_mmap - memory-map an exported CMA GEM object
> * @obj: GEM object
> diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
> index dc316cb79e00..ec57326c69c4 100644
> --- a/drivers/gpu/drm/vc4/vc4_bo.c
> +++ b/drivers/gpu/drm/vc4/vc4_bo.c
> @@ -387,6 +387,7 @@ static const struct drm_gem_object_funcs vc4_gem_object_funcs = {
> .export = vc4_prime_export,
> .get_sg_table = drm_gem_cma_get_sg_table,
> .vmap = vc4_prime_vmap,
> + .vmap_local = vc4_prime_vmap_local,
> .vm_ops = &vc4_vm_ops,
> };
>
> @@ -797,6 +798,18 @@ int vc4_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map)
> return drm_gem_cma_vmap(obj, map);
> }
>
> +int vc4_prime_vmap_local(struct drm_gem_object *obj, struct dma_buf_map *map)
> +{
> + struct vc4_bo *bo = to_vc4_bo(obj);
> +
> + if (bo->validated_shader) {
This freaks me out. It should be impossible to export a validated shader
as a dma-buf, and indeed the check exists already.
All the wrapper functions here are imo pointless. Either we should remove
them, or replace the if with a BUG_ON here since if that ever happens we
have a security bug already. I'd go with removing, less code. Maybe throw
a patch on top?
Anyway this patch looks good, with the todo deleted:
Reviewed-by: Daniel Vetter <daniel.vetter(a)ffwll.ch>
> + DRM_DEBUG("mmaping of shader BOs not allowed.\n");
> + return -EINVAL;
> + }
> +
> + return drm_gem_cma_vmap_local(obj, map);
> +}
> +
> struct drm_gem_object *
> vc4_prime_import_sg_table(struct drm_device *dev,
> struct dma_buf_attachment *attach,
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
> index 43a1af110b3e..efb6c47d318f 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.h
> +++ b/drivers/gpu/drm/vc4/vc4_drv.h
> @@ -812,6 +812,7 @@ struct drm_gem_object *vc4_prime_import_sg_table(struct drm_device *dev,
> struct dma_buf_attachment *attach,
> struct sg_table *sgt);
> int vc4_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map);
> +int vc4_prime_vmap_local(struct drm_gem_object *obj, struct dma_buf_map *map);
> int vc4_bo_cache_init(struct drm_device *dev);
> int vc4_bo_inc_usecnt(struct vc4_bo *bo);
> void vc4_bo_dec_usecnt(struct vc4_bo *bo);
> diff --git a/include/drm/drm_gem_cma_helper.h b/include/drm/drm_gem_cma_helper.h
> index 0a9711caa3e8..05122e71bc6d 100644
> --- a/include/drm/drm_gem_cma_helper.h
> +++ b/include/drm/drm_gem_cma_helper.h
> @@ -99,6 +99,7 @@ drm_gem_cma_prime_import_sg_table(struct drm_device *dev,
> struct dma_buf_attachment *attach,
> struct sg_table *sgt);
> int drm_gem_cma_vmap(struct drm_gem_object *obj, struct dma_buf_map *map);
> +int drm_gem_cma_vmap_local(struct drm_gem_object *obj, struct dma_buf_map *map);
> int drm_gem_cma_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
>
> /**
> --
> 2.29.2
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
On Wed, Dec 09, 2020 at 03:25:22PM +0100, Thomas Zimmermann wrote:
> The existing dma-buf calls dma_buf_vmap() and dma_buf_vunmap() are
> allowed to pin the buffer or acquire the buffer's reservation object
> lock.
>
> This is a problem for callers that only require a short-term mapping
> of the buffer without the pinning, or callers that have special locking
> requirements. These may suffer from unnecessary overhead or interfere
> with regular pin operations.
>
> The new interfaces dma_buf_vmap_local(), dma_buf_vunmapo_local(), and
> their rsp callbacks in struct dma_buf_ops provide an alternative without
> pinning or reservation locking. Callers are responsible for these
> operations.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann(a)suse.de>
> ---
> drivers/dma-buf/dma-buf.c | 80 +++++++++++++++++++++++++++++++++++++++
> include/linux/dma-buf.h | 34 +++++++++++++++++
> 2 files changed, 114 insertions(+)
>
> diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> index e63684d4cd90..be9f80190a66 100644
> --- a/drivers/dma-buf/dma-buf.c
> +++ b/drivers/dma-buf/dma-buf.c
> @@ -1265,6 +1265,86 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, struct dma_buf_map *map)
> }
> EXPORT_SYMBOL_GPL(dma_buf_vunmap);
>
> +/**
> + * dma_buf_vmap_local - Create virtual mapping for the buffer object into kernel
> + * address space.
> + * @dmabuf: [in] buffer to vmap
> + * @map: [out] returns the vmap pointer
> + *
> + * This call may fail due to lack of virtual mapping address space.
> + * These calls are optional in drivers. The intended use for them
> + * is for mapping objects linear in kernel space for high use objects.
> + * Please attempt to use kmap/kunmap before thinking about these interfaces.
Kmap is gone, so the entire 2 sentences here are no longer needed. Maybe
mention something like "Unlike dma_buf_vmap() this is a short term mapping
and will not pin the buffer. The struct dma_resv for the @dmabuf must be
locked until dma_buf_vunmap_local() is called."
> + *
> + * Returns:
> + * 0 on success, or a negative errno code otherwise.
> + */
> +int dma_buf_vmap_local(struct dma_buf *dmabuf, struct dma_buf_map *map)
> +{
> + struct dma_buf_map ptr;
> + int ret = 0;
> +
> + dma_buf_map_clear(map);
> +
> + if (WARN_ON(!dmabuf))
> + return -EINVAL;
> +
> + dma_resv_assert_held(dmabuf->resv);
> +
> + if (!dmabuf->ops->vmap_local)
> + return -EINVAL;
> +
> + mutex_lock(&dmabuf->lock);
> + if (dmabuf->vmapping_counter) {
> + dmabuf->vmapping_counter++;
> + BUG_ON(dma_buf_map_is_null(&dmabuf->vmap_ptr));
> + *map = dmabuf->vmap_ptr;
> + goto out_unlock;
> + }
> +
> + BUG_ON(dma_buf_map_is_set(&dmabuf->vmap_ptr));
> +
> + ret = dmabuf->ops->vmap_local(dmabuf, &ptr);
> + if (WARN_ON_ONCE(ret))
> + goto out_unlock;
> +
> + dmabuf->vmap_ptr = ptr;
> + dmabuf->vmapping_counter = 1;
> +
> + *map = dmabuf->vmap_ptr;
> +
> +out_unlock:
> + mutex_unlock(&dmabuf->lock);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(dma_buf_vmap_local);
> +
> +/**
> + * dma_buf_vunmap_local - Unmap a vmap obtained by dma_buf_vmap_local.
> + * @dmabuf: [in] buffer to vunmap
> + * @map: [in] vmap pointer to vunmap
Maybe for hyperlinking add "Release a mapping established with
dma_buf_vmap_local()."
> + */
> +void dma_buf_vunmap_local(struct dma_buf *dmabuf, struct dma_buf_map *map)
> +{
> + if (WARN_ON(!dmabuf))
> + return;
> +
> + dma_resv_assert_held(dmabuf->resv);
> +
> + BUG_ON(dma_buf_map_is_null(&dmabuf->vmap_ptr));
> + BUG_ON(dmabuf->vmapping_counter == 0);
> + BUG_ON(!dma_buf_map_is_equal(&dmabuf->vmap_ptr, map));
> +
> + mutex_lock(&dmabuf->lock);
> + if (--dmabuf->vmapping_counter == 0) {
> + if (dmabuf->ops->vunmap_local)
> + dmabuf->ops->vunmap_local(dmabuf, map);
> + dma_buf_map_clear(&dmabuf->vmap_ptr);
> + }
> + mutex_unlock(&dmabuf->lock);
> +}
> +EXPORT_SYMBOL_GPL(dma_buf_vunmap_local);
> +
> #ifdef CONFIG_DEBUG_FS
> static int dma_buf_debug_show(struct seq_file *s, void *unused)
> {
> diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
> index cf72699cb2bc..f66580d23a9b 100644
> --- a/include/linux/dma-buf.h
> +++ b/include/linux/dma-buf.h
> @@ -269,6 +269,38 @@ struct dma_buf_ops {
>
> int (*vmap)(struct dma_buf *dmabuf, struct dma_buf_map *map);
> void (*vunmap)(struct dma_buf *dmabuf, struct dma_buf_map *map);
> +
> + /**
> + * @vmap_local:
> + *
> + * Creates a virtual mapping for the buffer into kernel address space.
> + *
> + * This callback establishes short-term mappings for situations where
> + * callers only use the buffer for a bounded amount of time; such as
> + * updates to the framebuffer or reading back contained information.
> + * In contrast to the regular @vmap callback, vmap_local does never pin
> + * the buffer to a specific domain or acquire the buffer's reservation
> + * lock.
> + *
> + * This is called with the dmabuf->resv object locked. Callers must hold
^^Not the right kerneldoc, I think it
should be &dma_buf.resv to get the
hyperlink.
> + * the lock until after removing the mapping with @vunmap_local.
> + *
> + * This callback is optional.
> + *
> + * Returns:
> + *
> + * 0 on success or a negative error code on failure.
> + */
> + int (*vmap_local)(struct dma_buf *dmabuf, struct dma_buf_map *map);
> +
> + /**
> + * @vunmap_local:
> + *
> + * Removes a virtual mapping that wa sestablished by @vmap_local.
^^established
> + *
> + * This callback is optional.
> + */
> + void (*vunmap_local)(struct dma_buf *dmabuf, struct dma_buf_map *map);
> };
>
> /**
> @@ -506,4 +538,6 @@ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *,
> unsigned long);
> int dma_buf_vmap(struct dma_buf *dmabuf, struct dma_buf_map *map);
> void dma_buf_vunmap(struct dma_buf *dmabuf, struct dma_buf_map *map);
> +int dma_buf_vmap_local(struct dma_buf *dmabuf, struct dma_buf_map *map);
> +void dma_buf_vunmap_local(struct dma_buf *dmabuf, struct dma_buf_map *map);
> #endif /* __DMA_BUF_H__ */
With the doc nits addressed:
Reviewed-by: Daniel Vetter <daniel.vetter(a)ffwll.ch>
> --
> 2.29.2
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
This patchset introduces a new dma heap, chunk heap that makes it
easy to perform the bulk allocation of high order pages.
It has been created to help optimize the 4K/8K HDR video playback
with secure DRM HW to protect contents on memory. The HW needs
physically contiguous memory chunks up to several hundred MB memory.
The chunk heap is registered by device tree with alignment and memory
node of Contiguous Memory Allocator(CMA). Alignment defines chunk page size.
For example, alignment 0x1_0000 means chunk page size is 64KB.
The phandle to memory node indicates contiguous memory allocator(CMA).
If device node doesn't have cma, the registration of chunk heap fails.
This patchset is against on next-20201110.
The patchset includes the following:
- cma_alloc_bulk API
- export dma-heap API to register kernel module dma heap.
- add chunk heap implementation.
- devicetree
Hyesoo Yu (3):
dma-buf: add export symbol for dma-heap
dma-buf: heaps: add chunk heap to dmabuf heaps
dma-heap: Devicetree binding for chunk heap
Minchan Kim (1):
mm: introduce cma_alloc_bulk API
.../bindings/dma-buf/chunk_heap.yaml | 52 ++
drivers/dma-buf/dma-heap.c | 2 +
drivers/dma-buf/heaps/Kconfig | 9 +
drivers/dma-buf/heaps/Makefile | 1 +
drivers/dma-buf/heaps/chunk_heap.c | 458 ++++++++++++++++++
include/linux/cma.h | 5 +
include/linux/page-isolation.h | 1 +
mm/cma.c | 129 ++++-
mm/page_alloc.c | 19 +-
mm/page_isolation.c | 3 +-
10 files changed, 666 insertions(+), 13 deletions(-)
create mode 100644 Documentation/devicetree/bindings/dma-buf/chunk_heap.yaml
create mode 100644 drivers/dma-buf/heaps/chunk_heap.c
--
2.29.2.299.gdc1121823c-goog