From 86deef6158befc7c47deb9ea1f7d521faf764ec5 Mon Sep 17 00:00:00 2001
From: Markus Stockhausen <markus.stockhausen@gmx.de>
Date: Thu, 22 Aug 2024 01:55:36 -0400
Subject: [PATCH] realtek: 6.6: change to current dsa structures

The DSA framework has changed a bit since 6.1, lets adapt to match.
Currently there is no one-patch-fits-all solution to directly fix
all errors up to 6.6. So cover the final differences with this
second patch.

Most notable upstream changes are:
  - a88dd7538461 ("net: dsa: remove legacy_pre_march2020 detection")
  - 53d04b981110 ("net: dsa: remove phylink_validate() method")

Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
[Minor checkpatch.pl cleanups]
Signed-off-by: Sander Vanheule <sander@svanheule.net>
---
 .../drivers/net/dsa/rtl83xx/common.c          |  21 +++-
 .../files-6.6/drivers/net/dsa/rtl83xx/dsa.c   | 108 ++++++++++++------
 .../drivers/net/dsa/rtl83xx/rtl838x.h         |   7 ++
 3 files changed, 102 insertions(+), 34 deletions(-)

diff --git a/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/common.c
index 7ce5f0146e..b17d9ae5d5 100644
--- a/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/common.c
+++ b/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/common.c
@@ -25,6 +25,9 @@ extern const struct rtl838x_reg rtl931x_reg;
 extern const struct dsa_switch_ops rtl83xx_switch_ops;
 extern const struct dsa_switch_ops rtl930x_switch_ops;
 
+extern const struct phylink_pcs_ops rtl83xx_pcs_ops;
+extern const struct phylink_pcs_ops rtl93xx_pcs_ops;
+
 DEFINE_MUTEX(smi_lock);
 
 int rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port)
