Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Vivien Didelot and committed by
David S. Miller
f515f192 c5d35cb3

+77
+7
include/net/dsa.h
··· 13 13 14 14 #include <linux/if_ether.h> 15 15 #include <linux/list.h> 16 + #include <linux/notifier.h> 16 17 #include <linux/timer.h> 17 18 #include <linux/workqueue.h> 18 19 #include <linux/of.h> ··· 92 91 93 92 struct dsa_switch_tree { 94 93 struct list_head list; 94 + 95 + /* Notifier chain for switch-wide events */ 96 + struct raw_notifier_head nh; 95 97 96 98 /* Tree identifier */ 97 99 u32 tree; ··· 185 181 */ 186 182 struct dsa_switch_tree *dst; 187 183 int index; 184 + 185 + /* Listener for switch fabric events */ 186 + struct notifier_block nb; 188 187 189 188 /* 190 189 * Give the switch driver somewhere to hang its private data
+1
net/dsa/Makefile
··· 1 1 # the core 2 2 obj-$(CONFIG_NET_DSA) += dsa_core.o 3 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 6 # tagging formats 6 7 dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
+6
net/dsa/dsa.c
··· 275 275 if (ret < 0) 276 276 return ret; 277 277 278 + ret = dsa_switch_register_notifier(ds); 279 + if (ret) 280 + return ret; 281 + 278 282 if (ops->set_addr) { 279 283 ret = ops->set_addr(ds, dst->master_netdev->dev_addr); 280 284 if (ret < 0) ··· 404 400 405 401 if (ds->slave_mii_bus && ds->ops->phy_read) 406 402 mdiobus_unregister(ds->slave_mii_bus); 403 + 404 + dsa_switch_unregister_notifier(ds); 407 405 } 408 406 409 407 #ifdef CONFIG_PM_SLEEP
+6
net/dsa/dsa2.c
··· 294 294 if (err < 0) 295 295 return err; 296 296 297 + err = dsa_switch_register_notifier(ds); 298 + if (err) 299 + return err; 300 + 297 301 if (ds->ops->set_addr) { 298 302 err = ds->ops->set_addr(ds, dst->master_netdev->dev_addr); 299 303 if (err < 0) ··· 368 364 369 365 if (ds->slave_mii_bus && ds->ops->phy_read) 370 366 mdiobus_unregister(ds->slave_mii_bus); 367 + 368 + dsa_switch_unregister_notifier(ds); 371 369 } 372 370 373 371 static int dsa_dst_apply(struct dsa_switch_tree *dst)
+4
net/dsa/dsa_priv.h
··· 66 66 int dsa_slave_register_notifier(void); 67 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 73 /* tag_dsa.c */ 70 74 extern const struct dsa_device_ops dsa_netdev_ops; 71 75
+53
net/dsa/switch.c
··· 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 + }