2013-02-09 00:42:13 +04:00
/*
* Copyright ( C ) 2009 Red Hat < bskeggs @ redhat . com >
*
* Permission is hereby granted , free of charge , to any person obtaining
* a copy of this software and associated documentation files ( the
* " Software " ) , to deal in the Software without restriction , including
* without limitation the rights to use , copy , modify , merge , publish ,
* distribute , sublicense , and / or sell copies of the Software , and to
* permit persons to whom the Software is furnished to do so , subject to
* the following conditions :
*
* The above copyright notice and this permission notice ( including the
* next paragraph ) shall be included in all copies or substantial
* portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT .
* IN NO EVENT SHALL THE COPYRIGHT OWNER ( S ) AND / OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN ACTION
* OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*
*/
/*
* Authors :
* Ben Skeggs < bskeggs @ redhat . com >
*/
2015-07-29 14:44:21 +03:00
# include <linux/debugfs.h>
2015-07-30 12:52:23 +03:00
# include <nvif/class.h>
2015-07-30 12:53:31 +03:00
# include <nvif/if0001.h>
2013-02-09 00:42:13 +04:00
# include "nouveau_debugfs.h"
2016-05-20 02:22:55 +03:00
# include "nouveau_drv.h"
2013-02-09 00:42:13 +04:00
static int
nouveau_debugfs_vbios_image ( struct seq_file * m , void * data )
{
struct drm_info_node * node = ( struct drm_info_node * ) m - > private ;
struct nouveau_drm * drm = nouveau_drm ( node - > minor - > dev ) ;
int i ;
for ( i = 0 ; i < drm - > vbios . length ; i + + )
seq_printf ( m , " %c " , drm - > vbios . data [ i ] ) ;
return 0 ;
}
2018-09-19 20:13:51 +03:00
static int
nouveau_debugfs_strap_peek ( struct seq_file * m , void * data )
{
struct drm_info_node * node = m - > private ;
struct nouveau_drm * drm = nouveau_drm ( node - > minor - > dev ) ;
int ret ;
ret = pm_runtime_get_sync ( drm - > dev - > dev ) ;
if ( ret < 0 & & ret ! = - EACCES )
return ret ;
seq_printf ( m , " 0x%08x \n " ,
nvif_rd32 ( & drm - > client . device . object , 0x101000 ) ) ;
pm_runtime_mark_last_busy ( drm - > dev - > dev ) ;
pm_runtime_put_autosuspend ( drm - > dev - > dev ) ;
return 0 ;
}
2015-07-30 12:53:31 +03:00
static int
nouveau_debugfs_pstate_get ( struct seq_file * m , void * data )
{
2017-01-27 01:56:12 +03:00
struct drm_device * drm = m - > private ;
struct nouveau_debugfs * debugfs = nouveau_debugfs ( drm ) ;
2015-07-30 12:53:31 +03:00
struct nvif_object * ctrl = & debugfs - > ctrl ;
struct nvif_control_pstate_info_v0 info = { } ;
int ret , i ;
if ( ! debugfs )
return - ENODEV ;
ret = nvif_mthd ( ctrl , NVIF_CONTROL_PSTATE_INFO , & info , sizeof ( info ) ) ;
if ( ret )
return ret ;
for ( i = 0 ; i < info . count + 1 ; i + + ) {
const s32 state = i < info . count ? i :
NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT ;
struct nvif_control_pstate_attr_v0 attr = {
. state = state ,
. index = 0 ,
} ;
ret = nvif_mthd ( ctrl , NVIF_CONTROL_PSTATE_ATTR ,
& attr , sizeof ( attr ) ) ;
if ( ret )
return ret ;
if ( i < info . count )
seq_printf ( m , " %02x: " , attr . state ) ;
else
seq_printf ( m , " %s: " , info . pwrsrc = = 0 ? " DC " :
info . pwrsrc = = 1 ? " AC " : " -- " ) ;
attr . index = 0 ;
do {
attr . state = state ;
ret = nvif_mthd ( ctrl , NVIF_CONTROL_PSTATE_ATTR ,
& attr , sizeof ( attr ) ) ;
if ( ret )
return ret ;
seq_printf ( m , " %s %d " , attr . name , attr . min ) ;
if ( attr . min ! = attr . max )
seq_printf ( m , " -%d " , attr . max ) ;
seq_printf ( m , " %s " , attr . unit ) ;
} while ( attr . index ) ;
if ( state > = 0 ) {
if ( info . ustate_ac = = state )
seq_printf ( m , " AC " ) ;
if ( info . ustate_dc = = state )
seq_printf ( m , " DC " ) ;
if ( info . pstate = = state )
seq_printf ( m , " * " ) ;
} else {
if ( info . ustate_ac < - 1 )
seq_printf ( m , " AC " ) ;
if ( info . ustate_dc < - 1 )
seq_printf ( m , " DC " ) ;
}
seq_printf ( m , " \n " ) ;
}
return 0 ;
}
static ssize_t
nouveau_debugfs_pstate_set ( struct file * file , const char __user * ubuf ,
size_t len , loff_t * offp )
{
struct seq_file * m = file - > private_data ;
2017-01-27 01:56:12 +03:00
struct drm_device * drm = m - > private ;
struct nouveau_debugfs * debugfs = nouveau_debugfs ( drm ) ;
2015-07-30 12:53:31 +03:00
struct nvif_object * ctrl = & debugfs - > ctrl ;
struct nvif_control_pstate_user_v0 args = { . pwrsrc = - EINVAL } ;
char buf [ 32 ] = { } , * tmp , * cur = buf ;
long value , ret ;
if ( ! debugfs )
return - ENODEV ;
if ( len > = sizeof ( buf ) )
return - EINVAL ;
if ( copy_from_user ( buf , ubuf , len ) )
return - EFAULT ;
if ( ( tmp = strchr ( buf , ' \n ' ) ) )
* tmp = ' \0 ' ;
if ( ! strncasecmp ( cur , " dc: " , 3 ) ) {
args . pwrsrc = 0 ;
cur + = 3 ;
} else
if ( ! strncasecmp ( cur , " ac: " , 3 ) ) {
args . pwrsrc = 1 ;
cur + = 3 ;
}
if ( ! strcasecmp ( cur , " none " ) )
args . ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN ;
else
if ( ! strcasecmp ( cur , " auto " ) )
args . ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON ;
else {
ret = kstrtol ( cur , 16 , & value ) ;
if ( ret )
return ret ;
args . ustate = value ;
}
2018-07-14 13:52:09 +03:00
ret = pm_runtime_get_sync ( drm - > dev ) ;
if ( IS_ERR_VALUE ( ret ) & & ret ! = - EACCES )
return ret ;
2015-07-30 12:53:31 +03:00
ret = nvif_mthd ( ctrl , NVIF_CONTROL_PSTATE_USER , & args , sizeof ( args ) ) ;
2018-07-14 13:52:09 +03:00
pm_runtime_put_autosuspend ( drm - > dev ) ;
2015-07-30 12:53:31 +03:00
if ( ret < 0 )
return ret ;
return len ;
}
static int
nouveau_debugfs_pstate_open ( struct inode * inode , struct file * file )
{
return single_open ( file , nouveau_debugfs_pstate_get , inode - > i_private ) ;
}
static const struct file_operations nouveau_pstate_fops = {
. owner = THIS_MODULE ,
. open = nouveau_debugfs_pstate_open ,
. read = seq_read ,
. write = nouveau_debugfs_pstate_set ,
} ;
2013-02-09 00:42:13 +04:00
static struct drm_info_list nouveau_debugfs_list [ ] = {
2018-09-19 20:13:51 +03:00
{ " vbios.rom " , nouveau_debugfs_vbios_image , 0 , NULL } ,
{ " strap_peek " , nouveau_debugfs_strap_peek , 0 , NULL } ,
2013-02-09 00:42:13 +04:00
} ;
# define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)
2015-07-29 14:44:21 +03:00
static const struct nouveau_debugfs_files {
const char * name ;
const struct file_operations * fops ;
2015-07-30 12:53:31 +03:00
} nouveau_debugfs_files [ ] = {
{ " pstate " , & nouveau_pstate_fops } ,
} ;
2015-07-29 14:44:21 +03:00
2013-02-09 00:42:13 +04:00
int
2015-07-31 01:35:42 +03:00
nouveau_drm_debugfs_init ( struct drm_minor * minor )
2013-02-09 00:42:13 +04:00
{
2018-09-19 20:13:52 +03:00
struct nouveau_drm * drm = nouveau_drm ( minor - > dev ) ;
2017-01-27 01:56:12 +03:00
struct dentry * dentry ;
2018-09-19 20:13:52 +03:00
int i , ret ;
2015-07-29 14:44:21 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( nouveau_debugfs_files ) ; i + + ) {
2017-01-27 01:56:12 +03:00
dentry = debugfs_create_file ( nouveau_debugfs_files [ i ] . name ,
S_IRUGO | S_IWUSR ,
minor - > debugfs_root , minor - > dev ,
nouveau_debugfs_files [ i ] . fops ) ;
if ( ! dentry )
return - ENOMEM ;
2015-07-29 14:44:21 +03:00
}
2018-09-19 20:13:52 +03:00
ret = drm_debugfs_create_files ( nouveau_debugfs_list ,
NOUVEAU_DEBUGFS_ENTRIES ,
minor - > debugfs_root , minor ) ;
if ( ret )
return ret ;
/* Set the size of the vbios since we know it, and it's confusing to
* userspace if it wants to seek ( ) but the file has a length of 0
*/
dentry = debugfs_lookup ( " vbios.rom " , minor - > debugfs_root ) ;
if ( ! dentry )
return 0 ;
d_inode ( dentry ) - > i_size = drm - > vbios . length ;
dput ( dentry ) ;
return 0 ;
2013-02-09 00:42:13 +04:00
}
2015-07-30 12:52:23 +03:00
int
nouveau_debugfs_init ( struct nouveau_drm * drm )
{
int ret ;
drm - > debugfs = kzalloc ( sizeof ( * drm - > debugfs ) , GFP_KERNEL ) ;
if ( ! drm - > debugfs )
return - ENOMEM ;
2016-05-18 06:57:42 +03:00
ret = nvif_object_init ( & drm - > client . device . object , 0 ,
NVIF_CLASS_CONTROL , NULL , 0 ,
& drm - > debugfs - > ctrl ) ;
2015-07-30 12:52:23 +03:00
if ( ret )
return ret ;
return 0 ;
}
void
nouveau_debugfs_fini ( struct nouveau_drm * drm )
{
if ( drm - > debugfs & & drm - > debugfs - > ctrl . priv )
nvif_object_fini ( & drm - > debugfs - > ctrl ) ;
kfree ( drm - > debugfs ) ;
drm - > debugfs = NULL ;
}