xref: /linux/drivers/gpu/drm/xe/xe_sriov_pf_debugfs.c (revision f6e8dc9edf963dbc99085e54f6ced6da9daa6100)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2025 Intel Corporation
4  */
5 
6 #include <linux/debugfs.h>
7 #include <drm/drm_debugfs.h>
8 
9 #include "xe_device.h"
10 #include "xe_device_types.h"
11 #include "xe_pm.h"
12 #include "xe_sriov_pf.h"
13 #include "xe_sriov_pf_control.h"
14 #include "xe_sriov_pf_debugfs.h"
15 #include "xe_sriov_pf_helpers.h"
16 #include "xe_sriov_pf_provision.h"
17 #include "xe_sriov_pf_service.h"
18 #include "xe_sriov_printk.h"
19 #include "xe_tile_sriov_pf_debugfs.h"
20 
21 /*
22  *      /sys/kernel/debug/dri/BDF/
23  *      ├── sriov		# d_inode->i_private = (xe_device*)
24  *      │   ├── pf		# d_inode->i_private = (xe_device*)
25  *      │   ├── vf1		# d_inode->i_private = VFID(1)
26  *      :   :
27  *      │   ├── vfN		# d_inode->i_private = VFID(N)
28  */
29 
30 static void *extract_priv(struct dentry *d)
31 {
32 	return d->d_inode->i_private;
33 }
34 
35 static struct xe_device *extract_xe(struct dentry *d)
36 {
37 	return extract_priv(d->d_parent);
38 }
39 
40 static unsigned int extract_vfid(struct dentry *d)
41 {
42 	void *p = extract_priv(d);
43 
44 	return p == extract_xe(d) ? PFID : (uintptr_t)p;
45 }
46 
47 /*
48  *      /sys/kernel/debug/dri/BDF/
49  *      ├── sriov
50  *      │   ├── restore_auto_provisioning
51  *      │   :
52  *      │   ├── pf/
53  *      │   ├── vf1
54  *      │   │   ├── ...
55  */
56 
57 static ssize_t from_file_write_to_xe_call(struct file *file, const char __user *userbuf,
58 					  size_t count, loff_t *ppos,
59 					  int (*call)(struct xe_device *))
60 {
61 	struct dentry *dent = file_dentry(file);
62 	struct xe_device *xe = extract_xe(dent);
63 	bool yes;
64 	int ret;
65 
66 	if (*ppos)
67 		return -EINVAL;
68 	ret = kstrtobool_from_user(userbuf, count, &yes);
69 	if (ret < 0)
70 		return ret;
71 	if (yes) {
72 		xe_pm_runtime_get(xe);
73 		ret = call(xe);
74 		xe_pm_runtime_put(xe);
75 	}
76 	if (ret < 0)
77 		return ret;
78 	return count;
79 }
80 
81 #define DEFINE_SRIOV_ATTRIBUTE(OP)						\
82 static int OP##_show(struct seq_file *s, void *unused)				\
83 {										\
84 	return 0;								\
85 }										\
86 static ssize_t OP##_write(struct file *file, const char __user *userbuf,	\
87 			  size_t count, loff_t *ppos)				\
88 {										\
89 	return from_file_write_to_xe_call(file, userbuf, count, ppos,		\
90 					  xe_sriov_pf_##OP);			\
91 }										\
92 DEFINE_SHOW_STORE_ATTRIBUTE(OP)
93 
94 static inline int xe_sriov_pf_restore_auto_provisioning(struct xe_device *xe)
95 {
96 	return xe_sriov_pf_provision_set_mode(xe, XE_SRIOV_PROVISIONING_MODE_AUTO);
97 }
98 
99 DEFINE_SRIOV_ATTRIBUTE(restore_auto_provisioning);
100 
101 static void pf_populate_root(struct xe_device *xe, struct dentry *dent)
102 {
103 	debugfs_create_file("restore_auto_provisioning", 0200, dent, xe,
104 			    &restore_auto_provisioning_fops);
105 }
106 
107 static int simple_show(struct seq_file *m, void *data)
108 {
109 	struct drm_printer p = drm_seq_file_printer(m);
110 	struct drm_info_node *node = m->private;
111 	struct dentry *parent = node->dent->d_parent;
112 	struct xe_device *xe = parent->d_inode->i_private;
113 	void (*print)(struct xe_device *, struct drm_printer *) = node->info_ent->data;
114 
115 	print(xe, &p);
116 	return 0;
117 }
118 
119 static const struct drm_info_list debugfs_list[] = {
120 	{ .name = "vfs", .show = simple_show, .data = xe_sriov_pf_print_vfs_summary },
121 	{ .name = "versions", .show = simple_show, .data = xe_sriov_pf_service_print_versions },
122 };
123 
124 static void pf_populate_pf(struct xe_device *xe, struct dentry *pfdent)
125 {
126 	struct drm_minor *minor = xe->drm.primary;
127 
128 	drm_debugfs_create_files(debugfs_list, ARRAY_SIZE(debugfs_list), pfdent, minor);
129 }
130 
131 /*
132  *      /sys/kernel/debug/dri/BDF/
133  *      ├── sriov
134  *      │   ├── vf1
135  *      │   │   ├── pause
136  *      │   │   ├── reset
137  *      │   │   ├── resume
138  *      │   │   ├── stop
139  *      │   │   :
140  *      │   ├── vf2
141  *      │   │   ├── ...
142  */
143 
144 static ssize_t from_file_write_to_vf_call(struct file *file, const char __user *userbuf,
145 					  size_t count, loff_t *ppos,
146 					  int (*call)(struct xe_device *, unsigned int))
147 {
148 	struct dentry *dent = file_dentry(file)->d_parent;
149 	struct xe_device *xe = extract_xe(dent);
150 	unsigned int vfid = extract_vfid(dent);
151 	bool yes;
152 	int ret;
153 
154 	if (*ppos)
155 		return -EINVAL;
156 	ret = kstrtobool_from_user(userbuf, count, &yes);
157 	if (ret < 0)
158 		return ret;
159 	if (yes) {
160 		xe_pm_runtime_get(xe);
161 		ret = call(xe, vfid);
162 		xe_pm_runtime_put(xe);
163 	}
164 	if (ret < 0)
165 		return ret;
166 	return count;
167 }
168 
169 #define DEFINE_VF_CONTROL_ATTRIBUTE(OP)						\
170 static int OP##_show(struct seq_file *s, void *unused)				\
171 {										\
172 	return 0;								\
173 }										\
174 static ssize_t OP##_write(struct file *file, const char __user *userbuf,	\
175 			  size_t count, loff_t *ppos)				\
176 {										\
177 	return from_file_write_to_vf_call(file, userbuf, count, ppos,		\
178 					  xe_sriov_pf_control_##OP);		\
179 }										\
180 DEFINE_SHOW_STORE_ATTRIBUTE(OP)
181 
182 DEFINE_VF_CONTROL_ATTRIBUTE(pause_vf);
183 DEFINE_VF_CONTROL_ATTRIBUTE(resume_vf);
184 DEFINE_VF_CONTROL_ATTRIBUTE(stop_vf);
185 DEFINE_VF_CONTROL_ATTRIBUTE(reset_vf);
186 
187 static void pf_populate_vf(struct xe_device *xe, struct dentry *vfdent)
188 {
189 	debugfs_create_file("pause", 0200, vfdent, xe, &pause_vf_fops);
190 	debugfs_create_file("resume", 0200, vfdent, xe, &resume_vf_fops);
191 	debugfs_create_file("stop", 0200, vfdent, xe, &stop_vf_fops);
192 	debugfs_create_file("reset", 0200, vfdent, xe, &reset_vf_fops);
193 }
194 
195 static void pf_populate_with_tiles(struct xe_device *xe, struct dentry *dent, unsigned int vfid)
196 {
197 	struct xe_tile *tile;
198 	unsigned int id;
199 
200 	for_each_tile(tile, xe, id)
201 		xe_tile_sriov_pf_debugfs_populate(tile, dent, vfid);
202 }
203 
204 /**
205  * xe_sriov_pf_debugfs_register - Register PF debugfs attributes.
206  * @xe: the &xe_device
207  * @root: the root &dentry
208  *
209  * Create separate directory that will contain all SR-IOV related files,
210  * organized per each SR-IOV function (PF, VF1, VF2, ..., VFn).
211  */
212 void xe_sriov_pf_debugfs_register(struct xe_device *xe, struct dentry *root)
213 {
214 	int totalvfs = xe_sriov_pf_get_totalvfs(xe);
215 	struct dentry *pfdent;
216 	struct dentry *vfdent;
217 	struct dentry *dent;
218 	char vfname[16]; /* should be more than enough for "vf%u\0" and VFID(UINT_MAX) */
219 	unsigned int n;
220 
221 	/*
222 	 *      /sys/kernel/debug/dri/BDF/
223 	 *      ├── sriov		# d_inode->i_private = (xe_device*)
224 	 *      │   ├── ...
225 	 */
226 	dent = debugfs_create_dir("sriov", root);
227 	if (IS_ERR(dent))
228 		return;
229 	dent->d_inode->i_private = xe;
230 
231 	pf_populate_root(xe, dent);
232 
233 	/*
234 	 *      /sys/kernel/debug/dri/BDF/
235 	 *      ├── sriov		# d_inode->i_private = (xe_device*)
236 	 *      │   ├── pf		# d_inode->i_private = (xe_device*)
237 	 *      │   │   ├── ...
238 	 */
239 	pfdent = debugfs_create_dir("pf", dent);
240 	if (IS_ERR(pfdent))
241 		return;
242 	pfdent->d_inode->i_private = xe;
243 
244 	pf_populate_pf(xe, pfdent);
245 	pf_populate_with_tiles(xe, pfdent, PFID);
246 
247 	/*
248 	 *      /sys/kernel/debug/dri/BDF/
249 	 *      ├── sriov		# d_inode->i_private = (xe_device*)
250 	 *      │   ├── vf1		# d_inode->i_private = VFID(1)
251 	 *      │   ├── vf2		# d_inode->i_private = VFID(2)
252 	 *      │   ├── ...
253 	 */
254 	for (n = 1; n <= totalvfs; n++) {
255 		snprintf(vfname, sizeof(vfname), "vf%u", VFID(n));
256 		vfdent = debugfs_create_dir(vfname, dent);
257 		if (IS_ERR(vfdent))
258 			return;
259 		vfdent->d_inode->i_private = (void *)(uintptr_t)VFID(n);
260 
261 		pf_populate_vf(xe, vfdent);
262 		pf_populate_with_tiles(xe, vfdent, VFID(n));
263 	}
264 }
265