summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c16
-rw-r--r--drivers/net/dsa/sja1105/sja1105.h2
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c90
3 files changed, 104 insertions, 4 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 2b4a723c8306..7627ea61e0ea 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2233,26 +2233,34 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
mv88e6xxx_reg_unlock(chip);
}
-static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
+static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds,
+ int tree_index, int sw_index,
int port, struct net_device *br)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;
+ if (tree_index != ds->dst->index)
+ return 0;
+
mv88e6xxx_reg_lock(chip);
- err = mv88e6xxx_pvt_map(chip, dev, port);
+ err = mv88e6xxx_pvt_map(chip, sw_index, port);
mv88e6xxx_reg_unlock(chip);
return err;
}
-static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev,
+static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds,
+ int tree_index, int sw_index,
int port, struct net_device *br)
{
struct mv88e6xxx_chip *chip = ds->priv;
+ if (tree_index != ds->dst->index)
+ return;
+
mv88e6xxx_reg_lock(chip);
- if (mv88e6xxx_pvt_map(chip, dev, port))
+ if (mv88e6xxx_pvt_map(chip, sw_index, port))
dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
mv88e6xxx_reg_unlock(chip);
}
diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h
index 8df2a5c53b02..a64ace07b89f 100644
--- a/drivers/net/dsa/sja1105/sja1105.h
+++ b/drivers/net/dsa/sja1105/sja1105.h
@@ -8,6 +8,7 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/timecounter.h>
#include <linux/dsa/sja1105.h>
+#include <linux/dsa/8021q.h>
#include <net/dsa.h>
#include <linux/mutex.h>
#include "sja1105_static_config.h"
@@ -185,6 +186,7 @@ struct sja1105_private {
struct gpio_desc *reset_gpio;
struct spi_device *spidev;
struct dsa_switch *ds;
+ struct list_head crosschip_links;
struct sja1105_flow_block flow_block;
struct sja1105_port ports[SJA1105_NUM_PORTS];
/* Serializes transmission of management frames so that
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 666e54565df0..d5de9305df25 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -25,6 +25,8 @@
#include "sja1105_sgmii.h"
#include "sja1105_tas.h"
+static const struct dsa_switch_ops sja1105_switch_ops;
+
static void sja1105_hw_reset(struct gpio_desc *gpio, unsigned int pulse_len,
unsigned int startup_delay)
{
@@ -1791,6 +1793,84 @@ static int sja1105_vlan_apply(struct sja1105_private *priv, int port, u16 vid,
return 0;
}
+static int sja1105_crosschip_bridge_join(struct dsa_switch *ds,
+ int tree_index, int sw_index,
+ int other_port, struct net_device *br)
+{
+ struct dsa_switch *other_ds = dsa_switch_find(tree_index, sw_index);
+ struct sja1105_private *other_priv = other_ds->priv;
+ struct sja1105_private *priv = ds->priv;
+ int port, rc;
+
+ if (other_ds->ops != &sja1105_switch_ops)
+ return 0;
+
+ for (port = 0; port < ds->num_ports; port++) {
+ if (!dsa_is_user_port(ds, port))
+ continue;
+ if (dsa_to_port(ds, port)->bridge_dev != br)
+ continue;
+
+ rc = dsa_8021q_crosschip_bridge_join(ds, port, other_ds,
+ other_port, br,
+ &priv->crosschip_links);
+ if (rc)
+ return rc;
+
+ rc = dsa_8021q_crosschip_bridge_join(other_ds, other_port, ds,
+ port, br,
+ &other_priv->crosschip_links);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static void sja1105_crosschip_bridge_leave(struct dsa_switch *ds,
+ int tree_index, int sw_index,
+ int other_port,
+ struct net_device *br)
+{
+ struct dsa_switch *other_ds = dsa_switch_find(tree_index, sw_index);
+ struct sja1105_private *other_priv = other_ds->priv;
+ struct sja1105_private *priv = ds->priv;
+ int port;
+
+ if (other_ds->ops != &sja1105_switch_ops)
+ return;
+
+ for (port = 0; port < ds->num_ports; port++) {
+ if (!dsa_is_user_port(ds, port))
+ continue;
+ if (dsa_to_port(ds, port)->bridge_dev != br)
+ continue;
+
+ dsa_8021q_crosschip_bridge_leave(ds, port, other_ds, other_port,
+ br, &priv->crosschip_links);
+
+ dsa_8021q_crosschip_bridge_leave(other_ds, other_port, ds,
+ port, br,
+ &other_priv->crosschip_links);
+ }
+}
+
+static int sja1105_replay_crosschip_vlans(struct dsa_switch *ds, bool enabled)
+{
+ struct sja1105_private *priv = ds->priv;
+ struct dsa_8021q_crosschip_link *c;
+ int rc;
+
+ list_for_each_entry(c, &priv->crosschip_links, list) {
+ rc = dsa_8021q_crosschip_link_apply(ds, c->port, c->other_ds,
+ c->other_port, enabled);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
static int sja1105_setup_8021q_tagging(struct dsa_switch *ds, bool enabled)
{
int rc, i;
@@ -1803,6 +1883,12 @@ static int sja1105_setup_8021q_tagging(struct dsa_switch *ds, bool enabled)
return rc;
}
}
+ rc = sja1105_replay_crosschip_vlans(ds, enabled);
+ if (rc) {
+ dev_err(ds->dev, "Failed to replay crosschip VLANs: %d\n", rc);
+ return rc;
+ }
+
dev_info(ds->dev, "%s switch tagging\n",
enabled ? "Enabled" : "Disabled");
return 0;
@@ -2370,6 +2456,8 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
.cls_flower_add = sja1105_cls_flower_add,
.cls_flower_del = sja1105_cls_flower_del,
.cls_flower_stats = sja1105_cls_flower_stats,
+ .crosschip_bridge_join = sja1105_crosschip_bridge_join,
+ .crosschip_bridge_leave = sja1105_crosschip_bridge_leave,
};
static int sja1105_check_device_id(struct sja1105_private *priv)
@@ -2472,6 +2560,8 @@ static int sja1105_probe(struct spi_device *spi)
mutex_init(&priv->ptp_data.lock);
mutex_init(&priv->mgmt_lock);
+ INIT_LIST_HEAD(&priv->crosschip_links);
+
sja1105_tas_setup(ds);
sja1105_flower_setup(ds);