1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 #include <net/switchdev.h> 4 5 #include "br_private_mrp.h" 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 31 int br_mrp_switchdev_add(struct net_bridge *br, struct br_mrp *mrp) 32 { 33 struct switchdev_obj_mrp mrp_obj = { 34 .obj.orig_dev = br->dev, 35 .obj.id = SWITCHDEV_OBJ_ID_MRP, 36 .p_port = rtnl_dereference(mrp->p_port)->dev, 37 .s_port = rtnl_dereference(mrp->s_port)->dev, 38 .ring_id = mrp->ring_id, 39 .prio = mrp->prio, 40 }; 41 42 if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 43 return 0; 44 45 return switchdev_port_obj_add(br->dev, &mrp_obj.obj, NULL); 46 } 47 48 int br_mrp_switchdev_del(struct net_bridge *br, struct br_mrp *mrp) 49 { 50 struct switchdev_obj_mrp mrp_obj = { 51 .obj.orig_dev = br->dev, 52 .obj.id = SWITCHDEV_OBJ_ID_MRP, 53 .p_port = NULL, 54 .s_port = NULL, 55 .ring_id = mrp->ring_id, 56 }; 57 58 if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 59 return 0; 60 61 return switchdev_port_obj_del(br->dev, &mrp_obj.obj); 62 } 63 64 enum br_mrp_hw_support 65 br_mrp_switchdev_set_ring_role(struct net_bridge *br, struct br_mrp *mrp, 66 enum br_mrp_ring_role_type role) 67 { 68 struct switchdev_obj_ring_role_mrp mrp_role = { 69 .obj.orig_dev = br->dev, 70 .obj.id = SWITCHDEV_OBJ_ID_RING_ROLE_MRP, 71 .ring_role = role, 72 .ring_id = mrp->ring_id, 73 .sw_backup = false, 74 }; 75 enum br_mrp_hw_support support; 76 int err; 77 78 if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 79 return BR_MRP_SW; 80 81 support = br_mrp_switchdev_port_obj(br, &mrp_role.obj, 82 role != BR_MRP_RING_ROLE_DISABLED); 83 if (support != BR_MRP_SW) 84 return support; 85 86 /* If the driver can't configure to run completely the protocol in HW, 87 * then try again to configure the HW so the SW can run the protocol. 88 */ 89 mrp_role.sw_backup = true; 90 if (role != BR_MRP_RING_ROLE_DISABLED) 91 err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL); 92 else 93 err = switchdev_port_obj_del(br->dev, &mrp_role.obj); 94 95 if (!err) 96 return BR_MRP_SW; 97 98 return BR_MRP_NONE; 99 } 100 101 enum br_mrp_hw_support 102 br_mrp_switchdev_send_ring_test(struct net_bridge *br, struct br_mrp *mrp, 103 u32 interval, u8 max_miss, u32 period, 104 bool monitor) 105 { 106 struct switchdev_obj_ring_test_mrp test = { 107 .obj.orig_dev = br->dev, 108 .obj.id = SWITCHDEV_OBJ_ID_RING_TEST_MRP, 109 .interval = interval, 110 .max_miss = max_miss, 111 .ring_id = mrp->ring_id, 112 .period = period, 113 .monitor = monitor, 114 }; 115 116 if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 117 return BR_MRP_SW; 118 119 return br_mrp_switchdev_port_obj(br, &test.obj, interval != 0); 120 } 121 122 int br_mrp_switchdev_set_ring_state(struct net_bridge *br, 123 struct br_mrp *mrp, 124 enum br_mrp_ring_state_type state) 125 { 126 struct switchdev_obj_ring_state_mrp mrp_state = { 127 .obj.orig_dev = br->dev, 128 .obj.id = SWITCHDEV_OBJ_ID_RING_STATE_MRP, 129 .ring_state = state, 130 .ring_id = mrp->ring_id, 131 }; 132 133 if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 134 return 0; 135 136 return switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); 137 } 138 139 enum br_mrp_hw_support 140 br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, 141 u16 in_id, u32 ring_id, 142 enum br_mrp_in_role_type role) 143 { 144 struct switchdev_obj_in_role_mrp mrp_role = { 145 .obj.orig_dev = br->dev, 146 .obj.id = SWITCHDEV_OBJ_ID_IN_ROLE_MRP, 147 .in_role = role, 148 .in_id = mrp->in_id, 149 .ring_id = mrp->ring_id, 150 .i_port = rtnl_dereference(mrp->i_port)->dev, 151 .sw_backup = false, 152 }; 153 enum br_mrp_hw_support support; 154 int err; 155 156 if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 157 return BR_MRP_SW; 158 159 support = br_mrp_switchdev_port_obj(br, &mrp_role.obj, 160 role != BR_MRP_IN_ROLE_DISABLED); 161 if (support != BR_MRP_NONE) 162 return support; 163 164 /* If the driver can't configure to run completely the protocol in HW, 165 * then try again to configure the HW so the SW can run the protocol. 166 */ 167 mrp_role.sw_backup = true; 168 if (role != BR_MRP_IN_ROLE_DISABLED) 169 err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL); 170 else 171 err = switchdev_port_obj_del(br->dev, &mrp_role.obj); 172 173 if (!err) 174 return BR_MRP_SW; 175 176 return BR_MRP_NONE; 177 } 178 179 int br_mrp_switchdev_set_in_state(struct net_bridge *br, struct br_mrp *mrp, 180 enum br_mrp_in_state_type state) 181 { 182 struct switchdev_obj_in_state_mrp mrp_state = { 183 .obj.orig_dev = br->dev, 184 .obj.id = SWITCHDEV_OBJ_ID_IN_STATE_MRP, 185 .in_state = state, 186 .in_id = mrp->in_id, 187 }; 188 189 if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 190 return 0; 191 192 return switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); 193 } 194 195 enum br_mrp_hw_support 196 br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, 197 u32 interval, u8 max_miss, u32 period) 198 { 199 struct switchdev_obj_in_test_mrp test = { 200 .obj.orig_dev = br->dev, 201 .obj.id = SWITCHDEV_OBJ_ID_IN_TEST_MRP, 202 .interval = interval, 203 .max_miss = max_miss, 204 .in_id = mrp->in_id, 205 .period = period, 206 }; 207 208 if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 209 return BR_MRP_SW; 210 211 return br_mrp_switchdev_port_obj(br, &test.obj, interval != 0); 212 } 213 214 int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, u32 state) 215 { 216 struct switchdev_attr attr = { 217 .orig_dev = p->dev, 218 .id = SWITCHDEV_ATTR_ID_PORT_STP_STATE, 219 .u.stp_state = state, 220 }; 221 222 if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 223 return 0; 224 225 return switchdev_port_attr_set(p->dev, &attr, NULL); 226 } 227 228 int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, 229 enum br_mrp_port_role_type role) 230 { 231 struct switchdev_attr attr = { 232 .orig_dev = p->dev, 233 .id = SWITCHDEV_ATTR_ID_MRP_PORT_ROLE, 234 .u.mrp_port_role = role, 235 }; 236 237 if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) 238 return 0; 239 240 return switchdev_port_attr_set(p->dev, &attr, NULL); 241 } 242