Horatiu Vultur
2020-Jan-13 12:46 UTC
[Bridge] [RFC net-next Patch v2 4/4] net: bridge: mrp: switchdev: Add HW offload
Extend switchdev interface to add support for MRP. The HW is notified in following cases: - SWITCHDEV_OBJ_ID_PORT_MRP. This is used when a port is added/removed from the mrp ring. - SWITCHDEV_OBJ_ID_RING_ROLE_MRP. This is used when the role of the node changes. The current supported roles are Media Redundancy Manager and Media Redundancy Client. - SWITCHDEV_OBJ_ID_RING_TEST_MRP. This is used when to start/stop sending MRP_Test frames on the mrp ring ports. This is called only on nodes that have the role Media Redundancy Manager. - SWITCHDEV_ATTR_ID_MRP_PORT_STATE. This is used when the port's state is changed. It can be in blocking/forwarding mode. - SWITCHDEV_ATTR_ID_MRP_PORT_ROLE. This is used when ports's role changes. The roles of the port can be primary/secondary. This is required to notify HW because the MRP_Test frame contains the field MRP_PortRole that contains this information. - SWITCHDEV_ATTR_ID_MRP_STATE. This is used when the ring changes it states to open or closed. This is required to notify HW because the MRP_Test frame contains the field MRP_InState which contains this information. - SWITCHDEV_ATTR_ID_RING_TRANS. This is used to count the number of times the ring goes in open state. This is required to notify the HW because the MRP_Test frame contains the field MRP_Transition which contains this information. Signed-off-by: Horatiu Vultur <horatiu.vultur at microchip.com> --- include/net/switchdev.h | 52 ++++++++++ net/bridge/Makefile | 2 +- net/bridge/br_mrp.c | 96 +++++++++++------- net/bridge/br_mrp_switchdev.c | 180 ++++++++++++++++++++++++++++++++++ net/bridge/br_mrp_timer.c | 37 ++++++- net/bridge/br_private_mrp.h | 16 +++ 6 files changed, 344 insertions(+), 39 deletions(-) create mode 100644 net/bridge/br_mrp_switchdev.c diff --git a/include/net/switchdev.h b/include/net/switchdev.h index aee86a189432..c4cd180fbf5a 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -40,6 +40,12 @@ enum switchdev_attr_id { SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED, SWITCHDEV_ATTR_ID_BRIDGE_MROUTER, +#ifdef CONFIG_BRIDGE_MRP + SWITCHDEV_ATTR_ID_MRP_PORT_STATE, + SWITCHDEV_ATTR_ID_MRP_PORT_ROLE, + SWITCHDEV_ATTR_ID_MRP_RING_STATE, + SWITCHDEV_ATTR_ID_MRP_RING_TRANS, +#endif }; struct switchdev_attr { @@ -55,6 +61,12 @@ struct switchdev_attr { clock_t ageing_time; /* BRIDGE_AGEING_TIME */ bool vlan_filtering; /* BRIDGE_VLAN_FILTERING */ bool mc_disabled; /* MC_DISABLED */ +#ifdef CONFIG_BRIDGE_MRP + u8 mrp_port_state; /* MRP_PORT_STATE */ + u8 mrp_port_role; /* MRP_PORT_ROLE */ + u8 mrp_ring_state; /* MRP_RING_STATE */ + u32 mrp_ring_trans; /* MRP_RING_TRANSITION */ +#endif } u; }; @@ -63,6 +75,11 @@ enum switchdev_obj_id { SWITCHDEV_OBJ_ID_PORT_VLAN, SWITCHDEV_OBJ_ID_PORT_MDB, SWITCHDEV_OBJ_ID_HOST_MDB, +#ifdef CONFIG_BRIDGE_MRP + SWITCHDEV_OBJ_ID_PORT_MRP, + SWITCHDEV_OBJ_ID_RING_TEST_MRP, + SWITCHDEV_OBJ_ID_RING_ROLE_MRP, +#endif }; struct switchdev_obj { @@ -94,6 +111,41 @@ struct switchdev_obj_port_mdb { #define SWITCHDEV_OBJ_PORT_MDB(OBJ) \ container_of((OBJ), struct switchdev_obj_port_mdb, obj) +#ifdef CONFIG_BRIDGE_MRP +/* SWITCHDEV_OBJ_ID_PORT_MRP */ +struct switchdev_obj_port_mrp { + struct switchdev_obj obj; + struct net_device *port; + u32 ring_nr; +}; + +#define SWITCHDEV_OBJ_PORT_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_port_mrp, obj) + +/* SWITCHDEV_OBJ_ID_RING_TEST_MRP */ +struct switchdev_obj_ring_test_mrp { + struct switchdev_obj obj; + /* The value is in us and a value of 0 represents to stop */ + u32 interval; + u8 max; + u32 ring_nr; +}; + +#define SWITCHDEV_OBJ_RING_TEST_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_ring_test_mrp, obj) + +/* SWITCHDEV_OBJ_ID_RING_ROLE_MRP */ +struct switchdev_obj_ring_role_mrp { + struct switchdev_obj obj; + u8 ring_role; + u32 ring_nr; +}; + +#define SWITCHDEV_OBJ_RING_ROLE_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_ring_role_mrp, obj) + +#endif + typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj); enum switchdev_notifier_type { diff --git a/net/bridge/Makefile b/net/bridge/Makefile index 917826c9d8de..a51a9fc112ed 100644 --- a/net/bridge/Makefile +++ b/net/bridge/Makefile @@ -26,4 +26,4 @@ bridge-$(CONFIG_NET_SWITCHDEV) += br_switchdev.o obj-$(CONFIG_NETFILTER) += netfilter/ -bridge-$(CONFIG_BRIDGE_MRP) += br_mrp.o br_mrp_timer.o +bridge-$(CONFIG_BRIDGE_MRP) += br_mrp.o br_mrp_timer.o br_mrp_switchdev.o diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index 4173021d3bfa..d109fce226d5 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -78,6 +78,10 @@ void br_mrp_set_mrm_state(struct br_mrp *mrp, { br_debug(mrp->br, "mrm_state: %s\n", br_mrp_get_mrm_state(state)); mrp->mrm_state = state; + + br_mrp_switchdev_set_ring_state(mrp, state == BR_MRP_MRM_STATE_CHK_RC ? + BR_MRP_RING_STATE_CLOSED : + BR_MRP_RING_STATE_OPEN); } void br_mrp_set_mrc_state(struct br_mrp *mrp, @@ -101,9 +105,9 @@ static int br_mrp_set_mrm_role(struct br_mrp *mrp) br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_AC_STAT1); - mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; - mrp->ring_role = BR_MRP_RING_ROLE_MRM; + br_mrp_port_switchdev_set_state(mrp->p_port, BR_MRP_PORT_STATE_BLOCKED); + br_mrp_port_switchdev_set_state(mrp->s_port, BR_MRP_PORT_STATE_BLOCKED); + br_mrp_switchdev_set_ring_role(mrp, BR_MRP_RING_ROLE_MRM); if (br_mrp_is_port_up(mrp->p_port)) br_mrp_port_link_change(mrp->p_port, true); @@ -128,9 +132,9 @@ static int br_mrp_set_mrc_role(struct br_mrp *mrp) br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_AC_STAT1); - mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; - mrp->ring_role = BR_MRP_RING_ROLE_MRC; + br_mrp_port_switchdev_set_state(mrp->p_port, BR_MRP_PORT_STATE_BLOCKED); + br_mrp_port_switchdev_set_state(mrp->s_port, BR_MRP_PORT_STATE_BLOCKED); + br_mrp_switchdev_set_ring_role(mrp, BR_MRP_RING_ROLE_MRC); if (br_mrp_is_port_up(mrp->p_port)) br_mrp_port_link_change(mrp->p_port, true); @@ -385,7 +389,8 @@ static void br_mrp_mrm_recv_ring_test(struct br_mrp *mrp) br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_CHK_RC); break; case BR_MRP_MRM_STATE_CHK_RO: - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; + br_mrp_port_switchdev_set_state(mrp->s_port, + BR_MRP_PORT_STATE_BLOCKED); mrp->ring_test_curr_max = mrp->ring_test_conf_max - 1; mrp->ring_test_curr = 0; @@ -455,7 +460,8 @@ static void br_mrp_recv_ring_topo(struct net_bridge_port *port, case BR_MRP_MRC_STATE_PT: mrp->ring_link_curr_max = mrp->ring_link_conf_max; br_mrp_ring_link_up_stop(mrp); - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING; + br_mrp_port_switchdev_set_state(mrp->s_port, + BR_MRP_PORT_STATE_FORWARDING); br_mrp_clear_fdb_start(mrp, ntohs(hdr->interval)); br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_PT_IDLE); break; @@ -538,7 +544,8 @@ static void br_mrp_recv_ring_link(struct net_bridge_port *port, } if (type == BR_MRP_TLV_HEADER_RING_LINK_UP && !mrp->blocked) { - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; + br_mrp_port_switchdev_set_state(mrp->s_port, + BR_MRP_PORT_STATE_BLOCKED); mrp->ring_test_curr_max = mrp->ring_test_conf_max - 1; mrp->ring_test_curr = 0; @@ -570,8 +577,9 @@ static void br_mrp_recv_ring_link(struct net_bridge_port *port, if (type == BR_MRP_TLV_HEADER_RING_LINK_DOWN && mrp->react_on_link_change) { - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING; - mrp->ring_transitions++; + br_mrp_port_switchdev_set_state(mrp->s_port, + BR_MRP_PORT_STATE_FORWARDING); + br_mrp_switchdev_update_ring_transitions(mrp); br_mrp_ring_topo_req(mrp, 0); br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_CHK_RO); break; @@ -808,14 +816,16 @@ static void br_mrp_mrm_port_link(struct net_bridge_port *p, bool up) switch (mrp->mrm_state) { case BR_MRP_MRM_STATE_AC_STAT1: if (up && p == mrp->p_port) { - mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING; + br_mrp_port_switchdev_set_state(mrp->p_port, + BR_MRP_PORT_STATE_FORWARDING); br_mrp_ring_test_req(mrp, mrp->ring_test_conf_interval); br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_PRM_UP); } if (up && p != mrp->p_port) { mrp->s_port = mrp->p_port; mrp->p_port = p; - mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING; + br_mrp_port_switchdev_set_state(mrp->p_port, + BR_MRP_PORT_STATE_FORWARDING); br_mrp_ring_test_req(mrp, mrp->ring_test_conf_interval); br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_PRM_UP); } @@ -823,7 +833,8 @@ static void br_mrp_mrm_port_link(struct net_bridge_port *p, bool up) case BR_MRP_MRM_STATE_PRM_UP: if (!up && p == mrp->p_port) { br_mrp_ring_test_stop(mrp); - mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; + br_mrp_port_switchdev_set_state(mrp->p_port, + BR_MRP_PORT_STATE_BLOCKED); br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_AC_STAT1); } if (up && p != mrp->p_port) { @@ -838,14 +849,16 @@ static void br_mrp_mrm_port_link(struct net_bridge_port *p, bool up) if (!up && p == mrp->p_port) { mrp->s_port = mrp->p_port; mrp->p_port = p; - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; + br_mrp_port_switchdev_set_state(mrp->s_port, + BR_MRP_PORT_STATE_BLOCKED); br_mrp_ring_test_req(mrp, mrp->ring_test_conf_interval); br_mrp_ring_topo_req(mrp, topo_interval); br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_PRM_UP); break; } if (!up && p != mrp->p_port) { - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; + br_mrp_port_switchdev_set_state(mrp->s_port, + BR_MRP_PORT_STATE_BLOCKED); br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_PRM_UP); } break; @@ -853,16 +866,18 @@ static void br_mrp_mrm_port_link(struct net_bridge_port *p, bool up) if (!up && p == mrp->p_port) { mrp->p_port = mrp->s_port; mrp->s_port = p; - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; - mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING; + br_mrp_port_switchdev_set_role(mrp->s_port, + BR_MRP_PORT_STATE_BLOCKED); + br_mrp_port_switchdev_set_role(mrp->p_port, + BR_MRP_PORT_STATE_FORWARDING); br_mrp_ring_test_req(mrp, mrp->ring_test_conf_interval); br_mrp_ring_topo_req(mrp, topo_interval); - mrp->ring_transitions++; + br_mrp_switchdev_update_ring_transitions(mrp); br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_PRM_UP); break; } if (!up && p != mrp->p_port) { - mrp->ring_transitions++; + br_mrp_switchdev_update_ring_transitions(mrp); br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_PRM_UP); break; } @@ -887,13 +902,15 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up) switch (mrp->mrc_state) { case BR_MRP_MRC_STATE_AC_STAT1: if (up && p == mrp->p_port) { - mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING; + br_mrp_port_switchdev_set_state(mrp->p_port, + BR_MRP_PORT_STATE_FORWARDING); br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_DE_IDLE); } if (up && p != mrp->p_port) { mrp->s_port = mrp->p_port; mrp->p_port = p; - mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING; + br_mrp_port_switchdev_set_state(mrp->p_port, + BR_MRP_PORT_STATE_FORWARDING); br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_DE_IDLE); } break; @@ -908,7 +925,8 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up) br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_PT); } if (!up && p == mrp->p_port) { - mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; + br_mrp_port_switchdev_set_state(mrp->p_port, + BR_MRP_PORT_STATE_BLOCKED); br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_AC_STAT1); } break; @@ -916,7 +934,8 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up) if (!up && p != mrp->p_port) { mrp->ring_link_curr_max = mrp->ring_link_conf_max; br_mrp_ring_link_up_stop(mrp); - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; + br_mrp_port_switchdev_set_state(mrp->s_port, + BR_MRP_PORT_STATE_BLOCKED); br_mrp_ring_link_down_start(mrp, mrp->ring_link_conf_interval); br_mrp_ring_link_req(mrp->p_port, up, @@ -930,8 +949,10 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up) br_mrp_ring_link_up_stop(mrp); mrp->p_port = mrp->s_port; mrp->s_port = p; - mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING; - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; + br_mrp_port_switchdev_set_state(mrp->p_port, + BR_MRP_PORT_STATE_FORWARDING); + br_mrp_port_switchdev_set_state(mrp->s_port, + BR_MRP_PORT_STATE_BLOCKED); br_mrp_ring_link_down_start(mrp, mrp->ring_link_conf_interval); br_mrp_ring_link_req(mrp->p_port, up, @@ -953,7 +974,8 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up) } if (!up && p == mrp->p_port) { mrp->ring_link_curr_max = mrp->ring_link_conf_max; - mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; + br_mrp_port_switchdev_set_state(mrp->p_port, + BR_MRP_PORT_STATE_BLOCKED); br_mrp_ring_link_down_stop(mrp); br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_AC_STAT1); } @@ -961,7 +983,8 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up) case BR_MRP_MRC_STATE_PT_IDLE: if (!up && p != mrp->p_port) { mrp->ring_link_curr_max = mrp->ring_link_conf_max; - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; + br_mrp_port_switchdev_set_state(mrp->s_port, + BR_MRP_PORT_STATE_BLOCKED); br_mrp_ring_link_down_start(mrp, mrp->ring_link_conf_interval); br_mrp_ring_link_req(mrp->p_port, up, @@ -973,7 +996,8 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up) mrp->ring_link_curr_max = mrp->ring_link_conf_max; mrp->p_port = mrp->s_port; mrp->s_port = p; - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED; + br_mrp_port_switchdev_set_state(mrp->s_port, + BR_MRP_PORT_STATE_BLOCKED); br_mrp_ring_link_down_start(mrp, mrp->ring_link_conf_interval); br_mrp_ring_link_req(mrp->p_port, up, @@ -1183,7 +1207,7 @@ static int br_mrp_port_init(struct net_bridge_port *port, struct br_mrp *mrp, * to set again the role(MRM or MRC) */ br_mrp_reset_ring_state(mrp); - mrp->ring_role = BR_MRP_RING_ROLE_DISABLED; + br_mrp_switchdev_set_ring_role(mrp, BR_MRP_RING_ROLE_DISABLED); if (!port->mrp_port) { port->mrp_port = devm_kzalloc(&port->br->dev->dev, @@ -1194,8 +1218,9 @@ static int br_mrp_port_init(struct net_bridge_port *port, struct br_mrp *mrp, } port->mrp_port->mrp = mrp; - port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING; - port->mrp_port->role = role; + br_mrp_port_switchdev_set_role(port, BR_MRP_PORT_STATE_FORWARDING); + br_mrp_port_switchdev_set_role(port, role); + br_mrp_port_switchdev_add(port); if (role == BR_MRP_PORT_ROLE_PRIMARY) mrp->p_port = port; @@ -1218,15 +1243,16 @@ void br_mrp_port_uninit(struct net_bridge_port *port) mutex_lock(&mrp->lock); br_mrp_reset_ring_state(mrp); - mrp->ring_role = BR_MRP_RING_ROLE_DISABLED; + br_mrp_switchdev_set_ring_role(mrp, BR_MRP_RING_ROLE_DISABLED); if (port->mrp_port->role == BR_MRP_PORT_ROLE_PRIMARY) mrp->p_port = NULL; if (port->mrp_port->role == BR_MRP_PORT_ROLE_SECONDARY) mrp->s_port = NULL; - port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING; - port->mrp_port->role = BR_MRP_PORT_ROLE_NONE; + br_mrp_port_switchdev_set_state(port, BR_MRP_PORT_STATE_FORWARDING); + br_mrp_port_switchdev_set_role(port, BR_MRP_PORT_ROLE_NONE); + br_mrp_port_switchdev_del(port); port->mrp_port->mrp = NULL; devm_kfree(&port->br->dev->dev, port->mrp_port); diff --git a/net/bridge/br_mrp_switchdev.c b/net/bridge/br_mrp_switchdev.c new file mode 100644 index 000000000000..c02f46e0ca47 --- /dev/null +++ b/net/bridge/br_mrp_switchdev.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <net/switchdev.h> + +#include "br_private_mrp.h" + +int br_mrp_port_switchdev_add(struct net_bridge_port *p) +{ + struct net_bridge *br = p->br; + struct switchdev_obj_port_mrp mrp = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_PORT_MRP, + .port = p->dev, + .ring_nr = p->mrp_port->mrp->ring_nr, + }; + int err = 0; + + err = switchdev_port_obj_add(br->dev, &mrp.obj, NULL); + + if (err && err != -EOPNOTSUPP) + return err; + + return 0; +} + +int br_mrp_switchdev_set_ring_role(struct br_mrp *mrp, + enum br_mrp_ring_role_type role) +{ + struct switchdev_obj_ring_role_mrp mrp_role = { + .obj.orig_dev = mrp->br->dev, + .obj.id = SWITCHDEV_OBJ_ID_RING_ROLE_MRP, + .ring_role = role, + .ring_nr = mrp->ring_nr, + }; + int err = 0; + + mrp->ring_role = role; + + pr_info("%s role: %d\n", __func__, role); + + if (role == BR_MRP_RING_ROLE_DISABLED) + err = switchdev_port_obj_del(mrp->br->dev, &mrp_role.obj); + else + err = switchdev_port_obj_add(mrp->br->dev, &mrp_role.obj, NULL); + + if (err && err != -EOPNOTSUPP) + return err; + + return 0; +} + +int br_mrp_switchdev_send_ring_test(struct br_mrp *mrp, u32 interval, u8 max) +{ + struct switchdev_obj_ring_test_mrp test = { + .obj.orig_dev = mrp->br->dev, + .obj.id = SWITCHDEV_OBJ_ID_RING_TEST_MRP, + .interval = interval, + .max = max, + .ring_nr = mrp->ring_nr, + }; + int err = 0; + + if (interval == 0) + err = switchdev_port_obj_del(mrp->br->dev, &test.obj); + else + err = switchdev_port_obj_add(mrp->br->dev, &test.obj, NULL); + + return err; +} + +int br_mrp_port_switchdev_del(struct net_bridge_port *p) +{ + struct net_bridge *br = p->br; + struct switchdev_obj_port_mrp mrp = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_PORT_MRP, + .port = p->dev, + }; + int err = 0; + + if (!p->mrp_port->mrp) + return 0; + + mrp.ring_nr = p->mrp_port->mrp->ring_nr; + + err = switchdev_port_obj_del(br->dev, &mrp.obj); + + if (err && err != -EOPNOTSUPP) + return err; + + return 0; +} + +int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, + enum br_mrp_port_state_type state) +{ + struct switchdev_attr attr = { + .orig_dev = p->dev, + .id = SWITCHDEV_ATTR_ID_MRP_PORT_STATE, + .u.mrp_port_state = state, + }; + int err = 0; + + p->mrp_port->state = state; + + pr_info("%s port: %s, state: %d\n", __func__, p->dev->name, state); + + err = switchdev_port_attr_set(p->dev, &attr); + if (err && err != -EOPNOTSUPP) + br_warn(p->br, "error setting offload MRP state on port %u(%s)\n", + (unsigned int)p->port_no, p->dev->name); + + return err; +} + +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, + }; + int err; + + p->mrp_port->role = role; + + err = switchdev_port_attr_set(p->dev, &attr); + if (err && err != -EOPNOTSUPP) + return err; + + return 0; +} + +int br_mrp_switchdev_set_ring_state(struct br_mrp *mrp, + enum br_mrp_ring_state_type state) +{ + struct switchdev_attr attr = { + .id = SWITCHDEV_ATTR_ID_MRP_RING_STATE, + .u.mrp_ring_state = state, + }; + int err = 0; + + attr.orig_dev = mrp->p_port->dev, + err = switchdev_port_attr_set(mrp->p_port->dev, &attr); + if (err && err != -EOPNOTSUPP) + return err; + + attr.orig_dev = mrp->s_port->dev; + err = switchdev_port_attr_set(mrp->s_port->dev, &attr); + if (err && err != -EOPNOTSUPP) + return err; + + return err; +} + +int br_mrp_switchdev_update_ring_transitions(struct br_mrp *mrp) +{ + struct switchdev_attr attr = { + .id = SWITCHDEV_ATTR_ID_MRP_RING_TRANS, + }; + int err; + + mrp->ring_transitions++; + + attr.u.mrp_ring_trans = mrp->ring_transitions; + + attr.orig_dev = mrp->p_port->dev, + err = switchdev_port_attr_set(mrp->p_port->dev, &attr); + if (err && err != -EOPNOTSUPP) + return err; + + attr.orig_dev = mrp->s_port->dev; + err = switchdev_port_attr_set(mrp->s_port->dev, &attr); + if (err && err != -EOPNOTSUPP) + return err; + + return 0; +} + diff --git a/net/bridge/br_mrp_timer.c b/net/bridge/br_mrp_timer.c index 59aa8c05724f..6493fc94bd49 100644 --- a/net/bridge/br_mrp_timer.c +++ b/net/bridge/br_mrp_timer.c @@ -6,7 +6,8 @@ static void br_mrp_ring_open(struct br_mrp *mrp) { - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING; + br_mrp_port_switchdev_set_state(mrp->s_port, + BR_MRP_PORT_STATE_FORWARDING); mrp->ring_test_curr_max = mrp->ring_test_conf_max - 1; mrp->ring_test_curr = 0; @@ -18,7 +19,7 @@ static void br_mrp_ring_open(struct br_mrp *mrp) br_mrp_ring_test_req(mrp, mrp->ring_test_conf_interval); - mrp->ring_transitions++; + br_mrp_switchdev_update_ring_transitions(mrp); br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_CHK_RO); } @@ -111,7 +112,8 @@ static void br_mrp_ring_link_up_expired(struct work_struct *work) br_mrp_ring_link_req(mrp->p_port, true, interval); } else { mrp->ring_link_curr_max = mrp->ring_link_conf_max; - mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING; + br_mrp_port_switchdev_set_state(mrp->s_port, + BR_MRP_PORT_STATE_FORWARDING); br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_PT_IDLE); } @@ -152,12 +154,41 @@ static void br_mrp_ring_link_down_expired(struct work_struct *work) void br_mrp_ring_test_start(struct br_mrp *mrp, u32 interval) { + int err; + + err = br_mrp_switchdev_send_ring_test(mrp, interval, + mrp->ring_test_conf_max); + /* If HW can transmit the test frames then don't start anymore the + * SW timers + */ + if (!err) { + pr_info("HW timers started\n"); + return; + } else if (err != -EOPNOTSUPP) { + pr_info("HW can't start timers error: %d\n", err); + return; + } + queue_delayed_work(mrp->timers_queue, &mrp->ring_test_work, usecs_to_jiffies(interval)); } void br_mrp_ring_test_stop(struct br_mrp *mrp) { + int err; + + err = br_mrp_switchdev_send_ring_test(mrp, 0, 0); + /* If HW can stop the transmission of the test frames then the SW timers + * were not start so just exit + */ + if (!err) { + pr_info("HW timers stopped\n"); + return; + } else if (err != -EOPNOTSUPP) { + pr_info("HW can't stop timers error: %d\n", err); + return; + } + cancel_delayed_work(&mrp->ring_test_work); } diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 13fd2330ccfc..f3f34749774d 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -205,4 +205,20 @@ void br_mrp_ring_link_up_stop(struct br_mrp *mrp); void br_mrp_ring_link_down_start(struct br_mrp *mrp, u32 interval); void br_mrp_ring_link_down_stop(struct br_mrp *mrp); +/* br_mrp_switchdev.c */ +int br_mrp_port_switchdev_add(struct net_bridge_port *p); +int br_mrp_port_switchdev_del(struct net_bridge_port *p); +int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, + enum br_mrp_port_state_type state); +int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, + enum br_mrp_port_role_type role); + +int br_mrp_switchdev_set_ring_role(struct br_mrp *mrp, + enum br_mrp_ring_role_type role); +int br_mrp_switchdev_set_ring_state(struct br_mrp *mrp, + enum br_mrp_ring_state_type state); +int br_mrp_switchdev_update_ring_transitions(struct br_mrp *mrp); + +int br_mrp_switchdev_send_ring_test(struct br_mrp *mrp, u32 interval, u8 max); + #endif /* BR_PRIVATE_MRP_H_ */ -- 2.17.1
Andrew Lunn
2020-Jan-13 14:00 UTC
[Bridge] [RFC net-next Patch v2 4/4] net: bridge: mrp: switchdev: Add HW offload
On Mon, Jan 13, 2020 at 01:46:20PM +0100, Horatiu Vultur wrote:> +#ifdef CONFIG_BRIDGE_MRP > +/* SWITCHDEV_OBJ_ID_PORT_MRP */ > +struct switchdev_obj_port_mrp { > + struct switchdev_obj obj; > + struct net_device *port; > + u32 ring_nr; > +}; > + > +#define SWITCHDEV_OBJ_PORT_MRP(OBJ) \ > + container_of((OBJ), struct switchdev_obj_port_mrp, obj) > + > +/* SWITCHDEV_OBJ_ID_RING_TEST_MRP */ > +struct switchdev_obj_ring_test_mrp { > + struct switchdev_obj obj; > + /* The value is in us and a value of 0 represents to stop */ > + u32 interval; > + u8 max; > + u32 ring_nr; > +}; > + > +#define SWITCHDEV_OBJ_RING_TEST_MRP(OBJ) \ > + container_of((OBJ), struct switchdev_obj_ring_test_mrp, obj) > + > +/* SWITCHDEV_OBJ_ID_RING_ROLE_MRP */ > +struct switchdev_obj_ring_role_mrp { > + struct switchdev_obj obj; > + u8 ring_role; > + u32 ring_nr; > +};Hi Horatiu The structures above should give me enough information to build this, correct? Ethernet II, Src: 7a:8b:b1:35:96:e1 (7a:8b:b1:35:96:e1), Dst: Iec_00:00:01 (01:15:4e:00:00:01) Destination: Iec_00:00:01 (01:15:4e:00:00:01) Source: 7a:8b:b1:35:96:e1 (7a:8b:b1:35:96:e1) Type: MRP (0x88e3) PROFINET MRP MRP_Test, MRP_Common, MRP_End MRP_Version: 1 MRP_TLVHeader.Type: MRP_Test (0x02) MRP_TLVHeader.Type: MRP_Test (0x02) MRP_TLVHeader.Length: 18 MRP_Prio: 0x1f40 High priorities MRP_SA: 7a:8b:b1:35:96:e1 (7a:8b:b1:35:96:e1) MRP_PortRole: Primary ring port (0x0000) MRP_RingState: Ring closed (0x0001) MRP_Transition: 0x0001 MRP_TimeStamp [ms]: 0x000cf574 <---------- Updated automatic MRP_TLVHeader.Type: MRP_Common (0x01) MRP_TLVHeader.Type: MRP_Common (0x01) MRP_TLVHeader.Length: 18 MRP_SequenceID: 0x00e9 <---------- Updated automatic MRP_DomainUUID: ffffffff-ffff-ffff-ffff-ffffffffffff MRP_TLVHeader.Type: MRP_End (0x00) MRP_TLVHeader.Type: MRP_End (0x00) MRP_TLVHeader.Length: 0 There are a couple of fields i don't see. MRP_SA, MRP_Transition. What are max and ring_nr used for? Do you need to set the first value MRP_SequenceID uses? Often, in order to detect a reset, a random value is used to initialise the sequence number. Also, does the time stamp need initializing? Thanks Andrew