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