linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops
@ 2016-04-27 22:29 Vivien Didelot
  2016-04-27 22:29 ` [RFC 01/20] net: dsa: introduce a dsa_port structure Vivien Didelot
                   ` (19 more replies)
  0 siblings, 20 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:29 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

In a previous RFC [1], I introduced the need to implement cross-chip operations
in the DSA layer.

Here's a summary. In a multiple switches setup such as the following, every
switch of the tree must be aware of its configuration in order to configure a
correct data path between chips.

          sw0             sw1             sw2                                                             
    [ 0 1 2 3 4 5 ] [ 0 1 2 3 4 5 ] [ 0 1 2 3 4 5 ]                                                       
      |   '     ^     ^         ^     ^     '                                                             
      v   '     |     |         |     |     '                                                             
     CPU  '     `-DSA-'         `-DSA-'     '                                                             
          '                                 '                                                             
          + - - - - - - - br0 - - - - - - - +  

For instance, bridging sw0p2 and sw2p3 together in a VLAN 42 requires both
chips to allow frames from the external port to egress its internal port, all
DSA ports between them must learn their address, and sw1 must also be aware of
the VLAN 42 in order to allow tagged packets to cross the chip.

To implement all that nicely, we need a way to progagate such notification to
every switch of a DSA tree.

The patchset introduces a dsa_port structure to bundle port-centric info such
as its switch index, port number, bridge device, and change the DSA driver
functions to take such structure as parameter instead of a internal port
number.

The DSA layer then introduces tree-wide operations, which calls every switch
driver when a port operation occurs. This is the responsibility of a switch
driver to check if the related port is internal or external to its chip, and
behave in consequence.

See the patchset as different logical groups (that may be split later):

  * patches 1 to 5: introduce the dsa_port structure to DSA drivers

  * patches 6 to 11: put the bridge device in the dsa_port structure and allow
    the DSA drivers to get rid of their private bridge_dev pointer

  * patches 12 to 16: introduce tree-wide operations. Driver are now aware of
    cross-chip port operations

  * patches 17 to 20: implement cross-chip hardware bridging in mv88e6xxx

A branch is available here [2] and a debugfs patch is maintained here [3] in
order to inspect the Marvell switch's internal structures, such as the PVT.

Many things remains to do after this, such as using dsa_port_is_{cpu,dsa}
helpers, getting rid of dst->switches and ds->ports in favor of their related
switch and port lists, and introduce dynamic number of switches and ports.

[1] https://lkml.org/lkml/2016/4/20/733
[2] https://github.com/vivien/linux/tree/dsa/dev
[3] https://github.com/vivien/linux/commit/da33b1a698fef3a66515a05e2b9f31d0279a89d4.patch

Cheers,

Vivien Didelot (20):
  net: dsa: introduce a dsa_port structure
  net: dsa: be consistent with NETDEV_CHANGEUPPER
  net: dsa: pass dsa_port down to drivers bridge ops
  net: dsa: pass dsa_port down to drivers FDB ops
  net: dsa: pass dsa_port down to drivers VLAN ops
  net: dsa: move bridge device in dsa_port
  net: dsa: list ports in switch
  net: dsa: bcm_sf2: use bridge device from dsa_port
  net: dsa: mv88e6xxx: check HW vlan with dsa_port
  net: dsa: mv88e6xxx: setup a dsa_port
  net: dsa: mv88e6xxx: use bridge from dsa_port
  net: dsa: rename dst->ds to dst->switches
  net: dsa: list switches in tree
  net: dsa: add tree-wide bridge ops
  net: dsa: add tree-wide FDB ops
  net: dsa: add tree-wide VLAN ops
  net: dsa: mv88e6xxx: factorize port bridge change
  net: dsa: mv88e6xxx: add flags to info
  net: dsa: mv88e6xxx: conditionally init PVT
  net: dsa: mv88e6xxx: setup PVT on cross-chip ops

 drivers/net/dsa/bcm_sf2.c   |  92 +++++-----
 drivers/net/dsa/bcm_sf2.h   |   2 -
 drivers/net/dsa/mv88e6352.c |   1 +
 drivers/net/dsa/mv88e6xxx.c | 397 ++++++++++++++++++++++++++++++++------------
 drivers/net/dsa/mv88e6xxx.h |  41 +++--
 include/net/dsa.h           |  57 +++++--
 net/dsa/Makefile            |   2 +-
 net/dsa/dsa.c               |  25 ++-
 net/dsa/dsa_priv.h          |  37 +++--
 net/dsa/slave.c             | 283 +++++++++----------------------
 net/dsa/tag_brcm.c          |   6 +-
 net/dsa/tag_dsa.c           |  10 +-
 net/dsa/tag_edsa.c          |  10 +-
 net/dsa/tag_trailer.c       |   4 +-
 net/dsa/tree.c              | 187 +++++++++++++++++++++
 15 files changed, 751 insertions(+), 403 deletions(-)
 create mode 100644 net/dsa/tree.c

-- 
2.8.0

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [RFC 01/20] net: dsa: introduce a dsa_port structure
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
@ 2016-04-27 22:29 ` Vivien Didelot
  2016-04-27 23:07   ` Andrew Lunn
  2016-04-27 22:29 ` [RFC 02/20] net: dsa: be consistent with NETDEV_CHANGEUPPER Vivien Didelot
                   ` (18 subsequent siblings)
  19 siblings, 1 reply; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:29 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Introduce a new dsa_port structure, used to store port-centric
information, such as a pointer to its DSA switch and its port number.
It will later contains further data, such as its bridge device.

This is a first step towards implementing cross-chip port operations.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 include/net/dsa.h     |   5 ++
 net/dsa/dsa.c         |  10 +++-
 net/dsa/dsa_priv.h    |  13 ++---
 net/dsa/slave.c       | 147 +++++++++++++++++++++++++-------------------------
 net/dsa/tag_brcm.c    |   4 +-
 net/dsa/tag_dsa.c     |   8 +--
 net/dsa/tag_edsa.c    |   8 +--
 net/dsa/tag_trailer.c |   2 +-
 8 files changed, 104 insertions(+), 93 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 2d280ab..255c108 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -122,6 +122,11 @@ struct dsa_switch_tree {
 	struct dsa_switch	*ds[DSA_MAX_SWITCHES];
 };
 
+struct dsa_port {
+	struct dsa_switch	*ds;
+	int			port;
+};
+
 struct dsa_switch {
 	/*
 	 * Parent switch tree, and switch index.
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index d61ceed..222494c 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -219,6 +219,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
 {
 	struct dsa_switch_driver *drv = ds->drv;
 	struct dsa_switch_tree *dst = ds->dst;
+	struct dsa_port *dp[DSA_MAX_PORTS];
 	struct dsa_chip_data *pd = ds->pd;
 	bool valid_name_found = false;
 	int index = ds->index;
@@ -230,6 +231,13 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
 	for (i = 0; i < DSA_MAX_PORTS; i++) {
 		char *name;
 
+		dp[i] = devm_kzalloc(parent, sizeof(*dp), GFP_KERNEL);
+		if (dp[i] == NULL)
+			return -ENOMEM;
+
+		dp[i]->ds = ds;
+		dp[i]->port = i;
+
 		name = pd->port_names[i];
 		if (name == NULL)
 			continue;
@@ -328,7 +336,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
 		if (!(ds->enabled_port_mask & (1 << i)))
 			continue;
 
-		ret = dsa_slave_create(ds, parent, i, pd->port_names[i]);
+		ret = dsa_slave_create(dp[i], parent, pd->port_names[i]);
 		if (ret < 0) {
 			netdev_err(dst->master_netdev, "[%d]: can't create dsa slave device for port %d(%s): %d\n",
 				   index, i, pd->port_names[i], ret);
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index dfa3377..c7d5df0 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -26,13 +26,6 @@ struct dsa_slave_priv {
 					struct net_device *dev);
 
 	/*
-	 * Which switch this port is a part of, and the port index
-	 * for this port.
-	 */
-	struct dsa_switch	*parent;
-	u8			port;
-
-	/*
 	 * The phylib phy_device pointer for the PHY connected
 	 * to this port.
 	 */
@@ -46,6 +39,9 @@ struct dsa_slave_priv {
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	struct netpoll		*netpoll;
 #endif
+
+	/* DSA specific data */
+	struct dsa_port		*dp;
 };
 
 /* dsa.c */
@@ -54,8 +50,7 @@ extern char dsa_driver_version[];
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
 void dsa_slave_mii_bus_init(struct dsa_switch *ds);
-int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
-		     int port, char *name);
+int dsa_slave_create(struct dsa_port *dp, struct device *parent, char *name);
 void dsa_slave_destroy(struct net_device *slave_dev);
 int dsa_slave_suspend(struct net_device *slave_dev);
 int dsa_slave_resume(struct net_device *slave_dev);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 3b6750f..6115444 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -61,7 +61,7 @@ static int dsa_slave_get_iflink(const struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
 
-	return p->parent->dst->master_netdev->ifindex;
+	return p->dp->ds->dst->master_netdev->ifindex;
 }
 
 static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p)
@@ -72,8 +72,8 @@ static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p)
 static int dsa_slave_open(struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct net_device *master = p->parent->dst->master_netdev;
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
+	struct net_device *master = ds->dst->master_netdev;
 	u8 stp_state = dsa_port_is_bridged(p) ?
 			BR_STATE_BLOCKING : BR_STATE_FORWARDING;
 	int err;
@@ -99,13 +99,13 @@ static int dsa_slave_open(struct net_device *dev)
 	}
 
 	if (ds->drv->port_enable) {
-		err = ds->drv->port_enable(ds, p->port, p->phy);
+		err = ds->drv->port_enable(ds, p->dp->port, p->phy);
 		if (err)
 			goto clear_promisc;
 	}
 
 	if (ds->drv->port_stp_state_set)
-		ds->drv->port_stp_state_set(ds, p->port, stp_state);
+		ds->drv->port_stp_state_set(ds, p->dp->port, stp_state);
 
 	if (p->phy)
 		phy_start(p->phy);
@@ -128,8 +128,8 @@ out:
 static int dsa_slave_close(struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct net_device *master = p->parent->dst->master_netdev;
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
+	struct net_device *master = ds->dst->master_netdev;
 
 	if (p->phy)
 		phy_stop(p->phy);
@@ -145,10 +145,10 @@ static int dsa_slave_close(struct net_device *dev)
 		dev_uc_del(master, dev->dev_addr);
 
 	if (ds->drv->port_disable)
-		ds->drv->port_disable(ds, p->port, p->phy);
+		ds->drv->port_disable(ds, p->dp->port, p->phy);
 
 	if (ds->drv->port_stp_state_set)
-		ds->drv->port_stp_state_set(ds, p->port, BR_STATE_DISABLED);
+		ds->drv->port_stp_state_set(ds, p->dp->port, BR_STATE_DISABLED);
 
 	return 0;
 }
@@ -156,7 +156,7 @@ static int dsa_slave_close(struct net_device *dev)
 static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct net_device *master = p->parent->dst->master_netdev;
+	struct net_device *master = p->dp->ds->dst->master_netdev;
 
 	if (change & IFF_ALLMULTI)
 		dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1);
@@ -167,7 +167,7 @@ static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
 static void dsa_slave_set_rx_mode(struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct net_device *master = p->parent->dst->master_netdev;
+	struct net_device *master = p->dp->ds->dst->master_netdev;
 
 	dev_mc_sync(master, dev);
 	dev_uc_sync(master, dev);
@@ -176,7 +176,7 @@ static void dsa_slave_set_rx_mode(struct net_device *dev)
 static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct net_device *master = p->parent->dst->master_netdev;
+	struct net_device *master = p->dp->ds->dst->master_netdev;
 	struct sockaddr *addr = a;
 	int err;
 
@@ -206,16 +206,16 @@ static int dsa_slave_port_vlan_add(struct net_device *dev,
 				   struct switchdev_trans *trans)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (switchdev_trans_ph_prepare(trans)) {
 		if (!ds->drv->port_vlan_prepare || !ds->drv->port_vlan_add)
 			return -EOPNOTSUPP;
 
-		return ds->drv->port_vlan_prepare(ds, p->port, vlan, trans);
+		return ds->drv->port_vlan_prepare(ds, p->dp->port, vlan, trans);
 	}
 
-	ds->drv->port_vlan_add(ds, p->port, vlan, trans);
+	ds->drv->port_vlan_add(ds, p->dp->port, vlan, trans);
 
 	return 0;
 }
@@ -224,12 +224,12 @@ static int dsa_slave_port_vlan_del(struct net_device *dev,
 				   const struct switchdev_obj_port_vlan *vlan)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (!ds->drv->port_vlan_del)
 		return -EOPNOTSUPP;
 
-	return ds->drv->port_vlan_del(ds, p->port, vlan);
+	return ds->drv->port_vlan_del(ds, p->dp->port, vlan);
 }
 
 static int dsa_slave_port_vlan_dump(struct net_device *dev,
@@ -237,10 +237,10 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev,
 				    switchdev_obj_dump_cb_t *cb)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (ds->drv->port_vlan_dump)
-		return ds->drv->port_vlan_dump(ds, p->port, vlan, cb);
+		return ds->drv->port_vlan_dump(ds, p->dp->port, vlan, cb);
 
 	return -EOPNOTSUPP;
 }
@@ -250,16 +250,16 @@ static int dsa_slave_port_fdb_add(struct net_device *dev,
 				  struct switchdev_trans *trans)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (switchdev_trans_ph_prepare(trans)) {
 		if (!ds->drv->port_fdb_prepare || !ds->drv->port_fdb_add)
 			return -EOPNOTSUPP;
 
-		return ds->drv->port_fdb_prepare(ds, p->port, fdb, trans);
+		return ds->drv->port_fdb_prepare(ds, p->dp->port, fdb, trans);
 	}
 
-	ds->drv->port_fdb_add(ds, p->port, fdb, trans);
+	ds->drv->port_fdb_add(ds, p->dp->port, fdb, trans);
 
 	return 0;
 }
@@ -268,11 +268,11 @@ static int dsa_slave_port_fdb_del(struct net_device *dev,
 				  const struct switchdev_obj_port_fdb *fdb)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 	int ret = -EOPNOTSUPP;
 
 	if (ds->drv->port_fdb_del)
-		ret = ds->drv->port_fdb_del(ds, p->port, fdb);
+		ret = ds->drv->port_fdb_del(ds, p->dp->port, fdb);
 
 	return ret;
 }
@@ -282,10 +282,10 @@ static int dsa_slave_port_fdb_dump(struct net_device *dev,
 				   switchdev_obj_dump_cb_t *cb)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (ds->drv->port_fdb_dump)
-		return ds->drv->port_fdb_dump(ds, p->port, fdb, cb);
+		return ds->drv->port_fdb_dump(ds, p->dp->port, fdb, cb);
 
 	return -EOPNOTSUPP;
 }
@@ -305,12 +305,12 @@ static int dsa_slave_stp_state_set(struct net_device *dev,
 				   struct switchdev_trans *trans)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (switchdev_trans_ph_prepare(trans))
 		return ds->drv->port_stp_state_set ? 0 : -EOPNOTSUPP;
 
-	ds->drv->port_stp_state_set(ds, p->port, attr->u.stp_state);
+	ds->drv->port_stp_state_set(ds, p->dp->port, attr->u.stp_state);
 
 	return 0;
 }
@@ -320,14 +320,14 @@ static int dsa_slave_vlan_filtering(struct net_device *dev,
 				    struct switchdev_trans *trans)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	/* 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,
+		return ds->drv->port_vlan_filtering(ds, p->dp->port,
 						    attr->u.vlan_filtering);
 
 	return 0;
@@ -435,13 +435,13 @@ static int dsa_slave_bridge_port_join(struct net_device *dev,
 				      struct net_device *br)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 	int ret = -EOPNOTSUPP;
 
 	p->bridge_dev = br;
 
 	if (ds->drv->port_bridge_join)
-		ret = ds->drv->port_bridge_join(ds, p->port, br);
+		ret = ds->drv->port_bridge_join(ds, p->dp->port, br);
 
 	return ret == -EOPNOTSUPP ? 0 : ret;
 }
@@ -449,11 +449,11 @@ static int dsa_slave_bridge_port_join(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;
+	struct dsa_switch *ds = p->dp->ds;
 
 
 	if (ds->drv->port_bridge_leave)
-		ds->drv->port_bridge_leave(ds, p->port);
+		ds->drv->port_bridge_leave(ds, p->dp->port);
 
 	p->bridge_dev = NULL;
 
@@ -461,14 +461,15 @@ static void dsa_slave_bridge_port_leave(struct net_device *dev)
 	 * so allow it to be in BR_STATE_FORWARDING to be kept functional
 	 */
 	if (ds->drv->port_stp_state_set)
-		ds->drv->port_stp_state_set(ds, p->port, BR_STATE_FORWARDING);
+		ds->drv->port_stp_state_set(ds, p->dp->port,
+					    BR_STATE_FORWARDING);
 }
 
 static int dsa_slave_port_attr_get(struct net_device *dev,
 				   struct switchdev_attr *attr)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	switch (attr->id) {
 	case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
@@ -516,7 +517,7 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* Queue the SKB for transmission on the parent interface, but
 	 * do not modify its EtherType
 	 */
-	nskb->dev = p->parent->dst->master_netdev;
+	nskb->dev = p->dp->ds->dst->master_netdev;
 	dev_queue_xmit(nskb);
 
 	return NETDEV_TX_OK;
@@ -570,10 +571,10 @@ static void dsa_slave_get_drvinfo(struct net_device *dev,
 static int dsa_slave_get_regs_len(struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (ds->drv->get_regs_len)
-		return ds->drv->get_regs_len(ds, p->port);
+		return ds->drv->get_regs_len(ds, p->dp->port);
 
 	return -EOPNOTSUPP;
 }
@@ -582,10 +583,10 @@ static void
 dsa_slave_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (ds->drv->get_regs)
-		ds->drv->get_regs(ds, p->port, regs, _p);
+		ds->drv->get_regs(ds, p->dp->port, regs, _p);
 }
 
 static int dsa_slave_nway_reset(struct net_device *dev)
@@ -613,7 +614,7 @@ static u32 dsa_slave_get_link(struct net_device *dev)
 static int dsa_slave_get_eeprom_len(struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (ds->pd->eeprom_len)
 		return ds->pd->eeprom_len;
@@ -628,7 +629,7 @@ static int dsa_slave_get_eeprom(struct net_device *dev,
 				struct ethtool_eeprom *eeprom, u8 *data)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (ds->drv->get_eeprom)
 		return ds->drv->get_eeprom(ds, eeprom, data);
@@ -640,7 +641,7 @@ static int dsa_slave_set_eeprom(struct net_device *dev,
 				struct ethtool_eeprom *eeprom, u8 *data)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (ds->drv->set_eeprom)
 		return ds->drv->set_eeprom(ds, eeprom, data);
@@ -652,7 +653,7 @@ static void dsa_slave_get_strings(struct net_device *dev,
 				  uint32_t stringset, uint8_t *data)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (stringset == ETH_SS_STATS) {
 		int len = ETH_GSTRING_LEN;
@@ -662,7 +663,7 @@ static void dsa_slave_get_strings(struct net_device *dev,
 		strncpy(data + 2 * len, "rx_packets", len);
 		strncpy(data + 3 * len, "rx_bytes", len);
 		if (ds->drv->get_strings != NULL)
-			ds->drv->get_strings(ds, p->port, data + 4 * len);
+			ds->drv->get_strings(ds, p->dp->port, data + 4 * len);
 	}
 }
 
@@ -671,20 +672,20 @@ static void dsa_slave_get_ethtool_stats(struct net_device *dev,
 					uint64_t *data)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	data[0] = dev->stats.tx_packets;
 	data[1] = dev->stats.tx_bytes;
 	data[2] = dev->stats.rx_packets;
 	data[3] = dev->stats.rx_bytes;
 	if (ds->drv->get_ethtool_stats != NULL)
-		ds->drv->get_ethtool_stats(ds, p->port, data + 4);
+		ds->drv->get_ethtool_stats(ds, p->dp->port, data + 4);
 }
 
 static int dsa_slave_get_sset_count(struct net_device *dev, int sset)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (sset == ETH_SS_STATS) {
 		int count;
@@ -702,20 +703,20 @@ static int dsa_slave_get_sset_count(struct net_device *dev, int sset)
 static void dsa_slave_get_wol(struct net_device *dev, struct ethtool_wolinfo *w)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	if (ds->drv->get_wol)
-		ds->drv->get_wol(ds, p->port, w);
+		ds->drv->get_wol(ds, p->dp->port, w);
 }
 
 static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 	int ret = -EOPNOTSUPP;
 
 	if (ds->drv->set_wol)
-		ret = ds->drv->set_wol(ds, p->port, w);
+		ret = ds->drv->set_wol(ds, p->dp->port, w);
 
 	return ret;
 }
@@ -723,13 +724,13 @@ static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w)
 static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 	int ret;
 
 	if (!ds->drv->set_eee)
 		return -EOPNOTSUPP;
 
-	ret = ds->drv->set_eee(ds, p->port, p->phy, e);
+	ret = ds->drv->set_eee(ds, p->dp->port, p->phy, e);
 	if (ret)
 		return ret;
 
@@ -742,13 +743,13 @@ static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e)
 static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 	int ret;
 
 	if (!ds->drv->get_eee)
 		return -EOPNOTSUPP;
 
-	ret = ds->drv->get_eee(ds, p->port, e);
+	ret = ds->drv->get_eee(ds, p->dp->port, e);
 	if (ret)
 		return ret;
 
@@ -763,7 +764,7 @@ static int dsa_slave_netpoll_setup(struct net_device *dev,
 				   struct netpoll_info *ni)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 	struct net_device *master = ds->dst->master_netdev;
 	struct netpoll *netpoll;
 	int err = 0;
@@ -858,7 +859,7 @@ static struct device_type dsa_type = {
 static void dsa_slave_adjust_link(struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 	unsigned int status_changed = 0;
 
 	if (p->old_link != p->phy->link) {
@@ -877,7 +878,7 @@ static void dsa_slave_adjust_link(struct net_device *dev)
 	}
 
 	if (ds->drv->adjust_link && status_changed)
-		ds->drv->adjust_link(ds, p->port, p->phy);
+		ds->drv->adjust_link(ds, p->dp->port, p->phy);
 
 	if (status_changed)
 		phy_print_status(p->phy);
@@ -891,9 +892,9 @@ static int dsa_slave_fixed_link_update(struct net_device *dev,
 
 	if (dev) {
 		p = netdev_priv(dev);
-		ds = p->parent;
+		ds = p->dp->ds;
 		if (ds->drv->fixed_link_update)
-			ds->drv->fixed_link_update(ds, p->port, status);
+			ds->drv->fixed_link_update(ds, p->dp->port, status);
 	}
 
 	return 0;
@@ -904,7 +905,7 @@ static int dsa_slave_phy_connect(struct dsa_slave_priv *p,
 				 struct net_device *slave_dev,
 				 int addr)
 {
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 
 	p->phy = mdiobus_get_phy(ds->slave_mii_bus, addr);
 	if (!p->phy) {
@@ -924,14 +925,14 @@ static int dsa_slave_phy_connect(struct dsa_slave_priv *p,
 static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
 				struct net_device *slave_dev)
 {
-	struct dsa_switch *ds = p->parent;
+	struct dsa_switch *ds = p->dp->ds;
 	struct dsa_chip_data *cd = ds->pd;
 	struct device_node *phy_dn, *port_dn;
 	bool phy_is_fixed = false;
 	u32 phy_flags = 0;
 	int mode, ret;
 
-	port_dn = cd->port_dn[p->port];
+	port_dn = cd->port_dn[p->dp->port];
 	mode = of_get_phy_mode(port_dn);
 	if (mode < 0)
 		mode = PHY_INTERFACE_MODE_NA;
@@ -952,7 +953,7 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
 	}
 
 	if (ds->drv->get_phy_flags)
-		phy_flags = ds->drv->get_phy_flags(ds, p->port);
+		phy_flags = ds->drv->get_phy_flags(ds, p->dp->port);
 
 	if (phy_dn) {
 		int phy_id = of_mdio_parse_addr(&slave_dev->dev, phy_dn);
@@ -984,9 +985,11 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
 	 * MDIO bus instead
 	 */
 	if (!p->phy) {
-		ret = dsa_slave_phy_connect(p, slave_dev, p->port);
+		ret = dsa_slave_phy_connect(p, slave_dev, p->dp->port);
 		if (ret) {
-			netdev_err(slave_dev, "failed to connect to port %d: %d\n", p->port, ret);
+			netdev_err(slave_dev,
+				   "failed to connect to port %d: %d\n",
+				   p->dp->port, ret);
 			return ret;
 		}
 	}
@@ -1034,12 +1037,13 @@ int dsa_slave_resume(struct net_device *slave_dev)
 	return 0;
 }
 
-int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
-		     int port, char *name)
+int dsa_slave_create(struct dsa_port *dp, struct device *parent, char *name)
 {
+	struct dsa_switch *ds = dp->ds;
 	struct net_device *master = ds->dst->master_netdev;
 	struct net_device *slave_dev;
 	struct dsa_slave_priv *p;
+	int port = dp->port;
 	int ret;
 
 	slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), name,
@@ -1063,8 +1067,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
 	slave_dev->vlan_features = master->vlan_features;
 
 	p = netdev_priv(slave_dev);
-	p->parent = ds;
-	p->port = port;
+	p->dp = dp;
 
 	switch (ds->dst->tag_protocol) {
 #ifdef CONFIG_NET_DSA_TAG_DSA
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index e2aadb7..3d5aabc 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -80,9 +80,9 @@ static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev
 			((skb->priority << BRCM_IG_TC_SHIFT) & BRCM_IG_TC_MASK);
 	brcm_tag[1] = 0;
 	brcm_tag[2] = 0;
-	if (p->port == 8)
+	if (p->dp->port == 8)
 		brcm_tag[2] = BRCM_IG_DSTMAP2_MASK;
-	brcm_tag[3] = (1 << p->port) & BRCM_IG_DSTMAP1_MASK;
+	brcm_tag[3] = (1 << p->dp->port) & BRCM_IG_DSTMAP1_MASK;
 
 	return skb;
 
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index aa780e4..c870cfa 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -33,8 +33,8 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)
 		 * Construct tagged FROM_CPU DSA tag from 802.1q tag.
 		 */
 		dsa_header = skb->data + 2 * ETH_ALEN;
-		dsa_header[0] = 0x60 | p->parent->index;
-		dsa_header[1] = p->port << 3;
+		dsa_header[0] = 0x60 | p->dp->ds->index;
+		dsa_header[1] = p->dp->port << 3;
 
 		/*
 		 * Move CFI field from byte 2 to byte 1.
@@ -54,8 +54,8 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)
 		 * Construct untagged FROM_CPU DSA tag.
 		 */
 		dsa_header = skb->data + 2 * ETH_ALEN;
-		dsa_header[0] = 0x40 | p->parent->index;
-		dsa_header[1] = p->port << 3;
+		dsa_header[0] = 0x40 | p->dp->ds->index;
+		dsa_header[1] = p->dp->port << 3;
 		dsa_header[2] = 0x00;
 		dsa_header[3] = 0x00;
 	}
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index 2288c80..898f949d 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -42,8 +42,8 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)
 		edsa_header[1] = ETH_P_EDSA & 0xff;
 		edsa_header[2] = 0x00;
 		edsa_header[3] = 0x00;
-		edsa_header[4] = 0x60 | p->parent->index;
-		edsa_header[5] = p->port << 3;
+		edsa_header[4] = 0x60 | p->dp->ds->index;
+		edsa_header[5] = p->dp->port << 3;
 
 		/*
 		 * Move CFI field from byte 6 to byte 5.
@@ -67,8 +67,8 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)
 		edsa_header[1] = ETH_P_EDSA & 0xff;
 		edsa_header[2] = 0x00;
 		edsa_header[3] = 0x00;
-		edsa_header[4] = 0x40 | p->parent->index;
-		edsa_header[5] = p->port << 3;
+		edsa_header[4] = 0x40 | p->dp->ds->index;
+		edsa_header[5] = p->dp->port << 3;
 		edsa_header[6] = 0x00;
 		edsa_header[7] = 0x00;
 	}
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
index b6ca089..eaa3440 100644
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -50,7 +50,7 @@ static struct sk_buff *trailer_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	trailer = skb_put(nskb, 4);
 	trailer[0] = 0x80;
-	trailer[1] = 1 << p->port;
+	trailer[1] = 1 << p->dp->port;
 	trailer[2] = 0x10;
 	trailer[3] = 0x00;
 
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 02/20] net: dsa: be consistent with NETDEV_CHANGEUPPER
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
  2016-04-27 22:29 ` [RFC 01/20] net: dsa: introduce a dsa_port structure Vivien Didelot
