[PATCH v2] drm/i915/gvt: Enable gvt debugfs with mmio comparison on all vGPUs.

Colin Xu colin.xu at intel.com
Wed Jun 13 07:36:08 UTC 2018


v2:
  - Reuse most mmio_diff defines and functions.
  - Keep the helper name mmio_diff(), do not introduce new name.

Current mmio_diff_handler can only compare 1 active vGPU with host.

The patch will extend the mmio comparison debugfs capability to all
active vGPUs, selected by vGPU mask bits.
  - Add mmio_compare_vgpu_mask to enable vGPU selection.
    - Bit 0: select all active vGPU.
    - Bit i: select vGPU id i.
  - Add mmio_compare to show comparison result.
  - Retive mmio_diff since it's functionality is inherited and enhanced.

The new headline of the comparision results is:
+---+--------+----+--------+--------+-----+
| * | Offset | HW | vGPU i | vGPU j | ... |
+---+--------+----+--------+--------+-----+

The leading star of each line indicate diff between preg and vreg(s).
When only 1 vGPU is selected, per-bits-diff will append to each line.

Sample output:

- 1 vGPU, debugfs_vgpu_mask is 0x1 or 0x2:
* Offset   HW       vGPU   1 Diff-Bits
  0000003c 00000000 00000000
* 00002030 00000ad8 00000000 3-4,6-7,9,11

- 3 vGPUs, debugfs_vgpu_mask is 0x1:
* Offset   HW       vGPU   1 vGPU   2 vGPU   3
  0000003c 00000000 00000000 00000000 00000000
* 00002074 002012d0 0000cce8 00000000 00013b20

- 3 vGPUs, debugfs_vgpu_mask is 0xa:
* Offset   HW       vGPU   1 vGPU   3
  0000003c 00000000 00000000 00000000
* 00002074 0000be30 0000d040 00013b20

Signed-off-by: Colin Xu <colin.xu at intel.com>
---
 drivers/gpu/drm/i915/gvt/debugfs.c | 161 +++++++++++++++++++++++------
 drivers/gpu/drm/i915/gvt/gvt.h     |  10 ++
 2 files changed, 137 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/i915/gvt/debugfs.c b/drivers/gpu/drm/i915/gvt/debugfs.c
index 2ec89bcb59f1..3fa88bd22922 100644
--- a/drivers/gpu/drm/i915/gvt/debugfs.c
+++ b/drivers/gpu/drm/i915/gvt/debugfs.c
@@ -25,18 +25,38 @@
 #include "i915_drv.h"
 #include "gvt.h"
 
+/*
+ * mmio_diff_param holds necessary member to compare mmio
+ * between HW and vGPU(s)
+ */
 struct mmio_diff_param {
-	struct intel_vgpu *vgpu;
+	struct intel_gvt *gvt;
+	unsigned long vgpu_selected;
 	int total;
 	int diff;
 	struct list_head diff_mmio_list;
 };
 
+/*
+ * vreg_element holds vreg offset and value of selected vGPU.
+ * vGPU id is also saved for sanity check.
+ */
+struct vreg_element {
+	struct list_head node;
+	u32 vgpu_id;
+	u32 offset;
+	u32 val;
+};
+
+/*
+ * diff_mmio holds preg and vreg(s) of selected vGPU(s).
+ */
 struct diff_mmio {
 	struct list_head node;
 	u32 offset;
 	u32 preg;
-	u32 vreg;
+	struct list_head vreg_val_list;
+	bool all_equal;
 };
 
 /* Compare two diff_mmio items. */
