Create and initialize vGPU meta framebuffers during vGPU's creation.
Each meta framebuffer is an intel_framebuffer. Userspace can get the
userspace visible identifier of that meta framebuffer by accessing
plane_id_index attribute.

For example:
In "/sys/bus/pci/devices/0000\:00\:02.0/$vGPU_id/intel_vgpu/" directory,

   /* plane_id_index: pipe#(bit16:8) and plane#(bit7:0)*/
   echo "0x10" > plane_index_id //Set the index to the plane 0 of pipe 1

   /*
    * Dump userspace visible identifier of the meta framebuffer
    * standing for the primary plane of the vGPU's pipe one
    */
   cat plane_index_id //dump the id for plane 0 of pipe 1

Then userspace can use this id with the exsting KMS IOCTL, e.g.
drmModeSetPlane, to assign a physical plane to this virtual plane.

Signed-off-by: Tina Zhang <tina.zh...@intel.com>
Cc: Zhenyu Wang <zhen...@linux.intel.com>
Cc: Zhi Wang <zhi.a.w...@intel.com>
---
 drivers/gpu/drm/i915/gvt/display.c | 150 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/gvt.h     |  16 ++++
 drivers/gpu/drm/i915/gvt/kvmgt.c   |  46 ++++++++++++
 3 files changed, 212 insertions(+)

diff --git a/drivers/gpu/drm/i915/gvt/display.c 
b/drivers/gpu/drm/i915/gvt/display.c
index df1e141..a9176a1 100644
--- a/drivers/gpu/drm/i915/gvt/display.c
+++ b/drivers/gpu/drm/i915/gvt/display.c
@@ -442,6 +442,152 @@ void intel_gvt_emulate_vblank(struct intel_gvt *gvt)
        mutex_unlock(&gvt->lock);
 }
 