@ 2016-04-27 22:29 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 03/20] net: dsa: pass dsa_port down to drivers bridge ops Vivien Didelot
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:29 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Once NETDEV_CHANGEUPPER is emitted, the device is already (un)bridged.

If an error is returned on port_bridge_join, the bridge layer will
rollback the operation and unbridge the port.

Respect this by setting bridge_dev to NULL on error.

Also the DSA layer shouldn't assume that the drivers know about the
bridge device a port was previously bridged to. So pass the bridge
device to port_bridge_leave.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/bcm_sf2.c   |  4 ++--
 drivers/net/dsa/mv88e6xxx.c |  4 ++--
 drivers/net/dsa/mv88e6xxx.h |  3 ++-
 include/net/dsa.h           |  3 ++-
 net/dsa/slave.c             | 13 +++++++++----
 5 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 448deb5..f394ea9 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -525,10 +525,10 @@ static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
 	return 0;
 }
 
-static void 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 net_device *bridge)
 {
 	struct bcm_sf2_priv *priv = ds_to_priv(ds);
-	struct net_device *bridge = priv->port_sts[port].bridge_dev;
 	unsigned int i;
 	u32 reg, p_ctl;
 
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 028f92f..86f8f2f 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -2227,10 +2227,10 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
 	return err;
 }
 
-void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
+void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
+				 struct net_device *bridge)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-	struct net_device *bridge = ps->ports[port].bridge_dev;
 	int i;
 
 	mutex_lock(&ps->smi_mutex);
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 0dbe2d1..2eb9a82 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -492,7 +492,8 @@ 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);
-void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port);
+void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
+				 struct net_device *bridge);
 void mv88e6xxx_port_stp_state_set(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 255c108..ed33500 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -305,7 +305,8 @@ struct dsa_switch_driver {
 	 */
 	int	(*port_bridge_join)(struct dsa_switch *ds, int port,
 				    struct net_device *bridge);
-	void	(*port_bridge_leave)(struct dsa_switch *ds, int port);
+	void	(*port_bridge_leave)(struct dsa_switch *ds, int port,
+				     struct net_device *bridge);
 	void	(*port_stp_state_set)(struct dsa_switch *ds, int port,
 				      u8 state);
 
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 6115444..f2ec13d 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -443,19 +443,24 @@ static int dsa_slave_bridge_port_join(struct net_device *dev,
 	if (ds->drv->port_bridge_join)
 		ret = ds->drv->port_bridge_join(ds, p->dp->port, br);
 
-	return ret == -EOPNOTSUPP ? 0 : ret;
+	if (ret && ret != -EOPNOTSUPP) {
+		p->bridge_dev = NULL;
+		return ret;
+	}
+
+	return 0;
 }
 
 static void dsa_slave_bridge_port_leave(struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
 	struct dsa_switch *ds = p->dp->ds;
+	struct net_device *br = p->bridge_dev;
 
+	p->bridge_dev = NULL;
 
 	if (ds->drv->port_bridge_leave)
-		ds->drv->port_bridge_leave(ds, p->dp->port);
-
-	p->bridge_dev = NULL;
+		ds->drv->port_bridge_leave(ds, p->dp->port, br);
 
 	/* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
 	 * so allow it to be in BR_STATE_FORWARDING to be kept functional
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 03/20] net: dsa: pass dsa_port down to drivers bridge ops
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
  2016-04-27 22:29 ` [RFC 01/20] net: dsa: introduce a dsa_port structure Vivien Didelot
  2016-04-27 22:29 ` [RFC 02/20] net: dsa: be consistent with NETDEV_CHANGEUPPER Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 23:12   ` Andrew Lunn
  2016-04-27 22:30 ` [RFC 04/20] net: dsa: pass dsa_port down to drivers FDB ops Vivien Didelot
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Now that DSA as proper structure for DSA ports, pass it down to the
port_bridge_join and port_bridge_leave driver functions.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/bcm_sf2.c   | 28 ++++++++++++++--------------
 drivers/net/dsa/mv88e6xxx.c | 10 +++++-----
 drivers/net/dsa/mv88e6xxx.h |  4 ++--
 include/net/dsa.h           |  4 ++--
 net/dsa/slave.c             |  4 ++--
 5 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index f394ea9..2d7b297 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -491,15 +491,15 @@ static int bcm_sf2_sw_fast_age_port(struct dsa_switch  *ds, int port)
 	return 0;
 }
 
-static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
+static int bcm_sf2_sw_br_join(struct dsa_switch *ds, struct dsa_port *dp,
 			      struct net_device *bridge)
 {
 	struct bcm_sf2_priv *priv = ds_to_priv(ds);
 	unsigned int i;
 	u32 reg, p_ctl;
 
-	priv->port_sts[port].bridge_dev = bridge;
-	p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
+	priv->port_sts[dp->port].bridge_dev = bridge;
+	p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(dp->port));
 
 	for (i = 0; i < priv->hw_params.num_ports; i++) {
 		if (priv->port_sts[i].bridge_dev != bridge)
@@ -509,7 +509,7 @@ static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
 		 * membership and update the remote port bitmask
 		 */
 		reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
-		reg |= 1 << port;
+		reg |= 1 << dp->port;
 		core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
 		priv->port_sts[i].vlan_ctl_mask = reg;
 
@@ -519,20 +519,20 @@ static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
 	/* Configure the local port VLAN control membership to include
 	 * remote ports and update the local port bitmask
 	 */
-	core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port));
-	priv->port_sts[port].vlan_ctl_mask = p_ctl;
+	core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(dp->port));
+	priv->port_sts[dp->port].vlan_ctl_mask = p_ctl;
 
 	return 0;
 }
 
-static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port,
+static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, struct dsa_port *dp,
 				struct net_device *bridge)
 {
 	struct bcm_sf2_priv *priv = ds_to_priv(ds);
 	unsigned int i;
 	u32 reg, p_ctl;
 
-	p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
+	p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(dp->port));
 
 	for (i = 0; i < priv->hw_params.num_ports; i++) {
 		/* Don't touch the remaining ports */
@@ -540,18 +540,18 @@ static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port,
 			continue;
 
 		reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
-		reg &= ~(1 << port);
+		reg &= ~(1 << dp->port);
 		core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
-		priv->port_sts[port].vlan_ctl_mask = reg;
+		priv->port_sts[dp->port].vlan_ctl_mask = reg;
 
 		/* Prevent self removal to preserve isolation */
-		if (port != i)
+		if (dp->port != i)
 			p_ctl &= ~(1 << i);
 	}
 
-	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;
+	core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(dp->port));
+	priv->port_sts[dp->port].vlan_ctl_mask = p_ctl;
+	priv->port_sts[dp->port].bridge_dev = NULL;
 }
 
 static void 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 86f8f2f..3f78c73 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -2203,7 +2203,7 @@ unlock:
 	return err;
 }
 
-int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, struct dsa_port *dp,
 			       struct net_device *bridge)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
@@ -2212,7 +2212,7 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
 	mutex_lock(&ps->smi_mutex);
 
 	/* Assign the bridge and remap each port's VLANTable */
-	ps->ports[port].bridge_dev = bridge;
+	ps->ports[dp->port].bridge_dev = bridge;
 
 	for (i = 0; i < ps->info->num_ports; ++i) {
 		if (ps->ports[i].bridge_dev == bridge) {
@@ -2227,7 +2227,7 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
 	return err;
 }
 
-void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
+void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, struct dsa_port *dp,
 				 struct net_device *bridge)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
@@ -2236,10 +2236,10 @@ void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
 	mutex_lock(&ps->smi_mutex);
 
 	/* Unassign the bridge and remap each port's VLANTable */
-	ps->ports[port].bridge_dev = NULL;
+	ps->ports[dp->port].bridge_dev = NULL;
 
 	for (i = 0; i < ps->info->num_ports; ++i)
-		if (i == port || ps->ports[i].bridge_dev == bridge)
+		if (i == dp->port || ps->ports[i].bridge_dev == bridge)
 			if (_mv88e6xxx_port_based_vlan_map(ds, i))
 				netdev_warn(ds->ports[i], "failed to remap\n");
 
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 2eb9a82..55b8eac 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -490,9 +490,9 @@ int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum,
 int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e);
 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,
+int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, struct dsa_port *dp,
 			       struct net_device *bridge);
-void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
+void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, struct dsa_port *dp,
 				 struct net_device *bridge);
 void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
 int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
