diff options
| -rw-r--r-- | include/net/dsa.h | 7 | ||||
| -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 |
6 files changed, 77 insertions, 0 deletions
diff --git a/include/net/dsa.h b/include/net/dsa.h index 2cb77e64d648..ac4ea7c3a102 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #include <linux/if_ether.h> | 14 | #include <linux/if_ether.h> |
| 15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
| 16 | #include <linux/notifier.h> | ||
| 16 | #include <linux/timer.h> | 17 | #include <linux/timer.h> |
| 17 | #include <linux/workqueue.h> | 18 | #include <linux/workqueue.h> |
| 18 | #include <linux/of.h> | 19 | #include <linux/of.h> |
| @@ -92,6 +93,9 @@ struct packet_type; | |||
| 92 | struct dsa_switch_tree { | 93 | struct dsa_switch_tree { |
| 93 | struct list_head list; | 94 | struct list_head list; |
| 94 | 95 | ||
| 96 | /* Notifier chain for switch-wide events */ | ||
| 97 | struct raw_notifier_head nh; | ||
| 98 | |||
| 95 | /* Tree identifier */ | 99 | /* Tree identifier */ |
| 96 | u32 tree; | 100 | u32 tree; |
| 97 | 101 | ||
| @@ -182,6 +186,9 @@ struct dsa_switch { | |||
| 182 | struct dsa_switch_tree *dst; | 186 | struct dsa_switch_tree *dst; |
| 183 | int index; | 187 | int index; |
| 184 | 188 | ||
| 189 | /* Listener for switch fabric events */ | ||
| 190 | struct notifier_block nb; | ||
| 191 | |||
| 185 | /* | 192 | /* |
| 186 | * Give the switch driver somewhere to hang its private data | 193 | * Give the switch driver somewhere to hang its private data |
| 187 | * structure. | 194 | * structure. |
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 | } | ||
