Commit 005bcea9 authored by David S. Miller's avatar David S. Miller

Merge branch 'dsa-finers-bridging-control'

Vivien Didelot says:

====================
net: dsa: finer bridging control

This patchset renames the bridging routines of the DSA layer, make the
unbridging routine return void, and rework the DSA netdev notifier handler,
similar to what the Mellanox Spectrum driver does.

Changes RFC -> v1:
  - drop unused NETDEV_PRECHANGEUPPER case
  - add Andrew's Tested-by tag
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1e1589ad 6debb68a
...@@ -521,12 +521,12 @@ See Documentation/hwmon/sysfs-interface for details. ...@@ -521,12 +521,12 @@ See Documentation/hwmon/sysfs-interface for details.
Bridge layer Bridge layer
------------ ------------
- port_join_bridge: bridge layer function invoked when a given switch port is - port_bridge_join: bridge layer function invoked when a given switch port is
added to a bridge, this function should be doing the necessary at the switch added to a bridge, this function should be doing the necessary at the switch
level to permit the joining port from being added to the relevant logical level to permit the joining port from being added to the relevant logical
domain for it to ingress/egress traffic with other members of the bridge. domain for it to ingress/egress traffic with other members of the bridge.
- port_leave_bridge: bridge layer function invoked when a given switch port is - port_bridge_leave: bridge layer function invoked when a given switch port is
removed from a bridge, this function should be doing the necessary at the removed from a bridge, this function should be doing the necessary at the
switch level to deny the leaving port from ingress/egress traffic from the switch level to deny the leaving port from ingress/egress traffic from the
remaining bridge members. When the port leaves the bridge, it should be aged remaining bridge members. When the port leaves the bridge, it should be aged
......
...@@ -516,7 +516,7 @@ static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port, ...@@ -516,7 +516,7 @@ static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
return 0; return 0;
} }
static int bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port) static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port)
{ {
struct bcm_sf2_priv *priv = ds_to_priv(ds); struct bcm_sf2_priv *priv = ds_to_priv(ds);
struct net_device *bridge = priv->port_sts[port].bridge_dev; struct net_device *bridge = priv->port_sts[port].bridge_dev;
...@@ -543,8 +543,6 @@ static int bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port) ...@@ -543,8 +543,6 @@ static int bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port)
core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port)); core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port));
priv->port_sts[port].vlan_ctl_mask = p_ctl; priv->port_sts[port].vlan_ctl_mask = p_ctl;
priv->port_sts[port].bridge_dev = NULL; priv->port_sts[port].bridge_dev = NULL;
return 0;
} }
static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port, static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port,
...@@ -1387,8 +1385,8 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = { ...@@ -1387,8 +1385,8 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
.port_disable = bcm_sf2_port_disable, .port_disable = bcm_sf2_port_disable,
.get_eee = bcm_sf2_sw_get_eee, .get_eee = bcm_sf2_sw_get_eee,
.set_eee = bcm_sf2_sw_set_eee, .set_eee = bcm_sf2_sw_set_eee,
.port_join_bridge = bcm_sf2_sw_br_join, .port_bridge_join = bcm_sf2_sw_br_join,
.port_leave_bridge = bcm_sf2_sw_br_leave, .port_bridge_leave = bcm_sf2_sw_br_leave,
.port_stp_update = bcm_sf2_sw_br_set_stp_state, .port_stp_update = bcm_sf2_sw_br_set_stp_state,
.port_fdb_prepare = bcm_sf2_sw_fdb_prepare, .port_fdb_prepare = bcm_sf2_sw_fdb_prepare,
.port_fdb_add = bcm_sf2_sw_fdb_add, .port_fdb_add = bcm_sf2_sw_fdb_add,
......
...@@ -103,8 +103,8 @@ struct dsa_switch_driver mv88e6171_switch_driver = { ...@@ -103,8 +103,8 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
#endif #endif
.get_regs_len = mv88e6xxx_get_regs_len, .get_regs_len = mv88e6xxx_get_regs_len,
.get_regs = mv88e6xxx_get_regs, .get_regs = mv88e6xxx_get_regs,
.port_join_bridge = mv88e6xxx_port_bridge_join, .port_bridge_join = mv88e6xxx_port_bridge_join,
.port_leave_bridge = mv88e6xxx_port_bridge_leave, .port_bridge_leave = mv88e6xxx_port_bridge_leave,
.port_stp_update = mv88e6xxx_port_stp_update, .port_stp_update = mv88e6xxx_port_stp_update,
.port_vlan_filtering = mv88e6xxx_port_vlan_filtering, .port_vlan_filtering = mv88e6xxx_port_vlan_filtering,
.port_vlan_prepare = mv88e6xxx_port_vlan_prepare, .port_vlan_prepare = mv88e6xxx_port_vlan_prepare,
......
...@@ -324,8 +324,8 @@ struct dsa_switch_driver mv88e6352_switch_driver = { ...@@ -324,8 +324,8 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
.set_eeprom = mv88e6352_set_eeprom, .set_eeprom = mv88e6352_set_eeprom,
.get_regs_len = mv88e6xxx_get_regs_len, .get_regs_len = mv88e6xxx_get_regs_len,
.get_regs = mv88e6xxx_get_regs, .get_regs = mv88e6xxx_get_regs,
.port_join_bridge = mv88e6xxx_port_bridge_join, .port_bridge_join = mv88e6xxx_port_bridge_join,
.port_leave_bridge = mv88e6xxx_port_bridge_leave, .port_bridge_leave = mv88e6xxx_port_bridge_leave,
.port_stp_update = mv88e6xxx_port_stp_update, .port_stp_update = mv88e6xxx_port_stp_update,
.port_vlan_filtering = mv88e6xxx_port_vlan_filtering, .port_vlan_filtering = mv88e6xxx_port_vlan_filtering,
.port_vlan_prepare = mv88e6xxx_port_vlan_prepare, .port_vlan_prepare = mv88e6xxx_port_vlan_prepare,
......
...@@ -2219,39 +2219,29 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, ...@@ -2219,39 +2219,29 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
return err; return err;
} }
int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port) void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
{ {
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
struct net_device *bridge = ps->ports[port].bridge_dev; struct net_device *bridge = ps->ports[port].bridge_dev;
u16 fid; u16 fid;
int i, err; int i;
mutex_lock(&ps->smi_mutex); mutex_lock(&ps->smi_mutex);
/* Give the port a fresh Filtering Information Database */ /* Give the port a fresh Filtering Information Database */
err = _mv88e6xxx_fid_new(ds, &fid); if (_mv88e6xxx_fid_new(ds, &fid) ||
if (err) _mv88e6xxx_port_fid_set(ds, port, fid))
goto unlock; netdev_warn(ds->ports[port], "failed to assign a new FID\n");
err = _mv88e6xxx_port_fid_set(ds, port, fid);
if (err)
goto unlock;
/* Unassign the bridge and remap each port's VLANTable */ /* Unassign the bridge and remap each port's VLANTable */
ps->ports[port].bridge_dev = NULL; ps->ports[port].bridge_dev = NULL;
for (i = 0; i < ps->num_ports; ++i) { for (i = 0; i < ps->num_ports; ++i)
if (i == port || ps->ports[i].bridge_dev == bridge) { if (i == port || ps->ports[i].bridge_dev == bridge)
err = _mv88e6xxx_port_based_vlan_map(ds, i); if (_mv88e6xxx_port_based_vlan_map(ds, i))
if (err) netdev_warn(ds->ports[i], "failed to remap\n");
break;
}
}
unlock:
mutex_unlock(&ps->smi_mutex); mutex_unlock(&ps->smi_mutex);
return err;
} }
static void mv88e6xxx_bridge_work(struct work_struct *work) static void mv88e6xxx_bridge_work(struct work_struct *work)
......
...@@ -488,7 +488,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, ...@@ -488,7 +488,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
struct phy_device *phydev, struct ethtool_eee *e); struct phy_device *phydev, struct ethtool_eee *e);
int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
struct net_device *bridge); struct net_device *bridge);
int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port); void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port);
int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state); int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state);
int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
bool vlan_filtering); bool vlan_filtering);
......
...@@ -296,9 +296,9 @@ struct dsa_switch_driver { ...@@ -296,9 +296,9 @@ struct dsa_switch_driver {
/* /*
* Bridge integration * Bridge integration
*/ */
int (*port_join_bridge)(struct dsa_switch *ds, int port, int (*port_bridge_join)(struct dsa_switch *ds, int port,
struct net_device *bridge); struct net_device *bridge);
int (*port_leave_bridge)(struct dsa_switch *ds, int port); void (*port_bridge_leave)(struct dsa_switch *ds, int port);
int (*port_stp_update)(struct dsa_switch *ds, int port, int (*port_stp_update)(struct dsa_switch *ds, int port,
u8 state); u8 state);
......
...@@ -448,21 +448,20 @@ static int dsa_slave_bridge_port_join(struct net_device *dev, ...@@ -448,21 +448,20 @@ static int dsa_slave_bridge_port_join(struct net_device *dev,
p->bridge_dev = br; p->bridge_dev = br;
if (ds->drv->port_join_bridge) if (ds->drv->port_bridge_join)
ret = ds->drv->port_join_bridge(ds, p->port, br); ret = ds->drv->port_bridge_join(ds, p->port, br);
return ret; return ret == -EOPNOTSUPP ? 0 : ret;
} }
static int dsa_slave_bridge_port_leave(struct net_device *dev) static void dsa_slave_bridge_port_leave(struct net_device *dev)
{ {
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->parent; struct dsa_switch *ds = p->parent;
int ret = -EOPNOTSUPP;
if (ds->drv->port_leave_bridge) if (ds->drv->port_bridge_leave)
ret = ds->drv->port_leave_bridge(ds, p->port); ds->drv->port_bridge_leave(ds, p->port);
p->bridge_dev = NULL; p->bridge_dev = NULL;
...@@ -470,8 +469,6 @@ static int dsa_slave_bridge_port_leave(struct net_device *dev) ...@@ -470,8 +469,6 @@ static int dsa_slave_bridge_port_leave(struct net_device *dev)
* so allow it to be in BR_STATE_FORWARDING to be kept functional * so allow it to be in BR_STATE_FORWARDING to be kept functional
*/ */
dsa_slave_stp_update(dev, BR_STATE_FORWARDING); dsa_slave_stp_update(dev, BR_STATE_FORWARDING);
return ret;
} }
static int dsa_slave_port_attr_get(struct net_device *dev, static int dsa_slave_port_attr_get(struct net_device *dev,
...@@ -1146,40 +1143,46 @@ static bool dsa_slave_dev_check(struct net_device *dev) ...@@ -1146,40 +1143,46 @@ static bool dsa_slave_dev_check(struct net_device *dev)
return dev->netdev_ops == &dsa_slave_netdev_ops; return dev->netdev_ops == &dsa_slave_netdev_ops;
} }
static int dsa_slave_master_changed(struct net_device *dev) static int dsa_slave_port_upper_event(struct net_device *dev,
unsigned long event, void *ptr)
{ {
struct net_device *master = netdev_master_upper_dev_get(dev); struct netdev_notifier_changeupper_info *info = ptr;
struct dsa_slave_priv *p = netdev_priv(dev); struct net_device *upper = info->upper_dev;
int err = 0; int err = 0;
if (master && master->rtnl_link_ops && switch (event) {
!strcmp(master->rtnl_link_ops->kind, "bridge")) case NETDEV_CHANGEUPPER:
err = dsa_slave_bridge_port_join(dev, master); if (netif_is_bridge_master(upper)) {
else if (dsa_port_is_bridged(p)) if (info->linking)
err = dsa_slave_bridge_port_leave(dev); err = dsa_slave_bridge_port_join(dev, upper);
else
dsa_slave_bridge_port_leave(dev);
}
break;
}
return err; return notifier_from_errno(err);
} }
int dsa_slave_netdevice_event(struct notifier_block *unused, static int dsa_slave_port_event(struct net_device *dev, unsigned long event,
unsigned long event, void *ptr) void *ptr)
{ {
struct net_device *dev;
int err = 0;
switch (event) { switch (event) {
case NETDEV_CHANGEUPPER: case NETDEV_CHANGEUPPER:
dev = netdev_notifier_info_to_dev(ptr); return dsa_slave_port_upper_event(dev, event, ptr);
if (!dsa_slave_dev_check(dev)) }
goto out;
err = dsa_slave_master_changed(dev); return NOTIFY_DONE;
if (err && err != -EOPNOTSUPP) }
netdev_warn(dev, "failed to reflect master change\n");
break; int dsa_slave_netdevice_event(struct notifier_block *unused,
} unsigned long event, void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
if (dsa_slave_dev_check(dev))
return dsa_slave_port_event(dev, event, ptr);
out:
return NOTIFY_DONE; return NOTIFY_DONE;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment