Merge tag 'powerpc-5.15-6' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[platform/kernel/linux-starfive.git] / net / bridge / br_mrp_switchdev.c
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
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
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
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
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
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
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
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
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
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
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
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 }