From: Daniel Vetter <daniel@ffwll.ch>
To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>, dri-devel@lists.freedesktop.org
Subject: Re: [PATCH 15/15] drm: omapdrm: gem: Implement dma_buf import
Date: Sat, 5 Dec 2015 16:40:14 +0100 [thread overview]
Message-ID: <20151205154014.GS10243@phenom.ffwll.local> (raw)
In-Reply-To: <1449268039-24682-16-git-send-email-laurent.pinchart@ideasonboard.com>
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@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@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
next prev parent reply other threads:[~2015-12-05 15:40 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-12-04 22:27 [PATCH 00/15] omapdrm: Implement dma_buf import Laurent Pinchart
2015-12-04 22:27 ` [PATCH 01/15] drm: omapdrm: Fix plane state free in plane reset handler Laurent Pinchart
2015-12-09 12:43 ` Tomi Valkeinen
2015-12-13 20:39 ` Laurent Pinchart
2015-12-14 7:59 ` Tomi Valkeinen
2015-12-04 22:27 ` [PATCH 02/15] drm: omapdrm: Make fbdev emulation optional Laurent Pinchart
2015-12-04 22:27 ` [PATCH 03/15] drm: omapdrm: gem: Remove unused function prototypes Laurent Pinchart
2015-12-04 22:27 ` [PATCH 04/15] drm: omapdrm: gem: Remove forward declarations Laurent Pinchart
2015-12-04 22:27 ` [PATCH 05/15] drm: omapdrm: gem: Group functions by purpose Laurent Pinchart
2015-12-04 22:27 ` [PATCH 06/15] drm: omapdrm: gem: Move global usergart variable to omap_drm_private Laurent Pinchart
2015-12-04 22:27 ` [PATCH 07/15] drm: omapdrm: gem: Remove omap_drm_private has_dmm field Laurent Pinchart
2015-12-04 22:27 ` [PATCH 08/15] drm: omapdrm: gem: Mask out private flags passed from userspace Laurent Pinchart
2015-12-07 14:13 ` Emil Velikov
2015-12-14 20:33 ` Laurent Pinchart
2015-12-16 17:33 ` Emil Velikov
2015-12-16 23:27 ` Rob Clark
2015-12-04 22:27 ` [PATCH 09/15] drm: omapdrm: gem: Clean up GEM objects memory flags Laurent Pinchart
2015-12-04 22:27 ` [PATCH 10/15] drm: omapdrm: gem: Free the correct memory object Laurent Pinchart
2015-12-14 11:45 ` Tomi Valkeinen
2015-12-14 19:52 ` Laurent Pinchart
2015-12-04 22:27 ` [PATCH 11/15] drm: omapdrm: gem: Don't free mmap offset twice Laurent Pinchart
2015-12-04 22:27 ` [PATCH 12/15] drm: omapdrm: gem: Simplify error handling when creating GEM object Laurent Pinchart
2015-12-04 22:27 ` [PATCH 13/15] drm: omapdrm: gem: Remove check for impossible condition Laurent Pinchart
2015-12-04 22:27 ` [PATCH 14/15] drm: omapdrm: gem: Refactor GEM object allocation Laurent Pinchart
2015-12-04 22:27 ` [PATCH 15/15] drm: omapdrm: gem: Implement dma_buf import Laurent Pinchart
2015-12-05 15:40 ` Daniel Vetter [this message]
2015-12-05 22:24 ` Laurent Pinchart
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20151205154014.GS10243@phenom.ffwll.local \
--to=daniel@ffwll.ch \
--cc=dri-devel@lists.freedesktop.org \
--cc=laurent.pinchart@ideasonboard.com \
--cc=tomi.valkeinen@ti.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.