]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
drm/i915/gvt: Pin vgpu dma address before using
authorTina Zhang <tina.zhang@intel.com>
Fri, 13 Dec 2019 03:23:14 +0000 (11:23 +0800)
committerZhenyu Wang <zhenyuw@linux.intel.com>
Fri, 13 Dec 2019 03:24:01 +0000 (11:24 +0800)
Dma-buf display uses the vgpu dma address saved in the guest part GGTT
table which is updated by vCPU thread. In host side, when the dma
address is used by qemu ui thread, gvt-g must make sure the dma address
is validated before letting it go to the HW. Invalid guest dma address
will easily cause DMA fault and make GPU hang.

v2: Rebase

Fixes: e546e281d33d ("drm/i915/gvt: Dmabuf support for GVT-g")
Acked-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: Tina Zhang <tina.zhang@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20191212141342.3417-1-tina.zhang@intel.com
drivers/gpu/drm/i915/gvt/dmabuf.c
drivers/gpu/drm/i915/gvt/hypercall.h
drivers/gpu/drm/i915/gvt/kvmgt.c
drivers/gpu/drm/i915/gvt/mpt.h

index ee0f3094e6d03555fb5c0041a3785452df745d6e..2477a1e5a1669cf220ccb85b062885714c100d3d 100644 (file)
 
 #define GEN8_DECODE_PTE(pte) (pte & GENMASK_ULL(63, 12))
 
