]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
83c0afae AL |
2 | /* |
3 | * net/dsa/dsa2.c - Hardware switch handling, binding version 2 | |
4 | * Copyright (c) 2008-2009 Marvell Semiconductor | |
5 | * Copyright (c) 2013 Florian Fainelli <florian@openwrt.org> | |
6 | * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch> | |
83c0afae AL |
7 | */ |
8 | ||
9 | #include <linux/device.h> | |
10 | #include <linux/err.h> | |
11 | #include <linux/list.h> | |
c6e970a0 | 12 | #include <linux/netdevice.h> |
83c0afae AL |
13 | #include <linux/slab.h> |
14 | #include <linux/rtnetlink.h> | |
83c0afae AL |
15 | #include <linux/of.h> |
16 | #include <linux/of_net.h> | |
402f99e5 | 17 | #include <net/devlink.h> |
ea5dd34b | 18 | |
83c0afae AL |
19 | #include "dsa_priv.h" |
20 | ||
83c0afae | 21 | static DEFINE_MUTEX(dsa2_mutex); |
bff33f7e | 22 | LIST_HEAD(dsa_tree_list); |
83c0afae | 23 | |
f5e165e7 VO |
24 | /* Track the bridges with forwarding offload enabled */ |
25 | static unsigned long dsa_fwd_offloading_bridges; | |
26 | ||
886f8e26 VO |
27 | /** |
28 | * dsa_tree_notify - Execute code for all switches in a DSA switch tree. | |
29 | * @dst: collection of struct dsa_switch devices to notify. | |
30 | * @e: event, must be of type DSA_NOTIFIER_* | |
31 | * @v: event-specific value. | |
32 | * | |
33 | * Given a struct dsa_switch_tree, this can be used to run a function once for | |
34 | * each member DSA switch. The other alternative of traversing the tree is only | |
35 | * through its ports list, which does not uniquely list the switches. | |
36 | */ | |
37 | int dsa_tree_notify(struct dsa_switch_tree *dst, unsigned long e, void *v) | |
38 | { | |
39 | struct raw_notifier_head *nh = &dst->nh; | |
40 | int err; | |
41 | ||
42 | err = raw_notifier_call_chain(nh, e, v); | |
43 | ||
44 | return notifier_to_errno(err); | |
45 | } | |
46 | ||
47 | /** | |
48 | * dsa_broadcast - Notify all DSA trees in the system. | |
49 | * @e: event, must be of type DSA_NOTIFIER_* | |
50 | * @v: event-specific value. | |
51 | * | |
52 | * Can be used to notify the switching fabric of events such as cross-chip | |
53 | * bridging between disjoint trees (such as islands of tagger-compatible | |
54 | * switches bridged by an incompatible middle switch). | |
724395f4 VO |
55 | * |
56 | * WARNING: this function is not reliable during probe time, because probing | |
57 | * between trees is asynchronous and not all DSA trees might have probed. | |
886f8e26 VO |
58 | */ |
59 | int dsa_broadcast(unsigned long e, void *v) | |
60 | { | |
61 | struct dsa_switch_tree *dst; | |
62 | int err = 0; | |
63 | ||
64 | list_for_each_entry(dst, &dsa_tree_list, list) { | |
65 | err = dsa_tree_notify(dst, e, v); | |
66 | if (err) | |
67 | break; | |
68 | } | |
69 | ||
70 | return err; | |
71 | } | |
72 | ||
058102a6 TW |
73 | /** |
74 | * dsa_lag_map() - Map LAG netdev to a linear LAG ID | |
75 | * @dst: Tree in which to record the mapping. | |
76 | * @lag: Netdev that is to be mapped to an ID. | |
77 | * | |
78 | * dsa_lag_id/dsa_lag_dev can then be used to translate between the | |
79 | * two spaces. The size of the mapping space is determined by the | |
80 | * driver by setting ds->num_lag_ids. It is perfectly legal to leave | |
81 | * it unset if it is not needed, in which case these functions become | |
82 | * no-ops. | |
83 | */ | |
84 | void dsa_lag_map(struct dsa_switch_tree *dst, struct net_device *lag) | |
85 | { | |
86 | unsigned int id; | |
87 | ||
88 | if (dsa_lag_id(dst, lag) >= 0) | |
89 | /* Already mapped */ | |
90 | return; | |
91 | ||
92 | for (id = 0; id < dst->lags_len; id++) { | |
93 | if (!dsa_lag_dev(dst, id)) { | |
94 | dst->lags[id] = lag; | |
95 | return; | |
96 | } | |
97 | } | |
98 | ||
99 | /* No IDs left, which is OK. Some drivers do not need it. The | |
100 | * ones that do, e.g. mv88e6xxx, will discover that dsa_lag_id | |
101 | * returns an error for this device when joining the LAG. The | |
102 | * driver can then return -EOPNOTSUPP back to DSA, which will | |
103 | * fall back to a software LAG. | |
104 | */ | |
105 | } | |
106 | ||
107 | /** | |
108 | * dsa_lag_unmap() - Remove a LAG ID mapping | |
109 | * @dst: Tree in which the mapping is recorded. | |
110 | * @lag: Netdev that was mapped. | |
111 | * | |
112 | * As there may be multiple users of the mapping, it is only removed | |
113 | * if there are no other references to it. | |
114 | */ | |
115 | void dsa_lag_unmap(struct dsa_switch_tree *dst, struct net_device *lag) | |
116 | { | |
117 | struct dsa_port *dp; | |
118 | unsigned int id; | |
119 | ||
120 | dsa_lag_foreach_port(dp, dst, lag) | |
121 | /* There are remaining users of this mapping */ | |
122 | return; | |
123 | ||
124 | dsa_lags_foreach_id(id, dst) { | |
125 | if (dsa_lag_dev(dst, id) == lag) { | |
126 | dst->lags[id] = NULL; | |
127 | break; | |
128 | } | |
129 | } | |
130 | } | |
131 | ||
f5e165e7 VO |
132 | static int dsa_bridge_num_find(const struct net_device *bridge_dev) |
133 | { | |
134 | struct dsa_switch_tree *dst; | |
135 | struct dsa_port *dp; | |
136 | ||
137 | /* When preparing the offload for a port, it will have a valid | |
138 | * dp->bridge_dev pointer but a not yet valid dp->bridge_num. | |
139 | * However there might be other ports having the same dp->bridge_dev | |
140 | * and a valid dp->bridge_num, so just ignore this port. | |
141 | */ | |
142 | list_for_each_entry(dst, &dsa_tree_list, list) | |
143 | list_for_each_entry(dp, &dst->ports, list) | |
144 | if (dp->bridge_dev == bridge_dev && | |
145 | dp->bridge_num != -1) | |
146 | return dp->bridge_num; | |
147 | ||
148 | return -1; | |
149 | } | |
150 | ||
151 | int dsa_bridge_num_get(const struct net_device *bridge_dev, int max) | |
152 | { | |
153 | int bridge_num = dsa_bridge_num_find(bridge_dev); | |
154 | ||
155 | if (bridge_num < 0) { | |
156 | /* First port that offloads TX forwarding for this bridge */ | |
157 | bridge_num = find_first_zero_bit(&dsa_fwd_offloading_bridges, | |
158 | DSA_MAX_NUM_OFFLOADING_BRIDGES); | |
159 | if (bridge_num >= max) | |
160 | return -1; | |
161 | ||
162 | set_bit(bridge_num, &dsa_fwd_offloading_bridges); | |
163 | } | |
164 | ||
165 | return bridge_num; | |
166 | } | |
167 | ||
168 | void dsa_bridge_num_put(const struct net_device *bridge_dev, int bridge_num) | |
169 | { | |
170 | /* Check if the bridge is still in use, otherwise it is time | |
171 | * to clean it up so we can reuse this bridge_num later. | |
172 | */ | |
1bec0f05 | 173 | if (dsa_bridge_num_find(bridge_dev) < 0) |
f5e165e7 VO |
174 | clear_bit(bridge_num, &dsa_fwd_offloading_bridges); |
175 | } | |
176 | ||
3b7bc1f0 VO |
177 | struct dsa_switch *dsa_switch_find(int tree_index, int sw_index) |
178 | { | |
179 | struct dsa_switch_tree *dst; | |
180 | struct dsa_port *dp; | |
181 | ||
182 | list_for_each_entry(dst, &dsa_tree_list, list) { | |
183 | if (dst->index != tree_index) | |
184 | continue; | |
185 | ||
186 | list_for_each_entry(dp, &dst->ports, list) { | |
187 | if (dp->ds->index != sw_index) | |
188 | continue; | |
189 | ||
190 | return dp->ds; | |
191 | } | |
192 | } | |
193 | ||
194 | return NULL; | |
195 | } | |
196 | EXPORT_SYMBOL_GPL(dsa_switch_find); | |
197 | ||
1ca28ec9 | 198 | static struct dsa_switch_tree *dsa_tree_find(int index) |
83c0afae AL |
199 | { |
200 | struct dsa_switch_tree *dst; | |
201 | ||
1ca28ec9 | 202 | list_for_each_entry(dst, &dsa_tree_list, list) |
8e5bf975 | 203 | if (dst->index == index) |
83c0afae | 204 | return dst; |
8e5bf975 | 205 | |
83c0afae AL |
206 | return NULL; |
207 | } | |
208 | ||
1ca28ec9 | 209 | static struct dsa_switch_tree *dsa_tree_alloc(int index) |
83c0afae AL |
210 | { |
211 | struct dsa_switch_tree *dst; | |
212 | ||
213 | dst = kzalloc(sizeof(*dst), GFP_KERNEL); | |
214 | if (!dst) | |
215 | return NULL; | |
1ca28ec9 | 216 | |
49463b7f | 217 | dst->index = index; |
1ca28ec9 | 218 | |
c5f51765 VD |
219 | INIT_LIST_HEAD(&dst->rtable); |
220 | ||
ab8ccae1 VD |
221 | INIT_LIST_HEAD(&dst->ports); |
222 | ||
83c0afae | 223 | INIT_LIST_HEAD(&dst->list); |
50c7d2ba | 224 | list_add_tail(&dst->list, &dsa_tree_list); |
8e5bf975 | 225 | |
83c0afae AL |
226 | kref_init(&dst->refcount); |
227 | ||
228 | return dst; | |
229 | } | |
230 | ||
65254108 VD |
231 | static void dsa_tree_free(struct dsa_switch_tree *dst) |
232 | { | |
357f203b VO |
233 | if (dst->tag_ops) |
234 | dsa_tag_driver_put(dst->tag_ops); | |
65254108 VD |
235 | list_del(&dst->list); |
236 | kfree(dst); | |
237 | } | |
238 | ||
9e741045 | 239 | static struct dsa_switch_tree *dsa_tree_get(struct dsa_switch_tree *dst) |
1ca28ec9 | 240 | { |
9e741045 VD |
241 | if (dst) |
242 | kref_get(&dst->refcount); | |
1ca28ec9 VD |
243 | |
244 | return dst; | |
245 | } | |
246 | ||
9e741045 | 247 | static struct dsa_switch_tree *dsa_tree_touch(int index) |
65254108 | 248 | { |
9e741045 VD |
249 | struct dsa_switch_tree *dst; |
250 | ||
251 | dst = dsa_tree_find(index); | |
252 | if (dst) | |
253 | return dsa_tree_get(dst); | |
254 | else | |
255 | return dsa_tree_alloc(index); | |
65254108 VD |
256 | } |
257 | ||
258 | static void dsa_tree_release(struct kref *ref) | |
259 | { | |
260 | struct dsa_switch_tree *dst; | |
261 | ||
262 | dst = container_of(ref, struct dsa_switch_tree, refcount); | |
263 | ||
264 | dsa_tree_free(dst); | |
265 | } | |
266 | ||
267 | static void dsa_tree_put(struct dsa_switch_tree *dst) | |
268 | { | |
9e741045 VD |
269 | if (dst) |
270 | kref_put(&dst->refcount, dsa_tree_release); | |
65254108 VD |
271 | } |
272 | ||
f163da88 VD |
273 | static struct dsa_port *dsa_tree_find_port_by_node(struct dsa_switch_tree *dst, |
274 | struct device_node *dn) | |
83c0afae | 275 | { |
f163da88 | 276 | struct dsa_port *dp; |
83c0afae | 277 | |
764b7e62 VD |
278 | list_for_each_entry(dp, &dst->ports, list) |
279 | if (dp->dn == dn) | |
280 | return dp; | |
83c0afae AL |
281 | |
282 | return NULL; | |
283 | } | |
284 | ||
4e2ce6e5 BDC |
285 | static struct dsa_link *dsa_link_touch(struct dsa_port *dp, |
286 | struct dsa_port *link_dp) | |
c5f51765 VD |
287 | { |
288 | struct dsa_switch *ds = dp->ds; | |
289 | struct dsa_switch_tree *dst; | |
290 | struct dsa_link *dl; | |
291 | ||
292 | dst = ds->dst; | |
293 | ||
294 | list_for_each_entry(dl, &dst->rtable, list) | |
295 | if (dl->dp == dp && dl->link_dp == link_dp) | |
296 | return dl; | |
297 | ||
298 | dl = kzalloc(sizeof(*dl), GFP_KERNEL); | |
299 | if (!dl) | |
300 | return NULL; | |
301 | ||
302 | dl->dp = dp; | |
303 | dl->link_dp = link_dp; | |
304 | ||
305 | INIT_LIST_HEAD(&dl->list); | |
306 | list_add_tail(&dl->list, &dst->rtable); | |
307 | ||
308 | return dl; | |
309 | } | |
310 | ||
34c09a89 | 311 | static bool dsa_port_setup_routing_table(struct dsa_port *dp) |
83c0afae | 312 | { |
34c09a89 VD |
313 | struct dsa_switch *ds = dp->ds; |
314 | struct dsa_switch_tree *dst = ds->dst; | |
315 | struct device_node *dn = dp->dn; | |
c5286665 | 316 | struct of_phandle_iterator it; |
f163da88 | 317 | struct dsa_port *link_dp; |
c5f51765 | 318 | struct dsa_link *dl; |
c5286665 | 319 | int err; |
83c0afae | 320 | |
c5286665 VD |
321 | of_for_each_phandle(&it, err, dn, "link", NULL, 0) { |
322 | link_dp = dsa_tree_find_port_by_node(dst, it.node); | |
323 | if (!link_dp) { | |
324 | of_node_put(it.node); | |
34c09a89 | 325 | return false; |
c5286665 | 326 | } |
83c0afae | 327 | |
c5f51765 VD |
328 | dl = dsa_link_touch(dp, link_dp); |
329 | if (!dl) { | |
330 | of_node_put(it.node); | |
331 | return false; | |
332 | } | |
83c0afae AL |
333 | } |
334 | ||
34c09a89 | 335 | return true; |
83c0afae AL |
336 | } |
337 | ||
3774ecdb | 338 | static bool dsa_tree_setup_routing_table(struct dsa_switch_tree *dst) |
83c0afae | 339 | { |
34c09a89 VD |
340 | bool complete = true; |
341 | struct dsa_port *dp; | |
83c0afae | 342 | |
86bfb2c1 | 343 | list_for_each_entry(dp, &dst->ports, list) { |
3774ecdb | 344 | if (dsa_port_is_dsa(dp)) { |
34c09a89 VD |
345 | complete = dsa_port_setup_routing_table(dp); |
346 | if (!complete) | |
347 | break; | |
348 | } | |
83c0afae AL |
349 | } |
350 | ||
34c09a89 | 351 | return complete; |
83c0afae AL |
352 | } |
353 | ||
f070464c VD |
354 | static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst) |
355 | { | |
f070464c | 356 | struct dsa_port *dp; |
f070464c | 357 | |
c0b73628 VD |
358 | list_for_each_entry(dp, &dst->ports, list) |
359 | if (dsa_port_is_cpu(dp)) | |
360 | return dp; | |
f070464c VD |
361 | |
362 | return NULL; | |
363 | } | |
364 | ||
2c0b0325 VO |
365 | /* Assign the default CPU port (the first one in the tree) to all ports of the |
366 | * fabric which don't already have one as part of their own switch. | |
367 | */ | |
f070464c VD |
368 | static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst) |
369 | { | |
da4561cd | 370 | struct dsa_port *cpu_dp, *dp; |
f070464c | 371 | |
da4561cd VD |
372 | cpu_dp = dsa_tree_find_first_cpu(dst); |
373 | if (!cpu_dp) { | |
374 | pr_err("DSA: tree %d has no CPU port\n", dst->index); | |
f070464c VD |
375 | return -EINVAL; |
376 | } | |
377 | ||
2c0b0325 VO |
378 | list_for_each_entry(dp, &dst->ports, list) { |
379 | if (dp->cpu_dp) | |
380 | continue; | |
381 | ||
da4561cd VD |
382 | if (dsa_port_is_user(dp) || dsa_port_is_dsa(dp)) |
383 | dp->cpu_dp = cpu_dp; | |
2c0b0325 | 384 | } |
f070464c VD |
385 | |
386 | return 0; | |
387 | } | |
388 | ||
2c0b0325 VO |
389 | /* Perform initial assignment of CPU ports to user ports and DSA links in the |
390 | * fabric, giving preference to CPU ports local to each switch. Default to | |
391 | * using the first CPU port in the switch tree if the port does not have a CPU | |
392 | * port local to this switch. | |
393 | */ | |
394 | static int dsa_tree_setup_cpu_ports(struct dsa_switch_tree *dst) | |
395 | { | |
396 | struct dsa_port *cpu_dp, *dp; | |
397 | ||
398 | list_for_each_entry(cpu_dp, &dst->ports, list) { | |
399 | if (!dsa_port_is_cpu(cpu_dp)) | |
400 | continue; | |
401 | ||
402 | list_for_each_entry(dp, &dst->ports, list) { | |
403 | /* Prefer a local CPU port */ | |
404 | if (dp->ds != cpu_dp->ds) | |
405 | continue; | |
406 | ||
407 | /* Prefer the first local CPU port found */ | |
408 | if (dp->cpu_dp) | |
409 | continue; | |
410 | ||
411 | if (dsa_port_is_user(dp) || dsa_port_is_dsa(dp)) | |
412 | dp->cpu_dp = cpu_dp; | |
413 | } | |
414 | } | |
415 | ||
416 | return dsa_tree_setup_default_cpu(dst); | |
417 | } | |
418 | ||
0e8eb9a1 | 419 | static void dsa_tree_teardown_cpu_ports(struct dsa_switch_tree *dst) |
f070464c | 420 | { |
da4561cd VD |
421 | struct dsa_port *dp; |
422 | ||
423 | list_for_each_entry(dp, &dst->ports, list) | |
424 | if (dsa_port_is_user(dp) || dsa_port_is_dsa(dp)) | |
425 | dp->cpu_dp = NULL; | |
f070464c VD |
426 | } |
427 | ||
1d27732f | 428 | static int dsa_port_setup(struct dsa_port *dp) |
83c0afae | 429 | { |
955222ca | 430 | struct devlink_port *dlp = &dp->devlink_port; |
4ba0ebbc | 431 | bool dsa_port_link_registered = false; |
fd292c18 | 432 | struct dsa_switch *ds = dp->ds; |
4ba0ebbc VO |
433 | bool dsa_port_enabled = false; |
434 | int err = 0; | |
83c0afae | 435 | |
fb35c60c VD |
436 | if (dp->setup) |
437 | return 0; | |
438 | ||
3f6e32f9 | 439 | INIT_LIST_HEAD(&dp->fdbs); |
161ca59d VO |
440 | INIT_LIST_HEAD(&dp->mdbs); |
441 | ||
fd292c18 VO |
442 | if (ds->ops->port_setup) { |
443 | err = ds->ops->port_setup(ds, dp->index); | |
444 | if (err) | |
445 | return err; | |
446 | } | |
447 | ||
1d27732f VD |
448 | switch (dp->type) { |
449 | case DSA_PORT_TYPE_UNUSED: | |
0394a63a | 450 | dsa_port_disable(dp); |
1d27732f VD |
451 | break; |
452 | case DSA_PORT_TYPE_CPU: | |
da077392 | 453 | err = dsa_port_link_register_of(dp); |
0394a63a | 454 | if (err) |
4ba0ebbc VO |
455 | break; |
456 | dsa_port_link_registered = true; | |
0394a63a VD |
457 | |
458 | err = dsa_port_enable(dp, NULL); | |
e70c7aad | 459 | if (err) |
4ba0ebbc VO |
460 | break; |
461 | dsa_port_enabled = true; | |
462 | ||
da077392 | 463 | break; |
1d27732f | 464 | case DSA_PORT_TYPE_DSA: |
33615367 | 465 | err = dsa_port_link_register_of(dp); |
0394a63a | 466 | if (err) |
4ba0ebbc VO |
467 | break; |
468 | dsa_port_link_registered = true; | |
0394a63a VD |
469 | |
470 | err = dsa_port_enable(dp, NULL); | |
e70c7aad | 471 | if (err) |
4ba0ebbc VO |
472 | break; |
473 | dsa_port_enabled = true; | |
474 | ||
1d27732f VD |
475 | break; |
476 | case DSA_PORT_TYPE_USER: | |
83216e39 | 477 | of_get_mac_address(dp->dn, dp->mac); |
1d27732f VD |
478 | err = dsa_slave_create(dp); |
479 | if (err) | |
4ba0ebbc | 480 | break; |
955222ca VD |
481 | |
482 | devlink_port_type_eth_set(dlp, dp->slave); | |
1d27732f | 483 | break; |
83c0afae AL |
484 | } |
485 | ||
4ba0ebbc VO |
486 | if (err && dsa_port_enabled) |
487 | dsa_port_disable(dp); | |
488 | if (err && dsa_port_link_registered) | |
489 | dsa_port_link_unregister_of(dp); | |
fd292c18 VO |
490 | if (err) { |
491 | if (ds->ops->port_teardown) | |
492 | ds->ops->port_teardown(ds, dp->index); | |
fb35c60c | 493 | return err; |
fd292c18 | 494 | } |
4ba0ebbc | 495 | |
fb35c60c VD |
496 | dp->setup = true; |
497 | ||
498 | return 0; | |
83c0afae AL |
499 | } |
500 | ||
3122433e | 501 | static int dsa_port_devlink_setup(struct dsa_port *dp) |
83c0afae | 502 | { |
955222ca | 503 | struct devlink_port *dlp = &dp->devlink_port; |
3122433e AL |
504 | struct dsa_switch_tree *dst = dp->ds->dst; |
505 | struct devlink_port_attrs attrs = {}; | |
506 | struct devlink *dl = dp->ds->devlink; | |
507 | const unsigned char *id; | |
508 | unsigned char len; | |
509 | int err; | |
510 | ||
511 | id = (const unsigned char *)&dst->index; | |
512 | len = sizeof(dst->index); | |
513 | ||
514 | attrs.phys.port_number = dp->index; | |
515 | memcpy(attrs.switch_id.id, id, len); | |
516 | attrs.switch_id.id_len = len; | |
517 | memset(dlp, 0, sizeof(*dlp)); | |
518 | ||
519 | switch (dp->type) { | |
520 | case DSA_PORT_TYPE_UNUSED: | |
521 | attrs.flavour = DEVLINK_PORT_FLAVOUR_UNUSED; | |
522 | break; | |
523 | case DSA_PORT_TYPE_CPU: | |
524 | attrs.flavour = DEVLINK_PORT_FLAVOUR_CPU; | |
525 | break; | |
526 | case DSA_PORT_TYPE_DSA: | |
527 | attrs.flavour = DEVLINK_PORT_FLAVOUR_DSA; | |
528 | break; | |
529 | case DSA_PORT_TYPE_USER: | |
530 | attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; | |
531 | break; | |
532 | } | |
533 | ||
534 | devlink_port_attrs_set(dlp, &attrs); | |
535 | err = devlink_port_register(dl, dlp, dp->index); | |
536 | ||
537 | if (!err) | |
538 | dp->devlink_port_setup = true; | |
1d27732f | 539 | |
3122433e AL |
540 | return err; |
541 | } | |
542 | ||
543 | static void dsa_port_teardown(struct dsa_port *dp) | |
544 | { | |
91158e16 | 545 | struct devlink_port *dlp = &dp->devlink_port; |
fd292c18 | 546 | struct dsa_switch *ds = dp->ds; |
161ca59d | 547 | struct dsa_mac_addr *a, *tmp; |
91158e16 | 548 | |
fb35c60c VD |
549 | if (!dp->setup) |
550 | return; | |
551 | ||
fd292c18 VO |
552 | if (ds->ops->port_teardown) |
553 | ds->ops->port_teardown(ds, dp->index); | |
554 | ||
91158e16 VO |
555 | devlink_port_type_clear(dlp); |
556 | ||
1d27732f VD |
557 | switch (dp->type) { |
558 | case DSA_PORT_TYPE_UNUSED: | |
559 | break; | |
560 | case DSA_PORT_TYPE_CPU: | |
0394a63a | 561 | dsa_port_disable(dp); |
955222ca VD |
562 | dsa_port_link_unregister_of(dp); |
563 | break; | |
1d27732f | 564 | case DSA_PORT_TYPE_DSA: |
0394a63a | 565 | dsa_port_disable(dp); |
33615367 | 566 | dsa_port_link_unregister_of(dp); |
1d27732f VD |
567 | break; |
568 | case DSA_PORT_TYPE_USER: | |
569 | if (dp->slave) { | |
570 | dsa_slave_destroy(dp->slave); | |
571 | dp->slave = NULL; | |
572 | } | |
573 | break; | |
83c0afae | 574 | } |
fb35c60c | 575 | |
3f6e32f9 VO |
576 | list_for_each_entry_safe(a, tmp, &dp->fdbs, list) { |
577 | list_del(&a->list); | |
578 | kfree(a); | |
579 | } | |
580 | ||
161ca59d VO |
581 | list_for_each_entry_safe(a, tmp, &dp->mdbs, list) { |
582 | list_del(&a->list); | |
583 | kfree(a); | |
584 | } | |
585 | ||
fb35c60c | 586 | dp->setup = false; |
83c0afae AL |
587 | } |
588 | ||
3122433e AL |
589 | static void dsa_port_devlink_teardown(struct dsa_port *dp) |
590 | { | |
591 | struct devlink_port *dlp = &dp->devlink_port; | |
592 | ||
593 | if (dp->devlink_port_setup) | |
594 | devlink_port_unregister(dlp); | |
595 | dp->devlink_port_setup = false; | |
596 | } | |
597 | ||
fd292c18 VO |
598 | /* Destroy the current devlink port, and create a new one which has the UNUSED |
599 | * flavour. At this point, any call to ds->ops->port_setup has been already | |
600 | * balanced out by a call to ds->ops->port_teardown, so we know that any | |
601 | * devlink port regions the driver had are now unregistered. We then call its | |
602 | * ds->ops->port_setup again, in order for the driver to re-create them on the | |
603 | * new devlink port. | |
604 | */ | |
605 | static int dsa_port_reinit_as_unused(struct dsa_port *dp) | |
606 | { | |
607 | struct dsa_switch *ds = dp->ds; | |
608 | int err; | |
609 | ||
610 | dsa_port_devlink_teardown(dp); | |
611 | dp->type = DSA_PORT_TYPE_UNUSED; | |
612 | err = dsa_port_devlink_setup(dp); | |
613 | if (err) | |
614 | return err; | |
615 | ||
616 | if (ds->ops->port_setup) { | |
617 | /* On error, leave the devlink port registered, | |
618 | * dsa_switch_teardown will clean it up later. | |
619 | */ | |
620 | err = ds->ops->port_setup(ds, dp->index); | |
621 | if (err) | |
622 | return err; | |
623 | } | |
624 | ||
625 | return 0; | |
626 | } | |
627 | ||
0f06b855 AL |
628 | static int dsa_devlink_info_get(struct devlink *dl, |
629 | struct devlink_info_req *req, | |
630 | struct netlink_ext_ack *extack) | |
631 | { | |
632 | struct dsa_switch *ds = dsa_devlink_to_ds(dl); | |
633 | ||
634 | if (ds->ops->devlink_info_get) | |
635 | return ds->ops->devlink_info_get(ds, req, extack); | |
636 | ||
637 | return -EOPNOTSUPP; | |
638 | } | |
639 | ||
2a6ef763 VO |
640 | static int dsa_devlink_sb_pool_get(struct devlink *dl, |
641 | unsigned int sb_index, u16 pool_index, | |
642 | struct devlink_sb_pool_info *pool_info) | |
643 | { | |
644 | struct dsa_switch *ds = dsa_devlink_to_ds(dl); | |
645 | ||
646 | if (!ds->ops->devlink_sb_pool_get) | |
647 | return -EOPNOTSUPP; | |
648 | ||
649 | return ds->ops->devlink_sb_pool_get(ds, sb_index, pool_index, | |
650 | pool_info); | |
651 | } | |
652 | ||
653 | static int dsa_devlink_sb_pool_set(struct devlink *dl, unsigned int sb_index, | |
654 | u16 pool_index, u32 size, | |
655 | enum devlink_sb_threshold_type threshold_type, | |
656 | struct netlink_ext_ack *extack) | |
657 | { | |
658 | struct dsa_switch *ds = dsa_devlink_to_ds(dl); | |
659 | ||
660 | if (!ds->ops->devlink_sb_pool_set) | |
661 | return -EOPNOTSUPP; | |
662 | ||
663 | return ds->ops->devlink_sb_pool_set(ds, sb_index, pool_index, size, | |
664 | threshold_type, extack); | |
665 | } | |
666 | ||
667 | static int dsa_devlink_sb_port_pool_get(struct devlink_port *dlp, | |
668 | unsigned int sb_index, u16 pool_index, | |
669 | u32 *p_threshold) | |
670 | { | |
671 | struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp); | |
672 | int port = dsa_devlink_port_to_port(dlp); | |
673 | ||
674 | if (!ds->ops->devlink_sb_port_pool_get) | |
675 | return -EOPNOTSUPP; | |
676 | ||
677 | return ds->ops->devlink_sb_port_pool_get(ds, port, sb_index, | |
678 | pool_index, p_threshold); | |
679 | } | |
680 | ||
681 | static int dsa_devlink_sb_port_pool_set(struct devlink_port *dlp, | |
682 | unsigned int sb_index, u16 pool_index, | |
683 | u32 threshold, | |
684 | struct netlink_ext_ack *extack) | |
685 | { | |
686 | struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp); | |
687 | int port = dsa_devlink_port_to_port(dlp); | |
688 | ||
689 | if (!ds->ops->devlink_sb_port_pool_set) | |
690 | return -EOPNOTSUPP; | |
691 | ||
692 | return ds->ops->devlink_sb_port_pool_set(ds, port, sb_index, | |
693 | pool_index, threshold, extack); | |
694 | } | |
695 | ||
696 | static int | |
697 | dsa_devlink_sb_tc_pool_bind_get(struct devlink_port *dlp, | |
698 | unsigned int sb_index, u16 tc_index, | |
699 | enum devlink_sb_pool_type pool_type, | |
700 | u16 *p_pool_index, u32 *p_threshold) | |
701 | { | |
702 | struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp); | |
703 | int port = dsa_devlink_port_to_port(dlp); | |
704 | ||
705 | if (!ds->ops->devlink_sb_tc_pool_bind_get) | |
706 | return -EOPNOTSUPP; | |
707 | ||
708 | return ds->ops->devlink_sb_tc_pool_bind_get(ds, port, sb_index, | |
709 | tc_index, pool_type, | |
710 | p_pool_index, p_threshold); | |
711 | } | |
712 | ||
713 | static int | |
714 | dsa_devlink_sb_tc_pool_bind_set(struct devlink_port *dlp, | |
715 | unsigned int sb_index, u16 tc_index, | |
716 | enum devlink_sb_pool_type pool_type, | |
717 | u16 pool_index, u32 threshold, | |
718 | struct netlink_ext_ack *extack) | |
719 | { | |
720 | struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp); | |
721 | int port = dsa_devlink_port_to_port(dlp); | |
722 | ||
723 | if (!ds->ops->devlink_sb_tc_pool_bind_set) | |
724 | return -EOPNOTSUPP; | |
725 | ||
726 | return ds->ops->devlink_sb_tc_pool_bind_set(ds, port, sb_index, | |
727 | tc_index, pool_type, | |
728 | pool_index, threshold, | |
729 | extack); | |
730 | } | |
731 | ||
732 | static int dsa_devlink_sb_occ_snapshot(struct devlink *dl, | |
733 | unsigned int sb_index) | |
734 | { | |
735 | struct dsa_switch *ds = dsa_devlink_to_ds(dl); | |
736 | ||
737 | if (!ds->ops->devlink_sb_occ_snapshot) | |
738 | return -EOPNOTSUPP; | |
739 | ||
740 | return ds->ops->devlink_sb_occ_snapshot(ds, sb_index); | |
741 | } | |
742 | ||
743 | static int dsa_devlink_sb_occ_max_clear(struct devlink *dl, | |
744 | unsigned int sb_index) | |
745 | { | |
746 | struct dsa_switch *ds = dsa_devlink_to_ds(dl); | |
747 | ||
748 | if (!ds->ops->devlink_sb_occ_max_clear) | |
749 | return -EOPNOTSUPP; | |
750 | ||
751 | return ds->ops->devlink_sb_occ_max_clear(ds, sb_index); | |
752 | } | |
753 | ||
754 | static int dsa_devlink_sb_occ_port_pool_get(struct devlink_port *dlp, | |
755 | unsigned int sb_index, | |
756 | u16 pool_index, u32 *p_cur, | |
757 | u32 *p_max) | |
758 | { | |
759 | struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp); | |
760 | int port = dsa_devlink_port_to_port(dlp); | |
761 | ||
762 | if (!ds->ops->devlink_sb_occ_port_pool_get) | |
763 | return -EOPNOTSUPP; | |
764 | ||
765 | return ds->ops->devlink_sb_occ_port_pool_get(ds, port, sb_index, | |
766 | pool_index, p_cur, p_max); | |
767 | } | |
768 | ||
769 | static int | |
770 | dsa_devlink_sb_occ_tc_port_bind_get(struct devlink_port *dlp, | |
771 | unsigned int sb_index, u16 tc_index, | |
772 | enum devlink_sb_pool_type pool_type, | |
773 | u32 *p_cur, u32 *p_max) | |
774 | { | |
775 | struct dsa_switch *ds = dsa_devlink_port_to_ds(dlp); | |
776 | int port = dsa_devlink_port_to_port(dlp); | |
777 | ||
778 | if (!ds->ops->devlink_sb_occ_tc_port_bind_get) | |
779 | return -EOPNOTSUPP; | |
780 | ||
781 | return ds->ops->devlink_sb_occ_tc_port_bind_get(ds, port, | |
782 | sb_index, tc_index, | |
783 | pool_type, p_cur, | |
784 | p_max); | |
785 | } | |
786 | ||
0f06b855 | 787 | static const struct devlink_ops dsa_devlink_ops = { |
2a6ef763 VO |
788 | .info_get = dsa_devlink_info_get, |
789 | .sb_pool_get = dsa_devlink_sb_pool_get, | |
790 | .sb_pool_set = dsa_devlink_sb_pool_set, | |
791 | .sb_port_pool_get = dsa_devlink_sb_port_pool_get, | |
792 | .sb_port_pool_set = dsa_devlink_sb_port_pool_set, | |
793 | .sb_tc_pool_bind_get = dsa_devlink_sb_tc_pool_bind_get, | |
794 | .sb_tc_pool_bind_set = dsa_devlink_sb_tc_pool_bind_set, | |
795 | .sb_occ_snapshot = dsa_devlink_sb_occ_snapshot, | |
796 | .sb_occ_max_clear = dsa_devlink_sb_occ_max_clear, | |
797 | .sb_occ_port_pool_get = dsa_devlink_sb_occ_port_pool_get, | |
798 | .sb_occ_tc_port_bind_get = dsa_devlink_sb_occ_tc_port_bind_get, | |
0f06b855 AL |
799 | }; |
800 | ||
deff7107 TW |
801 | static int dsa_switch_setup_tag_protocol(struct dsa_switch *ds) |
802 | { | |
803 | const struct dsa_device_ops *tag_ops = ds->dst->tag_ops; | |
804 | struct dsa_switch_tree *dst = ds->dst; | |
805 | int port, err; | |
806 | ||
807 | if (tag_ops->proto == dst->default_proto) | |
808 | return 0; | |
809 | ||
810 | for (port = 0; port < ds->num_ports; port++) { | |
811 | if (!dsa_is_cpu_port(ds, port)) | |
812 | continue; | |
813 | ||
1951b3f1 | 814 | rtnl_lock(); |
deff7107 | 815 | err = ds->ops->change_tag_protocol(ds, port, tag_ops->proto); |
1951b3f1 | 816 | rtnl_unlock(); |
deff7107 TW |
817 | if (err) { |
818 | dev_err(ds->dev, "Unable to use tag protocol \"%s\": %pe\n", | |
819 | tag_ops->name, ERR_PTR(err)); | |
820 | return err; | |
821 | } | |
822 | } | |
823 | ||
824 | return 0; | |
825 | } | |
826 | ||
1f08f9e9 | 827 | static int dsa_switch_setup(struct dsa_switch *ds) |
83c0afae | 828 | { |
6b297524 | 829 | struct dsa_devlink_priv *dl_priv; |
3122433e | 830 | struct dsa_port *dp; |
fb35c60c VD |
831 | int err; |
832 | ||
833 | if (ds->setup) | |
834 | return 0; | |
83c0afae | 835 | |
6e830d8f | 836 | /* Initialize ds->phys_mii_mask before registering the slave MDIO bus |
9d490b4e | 837 | * driver and before ops->setup() has run, since the switch drivers and |
6e830d8f FF |
838 | * the slave MDIO bus driver rely on these values for probing PHY |
839 | * devices or not | |
840 | */ | |
02bc6e54 | 841 | ds->phys_mii_mask |= dsa_user_ports(ds); |
6e830d8f | 842 | |
96567d5d AL |
843 | /* Add the switch to devlink before calling setup, so that setup can |
844 | * add dpipe tables | |
845 | */ | |
919d13a7 LR |
846 | ds->devlink = |
847 | devlink_alloc(&dsa_devlink_ops, sizeof(*dl_priv), ds->dev); | |
96567d5d AL |
848 | if (!ds->devlink) |
849 | return -ENOMEM; | |
6b297524 AL |
850 | dl_priv = devlink_priv(ds->devlink); |
851 | dl_priv->ds = ds; | |
96567d5d | 852 | |
919d13a7 | 853 | err = devlink_register(ds->devlink); |
96567d5d | 854 | if (err) |
e70c7aad | 855 | goto free_devlink; |
96567d5d | 856 | |
3122433e AL |
857 | /* Setup devlink port instances now, so that the switch |
858 | * setup() can register regions etc, against the ports | |
859 | */ | |
860 | list_for_each_entry(dp, &ds->dst->ports, list) { | |
861 | if (dp->ds == ds) { | |
862 | err = dsa_port_devlink_setup(dp); | |
863 | if (err) | |
864 | goto unregister_devlink_ports; | |
865 | } | |
866 | } | |
867 | ||
f515f192 VD |
868 | err = dsa_switch_register_notifier(ds); |
869 | if (err) | |
3122433e | 870 | goto unregister_devlink_ports; |
f515f192 | 871 | |
0ee2af4e VO |
872 | ds->configure_vlan_while_not_filtering = true; |
873 | ||
b2243b36 VO |
874 | err = ds->ops->setup(ds); |
875 | if (err < 0) | |
e70c7aad | 876 | goto unregister_notifier; |
b2243b36 | 877 | |
deff7107 TW |
878 | err = dsa_switch_setup_tag_protocol(ds); |
879 | if (err) | |
880 | goto teardown; | |
881 | ||
6b297524 AL |
882 | devlink_params_publish(ds->devlink); |
883 | ||
9d490b4e | 884 | if (!ds->slave_mii_bus && ds->ops->phy_read) { |
5135e96a | 885 | ds->slave_mii_bus = mdiobus_alloc(); |
e70c7aad IC |
886 | if (!ds->slave_mii_bus) { |
887 | err = -ENOMEM; | |
8fd54a73 | 888 | goto teardown; |
e70c7aad | 889 | } |
1eb59443 FF |
890 | |
891 | dsa_slave_mii_bus_init(ds); | |
892 | ||
893 | err = mdiobus_register(ds->slave_mii_bus); | |
894 | if (err < 0) | |
5135e96a | 895 | goto free_slave_mii_bus; |
1eb59443 FF |
896 | } |
897 | ||
fb35c60c VD |
898 | ds->setup = true; |
899 | ||
83c0afae | 900 | return 0; |
e70c7aad | 901 | |
5135e96a VO |
902 | free_slave_mii_bus: |
903 | if (ds->slave_mii_bus && ds->ops->phy_read) | |
904 | mdiobus_free(ds->slave_mii_bus); | |
8fd54a73 VO |
905 | teardown: |
906 | if (ds->ops->teardown) | |
907 | ds->ops->teardown(ds); | |
e70c7aad IC |
908 | unregister_notifier: |
909 | dsa_switch_unregister_notifier(ds); | |
3122433e AL |
910 | unregister_devlink_ports: |
911 | list_for_each_entry(dp, &ds->dst->ports, list) | |
912 | if (dp->ds == ds) | |
913 | dsa_port_devlink_teardown(dp); | |
e70c7aad IC |
914 | devlink_unregister(ds->devlink); |
915 | free_devlink: | |
916 | devlink_free(ds->devlink); | |
917 | ds->devlink = NULL; | |
918 | ||
919 | return err; | |
83c0afae AL |
920 | } |
921 | ||
1f08f9e9 | 922 | static void dsa_switch_teardown(struct dsa_switch *ds) |
83c0afae | 923 | { |
3122433e AL |
924 | struct dsa_port *dp; |
925 | ||
fb35c60c VD |
926 | if (!ds->setup) |
927 | return; | |
928 | ||
5135e96a | 929 | if (ds->slave_mii_bus && ds->ops->phy_read) { |
1eb59443 | 930 | mdiobus_unregister(ds->slave_mii_bus); |
5135e96a VO |
931 | mdiobus_free(ds->slave_mii_bus); |
932 | ds->slave_mii_bus = NULL; | |
933 | } | |
f515f192 VD |
934 | |
935 | dsa_switch_unregister_notifier(ds); | |
96567d5d | 936 | |
5e3f847a VO |
937 | if (ds->ops->teardown) |
938 | ds->ops->teardown(ds); | |
939 | ||
96567d5d | 940 | if (ds->devlink) { |
3122433e AL |
941 | list_for_each_entry(dp, &ds->dst->ports, list) |
942 | if (dp->ds == ds) | |
943 | dsa_port_devlink_teardown(dp); | |
96567d5d AL |
944 | devlink_unregister(ds->devlink); |
945 | devlink_free(ds->devlink); | |
946 | ds->devlink = NULL; | |
947 | } | |
948 | ||
fb35c60c | 949 | ds->setup = false; |
83c0afae AL |
950 | } |
951 | ||
a57d8c21 VO |
952 | /* First tear down the non-shared, then the shared ports. This ensures that |
953 | * all work items scheduled by our switchdev handlers for user ports have | |
954 | * completed before we destroy the refcounting kept on the shared ports. | |
955 | */ | |
956 | static void dsa_tree_teardown_ports(struct dsa_switch_tree *dst) | |
957 | { | |
958 | struct dsa_port *dp; | |
959 | ||
960 | list_for_each_entry(dp, &dst->ports, list) | |
961 | if (dsa_port_is_user(dp) || dsa_port_is_unused(dp)) | |
962 | dsa_port_teardown(dp); | |
963 | ||
964 | dsa_flush_workqueue(); | |
965 | ||
966 | list_for_each_entry(dp, &dst->ports, list) | |
967 | if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp)) | |
968 | dsa_port_teardown(dp); | |
969 | } | |
970 | ||
971 | static void dsa_tree_teardown_switches(struct dsa_switch_tree *dst) | |
972 | { | |
973 | struct dsa_port *dp; | |
974 | ||
975 | list_for_each_entry(dp, &dst->ports, list) | |
976 | dsa_switch_teardown(dp->ds); | |
977 | } | |
978 | ||
1f08f9e9 VD |
979 | static int dsa_tree_setup_switches(struct dsa_switch_tree *dst) |
980 | { | |
1d27732f | 981 | struct dsa_port *dp; |
fb35c60c | 982 | int err; |
1f08f9e9 | 983 | |
fb35c60c VD |
984 | list_for_each_entry(dp, &dst->ports, list) { |
985 | err = dsa_switch_setup(dp->ds); | |
1f08f9e9 | 986 | if (err) |
fb35c60c VD |
987 | goto teardown; |
988 | } | |
1d27732f | 989 | |
fb35c60c VD |
990 | list_for_each_entry(dp, &dst->ports, list) { |
991 | err = dsa_port_setup(dp); | |
fb6ec87f | 992 | if (err) { |
fd292c18 | 993 | err = dsa_port_reinit_as_unused(dp); |
fb6ec87f MK |
994 | if (err) |
995 | goto teardown; | |
fb6ec87f | 996 | } |
1f08f9e9 VD |
997 | } |
998 | ||
999 | return 0; | |
e70c7aad | 1000 | |
fb35c60c | 1001 | teardown: |
a57d8c21 | 1002 | dsa_tree_teardown_ports(dst); |
e70c7aad | 1003 | |
a57d8c21 | 1004 | dsa_tree_teardown_switches(dst); |
e70c7aad IC |
1005 | |
1006 | return err; | |
1f08f9e9 VD |
1007 | } |
1008 | ||
17a22fcf VD |
1009 | static int dsa_tree_setup_master(struct dsa_switch_tree *dst) |
1010 | { | |
0cfec588 VD |
1011 | struct dsa_port *dp; |
1012 | int err; | |
17a22fcf | 1013 | |
0cfec588 VD |
1014 | list_for_each_entry(dp, &dst->ports, list) { |
1015 | if (dsa_port_is_cpu(dp)) { | |
1016 | err = dsa_master_setup(dp->master, dp); | |
1017 | if (err) | |
1018 | return err; | |
1019 | } | |
1020 | } | |
1021 | ||
1022 | return 0; | |
17a22fcf VD |
1023 | } |
1024 | ||
1025 | static void dsa_tree_teardown_master(struct dsa_switch_tree *dst) | |
1026 | { | |
0cfec588 | 1027 | struct dsa_port *dp; |
17a22fcf | 1028 | |
0cfec588 VD |
1029 | list_for_each_entry(dp, &dst->ports, list) |
1030 | if (dsa_port_is_cpu(dp)) | |
1031 | dsa_master_teardown(dp->master); | |
17a22fcf VD |
1032 | } |
1033 | ||
058102a6 TW |
1034 | static int dsa_tree_setup_lags(struct dsa_switch_tree *dst) |
1035 | { | |
1036 | unsigned int len = 0; | |
1037 | struct dsa_port *dp; | |
1038 | ||
1039 | list_for_each_entry(dp, &dst->ports, list) { | |
1040 | if (dp->ds->num_lag_ids > len) | |
1041 | len = dp->ds->num_lag_ids; | |
1042 | } | |
1043 | ||
1044 | if (!len) | |
1045 | return 0; | |
1046 | ||
1047 | dst->lags = kcalloc(len, sizeof(*dst->lags), GFP_KERNEL); | |
1048 | if (!dst->lags) | |
1049 | return -ENOMEM; | |
1050 | ||
1051 | dst->lags_len = len; | |
1052 | return 0; | |
1053 | } | |
1054 | ||
1055 | static void dsa_tree_teardown_lags(struct dsa_switch_tree *dst) | |
1056 | { | |
1057 | kfree(dst->lags); | |
1058 | } | |
1059 | ||
ec15dd42 | 1060 | static int dsa_tree_setup(struct dsa_switch_tree *dst) |
83c0afae | 1061 | { |
34c09a89 | 1062 | bool complete; |
83c0afae AL |
1063 | int err; |
1064 | ||
ec15dd42 VD |
1065 | if (dst->setup) { |
1066 | pr_err("DSA: tree %d already setup! Disjoint trees?\n", | |
1067 | dst->index); | |
1068 | return -EEXIST; | |
1069 | } | |
1070 | ||
34c09a89 VD |
1071 | complete = dsa_tree_setup_routing_table(dst); |
1072 | if (!complete) | |
1073 | return 0; | |
1074 | ||
2c0b0325 | 1075 | err = dsa_tree_setup_cpu_ports(dst); |
f070464c VD |
1076 | if (err) |
1077 | return err; | |
1078 | ||
1f08f9e9 VD |
1079 | err = dsa_tree_setup_switches(dst); |
1080 | if (err) | |
0e8eb9a1 | 1081 | goto teardown_cpu_ports; |
83c0afae | 1082 | |
17a22fcf | 1083 | err = dsa_tree_setup_master(dst); |
1943563d | 1084 | if (err) |
e70c7aad | 1085 | goto teardown_switches; |
1943563d | 1086 | |
058102a6 TW |
1087 | err = dsa_tree_setup_lags(dst); |
1088 | if (err) | |
1089 | goto teardown_master; | |
1090 | ||
ec15dd42 VD |
1091 | dst->setup = true; |
1092 | ||
1093 | pr_info("DSA: tree %d setup\n", dst->index); | |
83c0afae AL |
1094 | |
1095 | return 0; | |
e70c7aad | 1096 | |
058102a6 TW |
1097 | teardown_master: |
1098 | dsa_tree_teardown_master(dst); | |
e70c7aad | 1099 | teardown_switches: |
e5845aa0 | 1100 | dsa_tree_teardown_ports(dst); |
e70c7aad | 1101 | dsa_tree_teardown_switches(dst); |
0e8eb9a1 VO |
1102 | teardown_cpu_ports: |
1103 | dsa_tree_teardown_cpu_ports(dst); | |
e70c7aad IC |
1104 | |
1105 | return err; | |
83c0afae AL |
1106 | } |
1107 | ||
ec15dd42 | 1108 | static void dsa_tree_teardown(struct dsa_switch_tree *dst) |
83c0afae | 1109 | { |
c5f51765 VD |
1110 | struct dsa_link *dl, *next; |
1111 | ||
ec15dd42 | 1112 | if (!dst->setup) |
83c0afae AL |
1113 | return; |
1114 | ||
058102a6 TW |
1115 | dsa_tree_teardown_lags(dst); |
1116 | ||
17a22fcf | 1117 | dsa_tree_teardown_master(dst); |
83c0afae | 1118 | |
a57d8c21 VO |
1119 | dsa_tree_teardown_ports(dst); |
1120 | ||
1f08f9e9 | 1121 | dsa_tree_teardown_switches(dst); |
83c0afae | 1122 | |
0e8eb9a1 | 1123 | dsa_tree_teardown_cpu_ports(dst); |
0c73c523 | 1124 | |
c5f51765 VD |
1125 | list_for_each_entry_safe(dl, next, &dst->rtable, list) { |
1126 | list_del(&dl->list); | |
1127 | kfree(dl); | |
1128 | } | |
1129 | ||
ec15dd42 VD |
1130 | pr_info("DSA: tree %d torn down\n", dst->index); |
1131 | ||
1132 | dst->setup = false; | |
83c0afae AL |
1133 | } |
1134 | ||
53da0eba VO |
1135 | /* Since the dsa/tagging sysfs device attribute is per master, the assumption |
1136 | * is that all DSA switches within a tree share the same tagger, otherwise | |
1137 | * they would have formed disjoint trees (different "dsa,member" values). | |
1138 | */ | |
1139 | int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst, | |
1140 | struct net_device *master, | |
1141 | const struct dsa_device_ops *tag_ops, | |
1142 | const struct dsa_device_ops *old_tag_ops) | |
1143 | { | |
1144 | struct dsa_notifier_tag_proto_info info; | |
1145 | struct dsa_port *dp; | |
1146 | int err = -EBUSY; | |
1147 | ||
1148 | if (!rtnl_trylock()) | |
1149 | return restart_syscall(); | |
1150 | ||
1151 | /* At the moment we don't allow changing the tag protocol under | |
1152 | * traffic. The rtnl_mutex also happens to serialize concurrent | |
1153 | * attempts to change the tagging protocol. If we ever lift the IFF_UP | |
1154 | * restriction, there needs to be another mutex which serializes this. | |
1155 | */ | |
1156 | if (master->flags & IFF_UP) | |
1157 | goto out_unlock; | |
1158 | ||
1159 | list_for_each_entry(dp, &dst->ports, list) { | |
1160 | if (!dsa_is_user_port(dp->ds, dp->index)) | |
1161 | continue; | |
1162 | ||
1163 | if (dp->slave->flags & IFF_UP) | |
1164 | goto out_unlock; | |
1165 | } | |
1166 | ||
1167 | info.tag_ops = tag_ops; | |
1168 | err = dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, &info); | |
1169 | if (err) | |
1170 | goto out_unwind_tagger; | |
1171 | ||
1172 | dst->tag_ops = tag_ops; | |
1173 | ||
1174 | rtnl_unlock(); | |
1175 | ||
1176 | return 0; | |
1177 | ||
1178 | out_unwind_tagger: | |
1179 | info.tag_ops = old_tag_ops; | |
1180 | dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, &info); | |
1181 | out_unlock: | |
1182 | rtnl_unlock(); | |
1183 | return err; | |
1184 | } | |
1185 | ||
ab8ccae1 VD |
1186 | static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index) |
1187 | { | |
1188 | struct dsa_switch_tree *dst = ds->dst; | |
1189 | struct dsa_port *dp; | |
1190 | ||
05f294a8 VD |
1191 | list_for_each_entry(dp, &dst->ports, list) |
1192 | if (dp->ds == ds && dp->index == index) | |
1193 | return dp; | |
1194 | ||
1195 | dp = kzalloc(sizeof(*dp), GFP_KERNEL); | |
1196 | if (!dp) | |
1197 | return NULL; | |
ab8ccae1 VD |
1198 | |
1199 | dp->ds = ds; | |
1200 | dp->index = index; | |
123abc06 | 1201 | dp->bridge_num = -1; |
ab8ccae1 VD |
1202 | |
1203 | INIT_LIST_HEAD(&dp->list); | |
1204 | list_add_tail(&dp->list, &dst->ports); | |
1205 | ||
1206 | return dp; | |
1207 | } | |
1208 | ||
06e24d08 VD |
1209 | static int dsa_port_parse_user(struct dsa_port *dp, const char *name) |
1210 | { | |
1211 | if (!name) | |
1212 | name = "eth%d"; | |
1213 | ||
1214 | dp->type = DSA_PORT_TYPE_USER; | |
1215 | dp->name = name; | |
1216 | ||
1217 | return 0; | |
1218 | } | |
1219 | ||
1220 | static int dsa_port_parse_dsa(struct dsa_port *dp) | |
1221 | { | |
1222 | dp->type = DSA_PORT_TYPE_DSA; | |
1223 | ||
1224 | return 0; | |
1225 | } | |
1226 | ||
4d776482 FF |
1227 | static enum dsa_tag_protocol dsa_get_tag_protocol(struct dsa_port *dp, |
1228 | struct net_device *master) | |
1229 | { | |
1230 | enum dsa_tag_protocol tag_protocol = DSA_TAG_PROTO_NONE; | |
1231 | struct dsa_switch *mds, *ds = dp->ds; | |
1232 | unsigned int mdp_upstream; | |
1233 | struct dsa_port *mdp; | |
1234 | ||
1235 | /* It is possible to stack DSA switches onto one another when that | |
1236 | * happens the switch driver may want to know if its tagging protocol | |
1237 | * is going to work in such a configuration. | |
1238 | */ | |
1239 | if (dsa_slave_dev_check(master)) { | |
1240 | mdp = dsa_slave_to_port(master); | |
1241 | mds = mdp->ds; | |
1242 | mdp_upstream = dsa_upstream_port(mds, mdp->index); | |
1243 | tag_protocol = mds->ops->get_tag_protocol(mds, mdp_upstream, | |
1244 | DSA_TAG_PROTO_NONE); | |
1245 | } | |
1246 | ||
1247 | /* If the master device is not itself a DSA slave in a disjoint DSA | |
1248 | * tree, then return immediately. | |
1249 | */ | |
1250 | return ds->ops->get_tag_protocol(ds, dp->index, tag_protocol); | |
1251 | } | |
1252 | ||
deff7107 TW |
1253 | static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master, |
1254 | const char *user_protocol) | |
06e24d08 | 1255 | { |
7354fcb0 VD |
1256 | struct dsa_switch *ds = dp->ds; |
1257 | struct dsa_switch_tree *dst = ds->dst; | |
e0c755a4 | 1258 | const struct dsa_device_ops *tag_ops; |
deff7107 TW |
1259 | enum dsa_tag_protocol default_proto; |
1260 | ||
1261 | /* Find out which protocol the switch would prefer. */ | |
1262 | default_proto = dsa_get_tag_protocol(dp, master); | |
1263 | if (dst->default_proto) { | |
1264 | if (dst->default_proto != default_proto) { | |
1265 | dev_err(ds->dev, | |
1266 | "A DSA switch tree can have only one tagging protocol\n"); | |
1267 | return -EINVAL; | |
1268 | } | |
1269 | } else { | |
1270 | dst->default_proto = default_proto; | |
1271 | } | |
1272 | ||
1273 | /* See if the user wants to override that preference. */ | |
1274 | if (user_protocol) { | |
1275 | if (!ds->ops->change_tag_protocol) { | |
1276 | dev_err(ds->dev, "Tag protocol cannot be modified\n"); | |
1277 | return -EINVAL; | |
1278 | } | |
1279 | ||
1280 | tag_ops = dsa_find_tagger_by_name(user_protocol); | |
1281 | } else { | |
1282 | tag_ops = dsa_tag_driver_get(default_proto); | |
1283 | } | |
1284 | ||
1285 | if (IS_ERR(tag_ops)) { | |
1286 | if (PTR_ERR(tag_ops) == -ENOPROTOOPT) | |
1287 | return -EPROBE_DEFER; | |
1288 | ||
1289 | dev_warn(ds->dev, "No tagger for this switch\n"); | |
1290 | return PTR_ERR(tag_ops); | |
1291 | } | |
7354fcb0 | 1292 | |
357f203b | 1293 | if (dst->tag_ops) { |
deff7107 | 1294 | if (dst->tag_ops != tag_ops) { |
357f203b VO |
1295 | dev_err(ds->dev, |
1296 | "A DSA switch tree can have only one tagging protocol\n"); | |
deff7107 TW |
1297 | |
1298 | dsa_tag_driver_put(tag_ops); | |
357f203b VO |
1299 | return -EINVAL; |
1300 | } | |
deff7107 | 1301 | |
357f203b | 1302 | /* In the case of multiple CPU ports per switch, the tagging |
deff7107 | 1303 | * protocol is still reference-counted only per switch tree. |
357f203b | 1304 | */ |
deff7107 | 1305 | dsa_tag_driver_put(tag_ops); |
357f203b | 1306 | } else { |
e0c755a4 | 1307 | dst->tag_ops = tag_ops; |
7354fcb0 VD |
1308 | } |
1309 | ||
4d776482 | 1310 | dp->master = master; |
06e24d08 | 1311 | dp->type = DSA_PORT_TYPE_CPU; |
53da0eba | 1312 | dsa_port_set_tag_protocol(dp, dst->tag_ops); |
7354fcb0 | 1313 | dp->dst = dst; |
06e24d08 | 1314 | |
deff7107 TW |
1315 | /* At this point, the tree may be configured to use a different |
1316 | * tagger than the one chosen by the switch driver during | |
1317 | * .setup, in the case when a user selects a custom protocol | |
1318 | * through the DT. | |
1319 | * | |
1320 | * This is resolved by syncing the driver with the tree in | |
1321 | * dsa_switch_setup_tag_protocol once .setup has run and the | |
1322 | * driver is ready to accept calls to .change_tag_protocol. If | |
1323 | * the driver does not support the custom protocol at that | |
1324 | * point, the tree is wholly rejected, thereby ensuring that the | |
1325 | * tree and driver are always in agreement on the protocol to | |
1326 | * use. | |
1327 | */ | |
06e24d08 VD |
1328 | return 0; |
1329 | } | |
1330 | ||
fd223e2e VD |
1331 | static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn) |
1332 | { | |
6d4e5c57 | 1333 | struct device_node *ethernet = of_parse_phandle(dn, "ethernet", 0); |
1838fa89 | 1334 | const char *name = of_get_property(dn, "label", NULL); |
54df6fa9 | 1335 | bool link = of_property_read_bool(dn, "link"); |
6d4e5c57 | 1336 | |
06e24d08 VD |
1337 | dp->dn = dn; |
1338 | ||
6d4e5c57 | 1339 | if (ethernet) { |
cbabb0ac | 1340 | struct net_device *master; |
deff7107 | 1341 | const char *user_protocol; |
cbabb0ac VD |
1342 | |
1343 | master = of_find_net_device_by_node(ethernet); | |
15d413c4 | 1344 | of_node_put(ethernet); |
cbabb0ac VD |
1345 | if (!master) |
1346 | return -EPROBE_DEFER; | |
1347 | ||
deff7107 TW |
1348 | user_protocol = of_get_property(dn, "dsa-tag-protocol", NULL); |
1349 | return dsa_port_parse_cpu(dp, master, user_protocol); | |
6d4e5c57 VD |
1350 | } |
1351 | ||
06e24d08 VD |
1352 | if (link) |
1353 | return dsa_port_parse_dsa(dp); | |
fd223e2e | 1354 | |
06e24d08 | 1355 | return dsa_port_parse_user(dp, name); |
fd223e2e VD |
1356 | } |
1357 | ||
975e6e32 VD |
1358 | static int dsa_switch_parse_ports_of(struct dsa_switch *ds, |
1359 | struct device_node *dn) | |
83c0afae | 1360 | { |
5b32fe07 | 1361 | struct device_node *ports, *port; |
fd223e2e | 1362 | struct dsa_port *dp; |
9919a363 | 1363 | int err = 0; |
83c0afae | 1364 | u32 reg; |
5b32fe07 VD |
1365 | |
1366 | ports = of_get_child_by_name(dn, "ports"); | |
1367 | if (!ports) { | |
85e05d26 KK |
1368 | /* The second possibility is "ethernet-ports" */ |
1369 | ports = of_get_child_by_name(dn, "ethernet-ports"); | |
1370 | if (!ports) { | |
1371 | dev_err(ds->dev, "no ports child node found\n"); | |
1372 | return -EINVAL; | |
1373 | } | |
5b32fe07 | 1374 | } |
83c0afae AL |
1375 | |
1376 | for_each_available_child_of_node(ports, port) { | |
1377 | err = of_property_read_u32(port, "reg", ®); | |
ba69fd91 CJ |
1378 | if (err) { |
1379 | of_node_put(port); | |
9919a363 | 1380 | goto out_put_node; |
ba69fd91 | 1381 | } |
83c0afae | 1382 | |
9919a363 | 1383 | if (reg >= ds->num_ports) { |
8209f5bc RM |
1384 | dev_err(ds->dev, "port %pOF index %u exceeds num_ports (%zu)\n", |
1385 | port, reg, ds->num_ports); | |
ba69fd91 | 1386 | of_node_put(port); |
9919a363 WY |
1387 | err = -EINVAL; |
1388 | goto out_put_node; | |
1389 | } | |
83c0afae | 1390 | |
68bb8ea8 | 1391 | dp = dsa_to_port(ds, reg); |
fd223e2e VD |
1392 | |
1393 | err = dsa_port_parse_of(dp, port); | |
ba69fd91 CJ |
1394 | if (err) { |
1395 | of_node_put(port); | |
9919a363 | 1396 | goto out_put_node; |
ba69fd91 | 1397 | } |
83c0afae AL |
1398 | } |
1399 | ||
9919a363 WY |
1400 | out_put_node: |
1401 | of_node_put(ports); | |
1402 | return err; | |
83c0afae AL |
1403 | } |
1404 | ||
975e6e32 VD |
1405 | static int dsa_switch_parse_member_of(struct dsa_switch *ds, |
1406 | struct device_node *dn) | |
1407 | { | |
1408 | u32 m[2] = { 0, 0 }; | |
1409 | int sz; | |
1410 | ||
1411 | /* Don't error out if this optional property isn't found */ | |
1412 | sz = of_property_read_variable_u32_array(dn, "dsa,member", m, 2, 2); | |
1413 | if (sz < 0 && sz != -EINVAL) | |
1414 | return sz; | |
1415 | ||
1416 | ds->index = m[1]; | |
975e6e32 VD |
1417 | |
1418 | ds->dst = dsa_tree_touch(m[0]); | |
1419 | if (!ds->dst) | |
1420 | return -ENOMEM; | |
1421 | ||
8674f8d3 VO |
1422 | if (dsa_switch_find(ds->dst->index, ds->index)) { |
1423 | dev_err(ds->dev, | |
1424 | "A DSA switch with index %d already exists in tree %d\n", | |
1425 | ds->index, ds->dst->index); | |
1426 | return -EEXIST; | |
1427 | } | |
1428 | ||
5b22d366 VO |
1429 | if (ds->dst->last_switch < ds->index) |
1430 | ds->dst->last_switch = ds->index; | |
1431 | ||
975e6e32 VD |
1432 | return 0; |
1433 | } | |
1434 | ||
ab8ccae1 VD |
1435 | static int dsa_switch_touch_ports(struct dsa_switch *ds) |
1436 | { | |
1437 | struct dsa_port *dp; | |
1438 | int port; | |
1439 | ||
1440 | for (port = 0; port < ds->num_ports; port++) { | |
1441 | dp = dsa_port_touch(ds, port); | |
1442 | if (!dp) | |
1443 | return -ENOMEM; | |
1444 | } | |
1445 | ||
1446 | return 0; | |
1447 | } | |
1448 | ||
975e6e32 VD |
1449 | static int dsa_switch_parse_of(struct dsa_switch *ds, struct device_node *dn) |
1450 | { | |
1451 | int err; | |
1452 | ||
1453 | err = dsa_switch_parse_member_of(ds, dn); | |
1454 | if (err) | |
1455 | return err; | |
1456 | ||
ab8ccae1 VD |
1457 | err = dsa_switch_touch_ports(ds); |
1458 | if (err) | |
1459 | return err; | |
1460 | ||
975e6e32 VD |
1461 | return dsa_switch_parse_ports_of(ds, dn); |
1462 | } | |
1463 | ||
fd223e2e VD |
1464 | static int dsa_port_parse(struct dsa_port *dp, const char *name, |
1465 | struct device *dev) | |
1466 | { | |
6d4e5c57 | 1467 | if (!strcmp(name, "cpu")) { |
cbabb0ac VD |
1468 | struct net_device *master; |
1469 | ||
1470 | master = dsa_dev_to_net_device(dev); | |
1471 | if (!master) | |
1472 | return -EPROBE_DEFER; | |
1473 | ||
1474 | dev_put(master); | |
1475 | ||
deff7107 | 1476 | return dsa_port_parse_cpu(dp, master, NULL); |
6d4e5c57 VD |
1477 | } |
1478 | ||
06e24d08 VD |
1479 | if (!strcmp(name, "dsa")) |
1480 | return dsa_port_parse_dsa(dp); | |
fd223e2e | 1481 | |
06e24d08 | 1482 | return dsa_port_parse_user(dp, name); |
fd223e2e VD |
1483 | } |
1484 | ||
975e6e32 VD |
1485 | static int dsa_switch_parse_ports(struct dsa_switch *ds, |
1486 | struct dsa_chip_data *cd) | |
71e0bbde FF |
1487 | { |
1488 | bool valid_name_found = false; | |
fd223e2e VD |
1489 | struct dsa_port *dp; |
1490 | struct device *dev; | |
1491 | const char *name; | |
71e0bbde | 1492 | unsigned int i; |
fd223e2e | 1493 | int err; |
71e0bbde FF |
1494 | |
1495 | for (i = 0; i < DSA_MAX_PORTS; i++) { | |
fd223e2e VD |
1496 | name = cd->port_names[i]; |
1497 | dev = cd->netdev[i]; | |
68bb8ea8 | 1498 | dp = dsa_to_port(ds, i); |
fd223e2e VD |
1499 | |
1500 | if (!name) | |
71e0bbde FF |
1501 | continue; |
1502 | ||
fd223e2e VD |
1503 | err = dsa_port_parse(dp, name, dev); |
1504 | if (err) | |
1505 | return err; | |
1506 | ||
71e0bbde FF |
1507 | valid_name_found = true; |
1508 | } | |
1509 | ||
1510 | if (!valid_name_found && i == DSA_MAX_PORTS) | |
1511 | return -EINVAL; | |
1512 | ||
1513 | return 0; | |
1514 | } | |
1515 | ||
975e6e32 | 1516 | static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd) |
71e0bbde | 1517 | { |
ab8ccae1 VD |
1518 | int err; |
1519 | ||
975e6e32 | 1520 | ds->cd = cd; |
71e0bbde | 1521 | |
975e6e32 VD |
1522 | /* We don't support interconnected switches nor multiple trees via |
1523 | * platform data, so this is the unique switch of the tree. | |
1524 | */ | |
1525 | ds->index = 0; | |
1526 | ds->dst = dsa_tree_touch(0); | |
1527 | if (!ds->dst) | |
1528 | return -ENOMEM; | |
71e0bbde | 1529 | |
ab8ccae1 VD |
1530 | err = dsa_switch_touch_ports(ds); |
1531 | if (err) | |
1532 | return err; | |
1533 | ||
975e6e32 | 1534 | return dsa_switch_parse_ports(ds, cd); |
71e0bbde FF |
1535 | } |
1536 | ||
6dc43cd3 VO |
1537 | static void dsa_switch_release_ports(struct dsa_switch *ds) |
1538 | { | |
1539 | struct dsa_switch_tree *dst = ds->dst; | |
1540 | struct dsa_port *dp, *next; | |
1541 | ||
1542 | list_for_each_entry_safe(dp, next, &dst->ports, list) { | |
1543 | if (dp->ds != ds) | |
1544 | continue; | |
1545 | list_del(&dp->list); | |
1546 | kfree(dp); | |
1547 | } | |
1548 | } | |
1549 | ||
b4fbb347 | 1550 | static int dsa_switch_probe(struct dsa_switch *ds) |
83c0afae | 1551 | { |
8e5cb84c | 1552 | struct dsa_switch_tree *dst; |
556f124f CIK |
1553 | struct dsa_chip_data *pdata; |
1554 | struct device_node *np; | |
34c09a89 | 1555 | int err; |
83c0afae | 1556 | |
7e99e347 VD |
1557 | if (!ds->dev) |
1558 | return -ENODEV; | |
1559 | ||
556f124f CIK |
1560 | pdata = ds->dev->platform_data; |
1561 | np = ds->dev->of_node; | |
1562 | ||
7e99e347 VD |
1563 | if (!ds->num_ports) |
1564 | return -EINVAL; | |
1565 | ||
6dc43cd3 | 1566 | if (np) { |
975e6e32 | 1567 | err = dsa_switch_parse_of(ds, np); |
6dc43cd3 VO |
1568 | if (err) |
1569 | dsa_switch_release_ports(ds); | |
1570 | } else if (pdata) { | |
975e6e32 | 1571 | err = dsa_switch_parse(ds, pdata); |
6dc43cd3 VO |
1572 | if (err) |
1573 | dsa_switch_release_ports(ds); | |
1574 | } else { | |
975e6e32 | 1575 | err = -ENODEV; |
6dc43cd3 | 1576 | } |
83c0afae | 1577 | |
975e6e32 VD |
1578 | if (err) |
1579 | return err; | |
d390238c | 1580 | |
8e5cb84c VD |
1581 | dst = ds->dst; |
1582 | dsa_tree_get(dst); | |
1583 | err = dsa_tree_setup(dst); | |
6dc43cd3 VO |
1584 | if (err) { |
1585 | dsa_switch_release_ports(ds); | |
8e5cb84c | 1586 | dsa_tree_put(dst); |
6dc43cd3 | 1587 | } |
8e5cb84c VD |
1588 | |
1589 | return err; | |
83c0afae AL |
1590 | } |
1591 | ||
23c9ee49 | 1592 | int dsa_register_switch(struct dsa_switch *ds) |
83c0afae AL |
1593 | { |
1594 | int err; | |
1595 | ||
1596 | mutex_lock(&dsa2_mutex); | |
b4fbb347 | 1597 | err = dsa_switch_probe(ds); |
9e741045 | 1598 | dsa_tree_put(ds->dst); |
83c0afae AL |
1599 | mutex_unlock(&dsa2_mutex); |
1600 | ||
1601 | return err; | |
1602 | } | |
1603 | EXPORT_SYMBOL_GPL(dsa_register_switch); | |
1604 | ||
b4fbb347 | 1605 | static void dsa_switch_remove(struct dsa_switch *ds) |
83c0afae AL |
1606 | { |
1607 | struct dsa_switch_tree *dst = ds->dst; | |
05f294a8 | 1608 | |
c058f6df | 1609 | dsa_tree_teardown(dst); |
6dc43cd3 | 1610 | dsa_switch_release_ports(ds); |
8e5cb84c | 1611 | dsa_tree_put(dst); |
83c0afae AL |
1612 | } |
1613 | ||
1614 | void dsa_unregister_switch(struct dsa_switch *ds) | |
1615 | { | |
1616 | mutex_lock(&dsa2_mutex); | |
b4fbb347 | 1617 | dsa_switch_remove(ds); |
83c0afae AL |
1618 | mutex_unlock(&dsa2_mutex); |
1619 | } | |
1620 | EXPORT_SYMBOL_GPL(dsa_unregister_switch); | |
0650bf52 VO |
1621 | |
1622 | /* If the DSA master chooses to unregister its net_device on .shutdown, DSA is | |
1623 | * blocking that operation from completion, due to the dev_hold taken inside | |
1624 | * netdev_upper_dev_link. Unlink the DSA slave interfaces from being uppers of | |
1625 | * the DSA master, so that the system can reboot successfully. | |
1626 | */ | |
1627 | void dsa_switch_shutdown(struct dsa_switch *ds) | |
1628 | { | |
1629 | struct net_device *master, *slave_dev; | |
1630 | LIST_HEAD(unregister_list); | |
1631 | struct dsa_port *dp; | |
1632 | ||
1633 | mutex_lock(&dsa2_mutex); | |
1d4b4ee6 VO |
1634 | |
1635 | if (!ds->setup) | |
1636 | goto out; | |
1637 | ||
0650bf52 VO |
1638 | rtnl_lock(); |
1639 | ||
1640 | list_for_each_entry(dp, &ds->dst->ports, list) { | |
1641 | if (dp->ds != ds) | |
1642 | continue; | |
1643 | ||
1644 | if (!dsa_port_is_user(dp)) | |
1645 | continue; | |
1646 | ||
1647 | master = dp->cpu_dp->master; | |
1648 | slave_dev = dp->slave; | |
1649 | ||
1650 | netdev_upper_dev_unlink(master, slave_dev); | |
1651 | /* Just unlinking ourselves as uppers of the master is not | |
1652 | * sufficient. When the master net device unregisters, that will | |
1653 | * also call dev_close, which we will catch as NETDEV_GOING_DOWN | |
1654 | * and trigger a dev_close on our own devices (dsa_slave_close). | |
1655 | * In turn, that will call dev_mc_unsync on the master's net | |
1656 | * device. If the master is also a DSA switch port, this will | |
1657 | * trigger dsa_slave_set_rx_mode which will call dev_mc_sync on | |
1658 | * its own master. Lockdep will complain about the fact that | |
1659 | * all cascaded masters have the same dsa_master_addr_list_lock_key, | |
1660 | * which it normally would not do if the cascaded masters would | |
1661 | * be in a proper upper/lower relationship, which we've just | |
1662 | * destroyed. | |
1663 | * To suppress the lockdep warnings, let's actually unregister | |
1664 | * the DSA slave interfaces too, to avoid the nonsensical | |
1665 | * multicast address list synchronization on shutdown. | |
1666 | */ | |
1667 | unregister_netdevice_queue(slave_dev, &unregister_list); | |
1668 | } | |
1669 | unregister_netdevice_many(&unregister_list); | |
1670 | ||
1671 | rtnl_unlock(); | |
1d4b4ee6 | 1672 | out: |
0650bf52 VO |
1673 | mutex_unlock(&dsa2_mutex); |
1674 | } | |
1675 | EXPORT_SYMBOL_GPL(dsa_switch_shutdown); |