[PATCH RFC net-next 06/10] net: dsa: mv88e6xxx: Track soft bridge objects

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
---
 drivers/net/dsa/mv88e6xxx/chip.c | 85 ++++++++++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx/chip.h |  3 ++
 2 files changed, 88 insertions(+)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index fddcb596c421..f66ddde484dc 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -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)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 85eb293381a7..a32e4564eb3d 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -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 {
-- 
2.17.1





[Index of Archives]     [Netdev]     [AoE Tools]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]     [Video 4 Linux]

  Powered by Linux