Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bridge: mrp: Extend br_mrp_switchdev to detect better the errors

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>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Horatiu Vultur and committed by
David S. Miller
1a3ddb0b e1bd99d0

+120 -79
+106 -69
net/bridge/br_mrp_switchdev.c
··· 4 4 5 5 #include "br_private_mrp.h" 6 6 7 + static enum br_mrp_hw_support 8 + br_mrp_switchdev_port_obj(struct net_bridge *br, 9 + const struct switchdev_obj *obj, bool add) 10 + { 11 + int err; 12 + 13 + if (add) 14 + err = switchdev_port_obj_add(br->dev, obj, NULL); 15 + else 16 + err = switchdev_port_obj_del(br->dev, obj); 17 + 18 + /* In case of success just return and notify the SW that doesn't need 19 + * to do anything 20 + */ 21 + if (!err) 22 + return BR_MRP_HW; 23 + 24 + if (err != -EOPNOTSUPP) 25 + return BR_MRP_NONE; 26 + 27 + /* Continue with SW backup */ 28 + return BR_MRP_SW; 29 + } 30 + 7 31 int br_mrp_switchdev_add(struct net_bridge *br, struct br_mrp *mrp) 8 32 { 9 33 struct switchdev_obj_mrp mrp_obj = { ··· 38 14 .ring_id = mrp->ring_id, 39 15 .prio = mrp->prio, 40 16 }; 41 - int err; 42 17 43 - err = switchdev_port_obj_add(br->dev, &mrp_obj.obj, NULL); 18 + if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 19 + return 0; 44 20 45 - if (err && err != -EOPNOTSUPP) 46 - return err; 47 - 48 - return 0; 21 + return switchdev_port_obj_add(br->dev, &mrp_obj.obj, NULL); 49 22 } 50 23 51 24 int br_mrp_switchdev_del(struct net_bridge *br, struct br_mrp *mrp) ··· 54 33 .s_port = NULL, 55 34 .ring_id = mrp->ring_id, 56 35 }; 57 - int err; 58 36 59 - err = switchdev_port_obj_del(br->dev, &mrp_obj.obj); 37 + if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 38 + return 0; 60 39 61 - if (err && err != -EOPNOTSUPP) 62 - return err; 63 - 64 - return 0; 40 + return switchdev_port_obj_del(br->dev, &mrp_obj.obj); 65 41 } 66 42 67 - int br_mrp_switchdev_set_ring_role(struct net_bridge *br, 68 - struct br_mrp *mrp, 69 - enum br_mrp_ring_role_type role) 43 + enum br_mrp_hw_support 44 + br_mrp_switchdev_set_ring_role(struct net_bridge *br, struct br_mrp *mrp, 45 + enum br_mrp_ring_role_type role) 70 46 { 71 47 struct switchdev_obj_ring_role_mrp mrp_role = { 72 48 .obj.orig_dev = br->dev, 73 49 .obj.id = SWITCHDEV_OBJ_ID_RING_ROLE_MRP, 74 50 .ring_role = role, 75 51 .ring_id = mrp->ring_id, 52 + .sw_backup = false, 76 53 }; 54 + enum br_mrp_hw_support support; 77 55 int err; 78 56 79 - if (role == BR_MRP_RING_ROLE_DISABLED) 80 - err = switchdev_port_obj_del(br->dev, &mrp_role.obj); 81 - else 82 - err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL); 57 + if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 58 + return BR_MRP_SW; 83 59 84 - return err; 60 + support = br_mrp_switchdev_port_obj(br, &mrp_role.obj, 61 + role != BR_MRP_RING_ROLE_DISABLED); 62 + if (support != BR_MRP_SW) 63 + return support; 64 + 65 + /* If the driver can't configure to run completely the protocol in HW, 66 + * then try again to configure the HW so the SW can run the protocol. 67 + */ 68 + mrp_role.sw_backup = true; 69 + if (role != BR_MRP_RING_ROLE_DISABLED) 70 + err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL); 71 + else 72 + err = switchdev_port_obj_del(br->dev, &mrp_role.obj); 73 + 74 + if (!err) 75 + return BR_MRP_SW; 76 + 77 + return BR_MRP_NONE; 85 78 } 86 79 87 - int br_mrp_switchdev_send_ring_test(struct net_bridge *br, 88 - struct br_mrp *mrp, u32 interval, 89 - u8 max_miss, u32 period, 90 - bool monitor) 80 + enum br_mrp_hw_support 81 + br_mrp_switchdev_send_ring_test(struct net_bridge *br, struct br_mrp *mrp, 82 + u32 interval, u8 max_miss, u32 period, 83 + bool monitor) 91 84 { 92 85 struct switchdev_obj_ring_test_mrp test = { 93 86 .obj.orig_dev = br->dev, ··· 112 77 .period = period, 113 78 .monitor = monitor, 114 79 }; 115 - int err; 116 80 117 - if (interval == 0) 118 - err = switchdev_port_obj_del(br->dev, &test.obj); 119 - else 120 - err = switchdev_port_obj_add(br->dev, &test.obj, NULL); 81 + if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 82 + return BR_MRP_SW; 121 83 122 - return err; 84 + return br_mrp_switchdev_port_obj(br, &test.obj, interval != 0); 123 85 } 124 86 125 87 int br_mrp_switchdev_set_ring_state(struct net_bridge *br, ··· 129 97 .ring_state = state, 130 98 .ring_id = mrp->ring_id, 131 99 }; 132 - int err; 133 100 134 - err = switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); 101 + if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 102 + return 0; 135 103 136 - if (err && err != -EOPNOTSUPP) 137 - return err; 138 - 139 - return 0; 104 + return switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); 140 105 } 141 106 142 - int br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, 143 - u16 in_id, u32 ring_id, 144 - enum br_mrp_in_role_type role) 107 + enum br_mrp_hw_support 108 + br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, 109 + u16 in_id, u32 ring_id, 110 + enum br_mrp_in_role_type role) 145 111 { 146 112 struct switchdev_obj_in_role_mrp mrp_role = { 147 113 .obj.orig_dev = br->dev, ··· 148 118 .in_id = mrp->in_id, 149 119 .ring_id = mrp->ring_id, 150 120 .i_port = rtnl_dereference(mrp->i_port)->dev, 121 + .sw_backup = false, 151 122 }; 123 + enum br_mrp_hw_support support; 152 124 int err; 153 125 154 - if (role == BR_MRP_IN_ROLE_DISABLED) 155 - err = switchdev_port_obj_del(br->dev, &mrp_role.obj); 156 - else 157 - err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL); 126 + if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 127 + return BR_MRP_SW; 158 128 159 - return err; 129 + support = br_mrp_switchdev_port_obj(br, &mrp_role.obj, 130 + role != BR_MRP_IN_ROLE_DISABLED); 131 + if (support != BR_MRP_NONE) 132 + return support; 133 + 134 + /* If the driver can't configure to run completely the protocol in HW, 135 + * then try again to configure the HW so the SW can run the protocol. 136 + */ 137 + mrp_role.sw_backup = true; 138 + if (role != BR_MRP_IN_ROLE_DISABLED) 139 + err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL); 140 + else 141 + err = switchdev_port_obj_del(br->dev, &mrp_role.obj); 142 + 143 + if (!err) 144 + return BR_MRP_SW; 145 + 146 + return BR_MRP_NONE; 160 147 } 161 148 162 149 int br_mrp_switchdev_set_in_state(struct net_bridge *br, struct br_mrp *mrp, ··· 185 138 .in_state = state, 186 139 .in_id = mrp->in_id, 187 140 }; 188 - int err; 189 141 190 - err = switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); 142 + if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 143 + return 0; 191 144 192 - if (err && err != -EOPNOTSUPP) 193 - return err; 194 - 195 - return 0; 145 + return switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); 196 146 } 197 147 198 - int br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, 199 - u32 interval, u8 max_miss, u32 period) 148 + enum br_mrp_hw_support 149 + br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, 150 + u32 interval, u8 max_miss, u32 period) 200 151 { 201 152 struct switchdev_obj_in_test_mrp test = { 202 153 .obj.orig_dev = br->dev, ··· 204 159 .in_id = mrp->in_id, 205 160 .period = period, 206 161 }; 207 - int err; 208 162 209 - if (interval == 0) 210 - err = switchdev_port_obj_del(br->dev, &test.obj); 211 - else 212 - err = switchdev_port_obj_add(br->dev, &test.obj, NULL); 163 + if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 164 + return BR_MRP_SW; 213 165 214 - return err; 166 + return br_mrp_switchdev_port_obj(br, &test.obj, interval != 0); 215 167 } 216 168 217 169 int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, u32 state) ··· 218 176 .id = SWITCHDEV_ATTR_ID_PORT_STP_STATE, 219 177 .u.stp_state = state, 220 178 }; 221 - int err; 222 179 223 - err = switchdev_port_attr_set(p->dev, &attr, NULL); 224 - if (err && err != -EOPNOTSUPP) 225 - br_warn(p->br, "error setting offload MRP state on port %u(%s)\n", 226 - (unsigned int)p->port_no, p->dev->name); 180 + if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 181 + return 0; 227 182 228 - return err; 183 + return switchdev_port_attr_set(p->dev, &attr, NULL); 229 184 } 230 185 231 186 int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, ··· 233 194 .id = SWITCHDEV_ATTR_ID_MRP_PORT_ROLE, 234 195 .u.mrp_port_role = role, 235 196 }; 236 - int err; 237 197 238 - err = switchdev_port_attr_set(p->dev, &attr, NULL); 239 - if (err && err != -EOPNOTSUPP) 240 - return err; 198 + if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 199 + return 0; 241 200 242 - return 0; 201 + return switchdev_port_attr_set(p->dev, &attr, NULL); 243 202 }
+14 -10
net/bridge/br_private_mrp.h
··· 79 79 /* br_mrp_switchdev.c */ 80 80 int br_mrp_switchdev_add(struct net_bridge *br, struct br_mrp *mrp); 81 81 int br_mrp_switchdev_del(struct net_bridge *br, struct br_mrp *mrp); 82 - int br_mrp_switchdev_set_ring_role(struct net_bridge *br, struct br_mrp *mrp, 83 - enum br_mrp_ring_role_type role); 82 + enum br_mrp_hw_support 83 + br_mrp_switchdev_set_ring_role(struct net_bridge *br, struct br_mrp *mrp, 84 + enum br_mrp_ring_role_type role); 84 85 int br_mrp_switchdev_set_ring_state(struct net_bridge *br, struct br_mrp *mrp, 85 86 enum br_mrp_ring_state_type state); 86 - int br_mrp_switchdev_send_ring_test(struct net_bridge *br, struct br_mrp *mrp, 87 - u32 interval, u8 max_miss, u32 period, 88 - bool monitor); 87 + enum br_mrp_hw_support 88 + br_mrp_switchdev_send_ring_test(struct net_bridge *br, struct br_mrp *mrp, 89 + u32 interval, u8 max_miss, u32 period, 90 + bool monitor); 89 91 int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, u32 state); 90 92 int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, 91 93 enum br_mrp_port_role_type role); 92 - int br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, 93 - u16 in_id, u32 ring_id, 94 - enum br_mrp_in_role_type role); 94 + enum br_mrp_hw_support 95 + br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, 96 + u16 in_id, u32 ring_id, 97 + enum br_mrp_in_role_type role); 95 98 int br_mrp_switchdev_set_in_state(struct net_bridge *br, struct br_mrp *mrp, 96 99 enum br_mrp_in_state_type state); 97 - int br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, 98 - u32 interval, u8 max_miss, u32 period); 100 + enum br_mrp_hw_support 101 + br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, 102 + u32 interval, u8 max_miss, u32 period); 99 103 100 104 /* br_mrp_netlink.c */ 101 105 int br_mrp_ring_port_open(struct net_device *dev, u8 loc);