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