drm/i915/gvt: Add new debugfs tool mmio_diff
authorChangbin Du <changbin.du@intel.com>
Mon, 23 Oct 2017 03:46:44 +0000 (11:46 +0800)
committerZhenyu Wang <zhenyuw@linux.intel.com>
Thu, 16 Nov 2017 03:48:32 +0000 (11:48 +0800)
This new debugfs entry is used to figure out which registers of vGPU
is different to host. It is a useful tool for new platform enabling
and debugging. When read this entry, all the diff mmio are recognized
and sorted by mmio offset. Besides, the bit positions of different
value are listed in 'Diff' column. Here is a show:

$ sudo cat ./mmio_diff
Offset   HW       vGPU     Diff
00002030 000025f8 00000000 3-8,10,13
00002034 012025f8 00000000 3-8,10,13,21,24
00002038 027fb000 00000000 12-13,15-22,25
0000203c 00003000 00000000 12-13
00002054 0000000a 00000040 1,3,6
00002074 012025f8 00000000 3-8,10,13,21,24
00002080 fffe6000 00000000 13-14,17-31
000020a8 fffffeff ffffffff 8
000020d4 00000004 00000000 2
....
00145974 eb42718c 010c11b0 2-5,13-14,17-19,22,25,27,29-31
00145978 0000002f 0000002a 0,2
0014597c 0000002f 0000002a 0,2
00145980 0000002b 00000028 0-1
00145984 a5a87c9e b27d20c0 1-4,6,10-12,14,16,18,20,22-26,28
001459c0 88390000 883c0000 16,18
00146200 88350000 883a0000 16-19
Total: 72432, Diff: 901

v3: fix a typo.
v2: add mmio_hw_access_pre/post().

Signed-off-by: Changbin Du <changbin.du@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
drivers/gpu/drm/i915/gvt/debugfs.c

index 02acd5842605581fa6613fa3cf6dc67fab020206..32a66dfdf1127d3a0277fd29579cbdc2418fd7ac 100644 (file)
  * SOFTWARE.
  */
 #include <linux/debugfs.h>
+#include <linux/list_sort.h>
 #include "i915_drv.h"
 #include "gvt.h"
 
+struct mmio_diff_param {
+       struct intel_vgpu *vgpu;
+       int total;
+       int diff;
+       struct list_head diff_mmio_list;
+};
+
+struct diff_mmio {
+       struct list_head node;
+       u32 offset;
+       u32 preg;
+       u32 vreg;
+};
+
+/* Compare two diff_mmio items. */
+static int mmio_offset_compare(void *priv,
+       struct list_head *a, struct list_head *b)
+{
+       struct diff_mmio *ma;
+       struct diff_mmio *mb;
+
+       ma = container_of(a, struct diff_mmio, node);
+       mb = container_of(b, struct diff_mmio, node);
+       if (ma->offset < mb->offset)
+               return -1;
+       else if (ma->offset > mb->offset)
+               return 1;
+       return 0;
+}
+
+static inline int mmio_diff_handler(struct intel_gvt *gvt,
+                                   u32 offset, void *data)
+{
+       struct drm_i915_private *dev_priv = gvt->dev_priv;
+       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);
+
+       if (preg != vreg) {
+               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++;
+       }
+       param->total++;
+       return 0;
+}
+
+/* Show the all the different values of tracked mmio. */
+static int vgpu_mmio_diff_show(struct seq_file *s, void *unused)
+{
+       struct intel_vgpu *vgpu = s->private;
+       struct intel_gvt *gvt = vgpu->gvt;
+       struct mmio_diff_param param = {
+               .vgpu = vgpu,
+               .total = 0,
+               .diff = 0,
+       };
+       struct diff_mmio *node, *next;
+
+       INIT_LIST_HEAD(&param.diff_mmio_list);
+
+       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. */
+       intel_gvt_for_each_tracked_mmio(gvt, mmio_diff_handler, &param);
+       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, "%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;
+}
+
+static int vgpu_mmio_diff_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, vgpu_mmio_diff_show, inode->i_private);
+}
+
+static const struct file_operations vgpu_mmio_diff_fops = {
+       .open           = vgpu_mmio_diff_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 /**
  * intel_gvt_debugfs_add_vgpu - register debugfs entries for a vGPU
@@ -47,6 +157,11 @@ 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;
+
        return 0;
 }