diff options
author | Vivien Didelot <vivien.didelot@savoirfairelinux.com> | 2017-02-03 13:20:20 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-02-06 16:53:29 -0500 |
commit | f515f192ab4f45bb695146b82432d63d98775787 (patch) | |
tree | 5a6fddcbb34e28e6850e63d3023504b46e5ea9c3 /net/dsa | |
parent | c5d35cb32cffa6e4c2db1cbd9a544e10a8d6fda9 (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/Makefile | 1 | ||||
-rw-r--r-- | net/dsa/dsa.c | 6 | ||||
-rw-r--r-- | net/dsa/dsa2.c | 6 | ||||
-rw-r--r-- | net/dsa/dsa_priv.h | 4 | ||||
-rw-r--r-- | net/dsa/switch.c | 53 |
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 |
2 | obj-$(CONFIG_NET_DSA) += dsa_core.o | 2 | obj-$(CONFIG_NET_DSA) += dsa_core.o |
3 | dsa_core-y += dsa.o slave.o dsa2.o | 3 | dsa_core-y += dsa.o slave.o dsa2.o |
4 | dsa_core-y += dsa.o slave.o dsa2.o switch.o | ||
4 | 5 | ||
5 | # tagging formats | 6 | # tagging formats |
6 | dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o | 7 | dsa_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 | ||
369 | static int dsa_dst_apply(struct dsa_switch_tree *dst) | 375 | static 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); | |||
66 | int dsa_slave_register_notifier(void); | 66 | int dsa_slave_register_notifier(void); |
67 | void dsa_slave_unregister_notifier(void); | 67 | void dsa_slave_unregister_notifier(void); |
68 | 68 | ||
69 | /* switch.c */ | ||
70 | int dsa_switch_register_notifier(struct dsa_switch *ds); | ||
71 | void dsa_switch_unregister_notifier(struct dsa_switch *ds); | ||
72 | |||
69 | /* tag_dsa.c */ | 73 | /* tag_dsa.c */ |
70 | extern const struct dsa_device_ops dsa_netdev_ops; | 74 | extern 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 | |||
16 | static 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 | |||
39 | int 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 | |||
46 | void 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 | } | ||