mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-21 10:05:00 +08:00
8a25c4be58
Start using device specific parameters instead of module parameters for most things. The module parameters become the immutable initial values for i915 parameters. The device specific parameters in i915->params start life as a copy of i915_modparams. Any later changes are only reflected in the debugfs. The stragglers are: * i915.force_probe and i915.modeset. Needed before dev_priv is available. This is fine because the parameters are read-only and never modified. * i915.verbose_state_checks. Passing dev_priv to I915_STATE_WARN and I915_STATE_WARN_ON would result in massive and ugly churn. This is handled by not exposing the parameter via debugfs, and leaving the parameter writable in sysfs. This may be fixed up in follow-up work. * i915.inject_probe_failure. Only makes sense in terms of the module, not the device. This is handled by not exposing the parameter via debugfs. v2: Fix uc i915 lookup code (Michał Winiarski) Cc: Juha-Pekka Heikkilä <juha-pekka.heikkila@intel.com> Cc: Venkata Sandeep Dhanalakota <venkata.s.dhanalakota@intel.com> Cc: Michał Winiarski <michal.winiarski@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Acked-by: Michał Winiarski <michal.winiarski@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/20200618150402.14022-1-jani.nikula@intel.com
246 lines
5.7 KiB
C
246 lines
5.7 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Copyright © 2019 Intel Corporation
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include "i915_debugfs_params.h"
|
|
#include "i915_drv.h"
|
|
#include "i915_params.h"
|
|
|
|
/* int param */
|
|
static int i915_param_int_show(struct seq_file *m, void *data)
|
|
{
|
|
int *value = m->private;
|
|
|
|
seq_printf(m, "%d\n", *value);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int i915_param_int_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, i915_param_int_show, inode->i_private);
|
|
}
|
|
|
|
static ssize_t i915_param_int_write(struct file *file,
|
|
const char __user *ubuf, size_t len,
|
|
loff_t *offp)
|
|
{
|
|
struct seq_file *m = file->private_data;
|
|
int *value = m->private;
|
|
int ret;
|
|
|
|
ret = kstrtoint_from_user(ubuf, len, 0, value);
|
|
if (ret) {
|
|
/* support boolean values too */
|
|
bool b;
|
|
|
|
ret = kstrtobool_from_user(ubuf, len, &b);
|
|
if (!ret)
|
|
*value = b;
|
|
}
|
|
|
|
return ret ?: len;
|
|
}
|
|
|
|
static const struct file_operations i915_param_int_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = i915_param_int_open,
|
|
.read = seq_read,
|
|
.write = i915_param_int_write,
|
|
.llseek = default_llseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
static const struct file_operations i915_param_int_fops_ro = {
|
|
.owner = THIS_MODULE,
|
|
.open = i915_param_int_open,
|
|
.read = seq_read,
|
|
.llseek = default_llseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
/* unsigned int param */
|
|
static int i915_param_uint_show(struct seq_file *m, void *data)
|
|
{
|
|
unsigned int *value = m->private;
|
|
|
|
seq_printf(m, "%u\n", *value);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int i915_param_uint_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, i915_param_uint_show, inode->i_private);
|
|
}
|
|
|
|
static ssize_t i915_param_uint_write(struct file *file,
|
|
const char __user *ubuf, size_t len,
|
|
loff_t *offp)
|
|
{
|
|
struct seq_file *m = file->private_data;
|
|
unsigned int *value = m->private;
|
|
int ret;
|
|
|
|
ret = kstrtouint_from_user(ubuf, len, 0, value);
|
|
if (ret) {
|
|
/* support boolean values too */
|
|
bool b;
|
|
|
|
ret = kstrtobool_from_user(ubuf, len, &b);
|
|
if (!ret)
|
|
*value = b;
|
|
}
|
|
|
|
return ret ?: len;
|
|
}
|
|
|
|
static const struct file_operations i915_param_uint_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = i915_param_uint_open,
|
|
.read = seq_read,
|
|
.write = i915_param_uint_write,
|
|
.llseek = default_llseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
static const struct file_operations i915_param_uint_fops_ro = {
|
|
.owner = THIS_MODULE,
|
|
.open = i915_param_uint_open,
|
|
.read = seq_read,
|
|
.llseek = default_llseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
/* char * param */
|
|
static int i915_param_charp_show(struct seq_file *m, void *data)
|
|
{
|
|
const char **s = m->private;
|
|
|
|
seq_printf(m, "%s\n", *s);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int i915_param_charp_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, i915_param_charp_show, inode->i_private);
|
|
}
|
|
|
|
static ssize_t i915_param_charp_write(struct file *file,
|
|
const char __user *ubuf, size_t len,
|
|
loff_t *offp)
|
|
{
|
|
struct seq_file *m = file->private_data;
|
|
char **s = m->private;
|
|
char *new, *old;
|
|
|
|
old = *s;
|
|
new = strndup_user(ubuf, PAGE_SIZE);
|
|
if (IS_ERR(new)) {
|
|
len = PTR_ERR(new);
|
|
goto out;
|
|
}
|
|
|
|
*s = new;
|
|
|
|
kfree(old);
|
|
out:
|
|
return len;
|
|
}
|
|
|
|
static const struct file_operations i915_param_charp_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = i915_param_charp_open,
|
|
.read = seq_read,
|
|
.write = i915_param_charp_write,
|
|
.llseek = default_llseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
static const struct file_operations i915_param_charp_fops_ro = {
|
|
.owner = THIS_MODULE,
|
|
.open = i915_param_charp_open,
|
|
.read = seq_read,
|
|
.llseek = default_llseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
#define RO(mode) (((mode) & 0222) == 0)
|
|
|
|
static struct dentry *
|
|
i915_debugfs_create_int(const char *name, umode_t mode,
|
|
struct dentry *parent, int *value)
|
|
{
|
|
return debugfs_create_file_unsafe(name, mode, parent, value,
|
|
RO(mode) ? &i915_param_int_fops_ro :
|
|
&i915_param_int_fops);
|
|
}
|
|
|
|
static struct dentry *
|
|
i915_debugfs_create_uint(const char *name, umode_t mode,
|
|
struct dentry *parent, unsigned int *value)
|
|
{
|
|
return debugfs_create_file_unsafe(name, mode, parent, value,
|
|
RO(mode) ? &i915_param_uint_fops_ro :
|
|
&i915_param_uint_fops);
|
|
}
|
|
|
|
static struct dentry *
|
|
i915_debugfs_create_charp(const char *name, umode_t mode,
|
|
struct dentry *parent, char **value)
|
|
{
|
|
return debugfs_create_file(name, mode, parent, value,
|
|
RO(mode) ? &i915_param_charp_fops_ro :
|
|
&i915_param_charp_fops);
|
|
}
|
|
|
|
static __always_inline void
|
|
_i915_param_create_file(struct dentry *parent, const char *name,
|
|
const char *type, int mode, void *value)
|
|
{
|
|
if (!mode)
|
|
return;
|
|
|
|
if (!__builtin_strcmp(type, "bool"))
|
|
debugfs_create_bool(name, mode, parent, value);
|
|
else if (!__builtin_strcmp(type, "int"))
|
|
i915_debugfs_create_int(name, mode, parent, value);
|
|
else if (!__builtin_strcmp(type, "unsigned int"))
|
|
i915_debugfs_create_uint(name, mode, parent, value);
|
|
else if (!__builtin_strcmp(type, "unsigned long"))
|
|
debugfs_create_ulong(name, mode, parent, value);
|
|
else if (!__builtin_strcmp(type, "char *"))
|
|
i915_debugfs_create_charp(name, mode, parent, value);
|
|
else
|
|
WARN(1, "no debugfs fops defined for param type %s (i915.%s)\n",
|
|
type, name);
|
|
}
|
|
|
|
/* add a subdirectory with files for each i915 param */
|
|
struct dentry *i915_debugfs_params(struct drm_i915_private *i915)
|
|
{
|
|
struct drm_minor *minor = i915->drm.primary;
|
|
struct i915_params *params = &i915->params;
|
|
struct dentry *dir;
|
|
|
|
dir = debugfs_create_dir("i915_params", minor->debugfs_root);
|
|
if (IS_ERR(dir))
|
|
return dir;
|
|
|
|
/*
|
|
* Note: We could create files for params needing special handling
|
|
* here. Set mode in params to 0 to skip the generic create file, or
|
|
* just let the generic create file fail silently with -EEXIST.
|
|
*/
|
|
|
|
#define REGISTER(T, x, unused, mode, ...) _i915_param_create_file(dir, #x, #T, mode, ¶ms->x);
|
|
I915_PARAMS_FOR_EACH(REGISTER);
|
|
#undef REGISTER
|
|
|
|
return dir;
|
|
}
|