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