aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/gvt/debugfs.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-12-04 09:40:35 +1000
committerDave Airlie <airlied@redhat.com>2017-12-04 10:56:53 +1000
commitca797d29cd63e7b71b4eea29aff3b1cefd1ecb59 (patch)
treedb1ada69f713da68b43c828bd15f90e250f86ab7 /drivers/gpu/drm/i915/gvt/debugfs.c
parent2c1c55cb75a9c72f9726fabb8c3607947711a8df (diff)
parent010d118c20617021025a930bc8e90f371ab99da5 (diff)
Merge tag 'drm-intel-next-2017-11-17-1' of git://anongit.freedesktop.org/drm/drm-intel into drm-next
More change sets for 4.16: - Many improvements for selftests and other igt tests (Chris) - Forcewake with PUNIT->PMIC bus fixes and robustness (Hans) - Define an engine class for uABI (Tvrtko) - Context switch fixes and improvements (Chris) - GT powersavings and power gating simplification and fixes (Chris) - Other general driver clean-ups (Chris, Lucas, Ville) - Removing old, useless and/or bad workarounds (Chris, Oscar, Radhakrishna) - IPS, pipe config, etc in preparation for another Fast Boot attempt (Maarten) - OA perf fixes and support to Coffee Lake and Cannonlake (Lionel) - Fixes around GPU fault registers (Michel) - GEM Proxy (Tina) - Refactor of Geminilake and Cannonlake plane color handling (James) - Generalize transcoder loop (Mika Kahola) - New HW Workaround for Cannonlake and Geminilake (Rodrigo) - Resume GuC before using GEM (Chris) - Stolen Memory handling improvements (Ville) - Initialize entry in PPAT for older compilers (Chris) - Other fixes and robustness improvements on execbuf (Chris) - Improve logs of GEM_BUG_ON (Mika Kuoppala) - Rework with massive rename of GuC functions and files (Sagar) - Don't sanitize frame start delay if pipe is off (Ville) - Cannonlake clock fixes (Rodrigo) - Cannonlake HDMI 2.0 support (Rodrigo) - Add a GuC doorbells selftest (Michel) - Add might_sleep() check to our wait_for() (Chris) Many GVT changes for 4.16: - CSB HWSP update support (Weinan) - GVT debug helpers, dyndbg and debugfs (Chuanxiao, Shuo) - full virtualized opregion (Xiaolin) - VM health check for sane fallback (Fred) - workload submission code refactor for future enabling (Zhi) - Updated repo URL in MAINTAINERS (Zhenyu) - other many misc fixes * tag 'drm-intel-next-2017-11-17-1' of git://anongit.freedesktop.org/drm/drm-intel: (260 commits) drm/i915: Update DRIVER_DATE to 20171117 drm/i915: Add a policy note for removing workarounds drm/i915/selftests: Report ENOMEM clearly for an allocation failure Revert "drm/i915: Display WA #1133 WaFbcSkipSegments:cnl, glk" drm/i915: Calculate g4x intermediate watermarks correctly drm/i915: Calculate vlv/chv intermediate watermarks correctly, v3. drm/i915: Pass crtc_state to ips toggle functions, v2 drm/i915: Pass idle crtc_state to intel_dp_sink_crc drm/i915: Enable FIFO underrun reporting after initial fastset, v4. drm/i915: Mark the userptr invalidate workqueue as WQ_MEM_RECLAIM drm/i915: Add might_sleep() check to wait_for() drm/i915/selftests: Add a GuC doorbells selftest drm/i915/cnl: Extend HDMI 2.0 support to CNL. drm/i915/cnl: Simplify dco_fraction calculation. drm/i915/cnl: Don't blindly replace qdiv. drm/i915/cnl: Fix wrpll math for higher freqs. drm/i915/cnl: Fix, simplify and unify wrpll variable sizes. drm/i915/cnl: Remove useless conversion. drm/i915/cnl: Remove spurious central_freq. drm/i915/selftests: exercise_ggtt may have nothing to do ...
Diffstat (limited to 'drivers/gpu/drm/i915/gvt/debugfs.c')
-rw-r--r--drivers/gpu/drm/i915/gvt/debugfs.c212
1 files changed, 212 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/gvt/debugfs.c b/drivers/gpu/drm/i915/gvt/debugfs.c
new file mode 100644
index 000000000000..32a66dfdf112
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/debugfs.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright(c) 2011-2017 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * 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
+ * @vgpu: a vGPU
+ *
+ * Returns:
+ * Zero on success, negative error code if failed.
+ */
+int intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu)
+{
+ struct dentry *ent;
+ char name[10] = "";
+
+ sprintf(name, "vgpu%d", vgpu->id);
+ vgpu->debugfs = debugfs_create_dir(name, vgpu->gvt->debugfs_root);
+ if (!vgpu->debugfs)
+ return -ENOMEM;
+
+ ent = debugfs_create_bool("active", 0444, vgpu->debugfs,
+ &vgpu->active);
+ if (!ent)
+ return -ENOMEM;
+
+ ent = debugfs_create_file("mmio_diff", 0444, vgpu->debugfs,
+ vgpu, &vgpu_mmio_diff_fops);
+ if (!ent)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * intel_gvt_debugfs_remove_vgpu - remove debugfs entries of a vGPU
+ * @vgpu: a vGPU
+ */
+void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu *vgpu)
+{
+ debugfs_remove_recursive(vgpu->debugfs);
+ vgpu->debugfs = NULL;
+}
+
+/**
+ * intel_gvt_debugfs_init - register gvt debugfs root entry
+ * @gvt: GVT device
+ *
+ * Returns:
+ * zero on success, negative if failed.
+ */
+int intel_gvt_debugfs_init(struct intel_gvt *gvt)
+{
+ struct drm_minor *minor = gvt->dev_priv->drm.primary;
+ struct dentry *ent;
+
+ gvt->debugfs_root = debugfs_create_dir("gvt", minor->debugfs_root);
+ if (!gvt->debugfs_root) {
+ gvt_err("Cannot create debugfs dir\n");
+ return -ENOMEM;
+ }
+
+ ent = debugfs_create_ulong("num_tracked_mmio", 0444, gvt->debugfs_root,
+ &gvt->mmio.num_tracked_mmio);
+ if (!ent)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * intel_gvt_debugfs_clean - remove debugfs entries
+ * @gvt: GVT device
+ */
+void intel_gvt_debugfs_clean(struct intel_gvt *gvt)
+{
+ debugfs_remove_recursive(gvt->debugfs_root);
+ gvt->debugfs_root = NULL;
+}