diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/dsa/slave.c | 40 | ||||
| -rw-r--r-- | net/dsa/switch.c | 32 |
2 files changed, 61 insertions, 11 deletions
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index d8c3c0f00cf3..061a49c29cef 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c | |||
| @@ -27,6 +27,17 @@ | |||
| 27 | 27 | ||
| 28 | static bool dsa_slave_dev_check(struct net_device *dev); | 28 | static bool dsa_slave_dev_check(struct net_device *dev); |
| 29 | 29 | ||
| 30 | static int dsa_slave_notify(struct net_device *dev, unsigned long e, void *v) | ||
| 31 | { | ||
| 32 | struct dsa_slave_priv *p = netdev_priv(dev); | ||
| 33 | struct raw_notifier_head *nh = &p->dp->ds->dst->nh; | ||
| 34 | int err; | ||
| 35 | |||
| 36 | err = raw_notifier_call_chain(nh, e, v); | ||
| 37 | |||
| 38 | return notifier_to_errno(err); | ||
| 39 | } | ||
| 40 | |||
| 30 | /* slave mii_bus handling ***************************************************/ | 41 | /* slave mii_bus handling ***************************************************/ |
| 31 | static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) | 42 | static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) |
| 32 | { | 43 | { |
| @@ -562,39 +573,46 @@ static int dsa_slave_bridge_port_join(struct net_device *dev, | |||
| 562 | struct net_device *br) | 573 | struct net_device *br) |
| 563 | { | 574 | { |
| 564 | struct dsa_slave_priv *p = netdev_priv(dev); | 575 | struct dsa_slave_priv *p = netdev_priv(dev); |
| 565 | struct dsa_switch *ds = p->dp->ds; | 576 | struct dsa_notifier_bridge_info info = { |
| 566 | int ret = -EOPNOTSUPP; | 577 | .sw_index = p->dp->ds->index, |
| 578 | .port = p->dp->index, | ||
| 579 | .br = br, | ||
| 580 | }; | ||
| 581 | int err; | ||
| 567 | 582 | ||
| 568 | /* Here the port is already bridged. Reflect the current configuration | 583 | /* Here the port is already bridged. Reflect the current configuration |
| 569 | * so that drivers can program their chips accordingly. | 584 | * so that drivers can program their chips accordingly. |
| 570 | */ | 585 | */ |
| 571 | p->dp->bridge_dev = br; | 586 | p->dp->bridge_dev = br; |
| 572 | 587 | ||
| 573 | if (ds->ops->port_bridge_join) | 588 | err = dsa_slave_notify(dev, DSA_NOTIFIER_BRIDGE_JOIN, &info); |
| 574 | ret = ds->ops->port_bridge_join(ds, p->dp->index, br); | ||
| 575 | 589 | ||
| 576 | /* The bridging is rolled back on error */ | 590 | /* The bridging is rolled back on error */ |
| 577 | if (ret && ret != -EOPNOTSUPP) { | 591 | if (err) |
| 578 | p->dp->bridge_dev = NULL; | 592 | p->dp->bridge_dev = NULL; |
| 579 | return ret; | ||
| 580 | } | ||
| 581 | 593 | ||
| 582 | return 0; | 594 | return err; |
| 583 | } | 595 | } |
| 584 | 596 | ||
| 585 | static void dsa_slave_bridge_port_leave(struct net_device *dev, | 597 | static void dsa_slave_bridge_port_leave(struct net_device *dev, |
| 586 | struct net_device *br) | 598 | struct net_device *br) |
| 587 | { | 599 | { |
| 588 | struct dsa_slave_priv *p = netdev_priv(dev); | 600 | struct dsa_slave_priv *p = netdev_priv(dev); |
| 589 | struct dsa_switch *ds = p->dp->ds; | 601 | struct dsa_notifier_bridge_info info = { |
| 602 | .sw_index = p->dp->ds->index, | ||
| 603 | .port = p->dp->index, | ||
| 604 | .br = br, | ||
| 605 | }; | ||
| 606 | int err; | ||
| 590 | 607 | ||
| 591 | /* Here the port is already unbridged. Reflect the current configuration | 608 | /* Here the port is already unbridged. Reflect the current configuration |
| 592 | * so that drivers can program their chips accordingly. | 609 | * so that drivers can program their chips accordingly. |
| 593 | */ | 610 | */ |
| 594 | p->dp->bridge_dev = NULL; | 611 | p->dp->bridge_dev = NULL; |
| 595 | 612 | ||
| 596 | if (ds->ops->port_bridge_leave) | 613 | err = dsa_slave_notify(dev, DSA_NOTIFIER_BRIDGE_LEAVE, &info); |
| 597 | ds->ops->port_bridge_leave(ds, p->dp->index, br); | 614 | if (err) |
| 615 | netdev_err(dev, "failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); | ||
| 598 | 616 | ||
| 599 | /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, | 617 | /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, |
| 600 | * so allow it to be in BR_STATE_FORWARDING to be kept functional | 618 | * so allow it to be in BR_STATE_FORWARDING to be kept functional |
diff --git a/net/dsa/switch.c b/net/dsa/switch.c index e22fa7633d03..6456dacf9ae9 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c | |||
| @@ -13,6 +13,32 @@ | |||
| 13 | #include <linux/notifier.h> | 13 | #include <linux/notifier.h> |
| 14 | #include <net/dsa.h> | 14 | #include <net/dsa.h> |
| 15 | 15 | ||
| 16 | static int dsa_switch_bridge_join(struct dsa_switch *ds, | ||
| 17 | struct dsa_notifier_bridge_info *info) | ||
| 18 | { | ||
| 19 | if (ds->index == info->sw_index && ds->ops->port_bridge_join) | ||
| 20 | return ds->ops->port_bridge_join(ds, info->port, info->br); | ||
| 21 | |||
| 22 | if (ds->index != info->sw_index) | ||
| 23 | dev_dbg(ds->dev, "crosschip DSA port %d.%d bridged to %s\n", | ||
| 24 | info->sw_index, info->port, netdev_name(info->br)); | ||
| 25 | |||
| 26 | return 0; | ||
| 27 | } | ||
| 28 | |||
| 29 | static int dsa_switch_bridge_leave(struct dsa_switch *ds, | ||
| 30 | struct dsa_notifier_bridge_info *info) | ||
| 31 | { | ||
| 32 | if (ds->index == info->sw_index && ds->ops->port_bridge_leave) | ||
| 33 | ds->ops->port_bridge_leave(ds, info->port, info->br); | ||
| 34 | |||
| 35 | if (ds->index != info->sw_index) | ||
| 36 | dev_dbg(ds->dev, "crosschip DSA port %d.%d unbridged from %s\n", | ||
| 37 | info->sw_index, info->port, netdev_name(info->br)); | ||
| 38 | |||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | |||
| 16 | static int dsa_switch_event(struct notifier_block *nb, | 42 | static int dsa_switch_event(struct notifier_block *nb, |
| 17 | unsigned long event, void *info) | 43 | unsigned long event, void *info) |
| 18 | { | 44 | { |
| @@ -20,6 +46,12 @@ static int dsa_switch_event(struct notifier_block *nb, | |||
| 20 | int err; | 46 | int err; |
| 21 | 47 | ||
| 22 | switch (event) { | 48 | switch (event) { |
| 49 | case DSA_NOTIFIER_BRIDGE_JOIN: | ||
| 50 | err = dsa_switch_bridge_join(ds, info); | ||
| 51 | break; | ||
| 52 | case DSA_NOTIFIER_BRIDGE_LEAVE: | ||
| 53 | err = dsa_switch_bridge_leave(ds, info); | ||
| 54 | break; | ||
| 23 | default: | 55 | default: |
| 24 | err = -EOPNOTSUPP; | 56 | err = -EOPNOTSUPP; |
| 25 | break; | 57 | break; |
