File Index
Files and directories
Sign in
FILE

xe_sriov_pf_debugfs.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/xe/xe_sriov_pf_debugfs.c C
  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}
~/ Read-only file preview.