1bc7b0be3SChangbin Du /*
2bc7b0be3SChangbin Du * Copyright(c) 2011-2017 Intel Corporation. All rights reserved.
3bc7b0be3SChangbin Du *
4bc7b0be3SChangbin Du * Permission is hereby granted, free of charge, to any person obtaining a
5bc7b0be3SChangbin Du * copy of this software and associated documentation files (the "Software"),
6bc7b0be3SChangbin Du * to deal in the Software without restriction, including without limitation
7bc7b0be3SChangbin Du * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bc7b0be3SChangbin Du * and/or sell copies of the Software, and to permit persons to whom the
9bc7b0be3SChangbin Du * Software is furnished to do so, subject to the following conditions:
10bc7b0be3SChangbin Du *
11bc7b0be3SChangbin Du * The above copyright notice and this permission notice (including the next
12bc7b0be3SChangbin Du * paragraph) shall be included in all copies or substantial portions of the
13bc7b0be3SChangbin Du * Software.
14bc7b0be3SChangbin Du *
15bc7b0be3SChangbin Du * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bc7b0be3SChangbin Du * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bc7b0be3SChangbin Du * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18bc7b0be3SChangbin Du * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bc7b0be3SChangbin Du * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20bc7b0be3SChangbin Du * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21bc7b0be3SChangbin Du * SOFTWARE.
22bc7b0be3SChangbin Du */
23bc7b0be3SChangbin Du #include <linux/debugfs.h>
24cea9083eSChangbin Du #include <linux/list_sort.h>
25bc7b0be3SChangbin Du #include "i915_drv.h"
26bc7b0be3SChangbin Du #include "gvt.h"
27bc7b0be3SChangbin Du
28cea9083eSChangbin Du struct mmio_diff_param {
29cea9083eSChangbin Du struct intel_vgpu *vgpu;
30cea9083eSChangbin Du int total;
31cea9083eSChangbin Du int diff;
32cea9083eSChangbin Du struct list_head diff_mmio_list;
33cea9083eSChangbin Du };
34cea9083eSChangbin Du
35cea9083eSChangbin Du struct diff_mmio {
36cea9083eSChangbin Du struct list_head node;
37cea9083eSChangbin Du u32 offset;
38cea9083eSChangbin Du u32 preg;
39cea9083eSChangbin Du u32 vreg;
40cea9083eSChangbin Du };
41cea9083eSChangbin Du
42cea9083eSChangbin Du /* Compare two diff_mmio items. */
mmio_offset_compare(void * priv,const struct list_head * a,const struct list_head * b)43cea9083eSChangbin Du static int mmio_offset_compare(void *priv,
444f0f586bSSami Tolvanen const struct list_head *a, const struct list_head *b)
45cea9083eSChangbin Du {
46cea9083eSChangbin Du struct diff_mmio *ma;
47cea9083eSChangbin Du struct diff_mmio *mb;
48cea9083eSChangbin Du
49cea9083eSChangbin Du ma = container_of(a, struct diff_mmio, node);
50cea9083eSChangbin Du mb = container_of(b, struct diff_mmio, node);
51cea9083eSChangbin Du if (ma->offset < mb->offset)
52cea9083eSChangbin Du return -1;
53cea9083eSChangbin Du else if (ma->offset > mb->offset)
54cea9083eSChangbin Du return 1;
55cea9083eSChangbin Du return 0;
56cea9083eSChangbin Du }
57cea9083eSChangbin Du
mmio_diff_handler(struct intel_gvt * gvt,u32 offset,void * data)58cea9083eSChangbin Du static inline int mmio_diff_handler(struct intel_gvt *gvt,
59cea9083eSChangbin Du u32 offset, void *data)
60cea9083eSChangbin Du {
61cea9083eSChangbin Du struct mmio_diff_param *param = data;
62cea9083eSChangbin Du struct diff_mmio *node;
63cea9083eSChangbin Du u32 preg, vreg;
64cea9083eSChangbin Du
65a61ac1e7SChris Wilson preg = intel_uncore_read_notrace(gvt->gt->uncore, _MMIO(offset));
66cea9083eSChangbin Du vreg = vgpu_vreg(param->vgpu, offset);
67cea9083eSChangbin Du
68cea9083eSChangbin Du if (preg != vreg) {
69a291e4fbSColin Xu node = kmalloc(sizeof(*node), GFP_ATOMIC);
70cea9083eSChangbin Du if (!node)
71cea9083eSChangbin Du return -ENOMEM;
72cea9083eSChangbin Du
73cea9083eSChangbin Du node->offset = offset;
74cea9083eSChangbin Du node->preg = preg;
75cea9083eSChangbin Du node->vreg = vreg;
76cea9083eSChangbin Du list_add(&node->node, ¶m->diff_mmio_list);
77cea9083eSChangbin Du param->diff++;
78cea9083eSChangbin Du }
79cea9083eSChangbin Du param->total++;
80cea9083eSChangbin Du return 0;
81cea9083eSChangbin Du }
82cea9083eSChangbin Du
83cea9083eSChangbin Du /* Show the all the different values of tracked mmio. */
vgpu_mmio_diff_show(struct seq_file * s,void * unused)84cea9083eSChangbin Du static int vgpu_mmio_diff_show(struct seq_file *s, void *unused)
85cea9083eSChangbin Du {
86cea9083eSChangbin Du struct intel_vgpu *vgpu = s->private;
87cea9083eSChangbin Du struct intel_gvt *gvt = vgpu->gvt;
88cea9083eSChangbin Du struct mmio_diff_param param = {
89cea9083eSChangbin Du .vgpu = vgpu,
90cea9083eSChangbin Du .total = 0,
91cea9083eSChangbin Du .diff = 0,
92cea9083eSChangbin Du };
93cea9083eSChangbin Du struct diff_mmio *node, *next;
94cea9083eSChangbin Du
95cea9083eSChangbin Du INIT_LIST_HEAD(¶m.diff_mmio_list);
96cea9083eSChangbin Du
97cea9083eSChangbin Du mutex_lock(&gvt->lock);
98cea9083eSChangbin Du spin_lock_bh(&gvt->scheduler.mmio_context_lock);
99cea9083eSChangbin Du
100a61ac1e7SChris Wilson mmio_hw_access_pre(gvt->gt);
101cea9083eSChangbin Du /* Recognize all the diff mmios to list. */
102cea9083eSChangbin Du intel_gvt_for_each_tracked_mmio(gvt, mmio_diff_handler, ¶m);
103a61ac1e7SChris Wilson mmio_hw_access_post(gvt->gt);
104cea9083eSChangbin Du
105cea9083eSChangbin Du spin_unlock_bh(&gvt->scheduler.mmio_context_lock);
106cea9083eSChangbin Du mutex_unlock(&gvt->lock);
107cea9083eSChangbin Du
108cea9083eSChangbin Du /* In an ascending order by mmio offset. */
109cea9083eSChangbin Du list_sort(NULL, ¶m.diff_mmio_list, mmio_offset_compare);
110cea9083eSChangbin Du
111cea9083eSChangbin Du seq_printf(s, "%-8s %-8s %-8s %-8s\n", "Offset", "HW", "vGPU", "Diff");
112cea9083eSChangbin Du list_for_each_entry_safe(node, next, ¶m.diff_mmio_list, node) {
113cea9083eSChangbin Du u32 diff = node->preg ^ node->vreg;
114cea9083eSChangbin Du
115cea9083eSChangbin Du seq_printf(s, "%08x %08x %08x %*pbl\n",
116cea9083eSChangbin Du node->offset, node->preg, node->vreg,
117cea9083eSChangbin Du 32, &diff);
118cea9083eSChangbin Du list_del(&node->node);
119cea9083eSChangbin Du kfree(node);
120cea9083eSChangbin Du }
121cea9083eSChangbin Du seq_printf(s, "Total: %d, Diff: %d\n", param.total, param.diff);
122cea9083eSChangbin Du return 0;
123cea9083eSChangbin Du }
124e4006713SAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(vgpu_mmio_diff);
125bc7b0be3SChangbin Du
12696bebe39SZhao Yan static int
vgpu_scan_nonprivbb_get(void * data,u64 * val)12796bebe39SZhao Yan vgpu_scan_nonprivbb_get(void *data, u64 *val)
12896bebe39SZhao Yan {
12996bebe39SZhao Yan struct intel_vgpu *vgpu = (struct intel_vgpu *)data;
130aa444fc7SChris Wilson
13196bebe39SZhao Yan *val = vgpu->scan_nonprivbb;
13296bebe39SZhao Yan return 0;
13396bebe39SZhao Yan }
13496bebe39SZhao Yan
13596bebe39SZhao Yan /*
13696bebe39SZhao Yan * set/unset bit engine_id of vgpu->scan_nonprivbb to turn on/off scanning
13796bebe39SZhao Yan * of non-privileged batch buffer. e.g.
13896bebe39SZhao Yan * if vgpu->scan_nonprivbb=3, then it will scan non-privileged batch buffer
13996bebe39SZhao Yan * on engine 0 and 1.
14096bebe39SZhao Yan */
14196bebe39SZhao Yan static int
vgpu_scan_nonprivbb_set(void * data,u64 val)14296bebe39SZhao Yan vgpu_scan_nonprivbb_set(void *data, u64 val)
14396bebe39SZhao Yan {
14496bebe39SZhao Yan struct intel_vgpu *vgpu = (struct intel_vgpu *)data;
14596bebe39SZhao Yan
14696bebe39SZhao Yan vgpu->scan_nonprivbb = val;
14796bebe39SZhao Yan return 0;
14896bebe39SZhao Yan }
14996bebe39SZhao Yan
150*84edc94eSDeepak R Varma DEFINE_DEBUGFS_ATTRIBUTE(vgpu_scan_nonprivbb_fops,
15196bebe39SZhao Yan vgpu_scan_nonprivbb_get, vgpu_scan_nonprivbb_set,
15296bebe39SZhao Yan "0x%llx\n");
15396bebe39SZhao Yan
vgpu_status_get(void * data,u64 * val)154a06d4b9eSZhi Wang static int vgpu_status_get(void *data, u64 *val)
155a06d4b9eSZhi Wang {
156a06d4b9eSZhi Wang struct intel_vgpu *vgpu = (struct intel_vgpu *)data;
157a06d4b9eSZhi Wang
158a06d4b9eSZhi Wang *val = 0;
159a06d4b9eSZhi Wang
160a06d4b9eSZhi Wang if (test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status))
161a06d4b9eSZhi Wang *val |= (1 << INTEL_VGPU_STATUS_ATTACHED);
162a06d4b9eSZhi Wang if (test_bit(INTEL_VGPU_STATUS_ACTIVE, vgpu->status))
163a06d4b9eSZhi Wang *val |= (1 << INTEL_VGPU_STATUS_ACTIVE);
164a06d4b9eSZhi Wang
165a06d4b9eSZhi Wang return 0;
166a06d4b9eSZhi Wang }
167a06d4b9eSZhi Wang
168*84edc94eSDeepak R Varma DEFINE_DEBUGFS_ATTRIBUTE(vgpu_status_fops, vgpu_status_get, NULL, "0x%llx\n");
169a06d4b9eSZhi Wang
170bc7b0be3SChangbin Du /**
171bc7b0be3SChangbin Du * intel_gvt_debugfs_add_vgpu - register debugfs entries for a vGPU
172bc7b0be3SChangbin Du * @vgpu: a vGPU
173bc7b0be3SChangbin Du */
intel_gvt_debugfs_add_vgpu(struct intel_vgpu * vgpu)174f8871ec8SGreg Kroah-Hartman void intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu)
175bc7b0be3SChangbin Du {
1764feeea1dSAleksei Gimbitskii char name[16] = "";
177bc7b0be3SChangbin Du
1784feeea1dSAleksei Gimbitskii snprintf(name, 16, "vgpu%d", vgpu->id);
179bc7b0be3SChangbin Du vgpu->debugfs = debugfs_create_dir(name, vgpu->gvt->debugfs_root);
180bc7b0be3SChangbin Du
181f8871ec8SGreg Kroah-Hartman debugfs_create_file("mmio_diff", 0444, vgpu->debugfs, vgpu,
182f8871ec8SGreg Kroah-Hartman &vgpu_mmio_diff_fops);
183*84edc94eSDeepak R Varma debugfs_create_file_unsafe("scan_nonprivbb", 0644, vgpu->debugfs, vgpu,
184f8871ec8SGreg Kroah-Hartman &vgpu_scan_nonprivbb_fops);
185*84edc94eSDeepak R Varma debugfs_create_file_unsafe("status", 0644, vgpu->debugfs, vgpu,
186a06d4b9eSZhi Wang &vgpu_status_fops);
187bc7b0be3SChangbin Du }
188bc7b0be3SChangbin Du
189bc7b0be3SChangbin Du /**
190bc7b0be3SChangbin Du * intel_gvt_debugfs_remove_vgpu - remove debugfs entries of a vGPU
191bc7b0be3SChangbin Du * @vgpu: a vGPU
192bc7b0be3SChangbin Du */
intel_gvt_debugfs_remove_vgpu(struct intel_vgpu * vgpu)193bc7b0be3SChangbin Du void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu *vgpu)
194bc7b0be3SChangbin Du {
195704f3384SZhenyu Wang struct intel_gvt *gvt = vgpu->gvt;
196704f3384SZhenyu Wang struct drm_minor *minor = gvt->gt->i915->drm.primary;
197704f3384SZhenyu Wang
198704f3384SZhenyu Wang if (minor->debugfs_root && gvt->debugfs_root) {
199bc7b0be3SChangbin Du debugfs_remove_recursive(vgpu->debugfs);
200bc7b0be3SChangbin Du vgpu->debugfs = NULL;
201bc7b0be3SChangbin Du }
202704f3384SZhenyu Wang }
203bc7b0be3SChangbin Du
204bc7b0be3SChangbin Du /**
205bc7b0be3SChangbin Du * intel_gvt_debugfs_init - register gvt debugfs root entry
206bc7b0be3SChangbin Du * @gvt: GVT device
207bc7b0be3SChangbin Du */
intel_gvt_debugfs_init(struct intel_gvt * gvt)208f8871ec8SGreg Kroah-Hartman void intel_gvt_debugfs_init(struct intel_gvt *gvt)
209bc7b0be3SChangbin Du {
210a61ac1e7SChris Wilson struct drm_minor *minor = gvt->gt->i915->drm.primary;
211bc7b0be3SChangbin Du
212bc7b0be3SChangbin Du gvt->debugfs_root = debugfs_create_dir("gvt", minor->debugfs_root);
213bc7b0be3SChangbin Du
214f8871ec8SGreg Kroah-Hartman debugfs_create_ulong("num_tracked_mmio", 0444, gvt->debugfs_root,
215bc7b0be3SChangbin Du &gvt->mmio.num_tracked_mmio);
216bc7b0be3SChangbin Du }
217bc7b0be3SChangbin Du
218bc7b0be3SChangbin Du /**
219bc7b0be3SChangbin Du * intel_gvt_debugfs_clean - remove debugfs entries
220bc7b0be3SChangbin Du * @gvt: GVT device
221bc7b0be3SChangbin Du */
intel_gvt_debugfs_clean(struct intel_gvt * gvt)222bc7b0be3SChangbin Du void intel_gvt_debugfs_clean(struct intel_gvt *gvt)
223bc7b0be3SChangbin Du {
224c4b850d1SZhenyu Wang struct drm_minor *minor = gvt->gt->i915->drm.primary;
225c4b850d1SZhenyu Wang
226c4b850d1SZhenyu Wang if (minor->debugfs_root) {
227bc7b0be3SChangbin Du debugfs_remove_recursive(gvt->debugfs_root);
228bc7b0be3SChangbin Du gvt->debugfs_root = NULL;
229bc7b0be3SChangbin Du }
230c4b850d1SZhenyu Wang }
231