[PATCH v2] drm/vgem: implement virtual GEM

Rob Clark robdclark at gmail.com
Sat Jan 31 08:02:05 PST 2015


On Fri, Jan 30, 2015 at 1:05 PM, Zach Reizner <zachr at google.com> wrote:
> This patch implements the virtual GEM driver with PRIME sharing which
> allows vgem to import a gem object from other drivers for the purpose
> of mmap-ing them to userspace. The mmap is done using the mmap
> operation exported by other drivers.
>
> v2: remove platform_device and do not attach to dma bufs
>
> Reviewed-by: Stéphane Marchesin <marcheu at chromium.org>
> Signed-off-by: Adam Jackson <ajax at redhat.com>
> Signed-off-by: Ben Widawsky <ben at bwidawsk.net>
> Signed-off-by: Zach Reizner <zachr at google.com>

couple small suggestions/comments below, but with those addressed,

Reviewed-by: Rob Clark <robdclark at gmail.com>

> ---
>  drivers/gpu/drm/Kconfig             |   9 +
>  drivers/gpu/drm/Makefile            |   1 +
>  drivers/gpu/drm/vgem/Makefile       |   4 +
>  drivers/gpu/drm/vgem/vgem_dma_buf.c |  96 +++++++++
>  drivers/gpu/drm/vgem/vgem_drv.c     | 390 ++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/vgem/vgem_drv.h     |  57 ++++++
>  6 files changed, 557 insertions(+)
>  create mode 100644 drivers/gpu/drm/vgem/Makefile
>  create mode 100644 drivers/gpu/drm/vgem/vgem_dma_buf.c
>  create mode 100644 drivers/gpu/drm/vgem/vgem_drv.c
>  create mode 100644 drivers/gpu/drm/vgem/vgem_drv.h
>

[snip]

> diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
> new file mode 100644
> index 0000000..e20f4a4
> --- /dev/null
> +++ b/drivers/gpu/drm/vgem/vgem_drv.c
> @@ -0,0 +1,390 @@
> +/*
> + * Copyright 2011 Red Hat, Inc.
> + * Copyright © 2014 The Chromium OS Authors
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software")
> + * to deal in the software without restriction, including without limitation
> + * on the rights to use, copy, modify, merge, publish, distribute, sub
> + * license, and/or sell copies of the Software, and to permit persons to whom
> + * them Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
> + * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors:
> + *     Adam Jackson <ajax at redhat.com>
> + *     Ben Widawsky <ben at bwidawsk.net>
> + */
> +
> +/**
> + * This is vgem, a (non-hardware-backed) GEM service.  This is used by Mesa's
> + * software renderer and the X server for efficient buffer sharing.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/ramfs.h>
> +#include <linux/shmem_fs.h>
> +#include <linux/dma-buf.h>
> +#include "vgem_drv.h"
> +
> +#define DRIVER_NAME    "vgem"
> +#define DRIVER_DESC    "Virtual GEM provider"
> +#define DRIVER_DATE    "20120112"
> +#define DRIVER_MAJOR   1
> +#define DRIVER_MINOR   0
> +
> +void vgem_gem_put_pages(struct drm_vgem_gem_object *obj)
> +{
> +       int num_pages = obj->base.size / PAGE_SIZE;
> +       int i;
> +
> +       for (i = 0; i < num_pages; i++) {
> +               if (obj->pages[i] == NULL)
> +                       break;

seems like other than this break statement, you could use
drm_gem_put_pages()..  not entirely sure why you'd encounter a null
page, but if there is a legit reason for that, then just add the check
in drm_gem_put_pages() (plus maybe a comment) and use that..

> +               page_cache_release(obj->pages[i]);
> +       }
> +
> +       drm_free_large(obj->pages);
> +       obj->pages = NULL;
> +}
> +
> +static void vgem_gem_free_object(struct drm_gem_object *obj)
> +{
> +       struct drm_vgem_gem_object *vgem_obj = to_vgem_bo(obj);
> +
> +       drm_gem_free_mmap_offset(obj);
> +
> +       if (vgem_obj->use_dma_buf && obj->dma_buf) {
> +               dma_buf_put(obj->dma_buf);
> +               obj->dma_buf = NULL;
> +       }
> +
> +       drm_gem_object_release(obj);
> +
> +       if (vgem_obj->pages)
> +               vgem_gem_put_pages(vgem_obj);
> +
> +       vgem_obj->pages = NULL;
> +
> +       kfree(vgem_obj);
> +}
> +
> +int vgem_gem_get_pages(struct drm_vgem_gem_object *obj)
> +{
> +       struct address_space *mapping;
> +       gfp_t gfpmask = GFP_KERNEL;
> +       int num_pages, i, ret = 0;
> +
> +       if (obj->pages || obj->use_dma_buf)
> +               return 0;
> +
> +       num_pages = obj->base.size / PAGE_SIZE;
> +       obj->pages = drm_malloc_ab(num_pages, sizeof(struct page *));
> +       if (obj->pages == NULL)
> +               return -ENOMEM;
> +
> +       mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;

again, seems like you could use drm_gem_get_pages().. although you get
the mapping in a slightly different way.. not sure if that was
intentional?

BR,
-R

> +       gfpmask |= mapping_gfp_mask(mapping);
> +
> +       for (i = 0; i < num_pages; i++) {
> +               struct page *page;
> +               obj->pages[i] = NULL;
> +               page = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
> +               if (IS_ERR(page)) {
> +                       ret = PTR_ERR(page);
> +                       goto err_out;
> +               }
> +               obj->pages[i] = page;
> +       }
> +
> +       return ret;
> +
> +err_out:
> +       vgem_gem_put_pages(obj);
> +       return ret;
> +}
> +


More information about the dri-devel mailing list