xref: /linux/drivers/accel/amdxdna/amdxdna_debugfs.c (revision 0eaed89c18aeedf0898baf2dbf5ff027c6795152)
1*3cc5d7a5SMax Zhen // SPDX-License-Identifier: GPL-2.0
2*3cc5d7a5SMax Zhen /*
3*3cc5d7a5SMax Zhen  * Copyright (C) 2026, Advanced Micro Devices, Inc.
4*3cc5d7a5SMax Zhen  */
5*3cc5d7a5SMax Zhen 
6*3cc5d7a5SMax Zhen #include "amdxdna_cbuf.h"
7*3cc5d7a5SMax Zhen #include "amdxdna_debugfs.h"
8*3cc5d7a5SMax Zhen 
9*3cc5d7a5SMax Zhen #include <drm/drm_file.h>
10*3cc5d7a5SMax Zhen #include <linux/debugfs.h>
11*3cc5d7a5SMax Zhen #include <linux/pm_runtime.h>
12*3cc5d7a5SMax Zhen #include <linux/seq_file.h>
13*3cc5d7a5SMax Zhen #include <linux/string.h>
14*3cc5d7a5SMax Zhen #include <linux/uaccess.h>
15*3cc5d7a5SMax Zhen 
16*3cc5d7a5SMax Zhen #define _DBGFS_FOPS(_open, _release, _write) \
17*3cc5d7a5SMax Zhen { \
18*3cc5d7a5SMax Zhen 	.owner = THIS_MODULE, \
19*3cc5d7a5SMax Zhen 	.open = _open, \
20*3cc5d7a5SMax Zhen 	.read = seq_read, \
21*3cc5d7a5SMax Zhen 	.llseek = seq_lseek, \
22*3cc5d7a5SMax Zhen 	.release = _release, \
23*3cc5d7a5SMax Zhen 	.write = _write, \
24*3cc5d7a5SMax Zhen }
25*3cc5d7a5SMax Zhen 
26*3cc5d7a5SMax Zhen #define AMDXDNA_DBGFS_FOPS(_name, _show, _write) \
27*3cc5d7a5SMax Zhen 	static int amdxdna_dbgfs_##_name##_open(struct inode *inode, struct file *file) \
28*3cc5d7a5SMax Zhen 	{ \
29*3cc5d7a5SMax Zhen 		return single_open(file, _show, inode->i_private); \
30*3cc5d7a5SMax Zhen 	} \
31*3cc5d7a5SMax Zhen 	static int amdxdna_dbgfs_##_name##_release(struct inode *inode, struct file *file) \
32*3cc5d7a5SMax Zhen 	{ \
33*3cc5d7a5SMax Zhen 		return single_release(inode, file); \
34*3cc5d7a5SMax Zhen 	} \
35*3cc5d7a5SMax Zhen 	static const struct file_operations amdxdna_fops_##_name = \
36*3cc5d7a5SMax Zhen 		_DBGFS_FOPS(amdxdna_dbgfs_##_name##_open, amdxdna_dbgfs_##_name##_release, _write)
37*3cc5d7a5SMax Zhen 
38*3cc5d7a5SMax Zhen #define AMDXDNA_DBGFS_FILE(_name, _mode) { #_name, &amdxdna_fops_##_name, _mode }
39*3cc5d7a5SMax Zhen 
40*3cc5d7a5SMax Zhen #define file_to_xdna(file) (((struct seq_file *)(file)->private_data)->private)
41*3cc5d7a5SMax Zhen 
42*3cc5d7a5SMax Zhen static ssize_t amdxdna_carveout_write(struct file *file, const char __user *buf,
43*3cc5d7a5SMax Zhen 				      size_t count, loff_t *ppos)
44*3cc5d7a5SMax Zhen {
45*3cc5d7a5SMax Zhen 	struct amdxdna_dev *xdna = file_to_xdna(file);
46*3cc5d7a5SMax Zhen 	char kbuf[128];
47*3cc5d7a5SMax Zhen 	u64 size, addr;
48*3cc5d7a5SMax Zhen 	char *sep;
49*3cc5d7a5SMax Zhen 	int ret;
50*3cc5d7a5SMax Zhen 
51*3cc5d7a5SMax Zhen 	if (count == 0 || count >= sizeof(kbuf))
52*3cc5d7a5SMax Zhen 		return -EINVAL;
53*3cc5d7a5SMax Zhen 
54*3cc5d7a5SMax Zhen 	if (copy_from_user(kbuf, buf, count))
55*3cc5d7a5SMax Zhen 		return -EFAULT;
56*3cc5d7a5SMax Zhen 	kbuf[count] = '\0';
57*3cc5d7a5SMax Zhen 	strim(kbuf);
58*3cc5d7a5SMax Zhen 	XDNA_DBG(xdna, "Trying to set carveout to %s", kbuf);
59*3cc5d7a5SMax Zhen 
60*3cc5d7a5SMax Zhen 	sep = strchr(kbuf, '@');
61*3cc5d7a5SMax Zhen 	if (!sep)
62*3cc5d7a5SMax Zhen 		return -EINVAL;
63*3cc5d7a5SMax Zhen 	*sep = '\0';
64*3cc5d7a5SMax Zhen 	sep++;
65*3cc5d7a5SMax Zhen 
66*3cc5d7a5SMax Zhen 	ret = kstrtou64(kbuf, 0, &size);
67*3cc5d7a5SMax Zhen 	if (ret)
68*3cc5d7a5SMax Zhen 		return ret;
69*3cc5d7a5SMax Zhen 
70*3cc5d7a5SMax Zhen 	ret = kstrtou64(sep, 0, &addr);
71*3cc5d7a5SMax Zhen 	if (ret)
72*3cc5d7a5SMax Zhen 		return ret;
73*3cc5d7a5SMax Zhen 
74*3cc5d7a5SMax Zhen 	/* Sanity check the addr and size. */
75*3cc5d7a5SMax Zhen 	if (!size)
76*3cc5d7a5SMax Zhen 		return -EINVAL;
77*3cc5d7a5SMax Zhen 	if (!IS_ALIGNED(addr, PAGE_SIZE) || !IS_ALIGNED(size, PAGE_SIZE))
78*3cc5d7a5SMax Zhen 		return -EINVAL;
79*3cc5d7a5SMax Zhen 
80*3cc5d7a5SMax Zhen 	guard(mutex)(&xdna->dev_lock);
81*3cc5d7a5SMax Zhen 
82*3cc5d7a5SMax Zhen 	ret = amdxdna_carveout_init(xdna, addr, size);
83*3cc5d7a5SMax Zhen 	if (ret)
84*3cc5d7a5SMax Zhen 		return ret;
85*3cc5d7a5SMax Zhen 
86*3cc5d7a5SMax Zhen 	return count;
87*3cc5d7a5SMax Zhen }
88*3cc5d7a5SMax Zhen 
89*3cc5d7a5SMax Zhen static int amdxdna_carveout_show(struct seq_file *m, void *unused)
90*3cc5d7a5SMax Zhen {
91*3cc5d7a5SMax Zhen 	struct amdxdna_dev *xdna = m->private;
92*3cc5d7a5SMax Zhen 	u64 addr, size;
93*3cc5d7a5SMax Zhen 
94*3cc5d7a5SMax Zhen 	guard(mutex)(&xdna->dev_lock);
95*3cc5d7a5SMax Zhen 	amdxdna_get_carveout_conf(xdna, &addr, &size);
96*3cc5d7a5SMax Zhen 	seq_printf(m, "0x%llx@0x%llx\n", size, addr);
97*3cc5d7a5SMax Zhen 	return 0;
98*3cc5d7a5SMax Zhen }
99*3cc5d7a5SMax Zhen 
100*3cc5d7a5SMax Zhen /*
101*3cc5d7a5SMax Zhen  * Input/output format: <carveout_size>@<carveout_address>
102*3cc5d7a5SMax Zhen  */
103*3cc5d7a5SMax Zhen AMDXDNA_DBGFS_FOPS(carveout, amdxdna_carveout_show, amdxdna_carveout_write);
104*3cc5d7a5SMax Zhen 
105*3cc5d7a5SMax Zhen static const struct {
106*3cc5d7a5SMax Zhen 	const char *name;
107*3cc5d7a5SMax Zhen 	const struct file_operations *fops;
108*3cc5d7a5SMax Zhen 	umode_t mode;
109*3cc5d7a5SMax Zhen } amdxdna_dbgfs_files[] = {
110*3cc5d7a5SMax Zhen 	AMDXDNA_DBGFS_FILE(carveout, 0600),
111*3cc5d7a5SMax Zhen };
112*3cc5d7a5SMax Zhen 
113*3cc5d7a5SMax Zhen void amdxdna_debugfs_init(struct amdxdna_dev *xdna)
114*3cc5d7a5SMax Zhen {
115*3cc5d7a5SMax Zhen 	struct drm_minor *minor = xdna->ddev.accel;
116*3cc5d7a5SMax Zhen 	int i;
117*3cc5d7a5SMax Zhen 
118*3cc5d7a5SMax Zhen 	/*
119*3cc5d7a5SMax Zhen 	 * It should be okay that debugfs fails to init.
120*3cc5d7a5SMax Zhen 	 * We rely on DRM framework to finish debugfs.
121*3cc5d7a5SMax Zhen 	 */
122*3cc5d7a5SMax Zhen 	for (i = 0; i < ARRAY_SIZE(amdxdna_dbgfs_files); i++) {
123*3cc5d7a5SMax Zhen 		debugfs_create_file(amdxdna_dbgfs_files[i].name,
124*3cc5d7a5SMax Zhen 				    amdxdna_dbgfs_files[i].mode,
125*3cc5d7a5SMax Zhen 				    minor->debugfs_root,
126*3cc5d7a5SMax Zhen 				    xdna,
127*3cc5d7a5SMax Zhen 				    amdxdna_dbgfs_files[i].fops);
128*3cc5d7a5SMax Zhen 	}
129*3cc5d7a5SMax Zhen }
130