On Tue, May 23, 2017 at 06:32:00PM +0800, Xiaoguang Chen wrote:
> dmabuf for GVT-g can be exported to users who can use the dmabuf to show
> the desktop of vm which use intel vgpu.
> 
> Currently we provide query and create new dmabuf operations.
> 
> Users of dmabuf can cache some created dmabufs and related information
> such as the framebuffer's address, size, tiling mode, width, height etc.
> When refresh the screen first query the currnet vgpu's frambuffer and
> compare with the cached ones(address, size, tiling, width, height etc)
> if found one then reuse the found dmabuf to gain performance improvment.
> 
> If there is no dmabuf created yet or not found in the cached dmabufs then
> need to create a new dmabuf. To create a dmabuf first a gem object will
> be created and the backing storage of this gem object is the vgpu's
> framebuffer(primary/cursor).
> Set caching mode, change tiling mode and set domains of this gem object
> is not supported.
> Then associate this gem object to a dmabuf and export this dmabuf.
> A file descriptor will be generated for this dmabuf and this file
> descriptor can be sent to user space to do display.
> 
> Signed-off-by: Xiaoguang Chen <xiaoguang.c...@intel.com>
> ---
>  drivers/gpu/drm/i915/gvt/Makefile      |   2 +-
>  drivers/gpu/drm/i915/gvt/dmabuf.c      | 276 
> +++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/gvt/dmabuf.h      |  53 +++++++
>  drivers/gpu/drm/i915/gvt/gvt.h         |   1 +
>  drivers/gpu/drm/i915/i915_gem.c        |   8 +
>  drivers/gpu/drm/i915/i915_gem_object.h |   9 ++
>  6 files changed, 348 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/i915/gvt/dmabuf.c
>  create mode 100644 drivers/gpu/drm/i915/gvt/dmabuf.h
> 
> diff --git a/drivers/gpu/drm/i915/gvt/Makefile 
> b/drivers/gpu/drm/i915/gvt/Makefile
> index 192ca26..e480f7d 100644
> --- a/drivers/gpu/drm/i915/gvt/Makefile
> +++ b/drivers/gpu/drm/i915/gvt/Makefile
> @@ -2,7 +2,7 @@ GVT_DIR := gvt
>  GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o trace_points.o 
> firmware.o \
>       interrupt.o gtt.o cfg_space.o opregion.o mmio.o display.o edid.o \
>       execlist.o scheduler.o sched_policy.o render.o cmd_parser.o \
> -     fb_decoder.o
> +     fb_decoder.o dmabuf.o
>  
>  ccflags-y                            += -I$(src) -I$(src)/$(GVT_DIR) -Wall
>  i915-y                                       += $(addprefix $(GVT_DIR)/, 
> $(GVT_SOURCE))
> diff --git a/drivers/gpu/drm/i915/gvt/dmabuf.c 
> b/drivers/gpu/drm/i915/gvt/dmabuf.c
> new file mode 100644
> index 0000000..415453b
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gvt/dmabuf.c
> @@ -0,0 +1,276 @@
> +/*
> + * Copyright 2017 Intel Corporation. All rights reserved.
> + *
> + * 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
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * 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 MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS 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:
> + *    Zhiyuan Lv <zhiyuan...@intel.com>
> + *
> + * Contributors:
> + *    Xiaoguang Chen <xiaoguang.c...@intel.com>
> + */
> +
> +#include <linux/dma-buf.h>
> +#include <drm/drmP.h>
> +
> +#include "i915_drv.h"
> +#include "gvt.h"
> +
> +#define GEN8_DECODE_PTE(pte) \
> +     ((dma_addr_t)(((((u64)pte) >> 12) & 0x7ffffffULL) << 12))

pte & GENMASK_ULL(63, 12)

