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.
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
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.
- 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
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
......
......@@ -516,7 +516,7 @@ static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
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 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)
core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port));
priv->port_sts[port].vlan_ctl_mask = p_ctl;
priv->port_sts[port].bridge_dev = NULL;
return 0;
}
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 = {
.port_disable = bcm_sf2_port_disable,
.get_eee = bcm_sf2_sw_get_eee,
.set_eee = bcm_sf2_sw_set_eee,
.port_join_bridge = bcm_sf2_sw_br_join,
.port_leave_bridge = bcm_sf2_sw_br_leave,
.port_bridge_join = bcm_sf2_sw_br_join,
.port_bridge_leave = bcm_sf2_sw_br_leave,
.port_stp_update = bcm_sf2_sw_br_set_stp_state,
.port_fdb_prepare = bcm_sf2_sw_fdb_prepare,
.port_fdb_add = bcm_sf2_sw_fdb_add,
......
......@@ -103,8 +103,8 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
#endif
.get_regs_len = mv88e6xxx_get_regs_len,
.get_regs = mv88e6xxx_get_regs,
.port_join_bridge = mv88e6xxx_port_bridge_join,
.port_leave_bridge = mv88e6xxx_port_bridge_leave,
.port_bridge_join = mv88e6xxx_port_bridge_join,
.port_bridge_leave = mv88e6xxx_port_bridge_leave,
.port_stp_update = mv88e6xxx_port_stp_update,
.port_vlan_filtering = mv88e6xxx_port_vlan_filtering,
.port_vlan_prepare = mv88e6xxx_port_vlan_prepare,
......
......@@ -324,8 +324,8 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
.set_eeprom = mv88e6352_set_eeprom,
.get_regs_len = mv88e6xxx_get_regs_len,
.get_regs = mv88e6xxx_get_regs,
.port_join_bridge = mv88e6xxx_port_bridge_join,
.port_leave_bridge = mv88e6xxx_port_bridge_leave,
.port_bridge_join = mv88e6xxx_port_bridge_join,
.port_bridge_leave = mv88e6xxx_port_bridge_leave,
.port_stp_update = mv88e6xxx_port_stp_update,
.port_vlan_filtering = mv88e6xxx_port_vlan_filtering,
.port_vlan_prepare = mv88e6xxx_port_vlan_prepare,
......
......@@ -2219,39 +2219,29 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
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 net_device *bridge = ps->ports[port].bridge_dev;
u16 fid;
int i, err;
int i;
mutex_lock(&ps->smi_mutex);
/* Give the port a fresh Filtering Information Database */
err = _mv88e6xxx_fid_new(ds, &fid);
if (err)
goto unlock;
err = _mv88e6xxx_port_fid_set(ds, port, fid);
if (err)
goto unlock;
if (_mv88e6xxx_fid_new(ds, &fid) ||
_mv88e6xxx_port_fid_set(ds, port, fid))
netdev_warn(ds->ports[port], "failed to assign a new FID\n");
/* Unassign the bridge and remap each port's VLANTable */
ps->ports[port].bridge_dev = NULL;
for (i = 0; i < ps->num_ports; ++i) {
if (i == port || ps->ports[i].bridge_dev == bridge) {
err = _mv88e6xxx_port_based_vlan_map(ds, i);
if (err)
break;
}
}
for (i = 0; i < ps->num_ports; ++i)
if (i == port || ps->ports[i].bridge_dev == bridge)
if (_mv88e6xxx_port_based_vlan_map(ds, i))
netdev_warn(ds->ports[i], "failed to remap\n");
unlock:
mutex_unlock(&ps->smi_mutex);
return err;
}
static void mv88e6xxx_bridge_work(struct work_struct *work)
......
......@@ -488,7 +488,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
struct phy_device *phydev, struct ethtool_eee *e);
int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
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_vlan_filtering(struct dsa_switch *ds, int port,
bool vlan_filtering);
......
......@@ -296,9 +296,9 @@ struct dsa_switch_driver {
/*
* 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);
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,
u8 state);
......
......@@ -448,21 +448,20 @@ static int dsa_slave_bridge_port_join(struct net_device *dev,
p->bridge_dev = br;
if (ds->drv->port_join_bridge)
ret = ds->drv->port_join_bridge(ds, p->port, br);
if (ds->drv->port_bridge_join)
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_switch *ds = p->parent;
int ret = -EOPNOTSUPP;
if (ds->drv->port_leave_bridge)
ret = ds->drv->port_leave_bridge(ds, p->port);
if (ds->drv->port_bridge_leave)
ds->drv->port_bridge_leave(ds, p->port);
p->bridge_dev = NULL;
......@@ -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
*/
dsa_slave_stp_update(dev, BR_STATE_FORWARDING);
return ret;
}
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)
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 dsa_slave_priv *p = netdev_priv(dev);
struct netdev_notifier_changeupper_info *info = ptr;
struct net_device *upper = info->upper_dev;
int err = 0;
if (master && master->rtnl_link_ops &&
!strcmp(master->rtnl_link_ops->kind, "bridge"))
err = dsa_slave_bridge_port_join(dev, master);
else if (dsa_port_is_bridged(p))
err = dsa_slave_bridge_port_leave(dev);
switch (event) {
case NETDEV_CHANGEUPPER:
if (netif_is_bridge_master(upper)) {
if (info->linking)
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,
unsigned long event, void *ptr)
static int dsa_slave_port_event(struct net_device *dev, unsigned long event,
void *ptr)
{
struct net_device *dev;
int err = 0;
switch (event) {
case NETDEV_CHANGEUPPER:
dev = netdev_notifier_info_to_dev(ptr);
if (!dsa_slave_dev_check(dev))
goto out;
return dsa_slave_port_upper_event(dev, event, ptr);
}
err = dsa_slave_master_changed(dev);
if (err && err != -EOPNOTSUPP)
netdev_warn(dev, "failed to reflect master change\n");
return NOTIFY_DONE;
}
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;
}
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