linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 0/3] net: dsa: cross-chip operations
@ 2016-04-20 20:26 Vivien Didelot
  2016-04-20 20:26 ` [RFC 1/3] net: dsa: add cross-chip notification for bridge Vivien Didelot
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Vivien Didelot @ 2016-04-20 20:26 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

This patchset aims to start a thread on cross-chips operations in DSA, no need
to spend time on reviewing the details of the code (especially for mv88e6xxx).

So when several switch chips are interconnected, we need to configure them all
to ensure correct hardware switching. We can think about this case:

          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 - - - - - - - +

Here sw1 needs to be aware of br0, to configure itself with MAC addresses,
VIDs, or whatever to ensure hardware frame bridging between sw0 and sw2.

Two cross-chip unbridged ports (e.g. sw0p3 and sw1p1) of mv88e6xxx-supported
devices can currently talk to each other, because the chips are configured to
allow frames to ingress from any external ports. This is not what we want, and
this patchset fixes that. The only important part for the thread is 1/3 though.

Some Marvell switches have a cross-chip port based VLAN table used to allow or
not external frames to egress its internal ports. So a new switch-level
operation needs to be added in order to inform the other switches that a port
joined or left a bridge group. This is what dsa_slave_broadcast_bridge() does.

But this is not enough. When a port joins a bridge group, its switch driver
needs to learn the existing cross-chip members, so that ingressing frames from
them can be allowed. This is what dsa_tree_broadcast_bridge() does.

But that is ugly. This adds yet another DSA function, and makes the DSA layer
code quite complex. Also, similar notifications need to be implemented to
configure cross-chip VLANs (for VLAN filtering aware systems where br0 is
implemented with a 802.1Q VLAN), FDB additions/deletions so that frames get
switched correctly by the hardware, etc.

Actually the DSA drivers functions are just switchdev ops with a bit of
syntactic sugar, but no real value added. The purpose of the DSA layer is to
scale the switchdev ops "horizontally" to every tree port. To avoid numerous
operations and keep it simple for drivers, I think we need 2 things:

  1) The scope of DSA switch driver ops should be the DSA tree, not the switch.
  This means having each dsa_switch_driver implements functions such as:

      int (*port_bridge_join)(struct dsa_switch *ds, int sw_index, int sw_port,
           struct net_device *bridge);

  instead of the current:

      int (*port_bridge_join)(struct dsa_switch *ds, int port,
           struct net_device *bridge);

  So that drivers can configure their in-chip or cross-chip stuffs, return 0 or
  -EOPNOTSUPP if ds->index != sw_index. Replacing dsa_slave_broadcast_bridge.

  2) To replace dsa_tree_broadcast_bridge, drivers need to access public info
  in the tree, such as bridge membership of every port. That can be acheived
  with a bit of refactoring like the following:

      /* include/net/dsa.h */
      struct dsa_port {
          struct list_head    list;
          struct dsa_switch   *ds;
          int                 port;
          struct net_device   *bridge_dev;
      }

      struct dsa_switch_tree {
          ...
          struct list_head ports;
      };

      /* net/dsa/dsa_priv.h */
      struct dsa_slave_priv {
          ...
          dsa_port dp;
      };

      Then DSA switch drivers can implement tree-level ops such as:

      int (*port_bridge_join)(struct dsa_switch *ds, struct dsa_port *dp,
           struct net_device *bridge);

I'm working on an RFC for the above. Let me know what you think and if this
seems correct to you.

Cheers,

Vivien Didelot (3):
  net: dsa: add cross-chip notification for bridge
  net: dsa: mv88e6xxx: initialize PVT
  net: dsa: mv88e6xxx: setup PVT

 drivers/net/dsa/mv88e6352.c |   1 +
 drivers/net/dsa/mv88e6xxx.c | 181 ++++++++++++++++++++++++++++++++++++++++++--
 drivers/net/dsa/mv88e6xxx.h |   7 ++
 include/net/dsa.h           |   6 ++
 net/dsa/slave.c             |  60 ++++++++++++++-
 5 files changed, 246 insertions(+), 9 deletions(-)

-- 
2.8.0

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

* [RFC 1/3] net: dsa: add cross-chip notification for bridge
  2016-04-20 20:26 [RFC 0/3] net: dsa: cross-chip operations Vivien Didelot
@ 2016-04-20 20:26 ` Vivien Didelot
  2016-04-20 20:26 ` [RFC 2/3] net: dsa: mv88e6xxx: initialize PVT Vivien Didelot
  2016-04-20 20:26 ` [RFC 3/3] net: dsa: mv88e6xxx: setup PVT Vivien Didelot
  2 siblings, 0 replies; 4+ messages in thread
