2020-04-26 16:22:04 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
# include <net/switchdev.h>
# include "br_private_mrp.h"
2021-02-17 00:42:01 +03:00
static enum br_mrp_hw_support
br_mrp_switchdev_port_obj ( struct net_bridge * br ,
const struct switchdev_obj * obj , bool add )
{
int err ;
if ( add )
err = switchdev_port_obj_add ( br - > dev , obj , NULL ) ;
else
err = switchdev_port_obj_del ( br - > dev , obj ) ;
/* In case of success just return and notify the SW that doesn't need
* to do anything
*/
if ( ! err )
return BR_MRP_HW ;
if ( err ! = - EOPNOTSUPP )
return BR_MRP_NONE ;
/* Continue with SW backup */
return BR_MRP_SW ;
}
2020-04-26 16:22:04 +03:00
int br_mrp_switchdev_add ( struct net_bridge * br , struct br_mrp * mrp )
{
struct switchdev_obj_mrp mrp_obj = {
. obj . orig_dev = br - > dev ,
. obj . id = SWITCHDEV_OBJ_ID_MRP ,
. p_port = rtnl_dereference ( mrp - > p_port ) - > dev ,
. s_port = rtnl_dereference ( mrp - > s_port ) - > dev ,
. ring_id = mrp - > ring_id ,
2020-05-30 21:09:47 +03:00
. prio = mrp - > prio ,
2020-04-26 16:22:04 +03:00
} ;
2021-02-17 00:42:01 +03:00
if ( ! IS_ENABLED ( CONFIG_NET_SWITCHDEV ) )
return 0 ;
2020-04-26 16:22:04 +03:00
2021-02-17 00:42:01 +03:00
return switchdev_port_obj_add ( br - > dev , & mrp_obj . obj , NULL ) ;
2020-04-26 16:22:04 +03:00
}
int br_mrp_switchdev_del ( struct net_bridge * br , struct br_mrp * mrp )
{
struct switchdev_obj_mrp mrp_obj = {
. obj . orig_dev = br - > dev ,
. obj . id = SWITCHDEV_OBJ_ID_MRP ,
. p_port = NULL ,
. s_port = NULL ,
. ring_id = mrp - > ring_id ,
} ;
2021-02-17 00:42:01 +03:00
if ( ! IS_ENABLED ( CONFIG_NET_SWITCHDEV ) )
return 0 ;
2020-04-26 16:22:04 +03:00
2021-02-17 00:42:01 +03:00
return switchdev_port_obj_del ( br - > dev , & mrp_obj . obj ) ;
2020-04-26 16:22:04 +03:00
}
2021-02-17 00:42:01 +03:00
enum br_mrp_hw_support
br_mrp_switchdev_set_ring_role ( struct net_bridge * br , struct br_mrp * mrp ,
enum br_mrp_ring_role_type role )
2020-04-26 16:22:04 +03:00
{
struct switchdev_obj_ring_role_mrp mrp_role = {
. obj . orig_dev = br - > dev ,
. obj . id = SWITCHDEV_OBJ_ID_RING_ROLE_MRP ,
. ring_role = role ,
. ring_id = mrp - > ring_id ,
2021-02-17 00:42:01 +03:00
. sw_backup = false ,
2020-04-26 16:22:04 +03:00
} ;
2021-02-17 00:42:01 +03:00
enum br_mrp_hw_support support ;
2020-04-26 16:22:04 +03:00
int err ;
2021-02-17 00:42:01 +03:00
if ( ! IS_ENABLED ( CONFIG_NET_SWITCHDEV ) )
return BR_MRP_SW ;
support = br_mrp_switchdev_port_obj ( br , & mrp_role . obj ,
role ! = BR_MRP_RING_ROLE_DISABLED ) ;
if ( support ! = BR_MRP_SW )
return support ;
/* If the driver can't configure to run completely the protocol in HW,
* then try again to configure the HW so the SW can run the protocol .
*/
mrp_role . sw_backup = true ;
if ( role ! = BR_MRP_RING_ROLE_DISABLED )
2020-04-26 16:22:04 +03:00
err = switchdev_port_obj_add ( br - > dev , & mrp_role . obj , NULL ) ;
2021-02-17 00:42:01 +03:00
else
err = switchdev_port_obj_del ( br - > dev , & mrp_role . obj ) ;
2020-04-26 16:22:04 +03:00
2021-02-17 00:42:01 +03:00
if ( ! err )
return BR_MRP_SW ;
return BR_MRP_NONE ;
2020-04-26 16:22:04 +03:00
}
2021-02-17 00:42:01 +03:00
enum br_mrp_hw_support
br_mrp_switchdev_send_ring_test ( struct net_bridge * br , struct br_mrp * mrp ,
u32 interval , u8 max_miss , u32 period ,
bool monitor )
2020-04-26 16:22:04 +03:00
{
struct switchdev_obj_ring_test_mrp test = {
. obj . orig_dev = br - > dev ,
. obj . id = SWITCHDEV_OBJ_ID_RING_TEST_MRP ,
. interval = interval ,
. max_miss = max_miss ,
. ring_id = mrp - > ring_id ,
. period = period ,
2020-05-30 21:09:48 +03:00
. monitor = monitor ,
2020-04-26 16:22:04 +03:00
} ;
2021-02-17 00:42:01 +03:00
if ( ! IS_ENABLED ( CONFIG_NET_SWITCHDEV ) )
return BR_MRP_SW ;
2020-04-26 16:22:04 +03:00
2021-02-17 00:42:01 +03:00
return br_mrp_switchdev_port_obj ( br , & test . obj , interval ! = 0 ) ;
2020-04-26 16:22:04 +03:00
}
int br_mrp_switchdev_set_ring_state ( struct net_bridge * br ,
struct br_mrp * mrp ,
enum br_mrp_ring_state_type state )
{
struct switchdev_obj_ring_state_mrp mrp_state = {
. obj . orig_dev = br - > dev ,
. obj . id = SWITCHDEV_OBJ_ID_RING_STATE_MRP ,
. ring_state = state ,
. ring_id = mrp - > ring_id ,
} ;
2021-02-17 00:42:01 +03:00
if ( ! IS_ENABLED ( CONFIG_NET_SWITCHDEV ) )
return 0 ;
2020-04-26 16:22:04 +03:00
2021-02-17 00:42:01 +03:00
return switchdev_port_obj_add ( br - > dev , & mrp_state . obj , NULL ) ;
2020-04-26 16:22:04 +03:00
}
2021-02-17 00:42:01 +03:00
enum br_mrp_hw_support
br_mrp_switchdev_set_in_role ( struct net_bridge * br , struct br_mrp * mrp ,
u16 in_id , u32 ring_id ,
enum br_mrp_in_role_type role )
2020-07-14 10:34:53 +03:00
{
struct switchdev_obj_in_role_mrp mrp_role = {
. obj . orig_dev = br - > dev ,
. obj . id = SWITCHDEV_OBJ_ID_IN_ROLE_MRP ,
. in_role = role ,
. in_id = mrp - > in_id ,
. ring_id = mrp - > ring_id ,
. i_port = rtnl_dereference ( mrp - > i_port ) - > dev ,
2021-02-17 00:42:01 +03:00
. sw_backup = false ,
2020-07-14 10:34:53 +03:00
} ;
2021-02-17 00:42:01 +03:00
enum br_mrp_hw_support support ;
2020-07-14 10:34:53 +03:00
int err ;
2021-02-17 00:42:01 +03:00
if ( ! IS_ENABLED ( CONFIG_NET_SWITCHDEV ) )
return BR_MRP_SW ;
support = br_mrp_switchdev_port_obj ( br , & mrp_role . obj ,
role ! = BR_MRP_IN_ROLE_DISABLED ) ;
if ( support ! = BR_MRP_NONE )
return support ;
/* If the driver can't configure to run completely the protocol in HW,
* then try again to configure the HW so the SW can run the protocol .
*/
mrp_role . sw_backup = true ;
if ( role ! = BR_MRP_IN_ROLE_DISABLED )
2020-07-14 10:34:53 +03:00
err = switchdev_port_obj_add ( br - > dev , & mrp_role . obj , NULL ) ;
2021-02-17 00:42:01 +03:00
else
err = switchdev_port_obj_del ( br - > dev , & mrp_role . obj ) ;
if ( ! err )
return BR_MRP_SW ;
2020-07-14 10:34:53 +03:00
2021-02-17 00:42:01 +03:00
return BR_MRP_NONE ;
2020-07-14 10:34:53 +03:00
}
int br_mrp_switchdev_set_in_state ( struct net_bridge * br , struct br_mrp * mrp ,
enum br_mrp_in_state_type state )
{
struct switchdev_obj_in_state_mrp mrp_state = {
. obj . orig_dev = br - > dev ,
. obj . id = SWITCHDEV_OBJ_ID_IN_STATE_MRP ,
. in_state = state ,
. in_id = mrp - > in_id ,
} ;
2021-02-17 00:42:01 +03:00
if ( ! IS_ENABLED ( CONFIG_NET_SWITCHDEV ) )
return 0 ;
2020-07-14 10:34:53 +03:00
2021-02-17 00:42:01 +03:00
return switchdev_port_obj_add ( br - > dev , & mrp_state . obj , NULL ) ;
2020-07-14 10:34:53 +03:00
}
2021-02-17 00:42:01 +03:00
enum br_mrp_hw_support
br_mrp_switchdev_send_in_test ( struct net_bridge * br , struct br_mrp * mrp ,
u32 interval , u8 max_miss , u32 period )
2020-07-14 10:34:53 +03:00
{
struct switchdev_obj_in_test_mrp test = {
. obj . orig_dev = br - > dev ,
. obj . id = SWITCHDEV_OBJ_ID_IN_TEST_MRP ,
. interval = interval ,
. max_miss = max_miss ,
. in_id = mrp - > in_id ,
. period = period ,
} ;
2021-02-17 00:42:01 +03:00
if ( ! IS_ENABLED ( CONFIG_NET_SWITCHDEV ) )
return BR_MRP_SW ;
2020-07-14 10:34:53 +03:00
2021-02-17 00:42:01 +03:00
return br_mrp_switchdev_port_obj ( br , & test . obj , interval ! = 0 ) ;
2020-07-14 10:34:53 +03:00
}
2021-02-07 00:47:33 +03:00
int br_mrp_port_switchdev_set_state ( struct net_bridge_port * p , u32 state )
2020-04-26 16:22:04 +03:00
{
struct switchdev_attr attr = {
. orig_dev = p - > dev ,
2021-02-07 00:47:33 +03:00
. id = SWITCHDEV_ATTR_ID_PORT_STP_STATE ,
. u . stp_state = state ,
2020-04-26 16:22:04 +03:00
} ;
2021-02-17 00:42:01 +03:00
if ( ! IS_ENABLED ( CONFIG_NET_SWITCHDEV ) )
return 0 ;
2020-04-26 16:22:04 +03:00
2021-02-17 00:42:01 +03:00
return switchdev_port_attr_set ( p - > dev , & attr , NULL ) ;
2020-04-26 16:22:04 +03:00
}
int br_mrp_port_switchdev_set_role ( struct net_bridge_port * p ,
enum br_mrp_port_role_type role )
{
struct switchdev_attr attr = {
. orig_dev = p - > dev ,
. id = SWITCHDEV_ATTR_ID_MRP_PORT_ROLE ,
. u . mrp_port_role = role ,
} ;
2021-02-17 00:42:01 +03:00
if ( ! IS_ENABLED ( CONFIG_NET_SWITCHDEV ) )
return 0 ;
2020-04-26 16:22:04 +03:00
2021-02-17 00:42:01 +03:00
return switchdev_port_attr_set ( p - > dev , & attr , NULL ) ;
2020-04-26 16:22:04 +03:00
}