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