diff --git a/include/net/dsa.h b/include/net/dsa.h
index ed33500..fb626ae 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -303,9 +303,9 @@ struct dsa_switch_driver {
 	/*
 	 * Bridge integration
 	 */
-	int	(*port_bridge_join)(struct dsa_switch *ds, int port,
+	int	(*port_bridge_join)(struct dsa_switch *ds, struct dsa_port *dp,
 				    struct net_device *bridge);
-	void	(*port_bridge_leave)(struct dsa_switch *ds, int port,
+	void	(*port_bridge_leave)(struct dsa_switch *ds, struct dsa_port *dp,
 				     struct net_device *bridge);
 	void	(*port_stp_state_set)(struct dsa_switch *ds, int port,
 				      u8 state);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index f2ec13d..9a8ea9a 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -441,7 +441,7 @@ static int dsa_slave_bridge_port_join(struct net_device *dev,
 	p->bridge_dev = br;
 
 	if (ds->drv->port_bridge_join)
-		ret = ds->drv->port_bridge_join(ds, p->dp->port, br);
+		ret = ds->drv->port_bridge_join(ds, p->dp, br);
 
 	if (ret && ret != -EOPNOTSUPP) {
 		p->bridge_dev = NULL;
@@ -460,7 +460,7 @@ static void dsa_slave_bridge_port_leave(struct net_device *dev)
 	p->bridge_dev = NULL;
 
 	if (ds->drv->port_bridge_leave)
-		ds->drv->port_bridge_leave(ds, p->dp->port, br);
+		ds->drv->port_bridge_leave(ds, p->dp, br);
 
 	/* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
 	 * so allow it to be in BR_STATE_FORWARDING to be kept functional
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 04/20] net: dsa: pass dsa_port down to drivers FDB ops
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (2 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 03/20] net: dsa: pass dsa_port down to drivers bridge ops Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 05/20] net: dsa: pass dsa_port down to drivers VLAN ops Vivien Didelot
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Now that DSA as proper structure for DSA ports, pass it down to the
port_fdb_{prepare,add,del,dump} driver functions.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/bcm_sf2.c   | 20 +++++++++++---------
 drivers/net/dsa/mv88e6xxx.c | 22 +++++++++++-----------
 drivers/net/dsa/mv88e6xxx.h |  8 ++++----
 include/net/dsa.h           |  8 ++++----
 net/dsa/slave.c             |  8 ++++----
 5 files changed, 34 insertions(+), 32 deletions(-)

diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 2d7b297..f7b53fa 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -725,7 +725,7 @@ static int bcm_sf2_arl_op(struct bcm_sf2_priv *priv, int op, int port,
 	return bcm_sf2_arl_read(priv, mac, vid, &ent, &idx, is_valid);
 }
 
-static int bcm_sf2_sw_fdb_prepare(struct dsa_switch *ds, int port,
+static int bcm_sf2_sw_fdb_prepare(struct dsa_switch *ds, struct dsa_port *dp,
 				  const struct switchdev_obj_port_fdb *fdb,
 				  struct switchdev_trans *trans)
 {
@@ -733,22 +733,22 @@ static int bcm_sf2_sw_fdb_prepare(struct dsa_switch *ds, int port,
 	return 0;
 }
 
-static void bcm_sf2_sw_fdb_add(struct dsa_switch *ds, int port,
+static void bcm_sf2_sw_fdb_add(struct dsa_switch *ds, struct dsa_port *dp,
 			       const struct switchdev_obj_port_fdb *fdb,
 			       struct switchdev_trans *trans)
 {
 	struct bcm_sf2_priv *priv = ds_to_priv(ds);
 
-	if (bcm_sf2_arl_op(priv, 0, port, fdb->addr, fdb->vid, true))
+	if (bcm_sf2_arl_op(priv, 0, dp->port, fdb->addr, fdb->vid, true))
 		pr_err("%s: failed to add MAC address\n", __func__);
 }
 
-static int bcm_sf2_sw_fdb_del(struct dsa_switch *ds, int port,
+static int bcm_sf2_sw_fdb_del(struct dsa_switch *ds, struct dsa_port *dp,
 			      const struct switchdev_obj_port_fdb *fdb)
 {
 	struct bcm_sf2_priv *priv = ds_to_priv(ds);
 
-	return bcm_sf2_arl_op(priv, 0, port, fdb->addr, fdb->vid, false);
+	return bcm_sf2_arl_op(priv, 0, dp->port, fdb->addr, fdb->vid, false);
 }
 
 static int bcm_sf2_arl_search_wait(struct bcm_sf2_priv *priv)
@@ -799,16 +799,18 @@ static int bcm_sf2_sw_fdb_copy(struct net_device *dev, int port,
 	return cb(&fdb->obj);
 }
 
-static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port,
+static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, struct dsa_port *dp,
 			       struct switchdev_obj_port_fdb *fdb,
 			       int (*cb)(struct switchdev_obj *obj))
 {
 	struct bcm_sf2_priv *priv = ds_to_priv(ds);
-	struct net_device *dev = ds->ports[port];
+	struct net_device *dev;
 	struct bcm_sf2_arl_entry results[2];
 	unsigned int count = 0;
 	int ret;
 
+	dev = ds->ports[dp->port];
+
 	/* Start search operation */
 	core_writel(priv, ARLA_SRCH_STDN, CORE_ARLA_SRCH_CTL);
 
@@ -819,12 +821,12 @@ static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port,
 
 		/* Read both entries, then return their values back */
 		bcm_sf2_arl_search_rd(priv, 0, &results[0]);
-		ret = bcm_sf2_sw_fdb_copy(dev, port, &results[0], fdb, cb);
+		ret = bcm_sf2_sw_fdb_copy(dev, dp->port, &results[0], fdb, cb);
 		if (ret)
 			return ret;
 
 		bcm_sf2_arl_search_rd(priv, 1, &results[1]);
-		ret = bcm_sf2_sw_fdb_copy(dev, port, &results[1], fdb, cb);
+		ret = bcm_sf2_sw_fdb_copy(dev, dp->port, &results[1], fdb, cb);
 		if (ret)
 			return ret;
 
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 3f78c73..c1ff763 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -2031,7 +2031,7 @@ static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port,
 	return _mv88e6xxx_atu_load(ds, &entry);
 }
 
-int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, struct dsa_port *dp,
 			       const struct switchdev_obj_port_fdb *fdb,
 			       struct switchdev_trans *trans)
 {
@@ -2041,7 +2041,7 @@ int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port,
 	return 0;
 }
 
-void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
+void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, struct dsa_port *dp,
 			    const struct switchdev_obj_port_fdb *fdb,
 			    struct switchdev_trans *trans)
 {
@@ -2051,19 +2051,19 @@ void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
 
 	mutex_lock(&ps->smi_mutex);
-	if (_mv88e6xxx_port_fdb_load(ds, port, fdb->addr, fdb->vid, state))
-		netdev_err(ds->ports[port], "failed to load MAC address\n");
+	if (_mv88e6xxx_port_fdb_load(ds, dp->port, fdb->addr, fdb->vid, state))
+		netdev_err(ds->ports[dp->port], "failed to load MAC address\n");
 	mutex_unlock(&ps->smi_mutex);
 }
 
-int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, struct dsa_port *dp,
 			   const struct switchdev_obj_port_fdb *fdb)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
 	int ret;
 
 	mutex_lock(&ps->smi_mutex);
-	ret = _mv88e6xxx_port_fdb_load(ds, port, fdb->addr, fdb->vid,
+	ret = _mv88e6xxx_port_fdb_load(ds, dp->port, fdb->addr, fdb->vid,
 				       GLOBAL_ATU_DATA_STATE_UNUSED);
 	mutex_unlock(&ps->smi_mutex);
 
@@ -2156,7 +2156,7 @@ static int _mv88e6xxx_port_fdb_dump_one(struct dsa_switch *ds, u16 fid, u16 vid,
 	return err;
 }
 
-int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, struct dsa_port *dp,
 			    struct switchdev_obj_port_fdb *fdb,
 			    int (*cb)(struct switchdev_obj *obj))
 {
@@ -2170,11 +2170,11 @@ int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
 	mutex_lock(&ps->smi_mutex);
 
 	/* Dump port's default Filtering Information Database (VLAN ID 0) */
-	err = _mv88e6xxx_port_fid_get(ds, port, &fid);
+	err = _mv88e6xxx_port_fid_get(ds, dp->port, &fid);
 	if (err)
 		goto unlock;
 
-	err = _mv88e6xxx_port_fdb_dump_one(ds, fid, 0, port, fdb, cb);
+	err = _mv88e6xxx_port_fdb_dump_one(ds, fid, 0, dp->port, fdb, cb);
 	if (err)
 		goto unlock;
 
@@ -2191,8 +2191,8 @@ int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
 		if (!vlan.valid)
 			break;
 
-		err = _mv88e6xxx_port_fdb_dump_one(ds, vlan.fid, vlan.vid, port,
-						   fdb, cb);
+		err = _mv88e6xxx_port_fdb_dump_one(ds, vlan.fid, vlan.vid,
+						   dp->port, fdb, cb);
 		if (err)
 			break;
 	} while (vlan.vid < GLOBAL_VTU_VID_MASK);
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 55b8eac..0b6c37a 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -508,15 +508,15 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
 int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
 			     struct switchdev_obj_port_vlan *vlan,
 			     int (*cb)(struct switchdev_obj *obj));
-int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, struct dsa_port *dp,
 			       const struct switchdev_obj_port_fdb *fdb,
 			       struct switchdev_trans *trans);
-void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
+void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, struct dsa_port *dp,
 			    const struct switchdev_obj_port_fdb *fdb,
 			    struct switchdev_trans *trans);
-int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, struct dsa_port *dp,
 			   const struct switchdev_obj_port_fdb *fdb);
-int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, struct dsa_port *dp,
 			    struct switchdev_obj_port_fdb *fdb,
 			    int (*cb)(struct switchdev_obj *obj));
 int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg);
diff --git a/include/net/dsa.h b/include/net/dsa.h
index fb626ae..65bbf72 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -330,15 +330,15 @@ struct dsa_switch_driver {
 	/*
 	 * Forwarding database
 	 */
-	int	(*port_fdb_prepare)(struct dsa_switch *ds, int port,
+	int	(*port_fdb_prepare)(struct dsa_switch *ds, struct dsa_port *dp,
 				    const struct switchdev_obj_port_fdb *fdb,
 				    struct switchdev_trans *trans);
-	void	(*port_fdb_add)(struct dsa_switch *ds, int port,
+	void	(*port_fdb_add)(struct dsa_switch *ds, struct dsa_port *dp,
 				const struct switchdev_obj_port_fdb *fdb,
 				struct switchdev_trans *trans);
-	int	(*port_fdb_del)(struct dsa_switch *ds, int port,
+	int	(*port_fdb_del)(struct dsa_switch *ds, struct dsa_port *dp,
 				const struct switchdev_obj_port_fdb *fdb);
-	int	(*port_fdb_dump)(struct dsa_switch *ds, int port,
+	int	(*port_fdb_dump)(struct dsa_switch *ds, struct dsa_port *dp,
 				 struct switchdev_obj_port_fdb *fdb,
 				 int (*cb)(struct switchdev_obj *obj));
 };
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 9a8ea9a..1afcbc4 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -256,10 +256,10 @@ static int dsa_slave_port_fdb_add(struct net_device *dev,
 		if (!ds->drv->port_fdb_prepare || !ds->drv->port_fdb_add)
 			return -EOPNOTSUPP;
 
-		return ds->drv->port_fdb_prepare(ds, p->dp->port, fdb, trans);
+		return ds->drv->port_fdb_prepare(ds, p->dp, fdb, trans);
 	}
 
-	ds->drv->port_fdb_add(ds, p->dp->port, fdb, trans);
+	ds->drv->port_fdb_add(ds, p->dp, fdb, trans);
 
 	return 0;
 }
@@ -272,7 +272,7 @@ static int dsa_slave_port_fdb_del(struct net_device *dev,
 	int ret = -EOPNOTSUPP;
 
 	if (ds->drv->port_fdb_del)
-		ret = ds->drv->port_fdb_del(ds, p->dp->port, fdb);
+		ret = ds->drv->port_fdb_del(ds, p->dp, fdb);
 
 	return ret;
 }
@@ -285,7 +285,7 @@ static int dsa_slave_port_fdb_dump(struct net_device *dev,
 	struct dsa_switch *ds = p->dp->ds;
 
 	if (ds->drv->port_fdb_dump)
-		return ds->drv->port_fdb_dump(ds, p->dp->port, fdb, cb);
+		return ds->drv->port_fdb_dump(ds, p->dp, fdb, cb);
 
 	return -EOPNOTSUPP;
 }
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 05/20] net: dsa: pass dsa_port down to drivers VLAN ops
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (3 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 04/20] net: dsa: pass dsa_port down to drivers FDB ops Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 06/20] net: dsa: move bridge device in dsa_port Vivien Didelot
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Now that DSA as proper structure for DSA ports, pass it down to the
port_vlan_{filtering,prepare,add,del,dump} driver functions.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/mv88e6xxx.c | 41 +++++++++++++++++++++--------------------
 drivers/net/dsa/mv88e6xxx.h | 10 +++++-----
 include/net/dsa.h           | 11 ++++++-----
 net/dsa/slave.c             | 10 +++++-----
 4 files changed, 37 insertions(+), 35 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index c1ff763..7e03f4c 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -1367,7 +1367,7 @@ static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds,
 	return 0;
 }
 
-int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, struct dsa_port *dp,
 			     struct switchdev_obj_port_vlan *vlan,
 			     int (*cb)(struct switchdev_obj *obj))
 {
@@ -1378,7 +1378,7 @@ int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
 
 	mutex_lock(&ps->smi_mutex);
 
-	err = _mv88e6xxx_port_pvid_get(ds, port, &pvid);
+	err = _mv88e6xxx_port_pvid_get(ds, dp->port, &pvid);
 	if (err)
 		goto unlock;
 
@@ -1394,14 +1394,15 @@ int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
 		if (!next.valid)
 			break;
 
-		if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
+		if (next.data[dp->port] ==
+		    GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
 			continue;
 
 		/* reinit and dump this VLAN obj */
 		vlan->vid_begin = vlan->vid_end = next.vid;
 		vlan->flags = 0;
 
-		if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
+		if (next.data[dp->port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
 			vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
 
 		if (next.vid == pvid)
@@ -1789,7 +1790,7 @@ static const char * const mv88e6xxx_port_8021q_mode_names[] = {
 	[PORT_CONTROL_2_8021Q_SECURE] = "Secure",
 };
 
-int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, struct dsa_port *dp,
 				  bool vlan_filtering)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
@@ -1799,7 +1800,7 @@ int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
 
 	mutex_lock(&ps->smi_mutex);
 
-	ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_CONTROL_2);
+	ret = _mv88e6xxx_reg_read(ds, REG_PORT(dp->port), PORT_CONTROL_2);
 	if (ret < 0)
 		goto unlock;
 
@@ -1809,12 +1810,12 @@ int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
 		ret &= ~PORT_CONTROL_2_8021Q_MASK;
 		ret |= new & PORT_CONTROL_2_8021Q_MASK;
 
-		ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL_2,
-					   ret);
+		ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port),
+					   PORT_CONTROL_2, ret);
 		if (ret < 0)
 			goto unlock;
 
-		netdev_dbg(ds->ports[port], "802.1Q Mode %s (was %s)\n",
+		netdev_dbg(ds->ports[dp->port], "802.1Q Mode %s (was %s)\n",
 			   mv88e6xxx_port_8021q_mode_names[new],
 			   mv88e6xxx_port_8021q_mode_names[old]);
 	}
@@ -1826,7 +1827,7 @@ unlock:
 	return ret;
 }
 
-int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, struct dsa_port *dp,
 				const struct switchdev_obj_port_vlan *vlan,
 				struct switchdev_trans *trans)
 {
@@ -1835,7 +1836,7 @@ int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
 	/* If the requested port doesn't belong to the same bridge as the VLAN
 	 * members, do not support it (yet) and fallback to software VLAN.
 	 */
-	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
+	err = mv88e6xxx_port_check_hw_vlan(ds, dp->port, vlan->vid_begin,
 					   vlan->vid_end);
 	if (err)
 		return err;
@@ -1863,7 +1864,7 @@ static int _mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, u16 vid,
 	return _mv88e6xxx_vtu_loadpurge(ds, &vlan);
 }
 
-void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
+void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, struct dsa_port *dp,
 			     const struct switchdev_obj_port_vlan *vlan,
 			     struct switchdev_trans *trans)
 {
@@ -1875,12 +1876,12 @@ void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
 	mutex_lock(&ps->smi_mutex);
 
 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
-		if (_mv88e6xxx_port_vlan_add(ds, port, vid, untagged))
-			netdev_err(ds->ports[port], "failed to add VLAN %d%c\n",
+		if (_mv88e6xxx_port_vlan_add(ds, dp->port, vid, untagged))
+			netdev_err(ds->ports[dp->port], "failed to add VLAN %d%c\n",
 				   vid, untagged ? 'u' : 't');
 
-	if (pvid && _mv88e6xxx_port_pvid_set(ds, port, vlan->vid_end))
-		netdev_err(ds->ports[port], "failed to set PVID %d\n",
+	if (pvid && _mv88e6xxx_port_pvid_set(ds, dp->port, vlan->vid_end))
+		netdev_err(ds->ports[dp->port], "failed to set PVID %d\n",
 			   vlan->vid_end);
 
 	mutex_unlock(&ps->smi_mutex);
@@ -1921,7 +1922,7 @@ static int _mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)
 	return _mv88e6xxx_atu_remove(ds, vlan.fid, port, false);
 }
 
-int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, struct dsa_port *dp,
 			    const struct switchdev_obj_port_vlan *vlan)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
@@ -1930,17 +1931,17 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
 
 	mutex_lock(&ps->smi_mutex);
 
-	err = _mv88e6xxx_port_pvid_get(ds, port, &pvid);
+	err = _mv88e6xxx_port_pvid_get(ds, dp->port, &pvid);
 	if (err)
 		goto unlock;
 
 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
-		err = _mv88e6xxx_port_vlan_del(ds, port, vid);
+		err = _mv88e6xxx_port_vlan_del(ds, dp->port, vid);
 		if (err)
 			goto unlock;
 
 		if (vid == pvid) {
-			err = _mv88e6xxx_port_pvid_set(ds, port, 0);
+			err = _mv88e6xxx_port_pvid_set(ds, dp->port, 0);
 			if (err)
 				goto unlock;
 		}
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 0b6c37a..c49a514 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -495,17 +495,17 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, struct dsa_port *dp,
 void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, struct dsa_port *dp,
 				 struct net_device *bridge);
 void mv88e6xxx_port_stp_state_set(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, struct dsa_port *dp,
 				  bool vlan_filtering);
-int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, struct dsa_port *dp,
 				const struct switchdev_obj_port_vlan *vlan,
 				struct switchdev_trans *trans);
-void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
+void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, struct dsa_port *dp,
 			     const struct switchdev_obj_port_vlan *vlan,
 			     struct switchdev_trans *trans);
-int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, struct dsa_port *dp,
 			    const struct switchdev_obj_port_vlan *vlan);
