2019-05-29 17:18:02 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2017-10-03 09:12:13 +03:00
/*
* Copyright ( c ) 2017 , NVIDIA CORPORATION . All rights reserved .
*/
# include <linux/debugfs.h>
# include <linux/dma-mapping.h>
2020-07-12 13:01:17 +03:00
# include <linux/slab.h>
2017-10-03 09:12:13 +03:00
# include <linux/uaccess.h>
# include <soc/tegra/bpmp.h>
# include <soc/tegra/bpmp-abi.h>
2020-07-12 13:01:17 +03:00
static DEFINE_MUTEX ( bpmp_debug_lock ) ;
2017-10-03 09:12:13 +03:00
struct seqbuf {
char * buf ;
size_t pos ;
size_t size ;
} ;
static void seqbuf_init ( struct seqbuf * seqbuf , void * buf , size_t size )
{
seqbuf - > buf = buf ;
seqbuf - > size = size ;
seqbuf - > pos = 0 ;
}
static size_t seqbuf_avail ( struct seqbuf * seqbuf )
{
return seqbuf - > pos < seqbuf - > size ? seqbuf - > size - seqbuf - > pos : 0 ;
}
static size_t seqbuf_status ( struct seqbuf * seqbuf )
{
return seqbuf - > pos < = seqbuf - > size ? 0 : - EOVERFLOW ;
}
static int seqbuf_eof ( struct seqbuf * seqbuf )
{
return seqbuf - > pos > = seqbuf - > size ;
}
static int seqbuf_read ( struct seqbuf * seqbuf , void * buf , size_t nbyte )
{
nbyte = min ( nbyte , seqbuf_avail ( seqbuf ) ) ;
memcpy ( buf , seqbuf - > buf + seqbuf - > pos , nbyte ) ;
seqbuf - > pos + = nbyte ;
return seqbuf_status ( seqbuf ) ;
}
static int seqbuf_read_u32 ( struct seqbuf * seqbuf , uint32_t * v )
{
int err ;
err = seqbuf_read ( seqbuf , v , 4 ) ;
* v = le32_to_cpu ( * v ) ;
return err ;
}
static int seqbuf_read_str ( struct seqbuf * seqbuf , const char * * str )
{
* str = seqbuf - > buf + seqbuf - > pos ;
seqbuf - > pos + = strnlen ( * str , seqbuf_avail ( seqbuf ) ) ;
seqbuf - > pos + + ;
return seqbuf_status ( seqbuf ) ;
}
static void seqbuf_seek ( struct seqbuf * seqbuf , ssize_t offset )
{
seqbuf - > pos + = offset ;
}
/* map filename in Linux debugfs to corresponding entry in BPMP */
static const char * get_filename ( struct tegra_bpmp * bpmp ,
const struct file * file , char * buf , int size )
{
char root_path_buf [ 512 ] ;
const char * root_path ;
const char * filename ;
size_t root_len ;
root_path = dentry_path ( bpmp - > debugfs_mirror , root_path_buf ,
sizeof ( root_path_buf ) ) ;
if ( IS_ERR ( root_path ) )
return NULL ;
root_len = strlen ( root_path ) ;
filename = dentry_path ( file - > f_path . dentry , buf , size ) ;
if ( IS_ERR ( filename ) )
return NULL ;
if ( strlen ( filename ) < root_len | |
strncmp ( filename , root_path , root_len ) )
return NULL ;
filename + = root_len ;
return filename ;
}
2020-07-12 13:01:17 +03:00
static int mrq_debug_open ( struct tegra_bpmp * bpmp , const char * name ,
uint32_t * fd , uint32_t * len , bool write )
{
struct mrq_debug_request req = {
. cmd = cpu_to_le32 ( write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO ) ,
} ;
struct mrq_debug_response resp ;
struct tegra_bpmp_message msg = {
. mrq = MRQ_DEBUG ,
. tx = {
. data = & req ,
. size = sizeof ( req ) ,
} ,
. rx = {
. data = & resp ,
. size = sizeof ( resp ) ,
} ,
} ;
ssize_t sz_name ;
int err = 0 ;
sz_name = strscpy ( req . fop . name , name , sizeof ( req . fop . name ) ) ;
if ( sz_name < 0 ) {
pr_err ( " File name too large: %s \n " , name ) ;
return - EINVAL ;
}
err = tegra_bpmp_transfer ( bpmp , & msg ) ;
if ( err < 0 )
return err ;
else if ( msg . rx . ret < 0 )
return - EINVAL ;
* len = resp . fop . datalen ;
* fd = resp . fop . fd ;
return 0 ;
}
static int mrq_debug_close ( struct tegra_bpmp * bpmp , uint32_t fd )
{
struct mrq_debug_request req = {
. cmd = cpu_to_le32 ( CMD_DEBUG_CLOSE ) ,
. frd = {
. fd = fd ,
} ,
} ;
struct mrq_debug_response resp ;
struct tegra_bpmp_message msg = {
. mrq = MRQ_DEBUG ,
. tx = {
. data = & req ,
. size = sizeof ( req ) ,
} ,
. rx = {
. data = & resp ,
. size = sizeof ( resp ) ,
} ,
} ;
int err = 0 ;
err = tegra_bpmp_transfer ( bpmp , & msg ) ;
if ( err < 0 )
return err ;
else if ( msg . rx . ret < 0 )
return - EINVAL ;
return 0 ;
}
static int mrq_debug_read ( struct tegra_bpmp * bpmp , const char * name ,
char * data , size_t sz_data , uint32_t * nbytes )
{
struct mrq_debug_request req = {
. cmd = cpu_to_le32 ( CMD_DEBUG_READ ) ,
} ;
struct mrq_debug_response resp ;
struct tegra_bpmp_message msg = {
. mrq = MRQ_DEBUG ,
. tx = {
. data = & req ,
. size = sizeof ( req ) ,
} ,
. rx = {
. data = & resp ,
. size = sizeof ( resp ) ,
} ,
} ;
uint32_t fd = 0 , len = 0 ;
int remaining , err ;
mutex_lock ( & bpmp_debug_lock ) ;
err = mrq_debug_open ( bpmp , name , & fd , & len , 0 ) ;
if ( err )
goto out ;
if ( len > sz_data ) {
err = - EFBIG ;
goto close ;
}
req . frd . fd = fd ;
remaining = len ;
while ( remaining > 0 ) {
err = tegra_bpmp_transfer ( bpmp , & msg ) ;
if ( err < 0 ) {
goto close ;
} else if ( msg . rx . ret < 0 ) {
err = - EINVAL ;
goto close ;
}
if ( resp . frd . readlen > remaining ) {
pr_err ( " %s: read data length invalid \n " , __func__ ) ;
err = - EINVAL ;
goto close ;
}
memcpy ( data , resp . frd . data , resp . frd . readlen ) ;
data + = resp . frd . readlen ;
remaining - = resp . frd . readlen ;
}
* nbytes = len ;
close :
err = mrq_debug_close ( bpmp , fd ) ;
out :
mutex_unlock ( & bpmp_debug_lock ) ;
return err ;
}
static int mrq_debug_write ( struct tegra_bpmp * bpmp , const char * name ,
uint8_t * data , size_t sz_data )
{
struct mrq_debug_request req = {
. cmd = cpu_to_le32 ( CMD_DEBUG_WRITE )
} ;
struct mrq_debug_response resp ;
struct tegra_bpmp_message msg = {
. mrq = MRQ_DEBUG ,
. tx = {
. data = & req ,
. size = sizeof ( req ) ,
} ,
. rx = {
. data = & resp ,
. size = sizeof ( resp ) ,
} ,
} ;
uint32_t fd = 0 , len = 0 ;
size_t remaining ;
int err ;
mutex_lock ( & bpmp_debug_lock ) ;
err = mrq_debug_open ( bpmp , name , & fd , & len , 1 ) ;
if ( err )
goto out ;
if ( sz_data > len ) {
err = - EINVAL ;
goto close ;
}
req . fwr . fd = fd ;
remaining = sz_data ;
while ( remaining > 0 ) {
len = min ( remaining , sizeof ( req . fwr . data ) ) ;
memcpy ( req . fwr . data , data , len ) ;
req . fwr . datalen = len ;
err = tegra_bpmp_transfer ( bpmp , & msg ) ;
if ( err < 0 ) {
goto close ;
} else if ( msg . rx . ret < 0 ) {
err = - EINVAL ;
goto close ;
}
data + = req . fwr . datalen ;
remaining - = req . fwr . datalen ;
}
close :
err = mrq_debug_close ( bpmp , fd ) ;
out :
mutex_unlock ( & bpmp_debug_lock ) ;
return err ;
}
static int bpmp_debug_show ( struct seq_file * m , void * p )
{
struct file * file = m - > private ;
struct inode * inode = file_inode ( file ) ;
struct tegra_bpmp * bpmp = inode - > i_private ;
char fnamebuf [ 256 ] ;
const char * filename ;
2021-08-10 18:54:39 +03:00
struct mrq_debug_request req = {
. cmd = cpu_to_le32 ( CMD_DEBUG_READ ) ,
} ;
struct mrq_debug_response resp ;
struct tegra_bpmp_message msg = {
. mrq = MRQ_DEBUG ,
. tx = {
. data = & req ,
. size = sizeof ( req ) ,
} ,
. rx = {
. data = & resp ,
. size = sizeof ( resp ) ,
} ,
} ;
uint32_t fd = 0 , len = 0 ;
int remaining , err ;
2020-07-12 13:01:17 +03:00
filename = get_filename ( bpmp , file , fnamebuf , sizeof ( fnamebuf ) ) ;
if ( ! filename )
return - ENOENT ;
2021-08-10 18:54:39 +03:00
mutex_lock ( & bpmp_debug_lock ) ;
err = mrq_debug_open ( bpmp , filename , & fd , & len , 0 ) ;
if ( err )
goto out ;
req . frd . fd = fd ;
remaining = len ;
while ( remaining > 0 ) {
err = tegra_bpmp_transfer ( bpmp , & msg ) ;
if ( err < 0 ) {
goto close ;
} else if ( msg . rx . ret < 0 ) {
err = - EINVAL ;
goto close ;
}
if ( resp . frd . readlen > remaining ) {
pr_err ( " %s: read data length invalid \n " , __func__ ) ;
err = - EINVAL ;
goto close ;
}
seq_write ( m , resp . frd . data , resp . frd . readlen ) ;
remaining - = resp . frd . readlen ;
}
2020-07-12 13:01:17 +03:00
2021-08-10 18:54:39 +03:00
close :
err = mrq_debug_close ( bpmp , fd ) ;
out :
mutex_unlock ( & bpmp_debug_lock ) ;
2020-07-12 13:01:17 +03:00
return err ;
}
static ssize_t bpmp_debug_store ( struct file * file , const char __user * buf ,
size_t count , loff_t * f_pos )
{
struct inode * inode = file_inode ( file ) ;
struct tegra_bpmp * bpmp = inode - > i_private ;
char * databuf = NULL ;
char fnamebuf [ 256 ] ;
const char * filename ;
ssize_t err ;
filename = get_filename ( bpmp , file , fnamebuf , sizeof ( fnamebuf ) ) ;
if ( ! filename )
return - ENOENT ;
databuf = kmalloc ( count , GFP_KERNEL ) ;
if ( ! databuf )
return - ENOMEM ;
if ( copy_from_user ( databuf , buf , count ) ) {
err = - EFAULT ;
goto free_ret ;
}
err = mrq_debug_write ( bpmp , filename , databuf , count ) ;
free_ret :
kfree ( databuf ) ;
return err ? : count ;
}
static int bpmp_debug_open ( struct inode * inode , struct file * file )
{
return single_open_size ( file , bpmp_debug_show , file , SZ_256K ) ;
}
static const struct file_operations bpmp_debug_fops = {
. open = bpmp_debug_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. write = bpmp_debug_store ,
. release = single_release ,
} ;
static int bpmp_populate_debugfs_inband ( struct tegra_bpmp * bpmp ,
struct dentry * parent ,
char * ppath )
{
const size_t pathlen = SZ_256 ;
const size_t bufsize = SZ_16K ;
uint32_t dsize , attrs = 0 ;
struct dentry * dentry ;
struct seqbuf seqbuf ;
char * buf , * pathbuf ;
const char * name ;
int err = 0 ;
if ( ! bpmp | | ! parent | | ! ppath )
return - EINVAL ;
buf = kmalloc ( bufsize , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
pathbuf = kzalloc ( pathlen , GFP_KERNEL ) ;
if ( ! pathbuf ) {
kfree ( buf ) ;
return - ENOMEM ;
}
err = mrq_debug_read ( bpmp , ppath , buf , bufsize , & dsize ) ;
if ( err )
goto out ;
seqbuf_init ( & seqbuf , buf , dsize ) ;
while ( ! seqbuf_eof ( & seqbuf ) ) {
err = seqbuf_read_u32 ( & seqbuf , & attrs ) ;
if ( err )
goto out ;
err = seqbuf_read_str ( & seqbuf , & name ) ;
if ( err < 0 )
goto out ;
if ( attrs & DEBUGFS_S_ISDIR ) {
size_t len ;
dentry = debugfs_create_dir ( name , parent ) ;
if ( IS_ERR ( dentry ) ) {
err = PTR_ERR ( dentry ) ;
goto out ;
}
2020-10-26 19:49:21 +03:00
len = snprintf ( pathbuf , pathlen , " %s%s/ " , ppath , name ) ;
2020-07-12 13:01:17 +03:00
if ( len > = pathlen ) {
err = - EINVAL ;
goto out ;
}
err = bpmp_populate_debugfs_inband ( bpmp , dentry ,
pathbuf ) ;
if ( err < 0 )
goto out ;
} else {
umode_t mode ;
mode = attrs & DEBUGFS_S_IRUSR ? 0400 : 0 ;
mode | = attrs & DEBUGFS_S_IWUSR ? 0200 : 0 ;
dentry = debugfs_create_file ( name , mode , parent , bpmp ,
& bpmp_debug_fops ) ;
if ( ! dentry ) {
err = - ENOMEM ;
goto out ;
}
}
}
out :
kfree ( pathbuf ) ;
kfree ( buf ) ;
return err ;
}
2017-10-03 09:12:13 +03:00
static int mrq_debugfs_read ( struct tegra_bpmp * bpmp ,
dma_addr_t name , size_t sz_name ,
dma_addr_t data , size_t sz_data ,
size_t * nbytes )
{
struct mrq_debugfs_request req = {
. cmd = cpu_to_le32 ( CMD_DEBUGFS_READ ) ,
. fop = {
. fnameaddr = cpu_to_le32 ( ( uint32_t ) name ) ,
. fnamelen = cpu_to_le32 ( ( uint32_t ) sz_name ) ,
. dataaddr = cpu_to_le32 ( ( uint32_t ) data ) ,
. datalen = cpu_to_le32 ( ( uint32_t ) sz_data ) ,
} ,
} ;
struct mrq_debugfs_response resp ;
struct tegra_bpmp_message msg = {
. mrq = MRQ_DEBUGFS ,
. tx = {
. data = & req ,
. size = sizeof ( req ) ,
} ,
. rx = {
. data = & resp ,
. size = sizeof ( resp ) ,
} ,
} ;
int err ;
err = tegra_bpmp_transfer ( bpmp , & msg ) ;
if ( err < 0 )
return err ;
2020-07-12 13:01:14 +03:00
else if ( msg . rx . ret < 0 )
return - EINVAL ;
2017-10-03 09:12:13 +03:00
* nbytes = ( size_t ) resp . fop . nbytes ;
return 0 ;
}
static int mrq_debugfs_write ( struct tegra_bpmp * bpmp ,
dma_addr_t name , size_t sz_name ,
dma_addr_t data , size_t sz_data )
{
const struct mrq_debugfs_request req = {
. cmd = cpu_to_le32 ( CMD_DEBUGFS_WRITE ) ,
. fop = {
. fnameaddr = cpu_to_le32 ( ( uint32_t ) name ) ,
. fnamelen = cpu_to_le32 ( ( uint32_t ) sz_name ) ,
. dataaddr = cpu_to_le32 ( ( uint32_t ) data ) ,
. datalen = cpu_to_le32 ( ( uint32_t ) sz_data ) ,
} ,
} ;
struct tegra_bpmp_message msg = {
. mrq = MRQ_DEBUGFS ,
. tx = {
. data = & req ,
. size = sizeof ( req ) ,
} ,
} ;
return tegra_bpmp_transfer ( bpmp , & msg ) ;
}
static int mrq_debugfs_dumpdir ( struct tegra_bpmp * bpmp , dma_addr_t addr ,
size_t size , size_t * nbytes )
{
const struct mrq_debugfs_request req = {
. cmd = cpu_to_le32 ( CMD_DEBUGFS_DUMPDIR ) ,
. dumpdir = {
. dataaddr = cpu_to_le32 ( ( uint32_t ) addr ) ,
. datalen = cpu_to_le32 ( ( uint32_t ) size ) ,
} ,
} ;
struct mrq_debugfs_response resp ;
struct tegra_bpmp_message msg = {
. mrq = MRQ_DEBUGFS ,
. tx = {
. data = & req ,
. size = sizeof ( req ) ,
} ,
. rx = {
. data = & resp ,
. size = sizeof ( resp ) ,
} ,
} ;
int err ;
err = tegra_bpmp_transfer ( bpmp , & msg ) ;
if ( err < 0 )
return err ;
2020-07-12 13:01:14 +03:00
else if ( msg . rx . ret < 0 )
return - EINVAL ;
2017-10-03 09:12:13 +03:00
* nbytes = ( size_t ) resp . dumpdir . nbytes ;
return 0 ;
}
static int debugfs_show ( struct seq_file * m , void * p )
{
struct file * file = m - > private ;
struct inode * inode = file_inode ( file ) ;
struct tegra_bpmp * bpmp = inode - > i_private ;
const size_t datasize = m - > size ;
const size_t namesize = SZ_256 ;
void * datavirt , * namevirt ;
dma_addr_t dataphys , namephys ;
char buf [ 256 ] ;
const char * filename ;
size_t len , nbytes ;
2020-07-12 13:01:15 +03:00
int err ;
2017-10-03 09:12:13 +03:00
filename = get_filename ( bpmp , file , buf , sizeof ( buf ) ) ;
if ( ! filename )
return - ENOENT ;
namevirt = dma_alloc_coherent ( bpmp - > dev , namesize , & namephys ,
GFP_KERNEL | GFP_DMA32 ) ;
if ( ! namevirt )
return - ENOMEM ;
datavirt = dma_alloc_coherent ( bpmp - > dev , datasize , & dataphys ,
GFP_KERNEL | GFP_DMA32 ) ;
if ( ! datavirt ) {
2020-07-12 13:01:15 +03:00
err = - ENOMEM ;
2017-10-03 09:12:13 +03:00
goto free_namebuf ;
}
len = strlen ( filename ) ;
strncpy ( namevirt , filename , namesize ) ;
2020-07-12 13:01:15 +03:00
err = mrq_debugfs_read ( bpmp , namephys , len , dataphys , datasize ,
2017-10-03 09:12:13 +03:00
& nbytes ) ;
2020-07-12 13:01:15 +03:00
if ( ! err )
2017-10-03 09:12:13 +03:00
seq_write ( m , datavirt , nbytes ) ;
dma_free_coherent ( bpmp - > dev , datasize , datavirt , dataphys ) ;
free_namebuf :
dma_free_coherent ( bpmp - > dev , namesize , namevirt , namephys ) ;
2020-07-12 13:01:15 +03:00
return err ;
2017-10-03 09:12:13 +03:00
}
static int debugfs_open ( struct inode * inode , struct file * file )
{
return single_open_size ( file , debugfs_show , file , SZ_128K ) ;
}
static ssize_t debugfs_store ( struct file * file , const char __user * buf ,
size_t count , loff_t * f_pos )
{
struct inode * inode = file_inode ( file ) ;
struct tegra_bpmp * bpmp = inode - > i_private ;
const size_t datasize = count ;
const size_t namesize = SZ_256 ;
void * datavirt , * namevirt ;
dma_addr_t dataphys , namephys ;
char fnamebuf [ 256 ] ;
const char * filename ;
size_t len ;
2020-07-12 13:01:15 +03:00
int err ;
2017-10-03 09:12:13 +03:00
filename = get_filename ( bpmp , file , fnamebuf , sizeof ( fnamebuf ) ) ;
if ( ! filename )
return - ENOENT ;
namevirt = dma_alloc_coherent ( bpmp - > dev , namesize , & namephys ,
GFP_KERNEL | GFP_DMA32 ) ;
if ( ! namevirt )
return - ENOMEM ;
datavirt = dma_alloc_coherent ( bpmp - > dev , datasize , & dataphys ,
GFP_KERNEL | GFP_DMA32 ) ;
if ( ! datavirt ) {
2020-07-12 13:01:15 +03:00
err = - ENOMEM ;
2017-10-03 09:12:13 +03:00
goto free_namebuf ;
}
len = strlen ( filename ) ;
strncpy ( namevirt , filename , namesize ) ;
if ( copy_from_user ( datavirt , buf , count ) ) {
2020-07-12 13:01:15 +03:00
err = - EFAULT ;
2017-10-03 09:12:13 +03:00
goto free_databuf ;
}
2020-07-12 13:01:15 +03:00
err = mrq_debugfs_write ( bpmp , namephys , len , dataphys ,
2017-10-03 09:12:13 +03:00
count ) ;
free_databuf :
dma_free_coherent ( bpmp - > dev , datasize , datavirt , dataphys ) ;
free_namebuf :
dma_free_coherent ( bpmp - > dev , namesize , namevirt , namephys ) ;
2020-07-12 13:01:15 +03:00
return err ? : count ;
2017-10-03 09:12:13 +03:00
}
static const struct file_operations debugfs_fops = {
. open = debugfs_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. write = debugfs_store ,
. release = single_release ,
} ;
static int bpmp_populate_dir ( struct tegra_bpmp * bpmp , struct seqbuf * seqbuf ,
struct dentry * parent , uint32_t depth )
{
int err ;
uint32_t d , t ;
const char * name ;
struct dentry * dentry ;
while ( ! seqbuf_eof ( seqbuf ) ) {
err = seqbuf_read_u32 ( seqbuf , & d ) ;
if ( err < 0 )
return err ;
if ( d < depth ) {
seqbuf_seek ( seqbuf , - 4 ) ;
/* go up a level */
return 0 ;
} else if ( d ! = depth ) {
/* malformed data received from BPMP */
return - EIO ;
}
err = seqbuf_read_u32 ( seqbuf , & t ) ;
if ( err < 0 )
return err ;
err = seqbuf_read_str ( seqbuf , & name ) ;
if ( err < 0 )
return err ;
if ( t & DEBUGFS_S_ISDIR ) {
dentry = debugfs_create_dir ( name , parent ) ;
if ( ! dentry )
return - ENOMEM ;
err = bpmp_populate_dir ( bpmp , seqbuf , dentry , depth + 1 ) ;
if ( err < 0 )
return err ;
} else {
umode_t mode ;
mode = t & DEBUGFS_S_IRUSR ? S_IRUSR : 0 ;
mode | = t & DEBUGFS_S_IWUSR ? S_IWUSR : 0 ;
dentry = debugfs_create_file ( name , mode ,
parent , bpmp ,
& debugfs_fops ) ;
if ( ! dentry )
return - ENOMEM ;
}
}
return 0 ;
}
2020-07-12 13:01:17 +03:00
static int bpmp_populate_debugfs_shmem ( struct tegra_bpmp * bpmp )
2017-10-03 09:12:13 +03:00
{
struct seqbuf seqbuf ;
2020-07-12 13:01:16 +03:00
const size_t sz = SZ_512K ;
dma_addr_t phys ;
size_t nbytes ;
void * virt ;
2017-10-03 09:12:13 +03:00
int err ;
2020-07-12 13:01:16 +03:00
virt = dma_alloc_coherent ( bpmp - > dev , sz , & phys ,
GFP_KERNEL | GFP_DMA32 ) ;
if ( ! virt )
return - ENOMEM ;
err = mrq_debugfs_dumpdir ( bpmp , phys , sz , & nbytes ) ;
2017-10-03 09:12:13 +03:00
if ( err < 0 ) {
2020-07-12 13:01:16 +03:00
goto free ;
} else if ( nbytes > sz ) {
err = - EINVAL ;
goto free ;
2017-10-03 09:12:13 +03:00
}
2020-07-12 13:01:16 +03:00
seqbuf_init ( & seqbuf , virt , nbytes ) ;
err = bpmp_populate_dir ( bpmp , & seqbuf , bpmp - > debugfs_mirror , 0 ) ;
free :
dma_free_coherent ( bpmp - > dev , sz , virt , phys ) ;
2017-10-03 09:12:13 +03:00
return err ;
}
int tegra_bpmp_init_debugfs ( struct tegra_bpmp * bpmp )
{
struct dentry * root ;
2020-07-12 13:01:17 +03:00
bool inband ;
2020-07-12 13:01:15 +03:00
int err ;
2017-10-03 09:12:13 +03:00
2020-07-12 13:01:17 +03:00
inband = tegra_bpmp_mrq_is_supported ( bpmp , MRQ_DEBUG ) ;
if ( ! inband & & ! tegra_bpmp_mrq_is_supported ( bpmp , MRQ_DEBUGFS ) )
2017-10-03 09:12:13 +03:00
return 0 ;
root = debugfs_create_dir ( " bpmp " , NULL ) ;
if ( ! root )
return - ENOMEM ;
2020-07-12 13:01:17 +03:00
bpmp - > debugfs_mirror = debugfs_create_dir ( " debug " , root ) ;
if ( ! bpmp - > debugfs_mirror ) {
err = - ENOMEM ;
goto out ;
}
if ( inband )
err = bpmp_populate_debugfs_inband ( bpmp , bpmp - > debugfs_mirror ,
" / " ) ;
else
err = bpmp_populate_debugfs_shmem ( bpmp ) ;
out :
2020-07-12 13:01:15 +03:00
if ( err < 0 )
2020-07-12 13:01:16 +03:00
debugfs_remove_recursive ( root ) ;
2017-10-03 09:12:13 +03:00
2020-07-12 13:01:15 +03:00
return err ;
2017-10-03 09:12:13 +03:00
}