blob: 5b6a3dad80154fe6116bd1014d8f1ee6b2f87876 [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
Florian Fainelli293784a2017-01-26 10:45:52 -0800494static int dsa_cpu_parse(struct dsa_port *port, u32 index,
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200495 struct dsa_switch_tree *dst,
496 struct dsa_switch *ds)
497{
Vivien Didelot62fc9582017-09-29 17:19:17 -0400498 const struct dsa_device_ops *tag_ops;
Andrew Lunn7b314362016-08-22 16:01:01 +0200499 enum dsa_tag_protocol tag_protocol;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200500
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400501 if (!dst->cpu_dp)
Vivien Didelot8b0d3ea2017-05-16 14:10:33 -0400502 dst->cpu_dp = port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200503
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700504 tag_protocol = ds->ops->get_tag_protocol(ds);
Vivien Didelot62fc9582017-09-29 17:19:17 -0400505 tag_ops = dsa_resolve_tag_protocol(tag_protocol);
506 if (IS_ERR(tag_ops)) {
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700507 dev_warn(ds->dev, "No tagger for this switch\n");
Vivien Didelot62fc9582017-09-29 17:19:17 -0400508 return PTR_ERR(tag_ops);
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700509 }
510
Vivien Didelot15240242017-09-29 17:19:18 -0400511 dst->cpu_dp->tag_ops = tag_ops;
Vivien Didelot3e41f932017-09-29 17:19:19 -0400512
513 /* Make a few copies for faster access in master receive hot path */
514 dst->cpu_dp->rcv = dst->cpu_dp->tag_ops->rcv;
Vivien Didelot3e41f932017-09-29 17:19:19 -0400515 dst->cpu_dp->dst = dst;
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700516
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200517 return 0;
518}
519
520static int dsa_ds_parse(struct dsa_switch_tree *dst, struct dsa_switch *ds)
521{
Florian Fainelli293784a2017-01-26 10:45:52 -0800522 struct dsa_port *port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200523 u32 index;
524 int err;
525
Vivien Didelot26895e22017-01-27 15:29:37 -0500526 for (index = 0; index < ds->num_ports; index++) {
Florian Fainelli293784a2017-01-26 10:45:52 -0800527 port = &ds->ports[index];
Florian Fainelli14be36c2017-06-02 12:31:23 -0700528 if (!dsa_port_is_valid(port) ||
529 dsa_port_is_dsa(port))
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200530 continue;
531
532 if (dsa_port_is_cpu(port)) {
533 err = dsa_cpu_parse(port, index, dst, ds);
534 if (err)
535 return err;
536 }
Florian Fainelli14be36c2017-06-02 12:31:23 -0700537
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200538 }
539
Vivien Didelot49463b72017-11-03 19:05:21 -0400540 pr_info("DSA: switch %d %d parsed\n", dst->index, ds->index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200541
542 return 0;
543}
544
545static int dsa_dst_parse(struct dsa_switch_tree *dst)
546{
547 struct dsa_switch *ds;
Vivien Didelote4b77782017-06-15 15:06:54 -0400548 struct dsa_port *dp;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200549 u32 index;
Vivien Didelote4b77782017-06-15 15:06:54 -0400550 int port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200551 int err;
552
553 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
554 ds = dst->ds[index];
555 if (!ds)
556 continue;
557
558 err = dsa_ds_parse(dst, ds);
559 if (err)
560 return err;
561 }
562
Florian Fainellic7848392017-08-28 17:10:51 -0700563 if (!dst->cpu_dp) {
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200564 pr_warn("Tree has no master device\n");
565 return -EINVAL;
566 }
567
Vivien Didelote4b77782017-06-15 15:06:54 -0400568 /* Assign the default CPU port to all ports of the fabric */
569 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
570 ds = dst->ds[index];
571 if (!ds)
572 continue;
573
574 for (port = 0; port < ds->num_ports; port++) {
575 dp = &ds->ports[port];
576 if (!dsa_port_is_valid(dp) ||
577 dsa_port_is_dsa(dp) ||
578 dsa_port_is_cpu(dp))
579 continue;
580
581 dp->cpu_dp = dst->cpu_dp;
582 }
583 }
584
Vivien Didelot49463b72017-11-03 19:05:21 -0400585 pr_info("DSA: tree %d parsed\n", dst->index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200586
587 return 0;
588}
589
Vivien Didelotfd223e22017-10-27 15:55:14 -0400590static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn)
591{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400592 struct device_node *ethernet = of_parse_phandle(dn, "ethernet", 0);
593 struct device_node *link = of_parse_phandle(dn, "link", 0);
Vivien Didelot1838fa82017-10-27 15:55:18 -0400594 const char *name = of_get_property(dn, "label", NULL);
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400595
596 if (ethernet) {
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400597 struct net_device *master;
598
599 master = of_find_net_device_by_node(ethernet);
600 if (!master)
601 return -EPROBE_DEFER;
602
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400603 dp->type = DSA_PORT_TYPE_CPU;
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400604 dp->master = master;
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400605 } else if (link) {
606 dp->type = DSA_PORT_TYPE_DSA;
607 } else {
Vivien Didelot1838fa82017-10-27 15:55:18 -0400608 if (!name)
609 name = "eth%d";
610
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400611 dp->type = DSA_PORT_TYPE_USER;
Vivien Didelot1838fa82017-10-27 15:55:18 -0400612 dp->name = name;
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400613 }
614
Vivien Didelotfd223e22017-10-27 15:55:14 -0400615 dp->dn = dn;
616
617 return 0;
618}
619
Vivien Didelot5b32fe02017-10-27 15:55:13 -0400620static int dsa_parse_ports_of(struct device_node *dn, struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200621{
Vivien Didelot5b32fe02017-10-27 15:55:13 -0400622 struct device_node *ports, *port;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400623 struct dsa_port *dp;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200624 u32 reg;
Vivien Didelot5b32fe02017-10-27 15:55:13 -0400625 int err;
626
627 ports = of_get_child_by_name(dn, "ports");
628 if (!ports) {
629 dev_err(ds->dev, "no ports child node found\n");
630 return -EINVAL;
631 }
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200632
633 for_each_available_child_of_node(ports, port) {
634 err = of_property_read_u32(port, "reg", &reg);
635 if (err)
636 return err;
637
Vivien Didelot26895e22017-01-27 15:29:37 -0500638 if (reg >= ds->num_ports)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200639 return -EINVAL;
640
Vivien Didelotfd223e22017-10-27 15:55:14 -0400641 dp = &ds->ports[reg];
642
643 err = dsa_port_parse_of(dp, port);
644 if (err)
645 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200646 }
647
648 return 0;
649}
650
Vivien Didelotfd223e22017-10-27 15:55:14 -0400651static int dsa_port_parse(struct dsa_port *dp, const char *name,
652 struct device *dev)
653{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400654 if (!strcmp(name, "cpu")) {
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400655 struct net_device *master;
656
657 master = dsa_dev_to_net_device(dev);
658 if (!master)
659 return -EPROBE_DEFER;
660
661 dev_put(master);
662
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400663 dp->type = DSA_PORT_TYPE_CPU;
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400664 dp->master = master;
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400665 } else if (!strcmp(name, "dsa")) {
666 dp->type = DSA_PORT_TYPE_DSA;
667 } else {
668 dp->type = DSA_PORT_TYPE_USER;
669 }
670
Vivien Didelotfd223e22017-10-27 15:55:14 -0400671 dp->name = name;
672
673 return 0;
674}
675
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800676static int dsa_parse_ports(struct dsa_chip_data *cd, struct dsa_switch *ds)
677{
678 bool valid_name_found = false;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400679 struct dsa_port *dp;
680 struct device *dev;
681 const char *name;
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800682 unsigned int i;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400683 int err;
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800684
685 for (i = 0; i < DSA_MAX_PORTS; i++) {
Vivien Didelotfd223e22017-10-27 15:55:14 -0400686 name = cd->port_names[i];
687 dev = cd->netdev[i];
688 dp = &ds->ports[i];
689
690 if (!name)
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800691 continue;
692
Vivien Didelotfd223e22017-10-27 15:55:14 -0400693 err = dsa_port_parse(dp, name, dev);
694 if (err)
695 return err;
696
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800697 valid_name_found = true;
698 }
699
700 if (!valid_name_found && i == DSA_MAX_PORTS)
701 return -EINVAL;
702
703 return 0;
704}
705
Florian Fainelli3512a8e2017-01-26 10:45:53 -0800706static int dsa_parse_member_dn(struct device_node *np, u32 *tree, u32 *index)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200707{
708 int err;
709
710 *tree = *index = 0;
711
712 err = of_property_read_u32_index(np, "dsa,member", 0, tree);
713 if (err) {
714 /* Does not exist, but it is optional */
715 if (err == -EINVAL)
716 return 0;
717 return err;
718 }
719
720 err = of_property_read_u32_index(np, "dsa,member", 1, index);
721 if (err)
722 return err;
723
724 if (*index >= DSA_MAX_SWITCHES)
725 return -EINVAL;
726
727 return 0;
728}
729
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800730static int dsa_parse_member(struct dsa_chip_data *pd, u32 *tree, u32 *index)
731{
732 if (!pd)
733 return -ENODEV;
734
735 /* We do not support complex trees with dsa_chip_data */
736 *tree = 0;
737 *index = 0;
738
739 return 0;
740}
741
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400742static int _dsa_register_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200743{
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400744 struct dsa_chip_data *pdata = ds->dev->platform_data;
745 struct device_node *np = ds->dev->of_node;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200746 struct dsa_switch_tree *dst;
747 u32 tree, index;
Vivien Didelotd3902382016-07-06 20:03:54 -0400748 int i, err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200749
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800750 if (np) {
751 err = dsa_parse_member_dn(np, &tree, &index);
752 if (err)
753 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200754
Vivien Didelot5b32fe02017-10-27 15:55:13 -0400755 err = dsa_parse_ports_of(np, ds);
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800756 if (err)
757 return err;
758 } else {
759 err = dsa_parse_member(pdata, &tree, &index);
760 if (err)
761 return err;
762
763 err = dsa_parse_ports(pdata, ds);
764 if (err)
765 return err;
766 }
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200767
Vivien Didelot1ca28ec2017-11-03 19:05:24 -0400768 dst = dsa_tree_touch(tree);
769 if (!dst)
770 return -ENOMEM;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200771
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200772 ds->dst = dst;
773 ds->index = index;
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800774 ds->cd = pdata;
Vivien Didelotd3902382016-07-06 20:03:54 -0400775
776 /* Initialize the routing table */
777 for (i = 0; i < DSA_MAX_SWITCHES; ++i)
778 ds->rtable[i] = DSA_RTABLE_NONE;
779
Vivien Didelot6da2a942017-11-03 19:05:25 -0400780 err = dsa_tree_add_switch(dst, ds);
781 if (err)
782 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200783
784 err = dsa_dst_complete(dst);
785 if (err < 0)
786 goto out_del_dst;
787
Vivien Didelot8e5bf972017-11-03 19:05:22 -0400788 /* Not all switches registered yet */
789 if (err == 1)
790 return 0;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200791
792 if (dst->applied) {
793 pr_info("DSA: Disjoint trees?\n");
794 return -EINVAL;
795 }
796
797 err = dsa_dst_parse(dst);
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400798 if (err)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200799 goto out_del_dst;
800
801 err = dsa_dst_apply(dst);
802 if (err) {
803 dsa_dst_unapply(dst);
804 goto out_del_dst;
805 }
806
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200807 return 0;
808
809out_del_dst:
Vivien Didelot6da2a942017-11-03 19:05:25 -0400810 dsa_tree_remove_switch(dst, index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200811
812 return err;
813}
814
Vivien Didelota0c02162017-01-27 15:29:36 -0500815struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n)
816{
817 size_t size = sizeof(struct dsa_switch) + n * sizeof(struct dsa_port);
818 struct dsa_switch *ds;
Vivien Didelot818be842017-01-27 15:29:38 -0500819 int i;
Vivien Didelota0c02162017-01-27 15:29:36 -0500820
821 ds = devm_kzalloc(dev, size, GFP_KERNEL);
822 if (!ds)
823 return NULL;
824
825 ds->dev = dev;
826 ds->num_ports = n;
827
Vivien Didelot818be842017-01-27 15:29:38 -0500828 for (i = 0; i < ds->num_ports; ++i) {
829 ds->ports[i].index = i;
830 ds->ports[i].ds = ds;
831 }
832
Vivien Didelota0c02162017-01-27 15:29:36 -0500833 return ds;
834}
835EXPORT_SYMBOL_GPL(dsa_switch_alloc);
836
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400837int dsa_register_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200838{
839 int err;
840
841 mutex_lock(&dsa2_mutex);
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400842 err = _dsa_register_switch(ds);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200843 mutex_unlock(&dsa2_mutex);
844
845 return err;
846}
847EXPORT_SYMBOL_GPL(dsa_register_switch);
848
Wei Yongjun85c22ba2016-07-12 15:24:10 +0000849static void _dsa_unregister_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200850{
851 struct dsa_switch_tree *dst = ds->dst;
Vivien Didelot6da2a942017-11-03 19:05:25 -0400852 unsigned int index = ds->index;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200853
854 dsa_dst_unapply(dst);
855
Vivien Didelot6da2a942017-11-03 19:05:25 -0400856 dsa_tree_remove_switch(dst, index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200857}
858
859void dsa_unregister_switch(struct dsa_switch *ds)
860{
861 mutex_lock(&dsa2_mutex);
862 _dsa_unregister_switch(ds);
863 mutex_unlock(&dsa2_mutex);
864}
865EXPORT_SYMBOL_GPL(dsa_unregister_switch);