2 * Copyright(c) 2011-2017 Intel Corporation. All rights reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 #include <linux/debugfs.h>
24 #include <linux/list_sort.h>
28 struct mmio_diff_param
{
29 struct intel_vgpu
*vgpu
;
32 struct list_head diff_mmio_list
;
36 struct list_head node
;
42 /* Compare two diff_mmio items. */
43 static int mmio_offset_compare(void *priv
,
44 struct list_head
*a
, struct list_head
*b
)
49 ma
= container_of(a
, struct diff_mmio
, node
);
50 mb
= container_of(b
, struct diff_mmio
, node
);
51 if (ma
->offset
< mb
->offset
)
53 else if (ma
->offset
> mb
->offset
)
58 static inline int mmio_diff_handler(struct intel_gvt
*gvt
,
59 u32 offset
, void *data
)
61 struct drm_i915_private
*i915
= gvt
->dev_priv
;
62 struct mmio_diff_param
*param
= data
;
63 struct diff_mmio
*node
;
66 preg
= intel_uncore_read_notrace(&i915
->uncore
, _MMIO(offset
));
67 vreg
= vgpu_vreg(param
->vgpu
, offset
);
70 node
= kmalloc(sizeof(*node
), GFP_KERNEL
);
74 node
->offset
= offset
;
77 list_add(&node
->node
, ¶m
->diff_mmio_list
);
84 /* Show the all the different values of tracked mmio. */
85 static int vgpu_mmio_diff_show(struct seq_file
*s
, void *unused
)
87 struct intel_vgpu
*vgpu
= s
->private;
88 struct intel_gvt
*gvt
= vgpu
->gvt
;
89 struct mmio_diff_param param
= {
94 struct diff_mmio
*node
, *next
;
96 INIT_LIST_HEAD(¶m
.diff_mmio_list
);
98 mutex_lock(&gvt
->lock
);
99 spin_lock_bh(&gvt
->scheduler
.mmio_context_lock
);
101 mmio_hw_access_pre(gvt
->dev_priv
);
102 /* Recognize all the diff mmios to list. */
103 intel_gvt_for_each_tracked_mmio(gvt
, mmio_diff_handler
, ¶m
);
104 mmio_hw_access_post(gvt
->dev_priv
);
106 spin_unlock_bh(&gvt
->scheduler
.mmio_context_lock
);
107 mutex_unlock(&gvt
->lock
);
109 /* In an ascending order by mmio offset. */
110 list_sort(NULL
, ¶m
.diff_mmio_list
, mmio_offset_compare
);
112 seq_printf(s
, "%-8s %-8s %-8s %-8s\n", "Offset", "HW", "vGPU", "Diff");
113 list_for_each_entry_safe(node
, next
, ¶m
.diff_mmio_list
, node
) {
114 u32 diff
= node
->preg
^ node
->vreg
;
116 seq_printf(s
, "%08x %08x %08x %*pbl\n",
117 node
->offset
, node
->preg
, node
->vreg
,
119 list_del(&node
->node
);
122 seq_printf(s
, "Total: %d, Diff: %d\n", param
.total
, param
.diff
);
125 DEFINE_SHOW_ATTRIBUTE(vgpu_mmio_diff
);
128 vgpu_scan_nonprivbb_get(void *data
, u64
*val
)
130 struct intel_vgpu
*vgpu
= (struct intel_vgpu
*)data
;
131 *val
= vgpu
->scan_nonprivbb
;
136 * set/unset bit engine_id of vgpu->scan_nonprivbb to turn on/off scanning
137 * of non-privileged batch buffer. e.g.
138 * if vgpu->scan_nonprivbb=3, then it will scan non-privileged batch buffer
142 vgpu_scan_nonprivbb_set(void *data
, u64 val
)
144 struct intel_vgpu
*vgpu
= (struct intel_vgpu
*)data
;
145 struct drm_i915_private
*dev_priv
= vgpu
->gvt
->dev_priv
;
146 enum intel_engine_id id
;
150 val
&= (1 << I915_NUM_ENGINES
) - 1;
152 if (vgpu
->scan_nonprivbb
== val
)
159 "gvt: vgpu %d turns on non-privileged batch buffers scanning on Engines:",
164 for (id
= 0; id
< I915_NUM_ENGINES
; id
++) {
165 struct intel_engine_cs
*engine
;
167 engine
= dev_priv
->engine
[id
];
168 if (engine
&& (val
& (1 << id
))) {
169 len
= snprintf(s
, 4, "%d, ", engine
->id
);
176 sprintf(s
, "low performance expected.");
178 pr_warn("%s\n", buf
);
181 vgpu
->scan_nonprivbb
= val
;
185 DEFINE_SIMPLE_ATTRIBUTE(vgpu_scan_nonprivbb_fops
,
186 vgpu_scan_nonprivbb_get
, vgpu_scan_nonprivbb_set
,
190 * intel_gvt_debugfs_add_vgpu - register debugfs entries for a vGPU
193 void intel_gvt_debugfs_add_vgpu(struct intel_vgpu
*vgpu
)
197 snprintf(name
, 16, "vgpu%d", vgpu
->id
);
198 vgpu
->debugfs
= debugfs_create_dir(name
, vgpu
->gvt
->debugfs_root
);
200 debugfs_create_bool("active", 0444, vgpu
->debugfs
, &vgpu
->active
);
201 debugfs_create_file("mmio_diff", 0444, vgpu
->debugfs
, vgpu
,
202 &vgpu_mmio_diff_fops
);
203 debugfs_create_file("scan_nonprivbb", 0644, vgpu
->debugfs
, vgpu
,
204 &vgpu_scan_nonprivbb_fops
);
208 * intel_gvt_debugfs_remove_vgpu - remove debugfs entries of a vGPU
211 void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu
*vgpu
)
213 debugfs_remove_recursive(vgpu
->debugfs
);
214 vgpu
->debugfs
= NULL
;
218 * intel_gvt_debugfs_init - register gvt debugfs root entry
221 void intel_gvt_debugfs_init(struct intel_gvt
*gvt
)
223 struct drm_minor
*minor
= gvt
->dev_priv
->drm
.primary
;
225 gvt
->debugfs_root
= debugfs_create_dir("gvt", minor
->debugfs_root
);
227 debugfs_create_ulong("num_tracked_mmio", 0444, gvt
->debugfs_root
,
228 &gvt
->mmio
.num_tracked_mmio
);
232 * intel_gvt_debugfs_clean - remove debugfs entries
235 void intel_gvt_debugfs_clean(struct intel_gvt
*gvt
)
237 debugfs_remove_recursive(gvt
->debugfs_root
);
238 gvt
->debugfs_root
= NULL
;