diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.c | 16 | ||||
-rw-r--r-- | drivers/net/dsa/sja1105/sja1105.h | 2 | ||||
-rw-r--r-- | drivers/net/dsa/sja1105/sja1105_main.c | 90 |
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); |