@ -29,6 +29,15 @@
SWCONFIG_LED_PORT_SPEED_100 | \
SWCONFIG_LED_PORT_SPEED_1000 )
# define SWCONFIG_LED_MODE_LINK 0x01
# define SWCONFIG_LED_MODE_TX 0x02
# define SWCONFIG_LED_MODE_RX 0x04
# define SWCONFIG_LED_MODE_TXRX (SWCONFIG_LED_MODE_TX | \
SWCONFIG_LED_MODE_RX )
# define SWCONFIG_LED_MODE_ALL (SWCONFIG_LED_MODE_LINK | \
SWCONFIG_LED_MODE_TX | \
SWCONFIG_LED_MODE_RX )
struct switch_led_trigger {
struct led_trigger trig ;
struct switch_dev * swdev ;
@ -36,7 +45,8 @@ struct switch_led_trigger {
struct delayed_work sw_led_work ;
u32 port_mask ;
u32 port_link ;
unsigned long long port_traffic [ SWCONFIG_LED_NUM_PORTS ] ;
unsigned long long port_tx_traffic [ SWCONFIG_LED_NUM_PORTS ] ;
unsigned long long port_rx_traffic [ SWCONFIG_LED_NUM_PORTS ] ;
u8 link_speed [ SWCONFIG_LED_NUM_PORTS ] ;
} ;
@ -50,6 +60,7 @@ struct swconfig_trig_data {
bool prev_link ;
unsigned long prev_traffic ;
enum led_brightness prev_brightness ;
u8 mode ;
u8 speed_mask ;
} ;
@ -186,6 +197,79 @@ static ssize_t swconfig_trig_speed_mask_store(struct device *dev,
static DEVICE_ATTR ( speed_mask , 0644 , swconfig_trig_speed_mask_show ,
swconfig_trig_speed_mask_store ) ;
static ssize_t swconfig_trig_mode_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct led_classdev * led_cdev = dev_get_drvdata ( dev ) ;
struct swconfig_trig_data * trig_data = led_cdev - > trigger_data ;
u8 mode ;
read_lock ( & trig_data - > lock ) ;
mode = trig_data - > mode ;
read_unlock ( & trig_data - > lock ) ;
if ( mode = = 0 ) {
strcpy ( buf , " none \n " ) ;
} else {
if ( mode & SWCONFIG_LED_MODE_LINK )
strcat ( buf , " link " ) ;
if ( mode & SWCONFIG_LED_MODE_TX )
strcat ( buf , " tx " ) ;
if ( mode & SWCONFIG_LED_MODE_RX )
strcat ( buf , " rx " ) ;
strcat ( buf , " \n " ) ;
}
return strlen ( buf ) + 1 ;
}
static ssize_t swconfig_trig_mode_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t size )
{
struct led_classdev * led_cdev = dev_get_drvdata ( dev ) ;
struct swconfig_trig_data * trig_data = led_cdev - > trigger_data ;
char copybuf [ 128 ] ;
int new_mode = - 1 ;
char * p , * token ;
/* take a copy since we don't want to trash the inbound buffer when using strsep */
strncpy ( copybuf , buf , sizeof ( copybuf ) ) ;
copybuf [ sizeof ( copybuf ) - 1 ] = 0 ;
p = copybuf ;
while ( ( token = strsep ( & p , " \t \n " ) ) ! = NULL ) {
if ( ! * token )
continue ;
if ( new_mode < 0 )
new_mode = 0 ;
if ( ! strcmp ( token , " none " ) )
new_mode = 0 ;
else if ( ! strcmp ( token , " tx " ) )
new_mode | = SWCONFIG_LED_MODE_TX ;
else if ( ! strcmp ( token , " rx " ) )
new_mode | = SWCONFIG_LED_MODE_RX ;
else if ( ! strcmp ( token , " link " ) )
new_mode | = SWCONFIG_LED_MODE_LINK ;
else
return - EINVAL ;
}
if ( new_mode < 0 )
return - EINVAL ;
write_lock ( & trig_data - > lock ) ;
trig_data - > mode = ( u8 ) new_mode ;
write_unlock ( & trig_data - > lock ) ;
return size ;
}
/* mode special file */
static DEVICE_ATTR ( mode , 0644 , swconfig_trig_mode_show ,
swconfig_trig_mode_store ) ;
static void
swconfig_trig_activate ( struct led_classdev * led_cdev )
{
@ -206,6 +290,7 @@ swconfig_trig_activate(struct led_classdev *led_cdev)
trig_data - > led_cdev = led_cdev ;
trig_data - > swdev = sw_trig - > swdev ;
trig_data - > speed_mask = SWCONFIG_LED_PORT_SPEED_ALL ;
trig_data - > mode = SWCONFIG_LED_MODE_ALL ;
led_cdev - > trigger_data = trig_data ;
err = device_create_file ( led_cdev - > dev , & dev_attr_port_mask ) ;
@ -216,8 +301,15 @@ swconfig_trig_activate(struct led_classdev *led_cdev)
if ( err )
goto err_dev_free ;
err = device_create_file ( led_cdev - > dev , & dev_attr_mode ) ;
if ( err )
goto err_mode_free ;
return ;
err_mode_free :
device_remove_file ( led_cdev - > dev , & dev_attr_speed_mask ) ;
err_dev_free :
device_remove_file ( led_cdev - > dev , & dev_attr_port_mask ) ;
@ -237,10 +329,17 @@ swconfig_trig_deactivate(struct led_classdev *led_cdev)
if ( trig_data ) {
device_remove_file ( led_cdev - > dev , & dev_attr_port_mask ) ;
device_remove_file ( led_cdev - > dev , & dev_attr_speed_mask ) ;
device_remove_file ( led_cdev - > dev , & dev_attr_mode ) ;
kfree ( trig_data ) ;
}
}
/*
* link off - > led off ( can ' t be any other reason to turn it on )
* link on :
* mode link : led on by default only if speed matches , else off
* mode txrx : blink only if speed matches , else off
*/
static void
swconfig_trig_led_event ( struct switch_led_trigger * sw_trig ,
struct led_classdev * led_cdev )
@ -248,7 +347,8 @@ swconfig_trig_led_event(struct switch_led_trigger *sw_trig,
struct swconfig_trig_data * trig_data ;
u32 port_mask ;
bool link ;
u8 speed_mask ;
u8 speed_mask , mode ;
enum led_brightness led_base , led_blink ;
trig_data = led_cdev - > trigger_data ;
if ( ! trig_data )
@ -257,35 +357,48 @@ swconfig_trig_led_event(struct switch_led_trigger *sw_trig,
read_lock ( & trig_data - > lock ) ;
port_mask = trig_data - > port_mask ;
speed_mask = trig_data - > speed_mask ;
mode = trig_data - > mode ;
read_unlock ( & trig_data - > lock ) ;
link = ! ! ( sw_trig - > port_link & port_mask ) ;
if ( ! link ) {
if ( link ! = trig_data - > prev_link )
swconfig_trig_set_brightness ( trig_data , LED_OFF ) ;
} else {
if ( trig_data - > prev_brightness ! = LED_OFF )
swconfig_trig_set_brightness ( trig_data , LED_OFF ) ; /* and stop */
}
else {
unsigned long traffic ;
int speedok ; /* link speed flag */
int i ;
led_base = LED_FULL ;
led_blink = LED_OFF ;
traffic = 0 ;
speedok = 0 ;
for ( i = 0 ; i < SWCONFIG_LED_NUM_PORTS ; i + + ) {
if ( port_mask & ( 1 < < i ) )
if ( port_mask & ( 1 < < i ) ) {
if ( sw_trig - > link_speed [ i ] & speed_mask ) {
traffic + = sw_trig - > port_traffic [ i ] ;
traffic + = ( ( mode & SWCONFIG_LED_MODE_TX ) ?
sw_trig - > port_tx_traffic [ i ] : 0 ) +
( ( mode & SWCONFIG_LED_MODE_RX ) ?
sw_trig - > port_rx_traffic [ i ] : 0 ) ;
speedok = 1 ;
}
}
}
if ( speedok ) {
/* At least one port speed matches speed_mask */
if ( trig_data - > prev_brightness ! = LED_FULL )
if ( ! ( mode & SWCONFIG_LED_MODE_LINK ) ) {
led_base = LED_OFF ;
led_blink = LED_FULL ;
}
if ( trig_data - > prev_brightness ! = led_base )
swconfig_trig_set_brightness ( trig_data ,
LED_FULL ) ;
led_base ) ;
else if ( traffic ! = trig_data - > prev_traffic )
swconfig_trig_set_brightness ( trig_data ,
LED_OFF ) ;
led_blink ) ;
} else if ( trig_data - > prev_brightness ! = LED_OFF )
swconfig_trig_set_brightness ( trig_data , LED_OFF ) ;
@ -371,8 +484,8 @@ swconfig_led_work_func(struct work_struct *work)
memset ( & port_stats , ' \0 ' , sizeof ( port_stats ) ) ;
swdev - > ops - > get_port_stats ( swdev , i , & port_stats ) ;
sw_trig - > port_t raffic[ i ] = port_stats . tx_bytes +
port_stats . rx_bytes ;
sw_trig - > port_t x_t raffic[ i ] = port_stats . tx_bytes ;
sw_trig - > port_rx_traffic [ i ] = port_stats . rx_bytes ;
}
}