Thread (27 messages) 27 messages, 3 authors, 11d ago
COOLING11d

[PATCH net-next 17/17] net: dsa: mv88e6xxx: RMU DUMP_ATU support in devlink

From: Luke Howard <hidden>
Date: 2026-07-03 07:48:01
Also in: lkml
Subsystem: marvell 88e6xxx ethernet switch fabric driver, networking drivers, networking [dsa], the rest · Maintainers: Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Vladimir Oltean, Linus Torvalds

Support reading an ATU snapshot in a single RMU request.

Signed-off-by: Luke Howard <redacted>
---
 drivers/net/dsa/mv88e6xxx/chip.h    | 10 +++++
 drivers/net/dsa/mv88e6xxx/devlink.c | 67 ++++++++++++++++++++++---------
 drivers/net/dsa/mv88e6xxx/rmu.c     | 78 +++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx/rmu.h     | 35 +++++++++++++++++
 4 files changed, 171 insertions(+), 19 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index fdc87d02469b5..7bbb649330d55 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -205,6 +205,16 @@ struct mv88e6xxx_stu_entry {
 	u8	state[DSA_MAX_PORTS];
 };
 
+struct mv88e6xxx_devlink_atu_entry {
+	/* The FID is scattered over multiple registers. */
+	u16 fid;
+	u16 atu_op;
+	u16 atu_data;
+	u16 atu_01;
+	u16 atu_23;
+	u16 atu_45;
+};
+
 struct mv88e6xxx_bus_ops;
 struct mv88e6xxx_irq_ops;
 struct mv88e6xxx_gpio_ops;
diff --git a/drivers/net/dsa/mv88e6xxx/devlink.c b/drivers/net/dsa/mv88e6xxx/devlink.c
index 6d7da381f9f38..5c2a59d1145b8 100644
--- a/drivers/net/dsa/mv88e6xxx/devlink.c
+++ b/drivers/net/dsa/mv88e6xxx/devlink.c
@@ -6,6 +6,7 @@
 #include "global1.h"
 #include "global2.h"
 #include "port.h"
