@@ -43,6 +43,12 @@
#include "serdes.h"
#include "smi.h"
+struct mv88e6xxx_bridge {
+ struct list_head head;
+ struct net_device *br_dev;
+ u16 ports;
+};
+
static void assert_reg_lock(struct mv88e6xxx_chip *chip)
{
if (unlikely(!mutex_is_locked(&chip->reg_lock))) {
@@ -2958,6 +2964,60 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
return err;
}
+static struct mv88e6xxx_bridge *
+mv88e6xxx_bridge_create(struct mv88e6xxx_chip *chip, struct net_device *br_dev)
+{
+ struct mv88e6xxx_bridge *mv_bridge;
+
+ mv_bridge = kzalloc(sizeof(*mv_bridge), GFP_KERNEL);
+ if (!mv_bridge)
+ return ERR_PTR(-ENOMEM);
+
+ mv_bridge->br_dev = br_dev;
+ list_add(&mv_bridge->head, &chip->bridge_list);
+
+ return mv_bridge;
+}
+
+static void mv88e6xxx_bridge_destroy(struct mv88e6xxx_bridge *mv_bridge)
+{
+ list_del(&mv_bridge->head);
+
+ WARN_ON(mv_bridge->ports);
+ kfree(mv_bridge);
+}
+
+static
+struct mv88e6xxx_bridge *mv88e6xxx_bridge_by_dev(struct mv88e6xxx_chip *chip,
+ const struct net_device *br_dev)
+{
+ struct mv88e6xxx_bridge *mv_bridge;
+
+ list_for_each_entry(mv_bridge, &chip->bridge_list, head)
+ if (mv_bridge->br_dev == br_dev)
+ return mv_bridge;
+
+ return NULL;
+}
+
+static struct mv88e6xxx_bridge *
+mv88e6xxx_bridge_get(struct mv88e6xxx_chip *chip, struct net_device *br_dev)
+{
+ struct mv88e6xxx_bridge *mv_bridge;
+
+ mv_bridge = mv88e6xxx_bridge_by_dev(chip, br_dev);
+ if (!mv_bridge)
+ mv_bridge = mv88e6xxx_bridge_create(chip, br_dev);
+
+ return mv_bridge;
+}
+
+static void mv88e6xxx_bridge_put(struct mv88e6xxx_bridge *mv_bridge)
+{
+ if (!mv_bridge->ports)
+ mv88e6xxx_bridge_destroy(mv_bridge);
+}
+
static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
struct dsa_bridge bridge)
{
@@ -3009,8 +3069,16 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
struct netlink_ext_ack *extack)
{
struct mv88e6xxx_chip *chip = ds->priv;
+ struct mv88e6xxx_bridge *mv_bridge;
int err;
+ mv_bridge = mv88e6xxx_bridge_get(chip, bridge.dev);
+ if (IS_ERR(mv_bridge))
+ return PTR_ERR(mv_bridge);
+
+ if (mv_bridge->ports & BIT(port))
+ return -EEXIST;
+
mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_bridge_map(chip, bridge);
@@ -3033,6 +3101,8 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
*tx_fwd_offload = true;
}
+ mv_bridge->ports |= BIT(port);
+
unlock:
mv88e6xxx_reg_unlock(chip);
@@ -3043,8 +3113,19 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
struct dsa_bridge bridge)
{
struct mv88e6xxx_chip *chip = ds->priv;
+ struct mv88e6xxx_bridge *mv_bridge;
int err;
+ mv_bridge = mv88e6xxx_bridge_by_dev(chip, bridge.dev);
+ if (!mv_bridge)
+ return;
+
+ if (!(mv_bridge->ports & BIT(port)))
+ return;
+
+ mv_bridge->ports &= ~BIT(port);
+ mv88e6xxx_bridge_put(mv_bridge);
+
mv88e6xxx_reg_lock(chip);
if (bridge.tx_fwd_offload &&
@@ -6436,6 +6517,7 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
INIT_LIST_HEAD(&chip->mdios);
idr_init(&chip->policies);
INIT_LIST_HEAD(&chip->msts);
+ INIT_LIST_HEAD(&chip->bridge_list);
return chip;
}
@@ -7272,6 +7354,9 @@ static void mv88e6xxx_remove(struct mdio_device *mdiodev)
mv88e6xxx_g1_irq_free(chip);
else
mv88e6xxx_irq_poll_free(chip);
+
+ WARN_ON(!list_empty(&chip->bridge_list));
+
}
static void mv88e6xxx_shutdown(struct mdio_device *mdiodev)
@@ -432,6 +432,9 @@ struct mv88e6xxx_chip {
/* Bridge MST to SID mappings */
struct list_head msts;
+
+ /* software bridges */
+ struct list_head bridge_list;
};
struct mv88e6xxx_bus_ops {
Keep track of soft bridge objects in the driver. Since the driver doesn't get explicit notifications about bridge creation or destruction, just create the bridge data structure when the first port joins the bridge via mv88e6xxx_port_bridge_join(). Similarly, destroy the bridge after the last port left the bridge via mv88e6xxx_port_bridge_leave(). Use the bridge's net_device pointer as the key to the list. Port information is stored in a bitmask. Signed-off-by: Joseph Huang <Joseph.Huang@garmin.com> --- drivers/net/dsa/mv88e6xxx/chip.c | 85 ++++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/chip.h | 3 ++ 2 files changed, 88 insertions(+)