2019-05-29 17:18:03 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2020-07-01 11:30:51 +03:00
/*
2013-12-09 16:30:42 +04:00
* IBM Accelerator Family ' GenWQE '
*
* ( C ) Copyright IBM Corp . 2013
*
* Author : Frank Haverkamp < haver @ linux . vnet . ibm . com >
* Author : Joerg - Stephan Vogt < jsvogt @ de . ibm . com >
2014-09-10 18:37:48 +04:00
* Author : Michael Jung < mijung @ gmx . net >
2013-12-09 16:30:42 +04:00
* Author : Michael Ruettger < michael @ ibmra . de >
*/
/*
* Debugfs interfaces for the GenWQE card . Help to debug potential
* problems . Dump internal chip state for debugging and failure
* determination .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/debugfs.h>
# include <linux/seq_file.h>
# include <linux/uaccess.h>
# include "card_base.h"
# include "card_ddcb.h"
static void dbg_uidn_show ( struct seq_file * s , struct genwqe_reg * regs ,
int entries )
{
unsigned int i ;
u32 v_hi , v_lo ;
for ( i = 0 ; i < entries ; i + + ) {
v_hi = ( regs [ i ] . val > > 32 ) & 0xffffffff ;
v_lo = ( regs [ i ] . val ) & 0xffffffff ;
seq_printf ( s , " 0x%08x 0x%08x 0x%08x 0x%08x EXT_ERR_REC \n " ,
regs [ i ] . addr , regs [ i ] . idx , v_hi , v_lo ) ;
}
}
static int curr_dbg_uidn_show ( struct seq_file * s , void * unused , int uid )
{
struct genwqe_dev * cd = s - > private ;
int entries ;
struct genwqe_reg * regs ;
entries = genwqe_ffdc_buff_size ( cd , uid ) ;
if ( entries < 0 )
return - EINVAL ;
if ( entries = = 0 )
return 0 ;
regs = kcalloc ( entries , sizeof ( * regs ) , GFP_KERNEL ) ;
if ( regs = = NULL )
return - ENOMEM ;
genwqe_stop_traps ( cd ) ; /* halt the traps while dumping data */
genwqe_ffdc_buff_read ( cd , uid , regs , entries ) ;
genwqe_start_traps ( cd ) ;
dbg_uidn_show ( s , regs , entries ) ;
kfree ( regs ) ;
return 0 ;
}
2018-12-01 20:05:30 +03:00
static int curr_dbg_uid0_show ( struct seq_file * s , void * unused )
2013-12-09 16:30:42 +04:00
{
return curr_dbg_uidn_show ( s , unused , 0 ) ;
}
2018-12-01 20:05:30 +03:00
DEFINE_SHOW_ATTRIBUTE ( curr_dbg_uid0 ) ;
2013-12-09 16:30:42 +04:00
2018-12-01 20:05:30 +03:00
static int curr_dbg_uid1_show ( struct seq_file * s , void * unused )
2013-12-09 16:30:42 +04:00
{
return curr_dbg_uidn_show ( s , unused , 1 ) ;
}
2018-12-01 20:05:30 +03:00
DEFINE_SHOW_ATTRIBUTE ( curr_dbg_uid1 ) ;
2013-12-09 16:30:42 +04:00
2018-12-01 20:05:30 +03:00
static int curr_dbg_uid2_show ( struct seq_file * s , void * unused )
2013-12-09 16:30:42 +04:00
{
return curr_dbg_uidn_show ( s , unused , 2 ) ;
}
2018-12-01 20:05:30 +03:00
DEFINE_SHOW_ATTRIBUTE ( curr_dbg_uid2 ) ;
2013-12-09 16:30:42 +04:00
static int prev_dbg_uidn_show ( struct seq_file * s , void * unused , int uid )
{
struct genwqe_dev * cd = s - > private ;
dbg_uidn_show ( s , cd - > ffdc [ uid ] . regs , cd - > ffdc [ uid ] . entries ) ;
return 0 ;
}
2018-12-01 20:05:30 +03:00
static int prev_dbg_uid0_show ( struct seq_file * s , void * unused )
2013-12-09 16:30:42 +04:00
{
return prev_dbg_uidn_show ( s , unused , 0 ) ;
}
2018-12-01 20:05:30 +03:00
DEFINE_SHOW_ATTRIBUTE ( prev_dbg_uid0 ) ;
2013-12-09 16:30:42 +04:00
2018-12-01 20:05:30 +03:00
static int prev_dbg_uid1_show ( struct seq_file * s , void * unused )
2013-12-09 16:30:42 +04:00
{
return prev_dbg_uidn_show ( s , unused , 1 ) ;
}
2018-12-01 20:05:30 +03:00
DEFINE_SHOW_ATTRIBUTE ( prev_dbg_uid1 ) ;
2013-12-09 16:30:42 +04:00
2018-12-01 20:05:30 +03:00
static int prev_dbg_uid2_show ( struct seq_file * s , void * unused )
2013-12-09 16:30:42 +04:00
{
return prev_dbg_uidn_show ( s , unused , 2 ) ;
}
2018-12-01 20:05:30 +03:00
DEFINE_SHOW_ATTRIBUTE ( prev_dbg_uid2 ) ;
2013-12-09 16:30:42 +04:00
2018-12-01 20:05:30 +03:00
static int curr_regs_show ( struct seq_file * s , void * unused )
2013-12-09 16:30:42 +04:00
{
struct genwqe_dev * cd = s - > private ;
unsigned int i ;
struct genwqe_reg * regs ;
regs = kcalloc ( GENWQE_FFDC_REGS , sizeof ( * regs ) , GFP_KERNEL ) ;
if ( regs = = NULL )
return - ENOMEM ;
genwqe_stop_traps ( cd ) ;
genwqe_read_ffdc_regs ( cd , regs , GENWQE_FFDC_REGS , 1 ) ;
genwqe_start_traps ( cd ) ;
for ( i = 0 ; i < GENWQE_FFDC_REGS ; i + + ) {
if ( regs [ i ] . addr = = 0xffffffff )
break ; /* invalid entries */
if ( regs [ i ] . val = = 0x0ull )
continue ; /* do not print 0x0 FIRs */
seq_printf ( s , " 0x%08x 0x%016llx \n " ,
regs [ i ] . addr , regs [ i ] . val ) ;
}
return 0 ;
}
2018-12-01 20:05:30 +03:00
DEFINE_SHOW_ATTRIBUTE ( curr_regs ) ;
2013-12-09 16:30:42 +04:00
2018-12-01 20:05:30 +03:00
static int prev_regs_show ( struct seq_file * s , void * unused )
2013-12-09 16:30:42 +04:00
{
struct genwqe_dev * cd = s - > private ;
unsigned int i ;
struct genwqe_reg * regs = cd - > ffdc [ GENWQE_DBG_REGS ] . regs ;
if ( regs = = NULL )
return - EINVAL ;
for ( i = 0 ; i < GENWQE_FFDC_REGS ; i + + ) {
if ( regs [ i ] . addr = = 0xffffffff )
break ; /* invalid entries */
if ( regs [ i ] . val = = 0x0ull )
continue ; /* do not print 0x0 FIRs */
seq_printf ( s , " 0x%08x 0x%016llx \n " ,
regs [ i ] . addr , regs [ i ] . val ) ;
}
return 0 ;
}
2018-12-01 20:05:30 +03:00
DEFINE_SHOW_ATTRIBUTE ( prev_regs ) ;
2013-12-09 16:30:42 +04:00
2018-12-01 20:05:30 +03:00
static int jtimer_show ( struct seq_file * s , void * unused )
2013-12-09 16:30:42 +04:00
{
struct genwqe_dev * cd = s - > private ;
unsigned int vf_num ;
u64 jtimer ;
jtimer = genwqe_read_vreg ( cd , IO_SLC_VF_APPJOB_TIMEOUT , 0 ) ;
seq_printf ( s , " PF 0x%016llx %d msec \n " , jtimer ,
2017-12-14 17:34:05 +03:00
GENWQE_PF_JOBTIMEOUT_MSEC ) ;
2013-12-09 16:30:42 +04:00
for ( vf_num = 0 ; vf_num < cd - > num_vfs ; vf_num + + ) {
jtimer = genwqe_read_vreg ( cd , IO_SLC_VF_APPJOB_TIMEOUT ,
vf_num + 1 ) ;
seq_printf ( s , " VF%-2d 0x%016llx %d msec \n " , vf_num , jtimer ,
cd - > vf_jobtimeout_msec [ vf_num ] ) ;
}
return 0 ;
}
2018-12-01 20:05:30 +03:00
DEFINE_SHOW_ATTRIBUTE ( jtimer ) ;
2013-12-09 16:30:42 +04:00
2018-12-01 20:05:30 +03:00
static int queue_working_time_show ( struct seq_file * s , void * unused )
2013-12-09 16:30:42 +04:00
{
struct genwqe_dev * cd = s - > private ;
unsigned int vf_num ;
u64 t ;
t = genwqe_read_vreg ( cd , IO_SLC_VF_QUEUE_WTIME , 0 ) ;
seq_printf ( s , " PF 0x%016llx \n " , t ) ;
for ( vf_num = 0 ; vf_num < cd - > num_vfs ; vf_num + + ) {
t = genwqe_read_vreg ( cd , IO_SLC_VF_QUEUE_WTIME , vf_num + 1 ) ;
seq_printf ( s , " VF%-2d 0x%016llx \n " , vf_num , t ) ;
}
return 0 ;
}
2018-12-01 20:05:30 +03:00
DEFINE_SHOW_ATTRIBUTE ( queue_working_time ) ;
2013-12-09 16:30:42 +04:00
2018-12-01 20:05:30 +03:00
static int ddcb_info_show ( struct seq_file * s , void * unused )
2013-12-09 16:30:42 +04:00
{
struct genwqe_dev * cd = s - > private ;
unsigned int i ;
struct ddcb_queue * queue ;
struct ddcb * pddcb ;
queue = & cd - > queue ;
seq_puts ( s , " DDCB QUEUE: \n " ) ;
seq_printf ( s , " ddcb_max: %d \n "
" ddcb_daddr: %016llx - %016llx \n "
2019-04-21 14:47:48 +03:00
" ddcb_vaddr: %p \n "
2013-12-09 16:30:42 +04:00
" ddcbs_in_flight: %u \n "
" ddcbs_max_in_flight: %u \n "
" ddcbs_completed: %u \n "
2014-09-10 18:37:53 +04:00
" return_on_busy: %u \n "
" wait_on_busy: %u \n "
2013-12-09 16:30:42 +04:00
" irqs_processed: %u \n " ,
queue - > ddcb_max , ( long long ) queue - > ddcb_daddr ,
( long long ) queue - > ddcb_daddr +
( queue - > ddcb_max * DDCB_LENGTH ) ,
2019-04-21 14:47:48 +03:00
queue - > ddcb_vaddr , queue - > ddcbs_in_flight ,
2013-12-09 16:30:42 +04:00
queue - > ddcbs_max_in_flight , queue - > ddcbs_completed ,
2014-09-10 18:37:53 +04:00
queue - > return_on_busy , queue - > wait_on_busy ,
cd - > irqs_processed ) ;
2013-12-09 16:30:42 +04:00
/* Hardware State */
seq_printf ( s , " 0x%08x 0x%016llx IO_QUEUE_CONFIG \n "
" 0x%08x 0x%016llx IO_QUEUE_STATUS \n "
" 0x%08x 0x%016llx IO_QUEUE_SEGMENT \n "
" 0x%08x 0x%016llx IO_QUEUE_INITSQN \n "
" 0x%08x 0x%016llx IO_QUEUE_WRAP \n "
" 0x%08x 0x%016llx IO_QUEUE_OFFSET \n "
" 0x%08x 0x%016llx IO_QUEUE_WTIME \n "
" 0x%08x 0x%016llx IO_QUEUE_ERRCNTS \n "
" 0x%08x 0x%016llx IO_QUEUE_LRW \n " ,
queue - > IO_QUEUE_CONFIG ,
__genwqe_readq ( cd , queue - > IO_QUEUE_CONFIG ) ,
queue - > IO_QUEUE_STATUS ,
__genwqe_readq ( cd , queue - > IO_QUEUE_STATUS ) ,
queue - > IO_QUEUE_SEGMENT ,
__genwqe_readq ( cd , queue - > IO_QUEUE_SEGMENT ) ,
queue - > IO_QUEUE_INITSQN ,
__genwqe_readq ( cd , queue - > IO_QUEUE_INITSQN ) ,
queue - > IO_QUEUE_WRAP ,
__genwqe_readq ( cd , queue - > IO_QUEUE_WRAP ) ,
queue - > IO_QUEUE_OFFSET ,
__genwqe_readq ( cd , queue - > IO_QUEUE_OFFSET ) ,
queue - > IO_QUEUE_WTIME ,
__genwqe_readq ( cd , queue - > IO_QUEUE_WTIME ) ,
queue - > IO_QUEUE_ERRCNTS ,
__genwqe_readq ( cd , queue - > IO_QUEUE_ERRCNTS ) ,
queue - > IO_QUEUE_LRW ,
__genwqe_readq ( cd , queue - > IO_QUEUE_LRW ) ) ;
seq_printf ( s , " DDCB list (ddcb_act=%d/ddcb_next=%d): \n " ,
queue - > ddcb_act , queue - > ddcb_next ) ;
pddcb = queue - > ddcb_vaddr ;
for ( i = 0 ; i < queue - > ddcb_max ; i + + ) {
seq_printf ( s , " %-3d: RETC=%03x SEQ=%04x HSI/SHI=%02x/%02x " ,
i , be16_to_cpu ( pddcb - > retc_16 ) ,
be16_to_cpu ( pddcb - > seqnum_16 ) ,
pddcb - > hsi , pddcb - > shi ) ;
seq_printf ( s , " PRIV=%06llx CMD=%02x \n " ,
be64_to_cpu ( pddcb - > priv_64 ) , pddcb - > cmd ) ;
pddcb + + ;
}
return 0 ;
}
2018-12-01 20:05:30 +03:00
DEFINE_SHOW_ATTRIBUTE ( ddcb_info ) ;
2013-12-09 16:30:42 +04:00
2018-12-01 20:05:30 +03:00
static int info_show ( struct seq_file * s , void * unused )
2013-12-09 16:30:42 +04:00
{
struct genwqe_dev * cd = s - > private ;
u64 app_id , slu_id , bitstream = - 1 ;
struct pci_dev * pci_dev = cd - > pci_dev ;
slu_id = __genwqe_readq ( cd , IO_SLU_UNITCFG ) ;
app_id = __genwqe_readq ( cd , IO_APP_UNITCFG ) ;
if ( genwqe_is_privileged ( cd ) )
bitstream = __genwqe_readq ( cd , IO_SLU_BITSTREAM ) ;
seq_printf ( s , " %s driver version: %s \n "
" Device Name/Type: %s %s CardIdx: %d \n "
" SLU/APP Config : 0x%016llx/0x%016llx \n "
" Build Date : %u/%x/%u \n "
" Base Clock : %u MHz \n "
" Arch/SVN Release: %u/%llx \n "
" Bitstream : %llx \n " ,
2014-09-10 18:37:47 +04:00
GENWQE_DEVNAME , DRV_VERSION , dev_name ( & pci_dev - > dev ) ,
2013-12-09 16:30:42 +04:00
genwqe_is_privileged ( cd ) ?
" Physical " : " Virtual or no SR-IOV " ,
cd - > card_idx , slu_id , app_id ,
( u16 ) ( ( slu_id > > 12 ) & 0x0fLLU ) , /* month */
( u16 ) ( ( slu_id > > 4 ) & 0xffLLU ) , /* day */
( u16 ) ( ( slu_id > > 16 ) & 0x0fLLU ) + 2010 , /* year */
genwqe_base_clock_frequency ( cd ) ,
( u16 ) ( ( slu_id > > 32 ) & 0xffLLU ) , slu_id > > 40 ,
bitstream ) ;
return 0 ;
}
2018-12-01 20:05:30 +03:00
DEFINE_SHOW_ATTRIBUTE ( info ) ;
2013-12-09 16:30:42 +04:00
2019-06-11 21:41:07 +03:00
void genwqe_init_debugfs ( struct genwqe_dev * cd )
2013-12-09 16:30:42 +04:00
{
struct dentry * root ;
char card_name [ 64 ] ;
char name [ 64 ] ;
unsigned int i ;
2014-04-24 07:25:49 +04:00
sprintf ( card_name , " %s%d_card " , GENWQE_DEVNAME , cd - > card_idx ) ;
2013-12-09 16:30:42 +04:00
root = debugfs_create_dir ( card_name , cd - > debugfs_genwqe ) ;
/* non privileged interfaces are done here */
2019-06-11 21:41:07 +03:00
debugfs_create_file ( " ddcb_info " , S_IRUGO , root , cd , & ddcb_info_fops ) ;
debugfs_create_file ( " info " , S_IRUGO , root , cd , & info_fops ) ;
debugfs_create_x64 ( " err_inject " , 0666 , root , & cd - > err_inject ) ;
debugfs_create_u32 ( " ddcb_software_timeout " , 0666 , root ,
& cd - > ddcb_software_timeout ) ;
debugfs_create_u32 ( " kill_timeout " , 0666 , root , & cd - > kill_timeout ) ;
2013-12-09 16:30:42 +04:00
/* privileged interfaces follow here */
if ( ! genwqe_is_privileged ( cd ) ) {
cd - > debugfs_root = root ;
2019-06-11 21:41:07 +03:00
return ;
2013-12-09 16:30:42 +04:00
}
2019-06-11 21:41:07 +03:00
debugfs_create_file ( " curr_regs " , S_IRUGO , root , cd , & curr_regs_fops ) ;
debugfs_create_file ( " curr_dbg_uid0 " , S_IRUGO , root , cd ,
& curr_dbg_uid0_fops ) ;
debugfs_create_file ( " curr_dbg_uid1 " , S_IRUGO , root , cd ,
& curr_dbg_uid1_fops ) ;
debugfs_create_file ( " curr_dbg_uid2 " , S_IRUGO , root , cd ,
& curr_dbg_uid2_fops ) ;
debugfs_create_file ( " prev_regs " , S_IRUGO , root , cd , & prev_regs_fops ) ;
debugfs_create_file ( " prev_dbg_uid0 " , S_IRUGO , root , cd ,
& prev_dbg_uid0_fops ) ;
debugfs_create_file ( " prev_dbg_uid1 " , S_IRUGO , root , cd ,
& prev_dbg_uid1_fops ) ;
debugfs_create_file ( " prev_dbg_uid2 " , S_IRUGO , root , cd ,
& prev_dbg_uid2_fops ) ;
2013-12-09 16:30:42 +04:00
for ( i = 0 ; i < GENWQE_MAX_VFS ; i + + ) {
2014-04-24 07:25:49 +04:00
sprintf ( name , " vf%u_jobtimeout_msec " , i ) ;
2019-06-11 21:41:07 +03:00
debugfs_create_u32 ( name , 0666 , root ,
& cd - > vf_jobtimeout_msec [ i ] ) ;
2013-12-09 16:30:42 +04:00
}
2019-06-11 21:41:07 +03:00
debugfs_create_file ( " jobtimer " , S_IRUGO , root , cd , & jtimer_fops ) ;
debugfs_create_file ( " queue_working_time " , S_IRUGO , root , cd ,
& queue_working_time_fops ) ;
debugfs_create_u32 ( " skip_recovery " , 0666 , root , & cd - > skip_recovery ) ;
debugfs_create_u32 ( " use_platform_recovery " , 0666 , root ,
& cd - > use_platform_recovery ) ;
2014-06-04 17:57:51 +04:00
2013-12-09 16:30:42 +04:00
cd - > debugfs_root = root ;
}
void genqwe_exit_debugfs ( struct genwqe_dev * cd )
{
debugfs_remove_recursive ( cd - > debugfs_root ) ;
}