-int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
+int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, struct dsa_port *dp,
 			     struct switchdev_obj_port_vlan *vlan,
 			     int (*cb)(struct switchdev_obj *obj));
 int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, struct dsa_port *dp,
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 65bbf72..08a9536 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -313,17 +313,18 @@ struct dsa_switch_driver {
 	/*
 	 * VLAN support
 	 */
-	int	(*port_vlan_filtering)(struct dsa_switch *ds, int port,
+	int	(*port_vlan_filtering)(struct dsa_switch *ds,
+				       struct dsa_port *dp,
 				       bool vlan_filtering);
-	int	(*port_vlan_prepare)(struct dsa_switch *ds, int port,
+	int	(*port_vlan_prepare)(struct dsa_switch *ds, struct dsa_port *dp,
 				     const struct switchdev_obj_port_vlan *vlan,
 				     struct switchdev_trans *trans);
-	void	(*port_vlan_add)(struct dsa_switch *ds, int port,
+	void	(*port_vlan_add)(struct dsa_switch *ds, struct dsa_port *dp,
 				 const struct switchdev_obj_port_vlan *vlan,
 				 struct switchdev_trans *trans);
-	int	(*port_vlan_del)(struct dsa_switch *ds, int port,
+	int	(*port_vlan_del)(struct dsa_switch *ds, struct dsa_port *dp,
 				 const struct switchdev_obj_port_vlan *vlan);
-	int	(*port_vlan_dump)(struct dsa_switch *ds, int port,
+	int	(*port_vlan_dump)(struct dsa_switch *ds, struct dsa_port *dp,
 				  struct switchdev_obj_port_vlan *vlan,
 				  int (*cb)(struct switchdev_obj *obj));
 
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 1afcbc4..d6b6019 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -212,10 +212,10 @@ static int dsa_slave_port_vlan_add(struct net_device *dev,
 		if (!ds->drv->port_vlan_prepare || !ds->drv->port_vlan_add)
 			return -EOPNOTSUPP;
 
-		return ds->drv->port_vlan_prepare(ds, p->dp->port, vlan, trans);
+		return ds->drv->port_vlan_prepare(ds, p->dp, vlan, trans);
 	}
 
-	ds->drv->port_vlan_add(ds, p->dp->port, vlan, trans);
+	ds->drv->port_vlan_add(ds, p->dp, vlan, trans);
 
 	return 0;
 }
@@ -229,7 +229,7 @@ static int dsa_slave_port_vlan_del(struct net_device *dev,
 	if (!ds->drv->port_vlan_del)
 		return -EOPNOTSUPP;
 
-	return ds->drv->port_vlan_del(ds, p->dp->port, vlan);
+	return ds->drv->port_vlan_del(ds, p->dp, vlan);
 }
 
 static int dsa_slave_port_vlan_dump(struct net_device *dev,
@@ -240,7 +240,7 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev,
 	struct dsa_switch *ds = p->dp->ds;
 
 	if (ds->drv->port_vlan_dump)
-		return ds->drv->port_vlan_dump(ds, p->dp->port, vlan, cb);
+		return ds->drv->port_vlan_dump(ds, p->dp, vlan, cb);
 
 	return -EOPNOTSUPP;
 }
@@ -327,7 +327,7 @@ static int dsa_slave_vlan_filtering(struct net_device *dev,
 		return 0;
 
 	if (ds->drv->port_vlan_filtering)
-		return ds->drv->port_vlan_filtering(ds, p->dp->port,
+		return ds->drv->port_vlan_filtering(ds, p->dp,
 						    attr->u.vlan_filtering);
 
 	return 0;
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 06/20] net: dsa: move bridge device in dsa_port
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (4 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 05/20] net: dsa: pass dsa_port down to drivers VLAN ops Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 07/20] net: dsa: list ports in switch Vivien Didelot
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Move the pointer to the bridge device in the DSA port structure instead
of cluttering the dsa_slave_priv structure.

This can later be used by drivers to help them configuring their bridge
group ports membership.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 include/net/dsa.h  |  2 ++
 net/dsa/dsa_priv.h |  1 -
 net/dsa/slave.c    | 16 +++++-----------
 3 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 08a9536..69e467c 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -125,6 +125,8 @@ struct dsa_switch_tree {
 struct dsa_port {
 	struct dsa_switch	*ds;
 	int			port;
+
+	struct net_device	*br;
 };
 
 struct dsa_switch {
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index c7d5df0..c5afddd 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -35,7 +35,6 @@ struct dsa_slave_priv {
 	int			old_pause;
 	int			old_duplex;
 
-	struct net_device	*bridge_dev;
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	struct netpoll		*netpoll;
 #endif
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index d6b6019..b90caf8 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -64,18 +64,12 @@ static int dsa_slave_get_iflink(const struct net_device *dev)
 	return p->dp->ds->dst->master_netdev->ifindex;
 }
 
-static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p)
-{
-	return !!p->bridge_dev;
-}
-
 static int dsa_slave_open(struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
 	struct dsa_switch *ds = p->dp->ds;
 	struct net_device *master = ds->dst->master_netdev;
-	u8 stp_state = dsa_port_is_bridged(p) ?
-			BR_STATE_BLOCKING : BR_STATE_FORWARDING;
+	u8 stp_state = p->dp->br ? BR_STATE_BLOCKING : BR_STATE_FORWARDING;
 	int err;
 
 	if (!(master->flags & IFF_UP))
@@ -438,13 +432,13 @@ static int dsa_slave_bridge_port_join(struct net_device *dev,
 	struct dsa_switch *ds = p->dp->ds;
 	int ret = -EOPNOTSUPP;
 
-	p->bridge_dev = br;
+	p->dp->br = br;
 
 	if (ds->drv->port_bridge_join)
 		ret = ds->drv->port_bridge_join(ds, p->dp, br);
 
 	if (ret && ret != -EOPNOTSUPP) {
-		p->bridge_dev = NULL;
+		p->dp->br = NULL;
 		return ret;
 	}
 
@@ -455,9 +449,9 @@ static void dsa_slave_bridge_port_leave(struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
 	struct dsa_switch *ds = p->dp->ds;
-	struct net_device *br = p->bridge_dev;
+	struct net_device *br = p->dp->br;
 
-	p->bridge_dev = NULL;
+	p->dp->br = NULL;
 
 	if (ds->drv->port_bridge_leave)
 		ds->drv->port_bridge_leave(ds, p->dp, br);
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 07/20] net: dsa: list ports in switch
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (5 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 06/20] net: dsa: move bridge device in dsa_port Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 23:15   ` [RFC 07/20] net: dsa: list ports in switch\\ Andrew Lunn
  2016-04-27 22:30 ` [RFC 08/20] net: dsa: bcm_sf2: use bridge device from dsa_port Vivien Didelot
                   ` (12 subsequent siblings)
  19 siblings, 1 reply; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

List DSA port structures in their switch structure, so that drivers can
iterate on them to retrieve information such as their ports membership.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 include/net/dsa.h | 9 +++++++++
 net/dsa/dsa.c     | 4 ++++
 2 files changed, 13 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 69e467c..5f2e7df 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -32,6 +32,11 @@ enum dsa_tag_protocol {
 #define DSA_MAX_SWITCHES	4
 #define DSA_MAX_PORTS		12
 
+#define dsa_switch_for_each_port(_ds, _dp, _num_ports)			\
+	for (_dp = list_first_entry(&_ds->dp, typeof(*_dp), list);	\
+	     &_dp->list != (&_ds->dp) && _dp->port < _num_ports;	\
+	     _dp = list_next_entry(_dp, list))
+
 struct dsa_chip_data {
 	/*
 	 * How to access the switch configuration registers.
@@ -123,6 +128,8 @@ struct dsa_switch_tree {
 };
 
 struct dsa_port {
+	struct list_head	list;
+
 	struct dsa_switch	*ds;
 	int			port;
 
@@ -173,6 +180,8 @@ struct dsa_switch {
 	u32			phys_mii_mask;
 	struct mii_bus		*slave_mii_bus;
 	struct net_device	*ports[DSA_MAX_PORTS];
+
+	struct list_head	dp;
 };
 
 static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p)
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 222494c..3daffb6 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -225,6 +225,8 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
 	int index = ds->index;
 	int i, ret;
 
+	INIT_LIST_HEAD(&ds->dp);
+
 	/*
 	 * Validate supplied switch configuration.
 	 */
@@ -238,6 +240,8 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
 		dp[i]->ds = ds;
 		dp[i]->port = i;
 
+		list_add_tail(&dp[i]->list, &ds->dp);
+
 		name = pd->port_names[i];
 		if (name == NULL)
 			continue;
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 08/20] net: dsa: bcm_sf2: use bridge device from dsa_port
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (6 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 07/20] net: dsa: list ports in switch Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 09/20] net: dsa: mv88e6xxx: check HW vlan with dsa_port Vivien Didelot
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Now that the DSA layer exposes the DSA port structures to drivers, use
that to retrieve the port bridge membership and thus get rid of the
private bridge_dev pointer.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/bcm_sf2.c | 30 ++++++++++++++----------------
 drivers/net/dsa/bcm_sf2.h |  2 --
 2 files changed, 14 insertions(+), 18 deletions(-)

diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index f7b53fa..6e3b844 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -495,25 +495,24 @@ static int bcm_sf2_sw_br_join(struct dsa_switch *ds, struct dsa_port *dp,
 			      struct net_device *bridge)
 {
 	struct bcm_sf2_priv *priv = ds_to_priv(ds);
-	unsigned int i;
+	struct dsa_port *intp;
 	u32 reg, p_ctl;
 
-	priv->port_sts[dp->port].bridge_dev = bridge;
 	p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(dp->port));
 
-	for (i = 0; i < priv->hw_params.num_ports; i++) {
-		if (priv->port_sts[i].bridge_dev != bridge)
+	dsa_switch_for_each_port(ds, intp, priv->hw_params.num_ports) {
+		if (intp->br != bridge)
 			continue;
 
 		/* Add this local port to the remote port VLAN control
 		 * membership and update the remote port bitmask
 		 */
-		reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
+		reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(intp->port));
 		reg |= 1 << dp->port;
-		core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
-		priv->port_sts[i].vlan_ctl_mask = reg;
+		core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(intp->port));
+		priv->port_sts[intp->port].vlan_ctl_mask = reg;
 
-		p_ctl |= 1 << i;
+		p_ctl |= 1 << intp->port;
 	}
 
 	/* Configure the local port VLAN control membership to include
@@ -529,29 +528,28 @@ static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, struct dsa_port *dp,
 				struct net_device *bridge)
 {
 	struct bcm_sf2_priv *priv = ds_to_priv(ds);
-	unsigned int i;
+	struct dsa_port *intp;
 	u32 reg, p_ctl;
 
 	p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(dp->port));
 
-	for (i = 0; i < priv->hw_params.num_ports; i++) {
+	dsa_switch_for_each_port(ds, intp, priv->hw_params.num_ports) {
 		/* Don't touch the remaining ports */
-		if (priv->port_sts[i].bridge_dev != bridge)
+		if (intp->br != bridge)
 			continue;
 
-		reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
+		reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(intp->port));
 		reg &= ~(1 << dp->port);
-		core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
+		core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(intp->port));
 		priv->port_sts[dp->port].vlan_ctl_mask = reg;
 
 		/* Prevent self removal to preserve isolation */
-		if (dp->port != i)
-			p_ctl &= ~(1 << i);
+		if (dp != intp)
+			p_ctl &= ~(1 << intp->port);
 	}
 
 	core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(dp->port));
 	priv->port_sts[dp->port].vlan_ctl_mask = p_ctl;
-	priv->port_sts[dp->port].bridge_dev = NULL;
 }
 
 static void bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
index 200b1f5..6bba1c9 100644
--- a/drivers/net/dsa/bcm_sf2.h
+++ b/drivers/net/dsa/bcm_sf2.h
@@ -50,8 +50,6 @@ struct bcm_sf2_port_status {
 	struct ethtool_eee eee;
 
 	u32 vlan_ctl_mask;
-
-	struct net_device *bridge_dev;
 };
 
 struct bcm_sf2_arl_entry {
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 09/20] net: dsa: mv88e6xxx: check HW vlan with dsa_port
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (7 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 08/20] net: dsa: bcm_sf2: use bridge device from dsa_port Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 10/20] net: dsa: mv88e6xxx: setup a dsa_port Vivien Didelot
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Change the mv88e6xxx_port_check_hw_vlan function for a
mv88e6xxx_port_check_vtu which takes a dsa_port structure as parameter.
This will help us get rid of the bridge_dev pointer.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/mv88e6xxx.c | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 7e03f4c..00a0b92 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -1729,12 +1729,13 @@ static int _mv88e6xxx_vtu_get(struct dsa_switch *ds, u16 vid,
 	return err;
 }
 
-static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
-					u16 vid_begin, u16 vid_end)
+static int mv88e6xxx_port_check_vtu(struct dsa_switch *ds, struct dsa_port *dp,
+				    u16 vid_begin, u16 vid_end)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
 	struct mv88e6xxx_vtu_stu_entry vlan;
-	int i, err;
+	struct dsa_port *intp;
+	int err;
 
 	if (!vid_begin)
 		return -EOPNOTSUPP;
@@ -1756,22 +1757,21 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
 		if (vlan.vid > vid_end)
 			break;
 
-		for (i = 0; i < ps->info->num_ports; ++i) {
-			if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
+		dsa_switch_for_each_port(ds, intp, ps->info->num_ports) {
+			if (dsa_is_dsa_port(ds, intp->port) ||
+			    dsa_is_cpu_port(ds, intp->port))
 				continue;
 
-			if (vlan.data[i] ==
+			if (vlan.data[intp->port] ==
 			    GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
 				continue;
 
-			if (ps->ports[i].bridge_dev ==
-			    ps->ports[port].bridge_dev)
+			if (intp->br == dp->br)
 				break; /* same bridge, check next VLAN */
 
-			netdev_warn(ds->ports[port],
+			netdev_warn(ds->ports[dp->port],
 				    "hardware VLAN %d already used by %s\n",
-				    vlan.vid,
-				    netdev_name(ps->ports[i].bridge_dev));
+				    vlan.vid, netdev_name(intp->br));
 			err = -EOPNOTSUPP;
 			goto unlock;
 		}
@@ -1836,8 +1836,7 @@ int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, struct dsa_port *dp,
 	/* If the requested port doesn't belong to the same bridge as the VLAN
 	 * members, do not support it (yet) and fallback to software VLAN.
 	 */
-	err = mv88e6xxx_port_check_hw_vlan(ds, dp->port, vlan->vid_begin,
-					   vlan->vid_end);
+	err = mv88e6xxx_port_check_vtu(ds, dp, vlan->vid_begin, vlan->vid_end);
 	if (err)
 		return err;
 
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 10/20] net: dsa: mv88e6xxx: setup a dsa_port
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (8 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 09/20] net: dsa: mv88e6xxx: check HW vlan with dsa_port Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 11/20] net: dsa: mv88e6xxx: use bridge from dsa_port Vivien Didelot
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Change the mv88e6xxx_setup_port function to take a dsa_port structure as
parameter instead of a port index. This will help us get rid of the
private bridge_dev pointer.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/mv88e6xxx.c | 64 ++++++++++++++++++++++++---------------------
 1 file changed, 34 insertions(+), 30 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 00a0b92..0687894 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -2317,7 +2317,7 @@ static int mv88e6xxx_power_on_serdes(struct dsa_switch *ds)
 	return ret;
 }
 
-static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
+static int mv88e6xxx_setup_port(struct dsa_switch *ds, struct dsa_port *dp)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
 	int ret;
@@ -2335,8 +2335,10 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 		 * and all DSA ports to their maximum bandwidth and
 		 * full duplex.
 		 */
-		reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL);
-		if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
+		reg = _mv88e6xxx_reg_read(ds, REG_PORT(dp->port),
+					  PORT_PCS_CTRL);
+		if (dsa_is_cpu_port(ds, dp->port) ||
+		    dsa_is_dsa_port(ds, dp->port)) {
 			reg &= ~PORT_PCS_CTRL_UNFORCED;
 			reg |= PORT_PCS_CTRL_FORCE_LINK |
 				PORT_PCS_CTRL_LINK_UP |
@@ -2350,7 +2352,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 			reg |= PORT_PCS_CTRL_UNFORCED;
 		}
 
-		ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+		ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port),
 					   PORT_PCS_CTRL, reg);
 		if (ret)
 			goto abort;
@@ -2378,7 +2380,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 		reg = PORT_CONTROL_IGMP_MLD_SNOOP |
 		PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
 		PORT_CONTROL_STATE_FORWARDING;
-	if (dsa_is_cpu_port(ds, port)) {
+	if (dsa_is_cpu_port(ds, dp->port)) {
 		if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
 			reg |= PORT_CONTROL_DSA_TAG;
 		if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
@@ -2400,7 +2402,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 				reg |= PORT_CONTROL_EGRESS_ADD_TAG;
 		}
 	}
-	if (dsa_is_dsa_port(ds, port)) {
+	if (dsa_is_dsa_port(ds, dp->port)) {
 		if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
 			reg |= PORT_CONTROL_DSA_TAG;
 		if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
@@ -2409,13 +2411,13 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 			reg |= PORT_CONTROL_FRAME_MODE_DSA;
 		}
 
-		if (port == dsa_upstream_port(ds))
+		if (dp->port == dsa_upstream_port(ds))
 			reg |= PORT_CONTROL_FORWARD_UNKNOWN |
 				PORT_CONTROL_FORWARD_UNKNOWN_MC;
 	}
 	if (reg) {
-		ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
-					   PORT_CONTROL, reg);
+		ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port), PORT_CONTROL,
+					   reg);
 		if (ret)
 			goto abort;
 	}
@@ -2424,7 +2426,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 	 * powered down.
 	 */
 	if (mv88e6xxx_6352_family(ds)) {
-		ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS);
+		ret = _mv88e6xxx_reg_read(ds, REG_PORT(dp->port), PORT_STATUS);
 		if (ret < 0)
 			goto abort;
 		ret &= PORT_STATUS_CMODE_MASK;
@@ -2460,14 +2462,14 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 		/* enable forwarding of unknown multicast addresses to
 		 * the upstream port
 		 */
-		if (port == dsa_upstream_port(ds))
+		if (dp->port == dsa_upstream_port(ds))
 			reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
 	}
 
 	reg |= PORT_CONTROL_2_8021Q_DISABLED;
 
 	if (reg) {
-		ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+		ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port),
 					   PORT_CONTROL_2, reg);
 		if (ret)
 			goto abort;
@@ -2478,17 +2480,18 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 	 * a port bitmap that has only the bit for this port set and
 	 * the other bits clear.
 	 */
-	reg = 1 << port;
+	reg = 1 << dp->port;
 	/* Disable learning for CPU port */
-	if (dsa_is_cpu_port(ds, port))
+	if (dsa_is_cpu_port(ds, dp->port))
 		reg = 0;
 
-	ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_ASSOC_VECTOR, reg);
+	ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port), PORT_ASSOC_VECTOR,
+				   reg);
 	if (ret)
 		goto abort;
 
 	/* Egress rate control 2: disable egress rate control. */
-	ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_RATE_CONTROL_2,
+	ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port), PORT_RATE_CONTROL_2,
 				   0x0000);
 	if (ret)
 		goto abort;
@@ -2500,7 +2503,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 		 * be paused for by the remote end or the period of
 		 * time that this port can pause the remote end.
 		 */
-		ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+		ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port),
 					   PORT_PAUSE_CTRL, 0x0000);
 		if (ret)
 			goto abort;
@@ -2509,12 +2512,12 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 		 * address database entries that this port is allowed
 		 * to use.
 		 */
-		ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+		ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port),
 					   PORT_ATU_CONTROL, 0x0000);
 		/* Priority Override: disable DA, SA and VTU priority
 		 * override.
 		 */
-		ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+		ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port),
 					   PORT_PRI_OVERRIDE, 0x0000);
 		if (ret)
 			goto abort;
@@ -2522,14 +2525,14 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 		/* Port Ethertype: use the Ethertype DSA Ethertype
 		 * value.
 		 */
-		ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+		ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port),
 					   PORT_ETH_TYPE, ETH_P_EDSA);
 		if (ret)
 			goto abort;
 		/* Tag Remap: use an identity 802.1p prio -> switch
 		 * prio mapping.
 		 */
-		ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+		ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port),
 					   PORT_TAG_REGMAP_0123, 0x3210);
 		if (ret)
 			goto abort;
@@ -2537,7 +2540,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 		/* Tag Remap 2: use an identity 802.1p prio -> switch
 		 * prio mapping.
 		 */
-		ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+		ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port),
 					   PORT_TAG_REGMAP_4567, 0x7654);
 		if (ret)
 			goto abort;
@@ -2548,7 +2551,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 	    mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
 	    mv88e6xxx_6320_family(ds)) {
 		/* Rate Control: disable ingress rate limiting. */
-		ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+		ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port),
 					   PORT_RATE_CONTROL, 0x0001);
 		if (ret)
 			goto abort;
@@ -2557,7 +2560,8 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 	/* Port Control 1: disable trunking, disable sending
 	 * learning messages to this port.
 	 */
-	ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL_1, 0x0000);
+	ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port), PORT_CONTROL_1,
+				   0x0000);
 	if (ret)
 		goto abort;
 
@@ -2565,18 +2569,18 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 	 * database, and allow bidirectional communication between the
 	 * CPU and DSA port(s), and the other ports.
 	 */
-	ret = _mv88e6xxx_port_fid_set(ds, port, 0);
+	ret = _mv88e6xxx_port_fid_set(ds, dp->port, 0);
 	if (ret)
 		goto abort;
 
-	ret = _mv88e6xxx_port_based_vlan_map(ds, port);
+	ret = _mv88e6xxx_port_based_vlan_map(ds, dp->port);
 	if (ret)
 		goto abort;
 
 	/* Default VLAN ID and priority: don't set a default VLAN
 	 * ID, and set the default packet priority to zero.
 	 */
-	ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_DEFAULT_VLAN,
+	ret = _mv88e6xxx_reg_write(ds, REG_PORT(dp->port), PORT_DEFAULT_VLAN,
 				   0x0000);
 abort:
 	mutex_unlock(&ps->smi_mutex);
@@ -2586,11 +2590,11 @@ abort:
 int mv88e6xxx_setup_ports(struct dsa_switch *ds)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+	struct dsa_port *dp;
 	int ret;
-	int i;
 
-	for (i = 0; i < ps->info->num_ports; i++) {
-		ret = mv88e6xxx_setup_port(ds, i);
+	dsa_switch_for_each_port(ds, dp, ps->info->num_ports) {
+		ret = mv88e6xxx_setup_port(ds, dp);
 		if (ret < 0)
 			return ret;
 	}
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 11/20] net: dsa: mv88e6xxx: use bridge from dsa_port
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (9 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 10/20] net: dsa: mv88e6xxx: setup a dsa_port Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 12/20] net: dsa: rename dst->ds to dst->switches Vivien Didelot
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Change the _mv88e6xxx_port_based_vlan_map function for a
_mv88e6xxx_port_map_vlantable which takes a dsa_port structure as
parameter. This allows us to iterate on dsa_port's bridge device pointer
and thus get rid of the private bridge_dev structure.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/mv88e6xxx.c | 48 ++++++++++++++++++++++-----------------------
 drivers/net/dsa/mv88e6xxx.h |  1 -
 2 files changed, 24 insertions(+), 25 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 0687894..89d0206 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -1111,27 +1111,29 @@ static int _mv88e6xxx_port_state(struct dsa_switch *ds, int port, u8 state)
 	return ret;
 }
 
-static int _mv88e6xxx_port_based_vlan_map(struct dsa_switch *ds, int port)
+static int _mv88e6xxx_port_map_vlantable(struct dsa_switch *ds,
+					 struct dsa_port *dp)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-	struct net_device *bridge = ps->ports[port].bridge_dev;
 	const u16 mask = (1 << ps->info->num_ports) - 1;
 	u16 output_ports = 0;
+	int port = dp->port;
+	struct dsa_port *intp;
 	int reg;
-	int i;
 
 	/* allow CPU port or DSA link(s) to send frames to every port */
 	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
 		output_ports = mask;
 	} else {
-		for (i = 0; i < ps->info->num_ports; ++i) {
+		dsa_switch_for_each_port(ds, intp, ps->info->num_ports) {
 			/* allow sending frames to every group member */
-			if (bridge && ps->ports[i].bridge_dev == bridge)
-				output_ports |= BIT(i);
+			if (intp->br && intp->br == dp->br)
+				output_ports |= BIT(intp->port);
 
 			/* allow sending frames to CPU port and DSA link(s) */
-			if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
-				output_ports |= BIT(i);
+			if (dsa_is_cpu_port(ds, intp->port) ||
+			    dsa_is_dsa_port(ds, intp->port))
+				output_ports |= BIT(intp->port);
 		}
 	}
 
@@ -2207,16 +2209,15 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, struct dsa_port *dp,
 			       struct net_device *bridge)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-	int i, err;
+	struct dsa_port *intp;
+	int err;
 
 	mutex_lock(&ps->smi_mutex);
 
-	/* Assign the bridge and remap each port's VLANTable */
-	ps->ports[dp->port].bridge_dev = bridge;
-
-	for (i = 0; i < ps->info->num_ports; ++i) {
-		if (ps->ports[i].bridge_dev == bridge) {
-			err = _mv88e6xxx_port_based_vlan_map(ds, i);
+	/* Remap each port's VLANTable */
+	dsa_switch_for_each_port(ds, intp, ps->info->num_ports) {
+		if (intp->br == bridge) {
+			err = _mv88e6xxx_port_map_vlantable(ds, intp);
 			if (err)
 				break;
 		}
@@ -2231,17 +2232,16 @@ void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, struct dsa_port *dp,
 				 struct net_device *bridge)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-	int i;
+	struct dsa_port *intp;
 
 	mutex_lock(&ps->smi_mutex);
 
-	/* Unassign the bridge and remap each port's VLANTable */
-	ps->ports[dp->port].bridge_dev = NULL;
-
-	for (i = 0; i < ps->info->num_ports; ++i)
-		if (i == dp->port || ps->ports[i].bridge_dev == bridge)
-			if (_mv88e6xxx_port_based_vlan_map(ds, i))
-				netdev_warn(ds->ports[i], "failed to remap\n");
+	/* Remap each port's VLANTable */
+	dsa_switch_for_each_port(ds, intp, ps->info->num_ports)
+		if (intp == dp || intp->br == bridge)
+			if (_mv88e6xxx_port_map_vlantable(ds, intp))
+				netdev_warn(ds->ports[intp->port],
+					    "failed to remap\n");
 
 	mutex_unlock(&ps->smi_mutex);
 }
@@ -2573,7 +2573,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, struct dsa_port *dp)
 	if (ret)
 		goto abort;
 
-	ret = _mv88e6xxx_port_based_vlan_map(ds, dp->port);
+	ret = _mv88e6xxx_port_map_vlantable(ds, dp);
 	if (ret)
 		goto abort;
 
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index c49a514..56e3347 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -378,7 +378,6 @@ struct mv88e6xxx_vtu_stu_entry {
 };
 
 struct mv88e6xxx_priv_port {
-	struct net_device *bridge_dev;
 	u8 state;
 };
 
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 12/20] net: dsa: rename dst->ds to dst->switches
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (10 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 11/20] net: dsa: mv88e6xxx: use bridge from dsa_port Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 23:20   ` Andrew Lunn
  2016-04-27 22:30 ` [RFC 13/20] net: dsa: list switches in tree Vivien Didelot
                   ` (7 subsequent siblings)
  19 siblings, 1 reply; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

dsa_switch stores the net_device pointers in a "ports" member. Be
consistent and store the dsa_switch pointer in a "switches" member of
the dsa_switch_tree structure.

This free us the "ds" member for a future dsa_switch list.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 include/net/dsa.h     | 2 +-
 net/dsa/dsa.c         | 8 ++++----
 net/dsa/tag_brcm.c    | 2 +-
 net/dsa/tag_dsa.c     | 2 +-
 net/dsa/tag_edsa.c    | 2 +-
 net/dsa/tag_trailer.c | 2 +-
 6 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 5f2e7df..389227d 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -124,7 +124,7 @@ struct dsa_switch_tree {
 	/*
 	 * Data for the individual switch chips.
 	 */
-	struct dsa_switch	*ds[DSA_MAX_SWITCHES];
+	struct dsa_switch	*switches[DSA_MAX_SWITCHES];
 };
 
 struct dsa_port {
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 3daffb6..aa4a61a 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -857,7 +857,7 @@ static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev,
 			continue;
 		}
 
-		dst->ds[i] = ds;
+		dst->switches[i] = ds;
 
 		++configured;
 	}
@@ -953,7 +953,7 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst)
 	wmb();
 
 	for (i = 0; i < dst->pd->nr_chips; i++) {
-		struct dsa_switch *ds = dst->ds[i];
+		struct dsa_switch *ds = dst->switches[i];
 
 		if (ds)
 			dsa_switch_destroy(ds);
@@ -1006,7 +1006,7 @@ static int dsa_suspend(struct device *d)
 	int i, ret = 0;
 
 	for (i = 0; i < dst->pd->nr_chips; i++) {
-		struct dsa_switch *ds = dst->ds[i];
+		struct dsa_switch *ds = dst->switches[i];
 
 		if (ds != NULL)
 			ret = dsa_switch_suspend(ds);
@@ -1022,7 +1022,7 @@ static int dsa_resume(struct device *d)
 	int i, ret = 0;
 
 	for (i = 0; i < dst->pd->nr_chips; i++) {
-		struct dsa_switch *ds = dst->ds[i];
+		struct dsa_switch *ds = dst->switches[i];
 
 		if (ds != NULL)
 			ret = dsa_switch_resume(ds);
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index 3d5aabc..35fc75b 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -102,7 +102,7 @@ static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
 	if (unlikely(dst == NULL))
 		goto out_drop;
 
-	ds = dst->ds[0];
+	ds = dst->switches[0];
 
 	skb = skb_unshare(skb, GFP_ATOMIC);
 	if (skb == NULL)
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index c870cfa..bf3eebf8 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -109,7 +109,7 @@ static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
 	 */
 	if (source_device >= dst->pd->nr_chips)
 		goto out_drop;
-	ds = dst->ds[source_device];
+	ds = dst->switches[source_device];
 	if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
 		goto out_drop;
 
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index 898f949d..4ddbb85 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -122,7 +122,7 @@ static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
 	 */
 	if (source_device >= dst->pd->nr_chips)
 		goto out_drop;
-	ds = dst->ds[source_device];
+	ds = dst->switches[source_device];
 	if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
 		goto out_drop;
 
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
index eaa3440..ade0bbf 100644
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -67,7 +67,7 @@ static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,
 
 	if (unlikely(dst == NULL))
 		goto out_drop;
-	ds = dst->ds[0];
+	ds = dst->switches[0];
 
 	skb = skb_unshare(skb, GFP_ATOMIC);
 	if (skb == NULL)
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 13/20] net: dsa: list switches in tree
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (11 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 12/20] net: dsa: rename dst->ds to dst->switches Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 14/20] net: dsa: add tree-wide bridge ops Vivien Didelot
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

List the registered dsa_switch structures in a "ds" member of the
dsa_switch_tree structure. This allows the drivers to easily iterate on
the DSA switch structures of their related DSA tree.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 include/net/dsa.h | 9 +++++++++
 net/dsa/dsa.c     | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 389227d..85fac8a 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -32,11 +32,16 @@ enum dsa_tag_protocol {
 #define DSA_MAX_SWITCHES	4
 #define DSA_MAX_PORTS		12
 
+
+#define dsa_tree_for_each_switch(_dst, _ds)		\
+	list_for_each_entry(_ds, &_dst->ds, list)
+
 #define dsa_switch_for_each_port(_ds, _dp, _num_ports)			\
 	for (_dp = list_first_entry(&_ds->dp, typeof(*_dp), list);	\
 	     &_dp->list != (&_ds->dp) && _dp->port < _num_ports;	\
 	     _dp = list_next_entry(_dp, list))
 
+
 struct dsa_chip_data {
 	/*
 	 * How to access the switch configuration registers.
@@ -125,6 +130,8 @@ struct dsa_switch_tree {
 	 * Data for the individual switch chips.
 	 */
 	struct dsa_switch	*switches[DSA_MAX_SWITCHES];
+
+	struct list_head	ds;
 };
 
 struct dsa_port {
@@ -137,6 +144,8 @@ struct dsa_port {
 };
 
 struct dsa_switch {
+	struct list_head	list;
+
 	/*
 	 * Parent switch tree, and switch index.
 	 */
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index aa4a61a..b0055c7 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -842,6 +842,8 @@ static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev,
 	int i;
 	unsigned configured = 0;
 
+	INIT_LIST_HEAD(&dst->ds);
+
 	dst->pd = pd;
 	dst->master_netdev = dev;
 	dst->cpu_switch = -1;
@@ -858,6 +860,7 @@ static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev,
 		}
 
 		dst->switches[i] = ds;
+		list_add_tail(&ds->list, &dst->ds);
 
 		++configured;
 	}
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 14/20] net: dsa: add tree-wide bridge ops
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (12 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 13/20] net: dsa: list switches in tree Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 15/20] net: dsa: add tree-wide FDB ops Vivien Didelot
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

In order to support cross-chip operations, we need to inform each switch
driver when a port operation occurs in a DSA tree.

This allows drivers to configure cross-chip port-based VLAN table, VTU
or FDB entries on DSA links, in order to implement a correct hardware
switching of frames.

Add a new tree.c file to implement tree-wide operations, propagating a
port-based operation on each switch of a tree.

Implement tree-wide bridge operations.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/bcm_sf2.c   |  6 +++++
 drivers/net/dsa/mv88e6xxx.c |  6 +++++
 include/net/dsa.h           |  6 +++++
 net/dsa/Makefile            |  2 +-
 net/dsa/dsa_priv.h          |  6 +++++
 net/dsa/slave.c             | 46 ++++---------------------------
 net/dsa/tree.c              | 66 +++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 96 insertions(+), 42 deletions(-)
 create mode 100644 net/dsa/tree.c

diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 6e3b844..0a91ea9 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -498,6 +498,9 @@ static int bcm_sf2_sw_br_join(struct dsa_switch *ds, struct dsa_port *dp,
 	struct dsa_port *intp;
 	u32 reg, p_ctl;
 
+	if (dsa_port_is_external(dp, ds))
+		return -EOPNOTSUPP;
+
 	p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(dp->port));
 
 	dsa_switch_for_each_port(ds, intp, priv->hw_params.num_ports) {
@@ -531,6 +534,9 @@ static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, struct dsa_port *dp,
 	struct dsa_port *intp;
 	u32 reg, p_ctl;
 
+	if (dsa_port_is_external(dp, ds))
+		return;
+
 	p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(dp->port));
 
 	dsa_switch_for_each_port(ds, intp, priv->hw_params.num_ports) {
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 89d0206..6fef29b 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -2212,6 +2212,9 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, struct dsa_port *dp,
 	struct dsa_port *intp;
 	int err;
 
+	if (dsa_port_is_external(dp, ds))
+		return -EOPNOTSUPP;
+
 	mutex_lock(&ps->smi_mutex);
 
 	/* Remap each port's VLANTable */
@@ -2234,6 +2237,9 @@ void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, struct dsa_port *dp,
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
 	struct dsa_port *intp;
 
+	if (dsa_port_is_external(dp, ds))
+		return;
+
 	mutex_lock(&ps->smi_mutex);
 
 	/* Remap each port's VLANTable */
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 85fac8a..33172c9 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -193,6 +193,12 @@ struct dsa_switch {
 	struct list_head	dp;
 };
 
+static inline bool dsa_port_is_external(struct dsa_port *dp,
+					struct dsa_switch *ds)
+{
+	return dp->ds != ds;
+}
+
 static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p)
 {
 	return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port);
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index da06ed1..bf8d12c 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -1,6 +1,6 @@
 # the core
 obj-$(CONFIG_NET_DSA) += dsa_core.o
-dsa_core-y += dsa.o slave.o
+dsa_core-y += dsa.o tree.o slave.o
 
 # tagging formats
 dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index c5afddd..6e08b3d 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -46,6 +46,12 @@ struct dsa_slave_priv {
 /* dsa.c */
 extern char dsa_driver_version[];
 
+/* tree.c */
+int dsa_tree_bridge_port_join(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			      struct net_device *br);
+void dsa_tree_bridge_port_leave(struct dsa_switch_tree *dst,
+				struct dsa_port *dp, struct net_device *br);
+
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
 void dsa_slave_mii_bus_init(struct dsa_switch *ds);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index b90caf8..7123ae2 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -425,45 +425,6 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,
 	return err;
 }
 
-static int dsa_slave_bridge_port_join(struct net_device *dev,
-				      struct net_device *br)
-{
-	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->dp->ds;
-	int ret = -EOPNOTSUPP;
-
-	p->dp->br = br;
-
-	if (ds->drv->port_bridge_join)
-		ret = ds->drv->port_bridge_join(ds, p->dp, br);
-
-	if (ret && ret != -EOPNOTSUPP) {
-		p->dp->br = NULL;
-		return ret;
-	}
-
-	return 0;
-}
-
-static void dsa_slave_bridge_port_leave(struct net_device *dev)
-{
-	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->dp->ds;
-	struct net_device *br = p->dp->br;
-
-	p->dp->br = NULL;
-
-	if (ds->drv->port_bridge_leave)
-		ds->drv->port_bridge_leave(ds, p->dp, br);
-
-	/* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
-	 * so allow it to be in BR_STATE_FORWARDING to be kept functional
-	 */
-	if (ds->drv->port_stp_state_set)
-		ds->drv->port_stp_state_set(ds, p->dp->port,
-					    BR_STATE_FORWARDING);
-}
-
 static int dsa_slave_port_attr_get(struct net_device *dev,
 				   struct switchdev_attr *attr)
 {
@@ -1140,6 +1101,9 @@ static bool dsa_slave_dev_check(struct net_device *dev)
 static int dsa_slave_port_upper_event(struct net_device *dev,
 				      unsigned long event, void *ptr)
 {
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_port *dp = p->dp;
+	struct dsa_switch_tree *dst = dp->ds->dst;
 	struct netdev_notifier_changeupper_info *info = ptr;
 	struct net_device *upper = info->upper_dev;
 	int err = 0;
@@ -1148,9 +1112,9 @@ static int dsa_slave_port_upper_event(struct net_device *dev,
 	case NETDEV_CHANGEUPPER:
 		if (netif_is_bridge_master(upper)) {
 			if (info->linking)
-				err = dsa_slave_bridge_port_join(dev, upper);
+				err = dsa_tree_bridge_port_join(dst, dp, upper);
 			else
-				dsa_slave_bridge_port_leave(dev);
+				dsa_tree_bridge_port_leave(dst, dp, upper);
 		}
 
 		break;
diff --git a/net/dsa/tree.c b/net/dsa/tree.c
new file mode 100644
index 0000000..d3f5aea
--- /dev/null
+++ b/net/dsa/tree.c
@@ -0,0 +1,66 @@
+/*
+ * net/dsa/tree.c - DSA switch tree handling
+ * Copyright (c) 2016 Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/if_bridge.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+
+#include "dsa_priv.h"
+
+int dsa_tree_bridge_port_join(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			      struct net_device *br)
+{
+	struct dsa_switch *ds;
+	int err = 0;
+
+	/* on NETDEV_CHANGEUPPER, the port is already bridged */
+	dp->br = br;
+
+	dsa_tree_for_each_switch(dst, ds) {
+		if (ds->drv->port_bridge_join) {
+			err = ds->drv->port_bridge_join(ds, dp, br);
+			if (err) {
+				if (err != -EOPNOTSUPP)
+					break;
+				err = 0;
+			}
+		}
+	}
+
+	/* if an error is reported, bridge rolls back the operation */
+	if (err)
+		dp->br = NULL;
+
+	return err;
+}
+
+void dsa_tree_bridge_port_leave(struct dsa_switch_tree *dst,
+				struct dsa_port *dp, struct net_device *br)
+{
+	struct dsa_switch *ds;
+
+	/* on NETDEV_CHANGEUPPER, the port is already unbridged */
+	dp->br = NULL;
+
+	dsa_tree_for_each_switch(dst, ds) {
+		if (ds->drv->port_bridge_leave)
+			ds->drv->port_bridge_leave(ds, dp, br);
+
+		if (dsa_port_is_external(dp, ds))
+			continue;
+
+		/* The bridge layer put the port in BR_STATE_DISABLED,
+		 * restore BR_STATE_FORWARDING to keep it functional.
+		 */
+		if (ds->drv->port_stp_state_set)
+			ds->drv->port_stp_state_set(ds, dp->port,
+						    BR_STATE_FORWARDING);
+	}
+}
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 15/20] net: dsa: add tree-wide FDB ops
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (13 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 14/20] net: dsa: add tree-wide bridge ops Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 16/20] net: dsa: add tree-wide VLAN ops Vivien Didelot
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

In order to support cross-chip operations, we need to inform each switch
driver when a port operation occurs in a DSA tree.

Implement tree-wide FDB operations.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/bcm_sf2.c   | 12 ++++++++
 drivers/net/dsa/mv88e6xxx.c | 12 ++++++++
 net/dsa/dsa_priv.h          |  9 ++++++
 net/dsa/slave.c             | 68 ++++++++++-----------------------------------
 net/dsa/tree.c              | 61 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 109 insertions(+), 53 deletions(-)

diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 0a91ea9..6e634e5 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -733,6 +733,9 @@ static int bcm_sf2_sw_fdb_prepare(struct dsa_switch *ds, struct dsa_port *dp,
 				  const struct switchdev_obj_port_fdb *fdb,
 				  struct switchdev_trans *trans)
 {
+	if (dsa_port_is_external(dp, ds))
+		return -EOPNOTSUPP;
+
 	/* We do not need to do anything specific here yet */
 	return 0;
 }
@@ -743,6 +746,9 @@ static void bcm_sf2_sw_fdb_add(struct dsa_switch *ds, struct dsa_port *dp,
 {
 	struct bcm_sf2_priv *priv = ds_to_priv(ds);
 
+	if (dsa_port_is_external(dp, ds))
+		return;
+
 	if (bcm_sf2_arl_op(priv, 0, dp->port, fdb->addr, fdb->vid, true))
 		pr_err("%s: failed to add MAC address\n", __func__);
 }
@@ -752,6 +758,9 @@ static int bcm_sf2_sw_fdb_del(struct dsa_switch *ds, struct dsa_port *dp,
 {
 	struct bcm_sf2_priv *priv = ds_to_priv(ds);
 
+	if (dsa_port_is_external(dp, ds))
+		return -EOPNOTSUPP;
+
 	return bcm_sf2_arl_op(priv, 0, dp->port, fdb->addr, fdb->vid, false);
 }
 
@@ -813,6 +822,9 @@ static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, struct dsa_port *dp,
 	unsigned int count = 0;
 	int ret;
 
+	if (dsa_port_is_external(dp, ds))
+		return -EOPNOTSUPP;
+
 	dev = ds->ports[dp->port];
 
 	/* Start search operation */
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 6fef29b..7d29de3 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -2037,6 +2037,9 @@ int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, struct dsa_port *dp,
 			       const struct switchdev_obj_port_fdb *fdb,
 			       struct switchdev_trans *trans)
 {
+	if (dsa_port_is_external(dp, ds))
+		return -EOPNOTSUPP;
+
 	/* We don't need any dynamic resource from the kernel (yet),
 	 * so skip the prepare phase.
 	 */
@@ -2052,6 +2055,9 @@ void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, struct dsa_port *dp,
 		GLOBAL_ATU_DATA_STATE_UC_STATIC;
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
 
+	if (dsa_port_is_external(dp, ds))
+		return;
+
 	mutex_lock(&ps->smi_mutex);
 	if (_mv88e6xxx_port_fdb_load(ds, dp->port, fdb->addr, fdb->vid, state))
 		netdev_err(ds->ports[dp->port], "failed to load MAC address\n");
@@ -2064,6 +2070,9 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, struct dsa_port *dp,
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
 	int ret;
 
+	if (dsa_port_is_external(dp, ds))
+		return -EOPNOTSUPP;
+
 	mutex_lock(&ps->smi_mutex);
 	ret = _mv88e6xxx_port_fdb_load(ds, dp->port, fdb->addr, fdb->vid,
 				       GLOBAL_ATU_DATA_STATE_UNUSED);
@@ -2169,6 +2178,9 @@ int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, struct dsa_port *dp,
 	u16 fid;
 	int err;
 
+	if (dsa_port_is_external(dp, ds))
+		return -EOPNOTSUPP;
+
 	mutex_lock(&ps->smi_mutex);
 
 	/* Dump port's default Filtering Information Database (VLAN ID 0) */
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 6e08b3d..e8765c3 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -14,6 +14,7 @@
 #include <linux/phy.h>
 #include <linux/netdevice.h>
 #include <linux/netpoll.h>
+#include <net/switchdev.h>
 
 struct dsa_device_ops {
 	struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
@@ -51,6 +52,14 @@ int dsa_tree_bridge_port_join(struct dsa_switch_tree *dst, struct dsa_port *dp,
 			      struct net_device *br);
 void dsa_tree_bridge_port_leave(struct dsa_switch_tree *dst,
 				struct dsa_port *dp, struct net_device *br);
+int dsa_tree_port_fdb_add(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			  const struct switchdev_obj_port_fdb *fdb,
+			  struct switchdev_trans *trans);
+int dsa_tree_port_fdb_del(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			  const struct switchdev_obj_port_fdb *fdb);
+int dsa_tree_port_fdb_dump(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			   struct switchdev_obj_port_fdb *fdb,
+			   switchdev_obj_dump_cb_t *cb);
 
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 7123ae2..90bcf8a 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -239,51 +239,6 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev,
 	return -EOPNOTSUPP;
 }
 
-static int dsa_slave_port_fdb_add(struct net_device *dev,
-				  const struct switchdev_obj_port_fdb *fdb,
-				  struct switchdev_trans *trans)
-{
-	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->dp->ds;
-
-	if (switchdev_trans_ph_prepare(trans)) {
-		if (!ds->drv->port_fdb_prepare || !ds->drv->port_fdb_add)
-			return -EOPNOTSUPP;
-
-		return ds->drv->port_fdb_prepare(ds, p->dp, fdb, trans);
-	}
-
-	ds->drv->port_fdb_add(ds, p->dp, fdb, trans);
-
-	return 0;
-}
-
-static int dsa_slave_port_fdb_del(struct net_device *dev,
-				  const struct switchdev_obj_port_fdb *fdb)
-{
-	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->dp->ds;
-	int ret = -EOPNOTSUPP;
-
-	if (ds->drv->port_fdb_del)
-		ret = ds->drv->port_fdb_del(ds, p->dp, fdb);
-
-	return ret;
-}
-
-static int dsa_slave_port_fdb_dump(struct net_device *dev,
-				   struct switchdev_obj_port_fdb *fdb,
-				   switchdev_obj_dump_cb_t *cb)
-{
-	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->dp->ds;
-
-	if (ds->drv->port_fdb_dump)
-		return ds->drv->port_fdb_dump(ds, p->dp, fdb, cb);
-
-	return -EOPNOTSUPP;
-}
-
 static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
@@ -352,6 +307,9 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
 				  const struct switchdev_obj *obj,
 				  struct switchdev_trans *trans)
 {
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_port *dp = p->dp;
+	struct dsa_switch_tree *dst = dp->ds->dst;
 	int err;
 
 	/* For the prepare phase, ensure the full set of changes is feasable in
@@ -361,9 +319,8 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
 
 	switch (obj->id) {
 	case SWITCHDEV_OBJ_ID_PORT_FDB:
-		err = dsa_slave_port_fdb_add(dev,
-					     SWITCHDEV_OBJ_PORT_FDB(obj),
-					     trans);
+		err = dsa_tree_port_fdb_add(dst, dp,
+					    SWITCHDEV_OBJ_PORT_FDB(obj), trans);
 		break;
 	case SWITCHDEV_OBJ_ID_PORT_VLAN:
 		err = dsa_slave_port_vlan_add(dev,
@@ -381,12 +338,15 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
 static int dsa_slave_port_obj_del(struct net_device *dev,
 				  const struct switchdev_obj *obj)
 {
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_port *dp = p->dp;
+	struct dsa_switch_tree *dst = dp->ds->dst;
 	int err;
 
 	switch (obj->id) {
 	case SWITCHDEV_OBJ_ID_PORT_FDB:
-		err = dsa_slave_port_fdb_del(dev,
-					     SWITCHDEV_OBJ_PORT_FDB(obj));
+		err = dsa_tree_port_fdb_del(dst, dp,
+					    SWITCHDEV_OBJ_PORT_FDB(obj));
 		break;
 	case SWITCHDEV_OBJ_ID_PORT_VLAN:
 		err = dsa_slave_port_vlan_del(dev,
@@ -404,13 +364,15 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,
 				   struct switchdev_obj *obj,
 				   switchdev_obj_dump_cb_t *cb)
 {
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_port *dp = p->dp;
+	struct dsa_switch_tree *dst = dp->ds->dst;
 	int err;
 
 	switch (obj->id) {
 	case SWITCHDEV_OBJ_ID_PORT_FDB:
-		err = dsa_slave_port_fdb_dump(dev,
-					      SWITCHDEV_OBJ_PORT_FDB(obj),
-					      cb);
+		err = dsa_tree_port_fdb_dump(dst, dp,
+					     SWITCHDEV_OBJ_PORT_FDB(obj), cb);
 		break;
 	case SWITCHDEV_OBJ_ID_PORT_VLAN:
 		err = dsa_slave_port_vlan_dump(dev,
diff --git a/net/dsa/tree.c b/net/dsa/tree.c
index d3f5aea..8394019 100644
--- a/net/dsa/tree.c
+++ b/net/dsa/tree.c
@@ -11,6 +11,7 @@
 #include <linux/if_bridge.h>
 #include <linux/list.h>
 #include <linux/netdevice.h>
+#include <net/switchdev.h>
 
 #include "dsa_priv.h"
 
@@ -64,3 +65,63 @@ void dsa_tree_bridge_port_leave(struct dsa_switch_tree *dst,
 						    BR_STATE_FORWARDING);
 	}
 }
+
+int dsa_tree_port_fdb_add(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			  const struct switchdev_obj_port_fdb *fdb,
+			  struct switchdev_trans *trans)
+{
+	struct dsa_switch *ds;
+	int err;
+
+	dsa_tree_for_each_switch(dst, ds) {
+		if (switchdev_trans_ph_prepare(trans)) {
+			if (!ds->drv->port_fdb_prepare ||
+			    !ds->drv->port_fdb_add)
+				return -EOPNOTSUPP;
+
+			err = ds->drv->port_fdb_prepare(ds, dp, fdb, trans);
+			if (err)
+				return err;
+		} else {
+			ds->drv->port_fdb_add(ds, dp, fdb, trans);
+		}
+	}
+
+	return 0;
+}
+
+int dsa_tree_port_fdb_del(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			  const struct switchdev_obj_port_fdb *fdb)
+{
+	struct dsa_switch *ds;
+	int err;
+
+	dsa_tree_for_each_switch(dst, ds) {
+		if (!ds->drv->port_fdb_del)
+			return -EOPNOTSUPP;
+
+		err = ds->drv->port_fdb_del(ds, dp, fdb);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+int dsa_tree_port_fdb_dump(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			   struct switchdev_obj_port_fdb *fdb,
+			   switchdev_obj_dump_cb_t *cb)
+{
+	struct dsa_switch *ds;
+	int err;
+
+	dsa_tree_for_each_switch(dst, ds) {
+		if (ds->drv->port_fdb_dump) {
+			err = ds->drv->port_fdb_dump(ds, dp, fdb, cb);
+			if (err && err != -EOPNOTSUPP)
+				return err;
+		}
+	}
+
+	return 0;
+}
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 16/20] net: dsa: add tree-wide VLAN ops
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (14 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 15/20] net: dsa: add tree-wide FDB ops Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 17/20] net: dsa: mv88e6xxx: factorize port bridge change Vivien Didelot
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

In order to support cross-chip operations, we need to inform each switch
driver when a port operation occurs in a DSA tree.

Implement tree-wide VLAN operations.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/mv88e6xxx.c | 12 +++++++++
 net/dsa/dsa_priv.h          |  8 ++++++
 net/dsa/slave.c             | 59 ++++++--------------------------------------
 net/dsa/tree.c              | 60 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 87 insertions(+), 52 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 7d29de3..8004d00 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -1378,6 +1378,9 @@ int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, struct dsa_port *dp,
 	u16 pvid;
 	int err;
 
+	if (dsa_port_is_external(dp, ds))
+		return -EOPNOTSUPP;
+
 	mutex_lock(&ps->smi_mutex);
 
 	err = _mv88e6xxx_port_pvid_get(ds, dp->port, &pvid);
@@ -1835,6 +1838,9 @@ int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, struct dsa_port *dp,
 {
 	int err;
 
+	if (dsa_port_is_external(dp, ds))
+		return -EOPNOTSUPP;
+
 	/* If the requested port doesn't belong to the same bridge as the VLAN
 	 * members, do not support it (yet) and fallback to software VLAN.
 	 */
@@ -1874,6 +1880,9 @@ void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, struct dsa_port *dp,
 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
 	u16 vid;
 
+	if (dsa_port_is_external(dp, ds))
+		return;
+
 	mutex_lock(&ps->smi_mutex);
 
 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
@@ -1930,6 +1939,9 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, struct dsa_port *dp,
 	u16 pvid, vid;
 	int err = 0;
 
+	if (dsa_port_is_external(dp, ds))
+		return -EOPNOTSUPP;
+
 	mutex_lock(&ps->smi_mutex);
 
 	err = _mv88e6xxx_port_pvid_get(ds, dp->port, &pvid);
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index e8765c3..d743d6a 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -60,6 +60,14 @@ int dsa_tree_port_fdb_del(struct dsa_switch_tree *dst, struct dsa_port *dp,
 int dsa_tree_port_fdb_dump(struct dsa_switch_tree *dst, struct dsa_port *dp,
 			   struct switchdev_obj_port_fdb *fdb,
 			   switchdev_obj_dump_cb_t *cb);
+int dsa_tree_port_vlan_add(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			   const struct switchdev_obj_port_vlan *vlan,
+			   struct switchdev_trans *trans);
+int dsa_tree_port_vlan_del(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			   const struct switchdev_obj_port_vlan *vlan);
+int dsa_tree_port_vlan_dump(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			    struct switchdev_obj_port_vlan *vlan,
+			    switchdev_obj_dump_cb_t *cb);
 
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 90bcf8a..19469dc 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -195,50 +195,6 @@ out:
 	return 0;
 }
 
-static int dsa_slave_port_vlan_add(struct net_device *dev,
-				   const struct switchdev_obj_port_vlan *vlan,
-				   struct switchdev_trans *trans)
-{
-	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->dp->ds;
-
-	if (switchdev_trans_ph_prepare(trans)) {
-		if (!ds->drv->port_vlan_prepare || !ds->drv->port_vlan_add)
-			return -EOPNOTSUPP;
-
-		return ds->drv->port_vlan_prepare(ds, p->dp, vlan, trans);
-	}
-
-	ds->drv->port_vlan_add(ds, p->dp, vlan, trans);
-
-	return 0;
-}
-
-static int dsa_slave_port_vlan_del(struct net_device *dev,
-				   const struct switchdev_obj_port_vlan *vlan)
-{
-	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->dp->ds;
-
-	if (!ds->drv->port_vlan_del)
-		return -EOPNOTSUPP;
-
-	return ds->drv->port_vlan_del(ds, p->dp, vlan);
-}
-
-static int dsa_slave_port_vlan_dump(struct net_device *dev,
-				    struct switchdev_obj_port_vlan *vlan,
-				    switchdev_obj_dump_cb_t *cb)
-{
-	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct dsa_switch *ds = p->dp->ds;
-
-	if (ds->drv->port_vlan_dump)
-		return ds->drv->port_vlan_dump(ds, p->dp, vlan, cb);
-
-	return -EOPNOTSUPP;
-}
-
 static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
@@ -323,9 +279,9 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
 					    SWITCHDEV_OBJ_PORT_FDB(obj), trans);
 		break;
 	case SWITCHDEV_OBJ_ID_PORT_VLAN:
-		err = dsa_slave_port_vlan_add(dev,
-					      SWITCHDEV_OBJ_PORT_VLAN(obj),
-					      trans);
+		err = dsa_tree_port_vlan_add(dst, dp,
+					     SWITCHDEV_OBJ_PORT_VLAN(obj),
+					     trans);
 		break;
 	default:
 		err = -EOPNOTSUPP;
@@ -349,8 +305,8 @@ static int dsa_slave_port_obj_del(struct net_device *dev,
 					    SWITCHDEV_OBJ_PORT_FDB(obj));
 		break;
 	case SWITCHDEV_OBJ_ID_PORT_VLAN:
-		err = dsa_slave_port_vlan_del(dev,
-					      SWITCHDEV_OBJ_PORT_VLAN(obj));
+		err = dsa_tree_port_vlan_del(dst, dp,
+					     SWITCHDEV_OBJ_PORT_VLAN(obj));
 		break;
 	default:
 		err = -EOPNOTSUPP;
@@ -375,9 +331,8 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,
 					     SWITCHDEV_OBJ_PORT_FDB(obj), cb);
 		break;
 	case SWITCHDEV_OBJ_ID_PORT_VLAN:
-		err = dsa_slave_port_vlan_dump(dev,
-					       SWITCHDEV_OBJ_PORT_VLAN(obj),
-					       cb);
+		err = dsa_tree_port_vlan_dump(dst, dp,
+					      SWITCHDEV_OBJ_PORT_VLAN(obj), cb);
 		break;
 	default:
 		err = -EOPNOTSUPP;
diff --git a/net/dsa/tree.c b/net/dsa/tree.c
index 8394019..0ef103e 100644
--- a/net/dsa/tree.c
+++ b/net/dsa/tree.c
@@ -125,3 +125,63 @@ int dsa_tree_port_fdb_dump(struct dsa_switch_tree *dst, struct dsa_port *dp,
 
 	return 0;
 }
+
+int dsa_tree_port_vlan_add(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			    const struct switchdev_obj_port_vlan *vlan,
+			    struct switchdev_trans *trans)
+{
+	struct dsa_switch *ds;
+	int err;
+
+	dsa_tree_for_each_switch(dst, ds) {
+		if (switchdev_trans_ph_prepare(trans)) {
+			if (!ds->drv->port_vlan_prepare ||
+			    !ds->drv->port_vlan_add)
+				return -EOPNOTSUPP;
+
+			err = ds->drv->port_vlan_prepare(ds, dp, vlan, trans);
+			if (err)
+				return err;
+		} else {
+			ds->drv->port_vlan_add(ds, dp, vlan, trans);
+		}
+	}
+
+	return 0;
+}
+
+int dsa_tree_port_vlan_del(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			    const struct switchdev_obj_port_vlan *vlan)
+{
+	struct dsa_switch *ds;
+	int err;
+
+	dsa_tree_for_each_switch(dst, ds) {
+		if (!ds->drv->port_vlan_del)
+			return -EOPNOTSUPP;
+
+		err = ds->drv->port_vlan_del(ds, dp, vlan);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+int dsa_tree_port_vlan_dump(struct dsa_switch_tree *dst, struct dsa_port *dp,
+			     struct switchdev_obj_port_vlan *vlan,
+			     switchdev_obj_dump_cb_t *cb)
+{
+	struct dsa_switch *ds;
+	int err;
+
+	dsa_tree_for_each_switch(dst, ds) {
+		if (ds->drv->port_vlan_dump) {
+			err = ds->drv->port_vlan_dump(ds, dp, vlan, cb);
+			if (err && err != -EOPNOTSUPP)
+				return err;
+		}
+	}
+
+	return 0;
+}
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 17/20] net: dsa: mv88e6xxx: factorize port bridge change
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (15 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 16/20] net: dsa: add tree-wide VLAN ops Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 18/20] net: dsa: mv88e6xxx: add flags to info Vivien Didelot
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Implement a mv88e6xxx_port_bridge_change function to factorize the
configuration needed when a port joins or leaves a bridge group.

This will simplify the implementation of cross-chip bridging.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/mv88e6xxx.c | 67 +++++++++++++++++++++++++++------------------
 1 file changed, 40 insertions(+), 27 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 8004d00..25852ee 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -1150,6 +1150,24 @@ static int _mv88e6xxx_port_map_vlantable(struct dsa_switch *ds,
 	return _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_BASE_VLAN, reg);
 }
 
+static int _mv88e6xxx_remap_vlantable(struct dsa_switch *ds,
+				      struct net_device *bridge)
+{
+	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+	struct dsa_port *intp;
+	int err;
+
+	dsa_switch_for_each_port(ds, intp, ps->info->num_ports) {
+		if (intp->br == bridge) {
+			err = _mv88e6xxx_port_map_vlantable(ds, intp);
+			if (err)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
 void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
@@ -2229,51 +2247,46 @@ unlock:
 	return err;
 }
 
-int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, struct dsa_port *dp,
-			       struct net_device *bridge)
+int mv88e6xxx_port_bridge_change(struct dsa_switch *ds, struct dsa_port *dp,
+				 struct net_device *bridge)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-	struct dsa_port *intp;
 	int err;
 
-	if (dsa_port_is_external(dp, ds))
-		return -EOPNOTSUPP;
-
 	mutex_lock(&ps->smi_mutex);
 
-	/* Remap each port's VLANTable */
-	dsa_switch_for_each_port(ds, intp, ps->info->num_ports) {
-		if (intp->br == bridge) {
-			err = _mv88e6xxx_port_map_vlantable(ds, intp);
+	if (dsa_port_is_external(dp, ds)) {
+		err = -EOPNOTSUPP;
+	} else {
+		/* Remap VLANTable of concerned in-chip ports */
+		if (!dp->br) {
+			err = _mv88e6xxx_port_map_vlantable(ds, dp);
 			if (err)
-				break;
+				goto unlock;
 		}
+
+		err = _mv88e6xxx_remap_vlantable(ds, bridge);
+		if (err)
+			goto unlock;
 	}
 
+unlock:
 	mutex_unlock(&ps->smi_mutex);
 
 	return err;
 }
 
+int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, struct dsa_port *dp,
+			       struct net_device *bridge)
+{
+	return mv88e6xxx_port_bridge_change(ds, dp, bridge);
+}
+
 void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, struct dsa_port *dp,
 				 struct net_device *bridge)
 {
-	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-	struct dsa_port *intp;
-
-	if (dsa_port_is_external(dp, ds))
-		return;
-
-	mutex_lock(&ps->smi_mutex);
-
-	/* Remap each port's VLANTable */
-	dsa_switch_for_each_port(ds, intp, ps->info->num_ports)
-		if (intp == dp || intp->br == bridge)
-			if (_mv88e6xxx_port_map_vlantable(ds, intp))
-				netdev_warn(ds->ports[intp->port],
-					    "failed to remap\n");
-
-	mutex_unlock(&ps->smi_mutex);
+	if (mv88e6xxx_port_bridge_change(ds, dp, bridge))
+		netdev_err(ds->ports[dp->port], "failed to unbridge\n");
 }
 
 static void mv88e6xxx_bridge_work(struct work_struct *work)
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 18/20] net: dsa: mv88e6xxx: add flags to info
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (16 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 17/20] net: dsa: mv88e6xxx: factorize port bridge change Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 19/20] net: dsa: mv88e6xxx: conditionally init PVT Vivien Didelot
  2016-04-27 22:30 ` [RFC 20/20] net: dsa: mv88e6xxx: setup PVT on cross-chip ops Vivien Didelot
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Add a flags bitmap to the mv88e6xxx_info structure to help describing
features supported or not by a switch model.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/mv88e6xxx.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 56e3347..325caf8 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -338,6 +338,10 @@
 
 #define MV88E6XXX_N_FID		4096
 
+enum mv88e6xxx_flag {
+	MV88E6XXX_NUM_FLAGS,
+};
+
 enum mv88e6xxx_family {
 	MV88E6XXX_FAMILY_NONE,
 	MV88E6XXX_FAMILY_6065,	/* 6031 6035 6061 6065 */
@@ -356,6 +360,7 @@ struct mv88e6xxx_info {
 	const char *name;
 	unsigned int num_databases;
 	unsigned int num_ports;
+	unsigned long flags;
 };
 
 struct mv88e6xxx_atu_entry {
@@ -445,6 +450,12 @@ struct mv88e6xxx_hw_stat {
 	enum stat_type type;
 };
 
+static inline bool mv88e6xxx_has(struct mv88e6xxx_priv_state *ps,
+				 enum mv88e6xxx_flag flag)
+{
+	return !!(ps->info->flags & BIT(flag));
+}
+
 int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active);
 const char *mv88e6xxx_drv_probe(struct device *dsa_dev, struct device *host_dev,
 				int sw_addr, void **priv,
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 19/20] net: dsa: mv88e6xxx: conditionally init PVT
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (17 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 18/20] net: dsa: mv88e6xxx: add flags to info Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  2016-04-27 22:30 ` [RFC 20/20] net: dsa: mv88e6xxx: setup PVT on cross-chip ops Vivien Didelot
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

The current code initialize the Cross-chip Port VLAN Table to all ones,
even tough the switch model doesn't have one.

It also assumes that the switch is configured to support up to
32-switch/16-port cross-chip devices.

Implement the access to the PVT and initialize it only if the switch has
such feature. Support only 88E6352 for the moment.

This commit brings no functional change for devices with a PVT.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/mv88e6352.c |  1 +
 drivers/net/dsa/mv88e6xxx.c | 54 +++++++++++++++++++++++++++++++++++++++------
 drivers/net/dsa/mv88e6xxx.h |  6 +++++
 3 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c
index 4afc24d..29d9fd76 100644
--- a/drivers/net/dsa/mv88e6352.c
+++ b/drivers/net/dsa/mv88e6352.c
@@ -59,6 +59,7 @@ static const struct mv88e6xxx_info mv88e6352_table[] = {
 		.name = "Marvell 88E6352",
 		.num_databases = 4096,
 		.num_ports = 7,
+		.flags = BIT(MV88E6XXX_FLAG_PVT),
 	}
 };
 
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 25852ee..4341ffd 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -2247,6 +2247,47 @@ unlock:
 	return err;
 }
 
+static int _mv88e6xxx_pvt_wait(struct dsa_switch *ds)
+{
+	return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_PVT_ADDR,
+			       GLOBAL2_PVT_ADDR_BUSY);
+}
+
+static int _mv88e6xxx_pvt_cmd(struct dsa_switch *ds, int src_dev, int src_port,
+			      u16 op)
+{
+	u16 reg = op;
+	int err;
+
+	/* 9-bit Cross-chip PVT pointer: with GLOBAL2_MISC_5_BIT_PORT cleared,
+	 * source device is 5-bit, source port is 4-bit.
+	 */
+	reg |= (src_dev & 0x1f) << 4;
+	reg |= (src_port & 0xf);
+
+	err = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_PVT_ADDR, reg);
+	if (err)
+		return err;
+
+	return _mv88e6xxx_pvt_wait(ds);
+}
+
+static int _mv88e6xxx_pvt_init(struct dsa_switch *ds)
+{
+	int err;
+
+	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
+	 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
+	 */
+	err = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_MISC,
+				   0 & ~GLOBAL2_MISC_5_BIT_PORT);
+	if (err)
+		return err;
+
+	/* Allow any cross-chip frames to egress any internal ports */
+	return _mv88e6xxx_pvt_cmd(ds, 0, 0, GLOBAL2_PVT_ADDR_OP_INIT_ONES);
+}
+
 int mv88e6xxx_port_bridge_change(struct dsa_switch *ds, struct dsa_port *dp,
 				 struct net_device *bridge)
 {
@@ -2770,13 +2811,12 @@ int mv88e6xxx_setup_global(struct dsa_switch *ds)
 		if (err)
 			goto unlock;
 
-		/* Initialise cross-chip port VLAN table to reset
-		 * defaults.
-		 */
-		err = _mv88e6xxx_reg_write(ds, REG_GLOBAL2,
-					   GLOBAL2_PVT_ADDR, 0x9000);
-		if (err)
-			goto unlock;
+		/* Initialize Cross-chip Port VLAN Table (PVT) */
+		if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_PVT)) {
+			err = _mv88e6xxx_pvt_init(ds);
+			if (err)
+				goto unlock;
+		}
 
 		/* Clear the priority override table. */
 		for (i = 0; i < 16; i++) {
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 325caf8..fbde8b4 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -298,6 +298,10 @@
 #define GLOBAL2_INGRESS_OP	0x09
 #define GLOBAL2_INGRESS_DATA	0x0a
 #define GLOBAL2_PVT_ADDR	0x0b
+#define GLOBAL2_PVT_ADDR_BUSY	BIT(15)
+#define GLOBAL2_PVT_ADDR_OP_INIT_ONES	((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY)
+#define GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN	((0x03 << 12) | GLOBAL2_PVT_ADDR_BUSY)
+#define GLOBAL2_PVT_ADDR_OP_READ	((0x04 << 12) | GLOBAL2_PVT_ADDR_BUSY)
 #define GLOBAL2_PVT_DATA	0x0c
 #define GLOBAL2_SWITCH_MAC	0x0d
 #define GLOBAL2_SWITCH_MAC_BUSY BIT(15)
@@ -335,10 +339,12 @@
 #define GLOBAL2_WDOG_CONTROL	0x1b
 #define GLOBAL2_QOS_WEIGHT	0x1c
 #define GLOBAL2_MISC		0x1d
+#define GLOBAL2_MISC_5_BIT_PORT	BIT(14)
 
 #define MV88E6XXX_N_FID		4096
 
 enum mv88e6xxx_flag {
+	MV88E6XXX_FLAG_PVT,
 	MV88E6XXX_NUM_FLAGS,
 };
 
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RFC 20/20] net: dsa: mv88e6xxx: setup PVT on cross-chip ops
  2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
                   ` (18 preceding siblings ...)
  2016-04-27 22:30 ` [RFC 19/20] net: dsa: mv88e6xxx: conditionally init PVT Vivien Didelot
