]>
Commit | Line | Data |
---|---|---|
fadd4091 HV |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | ||
3 | #include <net/switchdev.h> | |
4 | ||
5 | #include "br_private_mrp.h" | |
6 | ||
1a3ddb0b HV |
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 | ||
fadd4091 HV |
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, | |
4b3a61b0 | 39 | .prio = mrp->prio, |
fadd4091 | 40 | }; |
fadd4091 | 41 | |
1a3ddb0b HV |
42 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
43 | return 0; | |
fadd4091 | 44 | |
1a3ddb0b | 45 | return switchdev_port_obj_add(br->dev, &mrp_obj.obj, NULL); |
fadd4091 HV |
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 | }; | |
fadd4091 | 57 | |
1a3ddb0b HV |
58 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
59 | return 0; | |
fadd4091 | 60 | |
1a3ddb0b | 61 | return switchdev_port_obj_del(br->dev, &mrp_obj.obj); |
fadd4091 HV |
62 | } |
63 | ||
1a3ddb0b HV |
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) | |
fadd4091 HV |
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, | |
1a3ddb0b | 73 | .sw_backup = false, |
fadd4091 | 74 | }; |
1a3ddb0b | 75 | enum br_mrp_hw_support support; |
fadd4091 HV |
76 | int err; |
77 | ||
1a3ddb0b HV |
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) | |
fadd4091 | 91 | err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL); |
1a3ddb0b HV |
92 | else |
93 | err = switchdev_port_obj_del(br->dev, &mrp_role.obj); | |
fadd4091 | 94 | |
1a3ddb0b HV |
95 | if (!err) |
96 | return BR_MRP_SW; | |
97 | ||
98 | return BR_MRP_NONE; | |
fadd4091 HV |
99 | } |
100 | ||
1a3ddb0b HV |
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) | |
fadd4091 HV |
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, | |
c6676e7d | 113 | .monitor = monitor, |
fadd4091 | 114 | }; |
fadd4091 | 115 | |
1a3ddb0b HV |
116 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
117 | return BR_MRP_SW; | |
fadd4091 | 118 | |
1a3ddb0b | 119 | return br_mrp_switchdev_port_obj(br, &test.obj, interval != 0); |
fadd4091 HV |
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 | }; | |
fadd4091 | 132 | |
1a3ddb0b HV |
133 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
134 | return 0; | |
fadd4091 | 135 | |
1a3ddb0b | 136 | return switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); |
fadd4091 HV |
137 | } |
138 | ||
1a3ddb0b HV |
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) | |
f23f0db3 HV |
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, | |
1a3ddb0b | 151 | .sw_backup = false, |
f23f0db3 | 152 | }; |
1a3ddb0b | 153 | enum br_mrp_hw_support support; |
f23f0db3 HV |
154 | int err; |
155 | ||
1a3ddb0b HV |
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) | |
f23f0db3 | 169 | err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL); |
1a3ddb0b HV |
170 | else |
171 | err = switchdev_port_obj_del(br->dev, &mrp_role.obj); | |
172 | ||
173 | if (!err) | |
174 | return BR_MRP_SW; | |
f23f0db3 | 175 | |
1a3ddb0b | 176 | return BR_MRP_NONE; |
f23f0db3 HV |
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 | }; | |
f23f0db3 | 188 | |
1a3ddb0b HV |
189 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
190 | return 0; | |
f23f0db3 | 191 | |
1a3ddb0b | 192 | return switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); |
f23f0db3 HV |
193 | } |
194 | ||
1a3ddb0b HV |
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) | |
f23f0db3 HV |
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 | }; | |
f23f0db3 | 207 | |
1a3ddb0b HV |
208 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
209 | return BR_MRP_SW; | |
f23f0db3 | 210 | |
1a3ddb0b | 211 | return br_mrp_switchdev_port_obj(br, &test.obj, interval != 0); |
f23f0db3 HV |
212 | } |
213 | ||
b2bdba1c | 214 | int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, u32 state) |
fadd4091 HV |
215 | { |
216 | struct switchdev_attr attr = { | |
217 | .orig_dev = p->dev, | |
b2bdba1c HV |
218 | .id = SWITCHDEV_ATTR_ID_PORT_STP_STATE, |
219 | .u.stp_state = state, | |
fadd4091 | 220 | }; |
fadd4091 | 221 | |
1a3ddb0b HV |
222 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
223 | return 0; | |
fadd4091 | 224 | |
1a3ddb0b | 225 | return switchdev_port_attr_set(p->dev, &attr, NULL); |
fadd4091 HV |
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 | }; | |
fadd4091 | 236 | |
1a3ddb0b HV |
237 | if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) |
238 | return 0; | |
fadd4091 | 239 | |
1a3ddb0b | 240 | return switchdev_port_attr_set(p->dev, &attr, NULL); |
fadd4091 | 241 | } |