1// SPDX-License-Identifier: MIT
2/*
3 * Copyright �� 2019 Intel Corporation
4 */
5
6#include <linux/kernel.h>
7
8#include "i915_debugfs_params.h"
9#include "gt/intel_gt.h"
10#include "gt/uc/intel_guc.h"
11#include "i915_drv.h"
12#include "i915_params.h"
13
14#define MATCH_DEBUGFS_NODE_NAME(_file, _name) \
15	(strcmp((_file)->f_path.dentry->d_name.name, (_name)) == 0)
16
17#define GET_I915(i915, name, ptr)	\
18	do {	\
19		struct i915_params *params;	\
20		params = container_of(((void *)(ptr)), typeof(*params), name);	\
21		(i915) = container_of(params, typeof(*(i915)), params);	\
22	} while (0)
23
24/* int param */
25static int i915_param_int_show(struct seq_file *m, void *data)
26{
27	int *value = m->private;
28
29	seq_printf(m, "%d\n", *value);
30
31	return 0;
32}
33
34static int i915_param_int_open(struct inode *inode, struct file *file)
35{
36	return single_open(file, i915_param_int_show, inode->i_private);
37}
38
39static int notify_guc(struct drm_i915_private *i915)
40{
41	struct intel_gt *gt;
42	int i, ret = 0;
43
44	for_each_gt(gt, i915, i) {
45		if (intel_uc_uses_guc_submission(&gt->uc))
46			ret = intel_guc_global_policies_update(&gt->uc.guc);
47	}
48
49	return ret;
50}
51
52static ssize_t i915_param_int_write(struct file *file,
53				    const char __user *ubuf, size_t len,
54				    loff_t *offp)
55{
56	struct seq_file *m = file->private_data;
57	int *value = m->private;
58	int ret;
59
60	ret = kstrtoint_from_user(ubuf, len, 0, value);
61	if (ret) {
62		/* support boolean values too */
63		bool b;
64
65		ret = kstrtobool_from_user(ubuf, len, &b);
66		if (!ret)
67			*value = b;
68	}
69
70	return ret ?: len;
71}
72
73static const struct file_operations i915_param_int_fops = {
74	.owner = THIS_MODULE,
75	.open = i915_param_int_open,
76	.read = seq_read,
77	.write = i915_param_int_write,
78	.llseek = default_llseek,
79	.release = single_release,
80};
81
82static const struct file_operations i915_param_int_fops_ro = {
83	.owner = THIS_MODULE,
84	.open = i915_param_int_open,
85	.read = seq_read,
86	.llseek = default_llseek,
87	.release = single_release,
88};
89
90/* unsigned int param */
91static int i915_param_uint_show(struct seq_file *m, void *data)
92{
93	unsigned int *value = m->private;
94
95	seq_printf(m, "%u\n", *value);
96
97	return 0;
98}
99
100static int i915_param_uint_open(struct inode *inode, struct file *file)
101{
102	return single_open(file, i915_param_uint_show, inode->i_private);
103}
104
105static ssize_t i915_param_uint_write(struct file *file,
106				     const char __user *ubuf, size_t len,
107				     loff_t *offp)
108{
109	struct drm_i915_private *i915;
110	struct seq_file *m = file->private_data;
111	unsigned int *value = m->private;
112	unsigned int old = *value;
113	int ret;
114
115	ret = kstrtouint_from_user(ubuf, len, 0, value);
116	if (ret) {
117		/* support boolean values too */
118		bool b;
119
120		ret = kstrtobool_from_user(ubuf, len, &b);
121		if (!ret)
122			*value = b;
123	}
124
125	if (!ret && MATCH_DEBUGFS_NODE_NAME(file, "reset")) {
126		GET_I915(i915, reset, value);
127
128		ret = notify_guc(i915);
129		if (ret)
130			*value = old;
131	}
132
133	return ret ?: len;
134}
135
136static const struct file_operations i915_param_uint_fops = {
137	.owner = THIS_MODULE,
138	.open = i915_param_uint_open,
139	.read = seq_read,
140	.write = i915_param_uint_write,
141	.llseek = default_llseek,
142	.release = single_release,
143};
144
145static const struct file_operations i915_param_uint_fops_ro = {
146	.owner = THIS_MODULE,
147	.open = i915_param_uint_open,
148	.read = seq_read,
149	.llseek = default_llseek,
150	.release = single_release,
151};
152
153/* char * param */
154static int i915_param_charp_show(struct seq_file *m, void *data)
155{
156	const char **s = m->private;
157
158	seq_printf(m, "%s\n", *s);
159
160	return 0;
161}
162
163static int i915_param_charp_open(struct inode *inode, struct file *file)
164{
165	return single_open(file, i915_param_charp_show, inode->i_private);
166}
167
168static ssize_t i915_param_charp_write(struct file *file,
169				      const char __user *ubuf, size_t len,
170				      loff_t *offp)
171{
172	struct seq_file *m = file->private_data;
173	char **s = m->private;
174	char *new, *old;
175
176	old = *s;
177	new = strndup_user(ubuf, PAGE_SIZE);
178	if (IS_ERR(new)) {
179		len = PTR_ERR(new);
180		goto out;
181	}
182
183	*s = new;
184
185	kfree(old);
186out:
187	return len;
188}
189
190static const struct file_operations i915_param_charp_fops = {
191	.owner = THIS_MODULE,
192	.open = i915_param_charp_open,
193	.read = seq_read,
194	.write = i915_param_charp_write,
195	.llseek = default_llseek,
196	.release = single_release,
197};
198
199static const struct file_operations i915_param_charp_fops_ro = {
200	.owner = THIS_MODULE,
201	.open = i915_param_charp_open,
202	.read = seq_read,
203	.llseek = default_llseek,
204	.release = single_release,
205};
206
207#define RO(mode) (((mode) & 0222) == 0)
208
209static struct dentry *
210i915_debugfs_create_int(const char *name, umode_t mode,
211			struct dentry *parent, int *value)
212{
213	return debugfs_create_file_unsafe(name, mode, parent, value,
214					  RO(mode) ? &i915_param_int_fops_ro :
215					  &i915_param_int_fops);
216}
217
218static struct dentry *
219i915_debugfs_create_uint(const char *name, umode_t mode,
220			 struct dentry *parent, unsigned int *value)
221{
222	return debugfs_create_file_unsafe(name, mode, parent, value,
223					  RO(mode) ? &i915_param_uint_fops_ro :
224					  &i915_param_uint_fops);
225}
226
227static struct dentry *
228i915_debugfs_create_charp(const char *name, umode_t mode,
229			  struct dentry *parent, char **value)
230{
231	return debugfs_create_file(name, mode, parent, value,
232				   RO(mode) ? &i915_param_charp_fops_ro :
233				   &i915_param_charp_fops);
234}
235
236#define _i915_param_create_file(parent, name, mode, valp)		\
237	do {								\
238		if (mode)						\
239			_Generic(valp,					\
240				 bool *: debugfs_create_bool,		\
241				 int *: i915_debugfs_create_int,	\
242				 unsigned int *: i915_debugfs_create_uint, \
243				 unsigned long *: debugfs_create_ulong,	\
244				 char **: i915_debugfs_create_charp)(name, mode, parent, valp); \
245	} while(0)
246
247/* add a subdirectory with files for each i915 param */
248struct dentry *i915_debugfs_params(struct drm_i915_private *i915)
249{
250	struct drm_minor *minor = i915->drm.primary;
251	struct i915_params *params = &i915->params;
252	struct dentry *dir;
253
254	dir = debugfs_create_dir("i915_params", minor->debugfs_root);
255	if (IS_ERR(dir))
256		return dir;
257
258	/*
259	 * Note: We could create files for params needing special handling
260	 * here. Set mode in params to 0 to skip the generic create file, or
261	 * just let the generic create file fail silently with -EEXIST.
262	 */
263
264#define REGISTER(T, x, unused, mode, ...) _i915_param_create_file(dir, #x, mode, &params->x);
265	I915_PARAMS_FOR_EACH(REGISTER);
266#undef REGISTER
267
268	return dir;
269}
270