@@ -1461,7 +1464,7 @@ static int rtl83xx_fib_event(struct notifier_block *this, unsigned long event, v
 
 static int __init rtl83xx_sw_probe(struct platform_device *pdev)
 {
-	int err = 0;
+	int i, err = 0;
 	struct rtl838x_switch_priv *priv;
 	struct device *dev = &pdev->dev;
 	u64 bpdu_mask;
@@ -1559,6 +1562,22 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
 	}
 	pr_debug("Chip version %c\n", priv->version);
 
+	for (i = 0; i <= priv->cpu_port; i++) {
+		switch (soc_info.family) {
+		case RTL8380_FAMILY_ID:
+		case RTL8390_FAMILY_ID:
+			priv->pcs[i].pcs.ops = &rtl83xx_pcs_ops;
+			break;
+		case RTL9300_FAMILY_ID:
+		case RTL9310_FAMILY_ID:
+			priv->pcs[i].pcs.ops = &rtl93xx_pcs_ops;
+			break;
+		}
+		priv->pcs[i].pcs.neg_mode = true;
+		priv->pcs[i].priv = priv;
+		priv->pcs[i].port = i;
+	}
+
 	err = rtl83xx_mdio_probe(priv);
 	if (err) {
 		/* Probing fails the 1st time because of missing ethernet driver
diff --git a/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/dsa.c
index 24c3643929..0f14947fda 100644
--- a/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/dsa.c
+++ b/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/dsa.c
@@ -312,11 +312,13 @@ static int rtl93xx_get_sds(struct phy_device *phydev)
 	return sds_num;
 }
 
-static void rtl83xx_phylink_validate(struct dsa_switch *ds, int port,
-				     unsigned long *supported,
-				     struct phylink_link_state *state)
+static int rtl83xx_pcs_validate(struct phylink_pcs *pcs,
+				unsigned long *supported,
+				const struct phylink_link_state *state)
 {
-	struct rtl838x_switch_priv *priv = ds->priv;
+	struct rtl838x_pcs *rtpcs = container_of(pcs, struct rtl838x_pcs, pcs);
+	struct rtl838x_switch_priv *priv = rtpcs->priv;
+	int port = rtpcs->port;
 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
 
 	pr_debug("In %s port %d, state is %d", __func__, port, state->interface);
@@ -331,10 +333,10 @@ static void rtl83xx_phylink_validate(struct dsa_switch *ds, int port,
 	    state->interface != PHY_INTERFACE_MODE_INTERNAL &&
 	    state->interface != PHY_INTERFACE_MODE_SGMII) {
 		bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
-		dev_err(ds->dev,
+		dev_err(priv->ds->dev,
 			"Unsupported interface: %d for port %d\n",
 			state->interface, port);
-		return;
+		return -EINVAL;
 	}
 
 	/* Allow all the expected bits */
@@ -367,15 +369,17 @@ static void rtl83xx_phylink_validate(struct dsa_switch *ds, int port,
 
 	bitmap_and(supported, supported, mask,
 		   __ETHTOOL_LINK_MODE_MASK_NBITS);
-	bitmap_and(state->advertising, state->advertising, mask,
-		   __ETHTOOL_LINK_MODE_MASK_NBITS);
+
+	return 0;
 }
 
-static void rtl93xx_phylink_validate(struct dsa_switch *ds, int port,
-				     unsigned long *supported,
-				     struct phylink_link_state *state)
+static int rtl93xx_pcs_validate(struct phylink_pcs *pcs,
+				unsigned long *supported,
+				const struct phylink_link_state *state)
 {
-	struct rtl838x_switch_priv *priv = ds->priv;
+	struct rtl838x_pcs *rtpcs = container_of(pcs, struct rtl838x_pcs, pcs);
+	struct rtl838x_switch_priv *priv = rtpcs->priv;
+	int port = rtpcs->port;
 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
 
 	pr_debug("In %s port %d, state is %d (%s)", __func__, port, state->interface,
@@ -396,10 +400,10 @@ static void rtl93xx_phylink_validate(struct dsa_switch *ds, int port,
 	    state->interface != PHY_INTERFACE_MODE_INTERNAL &&
 	    state->interface != PHY_INTERFACE_MODE_SGMII) {
 		bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
-		dev_err(ds->dev,
+		dev_err(priv->ds->dev,
 			"Unsupported interface: %d for port %d\n",
 			state->interface, port);
-		return;
+		return -EINVAL;
 	}
 
 	/* Allow all the expected bits */
@@ -449,20 +453,24 @@ static void rtl93xx_phylink_validate(struct dsa_switch *ds, int port,
 
 	bitmap_and(supported, supported, mask,
 		   __ETHTOOL_LINK_MODE_MASK_NBITS);
-	bitmap_and(state->advertising, state->advertising, mask,
-		   __ETHTOOL_LINK_MODE_MASK_NBITS);
 	pr_debug("%s leaving supported: %*pb", __func__, __ETHTOOL_LINK_MODE_MASK_NBITS, supported);
+
+	return 0;
 }
 
-static int rtl83xx_phylink_mac_link_state(struct dsa_switch *ds, int port,
-					  struct phylink_link_state *state)
+static void rtl83xx_pcs_get_state(struct phylink_pcs *pcs,
+				  struct phylink_link_state *state)
 {
-	struct rtl838x_switch_priv *priv = ds->priv;
+	struct rtl838x_pcs *rtpcs = container_of(pcs, struct rtl838x_pcs, pcs);
+	struct rtl838x_switch_priv *priv = rtpcs->priv;
+	int port = rtpcs->port;
 	u64 speed;
 	u64 link;
 
-	if (port < 0 || port > priv->cpu_port)
-		return -EINVAL;
+	if (port < 0 || port > priv->cpu_port) {
+		state->link = false;
+		return;
+	}
 
 	state->link = 0;
 	link = priv->r->get_port_reg_le(priv->r->mac_link_sts);
@@ -499,20 +507,22 @@ static int rtl83xx_phylink_mac_link_state(struct dsa_switch *ds, int port,
 		state->pause |= MLO_PAUSE_RX;
 	if (priv->r->get_port_reg_le(priv->r->mac_tx_pause_sts) & BIT_ULL(port))
 		state->pause |= MLO_PAUSE_TX;
-
-	return 1;
 }
 
-static int rtl93xx_phylink_mac_link_state(struct dsa_switch *ds, int port,
-					  struct phylink_link_state *state)
+static void rtl93xx_pcs_get_state(struct phylink_pcs *pcs,
+				  struct phylink_link_state *state)
 {
-	struct rtl838x_switch_priv *priv = ds->priv;
+	struct rtl838x_pcs *rtpcs = container_of(pcs, struct rtl838x_pcs, pcs);
+	struct rtl838x_switch_priv *priv = rtpcs->priv;
+	int port = rtpcs->port;
 	u64 speed;
 	u64 link;
 	u64 media;
 
-	if (port < 0 || port > priv->cpu_port)
-		return -EINVAL;
+	if (port < 0 || port > priv->cpu_port) {
+		state->link = false;
+		return;
+	}
 
 	/* On the RTL9300 for at least the RTL8226B PHY, the MAC-side link
 	 * state needs to be read twice in order to read a correct result.
@@ -581,8 +591,28 @@ static int rtl93xx_phylink_mac_link_state(struct dsa_switch *ds, int port,
 		state->pause |= MLO_PAUSE_RX;
 	if (priv->r->get_port_reg_le(priv->r->mac_tx_pause_sts) & BIT_ULL(port))
 		state->pause |= MLO_PAUSE_TX;
+}
+
+static int rtl83xx_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
+			      phy_interface_t interface,
+			      const unsigned long *advertising,
+			      bool permit_pause_to_mac)
+{
+	return 0;
+}
+
+static void rtl83xx_pcs_an_restart(struct phylink_pcs *pcs)
+{
+/* No restart functionality existed before we migrated to pcs */
+}
+
+static struct phylink_pcs *rtl83xx_phylink_mac_select_pcs(struct dsa_switch *ds,
+							  int port,
+							  phy_interface_t interface)
+{
+	struct rtl838x_switch_priv *priv = ds->priv;
 
-	return 1;
+	return &priv->pcs[port].pcs;
 }
 
 static void rtl83xx_config_interface(int port, phy_interface_t interface)
@@ -2126,6 +2156,13 @@ int dsa_phy_write(struct dsa_switch *ds, int phy_addr, int phy_reg, u16 val)
 	return write_phy(phy_addr, 0, phy_reg, val);
 }
 
+const struct phylink_pcs_ops rtl83xx_pcs_ops = {
+	.pcs_an_restart		= rtl83xx_pcs_an_restart,
+	.pcs_validate		= rtl83xx_pcs_validate,
+	.pcs_get_state		= rtl83xx_pcs_get_state,
+	.pcs_config		= rtl83xx_pcs_config,
+};
+
 const struct dsa_switch_ops rtl83xx_switch_ops = {
 	.get_tag_protocol	= rtl83xx_get_tag_protocol,
 	.setup			= rtl83xx_setup,
@@ -2133,11 +2170,10 @@ const struct dsa_switch_ops rtl83xx_switch_ops = {
 	.phy_read		= dsa_phy_read,
 	.phy_write		= dsa_phy_write,
 
-	.phylink_validate	= rtl83xx_phylink_validate,
-	.phylink_mac_link_state	= rtl83xx_phylink_mac_link_state,
 	.phylink_mac_config	= rtl83xx_phylink_mac_config,
 	.phylink_mac_link_down	= rtl83xx_phylink_mac_link_down,
 	.phylink_mac_link_up	= rtl83xx_phylink_mac_link_up,
+	.phylink_mac_select_pcs	= rtl83xx_phylink_mac_select_pcs,
 
 	.get_strings		= rtl83xx_get_strings,
 	.get_ethtool_stats	= rtl83xx_get_ethtool_stats,
@@ -2177,6 +2213,13 @@ const struct dsa_switch_ops rtl83xx_switch_ops = {
 	.port_bridge_flags	= rtl83xx_port_bridge_flags,
 };
 
+const struct phylink_pcs_ops rtl93xx_pcs_ops = {
+	.pcs_an_restart		= rtl83xx_pcs_an_restart,
+	.pcs_validate		= rtl93xx_pcs_validate,
+	.pcs_get_state		= rtl93xx_pcs_get_state,
+	.pcs_config		= rtl83xx_pcs_config,
+};
+
 const struct dsa_switch_ops rtl930x_switch_ops = {
 	.get_tag_protocol	= rtl83xx_get_tag_protocol,
 	.setup			= rtl93xx_setup,
@@ -2184,11 +2227,10 @@ const struct dsa_switch_ops rtl930x_switch_ops = {
 	.phy_read		= dsa_phy_read,
 	.phy_write		= dsa_phy_write,
 
-	.phylink_validate	= rtl93xx_phylink_validate,
-	.phylink_mac_link_state	= rtl93xx_phylink_mac_link_state,
 	.phylink_mac_config	= rtl93xx_phylink_mac_config,
 	.phylink_mac_link_down	= rtl93xx_phylink_mac_link_down,
 	.phylink_mac_link_up	= rtl93xx_phylink_mac_link_up,
+	.phylink_mac_select_pcs	= rtl83xx_phylink_mac_select_pcs,
 
 	.get_strings		= rtl83xx_get_strings,
 	.get_ethtool_stats	= rtl83xx_get_ethtool_stats,
diff --git a/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/rtl838x.h
index 261af32bb4..176fd07fe4 100644
--- a/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/rtl838x.h
+++ b/target/linux/realtek/files-6.6/drivers/net/dsa/rtl83xx/rtl838x.h
@@ -639,6 +639,12 @@ struct rtl838x_port {
 	const struct dsa_port *dp;
 };
 
+struct rtl838x_pcs {
+	struct phylink_pcs pcs;
+	struct rtl838x_switch_priv *priv;
+	int port;
+};
+
 struct rtl838x_vlan_info {
 	u64 untagged_ports;
 	u64 tagged_ports;
@@ -1058,6 +1064,7 @@ struct rtl838x_switch_priv {
 	u16 family_id;
 	char version;
 	struct rtl838x_port ports[57];
+	struct rtl838x_pcs pcs[57];
 	struct mutex reg_mutex;		/* Mutex for individual register manipulations */
 	struct mutex pie_mutex;		/* Mutex for Packet Inspection Engine */
 	int link_state_irq;
-- 
2.30.2