2005-11-07 12:00:15 +03:00
/*
* RapidIO sysfs attributes and support
*
* Copyright 2005 MontaVista Software , Inc .
* Matt Porter < mporter @ kernel . crashing . org >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*/
# include <linux/kernel.h>
# include <linux/rio.h>
# include <linux/rio_drv.h>
# include <linux/stat.h>
2011-03-24 02:43:03 +03:00
# include <linux/capability.h>
2005-11-07 12:00:15 +03:00
# include "rio.h"
/* Sysfs support */
# define rio_config_attr(field, format_string) \
static ssize_t \
2005-11-07 12:00:20 +03:00
field # # _show ( struct device * dev , struct device_attribute * attr , char * buf ) \
2005-11-07 12:00:15 +03:00
{ \
struct rio_dev * rdev = to_rio_dev ( dev ) ; \
\
return sprintf ( buf , format_string , rdev - > field ) ; \
} \
rio_config_attr ( did , " 0x%04x \n " ) ;
rio_config_attr ( vid , " 0x%04x \n " ) ;
rio_config_attr ( device_rev , " 0x%08x \n " ) ;
rio_config_attr ( asm_did , " 0x%04x \n " ) ;
rio_config_attr ( asm_vid , " 0x%04x \n " ) ;
rio_config_attr ( asm_rev , " 0x%04x \n " ) ;
2011-03-24 02:42:59 +03:00
rio_config_attr ( destid , " 0x%04x \n " ) ;
rio_config_attr ( hopcount , " 0x%02x \n " ) ;
2005-11-07 12:00:15 +03:00
2005-11-07 12:00:20 +03:00
static ssize_t routes_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-11-07 12:00:15 +03:00
{
struct rio_dev * rdev = to_rio_dev ( dev ) ;
char * str = buf ;
int i ;
2008-04-19 00:33:42 +04:00
for ( i = 0 ; i < RIO_MAX_ROUTE_ENTRIES ( rdev - > net - > hport - > sys_size ) ;
i + + ) {
2005-11-07 12:00:15 +03:00
if ( rdev - > rswitch - > route_table [ i ] = = RIO_INVALID_ROUTE )
continue ;
str + =
sprintf ( str , " %04x %02x \n " , i ,
rdev - > rswitch - > route_table [ i ] ) ;
}
return ( str - buf ) ;
}
2011-03-24 02:42:59 +03:00
static ssize_t lprev_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct rio_dev * rdev = to_rio_dev ( dev ) ;
return sprintf ( buf , " %s \n " ,
( rdev - > prev ) ? rio_name ( rdev - > prev ) : " root " ) ;
}
static ssize_t lnext_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct rio_dev * rdev = to_rio_dev ( dev ) ;
char * str = buf ;
int i ;
if ( rdev - > pef & RIO_PEF_SWITCH ) {
for ( i = 0 ; i < RIO_GET_TOTAL_PORTS ( rdev - > swpinfo ) ; i + + ) {
if ( rdev - > rswitch - > nextdev [ i ] )
str + = sprintf ( str , " %s \n " ,
rio_name ( rdev - > rswitch - > nextdev [ i ] ) ) ;
else
str + = sprintf ( str , " null \n " ) ;
}
}
return str - buf ;
}
2013-07-04 02:08:58 +04:00
static ssize_t modalias_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct rio_dev * rdev = to_rio_dev ( dev ) ;
return sprintf ( buf , " rapidio:v%04Xd%04Xav%04Xad%04X \n " ,
rdev - > vid , rdev - > did , rdev - > asm_vid , rdev - > asm_did ) ;
}
2005-11-07 12:00:15 +03:00
struct device_attribute rio_dev_attrs [ ] = {
__ATTR_RO ( did ) ,
__ATTR_RO ( vid ) ,
__ATTR_RO ( device_rev ) ,
__ATTR_RO ( asm_did ) ,
__ATTR_RO ( asm_vid ) ,
__ATTR_RO ( asm_rev ) ,
2011-03-24 02:42:59 +03:00
__ATTR_RO ( lprev ) ,
__ATTR_RO ( destid ) ,
2013-07-04 02:08:58 +04:00
__ATTR_RO ( modalias ) ,
2005-11-07 12:00:15 +03:00
__ATTR_NULL ,
} ;
2010-10-28 02:34:31 +04:00
static DEVICE_ATTR ( routes , S_IRUGO , routes_show , NULL ) ;
2011-03-24 02:42:59 +03:00
static DEVICE_ATTR ( lnext , S_IRUGO , lnext_show , NULL ) ;
static DEVICE_ATTR ( hopcount , S_IRUGO , hopcount_show , NULL ) ;
2010-10-28 02:34:31 +04:00
2005-11-07 12:00:15 +03:00
static ssize_t
2010-05-13 05:28:57 +04:00
rio_read_config ( struct file * filp , struct kobject * kobj ,
struct bin_attribute * bin_attr ,
2007-06-09 09:57:22 +04:00
char * buf , loff_t off , size_t count )
2005-11-07 12:00:15 +03:00
{
struct rio_dev * dev =
to_rio_dev ( container_of ( kobj , struct device , kobj ) ) ;
unsigned int size = 0x100 ;
loff_t init_off = off ;
u8 * data = ( u8 * ) buf ;
/* Several chips lock up trying to read undefined config space */
if ( capable ( CAP_SYS_ADMIN ) )
2011-02-26 01:44:31 +03:00
size = RIO_MAINT_SPACE_SZ ;
2005-11-07 12:00:15 +03:00
2011-02-26 01:44:31 +03:00
if ( off > = size )
2005-11-07 12:00:15 +03:00
return 0 ;
if ( off + count > size ) {
size - = off ;
count = size ;
} else {
size = count ;
}
if ( ( off & 1 ) & & size ) {
u8 val ;
rio_read_config_8 ( dev , off , & val ) ;
data [ off - init_off ] = val ;
off + + ;
size - - ;
}
if ( ( off & 3 ) & & size > 2 ) {
u16 val ;
rio_read_config_16 ( dev , off , & val ) ;
data [ off - init_off ] = ( val > > 8 ) & 0xff ;
data [ off - init_off + 1 ] = val & 0xff ;
off + = 2 ;
size - = 2 ;
}
while ( size > 3 ) {
u32 val ;
rio_read_config_32 ( dev , off , & val ) ;
data [ off - init_off ] = ( val > > 24 ) & 0xff ;
data [ off - init_off + 1 ] = ( val > > 16 ) & 0xff ;
data [ off - init_off + 2 ] = ( val > > 8 ) & 0xff ;
data [ off - init_off + 3 ] = val & 0xff ;
off + = 4 ;
size - = 4 ;
}
if ( size > = 2 ) {
u16 val ;
rio_read_config_16 ( dev , off , & val ) ;
data [ off - init_off ] = ( val > > 8 ) & 0xff ;
data [ off - init_off + 1 ] = val & 0xff ;
off + = 2 ;
size - = 2 ;
}
if ( size > 0 ) {
u8 val ;
rio_read_config_8 ( dev , off , & val ) ;
data [ off - init_off ] = val ;
off + + ;
- - size ;
}
return count ;
}
static ssize_t
2010-05-13 05:28:57 +04:00
rio_write_config ( struct file * filp , struct kobject * kobj ,
struct bin_attribute * bin_attr ,
2007-06-09 09:57:22 +04:00
char * buf , loff_t off , size_t count )
2005-11-07 12:00:15 +03:00
{
struct rio_dev * dev =
to_rio_dev ( container_of ( kobj , struct device , kobj ) ) ;
unsigned int size = count ;
loff_t init_off = off ;
u8 * data = ( u8 * ) buf ;
2011-02-26 01:44:31 +03:00
if ( off > = RIO_MAINT_SPACE_SZ )
2005-11-07 12:00:15 +03:00
return 0 ;
2011-02-26 01:44:31 +03:00
if ( off + count > RIO_MAINT_SPACE_SZ ) {
size = RIO_MAINT_SPACE_SZ - off ;
2005-11-07 12:00:15 +03:00
count = size ;
}
if ( ( off & 1 ) & & size ) {
rio_write_config_8 ( dev , off , data [ off - init_off ] ) ;
off + + ;
size - - ;
}
if ( ( off & 3 ) & & ( size > 2 ) ) {
u16 val = data [ off - init_off + 1 ] ;
val | = ( u16 ) data [ off - init_off ] < < 8 ;
rio_write_config_16 ( dev , off , val ) ;
off + = 2 ;
size - = 2 ;
}
while ( size > 3 ) {
u32 val = data [ off - init_off + 3 ] ;
val | = ( u32 ) data [ off - init_off + 2 ] < < 8 ;
val | = ( u32 ) data [ off - init_off + 1 ] < < 16 ;
val | = ( u32 ) data [ off - init_off ] < < 24 ;
rio_write_config_32 ( dev , off , val ) ;
off + = 4 ;
size - = 4 ;
}
if ( size > = 2 ) {
u16 val = data [ off - init_off + 1 ] ;
val | = ( u16 ) data [ off - init_off ] < < 8 ;
rio_write_config_16 ( dev , off , val ) ;
off + = 2 ;
size - = 2 ;
}
if ( size ) {
rio_write_config_8 ( dev , off , data [ off - init_off ] ) ;
off + + ;
- - size ;
}
return count ;
}
static struct bin_attribute rio_config_attr = {
. attr = {
. name = " config " ,
. mode = S_IRUGO | S_IWUSR ,
} ,
2011-02-26 01:44:31 +03:00
. size = RIO_MAINT_SPACE_SZ ,
2005-11-07 12:00:15 +03:00
. read = rio_read_config ,
. write = rio_write_config ,
} ;
/**
* rio_create_sysfs_dev_files - create RIO specific sysfs files
* @ rdev : device whose entries should be created
*
* Create files when @ rdev is added to sysfs .
*/
int rio_create_sysfs_dev_files ( struct rio_dev * rdev )
{
2009-05-12 02:36:02 +04:00
int err = 0 ;
2005-11-07 12:00:15 +03:00
2010-10-28 02:34:31 +04:00
err = device_create_bin_file ( & rdev - > dev , & rio_config_attr ) ;
2011-01-13 04:00:39 +03:00
if ( ! err & & ( rdev - > pef & RIO_PEF_SWITCH ) ) {
2011-03-24 02:42:59 +03:00
err | = device_create_file ( & rdev - > dev , & dev_attr_routes ) ;
err | = device_create_file ( & rdev - > dev , & dev_attr_lnext ) ;
err | = device_create_file ( & rdev - > dev , & dev_attr_hopcount ) ;
2010-10-28 02:34:31 +04:00
}
if ( err )
pr_warning ( " RIO: Failed to create attribute file(s) for %s \n " ,
rio_name ( rdev ) ) ;
2009-05-12 02:36:02 +04:00
return err ;
2005-11-07 12:00:15 +03:00
}
/**
* rio_remove_sysfs_dev_files - cleanup RIO specific sysfs files
* @ rdev : device whose entries we should free
*
* Cleanup when @ rdev is removed from sysfs .
*/
void rio_remove_sysfs_dev_files ( struct rio_dev * rdev )
{
2010-10-28 02:34:31 +04:00
device_remove_bin_file ( & rdev - > dev , & rio_config_attr ) ;
2011-01-13 04:00:39 +03:00
if ( rdev - > pef & RIO_PEF_SWITCH ) {
2010-10-28 02:34:31 +04:00
device_remove_file ( & rdev - > dev , & dev_attr_routes ) ;
2011-03-24 02:42:59 +03:00
device_remove_file ( & rdev - > dev , & dev_attr_lnext ) ;
device_remove_file ( & rdev - > dev , & dev_attr_hopcount ) ;
2010-10-28 02:34:31 +04:00
}
2005-11-07 12:00:15 +03:00
}
2013-05-25 02:55:06 +04:00
static ssize_t bus_scan_store ( struct bus_type * bus , const char * buf ,
size_t count )
{
long val ;
int rc ;
if ( kstrtol ( buf , 0 , & val ) < 0 )
return - EINVAL ;
if ( val = = RIO_MPORT_ANY ) {
rc = rio_init_mports ( ) ;
goto exit ;
}
if ( val < 0 | | val > = RIO_MAX_MPORTS )
return - EINVAL ;
2013-07-04 02:08:53 +04:00
rc = rio_mport_scan ( ( int ) val ) ;
2013-05-25 02:55:06 +04:00
exit :
if ( ! rc )
rc = count ;
return rc ;
}
2013-08-24 01:24:29 +04:00
static BUS_ATTR ( scan , ( S_IWUSR | S_IWGRP ) , NULL , bus_scan_store ) ;
2013-05-25 02:55:06 +04:00
2013-08-24 01:24:29 +04:00
static struct attribute * rio_bus_attrs [ ] = {
& bus_attr_scan . attr ,
NULL ,
} ;
static const struct attribute_group rio_bus_group = {
. attrs = rio_bus_attrs ,
} ;
const struct attribute_group * rio_bus_groups [ ] = {
& rio_bus_group ,
NULL ,
2013-05-25 02:55:06 +04:00
} ;