From: Vivien Didelot @ 2016-04-20 20:26 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

When multiple switch chips are chained together, one needs to know about
the bridge membership of others. For instance, switches like Marvell
6352 have cross-chip port-based VLAN table to allow or forbid cross-chip
frames to egress.

Add a cross_chip_bridge DSA driver function, used to notify a switch
about bridge membership configured in other chips.

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

diff --git a/include/net/dsa.h b/include/net/dsa.h
index c4bc42b..1994fa7 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -340,6 +340,12 @@ struct dsa_switch_driver {
 	int	(*port_fdb_dump)(struct dsa_switch *ds, int port,
 				 struct switchdev_obj_port_fdb *fdb,
 				 int (*cb)(struct switchdev_obj *obj));
+
+	/*
+	 * Cross-chip notifications
+	 */
+	void	(*cross_chip_bridge)(struct dsa_switch *ds, int sw_index,
+				     int sw_port, struct net_device *bridge);
 };
 
 void register_switch_driver(struct dsa_switch_driver *type);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 3b6750f..bd8f4e2 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -431,19 +431,68 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,
 	return err;
 }
 
+static void dsa_slave_broadcast_bridge(struct net_device *dev)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_switch *ds = p->parent;
+	int chip;
+
+	for (chip = 0; chip < ds->dst->pd->nr_chips; ++chip) {
+		struct dsa_switch *sw = ds->dst->ds[chip];
+
+		if (sw->index == ds->index)
+			continue;
+
+		if (sw->drv->cross_chip_bridge)
+			sw->drv->cross_chip_bridge(sw, ds->index, p->port,
+						   p->bridge_dev);
+	}
+}
+
+static void dsa_tree_broadcast_bridge(struct dsa_switch_tree *dst,
+				      struct net_device *bridge)
+{
+	struct net_device *dev;
+	struct dsa_slave_priv *p;
+	struct dsa_switch *ds;
+	int chip, port;
+
+	for (chip = 0; chip < dst->pd->nr_chips; ++chip) {
+		ds = dst->ds[chip];
+
+		for (port = 0; port < DSA_MAX_PORTS; ++port) {
+			if (!ds->ports[port])
+				continue;
+
+			dev = ds->ports[port];
+			p = netdev_priv(dev);
+
+			if (p->bridge_dev == bridge)
+				dsa_slave_broadcast_bridge(dev);
+		}
+	}
+}
+
 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;
-	int ret = -EOPNOTSUPP;
+	int err;
 
 	p->bridge_dev = br;
 
-	if (ds->drv->port_bridge_join)
-		ret = ds->drv->port_bridge_join(ds, p->port, br);
+	/* In-chip hardware bridging */
+	if (ds->drv->port_bridge_join) {
+		err = ds->drv->port_bridge_join(ds, p->port, br);
+		if (err && err != -EOPNOTSUPP)
+			return err;
+	}
+
+	/* Broadcast bridge membership across chips */
+	dsa_tree_broadcast_bridge(ds->dst, br);
 
-	return ret == -EOPNOTSUPP ? 0 : ret;
+	return 0;
 }
 
 static void dsa_slave_bridge_port_leave(struct net_device *dev)
@@ -462,6 +511,9 @@ static void dsa_slave_bridge_port_leave(struct net_device *dev)
 	 */
 	if (ds->drv->port_stp_state_set)
 		ds->drv->port_stp_state_set(ds, p->port, BR_STATE_FORWARDING);