@@ -59,70 +79,133 @@ static inline int mmio_diff_handler(struct intel_gvt *gvt,
 				    u32 offset, void *data)
 {
 	struct drm_i915_private *dev_priv = gvt->dev_priv;
+	struct intel_vgpu *vgpu;
+	int id;
 	struct mmio_diff_param *param = data;
 	struct diff_mmio *node;
-	u32 preg, vreg;
-
-	preg = I915_READ_NOTRACE(_MMIO(offset));
-	vreg = vgpu_vreg(param->vgpu, offset);
+	struct vreg_element *vgpu_node;
 
-	if (preg != vreg) {
-		node = kmalloc(sizeof(*node), GFP_KERNEL);
-		if (!node)
-			return -ENOMEM;
+	node = kmalloc(sizeof(*node), GFP_KERNEL);
+	if (!node)
+		return -ENOMEM;
 
-		node->offset = offset;
-		node->preg = preg;
-		node->vreg = vreg;
-		list_add(&node->node, &param->diff_mmio_list);
-		param->diff++;
+	node->offset = offset;
+	node->preg = I915_READ_NOTRACE(_MMIO(offset));
+	node->all_equal = true;
+	INIT_LIST_HEAD(&node->vreg_val_list);
+
+	for_each_active_vgpu(gvt, vgpu, id) {
+		/* Only save vreg of selected vGPU */
+		if (param->vgpu_selected & (1 << id)) {
+			vgpu_node = kmalloc(sizeof(*vgpu_node), GFP_KERNEL);
+			if (!vgpu_node)
+				return -ENOMEM;
+			vgpu_node->vgpu_id = id;
+			vgpu_node->offset = offset;
+			vgpu_node->val = vgpu_vreg(vgpu, offset);
+			list_add(&vgpu_node->node, &node->vreg_val_list);
+			/* Mark any preg vs. vreg diff as a diff count */
+			if (node->preg != vgpu_node->val)
+				node->all_equal = false;
+		}
 	}
+
+	list_add(&node->node, &param->diff_mmio_list);
+
 	param->total++;
+	if (!node->all_equal)
+		param->diff++;
+
 	return 0;
 }
 
-/* Show the all the different values of tracked mmio. */
-static int vgpu_mmio_diff_show(struct seq_file *s, void *unused)
+static int mmio_diff_show(struct seq_file *s, void *unused)
 {
-	struct intel_vgpu *vgpu = s->private;
-	struct intel_gvt *gvt = vgpu->gvt;
+	struct intel_gvt *gvt = s->private;
+	struct intel_vgpu *vgpu;
+	int id;
 	struct mmio_diff_param param = {
-		.vgpu = vgpu,
+		.gvt = gvt,
+		.vgpu_selected = 0,
 		.total = 0,
 		.diff = 0,
 	};
+	unsigned long vgpu_mask = gvt->debugfs_vgpu_mask;
 	struct diff_mmio *node, *next;
+	struct vreg_element *vgpu_node, *vgpu_node_next;
+
+	/*
+	 * Ignore per-vgpu selection is bit 0 is set, aka all vgpu selected.
+	 */
+	if (vgpu_mask & 0x1)
+		vgpu_mask = ~1;
 
 	INIT_LIST_HEAD(&param.diff_mmio_list);
 
+	/*
+	 * Print headers, with select vGPU only.
+	 * Leading star of each line indicates a mmio diff from HW at offset x.
+	 */
+	seq_printf(s, "* %-8s %-8s", "Offset", "HW");
+
 	mutex_lock(&gvt->lock);
 	spin_lock_bh(&gvt->scheduler.mmio_context_lock);
-
 	mmio_hw_access_pre(gvt->dev_priv);
-	/* Recognize all the diff mmios to list. */
+	for_each_active_vgpu(gvt, vgpu, id) {
+		if (vgpu_mask & (1 << id)) {
+			param.vgpu_selected |= 1 << id;
+			seq_printf(s, " vGPU % 3d", id);
+		}
+	}
+	/* Show diff bits if only 1 vGPU selected */
+	if (!(param.vgpu_selected & (param.vgpu_selected - 1)))
+		seq_puts(s, " Diff-Bits");
+	seq_puts(s, "\n");
+
+	/* Recognize all the mmios of select vGPU(s) to list. */
 	intel_gvt_for_each_tracked_mmio(gvt, mmio_diff_handler, &param);
-	mmio_hw_access_post(gvt->dev_priv);
 
+	mmio_hw_access_post(gvt->dev_priv);
 	spin_unlock_bh(&gvt->scheduler.mmio_context_lock);
 	mutex_unlock(&gvt->lock);
 
 	/* In an ascending order by mmio offset. */
 	list_sort(NULL, &param.diff_mmio_list, mmio_offset_compare);
 
-	seq_printf(s, "%-8s %-8s %-8s %-8s\n", "Offset", "HW", "vGPU", "Diff");
 	list_for_each_entry_safe(node, next, &param.diff_mmio_list, node) {
-		u32 diff = node->preg ^ node->vreg;
+		seq_printf(s, "%s", node->all_equal ? " " : "*");
+		seq_printf(s, " %08x %08x", node->offset, node->preg);
+
+		list_for_each_entry_safe(vgpu_node, vgpu_node_next,
+				&node->vreg_val_list, node) {
+			if (node->offset != vgpu_node->offset) {
+				pr_warn("Unmatched offset: preg (%08x) vs. vreg (%d-%08x)\n",
+					node->offset,
+					vgpu_node->vgpu_id,
+					vgpu_node->offset);
+			}
+			seq_printf(s, " %08x", vgpu_node->val);
+
+			/* Show diff bits if only 1 vGPU selected */
+			if (!(param.vgpu_selected & (param.vgpu_selected-1))) {
+				u32 diff_bits = node->preg ^ vgpu_node->val;
+
+				seq_printf(s, " %*pbl", 32, &diff_bits);
+			}
+
+			list_del(&vgpu_node->node);
+			kfree(vgpu_node);
+		}
+		seq_puts(s, "\n");
 
-		seq_printf(s, "%08x %08x %08x %*pbl\n",
-			   node->offset, node->preg, node->vreg,
-			   32, &diff);
 		list_del(&node->node);
 		kfree(node);
 	}
 	seq_printf(s, "Total: %d, Diff: %d\n", param.total, param.diff);
+
 	return 0;
 }
-DEFINE_SHOW_ATTRIBUTE(vgpu_mmio_diff);
+DEFINE_SHOW_ATTRIBUTE(mmio_diff);
 
 static int
 vgpu_scan_nonprivbb_get(void *data, u64 *val)
@@ -208,11 +291,6 @@ int intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu)
 	if (!ent)
 		return -ENOMEM;
 