+static int vgpu_pin_dma_address(struct intel_vgpu *vgpu,
+                               unsigned long size,
+                               dma_addr_t dma_addr)
+{
+       int ret = 0;
+
+       if (intel_gvt_hypervisor_dma_pin_guest_page(vgpu, dma_addr))
+               ret = -EINVAL;
+
+       return ret;
+}
+
+static void vgpu_unpin_dma_address(struct intel_vgpu *vgpu,
+                                  dma_addr_t dma_addr)
+{
+       intel_gvt_hypervisor_dma_unmap_guest_page(vgpu, dma_addr);
+}
+
 static int vgpu_gem_get_pages(
                struct drm_i915_gem_object *obj)
 {
        struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
+       struct intel_vgpu *vgpu;
        struct sg_table *st;
        struct scatterlist *sg;
-       int i, ret;
+       int i, j, ret;
        gen8_pte_t __iomem *gtt_entries;
        struct intel_vgpu_fb_info *fb_info;
        u32 page_num;
@@ -51,6 +70,10 @@ static int vgpu_gem_get_pages(
        if (WARN_ON(!fb_info))
                return -ENODEV;
 
+       vgpu = fb_info->obj->vgpu;
+       if (WARN_ON(!vgpu))
+               return -ENODEV;
+
        st = kmalloc(sizeof(*st), GFP_KERNEL);
        if (unlikely(!st))
                return -ENOMEM;
@@ -64,21 +87,53 @@ static int vgpu_gem_get_pages(
        gtt_entries = (gen8_pte_t __iomem *)dev_priv->ggtt.gsm +
                (fb_info->start >> PAGE_SHIFT);
        for_each_sg(st->sgl, sg, page_num, i) {
+               dma_addr_t dma_addr =
+                       GEN8_DECODE_PTE(readq(&gtt_entries[i]));
+               if (vgpu_pin_dma_address(vgpu, PAGE_SIZE, dma_addr)) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
                sg->offset = 0;
                sg->length = PAGE_SIZE;
-               sg_dma_address(sg) =
-                       GEN8_DECODE_PTE(readq(&gtt_entries[i]));
                sg_dma_len(sg) = PAGE_SIZE;
+               sg_dma_address(sg) = dma_addr;
        }
 
        __i915_gem_object_set_pages(obj, st, PAGE_SIZE);
+out:
+       if (ret) {
+               dma_addr_t dma_addr;
+
+               for_each_sg(st->sgl, sg, i, j) {
+                       dma_addr = sg_dma_address(sg);
+                       if (dma_addr)
+                               vgpu_unpin_dma_address(vgpu, dma_addr);
+               }
+               sg_free_table(st);
+               kfree(st);
+       }
+
+       return ret;
 
-       return 0;
 }
 
 static void vgpu_gem_put_pages(struct drm_i915_gem_object *obj,
                struct sg_table *pages)
 {
+       struct scatterlist *sg;
+
+       if (obj->base.dma_buf) {
+               struct intel_vgpu_fb_info *fb_info = obj->gvt_info;
+               struct intel_vgpu_dmabuf_obj *obj = fb_info->obj;
+               struct intel_vgpu *vgpu = obj->vgpu;
+               int i;
+
+               for_each_sg(pages->sgl, sg, fb_info->size, i)
+                       vgpu_unpin_dma_address(vgpu,
+                                              sg_dma_address(sg));
+       }
+
        sg_free_table(pages);
        kfree(pages);
 }
index 4862fb12778e096fd35ee5e71b8b27dc87a1ba9e..b19a3b1ea4c11cac83df40f5065789104d4993b4 100644 (file)
@@ -62,6 +62,8 @@ struct intel_gvt_mpt {
                                  unsigned long size, dma_addr_t *dma_addr);
        void (*dma_unmap_guest_page)(unsigned long handle, dma_addr_t dma_addr);
 
+       int (*dma_pin_guest_page)(unsigned long handle, dma_addr_t dma_addr);
+
        int (*map_gfn_to_mfn)(unsigned long handle, unsigned long gfn,
                              unsigned long mfn, unsigned int nr, bool map);
        int (*set_trap_area)(unsigned long handle, u64 start, u64 end,
index 04a5a0d9082393de81200181074b9683ed6bce81..3259a1fa69e105a2c91bca299dcec8d063bdfdc0 100644 (file)
@@ -1916,6 +1916,28 @@ static int kvmgt_dma_map_guest_page(unsigned long handle, unsigned long gfn,
        return ret;
 }
 
+static int kvmgt_dma_pin_guest_page(unsigned long handle, dma_addr_t dma_addr)
+{
+       struct kvmgt_guest_info *info;
+       struct gvt_dma *entry;
+       int ret = 0;
+
+       if (!handle_valid(handle))
+               return -ENODEV;
+
+       info = (struct kvmgt_guest_info *)handle;
+
+       mutex_lock(&info->vgpu->vdev.cache_lock);
+       entry = __gvt_cache_find_dma_addr(info->vgpu, dma_addr);
+       if (entry)
+               kref_get(&entry->ref);
+       else
+               ret = -ENOMEM;
+       mutex_unlock(&info->vgpu->vdev.cache_lock);
+
+       return ret;
+}
+
 static void __gvt_dma_release(struct kref *ref)
 {
        struct gvt_dma *entry = container_of(ref, typeof(*entry), ref);
@@ -2027,6 +2049,7 @@ static struct intel_gvt_mpt kvmgt_mpt = {
        .gfn_to_mfn = kvmgt_gfn_to_pfn,
        .dma_map_guest_page = kvmgt_dma_map_guest_page,
        .dma_unmap_guest_page = kvmgt_dma_unmap_guest_page,
+       .dma_pin_guest_page = kvmgt_dma_pin_guest_page,
        .set_opregion = kvmgt_set_opregion,
        .set_edid = kvmgt_set_edid,
        .get_vfio_device = kvmgt_get_vfio_device,
index 0f944012812304c052ad035917ffa442bd381a24..9ad224df9c68bb2aedbb58fbc0c4d4387a95eada 100644 (file)
@@ -254,6 +254,21 @@ static inline void intel_gvt_hypervisor_dma_unmap_guest_page(
        intel_gvt_host.mpt->dma_unmap_guest_page(vgpu->handle, dma_addr);
 }
 
+/**
+ * intel_gvt_hypervisor_dma_pin_guest_page - pin guest dma buf
+ * @vgpu: a vGPU
+ * @dma_addr: guest dma addr
+ *
+ * Returns:
+ * 0 on success, negative error code if failed.
+ */
+static inline int
+intel_gvt_hypervisor_dma_pin_guest_page(struct intel_vgpu *vgpu,
+                                       dma_addr_t dma_addr)
+{
+       return intel_gvt_host.mpt->dma_pin_guest_page(vgpu->handle, dma_addr);
+}
+
 /**
  * intel_gvt_hypervisor_map_gfn_to_mfn - map a GFN region to MFN
  * @vgpu: a vGPU