+
+	/* Notify the port leaving to other chips */
+	dsa_slave_broadcast_bridge(dev);
 }
 
 static int dsa_slave_port_attr_get(struct net_device *dev,
-- 
2.8.0

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

* [RFC 2/3] net: dsa: mv88e6xxx: initialize PVT
  2016-04-20 20:26 [RFC 0/3] net: dsa: cross-chip operations Vivien Didelot
  2016-04-20 20:26 ` [RFC 1/3] net: dsa: add cross-chip notification for bridge Vivien Didelot
@ 2016-04-20 20:26 ` Vivien Didelot
  2016-04-20 20:26 ` [RFC 3/3] net: dsa: mv88e6xxx: setup PVT Vivien Didelot
  2 siblings, 0 replies; 4+ messages in thread
From: Vivien Didelot @ 2016-04-20 20:26 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Expand the Cross-chip Port Based VLAN Table initilization code, and make
sure the "5 Bit Port" bit is cleared.

This commit doesn't make any functional change to the current code.

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

diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 1dd525d..e35bc9f 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -2203,6 +2203,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 external frame to egress any internal port */
+	return _mv88e6xxx_pvt_cmd(ds, 0, 0, GLOBAL2_PVT_ADDR_OP_INIT_ONES);
+}
+
 int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
 			       struct net_device *bridge)
 {
@@ -2747,11 +2788,8 @@ 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);
+		/* Initialize Cross-chip Port VLAN Table (PVT) */
+		err = _mv88e6xxx_pvt_init(ds);
 		if (err)
 			goto unlock;
 
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 0dbe2d1..dd63377 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,6 +339,7 @@
 #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
 
-- 
2.8.0

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

* [RFC 3/3] net: dsa: mv88e6xxx: setup PVT
  2016-04-20 20:26 [RFC 0/3] net: dsa: cross-chip operations Vivien Didelot
  2016-04-20 20:26 ` [RFC 1/3] net: dsa: add cross-chip notification for bridge Vivien Didelot
  2016-04-20 20:26 ` [RFC 2/3] net: dsa: mv88e6xxx: initialize PVT Vivien Didelot
@ 2016-04-20 20:26 ` Vivien Didelot
  2 siblings, 0 replies; 4+ messages in thread
From: Vivien Didelot @ 2016-04-20 20:26 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Vivien Didelot

Instead of allowing any external frame to egress any internal port,
configure the Cross-chip Port VLAN Table (PVT) to forbid that.

When an external source port joins or leaves a bridge crossing this
switch, mask it in the PVT to allow or forbid frames to egress.

Add support for the cross-chip bridge notification to the 6352 family.

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

diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c
index 4afc24d..03ab309 100644
--- a/drivers/net/dsa/mv88e6352.c
+++ b/drivers/net/dsa/mv88e6352.c
@@ -364,6 +364,7 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
 	.port_fdb_add		= mv88e6xxx_port_fdb_add,
 	.port_fdb_del		= mv88e6xxx_port_fdb_del,
 	.port_fdb_dump		= mv88e6xxx_port_fdb_dump,
+	.cross_chip_bridge	= mv88e6xxx_cross_chip_bridge,
 };
 
 MODULE_ALIAS("platform:mv88e6172");
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index e35bc9f..dccefdb 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -481,6 +481,14 @@ static bool mv88e6xxx_has_stu(struct dsa_switch *ds)
 	return false;
 }
 
+static bool mv88e6xxx_has_pvt(struct dsa_switch *ds)
+{
+	if (mv88e6xxx_6185_family(ds))
+		return false;
+
+	return true;
+}
+
 /* We expect the switch to perform auto negotiation if there is a real
  * phy. However, in the case of a fixed link phy, we force the port
  * settings from the fixed link settings.
@@ -2228,8 +2236,69 @@ static int _mv88e6xxx_pvt_cmd(struct dsa_switch *ds, int src_dev, int src_port,
 	return _mv88e6xxx_pvt_wait(ds);
 }
 
+static int _mv88e6xxx_pvt_read(struct dsa_switch *ds, int src_dev, int src_port,
+			       u16 *data)
+{
+	int ret;
+
+	ret = _mv88e6xxx_pvt_wait(ds);
+	if (ret < 0)
+		return ret;
+
+	ret = _mv88e6xxx_pvt_cmd(ds, src_dev, src_port,
+				GLOBAL2_PVT_ADDR_OP_READ);
+	if (ret < 0)
+		return ret;
+
+	ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_PVT_DATA);
+	if (ret < 0)
+		return ret;
+
+	*data = ret;
+
+	return 0;
+}
+
+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_map(struct dsa_switch *ds, int src_dev, int src_port,
+			      struct net_device *bridge)
+{
+	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+	u16 pvlan = 0;
+	int port;
+
+	for (port = 0; port < ps->info->num_ports; ++port) {
+		/* Frames from external ports can egress DSA and CPU ports */
+		if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
+			pvlan |= BIT(port);
+
+		/* Frames can egress bridge group members */
+		if (bridge && ps->ports[port].bridge_dev == bridge)
+			pvlan |= BIT(port);
+	}
+
+	return _mv88e6xxx_pvt_write(ds, src_dev, src_port, pvlan);
+}
+
 static int _mv88e6xxx_pvt_init(struct dsa_switch *ds)
 {
+	int src_dev, src_port;
 	int err;
 
 	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
@@ -2240,8 +2309,21 @@ static int _mv88e6xxx_pvt_init(struct dsa_switch *ds)
 	if (err)
 		return err;
 
-	/* Allow any external frame to egress any internal port */
-	return _mv88e6xxx_pvt_cmd(ds, 0, 0, GLOBAL2_PVT_ADDR_OP_INIT_ONES);
+	/* Forbid every port of potential neighbor switches to egress frames on
+	 * the normal ports of this switch.
+	 */
+	for (src_dev = 0; src_dev < 32; ++src_dev) {
+		if (src_dev == ds->index)
+			continue;
+
+		for (src_port = 0; src_port < 16; ++src_port) {
+			err = _mv88e6xxx_pvt_map(ds, src_dev, src_port, NULL);
+			if (err)
+				return err;
+		}
+	}
+
+	return 0;
 }
 
 int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
