blob: 25ed41262ead085af71020625d15ae12ad2f17d1 [file] [log] [blame]
Andrew Lunn83c0afa2016-06-04 21:17:07 +02001/*
2 * net/dsa/dsa2.c - Hardware switch handling, binding version 2
3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 * Copyright (c) 2013 Florian Fainelli <florian@openwrt.org>
5 * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <linux/device.h>
14#include <linux/err.h>
15#include <linux/list.h>
Andrew Lunnc6e970a2017-03-28 23:45:06 +020016#include <linux/netdevice.h>
Andrew Lunn83c0afa2016-06-04 21:17:07 +020017#include <linux/slab.h>
18#include <linux/rtnetlink.h>
Andrew Lunn83c0afa2016-06-04 21:17:07 +020019#include <linux/of.h>
20#include <linux/of_net.h>
Vivien Didelotea5dd342017-05-17 15:46:03 -040021
Andrew Lunn83c0afa2016-06-04 21:17:07 +020022#include "dsa_priv.h"
23
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040024static LIST_HEAD(dsa_tree_list);
Andrew Lunn83c0afa2016-06-04 21:17:07 +020025static DEFINE_MUTEX(dsa2_mutex);
26
Andrew Lunn96567d52017-03-28 23:45:07 +020027static const struct devlink_ops dsa_devlink_ops = {
28};
29
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040030static struct dsa_switch_tree *dsa_tree_find(int index)
Andrew Lunn83c0afa2016-06-04 21:17:07 +020031{
32 struct dsa_switch_tree *dst;
33
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040034 list_for_each_entry(dst, &dsa_tree_list, list)
Vivien Didelot8e5bf972017-11-03 19:05:22 -040035 if (dst->index == index)
Andrew Lunn83c0afa2016-06-04 21:17:07 +020036 return dst;
Vivien Didelot8e5bf972017-11-03 19:05:22 -040037
Andrew Lunn83c0afa2016-06-04 21:17:07 +020038 return NULL;
39}
40
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040041static struct dsa_switch_tree *dsa_tree_alloc(int index)
Andrew Lunn83c0afa2016-06-04 21:17:07 +020042{
43 struct dsa_switch_tree *dst;
44
45 dst = kzalloc(sizeof(*dst), GFP_KERNEL);
46 if (!dst)
47 return NULL;
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040048
Vivien Didelot49463b72017-11-03 19:05:21 -040049 dst->index = index;
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040050
Andrew Lunn83c0afa2016-06-04 21:17:07 +020051 INIT_LIST_HEAD(&dst->list);
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040052 list_add_tail(&dsa_tree_list, &dst->list);
Vivien Didelot8e5bf972017-11-03 19:05:22 -040053
54 /* Initialize the reference counter to the number of switches, not 1 */
Andrew Lunn83c0afa2016-06-04 21:17:07 +020055 kref_init(&dst->refcount);
Vivien Didelot8e5bf972017-11-03 19:05:22 -040056 refcount_set(&dst->refcount.refcount, 0);
Andrew Lunn83c0afa2016-06-04 21:17:07 +020057
58 return dst;
59}
60
Vivien Didelot65254102017-11-03 19:05:23 -040061static void dsa_tree_free(struct dsa_switch_tree *dst)
62{
63 list_del(&dst->list);
64 kfree(dst);
65}
66
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040067static struct dsa_switch_tree *dsa_tree_touch(int index)
68{
69 struct dsa_switch_tree *dst;
70
71 dst = dsa_tree_find(index);
72 if (!dst)
73 dst = dsa_tree_alloc(index);
74
75 return dst;
76}
77
Vivien Didelot65254102017-11-03 19:05:23 -040078static void dsa_tree_get(struct dsa_switch_tree *dst)
79{
80 kref_get(&dst->refcount);
81}
82
83static void dsa_tree_release(struct kref *ref)
84{
85 struct dsa_switch_tree *dst;
86
87 dst = container_of(ref, struct dsa_switch_tree, refcount);
88
89 dsa_tree_free(dst);
90}
91
92static void dsa_tree_put(struct dsa_switch_tree *dst)
93{
94 kref_put(&dst->refcount, dsa_tree_release);
95}
96
Florian Fainelli71e0bbd2017-02-04 13:02:43 -080097/* For platform data configurations, we need to have a valid name argument to
98 * differentiate a disabled port from an enabled one
99 */
Florian Fainelli293784a2017-01-26 10:45:52 -0800100static bool dsa_port_is_valid(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200101{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400102 return port->type != DSA_PORT_TYPE_UNUSED;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200103}
104
Florian Fainelli293784a2017-01-26 10:45:52 -0800105static bool dsa_port_is_dsa(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200106{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400107 return port->type == DSA_PORT_TYPE_DSA;
Florian Fainelli293784a2017-01-26 10:45:52 -0800108}
109
110static bool dsa_port_is_cpu(struct dsa_port *port)
111{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400112 return port->type == DSA_PORT_TYPE_CPU;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200113}
114
Vivien Didelotf0704642017-11-06 16:11:44 -0500115static bool dsa_port_is_user(struct dsa_port *dp)
116{
117 return dp->type == DSA_PORT_TYPE_USER;
118}
119
Vivien Didelotf163da82017-11-06 16:11:49 -0500120static struct dsa_port *dsa_tree_find_port_by_node(struct dsa_switch_tree *dst,
121 struct device_node *dn)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200122{
123 struct dsa_switch *ds;
Vivien Didelotf163da82017-11-06 16:11:49 -0500124 struct dsa_port *dp;
125 int device, port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200126
Vivien Didelotf163da82017-11-06 16:11:49 -0500127 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
128 ds = dst->ds[device];
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200129 if (!ds)
130 continue;
131
Vivien Didelotf163da82017-11-06 16:11:49 -0500132 for (port = 0; port < ds->num_ports; port++) {
133 dp = &ds->ports[port];
134
135 if (dp->dn == dn)
136 return dp;
137 }
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200138 }
139
140 return NULL;
141}
142
143static int dsa_port_complete(struct dsa_switch_tree *dst,
144 struct dsa_switch *src_ds,
Florian Fainelli293784a2017-01-26 10:45:52 -0800145 struct dsa_port *port,
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200146 u32 src_port)
147{
Vivien Didelotc5286662017-11-06 16:11:50 -0500148 struct device_node *dn = port->dn;
149 struct of_phandle_iterator it;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200150 struct dsa_switch *dst_ds;
Vivien Didelotf163da82017-11-06 16:11:49 -0500151 struct dsa_port *link_dp;
Vivien Didelotc5286662017-11-06 16:11:50 -0500152 int err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200153
Vivien Didelotc5286662017-11-06 16:11:50 -0500154 of_for_each_phandle(&it, err, dn, "link", NULL, 0) {
155 link_dp = dsa_tree_find_port_by_node(dst, it.node);
156 if (!link_dp) {
157 of_node_put(it.node);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200158 return 1;
Vivien Didelotc5286662017-11-06 16:11:50 -0500159 }
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200160
Vivien Didelotf163da82017-11-06 16:11:49 -0500161 dst_ds = link_dp->ds;
162
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200163 src_ds->rtable[dst_ds->index] = src_port;
164 }
165
166 return 0;
167}
168
169/* A switch is complete if all the DSA ports phandles point to ports
170 * known in the tree. A return value of 1 means the tree is not
171 * complete. This is not an error condition. A value of 0 is
172 * success.
173 */
174static int dsa_ds_complete(struct dsa_switch_tree *dst, struct dsa_switch *ds)
175{
Florian Fainelli293784a2017-01-26 10:45:52 -0800176 struct dsa_port *port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200177 u32 index;
178 int err;
179
Vivien Didelot26895e22017-01-27 15:29:37 -0500180 for (index = 0; index < ds->num_ports; index++) {
Florian Fainelli293784a2017-01-26 10:45:52 -0800181 port = &ds->ports[index];
182 if (!dsa_port_is_valid(port))
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200183 continue;
184
185 if (!dsa_port_is_dsa(port))
186 continue;
187
188 err = dsa_port_complete(dst, ds, port, index);
189 if (err != 0)
190 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200191 }
192
193 return 0;
194}
195
196/* A tree is complete if all the DSA ports phandles point to ports
197 * known in the tree. A return value of 1 means the tree is not
198 * complete. This is not an error condition. A value of 0 is
199 * success.
200 */
201static int dsa_dst_complete(struct dsa_switch_tree *dst)
202{
203 struct dsa_switch *ds;
204 u32 index;
205 int err;
206
207 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
208 ds = dst->ds[index];
209 if (!ds)
210 continue;
211
212 err = dsa_ds_complete(dst, ds);
213 if (err != 0)
214 return err;
215 }
216
217 return 0;
218}
219
Vivien Didelotf0704642017-11-06 16:11:44 -0500220static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst)
221{
222 struct dsa_switch *ds;
223 struct dsa_port *dp;
224 int device, port;
225
226 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
227 ds = dst->ds[device];
228 if (!ds)
229 continue;
230
231 for (port = 0; port < ds->num_ports; port++) {
232 dp = &ds->ports[port];
233
234 if (dsa_port_is_cpu(dp))
235 return dp;
236 }
237 }
238
239 return NULL;
240}
241
242static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst)
243{
244 struct dsa_switch *ds;
245 struct dsa_port *dp;
246 int device, port;
247
248 /* DSA currently only supports a single CPU port */
249 dst->cpu_dp = dsa_tree_find_first_cpu(dst);
250 if (!dst->cpu_dp) {
251 pr_warn("Tree has no master device\n");
252 return -EINVAL;
253 }
254
255 /* Assign the default CPU port to all ports of the fabric */
256 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
257 ds = dst->ds[device];
258 if (!ds)
259 continue;
260
261 for (port = 0; port < ds->num_ports; port++) {
262 dp = &ds->ports[port];
263
264 if (dsa_port_is_user(dp))
265 dp->cpu_dp = dst->cpu_dp;
266 }
267 }
268
269 return 0;
270}
271
272static void dsa_tree_teardown_default_cpu(struct dsa_switch_tree *dst)
273{
274 /* DSA currently only supports a single CPU port */
275 dst->cpu_dp = NULL;
276}
277
Vivien Didelot1d277322017-11-06 16:11:48 -0500278static int dsa_port_setup(struct dsa_port *dp)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200279{
Vivien Didelot1d277322017-11-06 16:11:48 -0500280 struct dsa_switch *ds = dp->ds;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200281 int err;
282
Vivien Didelot1d277322017-11-06 16:11:48 -0500283 memset(&dp->devlink_port, 0, sizeof(dp->devlink_port));
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200284
Vivien Didelot1d277322017-11-06 16:11:48 -0500285 err = devlink_port_register(ds->devlink, &dp->devlink_port, dp->index);
Andrew Lunn96567d52017-03-28 23:45:07 +0200286 if (err)
287 return err;
288
Vivien Didelot1d277322017-11-06 16:11:48 -0500289 switch (dp->type) {
290 case DSA_PORT_TYPE_UNUSED:
291 break;
292 case DSA_PORT_TYPE_CPU:
293 case DSA_PORT_TYPE_DSA:
294 err = dsa_port_fixed_link_register_of(dp);
295 if (err) {
296 dev_err(ds->dev, "failed to register fixed link for port %d.%d\n",
297 ds->index, dp->index);
298 return err;
299 }
300
301 break;
302 case DSA_PORT_TYPE_USER:
303 err = dsa_slave_create(dp);
304 if (err)
305 dev_err(ds->dev, "failed to create slave for port %d.%d\n",
306 ds->index, dp->index);
307 else
308 devlink_port_type_eth_set(&dp->devlink_port, dp->slave);
309 break;
310 }
Andrew Lunn96567d52017-03-28 23:45:07 +0200311
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200312 return 0;
313}
314
Vivien Didelot1d277322017-11-06 16:11:48 -0500315static void dsa_port_teardown(struct dsa_port *dp)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200316{
Vivien Didelot1d277322017-11-06 16:11:48 -0500317 devlink_port_unregister(&dp->devlink_port);
318
319 switch (dp->type) {
320 case DSA_PORT_TYPE_UNUSED:
321 break;
322 case DSA_PORT_TYPE_CPU:
323 case DSA_PORT_TYPE_DSA:
324 dsa_port_fixed_link_unregister_of(dp);
325 break;
326 case DSA_PORT_TYPE_USER:
327 if (dp->slave) {
328 dsa_slave_destroy(dp->slave);
329 dp->slave = NULL;
330 }
331 break;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200332 }
333}
334
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500335static int dsa_switch_setup(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200336{
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200337 int err;
338
Florian Fainelli6e830d82016-06-07 16:32:39 -0700339 /* Initialize ds->phys_mii_mask before registering the slave MDIO bus
Vivien Didelot9d490b42016-08-23 12:38:56 -0400340 * driver and before ops->setup() has run, since the switch drivers and
Florian Fainelli6e830d82016-06-07 16:32:39 -0700341 * the slave MDIO bus driver rely on these values for probing PHY
342 * devices or not
343 */
Vivien Didelot02bc6e52017-10-26 11:22:56 -0400344 ds->phys_mii_mask |= dsa_user_ports(ds);
Florian Fainelli6e830d82016-06-07 16:32:39 -0700345
Andrew Lunn96567d52017-03-28 23:45:07 +0200346 /* Add the switch to devlink before calling setup, so that setup can
347 * add dpipe tables
348 */
349 ds->devlink = devlink_alloc(&dsa_devlink_ops, 0);
350 if (!ds->devlink)
351 return -ENOMEM;
352
353 err = devlink_register(ds->devlink, ds->dev);
354 if (err)
355 return err;
356
Vivien Didelot9d490b42016-08-23 12:38:56 -0400357 err = ds->ops->setup(ds);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200358 if (err < 0)
359 return err;
360
Vivien Didelotf515f192017-02-03 13:20:20 -0500361 err = dsa_switch_register_notifier(ds);
362 if (err)
363 return err;
364
Vivien Didelot9d490b42016-08-23 12:38:56 -0400365 if (!ds->slave_mii_bus && ds->ops->phy_read) {
Florian Fainelli1eb59442016-06-07 16:32:40 -0700366 ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
367 if (!ds->slave_mii_bus)
368 return -ENOMEM;
369
370 dsa_slave_mii_bus_init(ds);
371
372 err = mdiobus_register(ds->slave_mii_bus);
373 if (err < 0)
374 return err;
375 }
376
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200377 return 0;
378}
379
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500380static void dsa_switch_teardown(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200381{
Vivien Didelot9d490b42016-08-23 12:38:56 -0400382 if (ds->slave_mii_bus && ds->ops->phy_read)
Florian Fainelli1eb59442016-06-07 16:32:40 -0700383 mdiobus_unregister(ds->slave_mii_bus);
Vivien Didelotf515f192017-02-03 13:20:20 -0500384
385 dsa_switch_unregister_notifier(ds);
Andrew Lunn96567d52017-03-28 23:45:07 +0200386
387 if (ds->devlink) {
388 devlink_unregister(ds->devlink);
389 devlink_free(ds->devlink);
390 ds->devlink = NULL;
391 }
392
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200393}
394
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500395static int dsa_tree_setup_switches(struct dsa_switch_tree *dst)
396{
397 struct dsa_switch *ds;
Vivien Didelot1d277322017-11-06 16:11:48 -0500398 struct dsa_port *dp;
399 int device, port;
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500400 int err;
401
402 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
403 ds = dst->ds[device];
404 if (!ds)
405 continue;
406
407 err = dsa_switch_setup(ds);
408 if (err)
409 return err;
Vivien Didelot1d277322017-11-06 16:11:48 -0500410
411 for (port = 0; port < ds->num_ports; port++) {
412 dp = &ds->ports[port];
413
414 err = dsa_port_setup(dp);
415 if (err)
416 return err;
417 }
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500418 }
419
420 return 0;
421}
422
423static void dsa_tree_teardown_switches(struct dsa_switch_tree *dst)
424{
425 struct dsa_switch *ds;
Vivien Didelot1d277322017-11-06 16:11:48 -0500426 struct dsa_port *dp;
427 int device, port;
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500428
429 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
430 ds = dst->ds[device];
431 if (!ds)
432 continue;
433
Vivien Didelot1d277322017-11-06 16:11:48 -0500434 for (port = 0; port < ds->num_ports; port++) {
435 dp = &ds->ports[port];
436
437 dsa_port_teardown(dp);
438 }
439
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500440 dsa_switch_teardown(ds);
441 }
442}
443
Vivien Didelot17a22fc2017-11-06 16:11:45 -0500444static int dsa_tree_setup_master(struct dsa_switch_tree *dst)
445{
446 struct dsa_port *cpu_dp = dst->cpu_dp;
447 struct net_device *master = cpu_dp->master;
448
449 /* DSA currently supports a single pair of CPU port and master device */
450 return dsa_master_setup(master, cpu_dp);
451}
452
453static void dsa_tree_teardown_master(struct dsa_switch_tree *dst)
454{
455 struct dsa_port *cpu_dp = dst->cpu_dp;
456 struct net_device *master = cpu_dp->master;
457
458 return dsa_master_teardown(master);
459}
460
Vivien Didelotec15dd42017-11-06 16:11:46 -0500461static int dsa_tree_setup(struct dsa_switch_tree *dst)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200462{
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200463 int err;
464
Vivien Didelotec15dd42017-11-06 16:11:46 -0500465 if (dst->setup) {
466 pr_err("DSA: tree %d already setup! Disjoint trees?\n",
467 dst->index);
468 return -EEXIST;
469 }
470
Vivien Didelotf0704642017-11-06 16:11:44 -0500471 err = dsa_tree_setup_default_cpu(dst);
472 if (err)
473 return err;
474
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500475 err = dsa_tree_setup_switches(dst);
476 if (err)
477 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200478
Vivien Didelot17a22fc2017-11-06 16:11:45 -0500479 err = dsa_tree_setup_master(dst);
Vivien Didelot19435632017-09-19 11:56:59 -0400480 if (err)
481 return err;
482
Vivien Didelotec15dd42017-11-06 16:11:46 -0500483 dst->setup = true;
484
485 pr_info("DSA: tree %d setup\n", dst->index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200486
487 return 0;
488}
489
Vivien Didelotec15dd42017-11-06 16:11:46 -0500490static void dsa_tree_teardown(struct dsa_switch_tree *dst)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200491{
Vivien Didelotec15dd42017-11-06 16:11:46 -0500492 if (!dst->setup)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200493 return;
494
Vivien Didelot17a22fc2017-11-06 16:11:45 -0500495 dsa_tree_teardown_master(dst);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200496
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500497 dsa_tree_teardown_switches(dst);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200498
Vivien Didelotf0704642017-11-06 16:11:44 -0500499 dsa_tree_teardown_default_cpu(dst);
Florian Fainelli0c73c522016-06-07 16:32:42 -0700500
Vivien Didelotec15dd42017-11-06 16:11:46 -0500501 pr_info("DSA: tree %d torn down\n", dst->index);
502
503 dst->setup = false;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200504}
505
Vivien Didelot6da2a942017-11-03 19:05:25 -0400506static void dsa_tree_remove_switch(struct dsa_switch_tree *dst,
507 unsigned int index)
508{
509 dst->ds[index] = NULL;
510 dsa_tree_put(dst);
511}
512
513static int dsa_tree_add_switch(struct dsa_switch_tree *dst,
514 struct dsa_switch *ds)
515{
516 unsigned int index = ds->index;
517
518 if (dst->ds[index])
519 return -EBUSY;
520
521 dsa_tree_get(dst);
522 dst->ds[index] = ds;
523
524 return 0;
525}
526
Vivien Didelot06e24d02017-11-03 19:05:29 -0400527static int dsa_port_parse_user(struct dsa_port *dp, const char *name)
528{
529 if (!name)
530 name = "eth%d";
531
532 dp->type = DSA_PORT_TYPE_USER;
533 dp->name = name;
534
535 return 0;
536}
537
538static int dsa_port_parse_dsa(struct dsa_port *dp)
539{
540 dp->type = DSA_PORT_TYPE_DSA;
541
542 return 0;
543}
544
545static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master)
546{
Vivien Didelot7354fcb2017-11-03 19:05:30 -0400547 struct dsa_switch *ds = dp->ds;
548 struct dsa_switch_tree *dst = ds->dst;
Vivien Didelot62fc9582017-09-29 17:19:17 -0400549 const struct dsa_device_ops *tag_ops;
Andrew Lunn7b314362016-08-22 16:01:01 +0200550 enum dsa_tag_protocol tag_protocol;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200551
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700552 tag_protocol = ds->ops->get_tag_protocol(ds);
Vivien Didelot62fc9582017-09-29 17:19:17 -0400553 tag_ops = dsa_resolve_tag_protocol(tag_protocol);
554 if (IS_ERR(tag_ops)) {
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700555 dev_warn(ds->dev, "No tagger for this switch\n");
Vivien Didelot62fc9582017-09-29 17:19:17 -0400556 return PTR_ERR(tag_ops);
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700557 }
558
Vivien Didelot7354fcb2017-11-03 19:05:30 -0400559 dp->type = DSA_PORT_TYPE_CPU;
560 dp->rcv = tag_ops->rcv;
561 dp->tag_ops = tag_ops;
562 dp->master = master;
563 dp->dst = dst;
Vivien Didelot3e41f932017-09-29 17:19:19 -0400564
Vivien Didelot7354fcb2017-11-03 19:05:30 -0400565 return 0;
566}
567
Vivien Didelotfd223e22017-10-27 15:55:14 -0400568static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn)
569{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400570 struct device_node *ethernet = of_parse_phandle(dn, "ethernet", 0);
Vivien Didelot1838fa82017-10-27 15:55:18 -0400571 const char *name = of_get_property(dn, "label", NULL);
Vivien Didelot54df6fa2017-11-03 19:05:28 -0400572 bool link = of_property_read_bool(dn, "link");
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400573
Vivien Didelot06e24d02017-11-03 19:05:29 -0400574 dp->dn = dn;
575
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400576 if (ethernet) {
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400577 struct net_device *master;
578
579 master = of_find_net_device_by_node(ethernet);
580 if (!master)
581 return -EPROBE_DEFER;
582
Vivien Didelot06e24d02017-11-03 19:05:29 -0400583 return dsa_port_parse_cpu(dp, master);
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400584 }
585
Vivien Didelot06e24d02017-11-03 19:05:29 -0400586 if (link)
587 return dsa_port_parse_dsa(dp);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400588
Vivien Didelot06e24d02017-11-03 19:05:29 -0400589 return dsa_port_parse_user(dp, name);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400590}
591
Vivien Didelot975e6e32017-11-03 19:05:27 -0400592static int dsa_switch_parse_ports_of(struct dsa_switch *ds,
593 struct device_node *dn)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200594{
Vivien Didelot5b32fe02017-10-27 15:55:13 -0400595 struct device_node *ports, *port;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400596 struct dsa_port *dp;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200597 u32 reg;
Vivien Didelot5b32fe02017-10-27 15:55:13 -0400598 int err;
599
600 ports = of_get_child_by_name(dn, "ports");
601 if (!ports) {
602 dev_err(ds->dev, "no ports child node found\n");
603 return -EINVAL;
604 }
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200605
606 for_each_available_child_of_node(ports, port) {
607 err = of_property_read_u32(port, "reg", &reg);
608 if (err)
609 return err;
610
Vivien Didelot26895e22017-01-27 15:29:37 -0500611 if (reg >= ds->num_ports)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200612 return -EINVAL;
613
Vivien Didelotfd223e22017-10-27 15:55:14 -0400614 dp = &ds->ports[reg];
615
616 err = dsa_port_parse_of(dp, port);
617 if (err)
618 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200619 }
620
621 return 0;
622}
623
Vivien Didelot975e6e32017-11-03 19:05:27 -0400624static int dsa_switch_parse_member_of(struct dsa_switch *ds,
625 struct device_node *dn)
626{
627 u32 m[2] = { 0, 0 };
628 int sz;
629
630 /* Don't error out if this optional property isn't found */
631 sz = of_property_read_variable_u32_array(dn, "dsa,member", m, 2, 2);
632 if (sz < 0 && sz != -EINVAL)
633 return sz;
634
635 ds->index = m[1];
636 if (ds->index >= DSA_MAX_SWITCHES)
637 return -EINVAL;
638
639 ds->dst = dsa_tree_touch(m[0]);
640 if (!ds->dst)
641 return -ENOMEM;
642
643 return 0;
644}
645
646static int dsa_switch_parse_of(struct dsa_switch *ds, struct device_node *dn)
647{
648 int err;
649
650 err = dsa_switch_parse_member_of(ds, dn);
651 if (err)
652 return err;
653
654 return dsa_switch_parse_ports_of(ds, dn);
655}
656
Vivien Didelotfd223e22017-10-27 15:55:14 -0400657static int dsa_port_parse(struct dsa_port *dp, const char *name,
658 struct device *dev)
659{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400660 if (!strcmp(name, "cpu")) {
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400661 struct net_device *master;
662
663 master = dsa_dev_to_net_device(dev);
664 if (!master)
665 return -EPROBE_DEFER;
666
667 dev_put(master);
668
Vivien Didelot06e24d02017-11-03 19:05:29 -0400669 return dsa_port_parse_cpu(dp, master);
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400670 }
671
Vivien Didelot06e24d02017-11-03 19:05:29 -0400672 if (!strcmp(name, "dsa"))
673 return dsa_port_parse_dsa(dp);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400674
Vivien Didelot06e24d02017-11-03 19:05:29 -0400675 return dsa_port_parse_user(dp, name);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400676}
677
Vivien Didelot975e6e32017-11-03 19:05:27 -0400678static int dsa_switch_parse_ports(struct dsa_switch *ds,
679 struct dsa_chip_data *cd)
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800680{
681 bool valid_name_found = false;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400682 struct dsa_port *dp;
683 struct device *dev;
684 const char *name;
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800685 unsigned int i;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400686 int err;
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800687
688 for (i = 0; i < DSA_MAX_PORTS; i++) {
Vivien Didelotfd223e22017-10-27 15:55:14 -0400689 name = cd->port_names[i];
690 dev = cd->netdev[i];
691 dp = &ds->ports[i];
692
693 if (!name)
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800694 continue;
695
Vivien Didelotfd223e22017-10-27 15:55:14 -0400696 err = dsa_port_parse(dp, name, dev);
697 if (err)
698 return err;
699
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800700 valid_name_found = true;
701 }
702
703 if (!valid_name_found && i == DSA_MAX_PORTS)
704 return -EINVAL;
705
706 return 0;
707}
708
Vivien Didelot975e6e32017-11-03 19:05:27 -0400709static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200710{
Vivien Didelot975e6e32017-11-03 19:05:27 -0400711 ds->cd = cd;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200712
Vivien Didelot975e6e32017-11-03 19:05:27 -0400713 /* We don't support interconnected switches nor multiple trees via
714 * platform data, so this is the unique switch of the tree.
715 */
716 ds->index = 0;
717 ds->dst = dsa_tree_touch(0);
718 if (!ds->dst)
719 return -ENOMEM;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200720
Vivien Didelot975e6e32017-11-03 19:05:27 -0400721 return dsa_switch_parse_ports(ds, cd);
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800722}
723
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400724static int _dsa_register_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200725{
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400726 struct dsa_chip_data *pdata = ds->dev->platform_data;
727 struct device_node *np = ds->dev->of_node;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200728 struct dsa_switch_tree *dst;
Vivien Didelot975e6e32017-11-03 19:05:27 -0400729 unsigned int index;
Vivien Didelotd3902382016-07-06 20:03:54 -0400730 int i, err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200731
Vivien Didelot975e6e32017-11-03 19:05:27 -0400732 if (np)
733 err = dsa_switch_parse_of(ds, np);
734 else if (pdata)
735 err = dsa_switch_parse(ds, pdata);
736 else
737 err = -ENODEV;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200738
Vivien Didelot975e6e32017-11-03 19:05:27 -0400739 if (err)
740 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200741
Vivien Didelot975e6e32017-11-03 19:05:27 -0400742 index = ds->index;
743 dst = ds->dst;
Vivien Didelot0eefe2c2017-11-03 19:05:26 -0400744
Vivien Didelotd3902382016-07-06 20:03:54 -0400745 /* Initialize the routing table */
746 for (i = 0; i < DSA_MAX_SWITCHES; ++i)
747 ds->rtable[i] = DSA_RTABLE_NONE;
748
Vivien Didelot6da2a942017-11-03 19:05:25 -0400749 err = dsa_tree_add_switch(dst, ds);
750 if (err)
751 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200752
753 err = dsa_dst_complete(dst);
754 if (err < 0)
755 goto out_del_dst;
756
Vivien Didelot8e5bf972017-11-03 19:05:22 -0400757 /* Not all switches registered yet */
758 if (err == 1)
759 return 0;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200760
Vivien Didelotec15dd42017-11-06 16:11:46 -0500761 err = dsa_tree_setup(dst);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200762 if (err) {
Vivien Didelotec15dd42017-11-06 16:11:46 -0500763 dsa_tree_teardown(dst);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200764 goto out_del_dst;
765 }
766
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200767 return 0;
768
769out_del_dst:
Vivien Didelot6da2a942017-11-03 19:05:25 -0400770 dsa_tree_remove_switch(dst, index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200771
772 return err;
773}
774
Vivien Didelota0c02162017-01-27 15:29:36 -0500775struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n)
776{
777 size_t size = sizeof(struct dsa_switch) + n * sizeof(struct dsa_port);
778 struct dsa_switch *ds;
Vivien Didelot818be842017-01-27 15:29:38 -0500779 int i;
Vivien Didelota0c02162017-01-27 15:29:36 -0500780
781 ds = devm_kzalloc(dev, size, GFP_KERNEL);
782 if (!ds)
783 return NULL;
784
785 ds->dev = dev;
786 ds->num_ports = n;
787
Vivien Didelot818be842017-01-27 15:29:38 -0500788 for (i = 0; i < ds->num_ports; ++i) {
789 ds->ports[i].index = i;
790 ds->ports[i].ds = ds;
791 }
792
Vivien Didelota0c02162017-01-27 15:29:36 -0500793 return ds;
794}
795EXPORT_SYMBOL_GPL(dsa_switch_alloc);
796
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400797int dsa_register_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200798{
799 int err;
800
801 mutex_lock(&dsa2_mutex);
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400802 err = _dsa_register_switch(ds);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200803 mutex_unlock(&dsa2_mutex);
804
805 return err;
806}
807EXPORT_SYMBOL_GPL(dsa_register_switch);
808
Wei Yongjun85c22ba2016-07-12 15:24:10 +0000809static void _dsa_unregister_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200810{
811 struct dsa_switch_tree *dst = ds->dst;
Vivien Didelot6da2a942017-11-03 19:05:25 -0400812 unsigned int index = ds->index;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200813
Vivien Didelotec15dd42017-11-06 16:11:46 -0500814 dsa_tree_teardown(dst);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200815
Vivien Didelot6da2a942017-11-03 19:05:25 -0400816 dsa_tree_remove_switch(dst, index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200817}
818
819void dsa_unregister_switch(struct dsa_switch *ds)
820{
821 mutex_lock(&dsa2_mutex);
822 _dsa_unregister_switch(ds);
823 mutex_unlock(&dsa2_mutex);
824}
825EXPORT_SYMBOL_GPL(dsa_unregister_switch);