On Sat, Dec 05, 2015 at 12:27:19AM +0200, Laurent Pinchart wrote:
> OMAP GEM objects backed by dma_buf reuse the current OMAP GEM object
> support as much as possible. If the imported buffer is physically
> contiguous its physical address will be used directly, reusing the
> OMAP_BO_MEM_DMA_API code paths. Otherwise it will be mapped through the
> TILER using a pages list created from the scatterlist instead of the
> shmem backing storage.
> 
> Disallow exporting imported buffers for now as those code paths haven't
> been verified. Use cases of such a feature are suspicious anyway.

If you export a buffer that's been imported the drm_prime.c helpers should
dig out the original dma-buf again. You should never end up with a dma-buf
-> omap gem bo -> dma-buf chain.

If that doesn't work then there's a bug somewhere ...
-Daniel

> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> ---
>  drivers/gpu/drm/omapdrm/omap_drv.h        |   2 +
>  drivers/gpu/drm/omapdrm/omap_gem.c        | 138 
> ++++++++++++++++++++++++------
>  drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c |  57 +++++++++---
>  3 files changed, 163 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h 
> b/drivers/gpu/drm/omapdrm/omap_drv.h
> index 97fcb892fdd7..6615b7d51ee3 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.h
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.h
> @@ -200,6 +200,8 @@ void omap_gem_deinit(struct drm_device *dev);
>  
>  struct drm_gem_object *omap_gem_new(struct drm_device *dev,
>               union omap_gem_size gsize, uint32_t flags);
> +struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t 
> size,
> +             struct sg_table *sgt);
>  int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file,
>               union omap_gem_size gsize, uint32_t flags, uint32_t *handle);
>  void omap_gem_free_object(struct drm_gem_object *obj);
> diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c 
> b/drivers/gpu/drm/omapdrm/omap_gem.c
> index 11df4f78d8a7..8a54d333a47b 100644
> --- a/drivers/gpu/drm/omapdrm/omap_gem.c
> +++ b/drivers/gpu/drm/omapdrm/omap_gem.c
> @@ -33,6 +33,7 @@
>  #define OMAP_BO_MEM_DMA_API  0x01000000      /* memory allocated with the 
> dma_alloc_* API */
>  #define OMAP_BO_MEM_SHMEM    0x02000000      /* memory allocated through 
> shmem backing */
>  #define OMAP_BO_MEM_EXT              0x04000000      /* memory allocated 
> externally */
> +#define OMAP_BO_MEM_DMABUF   0x08000000      /* memory imported from a 
> dmabuf */
>  #define OMAP_BO_EXT_SYNC     0x10000000      /* externally allocated sync 
> object */
>  
>  struct omap_gem_object {
> @@ -49,17 +50,25 @@ struct omap_gem_object {
>       uint32_t roll;
>  
>       /**
> -      * If buffer is allocated physically contiguous, the OMAP_BO_MEM_DMA_API
> -      * flag is set and the paddr is valid.  Also if the buffer is remapped
> -      * in TILER and paddr_cnt > 0, then paddr is valid. But if you are using
> -      * the physical address and OMAP_BO_MEM_DMA_API is not set, then you
> -      * should be going thru omap_gem_{get,put}_paddr() to ensure the mapping
> -      * is not removed from under your feet.
> +      * paddr contains the buffer DMA address. It is valid for
>        *
> -      * Note that OMAP_BO_SCANOUT is a hint from userspace that DMA capable
> -      * buffer is requested, but doesn't mean that it is. Use the
> -      * OMAP_BO_MEM_DMA_API flag to determine if the buffer has a DMA capable
> -      * physical address.
> +      * - buffers allocated through the DMA mapping API (with the
> +      *   OMAP_BO_MEM_DMA_API flag set)
> +      *
> +      * - buffers imported from dmabuf (with the OMAP_BO_MEM_DMABUF flag set)
> +      *   if they are physically contiguous (when sgt->orig_nents == 1)
> +      *
> +      * - buffers mapped through the TILER when paddr_cnt is not zero, in
> +      *   which case the DMA address points to the TILER aperture
> +      *
> +      * Physically contiguous buffers have their DMA address equal to the
> +      * physical address as we don't remap those buffers through the TILER.
> +      *
> +      * Buffers mapped to the TILER have their DMA address pointing to the
> +      * TILER aperture. As TILER mappings are refcounted (through paddr_cnt)
> +      * the DMA address must be accessed through omap_get_get_paddr() to
> +      * ensure that the mapping won't disappear unexpectedly. References must
> +      * be released with omap_gem_put_paddr().
>        */
>       dma_addr_t paddr;
>  
> @@ -69,6 +78,12 @@ struct omap_gem_object {
>       uint32_t paddr_cnt;
>  
>       /**
> +      * If the buffer has been imported from a dmabuf the OMAP_DB_DMABUF flag
> +      * is set and the sgt field is valid.
> +      */
> +     struct sg_table *sgt;
> +
> +     /**
>        * tiler block used when buffer is remapped in DMM/TILER.
>        */
>       struct tiler_block *block;
> @@ -166,6 +181,17 @@ static uint64_t mmap_offset(struct drm_gem_object *obj)
>       return drm_vma_node_offset_addr(&obj->vma_node);
>  }
>  
> +static bool is_contiguous(struct omap_gem_object *omap_obj)
> +{
> +     if (omap_obj->flags & OMAP_BO_MEM_DMA_API)
> +             return true;
> +
> +     if ((omap_obj->flags & OMAP_BO_MEM_DMABUF) && omap_obj->sgt->nents == 1)
> +             return true;
> +
> +     return false;
> +}
> +
>  /* 
> -----------------------------------------------------------------------------
>   * Eviction
>   */
> @@ -384,7 +410,7 @@ static int fault_1d(struct drm_gem_object *obj,
>               omap_gem_cpu_sync(obj, pgoff);
>               pfn = page_to_pfn(omap_obj->pages[pgoff]);
>       } else {
> -             BUG_ON(!(omap_obj->flags & OMAP_BO_MEM_DMA_API));
> +             BUG_ON(!is_contiguous(omap_obj));
>               pfn = (omap_obj->paddr >> PAGE_SHIFT) + pgoff;
>       }
>  
> @@ -774,8 +800,7 @@ int omap_gem_get_paddr(struct drm_gem_object *obj,
>  
>       mutex_lock(&obj->dev->struct_mutex);
>  
> -     if (!(omap_obj->flags & OMAP_BO_MEM_DMA_API) &&
> -         remap && priv->usergart) {
> +     if (!is_contiguous(omap_obj) && remap && priv->usergart) {
>               if (omap_obj->paddr_cnt == 0) {
>                       struct page **pages;
>                       uint32_t npages = obj->size >> PAGE_SHIFT;
> @@ -822,7 +847,7 @@ int omap_gem_get_paddr(struct drm_gem_object *obj,
>               omap_obj->paddr_cnt++;
>  
>               *paddr = omap_obj->paddr;
> -     } else if (omap_obj->flags & OMAP_BO_MEM_DMA_API) {
> +     } else if (is_contiguous(omap_obj)) {
>               *paddr = omap_obj->paddr;
>       } else {
>               ret = -EINVAL;
> @@ -1290,9 +1315,6 @@ unlock:
>   * Constructor & Destructor
>   */
>  
> -/* don't call directly.. called from GEM core when it is time to actually
> - * free the object..
> - */
>  void omap_gem_free_object(struct drm_gem_object *obj)
>  {
>       struct drm_device *dev = obj->dev;
> @@ -1314,14 +1336,20 @@ void omap_gem_free_object(struct drm_gem_object *obj)
>  
>       /* don't free externally allocated backing memory */
>       if (!(omap_obj->flags & OMAP_BO_MEM_EXT)) {
> -             if (omap_obj->pages)
> -                     omap_gem_detach_pages(obj);
> +             if (omap_obj->pages) {
> +                     if (omap_obj->flags & OMAP_BO_MEM_DMABUF)
> +                             kfree(omap_obj->pages);
> +                     else
> +                             omap_gem_detach_pages(obj);
> +             }
>  
>               if (omap_obj->flags & OMAP_BO_MEM_DMA_API) {
>                       dma_free_writecombine(dev->dev, obj->size,
>                                       omap_obj->vaddr, omap_obj->paddr);
>               } else if (omap_obj->vaddr) {
>                       vunmap(omap_obj->vaddr);
> +             } else if (obj->import_attach) {
> +                     drm_prime_gem_destroy(obj, omap_obj->sgt);
>               }
>       }
>  
> @@ -1367,14 +1395,15 @@ struct drm_gem_object *omap_gem_new(struct drm_device 
> *dev,
>               flags |= tiler_get_cpu_cache_flags();
>       } else if ((flags & OMAP_BO_SCANOUT) && !priv->usergart) {
>               /*
> -              * Use contiguous memory if we don't have DMM to remap
> -              * discontiguous buffers.
> +              * OMAP_BO_SCANOUT hints that the buffer doesn't need to be
> +              * tiled. However, to lower the pressure on memory allocation,
> +              * use contiguous memory only if no TILER is available.
>                */
>               flags |= OMAP_BO_MEM_DMA_API;
> -     } else if (!(flags & OMAP_BO_MEM_EXT)) {
> +     } else if (!(flags & (OMAP_BO_MEM_EXT | OMAP_BO_MEM_DMABUF))) {
>               /*
> -              * All other buffers not backed with external memory are
> -              * shmem-backed.
> +              * All other buffers not backed by external memory or dma_buf
> +              * are shmem-backed.
>                */
>               flags |= OMAP_BO_MEM_SHMEM;
>       }
> @@ -1436,6 +1465,67 @@ fail:
>       return NULL;
>  }
>  
> +struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t 
> size,
> +                                        struct sg_table *sgt)
> +{
> +     struct omap_drm_private *priv = dev->dev_private;
> +     struct omap_gem_object *omap_obj;
> +     struct drm_gem_object *obj;
> +     union omap_gem_size gsize;
> +
> +     /* Without a DMM only physically contiguous buffers can be supported. */
> +     if (sgt->orig_nents != 1 && !priv->usergart)
> +             return ERR_PTR(-EINVAL);
> +
> +     mutex_lock(&dev->struct_mutex);
> +
> +     gsize.bytes = PAGE_ALIGN(size);
> +     obj = omap_gem_new(dev, gsize, OMAP_BO_MEM_DMABUF | OMAP_BO_WC);
> +     if (!obj) {
> +             obj = ERR_PTR(-ENOMEM);
> +             goto done;
> +     }
> +
> +     omap_obj = to_omap_bo(obj);
> +     omap_obj->sgt = sgt;
> +
> +     if (sgt->orig_nents == 1) {
> +             omap_obj->paddr = sg_dma_address(sgt->sgl);
> +     } else {
> +             /* Create pages list from sgt */
> +             struct sg_page_iter iter;
> +             struct page **pages;
> +             unsigned int npages;
> +             unsigned int i = 0;
> +
> +             npages = DIV_ROUND_UP(size, PAGE_SIZE);
> +             pages = kcalloc(npages, sizeof(*pages), GFP_KERNEL);
> +             if (!pages) {
> +                     omap_gem_free_object(obj);
> +                     obj = ERR_PTR(-ENOMEM);
> +                     goto done;
> +             }
> +
> +             omap_obj->pages = pages;
> +
> +             for_each_sg_page(sgt->sgl, &iter, sgt->orig_nents, 0) {
> +                     pages[i++] = sg_page_iter_page(&iter);
> +                     if (i > npages)
> +                             break;
> +             }
> +
> +             if (WARN_ON(i != npages)) {
> +                     omap_gem_free_object(obj);
> +                     obj = ERR_PTR(-ENOMEM);
> +                     goto done;
> +             }
> +     }
> +
> +done:
> +     mutex_unlock(&dev->struct_mutex);
> +     return obj;
> +}
> +
>  /* convenience method to construct a GEM buffer object, and userspace handle 
> */
>  int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file,
>               union omap_gem_size gsize, uint32_t flags, uint32_t *handle)
> diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c 
> b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
> index 27c297672076..3f7d25a8baf1 100644
> --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
> +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
> @@ -21,6 +21,10 @@
>  
>  #include "omap_drv.h"
>  
> +/* 
> -----------------------------------------------------------------------------
> + * DMABUF Export
> + */
> +
>  static struct sg_table *omap_gem_map_dma_buf(
>               struct dma_buf_attachment *attachment,
>               enum dma_data_direction dir)
> @@ -170,6 +174,10 @@ struct dma_buf *omap_gem_prime_export(struct drm_device 
> *dev,
>  {
>       DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
>  
> +     /* Don't allow exporting buffers that have been imported. */
> +     if (obj->import_attach)
> +             return ERR_PTR(-EINVAL);
> +
>       exp_info.ops = &omap_dmabuf_ops;
>       exp_info.size = obj->size;
>       exp_info.flags = flags;
> @@ -178,15 +186,20 @@ struct dma_buf *omap_gem_prime_export(struct drm_device 
> *dev,
>       return dma_buf_export(&exp_info);
>  }
>  
> +/* 
> -----------------------------------------------------------------------------
> + * DMABUF Import
> + */
> +
>  struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev,
> -             struct dma_buf *buffer)
> +                                          struct dma_buf *dma_buf)
>  {
> +     struct dma_buf_attachment *attach;
>       struct drm_gem_object *obj;
> +     struct sg_table *sgt;
> +     int ret;
>  
> -     /* is this one of own objects? */
> -     if (buffer->ops == &omap_dmabuf_ops) {
> -             obj = buffer->priv;
> -             /* is it from our device? */
> +     if (dma_buf->ops == &omap_dmabuf_ops) {
> +             obj = dma_buf->priv;
>               if (obj->dev == dev) {
>                       /*
>                        * Importing dmabuf exported from out own gem increases
> @@ -197,9 +210,33 @@ struct drm_gem_object *omap_gem_prime_import(struct 
> drm_device *dev,
>               }
>       }
>  
> -     /*
> -      * TODO add support for importing buffers from other devices..
> -      * for now we don't need this but would be nice to add eventually
> -      */
> -     return ERR_PTR(-EINVAL);
> +     attach = dma_buf_attach(dma_buf, dev->dev);
> +     if (IS_ERR(attach))
> +             return ERR_CAST(attach);
> +
> +     get_dma_buf(dma_buf);
> +
> +     sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
> +     if (IS_ERR(sgt)) {
> +             ret = PTR_ERR(sgt);
> +             goto fail_detach;
> +     }
> +
> +     obj = omap_gem_new_dmabuf(dev, dma_buf->size, sgt);
> +     if (IS_ERR(obj)) {
> +             ret = PTR_ERR(obj);
> +             goto fail_unmap;
> +     }
> +
> +     obj->import_attach = attach;
> +
> +     return obj;
> +
> +fail_unmap:
> +     dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
> +fail_detach:
> +     dma_buf_detach(dma_buf, attach);
> +     dma_buf_put(dma_buf);
> +
> +     return ERR_PTR(ret);
>  }
> -- 
> 2.4.10
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

Reply via email to