aboutsummaryrefslogtreecommitdiffstats
path: root/net/dsa
diff options
context:
space:
mode:
authorVivien Didelot <vivien.didelot@savoirfairelinux.com>2017-02-03 13:20:20 -0500
committerDavid S. Miller <davem@davemloft.net>2017-02-06 16:53:29 -0500
commitf515f192ab4f45bb695146b82432d63d98775787 (patch)
tree5a6fddcbb34e28e6850e63d3023504b46e5ea9c3 /net/dsa
parentc5d35cb32cffa6e4c2db1cbd9a544e10a8d6fda9 (diff)
net: dsa: add switch notifier
Add a notifier block per DSA switch, registered against a notifier head in the switch fabric they belong to. This infrastructure will allow to propagate fabric-wide events such as port bridging, VLAN configuration, etc. If a DSA switch driver cares about cross-chip configuration, such events can be caught. Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa')
-rw-r--r--net/dsa/Makefile1
-rw-r--r--net/dsa/dsa.c6
-rw-r--r--net/dsa/dsa2.c6
-rw-r--r--net/dsa/dsa_priv.h4
-rw-r--r--net/dsa/switch.c53
5 files changed, 70 insertions, 0 deletions
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index a3380ed0e0be..72912982de3d 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -1,6 +1,7 @@
1# the core 1# the core
2obj-$(CONFIG_NET_DSA) += dsa_core.o 2obj-$(CONFIG_NET_DSA) += dsa_core.o
3dsa_core-y += dsa.o slave.o dsa2.o 3dsa_core-y += dsa.o slave.o dsa2.o
4dsa_core-y += dsa.o slave.o dsa2.o switch.o
4 5
5# tagging formats 6# tagging formats
6dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o 7dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index beb79ccf0f59..22e44f691ab9 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -275,6 +275,10 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
275 if (ret < 0) 275 if (ret < 0)
276 return ret; 276 return ret;
277 277
278 ret = dsa_switch_register_notifier(ds);
279 if (ret)
280 return ret;
281
278 if (ops->set_addr) { 282 if (ops->set_addr) {
279 ret = ops->set_addr(ds, dst->master_netdev->dev_addr); 283 ret = ops->set_addr(ds, dst->master_netdev->dev_addr);
280 if (ret < 0) 284 if (ret < 0)
@@ -400,6 +404,8 @@ static void dsa_switch_destroy(struct dsa_switch *ds)
400 404
401 if (ds->slave_mii_bus && ds->ops->phy_read) 405 if (ds->slave_mii_bus && ds->ops->phy_read)
402 mdiobus_unregister(ds->slave_mii_bus); 406 mdiobus_unregister(ds->slave_mii_bus);
407
408 dsa_switch_unregister_notifier(ds);
403} 409}
404 410
405#ifdef CONFIG_PM_SLEEP 411#ifdef CONFIG_PM_SLEEP
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 9f8cc26be9ea..1c546b6621ee 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -294,6 +294,10 @@ static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds)
294 if (err < 0) 294 if (err < 0)
295 return err; 295 return err;
296 296
297 err = dsa_switch_register_notifier(ds);
298 if (err)
299 return err;
300
297 if (ds->ops->set_addr) { 301 if (ds->ops->set_addr) {
298 err = ds->ops->set_addr(ds, dst->master_netdev->dev_addr); 302 err = ds->ops->set_addr(ds, dst->master_netdev->dev_addr);
299 if (err < 0) 303 if (err < 0)
@@ -364,6 +368,8 @@ static void dsa_ds_unapply(struct dsa_switch_tree *dst, struct dsa_switch *ds)
364 368
365 if (ds->slave_mii_bus && ds->ops->phy_read) 369 if (ds->slave_mii_bus && ds->ops->phy_read)
366 mdiobus_unregister(ds->slave_mii_bus); 370 mdiobus_unregister(ds->slave_mii_bus);
371
372 dsa_switch_unregister_notifier(ds);
367} 373}
368 374
369static int dsa_dst_apply(struct dsa_switch_tree *dst) 375static int dsa_dst_apply(struct dsa_switch_tree *dst)
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 591a40aea9ca..0706a511244e 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -66,6 +66,10 @@ int dsa_slave_resume(struct net_device *slave_dev);
66int dsa_slave_register_notifier(void); 66int dsa_slave_register_notifier(void);
67void dsa_slave_unregister_notifier(void); 67void dsa_slave_unregister_notifier(void);
68 68
69/* switch.c */
70int dsa_switch_register_notifier(struct dsa_switch *ds);
71void dsa_switch_unregister_notifier(struct dsa_switch *ds);
72
69/* tag_dsa.c */ 73/* tag_dsa.c */
70extern const struct dsa_device_ops dsa_netdev_ops; 74extern const struct dsa_device_ops dsa_netdev_ops;
71 75
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
new file mode 100644
index 000000000000..e22fa7633d03
--- /dev/null
+++ b/net/dsa/switch.c
@@ -0,0 +1,53 @@
1/*
2 * Handling of a single switch chip, part of a switch fabric
3 *
4 * Copyright (c) 2017 Vivien Didelot <vivien.didelot@savoirfairelinux.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/netdevice.h>
13#include <linux/notifier.h>
14#include <net/dsa.h>
15
16static int dsa_switch_event(struct notifier_block *nb,
17 unsigned long event, void *info)
18{
19 struct dsa_switch *ds = container_of(nb, struct dsa_switch, nb);
20 int err;
21
22 switch (event) {
23 default:
24 err = -EOPNOTSUPP;
25 break;
26 }
27
28 /* Non-switchdev operations cannot be rolled back. If a DSA driver
29 * returns an error during the chained call, switch chips may be in an
30 * inconsistent state.
31 */
32 if (err)
33 dev_dbg(ds->dev, "breaking chain for DSA event %lu (%d)\n",
34 event, err);
35
36 return notifier_from_errno(err);
37}
38
39int dsa_switch_register_notifier(struct dsa_switch *ds)
40{
41 ds->nb.notifier_call = dsa_switch_event;
42
43 return raw_notifier_chain_register(&ds->dst->nh, &ds->nb);
44}
45
46void dsa_switch_unregister_notifier(struct dsa_switch *ds)
47{
48 int err;
49
50 err = raw_notifier_chain_unregister(&ds->dst->nh, &ds->nb);
51 if (err)
52 dev_err(ds->dev, "failed to unregister notifier (%d)\n", err);
53}