From 7b18b787450759f1c2507c7b65c81c3686040c90 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Wed, 27 Mar 2024 15:52:43 +0100
Subject: [PATCH 02/27] net: dsa: mv88e6xxx: Improve indirect register access
 perf on 6393
Organization: Wires

When operating in multi-chip mode, the 6393 family maps a subset of
commonly used global registers to the outermost address space (in
which only the SMI command and data registers were available in
previous families).

Therefore, add a new set of SMI operations which remaps accesses to
such registers to the corresponding directly addressable register. All
other accesses use the regular indirect interface.
---
 drivers/net/dsa/mv88e6xxx/chip.c    |  7 +++
 drivers/net/dsa/mv88e6xxx/global1.h |  3 ++
 drivers/net/dsa/mv88e6xxx/global2.h |  3 ++
 drivers/net/dsa/mv88e6xxx/smi.c     | 76 +++++++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx/smi.h     | 30 ++++++++++++
 5 files changed, 119 insertions(+)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index d64c3eef4447..47138492885e 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -6539,6 +6539,13 @@ static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
 	/* Update the compatible info with the probed one */
 	chip->info = info;
 
+	/* Now that we know the exact chip in use, we might be able to
+	 * make use of more efficient SMI operations
+	 */
+	err = mv88e6xxx_smi_init(chip, chip->bus, chip->sw_addr);
+	if (err)
+		return err;
+
 	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
 		 chip->info->prod_num, chip->info->name, rev);
 
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 3dbb7a1b8fe1..5ea956aadecc 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -218,6 +218,9 @@
 #define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST_MGMTPRI	0x00e0
 #define MV88E6390_G1_MONITOR_MGMT_CTL_DATA_MASK			0x00ff
 
+/* Offset 0x1B: Free Queue Size Register */
+#define MV88E6XXX_G1_FREE_Q_SIZE		0x1b
+
 /* Offset 0x1C: Global Control 2 */
 #define MV88E6XXX_G1_CTL2			0x1c
 #define MV88E6185_G1_CTL2_CASCADE_PORT_MASK	0xf000
diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h
index 82f9b410de0b..3663645621c9 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.h
+++ b/drivers/net/dsa/mv88e6xxx/global2.h
@@ -143,6 +143,9 @@
 #define MV88E6XXX_G2_PRIO_OVERRIDE_QFPRIEN	0x0008
 #define MV88E6XXX_G2_PRIO_OVERRIDE_DATA_MASK	0x0007
 
+/* Offset 0x13: IMP Communication/Debug Register */
+#define MV88E6390_G2_IMP_COMM			0x13
+
 /* Offset 0x14: EEPROM Command */
 #define MV88E6XXX_G2_EEPROM_CMD			0x14
 #define MV88E6XXX_G2_EEPROM_CMD_BUSY		0x8000
diff --git a/drivers/net/dsa/mv88e6xxx/smi.c b/drivers/net/dsa/mv88e6xxx/smi.c
index a990271b7482..f54bb0e79030 100644
--- a/drivers/net/dsa/mv88e6xxx/smi.c
+++ b/drivers/net/dsa/mv88e6xxx/smi.c
@@ -8,6 +8,8 @@
  */
 
 #include "chip.h"