-	ent = debugfs_create_file("mmio_diff", 0444, vgpu->debugfs,
-				  vgpu, &vgpu_mmio_diff_fops);
-	if (!ent)
-		return -ENOMEM;
-
 	ent = debugfs_create_file("scan_nonprivbb", 0644, vgpu->debugfs,
 				 vgpu, &vgpu_scan_nonprivbb_fops);
 	if (!ent)
@@ -254,6 +332,21 @@ int intel_gvt_debugfs_init(struct intel_gvt *gvt)
 	if (!ent)
 		return -ENOMEM;
 
+	/*
+	 * Set bit at position [vgpu id] to indicate which vGPU to select.
+	 * Select all vGPU by default.
+	 */
+	gvt->debugfs_vgpu_mask = 1;
+	ent = debugfs_create_ulong("mmio_diff_vgpu_mask", 0644,
+		gvt->debugfs_root, &gvt->debugfs_vgpu_mask);
+	if (!ent)
+		return -ENOMEM;
+
+	ent = debugfs_create_file("mmio_diff", 0444, gvt->debugfs_root,
+				  gvt, &mmio_diff_fops);
+	if (!ent)
+		return -ENOMEM;
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index de2a3a2580be..8d0e40f55212 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -338,6 +338,16 @@ struct intel_gvt {
 	} engine_mmio_list;
 
 	struct dentry *debugfs_root;
+
+	/*
+	 * Set bit at position [vgpu id] to indicate which vGPU to select.
+	 * Set bit 0 to select all vGPUs, which override per-vGPU selection.
+	 * i.e.: 0x1 - select all vGPUs.
+	 *       0xA - select vGPU id 1 and 3.
+	 * The mask should be able to hold all possible vGPU mask bits:
+	 * current range is [IDLE_VGPU_IDR + 1, GVT_MAX_VGPU)
+	 */
+	unsigned long debugfs_vgpu_mask;
 };
 
 static inline struct intel_gvt *to_gvt(struct drm_i915_private *i915)
-- 
2.17.1



More information about the intel-gvt-dev mailing list