@ 2016-04-27 22:30 ` Vivien Didelot
  19 siblings, 0 replies; 28+ messages in thread
From: Vivien Didelot @ 2016-04-27 22:30 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Switches with a Cross-chip Port VLAN Table are currently configured to
allow cross-chip frames to egress any internal ports. This means that
unbridged cross-chip ports can actually talk to each other, and this is
not what we want.

In order to restrict that, we need to setup the PVT entry for an
external port when it joins or leave a bridge group crossing the switch.

Also initialize the PVT to forbid egressing of cross-chip frames to
internal user ports by default.

Note that a PVT-less switch cannot forbid such frames to egress its
internal ports, unless the kernel supports VLAN filtering. In such
systems, a bridge group is also implemented as a 802.1Q VLAN and thus a
global VTU-based logic can be used to correctly implement cross-chip
hardware bridging. Warn the user if the setup doesn't respect this.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/mv88e6xxx.c | 98 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 95 insertions(+), 3 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 4341ffd..e0f9e93 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -2272,8 +2272,29 @@ static int _mv88e6xxx_pvt_cmd(struct dsa_switch *ds, int src_dev, int src_port,
 	return _mv88e6xxx_pvt_wait(ds);
 }
 
+static int _mv88e6xxx_pvt_write(struct dsa_switch *ds, int src_dev,
+				int src_port, u16 data)
+{
+	int err;
+
+	err = _mv88e6xxx_pvt_wait(ds);
+	if (err)
+		return err;
+
+	err = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_PVT_DATA, data);
+	if (err)
+		return err;
+
+        return _mv88e6xxx_pvt_cmd(ds, src_dev, src_port,
+				  GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN);
+}
+
 static int _mv88e6xxx_pvt_init(struct dsa_switch *ds)
 {
+	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+	struct dsa_port *intp;
+	int src_dev, src_port;
+	u16 pv = 0;
 	int err;
 
 	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
@@ -2284,8 +2305,60 @@ static int _mv88e6xxx_pvt_init(struct dsa_switch *ds)
 	if (err)
 		return err;
 
-	/* Allow any cross-chip frames to egress any internal ports */
-	return _mv88e6xxx_pvt_cmd(ds, 0, 0, GLOBAL2_PVT_ADDR_OP_INIT_ONES);
+	/* Forbid cross-chip frames to egress internal ports */
+	dsa_switch_for_each_port(ds, intp, ps->info->num_ports)
+		if (dsa_is_cpu_port(ds, intp->port) ||
+		    dsa_is_dsa_port(ds, intp->port))
+			pv |= BIT(intp->port);
+
+	for (src_dev = 0; src_dev < 32; ++src_dev) {
+		for (src_port = 0; src_port < 16; ++src_port) {
+			err = _mv88e6xxx_pvt_write(ds, src_dev, src_port, pv);
+			if (err)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+static int _mv88e6xxx_port_map_pvt(struct dsa_switch *ds, struct dsa_port *dp)
+{
+	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+	struct dsa_port *intp;
+	u16 pvlan = 0;
+
+	/* Cross-chip frames can egress CPU and DSA ports, and bridge members */
+	dsa_switch_for_each_port(ds, intp, ps->info->num_ports)
+		if (dsa_is_cpu_port(ds, intp->port) ||
+		    dsa_is_dsa_port(ds, intp->port) ||
+		    (intp->br && intp->br == dp->br))
+			pvlan |= BIT(intp->port);
+
+	return _mv88e6xxx_pvt_write(ds, dp->ds->index, dp->port, pvlan);
+}
+
+static int _mv88e6xxx_remap_pvt(struct dsa_switch *ds,
+				struct net_device *bridge)
+{
+	struct dsa_switch *dsa_sw;
+	struct dsa_port *dsa_p;
+	int err;
+
+	dsa_tree_for_each_switch(ds->dst, dsa_sw) {
+		if (dsa_sw == ds)
+			continue;
+
+		dsa_switch_for_each_port(dsa_sw, dsa_p, DSA_MAX_PORTS) {
+			if (dsa_p->br == bridge) {
+				err = _mv88e6xxx_port_map_pvt(ds, dsa_p);
+				if (err)
+					return err;
+			}
+		}
+	}
+
+	return 0;
 }
 
 int mv88e6xxx_port_bridge_change(struct dsa_switch *ds, struct dsa_port *dp,
@@ -2297,7 +2370,19 @@ int mv88e6xxx_port_bridge_change(struct dsa_switch *ds, struct dsa_port *dp,
 	mutex_lock(&ps->smi_mutex);
 
 	if (dsa_port_is_external(dp, ds)) {
-		err = -EOPNOTSUPP;
+		/* Forbidding hardware bridging of cross-chip frames requires a
+		 * Cross-chip Port VLAN Table (PVT), unless VLAN filtering is
+		 * enabled, in which case a global VTU-based logic works.
+		 */
+		if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_PVT)) {
+			err = _mv88e6xxx_port_map_pvt(ds, dp);
+		} else if (IS_ENABLED(CONFIG_BRIDGE_VLAN_FILTERING)) {
+			err = 0;
+		} else {
+			pr_warn("%s: cannot prevent cross-chip frames without CONFIG_BRIDGE_VLAN_FILTERING\n",
+				ps->info->name);
+			err = -EOPNOTSUPP;
+		}
 	} else {
 		/* Remap VLANTable of concerned in-chip ports */
 		if (!dp->br) {
@@ -2309,6 +2394,13 @@ int mv88e6xxx_port_bridge_change(struct dsa_switch *ds, struct dsa_port *dp,
 		err = _mv88e6xxx_remap_vlantable(ds, bridge);
 		if (err)
 			goto unlock;
+
+		/* Remap PVT entries of concerned cross-chip ports */
+		if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_PVT)) {
+			err = _mv88e6xxx_remap_pvt(ds, bridge);
+			if (err)
+				goto unlock;
+		}
 	}
 
 unlock:
-- 
2.8.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [RFC 01/20] net: dsa: introduce a dsa_port structure
  2016-04-27 22:29 ` [RFC 01/20] net: dsa: introduce a dsa_port structure Vivien Didelot