+#include "rmu.h"
 
 static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
 {
@@ -307,16 +308,6 @@ static int mv88e6xxx_region_global_snapshot(struct devlink *dl,
  * mv88e6xxx generations
  */
 
-struct mv88e6xxx_devlink_atu_entry {
-	/* The FID is scattered over multiple registers. */
-	u16 fid;
-	u16 atu_op;
-	u16 atu_data;
-	u16 atu_01;
-	u16 atu_23;
-	u16 atu_45;
-};
-
 static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,
 					     int fid,
 					     struct mv88e6xxx_devlink_atu_entry *table,
@@ -369,6 +360,33 @@ static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,
 	return 0;
 }
 
+static int mv88e6xxx_region_atu_snapshot_rmu(struct mv88e6xxx_chip *chip,
+					     struct mv88e6xxx_devlink_atu_entry *table,
+					     int *count)
+{
+	unsigned int num_macs = mv88e6xxx_num_macs(chip);
+	u16 cont_code = 0;
+	int err;
+
+	do {
+		if (*count + MV88E6XXX_RMU_MAX_ATU_ENTRIES > num_macs) {
+			err = -ERANGE;
+			break;
+		}
+
+		err = mv88e6xxx_rmu_dump_atu(chip, &table[*count], &cont_code);
+		if (err < 0)
+			break;
+
+		*count += err;
+	} while (cont_code != 0);
+
+	if (err < 0)
+		*count = 0;
+
+	return err;
+}
+
 static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
 					 const struct devlink_region_ops *ops,
 					 struct netlink_ext_ack *extack,
@@ -386,18 +404,29 @@ static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
 
 	mv88e6xxx_reg_lock(chip);
 
-	while (1) {
-		fid = find_next_bit(chip->fid_bitmap, MV88E6XXX_N_FID, fid + 1);
-		if (fid == MV88E6XXX_N_FID)
-			break;
+	err = mv88e6xxx_region_atu_snapshot_rmu(chip, table, &count);
+	if (err >= 0) {
+		/* RMU succeeded, use its results */
+		err = 0;
+	} else if (!mv88e6xxx_rmu_can_mdio_fallback(chip, err)) {
+		kfree(table);
+		goto out;
+	} else {
+		while (1) {
+			fid = find_next_bit(chip->fid_bitmap, MV88E6XXX_N_FID,
+					    fid + 1);
+			if (fid == MV88E6XXX_N_FID)
+				break;
 
-		err =  mv88e6xxx_region_atu_snapshot_fid(chip, fid, table,
-							 &count);
-		if (err) {
-			kfree(table);
-			goto out;
+			err =  mv88e6xxx_region_atu_snapshot_fid(chip, fid,
+								 table, &count);
+			if (err) {
+				kfree(table);
+				goto out;
+			}
 		}
 	}
+
 	*data = (u8 *)table;
 out:
 	mv88e6xxx_reg_unlock(chip);
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.c b/drivers/net/dsa/mv88e6xxx/rmu.c
index 5660372f41ad7..36422039030cd 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.c
+++ b/drivers/net/dsa/mv88e6xxx/rmu.c
@@ -106,6 +106,84 @@ static int mv88e6xxx_rmu_request(struct mv88e6xxx_chip *chip,
 				  resp, resp_len, timeout_ms);
 }
 
+int mv88e6xxx_rmu_dump_atu(struct mv88e6xxx_chip *chip,
+			   struct mv88e6xxx_devlink_atu_entry *entries,
+			   u16 *cont_code)
+{
+	__be16 req[] = {
+		MV88E6XXX_RMU_REQ_FORMAT_SOHO,
+		MV88E6XXX_RMU_REQ_PAD,
+		MV88E6XXX_RMU_REQ_CODE_ATU,
+		htons(*cont_code),
+	};
+	struct mv88e6xxx_rmu_atu_resp resp;
+	int resp_len, count;
+	int ret, i;
+
+	if (chip->rmu_state == MV88E6XXX_RMU_DISABLED)
+		return -EOPNOTSUPP;
+
+	resp_len = sizeof(resp);
+	ret = mv88e6xxx_rmu_request(chip, req, sizeof(req),
+				    &resp, resp_len,
+				    MV88E6XXX_RMU_REQUEST_TIMEOUT_MS);
+	if (ret < 0) {
+		dev_dbg(chip->dev, "RMU: error for command DUMP_ATU %pe\n",
+			ERR_PTR(ret));
+		return ret;
+	}
+
+	/* minimum packet length */
+	resp_len = sizeof(struct mv88e6xxx_rmu_header) + sizeof(__be16); /* cont_code */
+
+	if (ret < resp_len || (ret - resp_len) % sizeof(struct mv88e6xxx_rmu_atu_entry)) {
+		dev_err(chip->dev, "RMU: DUMP_ATU returned wrong length: rx %d expecting %zd\n",
+			ret, sizeof(resp));
+		return -EPROTO;
+	}
+
+	count = (ret - resp_len) / sizeof(struct mv88e6xxx_rmu_atu_entry);
+
+	if (resp.rmu_header.code != MV88E6XXX_RMU_RESP_CODE_ATU) {
+		dev_err(chip->dev, "RMU: DUMP_ATU returned wrong code %d\n",
+			be16_to_cpu(resp.rmu_header.code));
+		return -EPROTO;
+	}
+
+	for (i = 0; i < count; i++) {
+		const struct mv88e6xxx_rmu_atu_entry *src = &resp.entries[i];
+		struct mv88e6xxx_devlink_atu_entry *dst = &entries[i];
+		u16 tmp;
+
+		tmp = ntohs(src->state_trunk_dpv);
+		if (!MV88E6XXX_RMU_ATU_ENTRY_STATE_GET(tmp)) {
+			*cont_code = 0;
+			return i;
+		}
+
+		dst->atu_data = MV88E6XXX_RMU_ATU_ENTRY_STATE_GET(tmp) & 0xf;
+		if (tmp & MV88E6XXX_RMU_ATU_TRUNK)
+			dst->atu_data |= MV88E6XXX_G1_ATU_DATA_TRUNK;
+		dst->atu_data |= (MV88E6XXX_RMU_ATU_DPV_GET(tmp) &
+				  mv88e6xxx_port_mask(chip)) << 4;
+
+		tmp = ntohs(src->pri_fid);
+		dst->fid = MV88E6XXX_RMU_ATU_FID_GET(tmp);
+		dst->atu_op = MV88E6XXX_G1_ATU_OP_GET_NEXT_DB;
+
+		dst->atu_01 = ntohs(src->atu_01);
+		dst->atu_23 = ntohs(src->atu_23);
+		dst->atu_45 = ntohs(src->atu_45);
+	}
+
+	if (i == MV88E6XXX_RMU_MAX_ATU_ENTRIES)
+		*cont_code = ntohs(resp.cont_code);
+	else
+		*cont_code = 0;
+
+	return i;
+}
+
 int mv88e6xxx_rmu_stats(struct mv88e6xxx_chip *chip, int port,
 			u64 *data,
 			const struct mv88e6xxx_hw_stat *hw_stats,
diff --git a/drivers/net/dsa/mv88e6xxx/rmu.h b/drivers/net/dsa/mv88e6xxx/rmu.h
index 0865e899cb340..3a288ff3b113f 100644
--- a/drivers/net/dsa/mv88e6xxx/rmu.h
+++ b/drivers/net/dsa/mv88e6xxx/rmu.h
@@ -17,6 +17,7 @@
 #define MV88E6XXX_RMU_REQ_FORMAT_SOHO		htons(0x0001)
 #define MV88E6XXX_RMU_REQ_PAD			htons(0x0000)
 #define MV88E6XXX_RMU_REQ_CODE_GET_ID		htons(0x0000)
+#define MV88E6XXX_RMU_REQ_CODE_ATU		htons(0x1000)
 #define MV88E6XXX_RMU_REQ_CODE_MIB		htons(0x1020)
 #define MV88E6XXX_RMU_REQ_CODE_REG_RW		htons(0x2000)
 #define MV88E6XXX_RMU_REQ_DATA			htons(0x0000)
@@ -50,6 +51,7 @@
 #define MV88E6XXX_RMU_RESP_FORMAT_1		htons(0x0001)
 #define MV88E6XXX_RMU_RESP_FORMAT_2		htons(0x0002)
 #define MV88E6XXX_RMU_RESP_CODE_GOT_ID		htons(0x0000)
+#define MV88E6XXX_RMU_RESP_CODE_ATU		htons(0x1000)
 #define MV88E6XXX_RMU_RESP_CODE_MIB		htons(0x1020)
 #define MV88E6XXX_RMU_RESP_CODE_REG_RW		htons(0x2000)
 
@@ -67,6 +69,34 @@ struct mv88e6xxx_rmu_rw_resp {
 	__be16 end1;
 } __packed;
 
+struct mv88e6xxx_rmu_atu_entry {
+	__be16 state_trunk_dpv;
+	__be16 atu_01;
+	__be16 atu_23;
+	__be16 atu_45;
+	__be16 pri_fid;
+} __packed;
+
+#define MV88E6XXX_RMU_MAX_ATU_ENTRIES		48
+
+#define MV88E6XXX_RMU_ATU_ENTRY_STATE_MASK	GENMASK(15, 12)
+#define MV88E6XXX_RMU_ATU_ENTRY_STATE_GET(p)	FIELD_GET(MV88E6XXX_RMU_ATU_ENTRY_STATE_MASK, p)
+#define MV88E6XXX_RMU_ATU_TRUNK			0x0800
+#define MV88E6XXX_RMU_ATU_DPV_MASK		GENMASK(10, 0)
+#define MV88E6XXX_RMU_ATU_DPV_GET(p)		FIELD_GET(MV88E6XXX_RMU_ATU_DPV_MASK, p)
+
+#define MV88E6XXX_RMU_ATU_PRI_MASK		GENMASK(14, 12)
+#define MV88E6XXX_RMU_ATU_PRI_GET(p)		FIELD_GET(MV88E6XXX_RMU_ATU_PRI_MASK, p)
+
+#define MV88E6XXX_RMU_ATU_FID_MASK		GENMASK(11, 0)
+#define MV88E6XXX_RMU_ATU_FID_GET(p)		FIELD_GET(MV88E6XXX_RMU_ATU_FID_MASK, p)
+
+struct mv88e6xxx_rmu_atu_resp {
+	struct mv88e6xxx_rmu_header rmu_header;
+	struct mv88e6xxx_rmu_atu_entry entries[MV88E6XXX_RMU_MAX_ATU_ENTRIES];
+	__be16 cont_code;
+} __packed;
+
 /* number of RMU MIB statistics, by type, in octets */
 #define MV88E6XXX_RMU_STATS_TYPE_DATA0_LEN	128
 #define MV88E6XXX_RMU_STATS_TYPE_PORT_LEN	12
@@ -81,6 +111,11 @@ struct mv88e6xxx_rmu_mib_resp {
 	__be32 data[MV88E6XXX_RMU_STATS_TYPE_MAX_LEN / 4];
 } __packed;
 
+struct mv88e6xxx_devlink_atu_entry;
+
+int mv88e6xxx_rmu_dump_atu(struct mv88e6xxx_chip *chip,
+			   struct mv88e6xxx_devlink_atu_entry *entries,
+			   u16 *cont_code);
 int mv88e6xxx_rmu_stats(struct mv88e6xxx_chip *chip, int port,
 			u64 *data,
 			const struct mv88e6xxx_hw_stat *hw_stats,
-- 
2.43.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help