blob: 283104e5ca6a9165f45377ad52ee75b6a6884abf [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
Florian Fainelli3512a8e2017-01-26 10:45:53 -0800115static bool dsa_ds_find_port_dn(struct dsa_switch *ds,
116 struct device_node *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200117{
118 u32 index;
119
Vivien Didelot26895e22017-01-27 15:29:37 -0500120 for (index = 0; index < ds->num_ports; index++)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200121 if (ds->ports[index].dn == port)
122 return true;
123 return false;
124}
125
Florian Fainelli3512a8e2017-01-26 10:45:53 -0800126static struct dsa_switch *dsa_dst_find_port_dn(struct dsa_switch_tree *dst,
127 struct device_node *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200128{
129 struct dsa_switch *ds;
130 u32 index;
131
132 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
133 ds = dst->ds[index];
134 if (!ds)
135 continue;
136
Florian Fainelli3512a8e2017-01-26 10:45:53 -0800137 if (dsa_ds_find_port_dn(ds, port))
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200138 return ds;
139 }
140
141 return NULL;
142}
143
144static int dsa_port_complete(struct dsa_switch_tree *dst,
145 struct dsa_switch *src_ds,
Florian Fainelli293784a2017-01-26 10:45:52 -0800146 struct dsa_port *port,
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200147 u32 src_port)
148{
149 struct device_node *link;
150 int index;
151 struct dsa_switch *dst_ds;
152
153 for (index = 0;; index++) {
Florian Fainelli293784a2017-01-26 10:45:52 -0800154 link = of_parse_phandle(port->dn, "link", index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200155 if (!link)
156 break;
157
Florian Fainelli3512a8e2017-01-26 10:45:53 -0800158 dst_ds = dsa_dst_find_port_dn(dst, link);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200159 of_node_put(link);
160
161 if (!dst_ds)
162 return 1;
163
164 src_ds->rtable[dst_ds->index] = src_port;
165 }
166
167 return 0;
168}
169
170/* A switch is complete if all the DSA ports phandles point to ports
171 * known in the tree. A return value of 1 means the tree is not
172 * complete. This is not an error condition. A value of 0 is
173 * success.
174 */
175static int dsa_ds_complete(struct dsa_switch_tree *dst, struct dsa_switch *ds)
176{
Florian Fainelli293784a2017-01-26 10:45:52 -0800177 struct dsa_port *port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200178 u32 index;
179 int err;
180
Vivien Didelot26895e22017-01-27 15:29:37 -0500181 for (index = 0; index < ds->num_ports; index++) {
Florian Fainelli293784a2017-01-26 10:45:52 -0800182 port = &ds->ports[index];
183 if (!dsa_port_is_valid(port))
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200184 continue;
185
186 if (!dsa_port_is_dsa(port))
187 continue;
188
189 err = dsa_port_complete(dst, ds, port, index);
190 if (err != 0)
191 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200192 }
193
194 return 0;
195}
196
197/* A tree is complete if all the DSA ports phandles point to ports
198 * known in the tree. A return value of 1 means the tree is not
199 * complete. This is not an error condition. A value of 0 is
200 * success.
201 */
202static int dsa_dst_complete(struct dsa_switch_tree *dst)
203{
204 struct dsa_switch *ds;
205 u32 index;
206 int err;
207
208 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
209 ds = dst->ds[index];
210 if (!ds)
211 continue;
212
213 err = dsa_ds_complete(dst, ds);
214 if (err != 0)
215 return err;
216 }
217
218 return 0;
219}
220
Florian Fainellie41c1b52017-06-02 12:31:22 -0700221static int dsa_dsa_port_apply(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200222{
Florian Fainellie41c1b52017-06-02 12:31:22 -0700223 struct dsa_switch *ds = port->ds;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200224 int err;
225
Vivien Didelot57ab1ca2017-10-26 10:50:07 -0400226 err = dsa_port_fixed_link_register_of(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200227 if (err) {
228 dev_warn(ds->dev, "Failed to setup dsa port %d: %d\n",
Florian Fainellie41c1b52017-06-02 12:31:22 -0700229 port->index, err);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200230 return err;
231 }
232
Florian Fainellie41c1b52017-06-02 12:31:22 -0700233 memset(&port->devlink_port, 0, sizeof(port->devlink_port));
Andrew Lunn96567d52017-03-28 23:45:07 +0200234
Florian Fainellie41c1b52017-06-02 12:31:22 -0700235 return devlink_port_register(ds->devlink, &port->devlink_port,
236 port->index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200237}
238
Florian Fainellie41c1b52017-06-02 12:31:22 -0700239static void dsa_dsa_port_unapply(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200240{
Florian Fainellie41c1b52017-06-02 12:31:22 -0700241 devlink_port_unregister(&port->devlink_port);
Vivien Didelot57ab1ca2017-10-26 10:50:07 -0400242 dsa_port_fixed_link_unregister_of(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200243}
244
Florian Fainellie41c1b52017-06-02 12:31:22 -0700245static int dsa_cpu_port_apply(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200246{
Florian Fainellie41c1b52017-06-02 12:31:22 -0700247 struct dsa_switch *ds = port->ds;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200248 int err;
249
Vivien Didelot57ab1ca2017-10-26 10:50:07 -0400250 err = dsa_port_fixed_link_register_of(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200251 if (err) {
252 dev_warn(ds->dev, "Failed to setup cpu port %d: %d\n",
Florian Fainellie41c1b52017-06-02 12:31:22 -0700253 port->index, err);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200254 return err;
255 }
256
Florian Fainellie41c1b52017-06-02 12:31:22 -0700257 memset(&port->devlink_port, 0, sizeof(port->devlink_port));
258 err = devlink_port_register(ds->devlink, &port->devlink_port,
259 port->index);
Andrew Lunn96567d52017-03-28 23:45:07 +0200260 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200261}
262
Florian Fainellie41c1b52017-06-02 12:31:22 -0700263static void dsa_cpu_port_unapply(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200264{
Florian Fainellie41c1b52017-06-02 12:31:22 -0700265 devlink_port_unregister(&port->devlink_port);
Vivien Didelot57ab1ca2017-10-26 10:50:07 -0400266 dsa_port_fixed_link_unregister_of(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200267}
268
Florian Fainellie41c1b52017-06-02 12:31:22 -0700269static int dsa_user_port_apply(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200270{
Florian Fainellie41c1b52017-06-02 12:31:22 -0700271 struct dsa_switch *ds = port->ds;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200272 int err;
273
Vivien Didelot951259aa2017-10-27 15:55:19 -0400274 err = dsa_slave_create(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200275 if (err) {
276 dev_warn(ds->dev, "Failed to create slave %d: %d\n",
Florian Fainellie41c1b52017-06-02 12:31:22 -0700277 port->index, err);
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400278 port->slave = NULL;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200279 return err;
280 }
281
Florian Fainellie41c1b52017-06-02 12:31:22 -0700282 memset(&port->devlink_port, 0, sizeof(port->devlink_port));
283 err = devlink_port_register(ds->devlink, &port->devlink_port,
284 port->index);
Andrew Lunn96567d52017-03-28 23:45:07 +0200285 if (err)
286 return err;
287
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400288 devlink_port_type_eth_set(&port->devlink_port, port->slave);
Andrew Lunn96567d52017-03-28 23:45:07 +0200289
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200290 return 0;
291}
292
Florian Fainellie41c1b52017-06-02 12:31:22 -0700293static void dsa_user_port_unapply(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200294{
Florian Fainellie41c1b52017-06-02 12:31:22 -0700295 devlink_port_unregister(&port->devlink_port);
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400296 if (port->slave) {
297 dsa_slave_destroy(port->slave);
298 port->slave = NULL;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200299 }
300}
301
302static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds)
303{
Florian Fainelli293784a2017-01-26 10:45:52 -0800304 struct dsa_port *port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200305 u32 index;
306 int err;
307
Florian Fainelli6e830d82016-06-07 16:32:39 -0700308 /* Initialize ds->phys_mii_mask before registering the slave MDIO bus
Vivien Didelot9d490b42016-08-23 12:38:56 -0400309 * driver and before ops->setup() has run, since the switch drivers and
Florian Fainelli6e830d82016-06-07 16:32:39 -0700310 * the slave MDIO bus driver rely on these values for probing PHY
311 * devices or not
312 */
Vivien Didelot02bc6e52017-10-26 11:22:56 -0400313 ds->phys_mii_mask |= dsa_user_ports(ds);
Florian Fainelli6e830d82016-06-07 16:32:39 -0700314
Andrew Lunn96567d52017-03-28 23:45:07 +0200315 /* Add the switch to devlink before calling setup, so that setup can
316 * add dpipe tables
317 */
318 ds->devlink = devlink_alloc(&dsa_devlink_ops, 0);
319 if (!ds->devlink)
320 return -ENOMEM;
321
322 err = devlink_register(ds->devlink, ds->dev);
323 if (err)
324 return err;
325
Vivien Didelot9d490b42016-08-23 12:38:56 -0400326 err = ds->ops->setup(ds);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200327 if (err < 0)
328 return err;
329
Vivien Didelotf515f192017-02-03 13:20:20 -0500330 err = dsa_switch_register_notifier(ds);
331 if (err)
332 return err;
333
Vivien Didelot9d490b42016-08-23 12:38:56 -0400334 if (!ds->slave_mii_bus && ds->ops->phy_read) {
Florian Fainelli1eb59442016-06-07 16:32:40 -0700335 ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
336 if (!ds->slave_mii_bus)
337 return -ENOMEM;
338
339 dsa_slave_mii_bus_init(ds);
340
341 err = mdiobus_register(ds->slave_mii_bus);
342 if (err < 0)
343 return err;
344 }
345
Vivien Didelot26895e22017-01-27 15:29:37 -0500346 for (index = 0; index < ds->num_ports; index++) {
Florian Fainelli293784a2017-01-26 10:45:52 -0800347 port = &ds->ports[index];
348 if (!dsa_port_is_valid(port))
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200349 continue;
350
351 if (dsa_port_is_dsa(port)) {
Florian Fainellie41c1b52017-06-02 12:31:22 -0700352 err = dsa_dsa_port_apply(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200353 if (err)
354 return err;
355 continue;
356 }
357
358 if (dsa_port_is_cpu(port)) {
Florian Fainellie41c1b52017-06-02 12:31:22 -0700359 err = dsa_cpu_port_apply(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200360 if (err)
361 return err;
362 continue;
363 }
364
Florian Fainellie41c1b52017-06-02 12:31:22 -0700365 err = dsa_user_port_apply(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200366 if (err)
367 continue;
368 }
369
370 return 0;
371}
372
373static void dsa_ds_unapply(struct dsa_switch_tree *dst, struct dsa_switch *ds)
374{
Florian Fainelli293784a2017-01-26 10:45:52 -0800375 struct dsa_port *port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200376 u32 index;
377
Vivien Didelot26895e22017-01-27 15:29:37 -0500378 for (index = 0; index < ds->num_ports; index++) {
Florian Fainelli293784a2017-01-26 10:45:52 -0800379 port = &ds->ports[index];
380 if (!dsa_port_is_valid(port))
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200381 continue;
382
383 if (dsa_port_is_dsa(port)) {
Florian Fainellie41c1b52017-06-02 12:31:22 -0700384 dsa_dsa_port_unapply(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200385 continue;
386 }
387
388 if (dsa_port_is_cpu(port)) {
Florian Fainellie41c1b52017-06-02 12:31:22 -0700389 dsa_cpu_port_unapply(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200390 continue;
391 }
392
Florian Fainellie41c1b52017-06-02 12:31:22 -0700393 dsa_user_port_unapply(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200394 }
Florian Fainelli1eb59442016-06-07 16:32:40 -0700395
Vivien Didelot9d490b42016-08-23 12:38:56 -0400396 if (ds->slave_mii_bus && ds->ops->phy_read)
Florian Fainelli1eb59442016-06-07 16:32:40 -0700397 mdiobus_unregister(ds->slave_mii_bus);
Vivien Didelotf515f192017-02-03 13:20:20 -0500398
399 dsa_switch_unregister_notifier(ds);
Andrew Lunn96567d52017-03-28 23:45:07 +0200400
401 if (ds->devlink) {
402 devlink_unregister(ds->devlink);
403 devlink_free(ds->devlink);
404 ds->devlink = NULL;
405 }
406
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200407}
408
409static int dsa_dst_apply(struct dsa_switch_tree *dst)
410{
411 struct dsa_switch *ds;
412 u32 index;
413 int err;
414
415 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
416 ds = dst->ds[index];
417 if (!ds)
418 continue;
419
420 err = dsa_ds_apply(dst, ds);
421 if (err)
422 return err;
423 }
424
425 /* If we use a tagging format that doesn't have an ethertype
426 * field, make sure that all packets from this point on get
427 * sent to the tag format's receive function.
428 */
429 wmb();
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400430 dst->cpu_dp->master->dsa_ptr = dst->cpu_dp;
Vivien Didelot19435632017-09-19 11:56:59 -0400431
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400432 err = dsa_master_ethtool_setup(dst->cpu_dp->master);
Vivien Didelot19435632017-09-19 11:56:59 -0400433 if (err)
434 return err;
435
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200436 dst->applied = true;
437
438 return 0;
439}
440
441static void dsa_dst_unapply(struct dsa_switch_tree *dst)
442{
443 struct dsa_switch *ds;
444 u32 index;
445
446 if (!dst->applied)
447 return;
448
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400449 dsa_master_ethtool_restore(dst->cpu_dp->master);
Vivien Didelot19435632017-09-19 11:56:59 -0400450
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400451 dst->cpu_dp->master->dsa_ptr = NULL;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200452
453 /* If we used a tagging format that doesn't have an ethertype
454 * field, make sure that all packets from this point get sent
455 * without the tag and go through the regular receive path.
456 */
457 wmb();
458
459 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
460 ds = dst->ds[index];
461 if (!ds)
462 continue;
463
464 dsa_ds_unapply(dst, ds);
465 }
466
Vivien Didelotcd8d7dd2017-09-19 11:56:58 -0400467 dst->cpu_dp = NULL;
Florian Fainelli0c73c522016-06-07 16:32:42 -0700468
Vivien Didelot49463b72017-11-03 19:05:21 -0400469 pr_info("DSA: tree %d unapplied\n", dst->index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200470 dst->applied = false;
471}
472
Vivien Didelot6da2a942017-11-03 19:05:25 -0400473static void dsa_tree_remove_switch(struct dsa_switch_tree *dst,
474 unsigned int index)
475{
476 dst->ds[index] = NULL;
477 dsa_tree_put(dst);
478}
479
480static int dsa_tree_add_switch(struct dsa_switch_tree *dst,
481 struct dsa_switch *ds)
482{
483 unsigned int index = ds->index;
484
485 if (dst->ds[index])
486 return -EBUSY;
487
488 dsa_tree_get(dst);
489 dst->ds[index] = ds;
490
491 return 0;
492}
493
Vivien Didelot06e24d02017-11-03 19:05:29 -0400494static int dsa_port_parse_user(struct dsa_port *dp, const char *name)
495{
496 if (!name)
497 name = "eth%d";
498
499 dp->type = DSA_PORT_TYPE_USER;
500 dp->name = name;
501
502 return 0;
503}
504
505static int dsa_port_parse_dsa(struct dsa_port *dp)
506{
507 dp->type = DSA_PORT_TYPE_DSA;
508
509 return 0;
510}
511
512static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master)
513{
Vivien Didelot7354fcb2017-11-03 19:05:30 -0400514 struct dsa_switch *ds = dp->ds;
515 struct dsa_switch_tree *dst = ds->dst;
Vivien Didelot62fc9582017-09-29 17:19:17 -0400516 const struct dsa_device_ops *tag_ops;
Andrew Lunn7b314362016-08-22 16:01:01 +0200517 enum dsa_tag_protocol tag_protocol;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200518
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700519 tag_protocol = ds->ops->get_tag_protocol(ds);
Vivien Didelot62fc9582017-09-29 17:19:17 -0400520 tag_ops = dsa_resolve_tag_protocol(tag_protocol);
521 if (IS_ERR(tag_ops)) {
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700522 dev_warn(ds->dev, "No tagger for this switch\n");
Vivien Didelot62fc9582017-09-29 17:19:17 -0400523 return PTR_ERR(tag_ops);
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700524 }
525
Vivien Didelot7354fcb2017-11-03 19:05:30 -0400526 dp->type = DSA_PORT_TYPE_CPU;
527 dp->rcv = tag_ops->rcv;
528 dp->tag_ops = tag_ops;
529 dp->master = master;
530 dp->dst = dst;
Vivien Didelot3e41f932017-09-29 17:19:19 -0400531
Vivien Didelot7354fcb2017-11-03 19:05:30 -0400532 return 0;
533}
534
535static int dsa_cpu_parse(struct dsa_port *port, u32 index,
536 struct dsa_switch_tree *dst,
537 struct dsa_switch *ds)
538{
539 if (!dst->cpu_dp)
540 dst->cpu_dp = port;
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700541
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200542 return 0;
543}
544
545static int dsa_ds_parse(struct dsa_switch_tree *dst, struct dsa_switch *ds)
546{
Florian Fainelli293784a2017-01-26 10:45:52 -0800547 struct dsa_port *port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200548 u32 index;
549 int err;
550
Vivien Didelot26895e22017-01-27 15:29:37 -0500551 for (index = 0; index < ds->num_ports; index++) {
Florian Fainelli293784a2017-01-26 10:45:52 -0800552 port = &ds->ports[index];
Florian Fainelli14be36c2017-06-02 12:31:23 -0700553 if (!dsa_port_is_valid(port) ||
554 dsa_port_is_dsa(port))
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200555 continue;
556
557 if (dsa_port_is_cpu(port)) {
558 err = dsa_cpu_parse(port, index, dst, ds);
559 if (err)
560 return err;
561 }
Florian Fainelli14be36c2017-06-02 12:31:23 -0700562
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200563 }
564
Vivien Didelot49463b72017-11-03 19:05:21 -0400565 pr_info("DSA: switch %d %d parsed\n", dst->index, ds->index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200566
567 return 0;
568}
569
570static int dsa_dst_parse(struct dsa_switch_tree *dst)
571{
572 struct dsa_switch *ds;
Vivien Didelote4b77782017-06-15 15:06:54 -0400573 struct dsa_port *dp;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200574 u32 index;
Vivien Didelote4b77782017-06-15 15:06:54 -0400575 int port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200576 int err;
577
578 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
579 ds = dst->ds[index];
580 if (!ds)
581 continue;
582
583 err = dsa_ds_parse(dst, ds);
584 if (err)
585 return err;
586 }
587
Florian Fainellic7848392017-08-28 17:10:51 -0700588 if (!dst->cpu_dp) {
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200589 pr_warn("Tree has no master device\n");
590 return -EINVAL;
591 }
592
Vivien Didelote4b77782017-06-15 15:06:54 -0400593 /* Assign the default CPU port to all ports of the fabric */
594 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
595 ds = dst->ds[index];
596 if (!ds)
597 continue;
598
599 for (port = 0; port < ds->num_ports; port++) {
600 dp = &ds->ports[port];
601 if (!dsa_port_is_valid(dp) ||
602 dsa_port_is_dsa(dp) ||
603 dsa_port_is_cpu(dp))
604 continue;
605
606 dp->cpu_dp = dst->cpu_dp;
607 }
608 }
609
Vivien Didelot49463b72017-11-03 19:05:21 -0400610 pr_info("DSA: tree %d parsed\n", dst->index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200611
612 return 0;
613}
614
Vivien Didelotfd223e22017-10-27 15:55:14 -0400615static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn)
616{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400617 struct device_node *ethernet = of_parse_phandle(dn, "ethernet", 0);
Vivien Didelot1838fa82017-10-27 15:55:18 -0400618 const char *name = of_get_property(dn, "label", NULL);
Vivien Didelot54df6fa2017-11-03 19:05:28 -0400619 bool link = of_property_read_bool(dn, "link");
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400620
Vivien Didelot06e24d02017-11-03 19:05:29 -0400621 dp->dn = dn;
622
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400623 if (ethernet) {
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400624 struct net_device *master;
625
626 master = of_find_net_device_by_node(ethernet);
627 if (!master)
628 return -EPROBE_DEFER;
629
Vivien Didelot06e24d02017-11-03 19:05:29 -0400630 return dsa_port_parse_cpu(dp, master);
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400631 }
632
Vivien Didelot06e24d02017-11-03 19:05:29 -0400633 if (link)
634 return dsa_port_parse_dsa(dp);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400635
Vivien Didelot06e24d02017-11-03 19:05:29 -0400636 return dsa_port_parse_user(dp, name);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400637}
638
Vivien Didelot975e6e32017-11-03 19:05:27 -0400639static int dsa_switch_parse_ports_of(struct dsa_switch *ds,
640 struct device_node *dn)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200641{
Vivien Didelot5b32fe02017-10-27 15:55:13 -0400642 struct device_node *ports, *port;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400643 struct dsa_port *dp;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200644 u32 reg;
Vivien Didelot5b32fe02017-10-27 15:55:13 -0400645 int err;
646
647 ports = of_get_child_by_name(dn, "ports");
648 if (!ports) {
649 dev_err(ds->dev, "no ports child node found\n");
650 return -EINVAL;
651 }
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200652
653 for_each_available_child_of_node(ports, port) {
654 err = of_property_read_u32(port, "reg", &reg);
655 if (err)
656 return err;
657
Vivien Didelot26895e22017-01-27 15:29:37 -0500658 if (reg >= ds->num_ports)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200659 return -EINVAL;
660
Vivien Didelotfd223e22017-10-27 15:55:14 -0400661 dp = &ds->ports[reg];
662
663 err = dsa_port_parse_of(dp, port);
664 if (err)
665 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200666 }
667
668 return 0;
669}
670
Vivien Didelot975e6e32017-11-03 19:05:27 -0400671static int dsa_switch_parse_member_of(struct dsa_switch *ds,
672 struct device_node *dn)
673{
674 u32 m[2] = { 0, 0 };
675 int sz;
676
677 /* Don't error out if this optional property isn't found */
678 sz = of_property_read_variable_u32_array(dn, "dsa,member", m, 2, 2);
679 if (sz < 0 && sz != -EINVAL)
680 return sz;
681
682 ds->index = m[1];
683 if (ds->index >= DSA_MAX_SWITCHES)
684 return -EINVAL;
685
686 ds->dst = dsa_tree_touch(m[0]);
687 if (!ds->dst)
688 return -ENOMEM;
689
690 return 0;
691}
692
693static int dsa_switch_parse_of(struct dsa_switch *ds, struct device_node *dn)
694{
695 int err;
696
697 err = dsa_switch_parse_member_of(ds, dn);
698 if (err)
699 return err;
700
701 return dsa_switch_parse_ports_of(ds, dn);
702}
703
Vivien Didelotfd223e22017-10-27 15:55:14 -0400704static int dsa_port_parse(struct dsa_port *dp, const char *name,
705 struct device *dev)
706{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400707 if (!strcmp(name, "cpu")) {
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400708 struct net_device *master;
709
710 master = dsa_dev_to_net_device(dev);
711 if (!master)
712 return -EPROBE_DEFER;
713
714 dev_put(master);
715
Vivien Didelot06e24d02017-11-03 19:05:29 -0400716 return dsa_port_parse_cpu(dp, master);
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400717 }
718
Vivien Didelot06e24d02017-11-03 19:05:29 -0400719 if (!strcmp(name, "dsa"))
720 return dsa_port_parse_dsa(dp);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400721
Vivien Didelot06e24d02017-11-03 19:05:29 -0400722 return dsa_port_parse_user(dp, name);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400723}
724
Vivien Didelot975e6e32017-11-03 19:05:27 -0400725static int dsa_switch_parse_ports(struct dsa_switch *ds,
726 struct dsa_chip_data *cd)
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800727{
728 bool valid_name_found = false;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400729 struct dsa_port *dp;
730 struct device *dev;
731 const char *name;
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800732 unsigned int i;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400733 int err;
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800734
735 for (i = 0; i < DSA_MAX_PORTS; i++) {
Vivien Didelotfd223e22017-10-27 15:55:14 -0400736 name = cd->port_names[i];
737 dev = cd->netdev[i];
738 dp = &ds->ports[i];
739
740 if (!name)
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800741 continue;
742
Vivien Didelotfd223e22017-10-27 15:55:14 -0400743 err = dsa_port_parse(dp, name, dev);
744 if (err)
745 return err;
746
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800747 valid_name_found = true;
748 }
749
750 if (!valid_name_found && i == DSA_MAX_PORTS)
751 return -EINVAL;
752
753 return 0;
754}
755
Vivien Didelot975e6e32017-11-03 19:05:27 -0400756static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200757{
Vivien Didelot975e6e32017-11-03 19:05:27 -0400758 ds->cd = cd;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200759
Vivien Didelot975e6e32017-11-03 19:05:27 -0400760 /* We don't support interconnected switches nor multiple trees via
761 * platform data, so this is the unique switch of the tree.
762 */
763 ds->index = 0;
764 ds->dst = dsa_tree_touch(0);
765 if (!ds->dst)
766 return -ENOMEM;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200767
Vivien Didelot975e6e32017-11-03 19:05:27 -0400768 return dsa_switch_parse_ports(ds, cd);
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800769}
770
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400771static int _dsa_register_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200772{
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400773 struct dsa_chip_data *pdata = ds->dev->platform_data;
774 struct device_node *np = ds->dev->of_node;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200775 struct dsa_switch_tree *dst;
Vivien Didelot975e6e32017-11-03 19:05:27 -0400776 unsigned int index;
Vivien Didelotd3902382016-07-06 20:03:54 -0400777 int i, err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200778
Vivien Didelot975e6e32017-11-03 19:05:27 -0400779 if (np)
780 err = dsa_switch_parse_of(ds, np);
781 else if (pdata)
782 err = dsa_switch_parse(ds, pdata);
783 else
784 err = -ENODEV;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200785
Vivien Didelot975e6e32017-11-03 19:05:27 -0400786 if (err)
787 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200788
Vivien Didelot975e6e32017-11-03 19:05:27 -0400789 index = ds->index;
790 dst = ds->dst;
Vivien Didelot0eefe2c2017-11-03 19:05:26 -0400791
Vivien Didelotd3902382016-07-06 20:03:54 -0400792 /* Initialize the routing table */
793 for (i = 0; i < DSA_MAX_SWITCHES; ++i)
794 ds->rtable[i] = DSA_RTABLE_NONE;
795
Vivien Didelot6da2a942017-11-03 19:05:25 -0400796 err = dsa_tree_add_switch(dst, ds);
797 if (err)
798 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200799
800 err = dsa_dst_complete(dst);
801 if (err < 0)
802 goto out_del_dst;
803
Vivien Didelot8e5bf972017-11-03 19:05:22 -0400804 /* Not all switches registered yet */
805 if (err == 1)
806 return 0;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200807
808 if (dst->applied) {
809 pr_info("DSA: Disjoint trees?\n");
810 return -EINVAL;
811 }
812
813 err = dsa_dst_parse(dst);
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400814 if (err)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200815 goto out_del_dst;
816
817 err = dsa_dst_apply(dst);
818 if (err) {
819 dsa_dst_unapply(dst);
820 goto out_del_dst;
821 }
822
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200823 return 0;
824
825out_del_dst:
Vivien Didelot6da2a942017-11-03 19:05:25 -0400826 dsa_tree_remove_switch(dst, index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200827
828 return err;
829}
830
Vivien Didelota0c02162017-01-27 15:29:36 -0500831struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n)
832{
833 size_t size = sizeof(struct dsa_switch) + n * sizeof(struct dsa_port);
834 struct dsa_switch *ds;
Vivien Didelot818be842017-01-27 15:29:38 -0500835 int i;
Vivien Didelota0c02162017-01-27 15:29:36 -0500836
837 ds = devm_kzalloc(dev, size, GFP_KERNEL);
838 if (!ds)
839 return NULL;
840
841 ds->dev = dev;
842 ds->num_ports = n;
843
Vivien Didelot818be842017-01-27 15:29:38 -0500844 for (i = 0; i < ds->num_ports; ++i) {
845 ds->ports[i].index = i;
846 ds->ports[i].ds = ds;
847 }
848
Vivien Didelota0c02162017-01-27 15:29:36 -0500849 return ds;
850}
851EXPORT_SYMBOL_GPL(dsa_switch_alloc);
852
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400853int dsa_register_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200854{
855 int err;
856
857 mutex_lock(&dsa2_mutex);
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400858 err = _dsa_register_switch(ds);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200859 mutex_unlock(&dsa2_mutex);
860
861 return err;
862}
863EXPORT_SYMBOL_GPL(dsa_register_switch);
864
Wei Yongjun85c22ba2016-07-12 15:24:10 +0000865static void _dsa_unregister_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200866{
867 struct dsa_switch_tree *dst = ds->dst;
Vivien Didelot6da2a942017-11-03 19:05:25 -0400868 unsigned int index = ds->index;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200869
870 dsa_dst_unapply(dst);
871
Vivien Didelot6da2a942017-11-03 19:05:25 -0400872 dsa_tree_remove_switch(dst, index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200873}
874
875void dsa_unregister_switch(struct dsa_switch *ds)
876{
877 mutex_lock(&dsa2_mutex);
878 _dsa_unregister_switch(ds);
879 mutex_unlock(&dsa2_mutex);
880}
881EXPORT_SYMBOL_GPL(dsa_unregister_switch);