Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | |
| 3 | #include <net/switchdev.h> |
| 4 | |
| 5 | #include "br_private_mrp.h" |
| 6 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 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 | |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 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, |
Horatiu Vultur | 4b3a61b | 2020-05-30 18:09:47 +0000 | [diff] [blame] | 39 | .prio = mrp->prio, |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 40 | }; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 41 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 42 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
| 43 | return 0; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 44 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 45 | return switchdev_port_obj_add(br->dev, &mrp_obj.obj, NULL); |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 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 | }; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 57 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 58 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
| 59 | return 0; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 60 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 61 | return switchdev_port_obj_del(br->dev, &mrp_obj.obj); |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 62 | } |
| 63 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 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) |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 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, |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 73 | .sw_backup = false, |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 74 | }; |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 75 | enum br_mrp_hw_support support; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 76 | int err; |
| 77 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 78 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
| 79 | return BR_MRP_SW; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 80 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 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; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 99 | } |
| 100 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 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) |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 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, |
Horatiu Vultur | c6676e7 | 2020-05-30 18:09:48 +0000 | [diff] [blame] | 113 | .monitor = monitor, |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 114 | }; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 115 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 116 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
| 117 | return BR_MRP_SW; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 118 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 119 | return br_mrp_switchdev_port_obj(br, &test.obj, interval != 0); |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 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 | }; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 132 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 133 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
| 134 | return 0; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 135 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 136 | return switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 137 | } |
| 138 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 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) |
Horatiu Vultur | f23f0db | 2020-07-14 09:34:53 +0200 | [diff] [blame] | 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, |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 151 | .sw_backup = false, |
Horatiu Vultur | f23f0db | 2020-07-14 09:34:53 +0200 | [diff] [blame] | 152 | }; |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 153 | enum br_mrp_hw_support support; |
Horatiu Vultur | f23f0db | 2020-07-14 09:34:53 +0200 | [diff] [blame] | 154 | int err; |
| 155 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 156 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
| 157 | return BR_MRP_SW; |
Horatiu Vultur | f23f0db | 2020-07-14 09:34:53 +0200 | [diff] [blame] | 158 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 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; |
Horatiu Vultur | f23f0db | 2020-07-14 09:34:53 +0200 | [diff] [blame] | 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 | }; |
Horatiu Vultur | f23f0db | 2020-07-14 09:34:53 +0200 | [diff] [blame] | 188 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 189 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
| 190 | return 0; |
Horatiu Vultur | f23f0db | 2020-07-14 09:34:53 +0200 | [diff] [blame] | 191 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 192 | return switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); |
Horatiu Vultur | f23f0db | 2020-07-14 09:34:53 +0200 | [diff] [blame] | 193 | } |
| 194 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 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) |
Horatiu Vultur | f23f0db | 2020-07-14 09:34:53 +0200 | [diff] [blame] | 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 | }; |
Horatiu Vultur | f23f0db | 2020-07-14 09:34:53 +0200 | [diff] [blame] | 207 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 208 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
| 209 | return BR_MRP_SW; |
Horatiu Vultur | f23f0db | 2020-07-14 09:34:53 +0200 | [diff] [blame] | 210 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 211 | return br_mrp_switchdev_port_obj(br, &test.obj, interval != 0); |
Horatiu Vultur | f23f0db | 2020-07-14 09:34:53 +0200 | [diff] [blame] | 212 | } |
| 213 | |
Horatiu Vultur | b2bdba1 | 2021-02-06 22:47:33 +0100 | [diff] [blame] | 214 | int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, u32 state) |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 215 | { |
| 216 | struct switchdev_attr attr = { |
| 217 | .orig_dev = p->dev, |
Horatiu Vultur | b2bdba1 | 2021-02-06 22:47:33 +0100 | [diff] [blame] | 218 | .id = SWITCHDEV_ATTR_ID_PORT_STP_STATE, |
| 219 | .u.stp_state = state, |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 220 | }; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 221 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 222 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
| 223 | return 0; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 224 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 225 | return switchdev_port_attr_set(p->dev, &attr, NULL); |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 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 | }; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 236 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 237 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
| 238 | return 0; |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 239 | |
Horatiu Vultur | 1a3ddb0 | 2021-02-16 22:42:01 +0100 | [diff] [blame] | 240 | return switchdev_port_attr_set(p->dev, &attr, NULL); |
Horatiu Vultur | fadd409 | 2020-04-26 15:22:04 +0200 | [diff] [blame] | 241 | } |