2019-12-05 17:43:40 +02:00
// SPDX-License-Identifier: MIT
/*
* Copyright © 2019 Intel Corporation
*/
# include <linux/kernel.h>
2020-01-17 10:21:45 +00:00
# include "i915_debugfs_params.h"
2021-07-26 17:23:36 -07:00
# include "gt/intel_gt.h"
# include "gt/uc/intel_guc.h"
2019-12-05 17:43:40 +02:00
# include "i915_drv.h"
# include "i915_params.h"
2021-07-26 17:23:36 -07:00
# define MATCH_DEBUGFS_NODE_NAME(_file, _name) \
( strcmp ( ( _file ) - > f_path . dentry - > d_name . name , ( _name ) ) = = 0 )
# define GET_I915(i915, name, ptr) \
do { \
struct i915_params * params ; \
params = container_of ( ( ( void * ) ( ptr ) ) , typeof ( * params ) , name ) ; \
( i915 ) = container_of ( params , typeof ( * ( i915 ) ) , params ) ; \
} while ( 0 )
2019-12-05 17:43:40 +02:00
/* 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 ) ;
}
2021-07-26 17:23:36 -07:00
static int notify_guc ( struct drm_i915_private * i915 )
{
int ret = 0 ;
2021-12-14 21:33:39 +02:00
if ( intel_uc_uses_guc_submission ( & to_gt ( i915 ) - > uc ) )
ret = intel_guc_global_policies_update ( & to_gt ( i915 ) - > uc . guc ) ;
2021-07-26 17:23:36 -07:00
return ret ;
}
2019-12-05 17:43:40 +02:00
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 ) ;
2019-12-05 17:43:41 +02:00
if ( ret ) {
/* support boolean values too */
bool b ;
ret = kstrtobool_from_user ( ubuf , len , & b ) ;
if ( ! ret )
* value = b ;
}
2019-12-05 17:43:40 +02:00
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 )
{
2021-07-26 17:23:36 -07:00
struct drm_i915_private * i915 ;
2019-12-05 17:43:40 +02:00
struct seq_file * m = file - > private_data ;
unsigned int * value = m - > private ;
2021-07-26 17:23:36 -07:00
unsigned int old = * value ;
2019-12-05 17:43:40 +02:00
int ret ;
ret = kstrtouint_from_user ( ubuf , len , 0 , value ) ;
2019-12-05 17:43:41 +02:00
if ( ret ) {
/* support boolean values too */
bool b ;
ret = kstrtobool_from_user ( ubuf , len , & b ) ;
if ( ! ret )
* value = b ;
}
2019-12-05 17:43:40 +02:00
2021-07-26 17:23:36 -07:00
if ( ! ret & & MATCH_DEBUGFS_NODE_NAME ( file , " reset " ) ) {
GET_I915 ( i915 , reset , value ) ;
ret = notify_guc ( i915 ) ;
if ( ret )
* value = old ;
}
2019-12-05 17:43:40 +02:00
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 ;
2020-06-18 18:04:02 +03:00
struct i915_params * params = & i915 - > params ;
2019-12-05 17:43:40 +02:00
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 ;
}