@ 2016-04-27 23:07   ` Andrew Lunn
  0 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2016-04-27 23:07 UTC (permalink / raw)
  To: Vivien Didelot
  Cc: netdev, linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Jiri Pirko

> @@ -230,6 +231,13 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
>  	for (i = 0; i < DSA_MAX_PORTS; i++) {
>  		char *name;
>  
> +		dp[i] = devm_kzalloc(parent, sizeof(*dp), GFP_KERNEL);
> +		if (dp[i] == NULL)
> +			return -ENOMEM;

You are not saving anything here by dynamically allocating the memory,
since you do it for all ports. So just make it a member of ds with
size DSA_MAX_PORTS. I would then call this array structure ports.

Humm, i also think keeping it in dsa_slave_priv is wrong, if you have
defined the structure in the global include/net/dsa.h. dsa_switch is a
better place for it.

     Andrew

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC 03/20] net: dsa: pass dsa_port down to drivers bridge ops
  2016-04-27 22:30 ` [RFC 03/20] net: dsa: pass dsa_port down to drivers bridge ops Vivien Didelot
@ 2016-04-27 23:12   ` Andrew Lunn
  0 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2016-04-27 23:12 UTC (permalink / raw)
  To: Vivien Didelot
  Cc: netdev, linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Jiri Pirko

On Wed, Apr 27, 2016 at 06:30:00PM -0400, Vivien Didelot wrote:
> Now that DSA as proper structure for DSA ports, pass it down to the
> port_bridge_join and port_bridge_leave driver functions.

I should look at the later patches, but this looks like a step
backwards.

If your ports array is a member of ds, you have no need for this patch
at all.

What advantage does this change bring?

      Andrew

> 
> Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
> ---
>  drivers/net/dsa/bcm_sf2.c   | 28 ++++++++++++++--------------
>  drivers/net/dsa/mv88e6xxx.c | 10 +++++-----
>  drivers/net/dsa/mv88e6xxx.h |  4 ++--
>  include/net/dsa.h           |  4 ++--
>  net/dsa/slave.c             |  4 ++--
>  5 files changed, 25 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
> index f394ea9..2d7b297 100644
> --- a/drivers/net/dsa/bcm_sf2.c
> +++ b/drivers/net/dsa/bcm_sf2.c
> @@ -491,15 +491,15 @@ static int bcm_sf2_sw_fast_age_port(struct dsa_switch  *ds, int port)
>  	return 0;
>  }
>  
> -static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
> +static int bcm_sf2_sw_br_join(struct dsa_switch *ds, struct dsa_port *dp,
>  			      struct net_device *bridge)
>  {
>  	struct bcm_sf2_priv *priv = ds_to_priv(ds);
>  	unsigned int i;
>  	u32 reg, p_ctl;
>  
> -	priv->port_sts[port].bridge_dev = bridge;
> -	p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
> +	priv->port_sts[dp->port].bridge_dev = bridge;
> +	p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(dp->port));
>  
>  	for (i = 0; i < priv->hw_params.num_ports; i++) {
>  		if (priv->port_sts[i].bridge_dev != bridge)
> @@ -509,7 +509,7 @@ static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
>  		 * membership and update the remote port bitmask
>  		 */
>  		reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
> -		reg |= 1 << port;
> +		reg |= 1 << dp->port;
>  		core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
>  		priv->port_sts[i].vlan_ctl_mask = reg;
>  
> @@ -519,20 +519,20 @@ static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
>  	/* Configure the local port VLAN control membership to include
>  	 * remote ports and update the local port bitmask
>  	 */
> -	core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port));
> -	priv->port_sts[port].vlan_ctl_mask = p_ctl;
> +	core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(dp->port));
> +	priv->port_sts[dp->port].vlan_ctl_mask = p_ctl;
>  
>  	return 0;
>  }
>  
> -static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port,
> +static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, struct dsa_port *dp,
>  				struct net_device *bridge)
>  {
>  	struct bcm_sf2_priv *priv = ds_to_priv(ds);
>  	unsigned int i;
>  	u32 reg, p_ctl;
>  
> -	p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
> +	p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(dp->port));
>  
>  	for (i = 0; i < priv->hw_params.num_ports; i++) {
>  		/* Don't touch the remaining ports */
> @@ -540,18 +540,18 @@ static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port,
>  			continue;
>  
>  		reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
> -		reg &= ~(1 << port);
> +		reg &= ~(1 << dp->port);
>  		core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
> -		priv->port_sts[port].vlan_ctl_mask = reg;
> +		priv->port_sts[dp->port].vlan_ctl_mask = reg;
>  
>  		/* Prevent self removal to preserve isolation */
> -		if (port != i)
> +		if (dp->port != i)
>  			p_ctl &= ~(1 << i);
>  	}
>  
> -	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;
> +	core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(dp->port));
> +	priv->port_sts[dp->port].vlan_ctl_mask = p_ctl;
> +	priv->port_sts[dp->port].bridge_dev = NULL;
>  }
>  
>  static void 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 86f8f2f..3f78c73 100644
> --- a/drivers/net/dsa/mv88e6xxx.c
> +++ b/drivers/net/dsa/mv88e6xxx.c
> @@ -2203,7 +2203,7 @@ unlock:
>  	return err;
>  }
>  
> -int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
> +int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, struct dsa_port *dp,
>  			       struct net_device *bridge)
>  {
>  	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
> @@ -2212,7 +2212,7 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
>  	mutex_lock(&ps->smi_mutex);
>  
>  	/* Assign the bridge and remap each port's VLANTable */
> -	ps->ports[port].bridge_dev = bridge;
> +	ps->ports[dp->port].bridge_dev = bridge;
>  
>  	for (i = 0; i < ps->info->num_ports; ++i) {
>  		if (ps->ports[i].bridge_dev == bridge) {
> @@ -2227,7 +2227,7 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
>  	return err;
>  }
>  
> -void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
> +void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, struct dsa_port *dp,
>  				 struct net_device *bridge)
>  {
>  	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
> @@ -2236,10 +2236,10 @@ void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
>  	mutex_lock(&ps->smi_mutex);
>  
>  	/* Unassign the bridge and remap each port's VLANTable */
> -	ps->ports[port].bridge_dev = NULL;
> +	ps->ports[dp->port].bridge_dev = NULL;
>  
>  	for (i = 0; i < ps->info->num_ports; ++i)
> -		if (i == port || ps->ports[i].bridge_dev == bridge)
> +		if (i == dp->port || ps->ports[i].bridge_dev == bridge)
>  			if (_mv88e6xxx_port_based_vlan_map(ds, i))
>  				netdev_warn(ds->ports[i], "failed to remap\n");
>  
> diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
> index 2eb9a82..55b8eac 100644
> --- a/drivers/net/dsa/mv88e6xxx.h
> +++ b/drivers/net/dsa/mv88e6xxx.h
> @@ -490,9 +490,9 @@ int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum,
>  int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e);
>  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,
> +int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, struct dsa_port *dp,
>  			       struct net_device *bridge);
> -void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
> +void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, struct dsa_port *dp,
>  				 struct net_device *bridge);
>  void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
>  int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
> diff --git a/include/net/dsa.h b/include/net/dsa.h
> index ed33500..fb626ae 100644
> --- a/include/net/dsa.h
> +++ b/include/net/dsa.h
> @@ -303,9 +303,9 @@ struct dsa_switch_driver {
>  	/*
>  	 * Bridge integration
>  	 */
> -	int	(*port_bridge_join)(struct dsa_switch *ds, int port,
> +	int	(*port_bridge_join)(struct dsa_switch *ds, struct dsa_port *dp,
>  				    struct net_device *bridge);
> -	void	(*port_bridge_leave)(struct dsa_switch *ds, int port,
> +	void	(*port_bridge_leave)(struct dsa_switch *ds, struct dsa_port *dp,
>  				     struct net_device *bridge);
>  	void	(*port_stp_state_set)(struct dsa_switch *ds, int port,
>  				      u8 state);
> diff --git a/net/dsa/slave.c b/net/dsa/slave.c
> index f2ec13d..9a8ea9a 100644
> --- a/net/dsa/slave.c
> +++ b/net/dsa/slave.c
> @@ -441,7 +441,7 @@ static int dsa_slave_bridge_port_join(struct net_device *dev,
>  	p->bridge_dev = br;
>  
>  	if (ds->drv->port_bridge_join)
> -		ret = ds->drv->port_bridge_join(ds, p->dp->port, br);
> +		ret = ds->drv->port_bridge_join(ds, p->dp, br);
>  
>  	if (ret && ret != -EOPNOTSUPP) {
>  		p->bridge_dev = NULL;
> @@ -460,7 +460,7 @@ static void dsa_slave_bridge_port_leave(struct net_device *dev)
>  	p->bridge_dev = NULL;
>  
>  	if (ds->drv->port_bridge_leave)
> -		ds->drv->port_bridge_leave(ds, p->dp->port, br);
> +		ds->drv->port_bridge_leave(ds, p->dp, br);
>  
>  	/* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
>  	 * so allow it to be in BR_STATE_FORWARDING to be kept functional
> -- 
> 2.8.0
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC 07/20] net: dsa: list ports in switch\\
  2016-04-27 22:30 ` [RFC 07/20] net: dsa: list ports in switch Vivien Didelot
