From a6692754d61a6b3735803783f394880805675f99 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 12 Feb 2016 12:09:39 -0500 Subject: net: dsa: pass bridge down to drivers Some DSA drivers may or may not support multiple software bridges on top of an hardware switch. It is more convenient for them to access the bridge's net_device for finer configuration. Removing the need to craft and access a bitmask also simplifies the code. This patch changes the signature of bridge related functions, update DSA drivers, and removes dsa_slave_br_port_mask. Signed-off-by: Vivien Didelot Tested-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/dsa.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'include/net/dsa.h') diff --git a/include/net/dsa.h b/include/net/dsa.h index 26a0e86e611e..1c845d7bf0b2 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -297,9 +297,8 @@ struct dsa_switch_driver { * Bridge integration */ int (*port_join_bridge)(struct dsa_switch *ds, int port, - u32 br_port_mask); - int (*port_leave_bridge)(struct dsa_switch *ds, int port, - u32 br_port_mask); + struct net_device *bridge); + int (*port_leave_bridge)(struct dsa_switch *ds, int port); int (*port_stp_update)(struct dsa_switch *ds, int port, u8 state); -- cgit v1.2.3 From 65aebfc002abc1827ac7c8644a2bba0459ce3ce2 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 23 Feb 2016 12:13:54 -0500 Subject: net: dsa: add port_vlan_dump routine Similar to port_fdb_dump, add a port_vlan_dump function to DSA drivers which gets passed the switchdev VLAN object and callback. This function, if implemented, takes precedence over the soon legacy vlan_getnext/port_pvid_get approach. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- Documentation/networking/dsa/dsa.txt | 4 ++++ include/net/dsa.h | 3 +++ net/dsa/slave.c | 3 +++ 3 files changed, 10 insertions(+) (limited to 'include/net/dsa.h') diff --git a/Documentation/networking/dsa/dsa.txt b/Documentation/networking/dsa/dsa.txt index ebf21530471f..350a502e031f 100644 --- a/Documentation/networking/dsa/dsa.txt +++ b/Documentation/networking/dsa/dsa.txt @@ -554,6 +554,10 @@ Bridge VLAN filtering - port_vlan_del: bridge layer function invoked when a VLAN is removed from the given switch port +- port_vlan_dump: bridge layer function invoked with a switchdev callback + function that the driver has to call for each VLAN the given port is a member + of. A switchdev object is used to carry the VID and bridge flags. + - vlan_getnext: bridge layer function invoked to query the next configured VLAN in the switch, i.e. returns the bitmaps of members and untagged ports diff --git a/include/net/dsa.h b/include/net/dsa.h index 1c845d7bf0b2..ebc0d9ea96a1 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -313,6 +313,9 @@ struct dsa_switch_driver { struct switchdev_trans *trans); int (*port_vlan_del)(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan); + int (*port_vlan_dump)(struct dsa_switch *ds, int port, + struct switchdev_obj_port_vlan *vlan, + int (*cb)(struct switchdev_obj *obj)); int (*port_pvid_get)(struct dsa_switch *ds, int port, u16 *pvid); int (*vlan_getnext)(struct dsa_switch *ds, u16 *vid, unsigned long *ports, unsigned long *untagged); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 14ca9784ec0c..a9cbb72fb155 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -248,6 +248,9 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev, u16 pvid, vid = 0; int err; + if (ds->drv->port_vlan_dump) + return ds->drv->port_vlan_dump(ds, p->port, vlan, cb); + if (!ds->drv->vlan_getnext || !ds->drv->port_pvid_get) return -EOPNOTSUPP; -- cgit v1.2.3 From 477b184526a7f44164029eea720da0e0c888cac6 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 23 Feb 2016 12:13:56 -0500 Subject: net: dsa: drop vlan_getnext The VLAN GetNext operation is specific to some switches, and thus can be complicated to implement for some drivers. Remove the support for the vlan_getnext/port_pvid_get approach in favor of the generic and simpler port_vlan_dump function. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- Documentation/networking/dsa/dsa.txt | 9 --------- include/net/dsa.h | 3 --- net/dsa/slave.c | 35 +---------------------------------- 3 files changed, 1 insertion(+), 46 deletions(-) (limited to 'include/net/dsa.h') diff --git a/Documentation/networking/dsa/dsa.txt b/Documentation/networking/dsa/dsa.txt index 350a502e031f..974e9c387d1e 100644 --- a/Documentation/networking/dsa/dsa.txt +++ b/Documentation/networking/dsa/dsa.txt @@ -542,12 +542,6 @@ Bridge layer Bridge VLAN filtering --------------------- -- port_pvid_get: bridge layer function invoked when a Port-based VLAN ID is - queried for the given switch port - -- port_pvid_set: bridge layer function invoked when a Port-based VLAN ID needs - to be configured on the given switch port - - port_vlan_add: bridge layer function invoked when a VLAN is configured (tagged or untagged) for the given switch port @@ -558,9 +552,6 @@ Bridge VLAN filtering function that the driver has to call for each VLAN the given port is a member of. A switchdev object is used to carry the VID and bridge flags. -- vlan_getnext: bridge layer function invoked to query the next configured VLAN - in the switch, i.e. returns the bitmaps of members and untagged ports - - port_fdb_add: bridge layer function invoked when the bridge wants to install a Forwarding Database entry, the switch hardware should be programmed with the specified address in the specified VLAN Id in the forwarding database diff --git a/include/net/dsa.h b/include/net/dsa.h index ebc0d9ea96a1..3dd54867174a 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -316,9 +316,6 @@ struct dsa_switch_driver { int (*port_vlan_dump)(struct dsa_switch *ds, int port, struct switchdev_obj_port_vlan *vlan, int (*cb)(struct switchdev_obj *obj)); - int (*port_pvid_get)(struct dsa_switch *ds, int port, u16 *pvid); - int (*vlan_getnext)(struct dsa_switch *ds, u16 *vid, - unsigned long *ports, unsigned long *untagged); /* * Forwarding database diff --git a/net/dsa/slave.c b/net/dsa/slave.c index a9cbb72fb155..cde29239b60d 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -243,44 +243,11 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev, { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; - DECLARE_BITMAP(members, DSA_MAX_PORTS); - DECLARE_BITMAP(untagged, DSA_MAX_PORTS); - u16 pvid, vid = 0; - int err; if (ds->drv->port_vlan_dump) return ds->drv->port_vlan_dump(ds, p->port, vlan, cb); - if (!ds->drv->vlan_getnext || !ds->drv->port_pvid_get) - return -EOPNOTSUPP; - - err = ds->drv->port_pvid_get(ds, p->port, &pvid); - if (err) - return err; - - for (;;) { - err = ds->drv->vlan_getnext(ds, &vid, members, untagged); - if (err) - break; - - if (!test_bit(p->port, members)) - continue; - - memset(vlan, 0, sizeof(*vlan)); - vlan->vid_begin = vlan->vid_end = vid; - - if (vid == pvid) - vlan->flags |= BRIDGE_VLAN_INFO_PVID; - - if (test_bit(p->port, untagged)) - vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; - - err = cb(&vlan->obj); - if (err) - break; - } - - return err == -ENOENT ? 0 : err; + return -EOPNOTSUPP; } static int dsa_slave_port_fdb_add(struct net_device *dev, -- cgit v1.2.3 From fb2dabad69f099fb9c03a44276778911da50ba29 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 26 Feb 2016 13:16:00 -0500 Subject: net: dsa: support VLAN filtering switchdev attr When a user explicitly requests VLAN filtering with something like: # echo 1 > /sys/class/net//bridge/vlan_filtering Switchdev propagates a SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING port attribute. Add support for it in the DSA layer with a new port_vlan_filtering function to let drivers toggle 802.1Q filtering on user demand. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- include/net/dsa.h | 2 ++ net/dsa/slave.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'include/net/dsa.h') diff --git a/include/net/dsa.h b/include/net/dsa.h index 3dd54867174a..26c0a3fa009a 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -305,6 +305,8 @@ struct dsa_switch_driver { /* * VLAN support */ + int (*port_vlan_filtering)(struct dsa_switch *ds, int port, + bool vlan_filtering); int (*port_vlan_prepare)(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan, struct switchdev_trans *trans); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index cde29239b60d..27bf03d11670 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -317,6 +317,24 @@ static int dsa_slave_stp_update(struct net_device *dev, u8 state) return ret; } +static int dsa_slave_vlan_filtering(struct net_device *dev, + const struct switchdev_attr *attr, + struct switchdev_trans *trans) +{ + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->parent; + + /* bridge skips -EOPNOTSUPP, so skip the prepare phase */ + if (switchdev_trans_ph_prepare(trans)) + return 0; + + if (ds->drv->port_vlan_filtering) + return ds->drv->port_vlan_filtering(ds, p->port, + attr->u.vlan_filtering); + + return 0; +} + static int dsa_slave_port_attr_set(struct net_device *dev, const struct switchdev_attr *attr, struct switchdev_trans *trans) @@ -333,6 +351,9 @@ static int dsa_slave_port_attr_set(struct net_device *dev, ret = ds->drv->port_stp_update(ds, p->port, attr->u.stp_state); break; + case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: + ret = dsa_slave_vlan_filtering(dev, attr, trans); + break; default: ret = -EOPNOTSUPP; break; -- cgit v1.2.3 From 71327a4e7d997276d49db92fd3d30008389ee6d5 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Sun, 13 Mar 2016 16:21:32 -0400 Subject: net: dsa: rename port_*_bridge routines Rename DSA port_join_bridge and port_leave_bridge routines to respectively port_bridge_join and port_bridge_leave in order to respect an implicit Port::Bridge namespace. Signed-off-by: Vivien Didelot Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- Documentation/networking/dsa/dsa.txt | 4 ++-- drivers/net/dsa/bcm_sf2.c | 4 ++-- drivers/net/dsa/mv88e6171.c | 4 ++-- drivers/net/dsa/mv88e6352.c | 4 ++-- include/net/dsa.h | 4 ++-- net/dsa/slave.c | 8 ++++---- 6 files changed, 14 insertions(+), 14 deletions(-) (limited to 'include/net/dsa.h') diff --git a/Documentation/networking/dsa/dsa.txt b/Documentation/networking/dsa/dsa.txt index 974e9c387d1e..3b196c304b73 100644 --- a/Documentation/networking/dsa/dsa.txt +++ b/Documentation/networking/dsa/dsa.txt @@ -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 diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 3f627598f277..4bcc9ebf5e06 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -1387,8 +1387,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, diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index d72ccbdf53ec..c0164b98fc08 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -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, diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index a41fa5043d77..5f528abc8af1 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -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, diff --git a/include/net/dsa.h b/include/net/dsa.h index 26c0a3fa009a..004e034184c1 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -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); + int (*port_bridge_leave)(struct dsa_switch *ds, int port); int (*port_stp_update)(struct dsa_switch *ds, int port, u8 state); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 49056d90b179..52653d715f64 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -448,8 +448,8 @@ 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; } @@ -461,8 +461,8 @@ static int dsa_slave_bridge_port_leave(struct net_device *dev) int ret = -EOPNOTSUPP; - if (ds->drv->port_leave_bridge) - ret = ds->drv->port_leave_bridge(ds, p->port); + if (ds->drv->port_bridge_leave) + ret = ds->drv->port_bridge_leave(ds, p->port); p->bridge_dev = NULL; -- cgit v1.2.3 From 16bfa7024eba5e36aff38ba62086b9027373007d Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Sun, 13 Mar 2016 16:21:33 -0400 Subject: net: dsa: make port_bridge_leave return void netdev_upper_dev_unlink() which notifies NETDEV_CHANGEUPPER, returns void, as well as del_nbp(). So there's no advantage to catch an eventual error from the port_bridge_leave routine at the DSA level. Make this routine void for the DSA layer and its existing drivers. Signed-off-by: Vivien Didelot Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 4 +--- drivers/net/dsa/mv88e6xxx.c | 28 +++++++++------------------- drivers/net/dsa/mv88e6xxx.h | 2 +- include/net/dsa.h | 2 +- net/dsa/slave.c | 9 +++------ 5 files changed, 15 insertions(+), 30 deletions(-) (limited to 'include/net/dsa.h') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 4bcc9ebf5e06..95944d5e3e22 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -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, diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 5309c738ff00..fa086e09d6b7 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -2219,39 +2219,29 @@ unlock: 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) diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 281cefe86afd..9a038aba48fb 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -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); diff --git a/include/net/dsa.h b/include/net/dsa.h index 004e034184c1..6463bb2863ac 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -298,7 +298,7 @@ struct dsa_switch_driver { */ int (*port_bridge_join)(struct dsa_switch *ds, int port, struct net_device *bridge); - int (*port_bridge_leave)(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); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 52653d715f64..8e00f1d83eb8 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -454,15 +454,14 @@ static int dsa_slave_bridge_port_join(struct net_device *dev, return 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_bridge_leave) - ret = ds->drv->port_bridge_leave(ds, p->port); + 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, @@ -1156,7 +1153,7 @@ static int dsa_slave_master_changed(struct net_device *dev) !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); + dsa_slave_bridge_port_leave(dev); return err; } -- cgit v1.2.3