2007-07-19 12:49:36 +04:00
/*
* file for managing the edac_device class of devices for EDAC
*
2007-07-19 12:50:29 +04:00
* ( C ) 2007 SoftwareBitMaker ( http : //www.softwarebitmaker.com)
*
2007-07-19 12:49:36 +04:00
* This file may be distributed under the terms of the
* GNU General Public License .
*
* Written Doug Thompson < norsk5 @ xmission . com >
*
*/
# include <linux/ctype.h>
2007-07-19 12:50:29 +04:00
# include <linux/module.h>
2007-07-19 12:49:36 +04:00
# include "edac_core.h"
# include "edac_module.h"
# define EDAC_DEVICE_SYMLINK "device"
# define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj)
# define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr)
/*
* Set of edac_device_ctl_info attribute store / show functions
*/
/* 'log_ue' */
2007-07-19 12:49:58 +04:00
static ssize_t edac_device_ctl_log_ue_show ( struct edac_device_ctl_info
2007-07-19 12:50:13 +04:00
* ctl_info , char * data )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:49:58 +04:00
return sprintf ( data , " %u \n " , ctl_info - > log_ue ) ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:49:58 +04:00
static ssize_t edac_device_ctl_log_ue_store ( struct edac_device_ctl_info
2007-07-19 12:50:13 +04:00
* ctl_info , const char * data ,
size_t count )
2007-07-19 12:49:36 +04:00
{
/* if parameter is zero, turn off flag, if non-zero turn on flag */
2007-07-19 12:49:58 +04:00
ctl_info - > log_ue = ( simple_strtoul ( data , NULL , 0 ) ! = 0 ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:49:58 +04:00
return count ;
2007-07-19 12:49:36 +04:00
}
/* 'log_ce' */
2007-07-19 12:49:58 +04:00
static ssize_t edac_device_ctl_log_ce_show ( struct edac_device_ctl_info
2007-07-19 12:50:13 +04:00
* ctl_info , char * data )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:49:58 +04:00
return sprintf ( data , " %u \n " , ctl_info - > log_ce ) ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:49:58 +04:00
static ssize_t edac_device_ctl_log_ce_store ( struct edac_device_ctl_info
2007-07-19 12:50:13 +04:00
* ctl_info , const char * data ,
size_t count )
2007-07-19 12:49:36 +04:00
{
/* if parameter is zero, turn off flag, if non-zero turn on flag */
2007-07-19 12:49:58 +04:00
ctl_info - > log_ce = ( simple_strtoul ( data , NULL , 0 ) ! = 0 ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:49:58 +04:00
return count ;
2007-07-19 12:49:36 +04:00
}
/* 'panic_on_ue' */
2007-07-19 12:49:58 +04:00
static ssize_t edac_device_ctl_panic_on_ue_show ( struct edac_device_ctl_info
* ctl_info , char * data )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:49:58 +04:00
return sprintf ( data , " %u \n " , ctl_info - > panic_on_ue ) ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:49:58 +04:00
static ssize_t edac_device_ctl_panic_on_ue_store ( struct edac_device_ctl_info
* ctl_info , const char * data ,
size_t count )
2007-07-19 12:49:36 +04:00
{
/* if parameter is zero, turn off flag, if non-zero turn on flag */
2007-07-19 12:49:58 +04:00
ctl_info - > panic_on_ue = ( simple_strtoul ( data , NULL , 0 ) ! = 0 ) ;
2007-07-19 12:49:36 +04:00
return count ;
}
/* 'poll_msec' show and store functions*/
2007-07-19 12:49:58 +04:00
static ssize_t edac_device_ctl_poll_msec_show ( struct edac_device_ctl_info
2007-07-19 12:50:13 +04:00
* ctl_info , char * data )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:49:58 +04:00
return sprintf ( data , " %u \n " , ctl_info - > poll_msec ) ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:49:58 +04:00
static ssize_t edac_device_ctl_poll_msec_store ( struct edac_device_ctl_info
2007-07-19 12:50:13 +04:00
* ctl_info , const char * data ,
size_t count )
2007-07-19 12:49:36 +04:00
{
unsigned long value ;
/* get the value and enforce that it is non-zero, must be at least
* one millisecond for the delay period , between scans
* Then cancel last outstanding delay for the work request
* and set a new one .
*/
2007-07-19 12:49:58 +04:00
value = simple_strtoul ( data , NULL , 0 ) ;
edac_device_reset_delay_period ( ctl_info , value ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:49:58 +04:00
return count ;
2007-07-19 12:49:36 +04:00
}
/* edac_device_ctl_info specific attribute structure */
struct ctl_info_attribute {
2007-07-19 12:49:58 +04:00
struct attribute attr ;
2007-07-19 12:50:29 +04:00
ssize_t ( * show ) ( struct edac_device_ctl_info * , char * ) ;
ssize_t ( * store ) ( struct edac_device_ctl_info * , const char * , size_t ) ;
2007-07-19 12:49:36 +04:00
} ;
# define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj)
# define to_ctl_info_attr(a) container_of(a,struct ctl_info_attribute,attr)
/* Function to 'show' fields from the edac_dev 'ctl_info' structure */
static ssize_t edac_dev_ctl_info_show ( struct kobject * kobj ,
2007-07-19 12:50:13 +04:00
struct attribute * attr , char * buffer )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:49:58 +04:00
struct edac_device_ctl_info * edac_dev = to_ctl_info ( kobj ) ;
struct ctl_info_attribute * ctl_info_attr = to_ctl_info_attr ( attr ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:49:58 +04:00
if ( ctl_info_attr - > show )
return ctl_info_attr - > show ( edac_dev , buffer ) ;
return - EIO ;
2007-07-19 12:49:36 +04:00
}
/* Function to 'store' fields into the edac_dev 'ctl_info' structure */
static ssize_t edac_dev_ctl_info_store ( struct kobject * kobj ,
2007-07-19 12:50:13 +04:00
struct attribute * attr ,
const char * buffer , size_t count )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:49:58 +04:00
struct edac_device_ctl_info * edac_dev = to_ctl_info ( kobj ) ;
struct ctl_info_attribute * ctl_info_attr = to_ctl_info_attr ( attr ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:49:58 +04:00
if ( ctl_info_attr - > store )
return ctl_info_attr - > store ( edac_dev , buffer , count ) ;
return - EIO ;
2007-07-19 12:49:36 +04:00
}
/* edac_dev file operations for an 'ctl_info' */
2010-01-19 04:58:23 +03:00
static const struct sysfs_ops device_ctl_info_ops = {
2007-07-19 12:49:58 +04:00
. show = edac_dev_ctl_info_show ,
. store = edac_dev_ctl_info_store
2007-07-19 12:49:36 +04:00
} ;
# define CTL_INFO_ATTR(_name,_mode,_show,_store) \
static struct ctl_info_attribute attr_ctl_info_ # # _name = { \
2007-07-19 12:50:13 +04:00
. attr = { . name = __stringify ( _name ) , . mode = _mode } , \
. show = _show , \
. store = _store , \
2007-07-19 12:49:36 +04:00
} ;
/* Declare the various ctl_info attributes here and their respective ops */
2007-07-19 12:49:58 +04:00
CTL_INFO_ATTR ( log_ue , S_IRUGO | S_IWUSR ,
2007-07-19 12:50:13 +04:00
edac_device_ctl_log_ue_show , edac_device_ctl_log_ue_store ) ;
2007-07-19 12:49:58 +04:00
CTL_INFO_ATTR ( log_ce , S_IRUGO | S_IWUSR ,
2007-07-19 12:50:13 +04:00
edac_device_ctl_log_ce_show , edac_device_ctl_log_ce_store ) ;
2007-07-19 12:49:58 +04:00
CTL_INFO_ATTR ( panic_on_ue , S_IRUGO | S_IWUSR ,
2007-07-19 12:50:13 +04:00
edac_device_ctl_panic_on_ue_show ,
edac_device_ctl_panic_on_ue_store ) ;
2007-07-19 12:49:58 +04:00
CTL_INFO_ATTR ( poll_msec , S_IRUGO | S_IWUSR ,
2007-07-19 12:50:13 +04:00
edac_device_ctl_poll_msec_show , edac_device_ctl_poll_msec_store ) ;
2007-07-19 12:49:36 +04:00
/* Base Attributes of the EDAC_DEVICE ECC object */
static struct ctl_info_attribute * device_ctrl_attr [ ] = {
& attr_ctl_info_panic_on_ue ,
& attr_ctl_info_log_ue ,
& attr_ctl_info_log_ce ,
& attr_ctl_info_poll_msec ,
NULL ,
} ;
2007-07-19 12:50:29 +04:00
/*
* edac_device_ctrl_master_release
*
* called when the reference count for the ' main ' kobj
* for a edac_device control struct reaches zero
*
* Reference count model :
* One ' main ' kobject for each control structure allocated .
* That main kobj is initially set to one AND
* the reference count for the EDAC ' core ' module is
* bumped by one , thus added ' keep in memory ' dependency .
*
* Each new internal kobj ( in instances and blocks ) then
* bumps the ' main ' kobject .
*
* When they are released their release functions decrement
* the ' main ' kobj .
*
* When the main kobj reaches zero ( 0 ) then THIS function
* is called which then decrements the EDAC ' core ' module .
* When the module reference count reaches zero then the
* module no longer has dependency on keeping the release
* function code in memory and module can be unloaded .
*
* This will support several control objects as well , each
* with its own ' main ' kobj .
*/
2007-07-19 12:49:36 +04:00
static void edac_device_ctrl_master_release ( struct kobject * kobj )
{
2007-07-19 12:50:29 +04:00
struct edac_device_ctl_info * edac_dev = to_edacdev ( kobj ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:33 +04:00
debugf4 ( " %s() control index=%d \n " , __func__ , edac_dev - > dev_idx ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:29 +04:00
/* decrement the EDAC CORE module ref count */
module_put ( edac_dev - > owner ) ;
/* free the control struct containing the 'main' kobj
* passed in to this routine
*/
kfree ( edac_dev ) ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:50:29 +04:00
/* ktype for the main (master) kobject */
2007-07-19 12:49:36 +04:00
static struct kobj_type ktype_device_ctrl = {
. release = edac_device_ctrl_master_release ,
. sysfs_ops = & device_ctl_info_ops ,
2007-07-19 12:49:58 +04:00
. default_attrs = ( struct attribute * * ) device_ctrl_attr ,
2007-07-19 12:49:36 +04:00
} ;
/*
2007-07-19 12:50:29 +04:00
* edac_device_register_sysfs_main_kobj
2007-07-19 12:49:36 +04:00
*
* perform the high level setup for the new edac_device instance
*
* Return : 0 SUCCESS
* ! 0 FAILURE
*/
2007-07-19 12:50:29 +04:00
int edac_device_register_sysfs_main_kobj ( struct edac_device_ctl_info * edac_dev )
2007-07-19 12:49:36 +04:00
{
struct sysdev_class * edac_class ;
2007-07-19 12:50:29 +04:00
int err ;
2007-07-19 12:49:36 +04:00
debugf1 ( " %s() \n " , __func__ ) ;
2007-07-19 12:49:58 +04:00
/* get the /sys/devices/system/edac reference */
edac_class = edac_get_edac_class ( ) ;
if ( edac_class = = NULL ) {
2007-07-19 12:50:29 +04:00
debugf1 ( " %s() no edac_class error \n " , __func__ ) ;
err = - ENODEV ;
goto err_out ;
2007-07-19 12:49:58 +04:00
}
2007-07-19 12:49:36 +04:00
/* Point to the 'edac_class' this instance 'reports' to */
edac_dev - > edac_class = edac_class ;
/* Init the devices's kobject */
2007-07-19 12:49:58 +04:00
memset ( & edac_dev - > kobj , 0 , sizeof ( struct kobject ) ) ;
2007-07-19 12:50:29 +04:00
/* Record which module 'owns' this control structure
* and bump the ref count of the module
*/
edac_dev - > owner = THIS_MODULE ;
if ( ! try_module_get ( edac_dev - > owner ) ) {
err = - ENODEV ;
goto err_out ;
}
/* register */
2007-12-17 22:54:39 +03:00
err = kobject_init_and_add ( & edac_dev - > kobj , & ktype_device_ctrl ,
& edac_class - > kset . kobj ,
" %s " , edac_dev - > name ) ;
2007-07-19 12:49:36 +04:00
if ( err ) {
debugf1 ( " %s()Failed to register '.../edac/%s' \n " ,
2007-07-19 12:49:58 +04:00
__func__ , edac_dev - > name ) ;
2007-07-19 12:50:29 +04:00
goto err_kobj_reg ;
2007-07-19 12:49:36 +04:00
}
2007-12-17 22:54:39 +03:00
kobject_uevent ( & edac_dev - > kobj , KOBJ_ADD ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:29 +04:00
/* At this point, to 'free' the control struct,
* edac_device_unregister_sysfs_main_kobj ( ) must be used
*/
2007-07-19 12:50:33 +04:00
debugf4 ( " %s() Registered '.../edac/%s' kobject \n " ,
2007-07-19 12:49:36 +04:00
__func__ , edac_dev - > name ) ;
return 0 ;
2007-07-19 12:50:29 +04:00
/* Error exit stack */
err_kobj_reg :
module_put ( edac_dev - > owner ) ;
err_out :
return err ;
2007-07-19 12:49:36 +04:00
}
/*
2007-07-19 12:50:29 +04:00
* edac_device_unregister_sysfs_main_kobj :
2007-07-19 12:49:36 +04:00
* the ' . . . . / edac / < name > ' kobject
*/
2007-07-19 12:50:29 +04:00
void edac_device_unregister_sysfs_main_kobj (
struct edac_device_ctl_info * edac_dev )
2007-07-19 12:49:36 +04:00
{
debugf0 ( " %s() \n " , __func__ ) ;
2007-07-19 12:50:33 +04:00
debugf4 ( " %s() name of kobject is: %s \n " ,
2007-07-19 12:49:36 +04:00
__func__ , kobject_name ( & edac_dev - > kobj ) ) ;
/*
* Unregister the edac device ' s kobject and
2007-07-19 12:50:29 +04:00
* allow for reference count to reach 0 at which point
* the callback will be called to :
* a ) module_put ( ) this module
* b ) ' kfree ' the memory
2007-07-19 12:49:36 +04:00
*/
2007-12-20 19:13:05 +03:00
kobject_put ( & edac_dev - > kobj ) ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:50:29 +04:00
/* edac_dev -> instance information */
2007-07-19 12:49:36 +04:00
/*
* Set of low - level instance attribute show functions
*/
2007-07-19 12:49:58 +04:00
static ssize_t instance_ue_count_show ( struct edac_device_instance * instance ,
2007-07-19 12:50:13 +04:00
char * data )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:49:58 +04:00
return sprintf ( data , " %u \n " , instance - > counters . ue_count ) ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:49:58 +04:00
static ssize_t instance_ce_count_show ( struct edac_device_instance * instance ,
2007-07-19 12:50:13 +04:00
char * data )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:49:58 +04:00
return sprintf ( data , " %u \n " , instance - > counters . ce_count ) ;
2007-07-19 12:49:36 +04:00
}
# define to_instance(k) container_of(k, struct edac_device_instance, kobj)
# define to_instance_attr(a) container_of(a,struct instance_attribute,attr)
/* DEVICE instance kobject release() function */
static void edac_device_ctrl_instance_release ( struct kobject * kobj )
{
struct edac_device_instance * instance ;
debugf1 ( " %s() \n " , __func__ ) ;
2007-07-19 12:50:29 +04:00
/* map from this kobj to the main control struct
* and then dec the main kobj count
*/
2007-07-19 12:49:36 +04:00
instance = to_instance ( kobj ) ;
2007-07-19 12:50:29 +04:00
kobject_put ( & instance - > ctl - > kobj ) ;
2007-07-19 12:49:36 +04:00
}
/* instance specific attribute structure */
struct instance_attribute {
2007-07-19 12:49:58 +04:00
struct attribute attr ;
2007-07-19 12:50:20 +04:00
ssize_t ( * show ) ( struct edac_device_instance * , char * ) ;
ssize_t ( * store ) ( struct edac_device_instance * , const char * , size_t ) ;
2007-07-19 12:49:36 +04:00
} ;
/* Function to 'show' fields from the edac_dev 'instance' structure */
static ssize_t edac_dev_instance_show ( struct kobject * kobj ,
2007-07-19 12:50:13 +04:00
struct attribute * attr , char * buffer )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:49:58 +04:00
struct edac_device_instance * instance = to_instance ( kobj ) ;
struct instance_attribute * instance_attr = to_instance_attr ( attr ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:49:58 +04:00
if ( instance_attr - > show )
return instance_attr - > show ( instance , buffer ) ;
return - EIO ;
2007-07-19 12:49:36 +04:00
}
/* Function to 'store' fields into the edac_dev 'instance' structure */
static ssize_t edac_dev_instance_store ( struct kobject * kobj ,
2007-07-19 12:50:13 +04:00
struct attribute * attr ,
const char * buffer , size_t count )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:49:58 +04:00
struct edac_device_instance * instance = to_instance ( kobj ) ;
struct instance_attribute * instance_attr = to_instance_attr ( attr ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:49:58 +04:00
if ( instance_attr - > store )
return instance_attr - > store ( instance , buffer , count ) ;
return - EIO ;
2007-07-19 12:49:36 +04:00
}
/* edac_dev file operations for an 'instance' */
2010-01-19 04:58:23 +03:00
static const struct sysfs_ops device_instance_ops = {
2007-07-19 12:49:58 +04:00
. show = edac_dev_instance_show ,
. store = edac_dev_instance_store
2007-07-19 12:49:36 +04:00
} ;
# define INSTANCE_ATTR(_name,_mode,_show,_store) \
static struct instance_attribute attr_instance_ # # _name = { \
2007-07-19 12:50:13 +04:00
. attr = { . name = __stringify ( _name ) , . mode = _mode } , \
. show = _show , \
. store = _store , \
2007-07-19 12:49:36 +04:00
} ;
/*
* Define attributes visible for the edac_device instance object
* Each contains a pointer to a show and an optional set
* function pointer that does the low level output / input
*/
2007-07-19 12:49:58 +04:00
INSTANCE_ATTR ( ce_count , S_IRUGO , instance_ce_count_show , NULL ) ;
INSTANCE_ATTR ( ue_count , S_IRUGO , instance_ue_count_show , NULL ) ;
2007-07-19 12:49:36 +04:00
/* list of edac_dev 'instance' attributes */
static struct instance_attribute * device_instance_attr [ ] = {
& attr_instance_ce_count ,
& attr_instance_ue_count ,
NULL ,
} ;
/* The 'ktype' for each edac_dev 'instance' */
static struct kobj_type ktype_instance_ctrl = {
. release = edac_device_ctrl_instance_release ,
. sysfs_ops = & device_instance_ops ,
2007-07-19 12:49:58 +04:00
. default_attrs = ( struct attribute * * ) device_instance_attr ,
2007-07-19 12:49:36 +04:00
} ;
2007-07-19 12:50:29 +04:00
/* edac_dev -> instance -> block information */
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:33 +04:00
# define to_block(k) container_of(k, struct edac_device_block, kobj)
# define to_block_attr(a) \
container_of ( a , struct edac_dev_sysfs_block_attribute , attr )
2007-07-19 12:49:36 +04:00
/*
* Set of low - level block attribute show functions
*/
2007-07-19 12:50:33 +04:00
static ssize_t block_ue_count_show ( struct kobject * kobj ,
struct attribute * attr , char * data )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:50:33 +04:00
struct edac_device_block * block = to_block ( kobj ) ;
2007-07-19 12:49:58 +04:00
return sprintf ( data , " %u \n " , block - > counters . ue_count ) ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:50:33 +04:00
static ssize_t block_ce_count_show ( struct kobject * kobj ,
struct attribute * attr , char * data )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:50:33 +04:00
struct edac_device_block * block = to_block ( kobj ) ;
2007-07-19 12:49:58 +04:00
return sprintf ( data , " %u \n " , block - > counters . ce_count ) ;
2007-07-19 12:49:36 +04:00
}
/* DEVICE block kobject release() function */
static void edac_device_ctrl_block_release ( struct kobject * kobj )
{
struct edac_device_block * block ;
debugf1 ( " %s() \n " , __func__ ) ;
2007-07-19 12:50:29 +04:00
/* get the container of the kobj */
2007-07-19 12:49:36 +04:00
block = to_block ( kobj ) ;
2007-07-19 12:50:29 +04:00
/* map from 'block kobj' to 'block->instance->controller->main_kobj'
* now ' release ' the block kobject
*/
kobject_put ( & block - > instance - > ctl - > kobj ) ;
2007-07-19 12:49:36 +04:00
}
/* Function to 'show' fields from the edac_dev 'block' structure */
static ssize_t edac_dev_block_show ( struct kobject * kobj ,
2007-07-19 12:50:13 +04:00
struct attribute * attr , char * buffer )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:50:33 +04:00
struct edac_dev_sysfs_block_attribute * block_attr =
to_block_attr ( attr ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:49:58 +04:00
if ( block_attr - > show )
2007-07-19 12:50:33 +04:00
return block_attr - > show ( kobj , attr , buffer ) ;
2007-07-19 12:49:58 +04:00
return - EIO ;
2007-07-19 12:49:36 +04:00
}
/* Function to 'store' fields into the edac_dev 'block' structure */
static ssize_t edac_dev_block_store ( struct kobject * kobj ,
2007-07-19 12:50:13 +04:00
struct attribute * attr ,
const char * buffer , size_t count )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:50:33 +04:00
struct edac_dev_sysfs_block_attribute * block_attr ;
block_attr = to_block_attr ( attr ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:49:58 +04:00
if ( block_attr - > store )
2007-07-19 12:50:33 +04:00
return block_attr - > store ( kobj , attr , buffer , count ) ;
2007-07-19 12:49:58 +04:00
return - EIO ;
2007-07-19 12:49:36 +04:00
}
/* edac_dev file operations for a 'block' */
2010-01-19 04:58:23 +03:00
static const struct sysfs_ops device_block_ops = {
2007-07-19 12:49:58 +04:00
. show = edac_dev_block_show ,
. store = edac_dev_block_store
2007-07-19 12:49:36 +04:00
} ;
# define BLOCK_ATTR(_name,_mode,_show,_store) \
2007-07-19 12:50:33 +04:00
static struct edac_dev_sysfs_block_attribute attr_block_ # # _name = { \
2007-07-19 12:50:13 +04:00
. attr = { . name = __stringify ( _name ) , . mode = _mode } , \
. show = _show , \
. store = _store , \
2007-07-19 12:49:36 +04:00
} ;
2007-07-19 12:49:58 +04:00
BLOCK_ATTR ( ce_count , S_IRUGO , block_ce_count_show , NULL ) ;
BLOCK_ATTR ( ue_count , S_IRUGO , block_ue_count_show , NULL ) ;
2007-07-19 12:49:36 +04:00
/* list of edac_dev 'block' attributes */
2007-07-19 12:50:33 +04:00
static struct edac_dev_sysfs_block_attribute * device_block_attr [ ] = {
2007-07-19 12:49:36 +04:00
& attr_block_ce_count ,
& attr_block_ue_count ,
NULL ,
} ;
/* The 'ktype' for each edac_dev 'block' */
static struct kobj_type ktype_block_ctrl = {
. release = edac_device_ctrl_block_release ,
. sysfs_ops = & device_block_ops ,
2007-07-19 12:49:58 +04:00
. default_attrs = ( struct attribute * * ) device_block_attr ,
2007-07-19 12:49:36 +04:00
} ;
2007-07-19 12:50:29 +04:00
/* block ctor/dtor code */
2007-07-19 12:49:36 +04:00
/*
* edac_device_create_block
*/
2007-07-19 12:49:58 +04:00
static int edac_device_create_block ( struct edac_device_ctl_info * edac_dev ,
2007-07-19 12:50:13 +04:00
struct edac_device_instance * instance ,
2007-07-19 12:50:29 +04:00
struct edac_device_block * block )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:50:25 +04:00
int i ;
2007-07-19 12:49:36 +04:00
int err ;
2007-07-19 12:50:25 +04:00
struct edac_dev_sysfs_block_attribute * sysfs_attrib ;
2007-07-19 12:50:29 +04:00
struct kobject * main_kobj ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:33 +04:00
debugf4 ( " %s() Instance '%s' inst_p=%p block '%s' block_p=%p \n " ,
__func__ , instance - > name , instance , block - > name , block ) ;
debugf4 ( " %s() block kobj=%p block kobj->parent=%p \n " ,
__func__ , & block - > kobj , & block - > kobj . parent ) ;
2007-07-19 12:49:36 +04:00
/* init this block's kobject */
2007-07-19 12:49:58 +04:00
memset ( & block - > kobj , 0 , sizeof ( struct kobject ) ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:29 +04:00
/* bump the main kobject's reference count for this controller
* and this instance is dependant on the main
*/
main_kobj = kobject_get ( & edac_dev - > kobj ) ;
if ( ! main_kobj ) {
err = - ENODEV ;
goto err_out ;
}
/* Add this block's kobject */
2007-12-17 22:54:39 +03:00
err = kobject_init_and_add ( & block - > kobj , & ktype_block_ctrl ,
& instance - > kobj ,
" %s " , block - > name ) ;
2007-07-19 12:49:36 +04:00
if ( err ) {
2007-07-19 12:50:29 +04:00
debugf1 ( " %s() Failed to register instance '%s' \n " ,
2007-07-19 12:49:58 +04:00
__func__ , block - > name ) ;
2007-07-19 12:50:29 +04:00
kobject_put ( main_kobj ) ;
err = - ENODEV ;
goto err_out ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:50:25 +04:00
/* If there are driver level block attributes, then added them
* to the block kobject
*/
sysfs_attrib = block - > block_attributes ;
2007-07-19 12:50:33 +04:00
if ( sysfs_attrib & & block - > nr_attribs ) {
for ( i = 0 ; i < block - > nr_attribs ; i + + , sysfs_attrib + + ) {
debugf4 ( " %s() creating block attrib='%s' "
" attrib->%p to kobj=%p \n " ,
__func__ ,
sysfs_attrib - > attr . name ,
sysfs_attrib , & block - > kobj ) ;
/* Create each block_attribute file */
2007-07-19 12:50:25 +04:00
err = sysfs_create_file ( & block - > kobj ,
2007-07-19 12:50:33 +04:00
& sysfs_attrib - > attr ) ;
2007-07-19 12:50:25 +04:00
if ( err )
goto err_on_attrib ;
}
}
2007-12-17 22:54:39 +03:00
kobject_uevent ( & block - > kobj , KOBJ_ADD ) ;
2007-07-19 12:50:25 +04:00
2007-07-19 12:49:36 +04:00
return 0 ;
2007-07-19 12:50:25 +04:00
2007-07-19 12:50:29 +04:00
/* Error unwind stack */
2007-07-19 12:50:25 +04:00
err_on_attrib :
2007-12-20 19:13:05 +03:00
kobject_put ( & block - > kobj ) ;
2007-07-19 12:50:25 +04:00
2007-07-19 12:50:29 +04:00
err_out :
2007-07-19 12:50:25 +04:00
return err ;
2007-07-19 12:49:36 +04:00
}
/*
2007-07-19 12:50:29 +04:00
* edac_device_delete_block ( edac_dev , block ) ;
2007-07-19 12:49:36 +04:00
*/
2007-07-19 12:49:58 +04:00
static void edac_device_delete_block ( struct edac_device_ctl_info * edac_dev ,
2007-07-19 12:50:29 +04:00
struct edac_device_block * block )
2007-07-19 12:49:36 +04:00
{
2007-07-19 12:50:29 +04:00
struct edac_dev_sysfs_block_attribute * sysfs_attrib ;
int i ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:29 +04:00
/* if this block has 'attributes' then we need to iterate over the list
* and ' remove ' the attributes on this block
*/
sysfs_attrib = block - > block_attributes ;
if ( sysfs_attrib & & block - > nr_attribs ) {
2007-07-19 12:50:33 +04:00
for ( i = 0 ; i < block - > nr_attribs ; i + + , sysfs_attrib + + ) {
/* remove each block_attrib file */
2007-07-19 12:50:29 +04:00
sysfs_remove_file ( & block - > kobj ,
( struct attribute * ) sysfs_attrib ) ;
}
}
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:29 +04:00
/* unregister this block's kobject, SEE:
* edac_device_ctrl_block_release ( ) callback operation
*/
2007-12-20 19:13:05 +03:00
kobject_put ( & block - > kobj ) ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:50:29 +04:00
/* instance ctor/dtor code */
2007-07-19 12:49:36 +04:00
/*
* edac_device_create_instance
* create just one instance of an edac_device ' instance '
*/
2007-07-19 12:49:58 +04:00
static int edac_device_create_instance ( struct edac_device_ctl_info * edac_dev ,
2007-07-19 12:50:13 +04:00
int idx )
2007-07-19 12:49:36 +04:00
{
int i , j ;
int err ;
struct edac_device_instance * instance ;
2007-07-19 12:50:29 +04:00
struct kobject * main_kobj ;
2007-07-19 12:49:36 +04:00
instance = & edac_dev - > instances [ idx ] ;
/* Init the instance's kobject */
2007-07-19 12:49:58 +04:00
memset ( & instance - > kobj , 0 , sizeof ( struct kobject ) ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:29 +04:00
instance - > ctl = edac_dev ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:29 +04:00
/* bump the main kobject's reference count for this controller
* and this instance is dependant on the main
*/
main_kobj = kobject_get ( & edac_dev - > kobj ) ;
if ( ! main_kobj ) {
err = - ENODEV ;
goto err_out ;
}
2007-07-19 12:49:36 +04:00
2007-12-17 22:54:39 +03:00
/* Formally register this instance's kobject under the edac_device */
err = kobject_init_and_add ( & instance - > kobj , & ktype_instance_ctrl ,
& edac_dev - > kobj , " %s " , instance - > name ) ;
2007-07-19 12:49:36 +04:00
if ( err ! = 0 ) {
debugf2 ( " %s() Failed to register instance '%s' \n " ,
2007-07-19 12:49:58 +04:00
__func__ , instance - > name ) ;
2007-07-19 12:50:29 +04:00
kobject_put ( main_kobj ) ;
goto err_out ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:50:33 +04:00
debugf4 ( " %s() now register '%d' blocks for instance %d \n " ,
2007-07-19 12:49:58 +04:00
__func__ , instance - > nr_blocks , idx ) ;
2007-07-19 12:49:36 +04:00
/* register all blocks of this instance */
2007-07-19 12:49:58 +04:00
for ( i = 0 ; i < instance - > nr_blocks ; i + + ) {
2007-07-19 12:50:29 +04:00
err = edac_device_create_block ( edac_dev , instance ,
& instance - > blocks [ i ] ) ;
2007-07-19 12:49:36 +04:00
if ( err ) {
2007-07-19 12:50:29 +04:00
/* If any fail, remove all previous ones */
2007-07-19 12:50:20 +04:00
for ( j = 0 ; j < i ; j + + )
2007-07-19 12:50:29 +04:00
edac_device_delete_block ( edac_dev ,
& instance - > blocks [ j ] ) ;
goto err_release_instance_kobj ;
2007-07-19 12:49:36 +04:00
}
}
2007-12-17 22:54:39 +03:00
kobject_uevent ( & instance - > kobj , KOBJ_ADD ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:33 +04:00
debugf4 ( " %s() Registered instance %d '%s' kobject \n " ,
2007-07-19 12:49:36 +04:00
__func__ , idx , instance - > name ) ;
return 0 ;
2007-07-19 12:50:29 +04:00
/* error unwind stack */
err_release_instance_kobj :
2007-12-20 19:13:05 +03:00
kobject_put ( & instance - > kobj ) ;
2007-07-19 12:50:29 +04:00
err_out :
return err ;
2007-07-19 12:49:36 +04:00
}
/*
* edac_device_remove_instance
* remove an edac_device instance
*/
2007-07-19 12:49:58 +04:00
static void edac_device_delete_instance ( struct edac_device_ctl_info * edac_dev ,
int idx )
2007-07-19 12:49:36 +04:00
{
struct edac_device_instance * instance ;
2007-07-19 12:50:29 +04:00
int i ;
2007-07-19 12:49:36 +04:00
instance = & edac_dev - > instances [ idx ] ;
/* unregister all blocks in this instance */
2007-07-19 12:50:20 +04:00
for ( i = 0 ; i < instance - > nr_blocks ; i + + )
2007-07-19 12:50:29 +04:00
edac_device_delete_block ( edac_dev , & instance - > blocks [ i ] ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:29 +04:00
/* unregister this instance's kobject, SEE:
* edac_device_ctrl_instance_release ( ) for callback operation
*/
2007-12-20 19:13:05 +03:00
kobject_put ( & instance - > kobj ) ;
2007-07-19 12:49:36 +04:00
}
/*
* edac_device_create_instances
* create the first level of ' instances ' for this device
* ( ie ' cache ' might have ' cache0 ' , ' cache1 ' , ' cache2 ' , etc
*/
static int edac_device_create_instances ( struct edac_device_ctl_info * edac_dev )
{
int i , j ;
int err ;
debugf0 ( " %s() \n " , __func__ ) ;
/* iterate over creation of the instances */
2007-07-19 12:49:58 +04:00
for ( i = 0 ; i < edac_dev - > nr_instances ; i + + ) {
err = edac_device_create_instance ( edac_dev , i ) ;
2007-07-19 12:49:36 +04:00
if ( err ) {
/* unwind previous instances on error */
2007-07-19 12:50:20 +04:00
for ( j = 0 ; j < i ; j + + )
2007-07-19 12:49:58 +04:00
edac_device_delete_instance ( edac_dev , j ) ;
2007-07-19 12:49:36 +04:00
return err ;
}
}
return 0 ;
}
/*
* edac_device_delete_instances ( edac_dev ) ;
* unregister all the kobjects of the instances
*/
static void edac_device_delete_instances ( struct edac_device_ctl_info * edac_dev )
{
int i ;
/* iterate over creation of the instances */
2007-07-19 12:50:20 +04:00
for ( i = 0 ; i < edac_dev - > nr_instances ; i + + )
2007-07-19 12:49:58 +04:00
edac_device_delete_instance ( edac_dev , i ) ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:50:29 +04:00
/* edac_dev sysfs ctor/dtor code */
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:10 +04:00
/*
2007-07-19 12:50:29 +04:00
* edac_device_add_main_sysfs_attributes
2007-07-19 12:50:10 +04:00
* add some attributes to this instance ' s main kobject
*/
2007-07-19 12:50:29 +04:00
static int edac_device_add_main_sysfs_attributes (
2007-07-19 12:50:10 +04:00
struct edac_device_ctl_info * edac_dev )
{
2007-07-19 12:50:13 +04:00
struct edac_dev_sysfs_attribute * sysfs_attrib ;
2007-07-19 12:50:29 +04:00
int err = 0 ;
2007-07-19 12:50:13 +04:00
sysfs_attrib = edac_dev - > sysfs_attributes ;
2007-07-19 12:50:29 +04:00
if ( sysfs_attrib ) {
/* iterate over the array and create an attribute for each
* entry in the list
*/
while ( sysfs_attrib - > attr . name ! = NULL ) {
err = sysfs_create_file ( & edac_dev - > kobj ,
2007-07-19 12:50:13 +04:00
( struct attribute * ) sysfs_attrib ) ;
2007-07-19 12:50:29 +04:00
if ( err )
goto err_out ;
2007-07-19 12:50:13 +04:00
2007-07-19 12:50:29 +04:00
sysfs_attrib + + ;
}
2007-07-19 12:50:13 +04:00
}
2007-07-19 12:50:10 +04:00
2007-07-19 12:50:29 +04:00
err_out :
return err ;
}
/*
* edac_device_remove_main_sysfs_attributes
* remove any attributes to this instance ' s main kobject
*/
static void edac_device_remove_main_sysfs_attributes (
struct edac_device_ctl_info * edac_dev )
{
struct edac_dev_sysfs_attribute * sysfs_attrib ;
/* if there are main attributes, defined, remove them. First,
* point to the start of the array and iterate over it
* removing each attribute listed from this device ' s instance ' s kobject
*/
sysfs_attrib = edac_dev - > sysfs_attributes ;
if ( sysfs_attrib ) {
while ( sysfs_attrib - > attr . name ! = NULL ) {
sysfs_remove_file ( & edac_dev - > kobj ,
( struct attribute * ) sysfs_attrib ) ;
sysfs_attrib + + ;
}
}
2007-07-19 12:50:10 +04:00
}
2007-07-19 12:49:36 +04:00
/*
* edac_device_create_sysfs ( ) Constructor
*
2007-07-19 12:50:29 +04:00
* accept a created edac_device control structure
* and ' export ' it to sysfs . The ' main ' kobj should already have been
* created . ' instance ' and ' block ' kobjects should be registered
* along with any ' block ' attributes from the low driver . In addition ,
* the main attributes ( if any ) are connected to the main kobject of
* the control structure .
2007-07-19 12:49:36 +04:00
*
* Return :
* 0 Success
* ! 0 Failure
*/
int edac_device_create_sysfs ( struct edac_device_ctl_info * edac_dev )
{
int err ;
2007-07-19 12:49:58 +04:00
struct kobject * edac_kobj = & edac_dev - > kobj ;
2007-07-19 12:49:36 +04:00
debugf0 ( " %s() idx=%d \n " , __func__ , edac_dev - > dev_idx ) ;
2007-07-19 12:50:29 +04:00
/* go create any main attributes callers wants */
err = edac_device_add_main_sysfs_attributes ( edac_dev ) ;
if ( err ) {
debugf0 ( " %s() failed to add sysfs attribs \n " , __func__ ) ;
goto err_out ;
2007-07-19 12:50:10 +04:00
}
2007-07-19 12:49:36 +04:00
/* create a symlink from the edac device
* to the platform ' device ' being used for this
*/
err = sysfs_create_link ( edac_kobj ,
2007-07-19 12:49:58 +04:00
& edac_dev - > dev - > kobj , EDAC_DEVICE_SYMLINK ) ;
2007-07-19 12:49:36 +04:00
if ( err ) {
debugf0 ( " %s() sysfs_create_link() returned err= %d \n " ,
__func__ , err ) ;
2007-07-19 12:50:29 +04:00
goto err_remove_main_attribs ;
2007-07-19 12:49:36 +04:00
}
2007-07-19 12:50:29 +04:00
/* Create the first level instance directories
* In turn , the nested blocks beneath the instances will
* be registered as well
*/
2007-07-19 12:49:36 +04:00
err = edac_device_create_instances ( edac_dev ) ;
2007-07-19 12:50:29 +04:00
if ( err ) {
debugf0 ( " %s() edac_device_create_instances() "
" returned err= %d \n " , __func__ , err ) ;
2007-07-19 12:50:10 +04:00
goto err_remove_link ;
2007-07-19 12:50:29 +04:00
}
2007-07-19 12:50:33 +04:00
debugf4 ( " %s() create-instances done, idx=%d \n " ,
2007-07-19 12:50:29 +04:00
__func__ , edac_dev - > dev_idx ) ;
2007-07-19 12:49:36 +04:00
return 0 ;
/* Error unwind stack */
2007-07-19 12:50:10 +04:00
err_remove_link :
/* remove the sym link */
sysfs_remove_link ( & edac_dev - > kobj , EDAC_DEVICE_SYMLINK ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:29 +04:00
err_remove_main_attribs :
edac_device_remove_main_sysfs_attributes ( edac_dev ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:29 +04:00
err_out :
2007-07-19 12:49:36 +04:00
return err ;
}
/*
* edac_device_remove_sysfs ( ) destructor
*
2007-07-19 12:50:29 +04:00
* given an edac_device struct , tear down the kobject resources
2007-07-19 12:49:36 +04:00
*/
void edac_device_remove_sysfs ( struct edac_device_ctl_info * edac_dev )
{
debugf0 ( " %s() \n " , __func__ ) ;
2007-07-19 12:50:29 +04:00
/* remove any main attributes for this device */
edac_device_remove_main_sysfs_attributes ( edac_dev ) ;
2007-07-19 12:49:36 +04:00
2007-07-19 12:50:29 +04:00
/* remove the device sym link */
2007-07-19 12:49:36 +04:00
sysfs_remove_link ( & edac_dev - > kobj , EDAC_DEVICE_SYMLINK ) ;
2007-07-19 12:50:29 +04:00
/* walk the instance/block kobject tree, deconstructing it */
edac_device_delete_instances ( edac_dev ) ;
2007-07-19 12:49:36 +04:00
}