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