This patch series extends MRP switchdev to allow the SW to have a better
understanding if the HW can implement the MRP functionality or it needs
to help the HW to run it. There are 3 cases:
- when HW can't implement at all the functionality.
- when HW can implement a part of the functionality but needs the SW
implement the rest. For example if it can't detect when it stops
receiving MRP Test frames but it can copy the MRP frames to CPU to
allow the SW to determine this. Another example is generating the MRP
Test frames. If HW can't do that then the SW is used as backup.
- when HW can implement completely the functionality.
So, initially the SW tries to offload the entire functionality in HW, if
that fails it tries offload parts of the functionality in HW and use the
SW as helper and if also this fails then MRP can't run on this HW.
Based on these new calls, implement the switchdev for Ocelot driver. This
is an example where the HW can't run completely the functionality but it
can help the SW to run it, by trapping all MRP frames to CPU.
Also this patch series adds MRP support to DSA and implements the Felix
driver which just reuse the Ocelot functions. This part was just compiled
tested because I don't have any HW on which to do the actual tests.
v4:
- remove ifdef MRP from include/net/switchdev.h
- move MRP implementation for Ocelot in a different file such that
Felix driver can use it.
- extend DSA with MRP support
- implement MRP support for Felix.
v3:
- implement the switchdev calls needed by Ocelot driver.
v2:
- fix typos in comments and in commit messages
- remove some of the comments
- move repeated code in helper function
- fix issue when deleting a node when sw_backup was true
Horatiu Vultur (8):
switchdev: mrp: Remove CONFIG_BRIDGE_MRP
switchdev: mrp: Extend ring_role_mrp and in_role_mrp
bridge: mrp: Add 'enum br_mrp_hw_support'
bridge: mrp: Extend br_mrp_switchdev to detect better the errors
bridge: mrp: Update br_mrp to use new return values of
br_mrp_switchdev
net: mscc: ocelot: Add support for MRP
net: dsa: add MRP support
net: dsa: felix: Add support for MRP
drivers/net/dsa/ocelot/felix.c | 38 ++++++
drivers/net/ethernet/mscc/Makefile | 1 +
drivers/net/ethernet/mscc/ocelot.c | 10 +-
drivers/net/ethernet/mscc/ocelot_mrp.c | 175 +++++++++++++++++++++++++
drivers/net/ethernet/mscc/ocelot_net.c | 60 +++++++++
include/linux/dsa/ocelot.h | 5 +
include/net/dsa.h | 12 ++
include/net/switchdev.h | 12 +-
include/soc/mscc/ocelot.h | 45 +++++++
net/bridge/br_mrp.c | 43 +++---
net/bridge/br_mrp_switchdev.c | 171 ++++++++++++++----------
net/bridge/br_private_mrp.h | 38 ++++--
net/dsa/dsa_priv.h | 26 ++++
net/dsa/port.c | 48 +++++++
net/dsa/slave.c | 22 ++++
net/dsa/switch.c | 105 +++++++++++++++
net/dsa/tag_ocelot.c | 8 ++
17 files changed, 715 insertions(+), 104 deletions(-)
create mode 100644 drivers/net/ethernet/mscc/ocelot_mrp.c
--
2.27.0
Remove #IS_ENABLED(CONFIG_BRIDGE_MRP) from switchdev.h. This will
simplify the code implements MRP callbacks and will be similar with the
vlan filtering.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
include/net/switchdev.h | 10 ----------
1 file changed, 10 deletions(-)
Add the member sw_backup to the structures switchdev_obj_ring_role_mrp
and switchdev_obj_in_role_mrp. In this way the SW can call the driver in
2 ways, once when sw_backup is set to false, meaning that the driver
should implement this completely in HW. And if that is not supported the
SW will call again but with sw_backup set to true, meaning that the
HW should help or allow the SW to run the protocol.
For example when role is MRM, if the HW can't detect when it stops
receiving MRP Test frames but it can trap these frames to CPU, then it
needs to return -EOPNOTSUPP when sw_backup is false and return 0 when
sw_backup is true.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
include/net/switchdev.h | 2 ++
1 file changed, 2 insertions(+)
Add basic support for MRP. The HW will just trap all MRP frames on the
ring ports to CPU and allow the SW to process them. In this way it is
possible to for this node to behave both as MRM and MRC.
Current limitations are:
- it doesn't support Interconnect roles.
- it supports only a single ring.
- the HW should be able to do forwarding of MRP Test frames so the SW
will not need to do this. So it would be able to have the role MRC
without SW support.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
drivers/net/ethernet/mscc/Makefile | 1 +
drivers/net/ethernet/mscc/ocelot.c | 10 +-
drivers/net/ethernet/mscc/ocelot_mrp.c | 175 +++++++++++++++++++++++++
drivers/net/ethernet/mscc/ocelot_net.c | 60 +++++++++
include/linux/dsa/ocelot.h | 5 +
include/soc/mscc/ocelot.h | 45 +++++++
6 files changed, 295 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/mscc/ocelot_mrp.c
Add the enum br_mrp_hw_support that is used by the br_mrp_switchdev
functions to allow the SW to detect the cases where HW can't implement
the functionality or when SW is used as a backup.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
net/bridge/br_private_mrp.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
@@ -46,6 +46,20 @@ struct br_mrp {structrcu_headrcu;};+/* This type is returned by br_mrp_switchdev functions that allow to have a SW+*backupincasetheHWcan'timplementcompletelytheprotocol.+*BR_MRP_NONE-meanstheHWcan'trunatalltheprotocol,sotheSWstops+*configuringthenodeanymore.+*BR_MRP_SW-theHWcanhelptheSWtoruntheprotocol,byredirectingMRP+*framestoCPU.+*BR_MRP_HW-theHWcanimplementcompletelytheprotocol.+*/+enumbr_mrp_hw_support{+BR_MRP_NONE,+BR_MRP_SW,+BR_MRP_HW,+};+/* br_mrp.c */intbr_mrp_add(structnet_bridge*br,structbr_mrp_instance*instance);intbr_mrp_del(structnet_bridge*br,structbr_mrp_instance*instance);
@@ -639,7 +639,7 @@ int br_mrp_set_ring_role(struct net_bridge *br,structbr_mrp_ring_role*role){structbr_mrp*mrp=br_mrp_find_id(br,role->ring_id);-interr;+enumbr_mrp_hw_supportsupport;if(!mrp)return-EINVAL;
@@ -647,9 +647,9 @@ int br_mrp_set_ring_role(struct net_bridge *br,mrp->ring_role=role->ring_role;/* If there is an error just bailed out */-err=br_mrp_switchdev_set_ring_role(br,mrp,role->ring_role);-if(err&&err!=-EOPNOTSUPP)-returnerr;+support=br_mrp_switchdev_set_ring_role(br,mrp,role->ring_role);+if(support==BR_MRP_NONE)+return-EOPNOTSUPP;/* Now detect if the HW actually applied the role or not. If the HW*appliedtheroleitmeansthattheSWwillnottodothoseoperations
@@ -657,7 +657,7 @@ int br_mrp_set_ring_role(struct net_bridge *br,*SWwhenringisopen,butiftheisnotpushedtotheHWtheSWwill*needtodetectwhentheringisopen*/-mrp->ring_role_offloaded=err==-EOPNOTSUPP?0:1;+mrp->ring_role_offloaded=support==BR_MRP_SW?0:1;return0;}
@@ -670,6 +670,7 @@ int br_mrp_start_test(struct net_bridge *br,structbr_mrp_start_test*test){structbr_mrp*mrp=br_mrp_find_id(br,test->ring_id);+enumbr_mrp_hw_supportsupport;if(!mrp)return-EINVAL;
@@ -677,9 +678,13 @@ int br_mrp_start_test(struct net_bridge *br,/* Try to push it to the HW and if it fails then continue with SW*implementationandifthatalsofailsthenreturnerror.*/-if(!br_mrp_switchdev_send_ring_test(br,mrp,test->interval,-test->max_miss,test->period,-test->monitor))+support=br_mrp_switchdev_send_ring_test(br,mrp,test->interval,+test->max_miss,test->period,+test->monitor);+if(support==BR_MRP_NONE)+return-EOPNOTSUPP;++if(support==BR_MRP_HW)return0;mrp->test_interval=test->interval;
@@ -780,10 +785,10 @@ int br_mrp_set_in_role(struct net_bridge *br, struct br_mrp_in_role *role)mrp->in_id=role->in_id;/* If there is an error just bailed out */-err=br_mrp_switchdev_set_in_role(br,mrp,role->in_id,-role->ring_id,role->in_role);-if(err&&err!=-EOPNOTSUPP)-returnerr;+support=br_mrp_switchdev_set_in_role(br,mrp,role->in_id,+role->ring_id,role->in_role);+if(support==BR_MRP_NONE)+return-EOPNOTSUPP;/* Now detect if the HW actually applied the role or not. If the HW*appliedtheroleitmeansthattheSWwillnottodothoseoperations
@@ -804,6 +809,7 @@ int br_mrp_start_in_test(struct net_bridge *br,structbr_mrp_start_in_test*in_test){structbr_mrp*mrp=br_mrp_find_in_id(br,in_test->in_id);+enumbr_mrp_hw_supportsupport;if(!mrp)return-EINVAL;
@@ -814,8 +820,13 @@ int br_mrp_start_in_test(struct net_bridge *br,/* Try to push it to the HW and if it fails then continue with SW*implementationandifthatalsofailsthenreturnerror.*/-if(!br_mrp_switchdev_send_in_test(br,mrp,in_test->interval,-in_test->max_miss,in_test->period))+support=br_mrp_switchdev_send_in_test(br,mrp,in_test->interval,+in_test->max_miss,+in_test->period);+if(support==BR_MRP_NONE)+return-EOPNOTSUPP;++if(support==BR_MRP_HW)return0;mrp->in_test_interval=in_test->interval;
This patch extends the br_mrp_switchdev functions to be able to have a
better understanding what cause the issue and if the SW needs to be used
as a backup.
There are the following cases:
- when the code is compiled without CONFIG_NET_SWITCHDEV. In this case
return success so the SW can continue with the protocol. Depending
on the function, it returns 0 or BR_MRP_SW.
- when code is compiled with CONFIG_NET_SWITCHDEV and the driver doesn't
implement any MRP callbacks. In this case the HW can't run MRP so it
just returns -EOPNOTSUPP. So the SW will stop further to configure the
node.
- when code is compiled with CONFIG_NET_SWITCHDEV and the driver fully
supports any MRP functionality. In this case the SW doesn't need to do
anything. The functions will return 0 or BR_MRP_HW.
- when code is compiled with CONFIG_NET_SWITCHDEV and the HW can't run
completely the protocol but it can help the SW to run it. For
example, the HW can't support completely MRM role(can't detect when it
stops receiving MRP Test frames) but it can redirect these frames to
CPU. In this case it is possible to have a SW fallback. The SW will
try initially to call the driver with sw_backup set to false, meaning
that the HW should implement completely the role. If the driver returns
-EOPNOTSUPP, the SW will try again with sw_backup set to false,
meaning that the SW will detect when it stops receiving the frames but
it needs HW support to redirect the frames to CPU. In case the driver
returns 0 then the SW will continue to configure the node accordingly.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
net/bridge/br_mrp_switchdev.c | 171 +++++++++++++++++++++-------------
net/bridge/br_private_mrp.h | 24 +++--
2 files changed, 118 insertions(+), 77 deletions(-)
@@ -4,6 +4,30 @@#include"br_private_mrp.h"+staticenumbr_mrp_hw_support+br_mrp_switchdev_port_obj(structnet_bridge*br,+conststructswitchdev_obj*obj,booladd)+{+interr;++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+*todoanything+*/+if(!err)+returnBR_MRP_HW;++if(err!=-EOPNOTSUPP)+returnBR_MRP_NONE;++/* Continue with SW backup */+returnBR_MRP_SW;+}+intbr_mrp_switchdev_add(structnet_bridge*br,structbr_mrp*mrp){structswitchdev_obj_mrpmrp_obj={
@@ -33,40 +54,54 @@ int br_mrp_switchdev_del(struct net_bridge *br, struct br_mrp *mrp).s_port=NULL,.ring_id=mrp->ring_id,};-interr;--err=switchdev_port_obj_del(br->dev,&mrp_obj.obj);-if(err&&err!=-EOPNOTSUPP)-returnerr;+if(!IS_ENABLED(CONFIG_NET_SWITCHDEV))+return0;-return0;+returnswitchdev_port_obj_del(br->dev,&mrp_obj.obj);}-intbr_mrp_switchdev_set_ring_role(structnet_bridge*br,-structbr_mrp*mrp,-enumbr_mrp_ring_role_typerole)+enumbr_mrp_hw_support+br_mrp_switchdev_set_ring_role(structnet_bridge*br,structbr_mrp*mrp,+enumbr_mrp_ring_role_typerole){structswitchdev_obj_ring_role_mrpmrp_role={.obj.orig_dev=br->dev,.obj.id=SWITCHDEV_OBJ_ID_RING_ROLE_MRP,.ring_role=role,.ring_id=mrp->ring_id,+.sw_backup=false,};+enumbr_mrp_hw_supportsupport;interr;-if(role==BR_MRP_RING_ROLE_DISABLED)-err=switchdev_port_obj_del(br->dev,&mrp_role.obj);-else+if(!IS_ENABLED(CONFIG_NET_SWITCHDEV))+returnBR_MRP_SW;++support=br_mrp_switchdev_port_obj(br,&mrp_role.obj,+role!=BR_MRP_RING_ROLE_DISABLED);+if(support!=BR_MRP_SW)+returnsupport;++/* If the driver can't configure to run completely the protocol in HW,+*thentryagaintoconfiguretheHWsotheSWcanruntheprotocol.+*/+mrp_role.sw_backup=true;+if(role!=BR_MRP_RING_ROLE_DISABLED)err=switchdev_port_obj_add(br->dev,&mrp_role.obj,NULL);+else+err=switchdev_port_obj_del(br->dev,&mrp_role.obj);-returnerr;+if(!err)+returnBR_MRP_SW;++returnBR_MRP_NONE;}-intbr_mrp_switchdev_send_ring_test(structnet_bridge*br,-structbr_mrp*mrp,u32interval,-u8max_miss,u32period,-boolmonitor)+enumbr_mrp_hw_support+br_mrp_switchdev_send_ring_test(structnet_bridge*br,structbr_mrp*mrp,+u32interval,u8max_miss,u32period,+boolmonitor){structswitchdev_obj_ring_test_mrptest={.obj.orig_dev=br->dev,
@@ -77,14 +112,11 @@ int br_mrp_switchdev_send_ring_test(struct net_bridge *br,.period=period,.monitor=monitor,};-interr;-if(interval==0)-err=switchdev_port_obj_del(br->dev,&test.obj);-else-err=switchdev_port_obj_add(br->dev,&test.obj,NULL);+if(!IS_ENABLED(CONFIG_NET_SWITCHDEV))+returnBR_MRP_SW;-returnerr;+returnbr_mrp_switchdev_port_obj(br,&test.obj,interval!=0);}intbr_mrp_switchdev_set_ring_state(structnet_bridge*br,
@@ -97,19 +129,17 @@ int br_mrp_switchdev_set_ring_state(struct net_bridge *br,.ring_state=state,.ring_id=mrp->ring_id,};-interr;--err=switchdev_port_obj_add(br->dev,&mrp_state.obj,NULL);-if(err&&err!=-EOPNOTSUPP)-returnerr;+if(!IS_ENABLED(CONFIG_NET_SWITCHDEV))+return0;-return0;+returnswitchdev_port_obj_add(br->dev,&mrp_state.obj,NULL);}-intbr_mrp_switchdev_set_in_role(structnet_bridge*br,structbr_mrp*mrp,-u16in_id,u32ring_id,-enumbr_mrp_in_role_typerole)+enumbr_mrp_hw_support+br_mrp_switchdev_set_in_role(structnet_bridge*br,structbr_mrp*mrp,+u16in_id,u32ring_id,+enumbr_mrp_in_role_typerole){structswitchdev_obj_in_role_mrpmrp_role={.obj.orig_dev=br->dev,
@@ -118,15 +148,32 @@ int br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp,.in_id=mrp->in_id,.ring_id=mrp->ring_id,.i_port=rtnl_dereference(mrp->i_port)->dev,+.sw_backup=false,};+enumbr_mrp_hw_supportsupport;interr;-if(role==BR_MRP_IN_ROLE_DISABLED)-err=switchdev_port_obj_del(br->dev,&mrp_role.obj);-else+if(!IS_ENABLED(CONFIG_NET_SWITCHDEV))+returnBR_MRP_SW;++support=br_mrp_switchdev_port_obj(br,&mrp_role.obj,+role!=BR_MRP_IN_ROLE_DISABLED);+if(support!=BR_MRP_NONE)+returnsupport;++/* If the driver can't configure to run completely the protocol in HW,+*thentryagaintoconfiguretheHWsotheSWcanruntheprotocol.+*/+mrp_role.sw_backup=true;+if(role!=BR_MRP_IN_ROLE_DISABLED)err=switchdev_port_obj_add(br->dev,&mrp_role.obj,NULL);+else+err=switchdev_port_obj_del(br->dev,&mrp_role.obj);++if(!err)+returnBR_MRP_SW;-returnerr;+returnBR_MRP_NONE;}intbr_mrp_switchdev_set_in_state(structnet_bridge*br,structbr_mrp*mrp,
@@ -176,14 +218,11 @@ int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, u32 state).id=SWITCHDEV_ATTR_ID_PORT_STP_STATE,.u.stp_state=state,};-interr;-err=switchdev_port_attr_set(p->dev,&attr,NULL);-if(err&&err!=-EOPNOTSUPP)-br_warn(p->br,"error setting offload MRP state on port %u(%s)\n",-(unsignedint)p->port_no,p->dev->name);+if(!IS_ENABLED(CONFIG_NET_SWITCHDEV))+return0;-returnerr;+returnswitchdev_port_attr_set(p->dev,&attr,NULL);}intbr_mrp_port_switchdev_set_role(structnet_bridge_port*p,
@@ -194,11 +233,9 @@ int br_mrp_port_switchdev_set_role(struct net_bridge_port *p,.id=SWITCHDEV_ATTR_ID_MRP_PORT_ROLE,.u.mrp_port_role=role,};-interr;-err=switchdev_port_attr_set(p->dev,&attr,NULL);-if(err&&err!=-EOPNOTSUPP)-returnerr;+if(!IS_ENABLED(CONFIG_NET_SWITCHDEV))+return0;-return0;+returnswitchdev_port_attr_set(p->dev,&attr,NULL);}
Add support for offloading MRP in HW. Currently implement the switchdev
calls 'SWITCHDEV_OBJ_ID_MRP', 'SWITCHDEV_OBJ_ID_RING_ROLE_MRP',
to allow to create MRP instances and to set the role of these instances.
Add DSA_NOTIFIER_MRP_ADD/DEL and DSA_NOTIFIER_MRP_ADD/DEL_RING_ROLE
which calls to .port_mrp_add/del and .port_mrp_add/del_ring_role in the
DSA driver for the switch.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
include/net/dsa.h | 12 ++++++
net/dsa/dsa_priv.h | 26 +++++++++++
net/dsa/port.c | 48 +++++++++++++++++++++
net/dsa/slave.c | 22 ++++++++++
net/dsa/switch.c | 105 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 213 insertions(+)
Implement functions 'port_mrp_add', 'port_mrp_del',
'port_mrp_add_ring_role' and 'port_mrp_del_ring_role' to call the mrp
functions from ocelot.
Also all MRP frames that arrive to CPU on queue number OCELOT_MRP_CPUQ
will be forward by the SW.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
drivers/net/dsa/ocelot/felix.c | 38 ++++++++++++++++++++++++++++++++++
net/dsa/tag_ocelot.c | 8 +++++++
2 files changed, 46 insertions(+)
@@ -83,6 +83,7 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,structdsa_port*dp;u8*extraction;u16vlan_tpid;+u64cpuq;/* Revert skb->data by the amount consumed by the DSA master,*soitpointstothebeginningoftheframe.
Hello:
This series was applied to netdev/net-next.git (refs/heads/master):
On Tue, 16 Feb 2021 22:41:57 +0100 you wrote:
This patch series extends MRP switchdev to allow the SW to have a better
understanding if the HW can implement the MRP functionality or it needs
to help the HW to run it. There are 3 cases:
- when HW can't implement at all the functionality.
- when HW can implement a part of the functionality but needs the SW
implement the rest. For example if it can't detect when it stops
receiving MRP Test frames but it can copy the MRP frames to CPU to
allow the SW to determine this. Another example is generating the MRP
Test frames. If HW can't do that then the SW is used as backup.
- when HW can implement completely the functionality.
[...]
Checking the EtherType seems redundant, since those are the only frames
trapped to the MRP CPU queue.
Also, the cpuq variable is potentially unused when CONFIG_BRIDGE_MRP is
unset. I'm concerned that static analysis people may come in and try to
fix it up with even more ifdeffery, which is definitely not what I would
like to go for.
How about just the following, which is not conditionally compiled:
if (!(cpuq & BIT(OCELOT_MRP_CPUQ)))
skb->offload_fwd_mark = 1;
+ skb->offload_fwd_mark = 0;
+#endif
+
/* Ocelot switches copy frames unmodified to the CPU. However, it is
* possible for the user to request a VLAN modification through
* VCAP_IS1_ACT_VID_REPLACE_ENA. In this case, what will happen is that
--
2.27.0
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2021-02-17 10:28:00
On Tue, Feb 16, 2021 at 10:41:58PM +0100, Horatiu Vultur wrote:
Remove #IS_ENABLED(CONFIG_BRIDGE_MRP) from switchdev.h. This will
simplify the code implements MRP callbacks and will be similar with the
vlan filtering.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2021-02-17 10:35:33
On Tue, Feb 16, 2021 at 10:41:59PM +0100, Horatiu Vultur wrote:
quoted hunk
Add the member sw_backup to the structures switchdev_obj_ring_role_mrp
and switchdev_obj_in_role_mrp. In this way the SW can call the driver in
2 ways, once when sw_backup is set to false, meaning that the driver
should implement this completely in HW. And if that is not supported the
SW will call again but with sw_backup set to true, meaning that the
HW should help or allow the SW to run the protocol.
For example when role is MRM, if the HW can't detect when it stops
receiving MRP Test frames but it can trap these frames to CPU, then it
needs to return -EOPNOTSUPP when sw_backup is false and return 0 when
sw_backup is true.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
include/net/switchdev.h | 2 ++
1 file changed, 2 insertions(+)
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2021-02-17 10:58:02
On Tue, Feb 16, 2021 at 10:42:01PM +0100, Horatiu Vultur wrote:
quoted hunk
This patch extends the br_mrp_switchdev functions to be able to have a
better understanding what cause the issue and if the SW needs to be used
as a backup.
There are the following cases:
- when the code is compiled without CONFIG_NET_SWITCHDEV. In this case
return success so the SW can continue with the protocol. Depending
on the function, it returns 0 or BR_MRP_SW.
- when code is compiled with CONFIG_NET_SWITCHDEV and the driver doesn't
implement any MRP callbacks. In this case the HW can't run MRP so it
just returns -EOPNOTSUPP. So the SW will stop further to configure the
node.
- when code is compiled with CONFIG_NET_SWITCHDEV and the driver fully
supports any MRP functionality. In this case the SW doesn't need to do
anything. The functions will return 0 or BR_MRP_HW.
- when code is compiled with CONFIG_NET_SWITCHDEV and the HW can't run
completely the protocol but it can help the SW to run it. For
example, the HW can't support completely MRM role(can't detect when it
stops receiving MRP Test frames) but it can redirect these frames to
CPU. In this case it is possible to have a SW fallback. The SW will
try initially to call the driver with sw_backup set to false, meaning
that the HW should implement completely the role. If the driver returns
-EOPNOTSUPP, the SW will try again with sw_backup set to false,
meaning that the SW will detect when it stops receiving the frames but
it needs HW support to redirect the frames to CPU. In case the driver
returns 0 then the SW will continue to configure the node accordingly.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
net/bridge/br_mrp_switchdev.c | 171 +++++++++++++++++++++-------------
net/bridge/br_private_mrp.h | 24 +++--
2 files changed, 118 insertions(+), 77 deletions(-)
Looks like you could have added this check here and simplified all the
callers:
if (!IS_ENABLED(CONFIG_NET_SWITCHDEV))
return BR_MRP_SW;
+ 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;
+}
+
@@ -639,7 +639,7 @@ int br_mrp_set_ring_role(struct net_bridge *br,structbr_mrp_ring_role*role){structbr_mrp*mrp=br_mrp_find_id(br,role->ring_id);-interr;+enumbr_mrp_hw_supportsupport;if(!mrp)return-EINVAL;
@@ -647,9 +647,9 @@ int br_mrp_set_ring_role(struct net_bridge *br,mrp->ring_role=role->ring_role;/* If there is an error just bailed out */-err=br_mrp_switchdev_set_ring_role(br,mrp,role->ring_role);-if(err&&err!=-EOPNOTSUPP)-returnerr;+support=br_mrp_switchdev_set_ring_role(br,mrp,role->ring_role);+if(support==BR_MRP_NONE)+return-EOPNOTSUPP;
It is broken to update the return type and value of a function in one
patch, and check for the updated return value in another patch.
quoted hunk
/* Now detect if the HW actually applied the role or not. If the HW
* applied the role it means that the SW will not to do those operations
@@ -657,7 +657,7 @@ int br_mrp_set_ring_role(struct net_bridge *br, * SW when ring is open, but if the is not pushed to the HW the SW will * need to detect when the ring is open */- mrp->ring_role_offloaded = err == -EOPNOTSUPP ? 0 : 1;+ mrp->ring_role_offloaded = support == BR_MRP_SW ? 0 : 1; return 0; }
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2021-02-17 11:15:23
On Tue, Feb 16, 2021 at 10:42:03PM +0100, Horatiu Vultur wrote:
quoted hunk
Add basic support for MRP. The HW will just trap all MRP frames on the
ring ports to CPU and allow the SW to process them. In this way it is
possible to for this node to behave both as MRM and MRC.
Current limitations are:
- it doesn't support Interconnect roles.
- it supports only a single ring.
- the HW should be able to do forwarding of MRP Test frames so the SW
will not need to do this. So it would be able to have the role MRC
without SW support.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
drivers/net/ethernet/mscc/Makefile | 1 +
drivers/net/ethernet/mscc/ocelot.c | 10 +-
drivers/net/ethernet/mscc/ocelot_mrp.c | 175 +++++++++++++++++++++++++
drivers/net/ethernet/mscc/ocelot_net.c | 60 +++++++++
include/linux/dsa/ocelot.h | 5 +
include/soc/mscc/ocelot.h | 45 +++++++
6 files changed, 295 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/mscc/ocelot_mrp.c
@@ -687,7 +687,7 @@ static int ocelot_xtr_poll_xfh(struct ocelot *ocelot, int grp, u32 *xfh)intocelot_xtr_poll_frame(structocelot*ocelot,intgrp,structsk_buff**nskb){structskb_shared_hwtstamps*shhwtstamps;-u64tod_in_ns,full_ts_in_ns;+u64tod_in_ns,full_ts_in_ns,cpuq;u64timestamp,src_port,len;u32xfh[OCELOT_TAG_LEN/4];structnet_device*dev;
@@ -704,6 +704,7 @@ int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb)ocelot_xfh_get_src_port(xfh,&src_port);ocelot_xfh_get_len(xfh,&len);ocelot_xfh_get_rew_val(xfh,×tamp);+ocelot_xfh_get_cpuq(xfh,&cpuq);if(WARN_ON(src_port>=ocelot->num_phys_ports))return-EINVAL;
@@ -770,6 +771,13 @@ int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb)skb->offload_fwd_mark=1;skb->protocol=eth_type_trans(skb,dev);++#if IS_ENABLED(CONFIG_BRIDGE_MRP)+if(skb->protocol==cpu_to_be16(ETH_P_MRP)&&+cpuq&BIT(OCELOT_MRP_CPUQ))+skb->offload_fwd_mark=0;+#endif
Same comment as in DSA, it sounds simpler to me to just do:
if ((ocelot->bridge_mask & BIT(src_port)) &&
!(cpuq & BIT(OCELOT_MRP_CPUQ)))
skb->offload_fwd_mark = 1;
When we add support for more packet traps, this check will be more
amortized anyway.
No, no, no.
The struct net_device registered by DSA uses a netdev_priv of
struct dsa_slave_priv. You can't just go ahead and assume that the
caller of this function uses struct ocelot_port_private.
Please go to struct ocelot_port and add:
bool is_mrp_primary;
bool is_mrp_secondary;
and replace the checks for a net_device with bools.
I'd rather have this without the ifdeffery, doesn't seem too expensive
to justify compiling it out. We have a 4K array of VLANs in struct
ocelot, for god's sake.
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2021-02-17 11:28:31
On Tue, Feb 16, 2021 at 10:42:04PM +0100, Horatiu Vultur wrote:
quoted hunk
Add support for offloading MRP in HW. Currently implement the switchdev
calls 'SWITCHDEV_OBJ_ID_MRP', 'SWITCHDEV_OBJ_ID_RING_ROLE_MRP',
to allow to create MRP instances and to set the role of these instances.
Add DSA_NOTIFIER_MRP_ADD/DEL and DSA_NOTIFIER_MRP_ADD/DEL_RING_ROLE
which calls to .port_mrp_add/del and .port_mrp_add/del_ring_role in the
DSA driver for the switch.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
include/net/dsa.h | 12 ++++++
net/dsa/dsa_priv.h | 26 +++++++++++
net/dsa/port.c | 48 +++++++++++++++++++++
net/dsa/slave.c | 22 ++++++++++
net/dsa/switch.c | 105 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 213 insertions(+)
The 02/17/2021 10:34, Vladimir Oltean wrote:
Hi Vladimir,
On Tue, Feb 16, 2021 at 10:41:59PM +0100, Horatiu Vultur wrote:
quoted
Add the member sw_backup to the structures switchdev_obj_ring_role_mrp
and switchdev_obj_in_role_mrp. In this way the SW can call the driver in
2 ways, once when sw_backup is set to false, meaning that the driver
should implement this completely in HW. And if that is not supported the
SW will call again but with sw_backup set to true, meaning that the
HW should help or allow the SW to run the protocol.
For example when role is MRM, if the HW can't detect when it stops
receiving MRP Test frames but it can trap these frames to CPU, then it
needs to return -EOPNOTSUPP when sw_backup is false and return 0 when
sw_backup is true.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
include/net/switchdev.h | 2 ++
1 file changed, 2 insertions(+)
If a driver implements full MRP offload for a ring/interconnect
manager/automanager, should it return -EOPNOTSUPP when sw_backup=false?
In that case it should return 0.
So if the driver can:
- fully support MRP, when sw_backup = false, return 0. Then end of story.
- partially support MRP, when sw_backup = false, return -EOPNOTSUPP,
when sw_backup = true, return 0.
- no support at all, return -EOPNOTSUPP.
--
/Horatiu
On Tue, Feb 16, 2021 at 10:42:01PM +0100, Horatiu Vultur wrote:
quoted
This patch extends the br_mrp_switchdev functions to be able to have a
better understanding what cause the issue and if the SW needs to be used
as a backup.
There are the following cases:
- when the code is compiled without CONFIG_NET_SWITCHDEV. In this case
return success so the SW can continue with the protocol. Depending
on the function, it returns 0 or BR_MRP_SW.
- when code is compiled with CONFIG_NET_SWITCHDEV and the driver doesn't
implement any MRP callbacks. In this case the HW can't run MRP so it
just returns -EOPNOTSUPP. So the SW will stop further to configure the
node.
- when code is compiled with CONFIG_NET_SWITCHDEV and the driver fully
supports any MRP functionality. In this case the SW doesn't need to do
anything. The functions will return 0 or BR_MRP_HW.
- when code is compiled with CONFIG_NET_SWITCHDEV and the HW can't run
completely the protocol but it can help the SW to run it. For
example, the HW can't support completely MRM role(can't detect when it
stops receiving MRP Test frames) but it can redirect these frames to
CPU. In this case it is possible to have a SW fallback. The SW will
try initially to call the driver with sw_backup set to false, meaning
that the HW should implement completely the role. If the driver returns
-EOPNOTSUPP, the SW will try again with sw_backup set to false,
meaning that the SW will detect when it stops receiving the frames but
it needs HW support to redirect the frames to CPU. In case the driver
returns 0 then the SW will continue to configure the node accordingly.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
net/bridge/br_mrp_switchdev.c | 171 +++++++++++++++++++++-------------
net/bridge/br_private_mrp.h | 24 +++--
2 files changed, 118 insertions(+), 77 deletions(-)
Looks like you could have added this check here and simplified all the
callers:
if (!IS_ENABLED(CONFIG_NET_SWITCHDEV))
return BR_MRP_SW;
Yes, good catch!
quoted
+ 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;
+}
+
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2021-02-17 16:10:49
On Wed, Feb 17, 2021 at 04:58:45PM +0100, Horatiu Vultur wrote:
quoted
If a driver implements full MRP offload for a ring/interconnect
manager/automanager, should it return -EOPNOTSUPP when sw_backup=false?
In that case it should return 0.
So if the driver can:
- fully support MRP, when sw_backup = false, return 0. Then end of story.
- partially support MRP, when sw_backup = false, return -EOPNOTSUPP,
when sw_backup = true, return 0.
- no support at all, return -EOPNOTSUPP.
Damn, I asked the wrong question.
I meant to ask about what it should return when sw_backup=true.
But you answered anyway that if it returns 0 when sw_backup=false, it
can simply not deal with the case where sw_backup=true, because that is
never supposed to happen.
@@ -639,7 +639,7 @@ int br_mrp_set_ring_role(struct net_bridge *br,structbr_mrp_ring_role*role){structbr_mrp*mrp=br_mrp_find_id(br,role->ring_id);-interr;+enumbr_mrp_hw_supportsupport;if(!mrp)return-EINVAL;
@@ -647,9 +647,9 @@ int br_mrp_set_ring_role(struct net_bridge *br,mrp->ring_role=role->ring_role;/* If there is an error just bailed out */-err=br_mrp_switchdev_set_ring_role(br,mrp,role->ring_role);-if(err&&err!=-EOPNOTSUPP)-returnerr;+support=br_mrp_switchdev_set_ring_role(br,mrp,role->ring_role);+if(support==BR_MRP_NONE)+return-EOPNOTSUPP;
It is broken to update the return type and value of a function in one
patch, and check for the updated return value in another patch.
Yes, I will be more careful next time. I have tried to compile between
the patches and I have not see any issues here so I though that
everything is good.
quoted
/* Now detect if the HW actually applied the role or not. If the HW
* applied the role it means that the SW will not to do those operations
@@ -657,7 +657,7 @@ int br_mrp_set_ring_role(struct net_bridge *br, * SW when ring is open, but if the is not pushed to the HW the SW will * need to detect when the ring is open */- mrp->ring_role_offloaded = err == -EOPNOTSUPP ? 0 : 1;+ mrp->ring_role_offloaded = support == BR_MRP_SW ? 0 : 1; return 0; }
On Tue, Feb 16, 2021 at 10:42:03PM +0100, Horatiu Vultur wrote:
quoted
Add basic support for MRP. The HW will just trap all MRP frames on the
ring ports to CPU and allow the SW to process them. In this way it is
possible to for this node to behave both as MRM and MRC.
Current limitations are:
- it doesn't support Interconnect roles.
- it supports only a single ring.
- the HW should be able to do forwarding of MRP Test frames so the SW
will not need to do this. So it would be able to have the role MRC
without SW support.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
drivers/net/ethernet/mscc/Makefile | 1 +
drivers/net/ethernet/mscc/ocelot.c | 10 +-
drivers/net/ethernet/mscc/ocelot_mrp.c | 175 +++++++++++++++++++++++++
drivers/net/ethernet/mscc/ocelot_net.c | 60 +++++++++
include/linux/dsa/ocelot.h | 5 +
include/soc/mscc/ocelot.h | 45 +++++++
6 files changed, 295 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/mscc/ocelot_mrp.c
@@ -687,7 +687,7 @@ static int ocelot_xtr_poll_xfh(struct ocelot *ocelot, int grp, u32 *xfh)intocelot_xtr_poll_frame(structocelot*ocelot,intgrp,structsk_buff**nskb){structskb_shared_hwtstamps*shhwtstamps;-u64tod_in_ns,full_ts_in_ns;+u64tod_in_ns,full_ts_in_ns,cpuq;u64timestamp,src_port,len;u32xfh[OCELOT_TAG_LEN/4];structnet_device*dev;
@@ -704,6 +704,7 @@ int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb)ocelot_xfh_get_src_port(xfh,&src_port);ocelot_xfh_get_len(xfh,&len);ocelot_xfh_get_rew_val(xfh,×tamp);+ocelot_xfh_get_cpuq(xfh,&cpuq);if(WARN_ON(src_port>=ocelot->num_phys_ports))return-EINVAL;
@@ -770,6 +771,13 @@ int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb)skb->offload_fwd_mark=1;skb->protocol=eth_type_trans(skb,dev);++#if IS_ENABLED(CONFIG_BRIDGE_MRP)+if(skb->protocol==cpu_to_be16(ETH_P_MRP)&&+cpuq&BIT(OCELOT_MRP_CPUQ))+skb->offload_fwd_mark=0;+#endif
Hi Vladimir,
Same comment as in DSA, it sounds simpler to me to just do:
if ((ocelot->bridge_mask & BIT(src_port)) &&
!(cpuq & BIT(OCELOT_MRP_CPUQ)))
skb->offload_fwd_mark = 1;
When we add support for more packet traps, this check will be more
amortized anyway.
Yes that looks simpler. But actually I think we can remove this once we
will do the forwarding of the frames in HW. And of course the same will
apply also for DSA driver.
No, no, no.
The struct net_device registered by DSA uses a netdev_priv of
struct dsa_slave_priv. You can't just go ahead and assume that the
caller of this function uses struct ocelot_port_private.
Please go to struct ocelot_port and add:
bool is_mrp_primary;
bool is_mrp_secondary;
and replace the checks for a net_device with bools.
My bad. I will create a new patch with your suggestion.
I'd rather have this without the ifdeffery, doesn't seem too expensive
to justify compiling it out. We have a 4K array of VLANs in struct
ocelot, for god's sake.