Swap pending with accepted patches, rebase remaining pending patches on top of new upstream. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
253 lines
6.8 KiB
Diff
253 lines
6.8 KiB
Diff
From 20be48bbcc89f5ca91e9d6adadeda9bd29d75c53 Mon Sep 17 00:00:00 2001
|
|
From: Daniel Golle <daniel@makrotopia.org>
|
|
Date: Tue, 24 Mar 2026 18:19:56 +0000
|
|
Subject: [PATCH 19/19] DO NOT SUBMIT: net: dsa: mxl862xx: legacy SFP API
|
|
fallback for old firmware
|
|
|
|
Re-introduce the SYS_MISC_SFP_SET-based PCS implementation as a
|
|
fallback for firmware versions older than 1.0.80 which lack the
|
|
XPCS API. mxl862xx_setup_pcs() selects between the XPCS ops and
|
|
legacy SFP ops based on firmware version.
|
|
|
|
This commit is for downstream use only and must not be submitted
|
|
upstream.
|
|
|
|
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
|
---
|
|
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 22 +++
|
|
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 1 +
|
|
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 160 +++++++++++++++++++-
|
|
3 files changed, 178 insertions(+), 5 deletions(-)
|
|
|
|
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
|
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
|
@@ -2400,6 +2400,28 @@ struct mxl862xx_sys_fw_image_version {
|
|
} __packed;
|
|
|
|
/**
|
|
+ * struct mxl862xx_sys_sfp_cfg - legacy SFP/SerDes port configuration
|
|
+ * @port_id: port id (0 or 1)
|
|
+ * @option: config options (0 - SFP mode/speed/link-status, 1 - flow control)
|
|
+ * @mode: SFP mode (0 - auto, 1 - fix, 2 - disable)
|
|
+ * @speed: select speed when mode is 1
|
|
+ * @link: get link state
|
|
+ * @fc_en: flow control (0 - disable, 1 - enable)
|
|
+ */
|
|
+struct mxl862xx_sys_sfp_cfg {
|
|
+ u8 port_id:4;
|
|
+ u8 option:4;
|
|
+ union {
|
|
+ struct {
|
|
+ u8 mode;
|
|
+ u8 speed;
|
|
+ u8 link;
|
|
+ };
|
|
+ u8 fc_en;
|
|
+ };
|
|
+} __packed;
|
|
+
|
|
+/**
|
|
* enum mxl862xx_rmon_port_type - RMON counter table type
|
|
* @MXL862XX_RMON_CTP_PORT_RX: CTP RX counters
|
|
* @MXL862XX_RMON_CTP_PORT_TX: CTP TX counters
|
|
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
|
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
|
@@ -85,6 +85,7 @@
|
|
|
|
#define SYS_MISC_FW_UPDATE (SYS_MISC_MAGIC + 0x1)
|
|
#define SYS_MISC_FW_VERSION (SYS_MISC_MAGIC + 0x2)
|
|
+#define SYS_MISC_SFP_SET (SYS_MISC_MAGIC + 0xe)
|
|
|
|
#define MXL862XX_XPCS_MAGIC 0x1a00
|
|
#define MXL862XX_XPCS_PCS_CONFIG (MXL862XX_XPCS_MAGIC + 0x1)
|
|
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
|
|
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
|
|
@@ -52,6 +52,156 @@ static struct mxl862xx_pcs *pcs_to_mxl86
|
|
return container_of(pcs, struct mxl862xx_pcs, pcs);
|
|
}
|
|
|
|
+/* Legacy SFP-based PCS implementation for firmware < 1.0.80 */
|
|
+static int mxl862xx_legacy_pcs_config(struct phylink_pcs *pcs,
|
|
+ unsigned int neg_mode,
|
|
+ phy_interface_t interface,
|
|
+ const unsigned long *advertising,
|
|
+ bool permit_pause_to_mac)
|
|
+{
|
|
+ struct mxl862xx_priv *priv = pcs_to_mxl862xx_pcs(pcs)->priv;
|
|
+ int port = pcs_to_mxl862xx_pcs(pcs)->port;
|
|
+ struct mxl862xx_sys_sfp_cfg ser_intf = {
|
|
+ .option = 0,
|
|
+ .mode = 1,
|
|
+ };
|
|
+
|
|
+ if (port != 9 && port != 13)
|
|
+ return 0;
|
|
+
|
|
+ if (port == 9)
|
|
+ ser_intf.port_id = 0;
|
|
+ else
|
|
+ ser_intf.port_id = 1;
|
|
+
|
|
+ switch (interface) {
|
|
+ case PHY_INTERFACE_MODE_SGMII:
|
|
+ ser_intf.speed = 8;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_1000BASEX:
|
|
+ ser_intf.speed = (neg_mode & PHYLINK_PCS_NEG_INBAND) ? 1 : 7;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_2500BASEX:
|
|
+ ser_intf.speed = 4;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_10GBASER:
|
|
+ ser_intf.speed = 2;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_USXGMII:
|
|
+ ser_intf.speed = 3;
|
|
+ break;
|
|
+ default:
|
|
+ dev_err(priv->ds->dev, "unsupported interface: %s\n",
|
|
+ phy_modes(interface));
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return MXL862XX_API_WRITE(priv, SYS_MISC_SFP_SET, ser_intf);
|
|
+}
|
|
+
|
|
+static void mxl862xx_legacy_pcs_get_state(struct phylink_pcs *pcs,
|
|
+ unsigned int neg_mode,
|
|
+ struct phylink_link_state *state)
|
|
+{
|
|
+ struct mxl862xx_priv *priv = pcs_to_mxl862xx_pcs(pcs)->priv;
|
|
+ int port = pcs_to_mxl862xx_pcs(pcs)->port;
|
|
+ struct mxl862xx_port_link_cfg port_link_cfg = {
|
|
+ .port_id = port,
|
|
+ };
|
|
+ struct mxl862xx_port_cfg port_cfg = {
|
|
+ .port_id = port,
|
|
+ };
|
|
+ int ret;
|
|
+
|
|
+ ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTLINKCFGGET,
|
|
+ port_link_cfg);
|
|
+ if (ret)
|
|
+ return;
|
|
+
|
|
+ ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTCFGGET, port_cfg);
|
|
+ if (ret)
|
|
+ return;
|
|
+
|
|
+ state->link = (port_link_cfg.link == MXL862XX_PORT_LINK_UP);
|
|
+ state->an_complete = state->link;
|
|
+
|
|
+ switch (port_link_cfg.speed) {
|
|
+ case MXL862XX_PORT_SPEED_10:
|
|
+ state->speed = SPEED_10;
|
|
+ break;
|
|
+ case MXL862XX_PORT_SPEED_100:
|
|
+ state->speed = SPEED_100;
|
|
+ break;
|
|
+ case MXL862XX_PORT_SPEED_1000:
|
|
+ state->speed = SPEED_1000;
|
|
+ break;
|
|
+ case MXL862XX_PORT_SPEED_2500:
|
|
+ state->speed = SPEED_2500;
|
|
+ break;
|
|
+ case MXL862XX_PORT_SPEED_5000:
|
|
+ state->speed = SPEED_5000;
|
|
+ break;
|
|
+ case MXL862XX_PORT_SPEED_10000:
|
|
+ state->speed = SPEED_10000;
|
|
+ break;
|
|
+ default:
|
|
+ state->speed = SPEED_UNKNOWN;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ switch (port_link_cfg.duplex) {
|
|
+ case MXL862XX_DUPLEX_HALF:
|
|
+ state->duplex = DUPLEX_HALF;
|
|
+ break;
|
|
+ case MXL862XX_DUPLEX_FULL:
|
|
+ state->duplex = DUPLEX_FULL;
|
|
+ break;
|
|
+ default:
|
|
+ state->duplex = DUPLEX_UNKNOWN;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX);
|
|
+ switch (port_cfg.flow_ctrl) {
|
|
+ case MXL862XX_FLOW_RXTX:
|
|
+ state->pause |= MLO_PAUSE_TXRX_MASK;
|
|
+ break;
|
|
+ case MXL862XX_FLOW_TX:
|
|
+ state->pause |= MLO_PAUSE_TX;
|
|
+ break;
|
|
+ case MXL862XX_FLOW_RX:
|
|
+ state->pause |= MLO_PAUSE_RX;
|
|
+ break;
|
|
+ case MXL862XX_FLOW_OFF:
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static unsigned int
|
|
+mxl862xx_legacy_pcs_inband_caps(struct phylink_pcs *pcs,
|
|
+ phy_interface_t interface)
|
|
+{
|
|
+ switch (interface) {
|
|
+ case PHY_INTERFACE_MODE_SGMII:
|
|
+ case PHY_INTERFACE_MODE_USXGMII:
|
|
+ return LINK_INBAND_ENABLE;
|
|
+ case PHY_INTERFACE_MODE_1000BASEX:
|
|
+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
|
|
+ case PHY_INTERFACE_MODE_10GBASER:
|
|
+ case PHY_INTERFACE_MODE_2500BASEX:
|
|
+ return LINK_INBAND_DISABLE;
|
|
+ default:
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+static const struct phylink_pcs_ops mxl862xx_legacy_pcs_ops = {
|
|
+ .pcs_get_state = mxl862xx_legacy_pcs_get_state,
|
|
+ .pcs_config = mxl862xx_legacy_pcs_config,
|
|
+ .pcs_inband_caps = mxl862xx_legacy_pcs_inband_caps,
|
|
+};
|
|
+
|
|
static int mxl862xx_xpcs_port_id(int port)
|
|
{
|
|
return port >= 13;
|
|
@@ -390,7 +540,10 @@ void mxl862xx_setup_pcs(struct mxl862xx_
|
|
pcs->priv = priv;
|
|
pcs->port = port;
|
|
|
|
- pcs->pcs.ops = &mxl862xx_pcs_ops;
|
|
+ if (MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
|
|
+ pcs->pcs.ops = &mxl862xx_pcs_ops;
|
|
+ else
|
|
+ pcs->pcs.ops = &mxl862xx_legacy_pcs_ops;
|
|
pcs->pcs.poll = true;
|
|
|
|
/* Sub-ports only support QSGMII (quad mode with dedicated
|
|
@@ -418,9 +571,6 @@ mxl862xx_phylink_mac_select_pcs(struct p
|
|
struct mxl862xx_priv *priv = dp->ds->priv;
|
|
int port = dp->index;
|
|
|
|
- if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
|
|
- return NULL;
|
|
-
|
|
switch (port) {
|
|
case 9 ... 16:
|
|
return &priv->serdes_ports[port - 9].pcs;
|
|
@@ -551,7 +701,7 @@ void mxl862xx_serdes_get_stats(struct ds
|
|
}
|
|
|
|
void mxl862xx_serdes_self_test(struct dsa_switch *ds, int port,
|
|
- struct ethtool_test *etest, u64 *data)
|
|
+ struct ethtool_test *etest, u64 *data)
|
|
{
|
|
struct mxl862xx_xpcs_prbs_cfg prbs = {};
|
|
struct mxl862xx_xpcs_bert_cfg bert = {};
|