blob: f1ad808516168cae980fe42f926649742cf3c991 [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>
Jiri Pirko402f99e52019-03-24 11:14:26 +010021#include <net/devlink.h>
Vivien Didelotea5dd342017-05-17 15:46:03 -040022
Andrew Lunn83c0afa2016-06-04 21:17:07 +020023#include "dsa_priv.h"
24
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040025static LIST_HEAD(dsa_tree_list);
Andrew Lunn83c0afa2016-06-04 21:17:07 +020026static DEFINE_MUTEX(dsa2_mutex);
27
Andrew Lunn96567d52017-03-28 23:45:07 +020028static const struct devlink_ops dsa_devlink_ops = {
29};
30
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040031static struct dsa_switch_tree *dsa_tree_find(int index)
Andrew Lunn83c0afa2016-06-04 21:17:07 +020032{
33 struct dsa_switch_tree *dst;
34
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040035 list_for_each_entry(dst, &dsa_tree_list, list)
Vivien Didelot8e5bf972017-11-03 19:05:22 -040036 if (dst->index == index)
Andrew Lunn83c0afa2016-06-04 21:17:07 +020037 return dst;
Vivien Didelot8e5bf972017-11-03 19:05:22 -040038
Andrew Lunn83c0afa2016-06-04 21:17:07 +020039 return NULL;
40}
41
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040042static struct dsa_switch_tree *dsa_tree_alloc(int index)
Andrew Lunn83c0afa2016-06-04 21:17:07 +020043{
44 struct dsa_switch_tree *dst;
45
46 dst = kzalloc(sizeof(*dst), GFP_KERNEL);
47 if (!dst)
48 return NULL;
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040049
Vivien Didelot49463b72017-11-03 19:05:21 -040050 dst->index = index;
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040051
Andrew Lunn83c0afa2016-06-04 21:17:07 +020052 INIT_LIST_HEAD(&dst->list);
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040053 list_add_tail(&dsa_tree_list, &dst->list);
Vivien Didelot8e5bf972017-11-03 19:05:22 -040054
Andrew Lunn83c0afa2016-06-04 21:17:07 +020055 kref_init(&dst->refcount);
56
57 return dst;
58}
59
Vivien Didelot65254102017-11-03 19:05:23 -040060static void dsa_tree_free(struct dsa_switch_tree *dst)
61{
62 list_del(&dst->list);
63 kfree(dst);
64}
65
Vivien Didelot9e741042017-11-24 11:36:06 -050066static struct dsa_switch_tree *dsa_tree_get(struct dsa_switch_tree *dst)
67{
68 if (dst)
69 kref_get(&dst->refcount);
70
71 return dst;
72}
73
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040074static struct dsa_switch_tree *dsa_tree_touch(int index)
75{
76 struct dsa_switch_tree *dst;
77
78 dst = dsa_tree_find(index);
Vivien Didelot9e741042017-11-24 11:36:06 -050079 if (dst)
80 return dsa_tree_get(dst);
81 else
82 return dsa_tree_alloc(index);
Vivien Didelot65254102017-11-03 19:05:23 -040083}
84
85static void dsa_tree_release(struct kref *ref)
86{
87 struct dsa_switch_tree *dst;
88
89 dst = container_of(ref, struct dsa_switch_tree, refcount);
90
91 dsa_tree_free(dst);
92}
93
94static void dsa_tree_put(struct dsa_switch_tree *dst)
95{
Vivien Didelot9e741042017-11-24 11:36:06 -050096 if (dst)
97 kref_put(&dst->refcount, dsa_tree_release);
Vivien Didelot65254102017-11-03 19:05:23 -040098}
99
Florian Fainelli293784a2017-01-26 10:45:52 -0800100static bool dsa_port_is_dsa(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_DSA;
Florian Fainelli293784a2017-01-26 10:45:52 -0800103}
104
105static bool dsa_port_is_cpu(struct dsa_port *port)
106{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400107 return port->type == DSA_PORT_TYPE_CPU;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200108}
109
Vivien Didelotf0704642017-11-06 16:11:44 -0500110static bool dsa_port_is_user(struct dsa_port *dp)
111{
112 return dp->type == DSA_PORT_TYPE_USER;
113}
114
Vivien Didelotf163da82017-11-06 16:11:49 -0500115static struct dsa_port *dsa_tree_find_port_by_node(struct dsa_switch_tree *dst,
116 struct device_node *dn)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200117{
118 struct dsa_switch *ds;
Vivien Didelotf163da82017-11-06 16:11:49 -0500119 struct dsa_port *dp;
120 int device, port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200121
Vivien Didelotf163da82017-11-06 16:11:49 -0500122 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
123 ds = dst->ds[device];
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200124 if (!ds)
125 continue;
126
Vivien Didelotf163da82017-11-06 16:11:49 -0500127 for (port = 0; port < ds->num_ports; port++) {
128 dp = &ds->ports[port];
129
130 if (dp->dn == dn)
131 return dp;
132 }
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200133 }
134
135 return NULL;
136}
137
Vivien Didelot34c09a82017-11-06 16:11:51 -0500138static bool dsa_port_setup_routing_table(struct dsa_port *dp)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200139{
Vivien Didelot34c09a82017-11-06 16:11:51 -0500140 struct dsa_switch *ds = dp->ds;
141 struct dsa_switch_tree *dst = ds->dst;
142 struct device_node *dn = dp->dn;
Vivien Didelotc5286662017-11-06 16:11:50 -0500143 struct of_phandle_iterator it;
Vivien Didelotf163da82017-11-06 16:11:49 -0500144 struct dsa_port *link_dp;
Vivien Didelotc5286662017-11-06 16:11:50 -0500145 int err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200146
Vivien Didelotc5286662017-11-06 16:11:50 -0500147 of_for_each_phandle(&it, err, dn, "link", NULL, 0) {
148 link_dp = dsa_tree_find_port_by_node(dst, it.node);
149 if (!link_dp) {
150 of_node_put(it.node);
Vivien Didelot34c09a82017-11-06 16:11:51 -0500151 return false;
Vivien Didelotc5286662017-11-06 16:11:50 -0500152 }
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200153
Vivien Didelot34c09a82017-11-06 16:11:51 -0500154 ds->rtable[link_dp->ds->index] = dp->index;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200155 }
156
Vivien Didelot34c09a82017-11-06 16:11:51 -0500157 return true;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200158}
159
Vivien Didelot34c09a82017-11-06 16:11:51 -0500160static bool dsa_switch_setup_routing_table(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200161{
Vivien Didelot34c09a82017-11-06 16:11:51 -0500162 bool complete = true;
163 struct dsa_port *dp;
164 int i;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200165
Vivien Didelot34c09a82017-11-06 16:11:51 -0500166 for (i = 0; i < DSA_MAX_SWITCHES; i++)
167 ds->rtable[i] = DSA_RTABLE_NONE;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200168
Vivien Didelot34c09a82017-11-06 16:11:51 -0500169 for (i = 0; i < ds->num_ports; i++) {
170 dp = &ds->ports[i];
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200171
Vivien Didelot34c09a82017-11-06 16:11:51 -0500172 if (dsa_port_is_dsa(dp)) {
173 complete = dsa_port_setup_routing_table(dp);
174 if (!complete)
175 break;
176 }
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200177 }
178
Vivien Didelot34c09a82017-11-06 16:11:51 -0500179 return complete;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200180}
181
Vivien Didelot34c09a82017-11-06 16:11:51 -0500182static bool dsa_tree_setup_routing_table(struct dsa_switch_tree *dst)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200183{
184 struct dsa_switch *ds;
Vivien Didelot34c09a82017-11-06 16:11:51 -0500185 bool complete = true;
186 int device;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200187
Vivien Didelot34c09a82017-11-06 16:11:51 -0500188 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
189 ds = dst->ds[device];
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200190 if (!ds)
191 continue;
192
Vivien Didelot34c09a82017-11-06 16:11:51 -0500193 complete = dsa_switch_setup_routing_table(ds);
194 if (!complete)
195 break;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200196 }
197
Vivien Didelot34c09a82017-11-06 16:11:51 -0500198 return complete;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200199}
200
Vivien Didelotf0704642017-11-06 16:11:44 -0500201static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst)
202{
203 struct dsa_switch *ds;
204 struct dsa_port *dp;
205 int device, port;
206
207 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
208 ds = dst->ds[device];
209 if (!ds)
210 continue;
211
212 for (port = 0; port < ds->num_ports; port++) {
213 dp = &ds->ports[port];
214
215 if (dsa_port_is_cpu(dp))
216 return dp;
217 }
218 }
219
220 return NULL;
221}
222
223static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst)
224{
225 struct dsa_switch *ds;
226 struct dsa_port *dp;
227 int device, port;
228
229 /* DSA currently only supports a single CPU port */
230 dst->cpu_dp = dsa_tree_find_first_cpu(dst);
231 if (!dst->cpu_dp) {
232 pr_warn("Tree has no master device\n");
233 return -EINVAL;
234 }
235
236 /* Assign the default CPU port to all ports of the fabric */
237 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
238 ds = dst->ds[device];
239 if (!ds)
240 continue;
241
242 for (port = 0; port < ds->num_ports; port++) {
243 dp = &ds->ports[port];
244
Vivien Didelot986d7cc2017-12-05 15:34:12 -0500245 if (dsa_port_is_user(dp) || dsa_port_is_dsa(dp))
Vivien Didelotf0704642017-11-06 16:11:44 -0500246 dp->cpu_dp = dst->cpu_dp;
247 }
248 }
249
250 return 0;
251}
252
253static void dsa_tree_teardown_default_cpu(struct dsa_switch_tree *dst)
254{
255 /* DSA currently only supports a single CPU port */
256 dst->cpu_dp = NULL;
257}
258
Vivien Didelot1d277322017-11-06 16:11:48 -0500259static int dsa_port_setup(struct dsa_port *dp)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200260{
Jiri Pirkod8ba3622019-03-24 11:14:32 +0100261 enum devlink_port_flavour flavour;
Vivien Didelot1d277322017-11-06 16:11:48 -0500262 struct dsa_switch *ds = dp->ds;
Jiri Pirko15b04ac2019-04-03 14:24:26 +0200263 struct dsa_switch_tree *dst = ds->dst;
Jiri Pirkod8ba3622019-03-24 11:14:32 +0100264 int err;
265
266 if (dp->type == DSA_PORT_TYPE_UNUSED)
267 return 0;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200268
Vivien Didelot1d277322017-11-06 16:11:48 -0500269 memset(&dp->devlink_port, 0, sizeof(dp->devlink_port));
Xiaofei Shena2c70232019-03-29 11:04:58 +0530270 dp->mac = of_get_mac_address(dp->dn);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200271
Jiri Pirkod8ba3622019-03-24 11:14:32 +0100272 switch (dp->type) {
273 case DSA_PORT_TYPE_CPU:
274 flavour = DEVLINK_PORT_FLAVOUR_CPU;
275 break;
276 case DSA_PORT_TYPE_DSA:
277 flavour = DEVLINK_PORT_FLAVOUR_DSA;
278 break;
279 case DSA_PORT_TYPE_USER: /* fall-through */
280 default:
281 flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
282 break;
283 }
284
285 /* dp->index is used now as port_number. However
286 * CPU and DSA ports should have separate numbering
287 * independent from front panel port numbers.
288 */
289 devlink_port_attrs_set(&dp->devlink_port, flavour,
Jiri Pirko15b04ac2019-04-03 14:24:26 +0200290 dp->index, false, 0,
291 (const char *) &dst->index, sizeof(dst->index));
Jiri Pirkod8ba3622019-03-24 11:14:32 +0100292 err = devlink_port_register(ds->devlink, &dp->devlink_port,
293 dp->index);
Andrew Lunn96567d52017-03-28 23:45:07 +0200294 if (err)
295 return err;
296
Vivien Didelot1d277322017-11-06 16:11:48 -0500297 switch (dp->type) {
298 case DSA_PORT_TYPE_UNUSED:
299 break;
300 case DSA_PORT_TYPE_CPU:
Jiri Pirkoda077392018-05-18 09:29:03 +0200301 err = dsa_port_link_register_of(dp);
302 if (err) {
303 dev_err(ds->dev, "failed to setup link for port %d.%d\n",
304 ds->index, dp->index);
305 return err;
306 }
307 break;
Vivien Didelot1d277322017-11-06 16:11:48 -0500308 case DSA_PORT_TYPE_DSA:
Sebastian Reichel33615362018-01-23 16:03:46 +0100309 err = dsa_port_link_register_of(dp);
Vivien Didelot1d277322017-11-06 16:11:48 -0500310 if (err) {
Sebastian Reichel33615362018-01-23 16:03:46 +0100311 dev_err(ds->dev, "failed to setup link for port %d.%d\n",
Vivien Didelot1d277322017-11-06 16:11:48 -0500312 ds->index, dp->index);
313 return err;
314 }
Vivien Didelot1d277322017-11-06 16:11:48 -0500315 break;
316 case DSA_PORT_TYPE_USER:
317 err = dsa_slave_create(dp);
318 if (err)
319 dev_err(ds->dev, "failed to create slave for port %d.%d\n",
320 ds->index, dp->index);
321 else
322 devlink_port_type_eth_set(&dp->devlink_port, dp->slave);
323 break;
324 }
Andrew Lunn96567d52017-03-28 23:45:07 +0200325
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200326 return 0;
327}
328
Vivien Didelot1d277322017-11-06 16:11:48 -0500329static void dsa_port_teardown(struct dsa_port *dp)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200330{
Florian Fainelli5447d782018-05-17 16:55:39 -0700331 if (dp->type != DSA_PORT_TYPE_UNUSED)
332 devlink_port_unregister(&dp->devlink_port);
Vivien Didelot1d277322017-11-06 16:11:48 -0500333
334 switch (dp->type) {
335 case DSA_PORT_TYPE_UNUSED:
336 break;
337 case DSA_PORT_TYPE_CPU:
Andrew Lunn4dad81e2019-04-28 19:37:19 +0200338 dsa_tag_driver_put(dp->tag_ops);
339 /* fall-through */
Vivien Didelot1d277322017-11-06 16:11:48 -0500340 case DSA_PORT_TYPE_DSA:
Sebastian Reichel33615362018-01-23 16:03:46 +0100341 dsa_port_link_unregister_of(dp);
Vivien Didelot1d277322017-11-06 16:11:48 -0500342 break;
343 case DSA_PORT_TYPE_USER:
344 if (dp->slave) {
345 dsa_slave_destroy(dp->slave);
346 dp->slave = NULL;
347 }
348 break;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200349 }
350}
351
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500352static int dsa_switch_setup(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200353{
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200354 int err;
355
Florian Fainelli6e830d82016-06-07 16:32:39 -0700356 /* Initialize ds->phys_mii_mask before registering the slave MDIO bus
Vivien Didelot9d490b42016-08-23 12:38:56 -0400357 * driver and before ops->setup() has run, since the switch drivers and
Florian Fainelli6e830d82016-06-07 16:32:39 -0700358 * the slave MDIO bus driver rely on these values for probing PHY
359 * devices or not
360 */
Vivien Didelot02bc6e52017-10-26 11:22:56 -0400361 ds->phys_mii_mask |= dsa_user_ports(ds);
Florian Fainelli6e830d82016-06-07 16:32:39 -0700362
Andrew Lunn96567d52017-03-28 23:45:07 +0200363 /* Add the switch to devlink before calling setup, so that setup can
364 * add dpipe tables
365 */
366 ds->devlink = devlink_alloc(&dsa_devlink_ops, 0);
367 if (!ds->devlink)
368 return -ENOMEM;
369
370 err = devlink_register(ds->devlink, ds->dev);
371 if (err)
372 return err;
373
Vivien Didelotf515f192017-02-03 13:20:20 -0500374 err = dsa_switch_register_notifier(ds);
375 if (err)
376 return err;
377
Vladimir Olteanb2243b32019-05-05 13:19:20 +0300378 err = ds->ops->setup(ds);
379 if (err < 0)
380 return err;
381
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 ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
384 if (!ds->slave_mii_bus)
385 return -ENOMEM;
386
387 dsa_slave_mii_bus_init(ds);
388
389 err = mdiobus_register(ds->slave_mii_bus);
390 if (err < 0)
391 return err;
392 }
393
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200394 return 0;
395}
396
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500397static void dsa_switch_teardown(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200398{
Vivien Didelot9d490b42016-08-23 12:38:56 -0400399 if (ds->slave_mii_bus && ds->ops->phy_read)
Florian Fainelli1eb59442016-06-07 16:32:40 -0700400 mdiobus_unregister(ds->slave_mii_bus);
Vivien Didelotf515f192017-02-03 13:20:20 -0500401
402 dsa_switch_unregister_notifier(ds);
Andrew Lunn96567d52017-03-28 23:45:07 +0200403
404 if (ds->devlink) {
405 devlink_unregister(ds->devlink);
406 devlink_free(ds->devlink);
407 ds->devlink = NULL;
408 }
409
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200410}
411
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500412static int dsa_tree_setup_switches(struct dsa_switch_tree *dst)
413{
414 struct dsa_switch *ds;
Vivien Didelot1d277322017-11-06 16:11:48 -0500415 struct dsa_port *dp;
416 int device, port;
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500417 int err;
418
419 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
420 ds = dst->ds[device];
421 if (!ds)
422 continue;
423
424 err = dsa_switch_setup(ds);
425 if (err)
426 return err;
Vivien Didelot1d277322017-11-06 16:11:48 -0500427
428 for (port = 0; port < ds->num_ports; port++) {
429 dp = &ds->ports[port];
430
431 err = dsa_port_setup(dp);
432 if (err)
433 return err;
434 }
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500435 }
436
437 return 0;
438}
439
440static void dsa_tree_teardown_switches(struct dsa_switch_tree *dst)
441{
442 struct dsa_switch *ds;
Vivien Didelot1d277322017-11-06 16:11:48 -0500443 struct dsa_port *dp;
444 int device, port;
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500445
446 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
447 ds = dst->ds[device];
448 if (!ds)
449 continue;
450
Vivien Didelot1d277322017-11-06 16:11:48 -0500451 for (port = 0; port < ds->num_ports; port++) {
452 dp = &ds->ports[port];
453
454 dsa_port_teardown(dp);
455 }
456
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500457 dsa_switch_teardown(ds);
458 }
459}
460
Vivien Didelot17a22fc2017-11-06 16:11:45 -0500461static int dsa_tree_setup_master(struct dsa_switch_tree *dst)
462{
463 struct dsa_port *cpu_dp = dst->cpu_dp;
464 struct net_device *master = cpu_dp->master;
465
466 /* DSA currently supports a single pair of CPU port and master device */
467 return dsa_master_setup(master, cpu_dp);
468}
469
470static void dsa_tree_teardown_master(struct dsa_switch_tree *dst)
471{
472 struct dsa_port *cpu_dp = dst->cpu_dp;
473 struct net_device *master = cpu_dp->master;
474
475 return dsa_master_teardown(master);
476}
477
Vivien Didelotec15dd42017-11-06 16:11:46 -0500478static int dsa_tree_setup(struct dsa_switch_tree *dst)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200479{
Vivien Didelot34c09a82017-11-06 16:11:51 -0500480 bool complete;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200481 int err;
482
Vivien Didelotec15dd42017-11-06 16:11:46 -0500483 if (dst->setup) {
484 pr_err("DSA: tree %d already setup! Disjoint trees?\n",
485 dst->index);
486 return -EEXIST;
487 }
488
Vivien Didelot34c09a82017-11-06 16:11:51 -0500489 complete = dsa_tree_setup_routing_table(dst);
490 if (!complete)
491 return 0;
492
Vivien Didelotf0704642017-11-06 16:11:44 -0500493 err = dsa_tree_setup_default_cpu(dst);
494 if (err)
495 return err;
496
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500497 err = dsa_tree_setup_switches(dst);
498 if (err)
499 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200500
Vivien Didelot17a22fc2017-11-06 16:11:45 -0500501 err = dsa_tree_setup_master(dst);
Vivien Didelot19435632017-09-19 11:56:59 -0400502 if (err)
503 return err;
504
Vivien Didelotec15dd42017-11-06 16:11:46 -0500505 dst->setup = true;
506
507 pr_info("DSA: tree %d setup\n", dst->index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200508
509 return 0;
510}
511
Vivien Didelotec15dd42017-11-06 16:11:46 -0500512static void dsa_tree_teardown(struct dsa_switch_tree *dst)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200513{
Vivien Didelotec15dd42017-11-06 16:11:46 -0500514 if (!dst->setup)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200515 return;
516
Vivien Didelot17a22fc2017-11-06 16:11:45 -0500517 dsa_tree_teardown_master(dst);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200518
Vivien Didelot1f08f9e2017-11-06 16:11:47 -0500519 dsa_tree_teardown_switches(dst);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200520
Vivien Didelotf0704642017-11-06 16:11:44 -0500521 dsa_tree_teardown_default_cpu(dst);
Florian Fainelli0c73c522016-06-07 16:32:42 -0700522
Vivien Didelotec15dd42017-11-06 16:11:46 -0500523 pr_info("DSA: tree %d torn down\n", dst->index);
524
525 dst->setup = false;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200526}
527
Vivien Didelot6da2a942017-11-03 19:05:25 -0400528static void dsa_tree_remove_switch(struct dsa_switch_tree *dst,
529 unsigned int index)
530{
Vivien Didelot30817352017-11-06 16:11:52 -0500531 dsa_tree_teardown(dst);
532
Vivien Didelot6da2a942017-11-03 19:05:25 -0400533 dst->ds[index] = NULL;
534 dsa_tree_put(dst);
535}
536
537static int dsa_tree_add_switch(struct dsa_switch_tree *dst,
538 struct dsa_switch *ds)
539{
540 unsigned int index = ds->index;
Vivien Didelot30817352017-11-06 16:11:52 -0500541 int err;
Vivien Didelot6da2a942017-11-03 19:05:25 -0400542
543 if (dst->ds[index])
544 return -EBUSY;
545
546 dsa_tree_get(dst);
547 dst->ds[index] = ds;
548
Vivien Didelot30817352017-11-06 16:11:52 -0500549 err = dsa_tree_setup(dst);
550 if (err)
551 dsa_tree_remove_switch(dst, index);
552
553 return err;
Vivien Didelot6da2a942017-11-03 19:05:25 -0400554}
555
Vivien Didelot06e24d02017-11-03 19:05:29 -0400556static int dsa_port_parse_user(struct dsa_port *dp, const char *name)
557{
558 if (!name)
559 name = "eth%d";
560
561 dp->type = DSA_PORT_TYPE_USER;
562 dp->name = name;
563
564 return 0;
565}
566
567static int dsa_port_parse_dsa(struct dsa_port *dp)
568{
569 dp->type = DSA_PORT_TYPE_DSA;
570
571 return 0;
572}
573
574static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master)
575{
Vivien Didelot7354fcb2017-11-03 19:05:30 -0400576 struct dsa_switch *ds = dp->ds;
577 struct dsa_switch_tree *dst = ds->dst;
Vivien Didelot62fc9582017-09-29 17:19:17 -0400578 const struct dsa_device_ops *tag_ops;
Andrew Lunn7b314362016-08-22 16:01:01 +0200579 enum dsa_tag_protocol tag_protocol;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200580
Florian Fainelli5ed4e3e2017-11-10 15:22:52 -0800581 tag_protocol = ds->ops->get_tag_protocol(ds, dp->index);
Andrew Lunnc39e2a12019-04-28 19:37:18 +0200582 tag_ops = dsa_tag_driver_get(tag_protocol);
Vivien Didelot62fc9582017-09-29 17:19:17 -0400583 if (IS_ERR(tag_ops)) {
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700584 dev_warn(ds->dev, "No tagger for this switch\n");
Vivien Didelot62fc9582017-09-29 17:19:17 -0400585 return PTR_ERR(tag_ops);
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700586 }
587
Vivien Didelot7354fcb2017-11-03 19:05:30 -0400588 dp->type = DSA_PORT_TYPE_CPU;
589 dp->rcv = tag_ops->rcv;
590 dp->tag_ops = tag_ops;
591 dp->master = master;
592 dp->dst = dst;
Vivien Didelot3e41f932017-09-29 17:19:19 -0400593
Vivien Didelot7354fcb2017-11-03 19:05:30 -0400594 return 0;
595}
596
Vivien Didelotfd223e22017-10-27 15:55:14 -0400597static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn)
598{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400599 struct device_node *ethernet = of_parse_phandle(dn, "ethernet", 0);
Vivien Didelot1838fa82017-10-27 15:55:18 -0400600 const char *name = of_get_property(dn, "label", NULL);
Vivien Didelot54df6fa2017-11-03 19:05:28 -0400601 bool link = of_property_read_bool(dn, "link");
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400602
Vivien Didelot06e24d02017-11-03 19:05:29 -0400603 dp->dn = dn;
604
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400605 if (ethernet) {
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400606 struct net_device *master;
607
608 master = of_find_net_device_by_node(ethernet);
609 if (!master)
610 return -EPROBE_DEFER;
611
Vivien Didelot06e24d02017-11-03 19:05:29 -0400612 return dsa_port_parse_cpu(dp, master);
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400613 }
614
Vivien Didelot06e24d02017-11-03 19:05:29 -0400615 if (link)
616 return dsa_port_parse_dsa(dp);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400617
Vivien Didelot06e24d02017-11-03 19:05:29 -0400618 return dsa_port_parse_user(dp, name);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400619}
620
Vivien Didelot975e6e32017-11-03 19:05:27 -0400621static int dsa_switch_parse_ports_of(struct dsa_switch *ds,
622 struct device_node *dn)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200623{
Vivien Didelot5b32fe02017-10-27 15:55:13 -0400624 struct device_node *ports, *port;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400625 struct dsa_port *dp;
Wen Yang9919a362019-02-25 15:22:19 +0800626 int err = 0;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200627 u32 reg;
Vivien Didelot5b32fe02017-10-27 15:55:13 -0400628
629 ports = of_get_child_by_name(dn, "ports");
630 if (!ports) {
631 dev_err(ds->dev, "no ports child node found\n");
632 return -EINVAL;
633 }
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200634
635 for_each_available_child_of_node(ports, port) {
636 err = of_property_read_u32(port, "reg", &reg);
637 if (err)
Wen Yang9919a362019-02-25 15:22:19 +0800638 goto out_put_node;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200639
Wen Yang9919a362019-02-25 15:22:19 +0800640 if (reg >= ds->num_ports) {
641 err = -EINVAL;
642 goto out_put_node;
643 }
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200644
Vivien Didelotfd223e22017-10-27 15:55:14 -0400645 dp = &ds->ports[reg];
646
647 err = dsa_port_parse_of(dp, port);
648 if (err)
Wen Yang9919a362019-02-25 15:22:19 +0800649 goto out_put_node;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200650 }
651
Wen Yang9919a362019-02-25 15:22:19 +0800652out_put_node:
653 of_node_put(ports);
654 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200655}
656
Vivien Didelot975e6e32017-11-03 19:05:27 -0400657static int dsa_switch_parse_member_of(struct dsa_switch *ds,
658 struct device_node *dn)
659{
660 u32 m[2] = { 0, 0 };
661 int sz;
662
663 /* Don't error out if this optional property isn't found */
664 sz = of_property_read_variable_u32_array(dn, "dsa,member", m, 2, 2);
665 if (sz < 0 && sz != -EINVAL)
666 return sz;
667
668 ds->index = m[1];
669 if (ds->index >= DSA_MAX_SWITCHES)
670 return -EINVAL;
671
672 ds->dst = dsa_tree_touch(m[0]);
673 if (!ds->dst)
674 return -ENOMEM;
675
676 return 0;
677}
678
679static int dsa_switch_parse_of(struct dsa_switch *ds, struct device_node *dn)
680{
681 int err;
682
683 err = dsa_switch_parse_member_of(ds, dn);
684 if (err)
685 return err;
686
687 return dsa_switch_parse_ports_of(ds, dn);
688}
689
Vivien Didelotfd223e22017-10-27 15:55:14 -0400690static int dsa_port_parse(struct dsa_port *dp, const char *name,
691 struct device *dev)
692{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400693 if (!strcmp(name, "cpu")) {
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400694 struct net_device *master;
695
696 master = dsa_dev_to_net_device(dev);
697 if (!master)
698 return -EPROBE_DEFER;
699
700 dev_put(master);
701
Vivien Didelot06e24d02017-11-03 19:05:29 -0400702 return dsa_port_parse_cpu(dp, master);
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400703 }
704
Vivien Didelot06e24d02017-11-03 19:05:29 -0400705 if (!strcmp(name, "dsa"))
706 return dsa_port_parse_dsa(dp);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400707
Vivien Didelot06e24d02017-11-03 19:05:29 -0400708 return dsa_port_parse_user(dp, name);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400709}
710
Vivien Didelot975e6e32017-11-03 19:05:27 -0400711static int dsa_switch_parse_ports(struct dsa_switch *ds,
712 struct dsa_chip_data *cd)
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800713{
714 bool valid_name_found = false;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400715 struct dsa_port *dp;
716 struct device *dev;
717 const char *name;
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800718 unsigned int i;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400719 int err;
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800720
721 for (i = 0; i < DSA_MAX_PORTS; i++) {
Vivien Didelotfd223e22017-10-27 15:55:14 -0400722 name = cd->port_names[i];
723 dev = cd->netdev[i];
724 dp = &ds->ports[i];
725
726 if (!name)
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800727 continue;
728
Vivien Didelotfd223e22017-10-27 15:55:14 -0400729 err = dsa_port_parse(dp, name, dev);
730 if (err)
731 return err;
732
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800733 valid_name_found = true;
734 }
735
736 if (!valid_name_found && i == DSA_MAX_PORTS)
737 return -EINVAL;
738
739 return 0;
740}
741
Vivien Didelot975e6e32017-11-03 19:05:27 -0400742static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200743{
Vivien Didelot975e6e32017-11-03 19:05:27 -0400744 ds->cd = cd;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200745
Vivien Didelot975e6e32017-11-03 19:05:27 -0400746 /* We don't support interconnected switches nor multiple trees via
747 * platform data, so this is the unique switch of the tree.
748 */
749 ds->index = 0;
750 ds->dst = dsa_tree_touch(0);
751 if (!ds->dst)
752 return -ENOMEM;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200753
Vivien Didelot975e6e32017-11-03 19:05:27 -0400754 return dsa_switch_parse_ports(ds, cd);
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800755}
756
Vivien Didelot30817352017-11-06 16:11:52 -0500757static int dsa_switch_add(struct dsa_switch *ds)
758{
759 struct dsa_switch_tree *dst = ds->dst;
760
761 return dsa_tree_add_switch(dst, ds);
762}
763
Vivien Didelotb4fbb342017-11-06 16:11:53 -0500764static int dsa_switch_probe(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200765{
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400766 struct dsa_chip_data *pdata = ds->dev->platform_data;
767 struct device_node *np = ds->dev->of_node;
Vivien Didelot34c09a82017-11-06 16:11:51 -0500768 int err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200769
Vivien Didelot975e6e32017-11-03 19:05:27 -0400770 if (np)
771 err = dsa_switch_parse_of(ds, np);
772 else if (pdata)
773 err = dsa_switch_parse(ds, pdata);
774 else
775 err = -ENODEV;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200776
Vivien Didelot975e6e32017-11-03 19:05:27 -0400777 if (err)
778 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200779
Vivien Didelot30817352017-11-06 16:11:52 -0500780 return dsa_switch_add(ds);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200781}
782
Vivien Didelota0c02162017-01-27 15:29:36 -0500783struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n)
784{
Vivien Didelota0c02162017-01-27 15:29:36 -0500785 struct dsa_switch *ds;
Vivien Didelot818be842017-01-27 15:29:38 -0500786 int i;
Vivien Didelota0c02162017-01-27 15:29:36 -0500787
Gustavo A. R. Silva33b363e2019-02-07 19:16:03 -0600788 ds = devm_kzalloc(dev, struct_size(ds, ports, n), GFP_KERNEL);
Vivien Didelota0c02162017-01-27 15:29:36 -0500789 if (!ds)
790 return NULL;
791
Salvatore Mesoraca0015b802018-07-16 21:10:34 -0700792 /* We avoid allocating memory outside dsa_switch
793 * if it is not needed.
794 */
795 if (n <= sizeof(ds->_bitmap) * 8) {
796 ds->bitmap = &ds->_bitmap;
797 } else {
798 ds->bitmap = devm_kcalloc(dev,
799 BITS_TO_LONGS(n),
800 sizeof(unsigned long),
801 GFP_KERNEL);
802 if (unlikely(!ds->bitmap))
803 return NULL;
804 }
805
Vivien Didelota0c02162017-01-27 15:29:36 -0500806 ds->dev = dev;
807 ds->num_ports = n;
808
Vivien Didelot818be842017-01-27 15:29:38 -0500809 for (i = 0; i < ds->num_ports; ++i) {
810 ds->ports[i].index = i;
811 ds->ports[i].ds = ds;
812 }
813
Vivien Didelota0c02162017-01-27 15:29:36 -0500814 return ds;
815}
816EXPORT_SYMBOL_GPL(dsa_switch_alloc);
817
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400818int dsa_register_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200819{
820 int err;
821
822 mutex_lock(&dsa2_mutex);
Vivien Didelotb4fbb342017-11-06 16:11:53 -0500823 err = dsa_switch_probe(ds);
Vivien Didelot9e741042017-11-24 11:36:06 -0500824 dsa_tree_put(ds->dst);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200825 mutex_unlock(&dsa2_mutex);
826
827 return err;
828}
829EXPORT_SYMBOL_GPL(dsa_register_switch);
830
Vivien Didelotb4fbb342017-11-06 16:11:53 -0500831static void dsa_switch_remove(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200832{
833 struct dsa_switch_tree *dst = ds->dst;
Vivien Didelot6da2a942017-11-03 19:05:25 -0400834 unsigned int index = ds->index;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200835
Vivien Didelot6da2a942017-11-03 19:05:25 -0400836 dsa_tree_remove_switch(dst, index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200837}
838
839void dsa_unregister_switch(struct dsa_switch *ds)
840{
841 mutex_lock(&dsa2_mutex);
Vivien Didelotb4fbb342017-11-06 16:11:53 -0500842 dsa_switch_remove(ds);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200843 mutex_unlock(&dsa2_mutex);
844}
845EXPORT_SYMBOL_GPL(dsa_unregister_switch);