@@ -2286,6 +2368,35 @@ unlock:
 	return err;
 }
 
+static int _mv88e6xxx_pvt_unmap_local(struct dsa_switch *ds, int port)
+{
+	u16 pvlan;
+	int src_dev, src_port, err;
+
+	for (src_dev = 0; src_dev < 32; ++src_dev) {
+		if (src_dev == ds->index)
+			continue;
+
+		for (src_port = 0; src_port < 16; ++src_port) {
+			err = _mv88e6xxx_pvt_read(ds, src_dev, src_port,
+						  &pvlan);
+			if (err)
+				return err;
+
+			/* Forbid external normal frames to egress this port */
+			if (pvlan & BIT(port)) {
+				err = _mv88e6xxx_pvt_write(ds, src_dev,
+							   src_port,
+							   pvlan & ~BIT(port));
+				if (err)
+					return err;
+			}
+		}
+	}
+
+	return 0;
+}
+
 void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
@@ -2308,6 +2419,28 @@ void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
 			if (_mv88e6xxx_port_based_vlan_map(ds, i))
 				netdev_warn(ds->ports[i], "failed to remap\n");
 
+	if (mv88e6xxx_has_pvt(ds) && _mv88e6xxx_pvt_unmap_local(ds, port))
+		netdev_err(ds->ports[port], "failed to unmap\n");
+
+	mutex_unlock(&ps->smi_mutex);
+}
+
+void mv88e6xxx_cross_chip_bridge(struct dsa_switch *ds, int sw_index,
+				 int sw_port, struct net_device *bridge)
+{
+	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+
+	if (!mv88e6xxx_has_pvt(ds))
+		return;
+
+	/* Update the Cross-chip Port VLAN Table (PVT) entry for this external
+	 * source port to map which internal ports frames are allowed to egress.
+	 */
+
+	mutex_lock(&ps->smi_mutex);
+	if (_mv88e6xxx_pvt_map(ds, sw_index, sw_port, bridge))
+		dev_err(ds->master_dev, "failed to access PVT for sw%dp%d\n",
+			sw_index, sw_port);
 	mutex_unlock(&ps->smi_mutex);
 }
 
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index dd63377..ea214f2 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -523,6 +523,8 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
 int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
 			    struct switchdev_obj_port_fdb *fdb,
 			    int (*cb)(struct switchdev_obj *obj));
+void mv88e6xxx_cross_chip_bridge(struct dsa_switch *ds, int sw_index,
+				 int sw_port, struct net_device *bridge);
 int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg);
 int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
 			     int reg, int val);
-- 
2.8.0

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

end of thread, other threads:[~2016-04-20 20:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-20 20:26 [RFC 0/3] net: dsa: cross-chip operations Vivien Didelot
2016-04-20 20:26 ` [RFC 1/3] net: dsa: add cross-chip notification for bridge Vivien Didelot
2016-04-20 20:26 ` [RFC 2/3] net: dsa: mv88e6xxx: initialize PVT Vivien Didelot
2016-04-20 20:26 ` [RFC 3/3] net: dsa: mv88e6xxx: setup PVT 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).