> +
> +static struct sg_table *intel_vgpu_gem_get_pages(
> +             struct drm_i915_gem_object *obj)
> +{
> +     struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
> +     struct sg_table *st;
> +     struct scatterlist *sg;
> +     int i, ret;
> +     gen8_pte_t __iomem *gtt_entries;
> +     unsigned int fb_gma = 0, fb_size = 0;
> +     struct intel_vgpu_plane_info *plane_info;
> +
> +     plane_info = (struct intel_vgpu_plane_info *)obj->gvt_plane_info;
> +     if (WARN_ON(!plane_info))
> +             return ERR_PTR(-EINVAL);

This is an internal bug, don't EINVAL.

> +     fb_gma = plane_info->start;
> +     fb_size = plane_info->size;
> +
> +     st = kmalloc(sizeof(*st), GFP_KERNEL);
> +     if (!st) {
> +             ret = -ENOMEM;
> +             return ERR_PTR(ret);
> +     }
> +
> +     ret = sg_alloc_table(st, fb_size, GFP_KERNEL);
> +     if (ret) {
> +             kfree(st);
> +             return ERR_PTR(ret);
> +     }
> +     gtt_entries = (gen8_pte_t __iomem *)dev_priv->ggtt.gsm +
> +             (fb_gma >> PAGE_SHIFT);
> +     for_each_sg(st->sgl, sg, fb_size, i) {
> +             sg->offset = 0;
> +             sg->length = PAGE_SIZE;
> +             sg_dma_address(sg) =
> +                     GEN8_DECODE_PTE(readq(&gtt_entries[i]));
> +             sg_dma_len(sg) = PAGE_SIZE;

This assumes that the entries are PAGE_SIZE. This will not remain true.
Also sg coalescing?

> +     }
> +
> +     return st;
> +}
> +
> +static void intel_vgpu_gem_put_pages(struct drm_i915_gem_object *obj,
> +             struct sg_table *pages)
> +{
> +     struct intel_vgpu_plane_info *plane_info;
> +
> +     plane_info = (struct intel_vgpu_plane_info *)obj->gvt_plane_info;
> +     if (WARN_ON(!plane_info))
> +             return;

Is there any value in this check?

> +     sg_free_table(pages);
> +     kfree(pages);
> +}
> +
> +static const struct drm_i915_gem_object_ops intel_vgpu_gem_ops = {
> +     .flags = I915_GEM_OBJECT_IS_GVT_DMABUF,

I'm going to suggest to call this bit I915_GEM_OBJECT_IS_PROXY to
generalise it beyond this special case. But I'm still debating how much
I approve of this change to the uABI.

> +     .get_pages = intel_vgpu_gem_get_pages,
> +     .put_pages = intel_vgpu_gem_put_pages,
> +};
> +
> +static struct drm_i915_gem_object *intel_vgpu_create_gem(struct drm_device 
> *dev,
> +             struct intel_vgpu_plane_info *info)
> +{
> +     struct drm_i915_private *pri = dev->dev_private;

to_i915(dev);

Please tell me that pri isn't common shorthand in gvt/! Commonly called
dev_priv, but I'm crusading for i915.

> +     struct drm_i915_gem_object *obj;
> +
> +     obj = i915_gem_object_alloc(pri);
> +     if (obj == NULL)
> +             return NULL;
> +
> +     drm_gem_private_object_init(dev, &obj->base,
> +             info->size << PAGE_SHIFT);
> +     i915_gem_object_init(obj, &intel_vgpu_gem_ops);
> +
> +     obj->base.read_domains = I915_GEM_DOMAIN_GTT;
> +     obj->base.write_domain = 0;


> +     obj->framebuffer_references++;

Missing comment. (And not amused with the magic, if it's only purpose is
to prevent set_tiling.)

> +     obj->gvt_plane_info = info;
> +
> +     if (IS_SKYLAKE(pri)) {
> +             unsigned int tiling_mode = 0;
> +
> +             switch (info->drm_format_mod << 10) {
> +             case PLANE_CTL_TILED_LINEAR:
> +                     tiling_mode = I915_TILING_NONE;
> +                     break;
> +             case PLANE_CTL_TILED_X:
> +                     tiling_mode = I915_TILING_X;
> +                     break;
> +             case PLANE_CTL_TILED_Y:
> +                     tiling_mode = I915_TILING_Y;
> +                     break;
> +             default:
> +                     gvt_dbg_core("not supported tiling mode\n");
> +             }
> +             obj->tiling_and_stride = tiling_mode | info->stride;

Stride should be zero if I915_TILING_NONE;

> +     } else {
> +             obj->tiling_and_stride = info->drm_format_mod ?
> +                                     I915_TILING_X : 0;
> +     }
> +
> +     return obj;
> +}
> +
> +static struct intel_vgpu_plane_info *intel_vgpu_get_plane_info(
> +             struct drm_device *dev,
> +             struct intel_vgpu *vgpu, uint32_t plane_id)
> +{
> +     struct drm_i915_private *dev_priv = dev->dev_private;

dev_priv here! Still use to_i915() though.

> +     struct intel_vgpu_primary_plane_format *p;
> +     struct intel_vgpu_cursor_plane_format *c;
> +     struct intel_vgpu_plane_info *info;
> +     struct intel_vgpu_pipe_format *pipe;
> +
> +     info = kmalloc(sizeof(*info), GFP_KERNEL);
> +     if (!info)
> +             return NULL;
> +
> +     pipe = intel_vgpu_decode_plane(dev, vgpu);
> +     if (pipe == NULL)
> +             return NULL;

Onion unwind to kill the leaks as others have mentioned.

> +int intel_vgpu_query_plane(struct intel_vgpu *vgpu, void *args)
> +{
> +     struct drm_device *dev = &vgpu->gvt->dev_priv->drm;
> +     struct intel_vgpu_plane_info *info = args;
> +
> +     info = intel_vgpu_get_plane_info(dev, vgpu, info->plane_id);
> +     if (info == NULL)
> +             return -EINVAL;
> +
> +     return 0;
> +}
> +
> +int intel_vgpu_create_dmabuf(struct intel_vgpu *vgpu, void *args)
> +{
> +     struct dma_buf *dmabuf;
> +     struct drm_i915_gem_object *obj;
> +     struct drm_device *dev = &vgpu->gvt->dev_priv->drm;
> +     struct intel_vgpu_dmabuf *gvt_dmabuf = args;
> +     struct intel_vgpu_plane_info *info;
> +     int ret;
> +
> +     info = intel_vgpu_get_plane_info(dev, vgpu,
> +                                     gvt_dmabuf->plane_info.plane_id);
> +     if (info == NULL)
> +             return -EINVAL;
> +
> +     obj = intel_vgpu_create_gem(dev, info);
> +     if (obj == NULL) {
> +             gvt_vgpu_err("create gvt gem obj failed:%d\n", vgpu->id);
> +             return -EINVAL;

Of all the errors that can cause this, do you think the user is at fault?

> +     }
> +
> +     dmabuf = i915_gem_prime_export(dev, &obj->base, DRM_CLOEXEC | DRM_RDWR);
> +
> +     if (IS_ERR(dmabuf)) {
> +             gvt_vgpu_err("export dma-buf failed\n");
> +             return -EINVAL;

Again, was this a user error? You even have the right error to hand!

> +     }
> +
> +     ret = dma_buf_fd(dmabuf, DRM_CLOEXEC | DRM_RDWR);
> +     if (ret < 0) {
> +             gvt_vgpu_err("create dma-buf fd failed ret:%d\n", ret);
> +             return -EINVAL;

Sitll a user error? Not ret?

> +     }
> +     gvt_dmabuf->fd = ret;
> +     gvt_dmabuf->plane_info = *info;
> +
> +     return 0;
> +}

> diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
> index c42266c..763a8c5 100644
> --- a/drivers/gpu/drm/i915/gvt/gvt.h
> +++ b/drivers/gpu/drm/i915/gvt/gvt.h
> @@ -47,6 +47,7 @@
>  #include "render.h"
>  #include "cmd_parser.h"
>  #include "fb_decoder.h"
> +#include "dmabuf.h"
>  
>  #define GVT_MAX_VGPU 8
>  
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 0c1cbe9..54f7a0f 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -1609,6 +1609,10 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void 
> *data,
>       if (!obj)
>               return -ENOENT;
>  
> +     /* The obj is a gvt dma-buf object and set domain is not supported */
> +     if (i915_gem_object_is_gvt_dmabuf(obj))
> +             return -EPERM;

Leaks the obj.

Ok, I'm slightly warming to this.

Newly broken ioctls:
        i915_gem_set_caching_ioctl
        i915_gem_set_domain_ioctl
        i915_gem_sw_finish_ioctl
        i915_gem_set_tiling_ioctl
        i915_gem_madvise_ioctl

These should all be -EPERM.

Existing broken ioctls:
        i915_gem_mmap_ioctl

Sadly this used -EINVAL. Might sneak a change in to use -EPERM for
constistency.

Misbehaving ioctls:
        i915_gem_busy_ioctl
        i915_gem_throttle_ioctl
        i915_gem_wait_ioctl

These only work on the proxy bo and do not reflect the real object.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to