blob: 0a63a2119cd07eccb05d02aebd241b0e0413a373 [file] [log] [blame]
Andrew Lunn83c0afa2016-06-04 21:17:07 +02001/*
2 * net/dsa/dsa2.c - Hardware switch handling, binding version 2
3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 * Copyright (c) 2013 Florian Fainelli <florian@openwrt.org>
5 * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <linux/device.h>
14#include <linux/err.h>
15#include <linux/list.h>
Andrew Lunnc6e970a2017-03-28 23:45:06 +020016#include <linux/netdevice.h>
Andrew Lunn83c0afa2016-06-04 21:17:07 +020017#include <linux/slab.h>
18#include <linux/rtnetlink.h>
Andrew Lunn83c0afa2016-06-04 21:17:07 +020019#include <linux/of.h>
20#include <linux/of_net.h>
Vivien Didelotea5dd342017-05-17 15:46:03 -040021
Andrew Lunn83c0afa2016-06-04 21:17:07 +020022#include "dsa_priv.h"
23
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040024static LIST_HEAD(dsa_tree_list);
Andrew Lunn83c0afa2016-06-04 21:17:07 +020025static DEFINE_MUTEX(dsa2_mutex);
26
Andrew Lunn96567d52017-03-28 23:45:07 +020027static const struct devlink_ops dsa_devlink_ops = {
28};
29
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040030static struct dsa_switch_tree *dsa_tree_find(int index)
Andrew Lunn83c0afa2016-06-04 21:17:07 +020031{
32 struct dsa_switch_tree *dst;
33
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040034 list_for_each_entry(dst, &dsa_tree_list, list)
Vivien Didelot8e5bf972017-11-03 19:05:22 -040035 if (dst->index == index)
Andrew Lunn83c0afa2016-06-04 21:17:07 +020036 return dst;
Vivien Didelot8e5bf972017-11-03 19:05:22 -040037
Andrew Lunn83c0afa2016-06-04 21:17:07 +020038 return NULL;
39}
40
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040041static struct dsa_switch_tree *dsa_tree_alloc(int index)
Andrew Lunn83c0afa2016-06-04 21:17:07 +020042{
43 struct dsa_switch_tree *dst;
44
45 dst = kzalloc(sizeof(*dst), GFP_KERNEL);
46 if (!dst)
47 return NULL;
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040048
Vivien Didelot49463b72017-11-03 19:05:21 -040049 dst->index = index;
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040050
Andrew Lunn83c0afa2016-06-04 21:17:07 +020051 INIT_LIST_HEAD(&dst->list);
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040052 list_add_tail(&dsa_tree_list, &dst->list);
Vivien Didelot8e5bf972017-11-03 19:05:22 -040053
54 /* Initialize the reference counter to the number of switches, not 1 */
Andrew Lunn83c0afa2016-06-04 21:17:07 +020055 kref_init(&dst->refcount);
Vivien Didelot8e5bf972017-11-03 19:05:22 -040056 refcount_set(&dst->refcount.refcount, 0);
Andrew Lunn83c0afa2016-06-04 21:17:07 +020057
58 return dst;
59}
60
Vivien Didelot65254102017-11-03 19:05:23 -040061static void dsa_tree_free(struct dsa_switch_tree *dst)
62{
63 list_del(&dst->list);
64 kfree(dst);
65}
66
Vivien Didelot1ca28ec2017-11-03 19:05:24 -040067static struct dsa_switch_tree *dsa_tree_touch(int index)
68{
69 struct dsa_switch_tree *dst;
70
71 dst = dsa_tree_find(index);
72 if (!dst)
73 dst = dsa_tree_alloc(index);
74
75 return dst;
76}
77
Vivien Didelot65254102017-11-03 19:05:23 -040078static void dsa_tree_get(struct dsa_switch_tree *dst)
79{
80 kref_get(&dst->refcount);
81}
82
83static void dsa_tree_release(struct kref *ref)
84{
85 struct dsa_switch_tree *dst;
86
87 dst = container_of(ref, struct dsa_switch_tree, refcount);
88
89 dsa_tree_free(dst);
90}
91
92static void dsa_tree_put(struct dsa_switch_tree *dst)
93{
94 kref_put(&dst->refcount, dsa_tree_release);
95}
96
Florian Fainelli71e0bbd2017-02-04 13:02:43 -080097/* For platform data configurations, we need to have a valid name argument to
98 * differentiate a disabled port from an enabled one
99 */
Florian Fainelli293784a2017-01-26 10:45:52 -0800100static bool dsa_port_is_valid(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200101{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400102 return port->type != DSA_PORT_TYPE_UNUSED;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200103}
104
Florian Fainelli293784a2017-01-26 10:45:52 -0800105static bool dsa_port_is_dsa(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200106{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400107 return port->type == DSA_PORT_TYPE_DSA;
Florian Fainelli293784a2017-01-26 10:45:52 -0800108}
109
110static bool dsa_port_is_cpu(struct dsa_port *port)
111{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400112 return port->type == DSA_PORT_TYPE_CPU;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200113}
114
Vivien Didelotf0704642017-11-06 16:11:44 -0500115static bool dsa_port_is_user(struct dsa_port *dp)
116{
117 return dp->type == DSA_PORT_TYPE_USER;
118}
119
Florian Fainelli3512a8e2017-01-26 10:45:53 -0800120static bool dsa_ds_find_port_dn(struct dsa_switch *ds,
121 struct device_node *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200122{
123 u32 index;
124
Vivien Didelot26895e22017-01-27 15:29:37 -0500125 for (index = 0; index < ds->num_ports; index++)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200126 if (ds->ports[index].dn == port)
127 return true;
128 return false;
129}
130
Florian Fainelli3512a8e2017-01-26 10:45:53 -0800131static struct dsa_switch *dsa_dst_find_port_dn(struct dsa_switch_tree *dst,
132 struct device_node *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200133{
134 struct dsa_switch *ds;
135 u32 index;
136
137 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
138 ds = dst->ds[index];
139 if (!ds)
140 continue;
141
Florian Fainelli3512a8e2017-01-26 10:45:53 -0800142 if (dsa_ds_find_port_dn(ds, port))
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200143 return ds;
144 }
145
146 return NULL;
147}
148
149static int dsa_port_complete(struct dsa_switch_tree *dst,
150 struct dsa_switch *src_ds,
Florian Fainelli293784a2017-01-26 10:45:52 -0800151 struct dsa_port *port,
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200152 u32 src_port)
153{
154 struct device_node *link;
155 int index;
156 struct dsa_switch *dst_ds;
157
158 for (index = 0;; index++) {
Florian Fainelli293784a2017-01-26 10:45:52 -0800159 link = of_parse_phandle(port->dn, "link", index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200160 if (!link)
161 break;
162
Florian Fainelli3512a8e2017-01-26 10:45:53 -0800163 dst_ds = dsa_dst_find_port_dn(dst, link);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200164 of_node_put(link);
165
166 if (!dst_ds)
167 return 1;
168
169 src_ds->rtable[dst_ds->index] = src_port;
170 }
171
172 return 0;
173}
174
175/* A switch is complete if all the DSA ports phandles point to ports
176 * known in the tree. A return value of 1 means the tree is not
177 * complete. This is not an error condition. A value of 0 is
178 * success.
179 */
180static int dsa_ds_complete(struct dsa_switch_tree *dst, struct dsa_switch *ds)
181{
Florian Fainelli293784a2017-01-26 10:45:52 -0800182 struct dsa_port *port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200183 u32 index;
184 int err;
185
Vivien Didelot26895e22017-01-27 15:29:37 -0500186 for (index = 0; index < ds->num_ports; index++) {
Florian Fainelli293784a2017-01-26 10:45:52 -0800187 port = &ds->ports[index];
188 if (!dsa_port_is_valid(port))
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200189 continue;
190
191 if (!dsa_port_is_dsa(port))
192 continue;
193
194 err = dsa_port_complete(dst, ds, port, index);
195 if (err != 0)
196 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200197 }
198
199 return 0;
200}
201
202/* A tree is complete if all the DSA ports phandles point to ports
203 * known in the tree. A return value of 1 means the tree is not
204 * complete. This is not an error condition. A value of 0 is
205 * success.
206 */
207static int dsa_dst_complete(struct dsa_switch_tree *dst)
208{
209 struct dsa_switch *ds;
210 u32 index;
211 int err;
212
213 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
214 ds = dst->ds[index];
215 if (!ds)
216 continue;
217
218 err = dsa_ds_complete(dst, ds);
219 if (err != 0)
220 return err;
221 }
222
223 return 0;
224}
225
Vivien Didelotf0704642017-11-06 16:11:44 -0500226static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst)
227{
228 struct dsa_switch *ds;
229 struct dsa_port *dp;
230 int device, port;
231
232 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
233 ds = dst->ds[device];
234 if (!ds)
235 continue;
236
237 for (port = 0; port < ds->num_ports; port++) {
238 dp = &ds->ports[port];
239
240 if (dsa_port_is_cpu(dp))
241 return dp;
242 }
243 }
244
245 return NULL;
246}
247
248static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst)
249{
250 struct dsa_switch *ds;
251 struct dsa_port *dp;
252 int device, port;
253
254 /* DSA currently only supports a single CPU port */
255 dst->cpu_dp = dsa_tree_find_first_cpu(dst);
256 if (!dst->cpu_dp) {
257 pr_warn("Tree has no master device\n");
258 return -EINVAL;
259 }
260
261 /* Assign the default CPU port to all ports of the fabric */
262 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
263 ds = dst->ds[device];
264 if (!ds)
265 continue;
266
267 for (port = 0; port < ds->num_ports; port++) {
268 dp = &ds->ports[port];
269
270 if (dsa_port_is_user(dp))
271 dp->cpu_dp = dst->cpu_dp;
272 }
273 }
274
275 return 0;
276}
277
278static void dsa_tree_teardown_default_cpu(struct dsa_switch_tree *dst)
279{
280 /* DSA currently only supports a single CPU port */
281 dst->cpu_dp = NULL;
282}
283
Florian Fainellie41c1b52017-06-02 12:31:22 -0700284static int dsa_dsa_port_apply(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200285{
Florian Fainellie41c1b52017-06-02 12:31:22 -0700286 struct dsa_switch *ds = port->ds;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200287 int err;
288
Vivien Didelot57ab1ca2017-10-26 10:50:07 -0400289 err = dsa_port_fixed_link_register_of(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200290 if (err) {
291 dev_warn(ds->dev, "Failed to setup dsa port %d: %d\n",
Florian Fainellie41c1b52017-06-02 12:31:22 -0700292 port->index, err);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200293 return err;
294 }
295
Florian Fainellie41c1b52017-06-02 12:31:22 -0700296 memset(&port->devlink_port, 0, sizeof(port->devlink_port));
Andrew Lunn96567d52017-03-28 23:45:07 +0200297
Florian Fainellie41c1b52017-06-02 12:31:22 -0700298 return devlink_port_register(ds->devlink, &port->devlink_port,
299 port->index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200300}
301
Florian Fainellie41c1b52017-06-02 12:31:22 -0700302static void dsa_dsa_port_unapply(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200303{
Florian Fainellie41c1b52017-06-02 12:31:22 -0700304 devlink_port_unregister(&port->devlink_port);
Vivien Didelot57ab1ca2017-10-26 10:50:07 -0400305 dsa_port_fixed_link_unregister_of(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200306}
307
Florian Fainellie41c1b52017-06-02 12:31:22 -0700308static int dsa_cpu_port_apply(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200309{
Florian Fainellie41c1b52017-06-02 12:31:22 -0700310 struct dsa_switch *ds = port->ds;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200311 int err;
312
Vivien Didelot57ab1ca2017-10-26 10:50:07 -0400313 err = dsa_port_fixed_link_register_of(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200314 if (err) {
315 dev_warn(ds->dev, "Failed to setup cpu port %d: %d\n",
Florian Fainellie41c1b52017-06-02 12:31:22 -0700316 port->index, err);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200317 return err;
318 }
319
Florian Fainellie41c1b52017-06-02 12:31:22 -0700320 memset(&port->devlink_port, 0, sizeof(port->devlink_port));
321 err = devlink_port_register(ds->devlink, &port->devlink_port,
322 port->index);
Andrew Lunn96567d52017-03-28 23:45:07 +0200323 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200324}
325
Florian Fainellie41c1b52017-06-02 12:31:22 -0700326static void dsa_cpu_port_unapply(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200327{
Florian Fainellie41c1b52017-06-02 12:31:22 -0700328 devlink_port_unregister(&port->devlink_port);
Vivien Didelot57ab1ca2017-10-26 10:50:07 -0400329 dsa_port_fixed_link_unregister_of(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200330}
331
Florian Fainellie41c1b52017-06-02 12:31:22 -0700332static int dsa_user_port_apply(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200333{
Florian Fainellie41c1b52017-06-02 12:31:22 -0700334 struct dsa_switch *ds = port->ds;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200335 int err;
336
Vivien Didelot951259aa2017-10-27 15:55:19 -0400337 err = dsa_slave_create(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200338 if (err) {
339 dev_warn(ds->dev, "Failed to create slave %d: %d\n",
Florian Fainellie41c1b52017-06-02 12:31:22 -0700340 port->index, err);
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400341 port->slave = NULL;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200342 return err;
343 }
344
Florian Fainellie41c1b52017-06-02 12:31:22 -0700345 memset(&port->devlink_port, 0, sizeof(port->devlink_port));
346 err = devlink_port_register(ds->devlink, &port->devlink_port,
347 port->index);
Andrew Lunn96567d52017-03-28 23:45:07 +0200348 if (err)
349 return err;
350
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400351 devlink_port_type_eth_set(&port->devlink_port, port->slave);
Andrew Lunn96567d52017-03-28 23:45:07 +0200352
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200353 return 0;
354}
355
Florian Fainellie41c1b52017-06-02 12:31:22 -0700356static void dsa_user_port_unapply(struct dsa_port *port)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200357{
Florian Fainellie41c1b52017-06-02 12:31:22 -0700358 devlink_port_unregister(&port->devlink_port);
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400359 if (port->slave) {
360 dsa_slave_destroy(port->slave);
361 port->slave = NULL;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200362 }
363}
364
365static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds)
366{
Florian Fainelli293784a2017-01-26 10:45:52 -0800367 struct dsa_port *port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200368 u32 index;
369 int err;
370
Florian Fainelli6e830d82016-06-07 16:32:39 -0700371 /* Initialize ds->phys_mii_mask before registering the slave MDIO bus
Vivien Didelot9d490b42016-08-23 12:38:56 -0400372 * driver and before ops->setup() has run, since the switch drivers and
Florian Fainelli6e830d82016-06-07 16:32:39 -0700373 * the slave MDIO bus driver rely on these values for probing PHY
374 * devices or not
375 */
Vivien Didelot02bc6e52017-10-26 11:22:56 -0400376 ds->phys_mii_mask |= dsa_user_ports(ds);
Florian Fainelli6e830d82016-06-07 16:32:39 -0700377
Andrew Lunn96567d52017-03-28 23:45:07 +0200378 /* Add the switch to devlink before calling setup, so that setup can
379 * add dpipe tables
380 */
381 ds->devlink = devlink_alloc(&dsa_devlink_ops, 0);
382 if (!ds->devlink)
383 return -ENOMEM;
384
385 err = devlink_register(ds->devlink, ds->dev);
386 if (err)
387 return err;
388
Vivien Didelot9d490b42016-08-23 12:38:56 -0400389 err = ds->ops->setup(ds);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200390 if (err < 0)
391 return err;
392
Vivien Didelotf515f192017-02-03 13:20:20 -0500393 err = dsa_switch_register_notifier(ds);
394 if (err)
395 return err;
396
Vivien Didelot9d490b42016-08-23 12:38:56 -0400397 if (!ds->slave_mii_bus && ds->ops->phy_read) {
Florian Fainelli1eb59442016-06-07 16:32:40 -0700398 ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
399 if (!ds->slave_mii_bus)
400 return -ENOMEM;
401
402 dsa_slave_mii_bus_init(ds);
403
404 err = mdiobus_register(ds->slave_mii_bus);
405 if (err < 0)
406 return err;
407 }
408
Vivien Didelot26895e22017-01-27 15:29:37 -0500409 for (index = 0; index < ds->num_ports; index++) {
Florian Fainelli293784a2017-01-26 10:45:52 -0800410 port = &ds->ports[index];
411 if (!dsa_port_is_valid(port))
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200412 continue;
413
414 if (dsa_port_is_dsa(port)) {
Florian Fainellie41c1b52017-06-02 12:31:22 -0700415 err = dsa_dsa_port_apply(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200416 if (err)
417 return err;
418 continue;
419 }
420
421 if (dsa_port_is_cpu(port)) {
Florian Fainellie41c1b52017-06-02 12:31:22 -0700422 err = dsa_cpu_port_apply(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200423 if (err)
424 return err;
425 continue;
426 }
427
Florian Fainellie41c1b52017-06-02 12:31:22 -0700428 err = dsa_user_port_apply(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200429 if (err)
430 continue;
431 }
432
433 return 0;
434}
435
436static void dsa_ds_unapply(struct dsa_switch_tree *dst, struct dsa_switch *ds)
437{
Florian Fainelli293784a2017-01-26 10:45:52 -0800438 struct dsa_port *port;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200439 u32 index;
440
Vivien Didelot26895e22017-01-27 15:29:37 -0500441 for (index = 0; index < ds->num_ports; index++) {
Florian Fainelli293784a2017-01-26 10:45:52 -0800442 port = &ds->ports[index];
443 if (!dsa_port_is_valid(port))
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200444 continue;
445
446 if (dsa_port_is_dsa(port)) {
Florian Fainellie41c1b52017-06-02 12:31:22 -0700447 dsa_dsa_port_unapply(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200448 continue;
449 }
450
451 if (dsa_port_is_cpu(port)) {
Florian Fainellie41c1b52017-06-02 12:31:22 -0700452 dsa_cpu_port_unapply(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200453 continue;
454 }
455
Florian Fainellie41c1b52017-06-02 12:31:22 -0700456 dsa_user_port_unapply(port);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200457 }
Florian Fainelli1eb59442016-06-07 16:32:40 -0700458
Vivien Didelot9d490b42016-08-23 12:38:56 -0400459 if (ds->slave_mii_bus && ds->ops->phy_read)
Florian Fainelli1eb59442016-06-07 16:32:40 -0700460 mdiobus_unregister(ds->slave_mii_bus);
Vivien Didelotf515f192017-02-03 13:20:20 -0500461
462 dsa_switch_unregister_notifier(ds);
Andrew Lunn96567d52017-03-28 23:45:07 +0200463
464 if (ds->devlink) {
465 devlink_unregister(ds->devlink);
466 devlink_free(ds->devlink);
467 ds->devlink = NULL;
468 }
469
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200470}
471
472static int dsa_dst_apply(struct dsa_switch_tree *dst)
473{
474 struct dsa_switch *ds;
475 u32 index;
476 int err;
477
Vivien Didelotf0704642017-11-06 16:11:44 -0500478 err = dsa_tree_setup_default_cpu(dst);
479 if (err)
480 return err;
481
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200482 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
483 ds = dst->ds[index];
484 if (!ds)
485 continue;
486
487 err = dsa_ds_apply(dst, ds);
488 if (err)
489 return err;
490 }
491
492 /* If we use a tagging format that doesn't have an ethertype
493 * field, make sure that all packets from this point on get
494 * sent to the tag format's receive function.
495 */
496 wmb();
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400497 dst->cpu_dp->master->dsa_ptr = dst->cpu_dp;
Vivien Didelot19435632017-09-19 11:56:59 -0400498
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400499 err = dsa_master_ethtool_setup(dst->cpu_dp->master);
Vivien Didelot19435632017-09-19 11:56:59 -0400500 if (err)
501 return err;
502
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200503 dst->applied = true;
504
505 return 0;
506}
507
508static void dsa_dst_unapply(struct dsa_switch_tree *dst)
509{
510 struct dsa_switch *ds;
511 u32 index;
512
513 if (!dst->applied)
514 return;
515
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400516 dsa_master_ethtool_restore(dst->cpu_dp->master);
Vivien Didelot19435632017-09-19 11:56:59 -0400517
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -0400518 dst->cpu_dp->master->dsa_ptr = NULL;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200519
520 /* If we used a tagging format that doesn't have an ethertype
521 * field, make sure that all packets from this point get sent
522 * without the tag and go through the regular receive path.
523 */
524 wmb();
525
526 for (index = 0; index < DSA_MAX_SWITCHES; index++) {
527 ds = dst->ds[index];
528 if (!ds)
529 continue;
530
531 dsa_ds_unapply(dst, ds);
532 }
533
Vivien Didelotf0704642017-11-06 16:11:44 -0500534 dsa_tree_teardown_default_cpu(dst);
Florian Fainelli0c73c522016-06-07 16:32:42 -0700535
Vivien Didelot49463b72017-11-03 19:05:21 -0400536 pr_info("DSA: tree %d unapplied\n", dst->index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200537 dst->applied = false;
538}
539
Vivien Didelot6da2a942017-11-03 19:05:25 -0400540static void dsa_tree_remove_switch(struct dsa_switch_tree *dst,
541 unsigned int index)
542{
543 dst->ds[index] = NULL;
544 dsa_tree_put(dst);
545}
546
547static int dsa_tree_add_switch(struct dsa_switch_tree *dst,
548 struct dsa_switch *ds)
549{
550 unsigned int index = ds->index;
551
552 if (dst->ds[index])
553 return -EBUSY;
554
555 dsa_tree_get(dst);
556 dst->ds[index] = ds;
557
558 return 0;
559}
560
Vivien Didelot06e24d02017-11-03 19:05:29 -0400561static int dsa_port_parse_user(struct dsa_port *dp, const char *name)
562{
563 if (!name)
564 name = "eth%d";
565
566 dp->type = DSA_PORT_TYPE_USER;
567 dp->name = name;
568
569 return 0;
570}
571
572static int dsa_port_parse_dsa(struct dsa_port *dp)
573{
574 dp->type = DSA_PORT_TYPE_DSA;
575
576 return 0;
577}
578
579static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master)
580{
Vivien Didelot7354fcb2017-11-03 19:05:30 -0400581 struct dsa_switch *ds = dp->ds;
582 struct dsa_switch_tree *dst = ds->dst;
Vivien Didelot62fc9582017-09-29 17:19:17 -0400583 const struct dsa_device_ops *tag_ops;
Andrew Lunn7b314362016-08-22 16:01:01 +0200584 enum dsa_tag_protocol tag_protocol;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200585
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700586 tag_protocol = ds->ops->get_tag_protocol(ds);
Vivien Didelot62fc9582017-09-29 17:19:17 -0400587 tag_ops = dsa_resolve_tag_protocol(tag_protocol);
588 if (IS_ERR(tag_ops)) {
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700589 dev_warn(ds->dev, "No tagger for this switch\n");
Vivien Didelot62fc9582017-09-29 17:19:17 -0400590 return PTR_ERR(tag_ops);
Florian Fainelli9f9e7722017-07-24 10:49:23 -0700591 }
592
Vivien Didelot7354fcb2017-11-03 19:05:30 -0400593 dp->type = DSA_PORT_TYPE_CPU;
594 dp->rcv = tag_ops->rcv;
595 dp->tag_ops = tag_ops;
596 dp->master = master;
597 dp->dst = dst;
Vivien Didelot3e41f932017-09-29 17:19:19 -0400598
Vivien Didelot7354fcb2017-11-03 19:05:30 -0400599 return 0;
600}
601
Vivien Didelotfd223e22017-10-27 15:55:14 -0400602static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn)
603{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400604 struct device_node *ethernet = of_parse_phandle(dn, "ethernet", 0);
Vivien Didelot1838fa82017-10-27 15:55:18 -0400605 const char *name = of_get_property(dn, "label", NULL);
Vivien Didelot54df6fa2017-11-03 19:05:28 -0400606 bool link = of_property_read_bool(dn, "link");
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400607
Vivien Didelot06e24d02017-11-03 19:05:29 -0400608 dp->dn = dn;
609
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400610 if (ethernet) {
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400611 struct net_device *master;
612
613 master = of_find_net_device_by_node(ethernet);
614 if (!master)
615 return -EPROBE_DEFER;
616
Vivien Didelot06e24d02017-11-03 19:05:29 -0400617 return dsa_port_parse_cpu(dp, master);
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400618 }
619
Vivien Didelot06e24d02017-11-03 19:05:29 -0400620 if (link)
621 return dsa_port_parse_dsa(dp);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400622
Vivien Didelot06e24d02017-11-03 19:05:29 -0400623 return dsa_port_parse_user(dp, name);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400624}
625
Vivien Didelot975e6e32017-11-03 19:05:27 -0400626static int dsa_switch_parse_ports_of(struct dsa_switch *ds,
627 struct device_node *dn)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200628{
Vivien Didelot5b32fe02017-10-27 15:55:13 -0400629 struct device_node *ports, *port;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400630 struct dsa_port *dp;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200631 u32 reg;
Vivien Didelot5b32fe02017-10-27 15:55:13 -0400632 int err;
633
634 ports = of_get_child_by_name(dn, "ports");
635 if (!ports) {
636 dev_err(ds->dev, "no ports child node found\n");
637 return -EINVAL;
638 }
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200639
640 for_each_available_child_of_node(ports, port) {
641 err = of_property_read_u32(port, "reg", &reg);
642 if (err)
643 return err;
644
Vivien Didelot26895e22017-01-27 15:29:37 -0500645 if (reg >= ds->num_ports)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200646 return -EINVAL;
647
Vivien Didelotfd223e22017-10-27 15:55:14 -0400648 dp = &ds->ports[reg];
649
650 err = dsa_port_parse_of(dp, port);
651 if (err)
652 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200653 }
654
655 return 0;
656}
657
Vivien Didelot975e6e32017-11-03 19:05:27 -0400658static int dsa_switch_parse_member_of(struct dsa_switch *ds,
659 struct device_node *dn)
660{
661 u32 m[2] = { 0, 0 };
662 int sz;
663
664 /* Don't error out if this optional property isn't found */
665 sz = of_property_read_variable_u32_array(dn, "dsa,member", m, 2, 2);
666 if (sz < 0 && sz != -EINVAL)
667 return sz;
668
669 ds->index = m[1];
670 if (ds->index >= DSA_MAX_SWITCHES)
671 return -EINVAL;
672
673 ds->dst = dsa_tree_touch(m[0]);
674 if (!ds->dst)
675 return -ENOMEM;
676
677 return 0;
678}
679
680static int dsa_switch_parse_of(struct dsa_switch *ds, struct device_node *dn)
681{
682 int err;
683
684 err = dsa_switch_parse_member_of(ds, dn);
685 if (err)
686 return err;
687
688 return dsa_switch_parse_ports_of(ds, dn);
689}
690
Vivien Didelotfd223e22017-10-27 15:55:14 -0400691static int dsa_port_parse(struct dsa_port *dp, const char *name,
692 struct device *dev)
693{
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400694 if (!strcmp(name, "cpu")) {
Vivien Didelotcbabb0a2017-10-27 15:55:17 -0400695 struct net_device *master;
696
697 master = dsa_dev_to_net_device(dev);
698 if (!master)
699 return -EPROBE_DEFER;
700
701 dev_put(master);
702
Vivien Didelot06e24d02017-11-03 19:05:29 -0400703 return dsa_port_parse_cpu(dp, master);
Vivien Didelot6d4e5c52017-10-27 15:55:15 -0400704 }
705
Vivien Didelot06e24d02017-11-03 19:05:29 -0400706 if (!strcmp(name, "dsa"))
707 return dsa_port_parse_dsa(dp);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400708
Vivien Didelot06e24d02017-11-03 19:05:29 -0400709 return dsa_port_parse_user(dp, name);
Vivien Didelotfd223e22017-10-27 15:55:14 -0400710}
711
Vivien Didelot975e6e32017-11-03 19:05:27 -0400712static int dsa_switch_parse_ports(struct dsa_switch *ds,
713 struct dsa_chip_data *cd)
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800714{
715 bool valid_name_found = false;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400716 struct dsa_port *dp;
717 struct device *dev;
718 const char *name;
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800719 unsigned int i;
Vivien Didelotfd223e22017-10-27 15:55:14 -0400720 int err;
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800721
722 for (i = 0; i < DSA_MAX_PORTS; i++) {
Vivien Didelotfd223e22017-10-27 15:55:14 -0400723 name = cd->port_names[i];
724 dev = cd->netdev[i];
725 dp = &ds->ports[i];
726
727 if (!name)
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800728 continue;
729
Vivien Didelotfd223e22017-10-27 15:55:14 -0400730 err = dsa_port_parse(dp, name, dev);
731 if (err)
732 return err;
733
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800734 valid_name_found = true;
735 }
736
737 if (!valid_name_found && i == DSA_MAX_PORTS)
738 return -EINVAL;
739
740 return 0;
741}
742
Vivien Didelot975e6e32017-11-03 19:05:27 -0400743static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200744{
Vivien Didelot975e6e32017-11-03 19:05:27 -0400745 ds->cd = cd;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200746
Vivien Didelot975e6e32017-11-03 19:05:27 -0400747 /* We don't support interconnected switches nor multiple trees via
748 * platform data, so this is the unique switch of the tree.
749 */
750 ds->index = 0;
751 ds->dst = dsa_tree_touch(0);
752 if (!ds->dst)
753 return -ENOMEM;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200754
Vivien Didelot975e6e32017-11-03 19:05:27 -0400755 return dsa_switch_parse_ports(ds, cd);
Florian Fainelli71e0bbd2017-02-04 13:02:43 -0800756}
757
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400758static int _dsa_register_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200759{
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400760 struct dsa_chip_data *pdata = ds->dev->platform_data;
761 struct device_node *np = ds->dev->of_node;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200762 struct dsa_switch_tree *dst;
Vivien Didelot975e6e32017-11-03 19:05:27 -0400763 unsigned int index;
Vivien Didelotd3902382016-07-06 20:03:54 -0400764 int i, err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200765
Vivien Didelot975e6e32017-11-03 19:05:27 -0400766 if (np)
767 err = dsa_switch_parse_of(ds, np);
768 else if (pdata)
769 err = dsa_switch_parse(ds, pdata);
770 else
771 err = -ENODEV;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200772
Vivien Didelot975e6e32017-11-03 19:05:27 -0400773 if (err)
774 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200775
Vivien Didelot975e6e32017-11-03 19:05:27 -0400776 index = ds->index;
777 dst = ds->dst;
Vivien Didelot0eefe2c2017-11-03 19:05:26 -0400778
Vivien Didelotd3902382016-07-06 20:03:54 -0400779 /* Initialize the routing table */
780 for (i = 0; i < DSA_MAX_SWITCHES; ++i)
781 ds->rtable[i] = DSA_RTABLE_NONE;
782
Vivien Didelot6da2a942017-11-03 19:05:25 -0400783 err = dsa_tree_add_switch(dst, ds);
784 if (err)
785 return err;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200786
787 err = dsa_dst_complete(dst);
788 if (err < 0)
789 goto out_del_dst;
790
Vivien Didelot8e5bf972017-11-03 19:05:22 -0400791 /* Not all switches registered yet */
792 if (err == 1)
793 return 0;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200794
795 if (dst->applied) {
796 pr_info("DSA: Disjoint trees?\n");
797 return -EINVAL;
798 }
799
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200800 err = dsa_dst_apply(dst);
801 if (err) {
802 dsa_dst_unapply(dst);
803 goto out_del_dst;
804 }
805
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200806 return 0;
807
808out_del_dst:
Vivien Didelot6da2a942017-11-03 19:05:25 -0400809 dsa_tree_remove_switch(dst, index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200810
811 return err;
812}
813
Vivien Didelota0c02162017-01-27 15:29:36 -0500814struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n)
815{
816 size_t size = sizeof(struct dsa_switch) + n * sizeof(struct dsa_port);
817 struct dsa_switch *ds;
Vivien Didelot818be842017-01-27 15:29:38 -0500818 int i;
Vivien Didelota0c02162017-01-27 15:29:36 -0500819
820 ds = devm_kzalloc(dev, size, GFP_KERNEL);
821 if (!ds)
822 return NULL;
823
824 ds->dev = dev;
825 ds->num_ports = n;
826
Vivien Didelot818be842017-01-27 15:29:38 -0500827 for (i = 0; i < ds->num_ports; ++i) {
828 ds->ports[i].index = i;
829 ds->ports[i].ds = ds;
830 }
831
Vivien Didelota0c02162017-01-27 15:29:36 -0500832 return ds;
833}
834EXPORT_SYMBOL_GPL(dsa_switch_alloc);
835
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400836int dsa_register_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200837{
838 int err;
839
840 mutex_lock(&dsa2_mutex);
Vivien Didelot23c9ee42017-05-26 18:12:51 -0400841 err = _dsa_register_switch(ds);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200842 mutex_unlock(&dsa2_mutex);
843
844 return err;
845}
846EXPORT_SYMBOL_GPL(dsa_register_switch);
847
Wei Yongjun85c22ba2016-07-12 15:24:10 +0000848static void _dsa_unregister_switch(struct dsa_switch *ds)
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200849{
850 struct dsa_switch_tree *dst = ds->dst;
Vivien Didelot6da2a942017-11-03 19:05:25 -0400851 unsigned int index = ds->index;
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200852
853 dsa_dst_unapply(dst);
854
Vivien Didelot6da2a942017-11-03 19:05:25 -0400855 dsa_tree_remove_switch(dst, index);
Andrew Lunn83c0afa2016-06-04 21:17:07 +0200856}
857
858void dsa_unregister_switch(struct dsa_switch *ds)
859{
860 mutex_lock(&dsa2_mutex);
861 _dsa_unregister_switch(ds);
862 mutex_unlock(&dsa2_mutex);
863}
864EXPORT_SYMBOL_GPL(dsa_unregister_switch);