@ 2016-04-27 23:15   ` Andrew Lunn
  2016-04-28 17:00     ` Florian Fainelli
  0 siblings, 1 reply; 28+ messages in thread
From: Andrew Lunn @ 2016-04-27 23:15 UTC (permalink / raw)
  To: Vivien Didelot
  Cc: netdev, linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Jiri Pirko

On Wed, Apr 27, 2016 at 06:30:04PM -0400, Vivien Didelot wrote:
> List DSA port structures in their switch structure, so that drivers can
> iterate on them to retrieve information such as their ports membership.

And this would be so much easier using a plan array.

    Andrew

> 
> Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
> ---
>  include/net/dsa.h | 9 +++++++++
>  net/dsa/dsa.c     | 4 ++++
>  2 files changed, 13 insertions(+)
> 
> diff --git a/include/net/dsa.h b/include/net/dsa.h
> index 69e467c..5f2e7df 100644
> --- a/include/net/dsa.h
> +++ b/include/net/dsa.h
> @@ -32,6 +32,11 @@ enum dsa_tag_protocol {
>  #define DSA_MAX_SWITCHES	4
>  #define DSA_MAX_PORTS		12
>  
> +#define dsa_switch_for_each_port(_ds, _dp, _num_ports)			\
> +	for (_dp = list_first_entry(&_ds->dp, typeof(*_dp), list);	\
> +	     &_dp->list != (&_ds->dp) && _dp->port < _num_ports;	\
> +	     _dp = list_next_entry(_dp, list))
> +
>  struct dsa_chip_data {
>  	/*
>  	 * How to access the switch configuration registers.
> @@ -123,6 +128,8 @@ struct dsa_switch_tree {
>  };
>  
>  struct dsa_port {
> +	struct list_head	list;
> +
>  	struct dsa_switch	*ds;
>  	int			port;
>  
> @@ -173,6 +180,8 @@ struct dsa_switch {
>  	u32			phys_mii_mask;
>  	struct mii_bus		*slave_mii_bus;
>  	struct net_device	*ports[DSA_MAX_PORTS];
> +
> +	struct list_head	dp;
>  };
>  
>  static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p)
> diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
> index 222494c..3daffb6 100644
> --- a/net/dsa/dsa.c
> +++ b/net/dsa/dsa.c
> @@ -225,6 +225,8 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
>  	int index = ds->index;
>  	int i, ret;
>  
> +	INIT_LIST_HEAD(&ds->dp);
> +
>  	/*
>  	 * Validate supplied switch configuration.
>  	 */
> @@ -238,6 +240,8 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
>  		dp[i]->ds = ds;
>  		dp[i]->port = i;
>  
> +		list_add_tail(&dp[i]->list, &ds->dp);
> +
>  		name = pd->port_names[i];
>  		if (name == NULL)
>  			continue;
> -- 
> 2.8.0
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC 12/20] net: dsa: rename dst->ds to dst->switches
  2016-04-27 22:30 ` [RFC 12/20] net: dsa: rename dst->ds to dst->switches Vivien Didelot
@ 2016-04-27 23:20   ` Andrew Lunn
  0 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2016-04-27 23:20 UTC (permalink / raw)
  To: Vivien Didelot
  Cc: netdev, linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Jiri Pirko

On Wed, Apr 27, 2016 at 06:30:09PM -0400, Vivien Didelot wrote:
> dsa_switch stores the net_device pointers in a "ports" member. Be
> consistent and store the dsa_switch pointer in a "switches" member of
> the dsa_switch_tree structure.
> 
> This free us the "ds" member for a future dsa_switch list.

NACK.

Or you need to change ds absolutely everywhere, in all drivers and
APIs. We cannot have ds meaning two different things.

       Andrew

> 
> Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
> ---
>  include/net/dsa.h     | 2 +-
>  net/dsa/dsa.c         | 8 ++++----
>  net/dsa/tag_brcm.c    | 2 +-
>  net/dsa/tag_dsa.c     | 2 +-
>  net/dsa/tag_edsa.c    | 2 +-
>  net/dsa/tag_trailer.c | 2 +-
>  6 files changed, 9 insertions(+), 9 deletions(-)
> 
> diff --git a/include/net/dsa.h b/include/net/dsa.h
> index 5f2e7df..389227d 100644
> --- a/include/net/dsa.h
> +++ b/include/net/dsa.h
> @@ -124,7 +124,7 @@ struct dsa_switch_tree {
>  	/*
>  	 * Data for the individual switch chips.
>  	 */
> -	struct dsa_switch	*ds[DSA_MAX_SWITCHES];
> +	struct dsa_switch	*switches[DSA_MAX_SWITCHES];
>  };
>  
>  struct dsa_port {
> diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
> index 3daffb6..aa4a61a 100644
> --- a/net/dsa/dsa.c
> +++ b/net/dsa/dsa.c
> @@ -857,7 +857,7 @@ static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev,
>  			continue;
>  		}
>  
> -		dst->ds[i] = ds;
> +		dst->switches[i] = ds;
>  
>  		++configured;
>  	}
> @@ -953,7 +953,7 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst)
>  	wmb();
>  
>  	for (i = 0; i < dst->pd->nr_chips; i++) {
> -		struct dsa_switch *ds = dst->ds[i];
> +		struct dsa_switch *ds = dst->switches[i];
>  
>  		if (ds)
>  			dsa_switch_destroy(ds);
> @@ -1006,7 +1006,7 @@ static int dsa_suspend(struct device *d)
>  	int i, ret = 0;
>  
>  	for (i = 0; i < dst->pd->nr_chips; i++) {
> -		struct dsa_switch *ds = dst->ds[i];
> +		struct dsa_switch *ds = dst->switches[i];
>  
>  		if (ds != NULL)
>  			ret = dsa_switch_suspend(ds);
> @@ -1022,7 +1022,7 @@ static int dsa_resume(struct device *d)
>  	int i, ret = 0;
>  
>  	for (i = 0; i < dst->pd->nr_chips; i++) {
> -		struct dsa_switch *ds = dst->ds[i];
> +		struct dsa_switch *ds = dst->switches[i];
>  
>  		if (ds != NULL)
>  			ret = dsa_switch_resume(ds);
> diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
> index 3d5aabc..35fc75b 100644
> --- a/net/dsa/tag_brcm.c
> +++ b/net/dsa/tag_brcm.c
> @@ -102,7 +102,7 @@ static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
>  	if (unlikely(dst == NULL))
>  		goto out_drop;
>  
> -	ds = dst->ds[0];
> +	ds = dst->switches[0];
>  
>  	skb = skb_unshare(skb, GFP_ATOMIC);
>  	if (skb == NULL)
> diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
> index c870cfa..bf3eebf8 100644
> --- a/net/dsa/tag_dsa.c
> +++ b/net/dsa/tag_dsa.c
> @@ -109,7 +109,7 @@ static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
>  	 */
>  	if (source_device >= dst->pd->nr_chips)
>  		goto out_drop;
> -	ds = dst->ds[source_device];
> +	ds = dst->switches[source_device];
>  	if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
>  		goto out_drop;
>  
> diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
> index 898f949d..4ddbb85 100644
> --- a/net/dsa/tag_edsa.c
> +++ b/net/dsa/tag_edsa.c
> @@ -122,7 +122,7 @@ static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
>  	 */
>  	if (source_device >= dst->pd->nr_chips)
>  		goto out_drop;
> -	ds = dst->ds[source_device];
> +	ds = dst->switches[source_device];
>  	if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
>  		goto out_drop;
>  
> diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
> index eaa3440..ade0bbf 100644
> --- a/net/dsa/tag_trailer.c
> +++ b/net/dsa/tag_trailer.c
> @@ -67,7 +67,7 @@ static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,
>  
>  	if (unlikely(dst == NULL))
>  		goto out_drop;
> -	ds = dst->ds[0];
> +	ds = dst->switches[0];
>  
>  	skb = skb_unshare(skb, GFP_ATOMIC);
>  	if (skb == NULL)
> -- 
> 2.8.0
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC 07/20] net: dsa: list ports in switch\\
  2016-04-27 23:15   ` [RFC 07/20] net: dsa: list ports in switch\\ Andrew Lunn
@ 2016-04-28 17:00     ` Florian Fainelli
  2016-04-28 18:18       ` Vivien Didelot
  0 siblings, 1 reply; 28+ messages in thread
From: Florian Fainelli @ 2016-04-28 17:00 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot
  Cc: netdev, linux-kernel, kernel, David S. Miller, Jiri Pirko

On 27/04/16 16:15, Andrew Lunn wrote:
> On Wed, Apr 27, 2016 at 06:30:04PM -0400, Vivien Didelot wrote:
>> List DSA port structures in their switch structure, so that drivers can
>> iterate on them to retrieve information such as their ports membership.
> 
> And this would be so much easier using a plan array.

Agreed, I do not see much value in doing this at the moment. Even if you
have unused ports in a switch, allocating an array is a small price to
pay compared to directly indexing by port number.

NAK from me unless there is a compelling reason for doing so.
-- 
Florian

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC 07/20] net: dsa: list ports in switch\\
  2016-04-28 17:00     ` Florian Fainelli
@ 2016-04-28 18:18       ` Vivien Didelot
  2016-04-28 18:29         ` Florian Fainelli
  0 siblings, 1 reply; 28+ messages in thread
From: Vivien Didelot @ 2016-04-28 18:18 UTC (permalink / raw)
  To: Florian Fainelli, Andrew Lunn
  Cc: netdev, linux-kernel, kernel, David S. Miller, Jiri Pirko

Florian Fainelli <f.fainelli@gmail.com> writes:

> On 27/04/16 16:15, Andrew Lunn wrote:
>> On Wed, Apr 27, 2016 at 06:30:04PM -0400, Vivien Didelot wrote:
>>> List DSA port structures in their switch structure, so that drivers can
>>> iterate on them to retrieve information such as their ports membership.
>> 
>> And this would be so much easier using a plan array.
>
> Agreed, I do not see much value in doing this at the moment. Even if you
> have unused ports in a switch, allocating an array is a small price to
> pay compared to directly indexing by port number.
>
> NAK from me unless there is a compelling reason for doing so.

The point of having a list is 1) get rid of the DSA_MAX_PORTS and have
variable number of ports 2) lists make iteration easier with variable
number of switchs/ports, e.g.:

    dsa_tree_for_each_switch(dst, ds)
        dsa_switch_for_each_port(ds, dp)
            /* do something with the port */;