+#include "global1.h"
+#include "global2.h"
 #include "smi.h"
 
 /* The switch ADDR[4:1] configuration pins define the chip SMI device address
@@ -168,6 +170,78 @@ static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_indirect_ops = {
 	.init = mv88e6xxx_smi_indirect_init,
 };
 
+static u8 mv88e6393_smi_indirect_remap(int dev, int reg)
+{
+	static const u8 g1_remap[32] = {
+		[MV88E6352_G1_VTU_FID] = MV88E6393_SMI_G1_VTU_FID,
+		[MV88E6352_G1_VTU_SID] = MV88E6393_SMI_G1_VTU_SID,
+		[MV88E6XXX_G1_STS] = MV88E6393_SMI_G1_STS,
+		[MV88E6XXX_G1_VTU_OP] = MV88E6393_SMI_G1_VTU_OP,
+		[MV88E6XXX_G1_VTU_VID] = MV88E6393_SMI_G1_VTU_VID,
+		[MV88E6XXX_G1_VTU_DATA1] = MV88E6393_SMI_G1_VTU_DATA1,
+		[MV88E6XXX_G1_VTU_DATA2] = MV88E6393_SMI_G1_VTU_DATA2,
+		[MV88E6352_G1_ATU_FID] = MV88E6393_SMI_G1_ATU_FID,
+		[MV88E6XXX_G1_ATU_CTL] = MV88E6393_SMI_G1_ATU_CTL,
+		[MV88E6XXX_G1_ATU_OP] = MV88E6393_SMI_G1_ATU_OP,
+		[MV88E6XXX_G1_ATU_DATA] = MV88E6393_SMI_G1_ATU_DATA,
+		[MV88E6XXX_G1_ATU_MAC01] = MV88E6393_SMI_G1_ATU_MAC01,
+		[MV88E6XXX_G1_ATU_MAC23] = MV88E6393_SMI_G1_ATU_MAC23,
+		[MV88E6XXX_G1_ATU_MAC45] = MV88E6393_SMI_G1_ATU_MAC45,
+		[MV88E6XXX_G1_FREE_Q_SIZE] = MV88E6393_SMI_G1_FREE_Q_SIZE,
+		[MV88E6XXX_G1_STATS_OP] = MV88E6393_SMI_G1_STATS_OP,
+		[MV88E6XXX_G1_STATS_COUNTER_32] = MV88E6393_SMI_G1_STATS_COUNTER_32,
+		[MV88E6XXX_G1_STATS_COUNTER_01] = MV88E6393_SMI_G1_STATS_COUNTER_01,
+	};
+
+	static const u8 g2_remap[32] = {
+		[MV88E6390_G2_IMP_COMM] = MV88E6393_SMI_G2_IMP_COMM,
+		[MV88E6352_G2_AVB_CMD] = MV88E6393_SMI_G2_AVB_CMD,
+		[MV88E6352_G2_AVB_DATA] = MV88E6393_SMI_G2_AVB_DATA,
+		[MV88E6XXX_G2_SMI_PHY_CMD] = MV88E6393_SMI_G2_SMI_PHY_CMD,
+		[MV88E6XXX_G2_SMI_PHY_DATA] = MV88E6393_SMI_G2_SMI_PHY_DATA,
+		[MV88E6393X_G2_MACLINK_INT_SRC] = MV88E6393_SMI_G2_MACLINK_INT_SRC,
+	};
+
+	switch (dev) {
+	case 0x1b:
+		return g1_remap[reg];
+	case 0x1c:
+		return g2_remap[reg];
+	}
+
+	return 0;
+}
+
+static int mv88e6393_smi_indirect_read(struct mv88e6xxx_chip *chip,
+				       int dev, int reg, u16 *data)
+{
+	u8 remap = mv88e6393_smi_indirect_remap(dev, reg);
+
+	if (remap)
+		return mv88e6xxx_smi_direct_read(chip, chip->sw_addr,
+						 remap, data);
+
+	return mv88e6xxx_smi_indirect_read(chip, dev, reg, data);
+}
+
+static int mv88e6393_smi_indirect_write(struct mv88e6xxx_chip *chip,
+					int dev, int reg, u16 data)
+{
+	u8 remap = mv88e6393_smi_indirect_remap(dev, reg);
+
+	if (remap)
+		return mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
+						  remap, data);
+
+	return mv88e6xxx_smi_indirect_write(chip, dev, reg, data);
+}
+
+static const struct mv88e6xxx_bus_ops mv88e6393_smi_indirect_ops = {
+	.read = mv88e6393_smi_indirect_read,
+	.write = mv88e6393_smi_indirect_write,
+	.init = mv88e6xxx_smi_indirect_init,
+};
+
 int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
 		       struct mii_bus *bus, int sw_addr)
 {
@@ -175,6 +249,8 @@ int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
 		chip->smi_ops = &mv88e6xxx_smi_dual_direct_ops;
 	else if (sw_addr == 0)
 		chip->smi_ops = &mv88e6xxx_smi_direct_ops;
+	else if (chip->info->family == MV88E6XXX_FAMILY_6393)
+		chip->smi_ops = &mv88e6393_smi_indirect_ops;
 	else if (chip->info->multi_chip)
 		chip->smi_ops = &mv88e6xxx_smi_indirect_ops;
 	else
diff --git a/drivers/net/dsa/mv88e6xxx/smi.h b/drivers/net/dsa/mv88e6xxx/smi.h
index c6c71d5757f5..788cf68b7b33 100644
--- a/drivers/net/dsa/mv88e6xxx/smi.h
+++ b/drivers/net/dsa/mv88e6xxx/smi.h
@@ -31,6 +31,36 @@
 /* Offset 0x01: SMI Data Register */
 #define MV88E6XXX_SMI_DATA			0x01
 
+/* When using the 6393 in indirect addressing mode, a subset of the
+ * most commonly used registers are directly mapped out to the chip's
+ * top address space, allowing them to be directly accessed.
+ */
+#define MV88E6393_SMI_G1_VTU_FID		0x02
+#define MV88E6393_SMI_G1_VTU_SID		0x03
+#define MV88E6393_SMI_G1_STS			0x04
+#define MV88E6393_SMI_G1_VTU_OP			0x05
+#define MV88E6393_SMI_G1_VTU_VID		0x06
+#define MV88E6393_SMI_G1_VTU_DATA1		0x07
+#define MV88E6393_SMI_G1_VTU_DATA2		0x08
+#define MV88E6393_SMI_G1_ATU_FID		0x09
+#define MV88E6393_SMI_G1_ATU_CTL		0x0a
+#define MV88E6393_SMI_G1_ATU_OP			0x0b
+#define MV88E6393_SMI_G1_ATU_DATA		0x0c
+#define MV88E6393_SMI_G1_ATU_MAC01		0x0d
+#define MV88E6393_SMI_G1_ATU_MAC23		0x0e
+#define MV88E6393_SMI_G1_ATU_MAC45		0x0f
+#define MV88E6393_SMI_G2_IMP_COMM		0x13
+#define MV88E6393_SMI_G2_AVB_CMD		0x16
+#define MV88E6393_SMI_G2_AVB_DATA		0x17
+#define MV88E6393_SMI_G2_SMI_PHY_CMD		0x18
+#define MV88E6393_SMI_G2_SMI_PHY_DATA		0x19
+#define MV88E6393_SMI_G2_MACLINK_INT_SRC	0x1a
+#define MV88E6393_SMI_G1_FREE_Q_SIZE		0x1b
+#define MV88E6393_SMI_G1_STATS_OP		0x1d
+#define MV88E6393_SMI_G1_STATS_COUNTER_32	0x1e
+#define MV88E6393_SMI_G1_STATS_COUNTER_01	0x1f
+
+
 int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
 		       struct mii_bus *bus, int sw_addr);
 
