xref: /linux/drivers/gpu/drm/xe/xe_sriov_pf_debugfs.c (revision ca220141fa8ebae09765a242076b2b77338106b0)
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_migration.h"
17 #include "xe_sriov_pf_provision.h"
18 #include "xe_sriov_pf_service.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 		guard(xe_pm_runtime)(xe);
73 		ret = call(xe);
74 	}
75 	if (ret < 0)
76 		return ret;
77 	return count;
78 }
79 
80 #define DEFINE_SRIOV_ATTRIBUTE(OP)						\
81 static int OP##_show(struct seq_file *s, void *unused)				\
82 {										\
83 	return 0;								\
84 }										\
85 static ssize_t OP##_write(struct file *file, const char __user *userbuf,	\
86 			  size_t count, loff_t *ppos)				\
87 {										\
88 	return from_file_write_to_xe_call(file, userbuf, count, ppos,		\
89 					  xe_sriov_pf_##OP);			\
90 }										\
91 DEFINE_SHOW_STORE_ATTRIBUTE(OP)
92 
93 static inline int xe_sriov_pf_restore_auto_provisioning(struct xe_device *xe)
94 {
95 	return xe_sriov_pf_provision_set_mode(xe, XE_SRIOV_PROVISIONING_MODE_AUTO);
96 }
97 
98 DEFINE_SRIOV_ATTRIBUTE(restore_auto_provisioning);
99 
100 static int lockdown_vfs_enabling_open(struct inode *inode, struct file *file)
101 {
102 	struct dentry *dent = file_dentry(file);
103 	struct xe_device *xe = extract_xe(dent);
104 	ssize_t ret;
105 
106 	ret = xe_sriov_pf_lockdown(xe);
107 	if (ret < 0)
108 		return ret;
109 
110 	file->private_data = xe;
111 	return nonseekable_open(inode, file);
112 }
113 
114 static int lockdown_vfs_enabling_release(struct inode *inode, struct file *file)
115 {
116 	struct xe_device *xe = file->private_data;
117 
118 	xe_sriov_pf_end_lockdown(xe);
119 	return 0;
120 }
121 
122 static const struct file_operations lockdown_vfs_enabling_fops = {
123 	.owner		= THIS_MODULE,
124 	.open		= lockdown_vfs_enabling_open,
125 	.release	= lockdown_vfs_enabling_release,
126 };
127 
128 static void pf_populate_root(struct xe_device *xe, struct dentry *dent)
129 {
130 	debugfs_create_file("restore_auto_provisioning", 0200, dent, xe,
131 			    &restore_auto_provisioning_fops);
132 	debugfs_create_file("lockdown_vfs_enabling", 0400, dent, xe,
133 			    &lockdown_vfs_enabling_fops);
134 }
135 
136 static int simple_show(struct seq_file *m, void *data)
137 {
138 	struct drm_printer p = drm_seq_file_printer(m);
139 	struct drm_info_node *node = m->private;
140 	struct dentry *parent = node->dent->d_parent;
141 	struct xe_device *xe = parent->d_inode->i_private;
142 	void (*print)(struct xe_device *, struct drm_printer *) = node->info_ent->data;
143 
144 	print(xe, &p);
145 	return 0;
146 }
147 
148 static const struct drm_info_list debugfs_list[] = {
149 	{ .name = "vfs", .show = simple_show, .data = xe_sriov_pf_print_vfs_summary },
150 	{ .name = "versions", .show = simple_show, .data = xe_sriov_pf_service_print_versions },
151 };
152 
153 static void pf_populate_pf(struct xe_device *xe, struct dentry *pfdent)
154 {
155 	struct drm_minor *minor = xe->drm.primary;
156 
157 	drm_debugfs_create_files(debugfs_list, ARRAY_SIZE(debugfs_list), pfdent, minor);
158 }
159 
160 /*
161  *      /sys/kernel/debug/dri/BDF/
162  *      ├── sriov
163  *      │   ├── vf1
164  *      │   │   ├── migration_data
165  *      │   │   ├── pause
166  *      │   │   ├── reset
167  *      │   │   ├── resume
168  *      │   │   ├── stop
169  *      │   │   ├── save
170  *      │   │   ├── restore
171  *      │   │   :
172  *      │   ├── vf2
173  *      │   │   ├── ...
174  */
175 
176 static int from_file_read_to_vf_call(struct seq_file *s,
177 				     int (*call)(struct xe_device *, unsigned int))
178 {
179 	struct dentry *dent = file_dentry(s->file)->d_parent;
180 	struct xe_device *xe = extract_xe(dent);
181 	unsigned int vfid = extract_vfid(dent);
182 	int ret;
183 
184 	xe_pm_runtime_get(xe);
185 	ret = call(xe, vfid);
186 	xe_pm_runtime_put(xe);
187 
188 	if (ret < 0)
189 		return ret;
190 
191 	return 0;
192 }
193 
194 static ssize_t from_file_write_to_vf_call(struct file *file, const char __user *userbuf,
195 					  size_t count, loff_t *ppos,
196 					  int (*call)(struct xe_device *, unsigned int))
197 {
198 	struct dentry *dent = file_dentry(file)->d_parent;
199 	struct xe_device *xe = extract_xe(dent);
200 	unsigned int vfid = extract_vfid(dent);
201 	bool yes;
202 	int ret;
203 
204 	if (*ppos)
205 		return -EINVAL;
206 	ret = kstrtobool_from_user(userbuf, count, &yes);
207 	if (ret < 0)
208 		return ret;
209 	if (yes) {
210 		guard(xe_pm_runtime)(xe);
211 		ret = call(xe, vfid);
212 	}
213 	if (ret < 0)
214 		return ret;
215 	return count;
216 }
217 
218 #define DEFINE_VF_CONTROL_ATTRIBUTE(OP)						\
219 static int OP##_show(struct seq_file *s, void *unused)				\
220 {										\
221 	return 0;								\
222 }										\
223 static ssize_t OP##_write(struct file *file, const char __user *userbuf,	\
224 			  size_t count, loff_t *ppos)				\
225 {										\
226 	return from_file_write_to_vf_call(file, userbuf, count, ppos,		\
227 					  xe_sriov_pf_control_##OP);		\
228 }										\
229 DEFINE_SHOW_STORE_ATTRIBUTE(OP)
230 
231 #define DEFINE_VF_CONTROL_ATTRIBUTE_RW(OP)					\
232 static int OP##_show(struct seq_file *s, void *unused)				\
233 {										\
234 	return from_file_read_to_vf_call(s,					\
235 					 xe_sriov_pf_control_finish_##OP);	\
236 }										\
237 static ssize_t OP##_write(struct file *file, const char __user *userbuf,	\
238 			  size_t count, loff_t *ppos)				\
239 {										\
240 	return from_file_write_to_vf_call(file, userbuf, count, ppos,		\
241 					  xe_sriov_pf_control_trigger_##OP);	\
242 }										\
243 DEFINE_SHOW_STORE_ATTRIBUTE(OP)
244 
245 DEFINE_VF_CONTROL_ATTRIBUTE(pause_vf);
246 DEFINE_VF_CONTROL_ATTRIBUTE(resume_vf);
247 DEFINE_VF_CONTROL_ATTRIBUTE(stop_vf);
248 DEFINE_VF_CONTROL_ATTRIBUTE(reset_vf);
249 DEFINE_VF_CONTROL_ATTRIBUTE_RW(save_vf);
250 DEFINE_VF_CONTROL_ATTRIBUTE_RW(restore_vf);
251 
252 static ssize_t data_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
253 {
254 	struct dentry *dent = file_dentry(file)->d_parent;
255 	struct xe_device *xe = extract_xe(dent);
256 	unsigned int vfid = extract_vfid(dent);
257 
258 	if (*pos)
259 		return -ESPIPE;
260 
261 	return xe_sriov_pf_migration_write(xe, vfid, buf, count);
262 }
263 
264 static ssize_t data_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
265 {
266 	struct dentry *dent = file_dentry(file)->d_parent;
267 	struct xe_device *xe = extract_xe(dent);
268 	unsigned int vfid = extract_vfid(dent);
269 
270 	if (*ppos)
271 		return -ESPIPE;
272 
273 	return xe_sriov_pf_migration_read(xe, vfid, buf, count);
274 }
275 
276 static const struct file_operations data_vf_fops = {
277 	.owner		= THIS_MODULE,
278 	.open		= simple_open,
279 	.write		= data_write,
280 	.read		= data_read,
281 	.llseek		= default_llseek,
282 };
283 
284 static ssize_t size_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos)
285 {
286 	struct dentry *dent = file_dentry(file)->d_parent;
287 	struct xe_device *xe = extract_xe(dent);
288 	unsigned int vfid = extract_vfid(dent);
289 	char buf[21];
290 	ssize_t ret;
291 	int len;
292 
293 	xe_pm_runtime_get(xe);
294 	ret = xe_sriov_pf_migration_size(xe, vfid);
295 	xe_pm_runtime_put(xe);
296 	if (ret < 0)
297 		return ret;
298 
299 	len = scnprintf(buf, sizeof(buf), "%zd\n", ret);
300 
301 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
302 }
303 
304 static const struct file_operations size_vf_fops = {
305 	.owner		= THIS_MODULE,
306 	.open		= simple_open,
307 	.read		= size_read,
308 	.llseek		= default_llseek,
309 };
310 
311 static void pf_populate_vf(struct xe_device *xe, struct dentry *vfdent)
312 {
313 	debugfs_create_file("pause", 0200, vfdent, xe, &pause_vf_fops);
314 	debugfs_create_file("resume", 0200, vfdent, xe, &resume_vf_fops);
315 	debugfs_create_file("stop", 0200, vfdent, xe, &stop_vf_fops);
316 	debugfs_create_file("reset", 0200, vfdent, xe, &reset_vf_fops);
317 	debugfs_create_file("save", 0600, vfdent, xe, &save_vf_fops);
318 	debugfs_create_file("restore", 0600, vfdent, xe, &restore_vf_fops);
319 	debugfs_create_file("migration_data", 0600, vfdent, xe, &data_vf_fops);
320 	debugfs_create_file("migration_size", 0400, vfdent, xe, &size_vf_fops);
321 }
322 
323 static void pf_populate_with_tiles(struct xe_device *xe, struct dentry *dent, unsigned int vfid)
324 {
325 	struct xe_tile *tile;
326 	unsigned int id;
327 
328 	for_each_tile(tile, xe, id)
329 		xe_tile_sriov_pf_debugfs_populate(tile, dent, vfid);
330 }
331 
332 /**
333  * xe_sriov_pf_debugfs_register - Register PF debugfs attributes.
334  * @xe: the &xe_device
335  * @root: the root &dentry
336  *
337  * Create separate directory that will contain all SR-IOV related files,
338  * organized per each SR-IOV function (PF, VF1, VF2, ..., VFn).
339  */
340 void xe_sriov_pf_debugfs_register(struct xe_device *xe, struct dentry *root)
341 {
342 	int totalvfs = xe_sriov_pf_get_totalvfs(xe);
343 	struct dentry *pfdent;
344 	struct dentry *vfdent;
345 	struct dentry *dent;
346 	char vfname[16]; /* should be more than enough for "vf%u\0" and VFID(UINT_MAX) */
347 	unsigned int n;
348 
349 	/*
350 	 *      /sys/kernel/debug/dri/BDF/
351 	 *      ├── sriov		# d_inode->i_private = (xe_device*)
352 	 *      │   ├── ...
353 	 */
354 	dent = debugfs_create_dir("sriov", root);
355 	if (IS_ERR(dent))
356 		return;
357 	dent->d_inode->i_private = xe;
358 
359 	pf_populate_root(xe, dent);
360 
361 	/*
362 	 *      /sys/kernel/debug/dri/BDF/
363 	 *      ├── sriov		# d_inode->i_private = (xe_device*)
364 	 *      │   ├── pf		# d_inode->i_private = (xe_device*)
365 	 *      │   │   ├── ...
366 	 */
367 	pfdent = debugfs_create_dir("pf", dent);
368 	if (IS_ERR(pfdent))
369 		return;
370 	pfdent->d_inode->i_private = xe;
371 
372 	pf_populate_pf(xe, pfdent);
373 	pf_populate_with_tiles(xe, pfdent, PFID);
374 
375 	/*
376 	 *      /sys/kernel/debug/dri/BDF/
377 	 *      ├── sriov		# d_inode->i_private = (xe_device*)
378 	 *      │   ├── vf1		# d_inode->i_private = VFID(1)
379 	 *      │   ├── vf2		# d_inode->i_private = VFID(2)
380 	 *      │   ├── ...
381 	 */
382 	for (n = 1; n <= totalvfs; n++) {
383 		snprintf(vfname, sizeof(vfname), "vf%u", VFID(n));
384 		vfdent = debugfs_create_dir(vfname, dent);
385 		if (IS_ERR(vfdent))
386 			return;
387 		vfdent->d_inode->i_private = (void *)(uintptr_t)VFID(n);
388 
389 		pf_populate_vf(xe, vfdent);
390 		pf_populate_with_tiles(xe, vfdent, VFID(n));
391 	}
392 }
393