+struct intel_vgpu_fb_meta_data {
+       u32 vgpu_plane_id; /* vgpu_id(23:16):vgpu_pipe(15:8):vgpu_plane(7:0)*/
+       struct intel_vgpu *vgpu; // the vGPU this meta_fb belongs to
+};
+
+static void meta_fb_destroy(struct drm_framebuffer *fb)
+{
+       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+
+       if (intel_fb->meta_fb.type_id != INTEL_META_FB_VGPU)
+               return;
+
+       kfree(intel_fb->meta_fb.private);
+       intel_fb->meta_fb.private = NULL;
+
+       drm_framebuffer_cleanup(fb);
+       kfree(intel_fb);
+}
+
+static void clean_meta_fb(struct intel_vgpu *vgpu)
+{
+       enum pipe pipe;
+       enum plane_id plane_id;
+       struct intel_framebuffer *intel_fb;
+
+       for (pipe = 0; pipe < I915_MAX_PIPES; pipe++) {
+               for (plane_id = 0; plane_id < I915_MAX_PLANES; plane_id++) {
+                       intel_fb = 
vgpu->display.meta_fbs.meta_fb[pipe][plane_id];
+                       if (!intel_fb)
+                               drm_framebuffer_put(&intel_fb->base);
+
+                       intel_fb = NULL;
+               }
+       }
+}
+
+static int meta_fb_create_handle(struct drm_framebuffer *fb,
+                                struct drm_file *file,
+                                unsigned int *handle)
+{
+       return -ENODEV;
+}
+
+static int meta_fb_dirty(struct drm_framebuffer *fb,
+                        struct drm_file *file,
+                        unsigned int flags,
+                        unsigned int color,
+                        struct drm_clip_rect *clips,
+                        unsigned int num_clips)
+{
+       return 0;
+}
+
+static const struct drm_framebuffer_funcs meta_fb_funcs = {
+       .destroy = meta_fb_destroy,
+       .create_handle = meta_fb_create_handle,
+       .dirty = meta_fb_dirty,
+};
+
+static void meta_fb_update(struct intel_framebuffer *intel_fb,
+                          enum pipe pipe, enum plane_id plane_id)
+{
+       struct intel_vgpu_fb_meta_data *meta_data;
+       struct intel_gvt *gvt;
+
+       if (!intel_fb || intel_fb->meta_fb.type_id != INTEL_META_FB_VGPU)
+               return;
+
+       meta_data = intel_fb->meta_fb.private;
+       gvt = meta_data->vgpu->gvt;
+
+       if (gvt->assigned_plane[pipe][plane_id].vgpu_plane_id !=
+                                               meta_data->vgpu_plane_id) {
+               gvt->assigned_plane[pipe][plane_id].vgpu_plane_id =
+                                               meta_data->vgpu_plane_id;
+               gvt->assigned_plane[pipe][plane_id].framebuffer_id =
+                                               intel_fb->base.base.id;
+               intel_fb->meta_fb.ggtt_offset = 0;
+               intel_fb->meta_fb.should_be_offscreen = true;
+       } else if (!intel_fb->meta_fb.ggtt_offset) {
+               intel_fb->meta_fb.should_be_offscreen = true;
+       } else {
+               intel_fb->meta_fb.should_be_offscreen = false;
+       }
+}
+
+static int init_meta_fb(struct intel_vgpu *vgpu)
+{
+       struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
+       struct intel_vgpu_fb_meta_data *meta_data;
+       struct drm_mode_fb_cmd2 mode_cmd;
+       struct intel_framebuffer *intel_fb;
+       enum pipe pipe;
+       enum plane_id plane_id;
+       int ret = 0;
+
+       for (pipe = 0; pipe < I915_MAX_PIPES; pipe++) {
+               for (plane_id = 0; plane_id < I915_MAX_PLANES; plane_id++) {
+                       intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+                       if (!intel_fb)
+                               return -ENOMEM;
+
+                       /*
+                        * Create a drm_framebuffer with defaults.
+                        */
+                       mode_cmd.pixel_format = DRM_FORMAT_XRGB8888;
+                       mode_cmd.width = dev_priv->drm.mode_config.max_width;
+                       mode_cmd.height = dev_priv->drm.mode_config.max_height;
+                       mode_cmd.flags = DRM_MODE_FB_MODIFIERS;
+                       mode_cmd.handles[0] = 0;
+                       mode_cmd.pitches[0] = mode_cmd.width * 4;
+                       mode_cmd.offsets[0] = 0;
+                       mode_cmd.modifier[0] = DRM_FORMAT_MOD_LINEAR;
+
+                       drm_helper_mode_fill_fb_struct(&dev_priv->drm,
+                                                      &intel_fb->base, 
&mode_cmd);
+
+                       ret = drm_framebuffer_init(&dev_priv->drm,
+                                                  &intel_fb->base, 
&meta_fb_funcs);
+                       if (ret) {
+                               DRM_ERROR("%s: framebuffer init failed %d\n",
+                                         __func__, ret);
+                               kfree(intel_fb);
+                               return ret;
+                       }
+
+                       meta_data = kmalloc(sizeof(struct 
intel_vgpu_fb_meta_data),
+                                           GFP_KERNEL);
+                       if (unlikely(!meta_data)) {
+                               return -ENOMEM;
+                       }
+
+                       meta_data->vgpu_plane_id = (vgpu->id << 16) |
+                               (pipe << 8) | plane_id;
+                       meta_data->vgpu = vgpu;
+
+                       intel_fb->meta_fb.private = meta_data;
+                       intel_fb->meta_fb.update = meta_fb_update;
+                       intel_fb->meta_fb.type_id = INTEL_META_FB_VGPU;
+
+                       vgpu->display.meta_fbs.meta_fb[pipe][plane_id] = 
intel_fb;
+               }
+       }
+       return 0;
+}
+
 /**
  * intel_vgpu_clean_display - clean vGPU virtual display emulation
  * @vgpu: a vGPU
@@ -457,6 +603,8 @@ void intel_vgpu_clean_display(struct intel_vgpu *vgpu)
                clean_virtual_dp_monitor(vgpu, PORT_D);
        else
                clean_virtual_dp_monitor(vgpu, PORT_B);
+
+       clean_meta_fb(vgpu);
 }
 
 /**
@@ -476,6 +624,8 @@ int intel_vgpu_init_display(struct intel_vgpu *vgpu, u64 
resolution)
 
        intel_vgpu_init_i2c_edid(vgpu);
 
+       init_meta_fb(vgpu);
+
        if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
                return setup_virtual_dp_monitor(vgpu, PORT_D, GVT_DP_D,
                                                resolution);
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 31f6cdb..0ab10b0 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -131,10 +131,16 @@ struct intel_vgpu_opregion {
 
 #define vgpu_opregion(vgpu) (&(vgpu->opregion))
 
+struct intel_vgpu_meta_fbs {
+       struct intel_framebuffer *meta_fb[I915_MAX_PIPES][I915_MAX_PLANES];
+       u32 plane_id_index;
+};
+
 struct intel_vgpu_display {
        struct intel_vgpu_i2c_edid i2c_edid;
        struct intel_vgpu_port ports[I915_MAX_PORTS];
        struct intel_vgpu_sbi sbi;
+       struct intel_vgpu_meta_fbs meta_fbs;
 };
 
 struct vgpu_sched_ctl {
@@ -301,6 +307,13 @@ struct intel_vgpu_type {
        enum intel_vgpu_edid resolution;
 };
 
+struct assigned_plane {
+       u32 vgpu_plane_id;
+
+       /* userspace visible identifier */
+       int framebuffer_id;
+};
+
 struct intel_gvt {
        /* GVT scope lock, protect GVT itself, and all resource currently
         * not yet protected by special locks(vgpu and scheduler lock).
@@ -340,6 +353,9 @@ struct intel_gvt {
        } engine_mmio_list;
 
        struct dentry *debugfs_root;
+
+       /* vGPU plane assignment */
+       struct assigned_plane assigned_plane[I915_MAX_PIPES][I915_MAX_PLANES];
 };
 
 static inline struct intel_gvt *to_gvt(struct drm_i915_private *i915)
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
index c107214..7f4704d 100644
--- a/drivers/gpu/drm/i915/gvt/kvmgt.c
+++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
@@ -1420,12 +1420,58 @@ hw_id_show(struct device *dev, struct device_attribute 
*attr,
        return sprintf(buf, "\n");
 }
 
