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