2011-10-20 19:24:15 +04:00
/*
* Remote Processor Framework
*
* Copyright ( C ) 2011 Texas Instruments , Inc .
* Copyright ( C ) 2011 Google , Inc .
*
* Ohad Ben - Cohen < ohad @ wizery . com >
* Mark Grosen < mgrosen @ ti . com >
* Brian Swetland < swetland @ google . com >
* Fernando Guzman Lugo < fernando . lugo @ ti . com >
* Suman Anna < s - anna @ ti . com >
* Robert Tivy < rtivy @ ti . com >
* Armando Uribe De Leon < x0095078 @ ti . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# define pr_fmt(fmt) "%s: " fmt, __func__
# include <linux/kernel.h>
# include <linux/debugfs.h>
# include <linux/remoteproc.h>
# include <linux/device.h>
2012-09-18 13:26:35 +04:00
# include <linux/uaccess.h>
# include "remoteproc_internal.h"
2011-10-20 19:24:15 +04:00
/* remoteproc debugfs parent dir */
static struct dentry * rproc_dbg ;
/*
* Some remote processors may support dumping trace logs into a shared
* memory buffer . We expose this trace buffer using debugfs , so users
* can easily tell what ' s going on remotely .
*
* We will most probably improve the rproc tracing facilities later on ,
* but this kind of lightweight and simple mechanism is always good to have ,
* as it provides very early tracing with little to no dependencies at all .
*/
static ssize_t rproc_trace_read ( struct file * filp , char __user * userbuf ,
size_t count , loff_t * ppos )
{
struct rproc_mem_entry * trace = filp - > private_data ;
int len = strnlen ( trace - > va , trace - > len ) ;
return simple_read_from_buffer ( userbuf , count , ppos , trace - > va , len ) ;
}
static const struct file_operations trace_rproc_ops = {
. read = rproc_trace_read ,
2012-04-06 01:25:11 +04:00
. open = simple_open ,
2011-10-20 19:24:15 +04:00
. llseek = generic_file_llseek ,
} ;
/*
* A state - to - string lookup table , for exposing a human readable state
* via debugfs . Always keep in sync with enum rproc_state
*/
static const char * const rproc_state_string [ ] = {
" offline " ,
" suspended " ,
" running " ,
" crashed " ,
" invalid " ,
} ;
/* expose the state of the remote processor via debugfs */
static ssize_t rproc_state_read ( struct file * filp , char __user * userbuf ,
size_t count , loff_t * ppos )
{
struct rproc * rproc = filp - > private_data ;
unsigned int state ;
char buf [ 30 ] ;
int i ;
state = rproc - > state > RPROC_LAST ? RPROC_LAST : rproc - > state ;
2012-09-25 11:02:51 +04:00
i = scnprintf ( buf , 30 , " %.28s (%d) \n " , rproc_state_string [ state ] ,
2011-10-20 19:24:15 +04:00
rproc - > state ) ;
return simple_read_from_buffer ( userbuf , count , ppos , buf , i ) ;
}
static const struct file_operations rproc_state_ops = {
. read = rproc_state_read ,
2012-04-06 01:25:11 +04:00
. open = simple_open ,
2011-10-20 19:24:15 +04:00
. llseek = generic_file_llseek ,
} ;
/* expose the name of the remote processor via debugfs */
static ssize_t rproc_name_read ( struct file * filp , char __user * userbuf ,
size_t count , loff_t * ppos )
{
struct rproc * rproc = filp - > private_data ;
/* need room for the name, a newline and a terminating null */
char buf [ 100 ] ;
int i ;
2012-09-25 11:02:51 +04:00
i = scnprintf ( buf , sizeof ( buf ) , " %.98s \n " , rproc - > name ) ;
2011-10-20 19:24:15 +04:00
return simple_read_from_buffer ( userbuf , count , ppos , buf , i ) ;
}
static const struct file_operations rproc_name_ops = {
. read = rproc_name_read ,
2012-04-06 01:25:11 +04:00
. open = simple_open ,
2011-10-20 19:24:15 +04:00
. llseek = generic_file_llseek ,
} ;
2012-09-18 13:26:35 +04:00
/* expose recovery flag via debugfs */
static ssize_t rproc_recovery_read ( struct file * filp , char __user * userbuf ,
size_t count , loff_t * ppos )
{
struct rproc * rproc = filp - > private_data ;
char * buf = rproc - > recovery_disabled ? " disabled \n " : " enabled \n " ;
return simple_read_from_buffer ( userbuf , count , ppos , buf , strlen ( buf ) ) ;
}
/*
* By writing to the ' recovery ' debugfs entry , we control the behavior of the
* recovery mechanism dynamically . The default value of this entry is " enabled " .
*
* The ' recovery ' debugfs entry supports these commands :
*
* enabled : When enabled , the remote processor will be automatically
* recovered whenever it crashes . Moreover , if the remote
* processor crashes while recovery is disabled , it will
* be automatically recovered too as soon as recovery is enabled .
*
* disabled : When disabled , a remote processor will remain in a crashed
* state if it crashes . This is useful for debugging purposes ;
* without it , debugging a crash is substantially harder .
*
* recover : This function will trigger an immediate recovery if the
* remote processor is in a crashed state , without changing
* or checking the recovery state ( enabled / disabled ) .
* This is useful during debugging sessions , when one expects
* additional crashes to happen after enabling recovery . In this
* case , enabling recovery will make it hard to debug subsequent
* crashes , so it ' s recommended to keep recovery disabled , and
* instead use the " recover " command as needed .
*/
static ssize_t
rproc_recovery_write ( struct file * filp , const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct rproc * rproc = filp - > private_data ;
char buf [ 10 ] ;
int ret ;
if ( count > sizeof ( buf ) )
return count ;
ret = copy_from_user ( buf , user_buf , count ) ;
if ( ret )
2012-09-25 11:05:33 +04:00
return - EFAULT ;
2012-09-18 13:26:35 +04:00
/* remove end of line */
if ( buf [ count - 1 ] = = ' \n ' )
buf [ count - 1 ] = ' \0 ' ;
if ( ! strncmp ( buf , " enabled " , count ) ) {
rproc - > recovery_disabled = false ;
/* if rproc has crashed, trigger recovery */
if ( rproc - > state = = RPROC_CRASHED )
rproc_trigger_recovery ( rproc ) ;
} else if ( ! strncmp ( buf , " disabled " , count ) ) {
rproc - > recovery_disabled = true ;
} else if ( ! strncmp ( buf , " recover " , count ) ) {
/* if rproc has crashed, trigger recovery */
if ( rproc - > state = = RPROC_CRASHED )
rproc_trigger_recovery ( rproc ) ;
}
return count ;
}
static const struct file_operations rproc_recovery_ops = {
. read = rproc_recovery_read ,
. write = rproc_recovery_write ,
. open = simple_open ,
. llseek = generic_file_llseek ,
} ;
2011-10-20 19:24:15 +04:00
void rproc_remove_trace_file ( struct dentry * tfile )
{
debugfs_remove ( tfile ) ;
}
struct dentry * rproc_create_trace_file ( const char * name , struct rproc * rproc ,
struct rproc_mem_entry * trace )
{
struct dentry * tfile ;
tfile = debugfs_create_file ( name , 0400 , rproc - > dbg_dir ,
trace , & trace_rproc_ops ) ;
if ( ! tfile ) {
remoteproc: maintain a generic child device for each rproc
For each registered rproc, maintain a generic remoteproc device whose
parent is the low level platform-specific device (commonly a pdev, but
it may certainly be any other type of device too).
With this in hand, the resulting device hierarchy might then look like:
omap-rproc.0
|
- remoteproc0 <---- new !
|
- virtio0
|
- virtio1
|
- rpmsg0
|
- rpmsg1
|
- rpmsg2
Where:
- omap-rproc.0 is the low level device that's bound to the
driver which invokes rproc_register()
- remoteproc0 is the result of this patch, and will be added by the
remoteproc framework when rproc_register() is invoked
- virtio0 and virtio1 are vdevs that are registered by remoteproc
when it realizes that they are supported by the firmware
of the physical remote processor represented by omap-rproc.0
- rpmsg0, rpmsg1 and rpmsg2 are rpmsg devices that represent rpmsg
channels, and are registerd by the rpmsg bus when it gets notified
about their existence
Technically, this patch:
- changes 'struct rproc' to contain this generic remoteproc.x device
- creates a new "remoteproc" type, to which this new generic remoteproc.x
device belong to.
- adds a super simple enumeration method for the indices of the
remoteproc.x devices
- updates all dev_* messaging to use the generic remoteproc.x device
instead of the low level platform-specific device
- updates all dma_* allocations to use the parent of remoteproc.x (where
the platform-specific memory pools, most commonly CMA, are to be found)
Adding this generic device has several merits:
- we can now add remoteproc runtime PM support simply by hooking onto the
new "remoteproc" type
- all remoteproc log messages will now carry a common name prefix
instead of having a platform-specific one
- having a device as part of the rproc struct makes it possible to simplify
refcounting (see subsequent patch)
Thanks to Stephen Boyd <sboyd@codeaurora.org> for suggesting and
discussing these ideas in one of the remoteproc review threads and
to Fernando Guzman Lugo <fernando.lugo@ti.com> for trying them out
with the (upcoming) runtime PM support for remoteproc.
Cc: Fernando Guzman Lugo <fernando.lugo@ti.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
2012-05-30 23:01:25 +04:00
dev_err ( & rproc - > dev , " failed to create debugfs trace entry \n " ) ;
2011-10-20 19:24:15 +04:00
return NULL ;
}
return tfile ;
}
void rproc_delete_debug_dir ( struct rproc * rproc )
{
if ( ! rproc - > dbg_dir )
return ;
debugfs_remove_recursive ( rproc - > dbg_dir ) ;
}
void rproc_create_debug_dir ( struct rproc * rproc )
{
remoteproc: maintain a generic child device for each rproc
For each registered rproc, maintain a generic remoteproc device whose
parent is the low level platform-specific device (commonly a pdev, but
it may certainly be any other type of device too).
With this in hand, the resulting device hierarchy might then look like:
omap-rproc.0
|
- remoteproc0 <---- new !
|
- virtio0
|
- virtio1
|
- rpmsg0
|
- rpmsg1
|
- rpmsg2
Where:
- omap-rproc.0 is the low level device that's bound to the
driver which invokes rproc_register()
- remoteproc0 is the result of this patch, and will be added by the
remoteproc framework when rproc_register() is invoked
- virtio0 and virtio1 are vdevs that are registered by remoteproc
when it realizes that they are supported by the firmware
of the physical remote processor represented by omap-rproc.0
- rpmsg0, rpmsg1 and rpmsg2 are rpmsg devices that represent rpmsg
channels, and are registerd by the rpmsg bus when it gets notified
about their existence
Technically, this patch:
- changes 'struct rproc' to contain this generic remoteproc.x device
- creates a new "remoteproc" type, to which this new generic remoteproc.x
device belong to.
- adds a super simple enumeration method for the indices of the
remoteproc.x devices
- updates all dev_* messaging to use the generic remoteproc.x device
instead of the low level platform-specific device
- updates all dma_* allocations to use the parent of remoteproc.x (where
the platform-specific memory pools, most commonly CMA, are to be found)
Adding this generic device has several merits:
- we can now add remoteproc runtime PM support simply by hooking onto the
new "remoteproc" type
- all remoteproc log messages will now carry a common name prefix
instead of having a platform-specific one
- having a device as part of the rproc struct makes it possible to simplify
refcounting (see subsequent patch)
Thanks to Stephen Boyd <sboyd@codeaurora.org> for suggesting and
discussing these ideas in one of the remoteproc review threads and
to Fernando Guzman Lugo <fernando.lugo@ti.com> for trying them out
with the (upcoming) runtime PM support for remoteproc.
Cc: Fernando Guzman Lugo <fernando.lugo@ti.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
2012-05-30 23:01:25 +04:00
struct device * dev = & rproc - > dev ;
2011-10-20 19:24:15 +04:00
if ( ! rproc_dbg )
return ;
rproc - > dbg_dir = debugfs_create_dir ( dev_name ( dev ) , rproc_dbg ) ;
if ( ! rproc - > dbg_dir )
return ;
debugfs_create_file ( " name " , 0400 , rproc - > dbg_dir ,
rproc , & rproc_name_ops ) ;
debugfs_create_file ( " state " , 0400 , rproc - > dbg_dir ,
rproc , & rproc_state_ops ) ;
2012-09-18 13:26:35 +04:00
debugfs_create_file ( " recovery " , 0400 , rproc - > dbg_dir ,
rproc , & rproc_recovery_ops ) ;
2011-10-20 19:24:15 +04:00
}
void __init rproc_init_debugfs ( void )
{
if ( debugfs_initialized ( ) ) {
rproc_dbg = debugfs_create_dir ( KBUILD_MODNAME , NULL ) ;
if ( ! rproc_dbg )
pr_err ( " can't create debugfs dir \n " ) ;
}
}
void __exit rproc_exit_debugfs ( void )
{
2013-06-30 12:33:05 +04:00
debugfs_remove ( rproc_dbg ) ;
2011-10-20 19:24:15 +04:00
}