[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, ¶m->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, ¶m->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(¶m.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, ¶m);
- 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, ¶m.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, ¶m.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