0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #include <linux/debugfs.h>
0024 #include <linux/list_sort.h>
0025 #include "i915_drv.h"
0026 #include "gvt.h"
0027
0028 struct mmio_diff_param {
0029 struct intel_vgpu *vgpu;
0030 int total;
0031 int diff;
0032 struct list_head diff_mmio_list;
0033 };
0034
0035 struct diff_mmio {
0036 struct list_head node;
0037 u32 offset;
0038 u32 preg;
0039 u32 vreg;
0040 };
0041
0042
0043 static int mmio_offset_compare(void *priv,
0044 const struct list_head *a, const struct list_head *b)
0045 {
0046 struct diff_mmio *ma;
0047 struct diff_mmio *mb;
0048
0049 ma = container_of(a, struct diff_mmio, node);
0050 mb = container_of(b, struct diff_mmio, node);
0051 if (ma->offset < mb->offset)
0052 return -1;
0053 else if (ma->offset > mb->offset)
0054 return 1;
0055 return 0;
0056 }
0057
0058 static inline int mmio_diff_handler(struct intel_gvt *gvt,
0059 u32 offset, void *data)
0060 {
0061 struct mmio_diff_param *param = data;
0062 struct diff_mmio *node;
0063 u32 preg, vreg;
0064
0065 preg = intel_uncore_read_notrace(gvt->gt->uncore, _MMIO(offset));
0066 vreg = vgpu_vreg(param->vgpu, offset);
0067
0068 if (preg != vreg) {
0069 node = kmalloc(sizeof(*node), GFP_ATOMIC);
0070 if (!node)
0071 return -ENOMEM;
0072
0073 node->offset = offset;
0074 node->preg = preg;
0075 node->vreg = vreg;
0076 list_add(&node->node, ¶m->diff_mmio_list);
0077 param->diff++;
0078 }
0079 param->total++;
0080 return 0;
0081 }
0082
0083
0084 static int vgpu_mmio_diff_show(struct seq_file *s, void *unused)
0085 {
0086 struct intel_vgpu *vgpu = s->private;
0087 struct intel_gvt *gvt = vgpu->gvt;
0088 struct mmio_diff_param param = {
0089 .vgpu = vgpu,
0090 .total = 0,
0091 .diff = 0,
0092 };
0093 struct diff_mmio *node, *next;
0094
0095 INIT_LIST_HEAD(¶m.diff_mmio_list);
0096
0097 mutex_lock(&gvt->lock);
0098 spin_lock_bh(&gvt->scheduler.mmio_context_lock);
0099
0100 mmio_hw_access_pre(gvt->gt);
0101
0102 intel_gvt_for_each_tracked_mmio(gvt, mmio_diff_handler, ¶m);
0103 mmio_hw_access_post(gvt->gt);
0104
0105 spin_unlock_bh(&gvt->scheduler.mmio_context_lock);
0106 mutex_unlock(&gvt->lock);
0107
0108
0109 list_sort(NULL, ¶m.diff_mmio_list, mmio_offset_compare);
0110
0111 seq_printf(s, "%-8s %-8s %-8s %-8s\n", "Offset", "HW", "vGPU", "Diff");
0112 list_for_each_entry_safe(node, next, ¶m.diff_mmio_list, node) {
0113 u32 diff = node->preg ^ node->vreg;
0114
0115 seq_printf(s, "%08x %08x %08x %*pbl\n",
0116 node->offset, node->preg, node->vreg,
0117 32, &diff);
0118 list_del(&node->node);
0119 kfree(node);
0120 }
0121 seq_printf(s, "Total: %d, Diff: %d\n", param.total, param.diff);
0122 return 0;
0123 }
0124 DEFINE_SHOW_ATTRIBUTE(vgpu_mmio_diff);
0125
0126 static int
0127 vgpu_scan_nonprivbb_get(void *data, u64 *val)
0128 {
0129 struct intel_vgpu *vgpu = (struct intel_vgpu *)data;
0130
0131 *val = vgpu->scan_nonprivbb;
0132 return 0;
0133 }
0134
0135
0136
0137
0138
0139
0140
0141 static int
0142 vgpu_scan_nonprivbb_set(void *data, u64 val)
0143 {
0144 struct intel_vgpu *vgpu = (struct intel_vgpu *)data;
0145
0146 vgpu->scan_nonprivbb = val;
0147 return 0;
0148 }
0149
0150 DEFINE_SIMPLE_ATTRIBUTE(vgpu_scan_nonprivbb_fops,
0151 vgpu_scan_nonprivbb_get, vgpu_scan_nonprivbb_set,
0152 "0x%llx\n");
0153
0154
0155
0156
0157
0158 void intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu)
0159 {
0160 char name[16] = "";
0161
0162 snprintf(name, 16, "vgpu%d", vgpu->id);
0163 vgpu->debugfs = debugfs_create_dir(name, vgpu->gvt->debugfs_root);
0164
0165 debugfs_create_bool("active", 0444, vgpu->debugfs, &vgpu->active);
0166 debugfs_create_file("mmio_diff", 0444, vgpu->debugfs, vgpu,
0167 &vgpu_mmio_diff_fops);
0168 debugfs_create_file("scan_nonprivbb", 0644, vgpu->debugfs, vgpu,
0169 &vgpu_scan_nonprivbb_fops);
0170 }
0171
0172
0173
0174
0175
0176 void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu *vgpu)
0177 {
0178 debugfs_remove_recursive(vgpu->debugfs);
0179 vgpu->debugfs = NULL;
0180 }
0181
0182
0183
0184
0185
0186 void intel_gvt_debugfs_init(struct intel_gvt *gvt)
0187 {
0188 struct drm_minor *minor = gvt->gt->i915->drm.primary;
0189
0190 gvt->debugfs_root = debugfs_create_dir("gvt", minor->debugfs_root);
0191
0192 debugfs_create_ulong("num_tracked_mmio", 0444, gvt->debugfs_root,
0193 &gvt->mmio.num_tracked_mmio);
0194 }
0195
0196
0197
0198
0199
0200 void intel_gvt_debugfs_clean(struct intel_gvt *gvt)
0201 {
0202 debugfs_remove_recursive(gvt->debugfs_root);
0203 gvt->debugfs_root = NULL;
0204 }