Anyway, I'm writing a proposal for a new design of DSA, in order to
support the D in DSA. That way, we'll avoid reviewing details of the
implementation and have a big picture of the necessary API changes.

Thanks,

        Vivien

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC 07/20] net: dsa: list ports in switch\\
  2016-04-28 18:18       ` Vivien Didelot
@ 2016-04-28 18:29         ` Florian Fainelli
  0 siblings, 0 replies; 28+ messages in thread
From: Florian Fainelli @ 2016-04-28 18:29 UTC (permalink / raw)
  To: Vivien Didelot, Andrew Lunn
  Cc: netdev, linux-kernel, kernel, David S. Miller, Jiri Pirko

On 28/04/16 11:18, Vivien Didelot wrote:
> Florian Fainelli <f.fainelli@gmail.com> writes:
> 
>> On 27/04/16 16:15, Andrew Lunn wrote:
>>> On Wed, Apr 27, 2016 at 06:30:04PM -0400, Vivien Didelot wrote:
>>>> List DSA port structures in their switch structure, so that drivers can
>>>> iterate on them to retrieve information such as their ports membership.
>>>
>>> And this would be so much easier using a plan array.
>>
>> Agreed, I do not see much value in doing this at the moment. Even if you
>> have unused ports in a switch, allocating an array is a small price to
>> pay compared to directly indexing by port number.
>>
>> NAK from me unless there is a compelling reason for doing so.
> 
> The point of having a list is 1) get rid of the DSA_MAX_PORTS and have
> variable number of ports 2) lists make iteration easier with variable
> number of switchs/ports, e.g.:

You could get rid of the DSA_MAX_PORTS by asking switch drivers how many
ports they support and allocate that dynamically.

> 
>     dsa_tree_for_each_switch(dst, ds)
>         dsa_switch_for_each_port(ds, dp)
>             /* do something with the port */;

This is not more compact or efficient than an array walk, but at this
point this becoming preference over anything.

> 
> Anyway, I'm writing a proposal for a new design of DSA, in order to
> support the D in DSA. That way, we'll avoid reviewing details of the
> implementation and have a big picture of the necessary API changes.

Quite frankly, I think your set of changes are submitted at a terrible
time, I would very much prefer to allow Andrew to complete his work on
re-designing the DSA layer to allow different kinds of switches, thus
allowing other people to support more HW in a blink of an eye, and
therefore allowing us all to get a clearer picture of what these little
switches are capable, rather than some patches that produce a lot of
churn with little documented benefits outside of the cross-chip operations.

Don't get me wrong, I think we should get to the point where you want us
to go, and work in that area is very much appreciated!

Thanks
-- 
Florian

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2016-04-28 18:31 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-27 22:29 [RFC 00/20] net: dsa: dsa_port structure and tree-wide ops Vivien Didelot
2016-04-27 22:29 ` [RFC 01/20] net: dsa: introduce a dsa_port structure Vivien Didelot
2016-04-27 23:07   ` Andrew Lunn
2016-04-27 22:29 ` [RFC 02/20] net: dsa: be consistent with NETDEV_CHANGEUPPER Vivien Didelot
2016-04-27 22:30 ` [RFC 03/20] net: dsa: pass dsa_port down to drivers bridge ops Vivien Didelot
2016-04-27 23:12   ` Andrew Lunn
2016-04-27 22:30 ` [RFC 04/20] net: dsa: pass dsa_port down to drivers FDB ops Vivien Didelot
2016-04-27 22:30 ` [RFC 05/20] net: dsa: pass dsa_port down to drivers VLAN ops Vivien Didelot
2016-04-27 22:30 ` [RFC 06/20] net: dsa: move bridge device in dsa_port Vivien Didelot
2016-04-27 22:30 ` [RFC 07/20] net: dsa: list ports in switch Vivien Didelot
2016-04-27 23:15   ` [RFC 07/20] net: dsa: list ports in switch\\ Andrew Lunn
2016-04-28 17:00     ` Florian Fainelli
2016-04-28 18:18       ` Vivien Didelot
2016-04-28 18:29         ` Florian Fainelli
2016-04-27 22:30 ` [RFC 08/20] net: dsa: bcm_sf2: use bridge device from dsa_port Vivien Didelot
2016-04-27 22:30 ` [RFC 09/20] net: dsa: mv88e6xxx: check HW vlan with dsa_port Vivien Didelot
2016-04-27 22:30 ` [RFC 10/20] net: dsa: mv88e6xxx: setup a dsa_port Vivien Didelot
2016-04-27 22:30 ` [RFC 11/20] net: dsa: mv88e6xxx: use bridge from dsa_port Vivien Didelot
2016-04-27 22:30 ` [RFC 12/20] net: dsa: rename dst->ds to dst->switches Vivien Didelot
2016-04-27 23:20   ` Andrew Lunn
2016-04-27 22:30 ` [RFC 13/20] net: dsa: list switches in tree Vivien Didelot
2016-04-27 22:30 ` [RFC 14/20] net: dsa: add tree-wide bridge ops Vivien Didelot
2016-04-27 22:30 ` [RFC 15/20] net: dsa: add tree-wide FDB ops Vivien Didelot
2016-04-27 22:30 ` [RFC 16/20] net: dsa: add tree-wide VLAN ops Vivien Didelot
2016-04-27 22:30 ` [RFC 17/20] net: dsa: mv88e6xxx: factorize port bridge change Vivien Didelot
2016-04-27 22:30 ` [RFC 18/20] net: dsa: mv88e6xxx: add flags to info Vivien Didelot
2016-04-27 22:30 ` [RFC 19/20] net: dsa: mv88e6xxx: conditionally init PVT Vivien Didelot
2016-04-27 22:30 ` [RFC 20/20] net: dsa: mv88e6xxx: setup PVT on cross-chip ops Vivien Didelot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).