1 /* 2 * Handling of a single switch chip, part of a switch fabric 3 * 4 * Copyright (c) 2017 Savoir-faire Linux Inc. 5 * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 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/netdevice.h> 14 #include <linux/notifier.h> 15 #include <net/dsa.h> 16 17 static int dsa_switch_bridge_join(struct dsa_switch *ds, 18 struct dsa_notifier_bridge_info *info) 19 { 20 if (ds->index == info->sw_index && ds->ops->port_bridge_join) 21 return ds->ops->port_bridge_join(ds, info->port, info->br); 22 23 if (ds->index != info->sw_index && ds->ops->crosschip_bridge_join) 24 return ds->ops->crosschip_bridge_join(ds, info->sw_index, 25 info->port, info->br); 26 27 return 0; 28 } 29 30 static int dsa_switch_bridge_leave(struct dsa_switch *ds, 31 struct dsa_notifier_bridge_info *info) 32 { 33 if (ds->index == info->sw_index && ds->ops->port_bridge_leave) 34 ds->ops->port_bridge_leave(ds, info->port, info->br); 35 36 if (ds->index != info->sw_index && ds->ops->crosschip_bridge_leave) 37 ds->ops->crosschip_bridge_leave(ds, info->sw_index, info->port, 38 info->br); 39 40 return 0; 41 } 42 43 static int dsa_switch_event(struct notifier_block *nb, 44 unsigned long event, void *info) 45 { 46 struct dsa_switch *ds = container_of(nb, struct dsa_switch, nb); 47 int err; 48 49 switch (event) { 50 case DSA_NOTIFIER_BRIDGE_JOIN: 51 err = dsa_switch_bridge_join(ds, info); 52 break; 53 case DSA_NOTIFIER_BRIDGE_LEAVE: 54 err = dsa_switch_bridge_leave(ds, info); 55 break; 56 default: 57 err = -EOPNOTSUPP; 58 break; 59 } 60 61 /* Non-switchdev operations cannot be rolled back. If a DSA driver 62 * returns an error during the chained call, switch chips may be in an 63 * inconsistent state. 64 */ 65 if (err) 66 dev_dbg(ds->dev, "breaking chain for DSA event %lu (%d)\n", 67 event, err); 68 69 return notifier_from_errno(err); 70 } 71 72 int dsa_switch_register_notifier(struct dsa_switch *ds) 73 { 74 ds->nb.notifier_call = dsa_switch_event; 75 76 return raw_notifier_chain_register(&ds->dst->nh, &ds->nb); 77 } 78 79 void dsa_switch_unregister_notifier(struct dsa_switch *ds) 80 { 81 int err; 82 83 err = raw_notifier_chain_unregister(&ds->dst->nh, &ds->nb); 84 if (err) 85 dev_err(ds->dev, "failed to unregister notifier (%d)\n", err); 86 } 87