[RFC PATCH 2/7] drm/i915/gvt: Use meta fbs to stand for vGPU's planes
Tina Zhang
tina.zhang at intel.com
Mon Dec 3 07:35:17 UTC 2018
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.zhang at intel.com>
Cc: Zhenyu Wang <zhenyuw at linux.intel.com>
Cc: Zhi Wang <zhi.a.wang at 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
More information about the intel-gvt-dev
mailing list