+static ssize_t
+plane_id_index_show(struct device *dev, struct device_attribute *attr,
+        char *buf)
+{
+       struct mdev_device *mdev = mdev_from_dev(dev);
+
+       if (mdev) {
+               struct intel_vgpu *vgpu = (struct intel_vgpu *)
+                       mdev_get_drvdata(mdev);
+               enum pipe pipe = vgpu->display.meta_fbs.plane_id_index &
+                       0x000000F0;
+               enum plane_id plane_id = vgpu->display.meta_fbs.plane_id_index &
+                       0x0000000F;
+
+               if ((pipe < I915_MAX_PIPES || plane_id < I915_MAX_PLANES) &&
+                       vgpu->display.meta_fbs.meta_fb[pipe][plane_id]) {
+                       return sprintf(buf, "%u\n",
+                              
vgpu->display.meta_fbs.meta_fb[pipe][plane_id]->base.base.id);
+               }
+       }
+       return sprintf(buf, "\n");
+}
+
+static ssize_t
+plane_id_index_store(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t n)
+{
+       struct mdev_device *mdev = mdev_from_dev(dev);
+       ssize_t ret;
+       u32 val;
+
+       ret = kstrtou32(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       if (mdev) {
+               struct intel_vgpu *vgpu = (struct intel_vgpu *)
+                       mdev_get_drvdata(mdev);
+               vgpu->display.meta_fbs.plane_id_index = val;
+       }
+
+       return n;
+}
+
 static DEVICE_ATTR_RO(vgpu_id);
 static DEVICE_ATTR_RO(hw_id);
+static DEVICE_ATTR_RW(plane_id_index);
 
 static struct attribute *intel_vgpu_attrs[] = {
        &dev_attr_vgpu_id.attr,
        &dev_attr_hw_id.attr,
+       &dev_attr_plane_id_index.attr,
        NULL
 };
 
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to