2017-02-03 13:20:20 -05:00
/*
* Handling of a single switch chip , part of a switch fabric
*
2017-03-28 15:10:36 -04:00
* Copyright ( c ) 2017 Savoir - faire Linux Inc .
* Vivien Didelot < vivien . didelot @ savoirfairelinux . com >
2017-02-03 13:20:20 -05:00
*
* 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/netdevice.h>
# include <linux/notifier.h>
# include <net/dsa.h>
2017-02-03 13:20:21 -05:00
static int dsa_switch_bridge_join ( struct dsa_switch * ds ,
struct dsa_notifier_bridge_info * info )
{
if ( ds - > index = = info - > sw_index & & ds - > ops - > port_bridge_join )
return ds - > ops - > port_bridge_join ( ds , info - > port , info - > br ) ;
2017-03-30 17:37:14 -04:00
if ( ds - > index ! = info - > sw_index & & ds - > ops - > crosschip_bridge_join )
return ds - > ops - > crosschip_bridge_join ( ds , info - > sw_index ,
info - > port , info - > br ) ;
2017-02-03 13:20:21 -05:00
return 0 ;
}
static int dsa_switch_bridge_leave ( struct dsa_switch * ds ,
struct dsa_notifier_bridge_info * info )
{
if ( ds - > index = = info - > sw_index & & ds - > ops - > port_bridge_leave )
ds - > ops - > port_bridge_leave ( ds , info - > port , info - > br ) ;
2017-03-30 17:37:14 -04:00
if ( ds - > index ! = info - > sw_index & & ds - > ops - > crosschip_bridge_leave )
ds - > ops - > crosschip_bridge_leave ( ds , info - > sw_index , info - > port ,
info - > br ) ;
2017-02-03 13:20:21 -05:00
return 0 ;
}
2017-02-03 13:20:20 -05:00
static int dsa_switch_event ( struct notifier_block * nb ,
unsigned long event , void * info )
{
struct dsa_switch * ds = container_of ( nb , struct dsa_switch , nb ) ;
int err ;
switch ( event ) {
2017-02-03 13:20:21 -05:00
case DSA_NOTIFIER_BRIDGE_JOIN :
err = dsa_switch_bridge_join ( ds , info ) ;
break ;
case DSA_NOTIFIER_BRIDGE_LEAVE :
err = dsa_switch_bridge_leave ( ds , info ) ;
break ;
2017-02-03 13:20:20 -05:00
default :
err = - EOPNOTSUPP ;
break ;
}
/* Non-switchdev operations cannot be rolled back. If a DSA driver
* returns an error during the chained call , switch chips may be in an
* inconsistent state .
*/
if ( err )
dev_dbg ( ds - > dev , " breaking chain for DSA event %lu (%d) \n " ,
event , err ) ;
return notifier_from_errno ( err ) ;
}
int dsa_switch_register_notifier ( struct dsa_switch * ds )
{
ds - > nb . notifier_call = dsa_switch_event ;
return raw_notifier_chain_register ( & ds - > dst - > nh , & ds - > nb ) ;
}
void dsa_switch_unregister_notifier ( struct dsa_switch * ds )
{
int err ;
err = raw_notifier_chain_unregister ( & ds - > dst - > nh , & ds - > nb ) ;
if ( err )
dev_err ( ds - > dev , " failed to unregister notifier (%d) \n " , err ) ;
}