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