xref: /openbmc/linux/net/bridge/br_mrp_switchdev.c (revision d0034a7a4ac7fae708146ac0059b9c47a1543f0d)
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
br_mrp_switchdev_port_obj(struct net_bridge * br,const struct switchdev_obj * obj,bool add)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 
br_mrp_switchdev_add(struct net_bridge * br,struct br_mrp * mrp)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 
br_mrp_switchdev_del(struct net_bridge * br,struct br_mrp * mrp)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
br_mrp_switchdev_set_ring_role(struct net_bridge * br,struct br_mrp * mrp,enum br_mrp_ring_role_type role)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
br_mrp_switchdev_send_ring_test(struct net_bridge * br,struct br_mrp * mrp,u32 interval,u8 max_miss,u32 period,bool monitor)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 
br_mrp_switchdev_set_ring_state(struct net_bridge * br,struct br_mrp * mrp,enum br_mrp_ring_state_type state)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
br_mrp_switchdev_set_in_role(struct net_bridge * br,struct br_mrp * mrp,u16 in_id,u32 ring_id,enum br_mrp_in_role_type role)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 
br_mrp_switchdev_set_in_state(struct net_bridge * br,struct br_mrp * mrp,enum br_mrp_in_state_type state)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
br_mrp_switchdev_send_in_test(struct net_bridge * br,struct br_mrp * mrp,u32 interval,u8 max_miss,u32 period)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 
br_mrp_port_switchdev_set_state(struct net_bridge_port * p,u32 state)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 
br_mrp_port_switchdev_set_role(struct net_bridge_port * p,enum br_mrp_port_role_type role)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