diff mbox series

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

Message ID 20240402001137.2980589-7-Joseph.Huang@garmin.com (mailing list archive)
State RFC
Delegated to: Netdev Maintainers
Headers show
Series MC Flood disable and snooping | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 943 this patch: 943
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 7 of 7 maintainers
netdev/build_clang success Errors and warnings before: 954 this patch: 954
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 954 this patch: 954
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Joseph Huang April 2, 2024, 12:11 a.m. UTC
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(+)
diff mbox series

Patch

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 {