mirror of
https://github.com/openwrt/openwrt.git
synced 2026-05-27 23:00:59 +04:00
generic: 6.18: update MxL862xx DSA switch driver
Update driver to be ready for the upcoming firmware release. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
+19
-32
@@ -1,4 +1,4 @@
|
||||
From 60a23e663e0c607ae4ed871aaa24d257051ad557 Mon Sep 17 00:00:00 2001
|
||||
From 1ad83956d550a252fffc473a191dbe155c4a383e Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 17:56:35 +0000
|
||||
Subject: [PATCH 01/19] net: dsa: mxl862xx: store firmware version for feature
|
||||
@@ -8,15 +8,15 @@ Query the firmware version at init (already done in wait_ready),
|
||||
cache it in priv->fw_version, and provide MXL862XX_FW_VER_MIN()
|
||||
for version-gated code paths throughout the driver.
|
||||
|
||||
The union mxl862xx_fw_version lays out major/minor/revision so
|
||||
that the u32 raw field compares with natural version ordering on
|
||||
both big- and little-endian machines.
|
||||
MXL862XX_FW_VER() packs major/minor/revision into a u32 with
|
||||
bitwise shifts so that versions compare with natural ordering,
|
||||
independent of host endianness.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 3 +++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 36 +++++++++++++++++++++++++++++
|
||||
2 files changed, 39 insertions(+)
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 23 +++++++++++++++++++++++
|
||||
2 files changed, 26 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -40,46 +40,33 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <net/dsa.h>
|
||||
@@ -241,6 +242,38 @@ struct mxl862xx_port {
|
||||
@@ -241,6 +242,25 @@ struct mxl862xx_port {
|
||||
spinlock_t stats_lock; /* protects stats accumulators */
|
||||
};
|
||||
|
||||
+/**
|
||||
+ * union mxl862xx_fw_version - firmware version for comparison and display
|
||||
+ * struct mxl862xx_fw_version - firmware version for comparison and display
|
||||
+ * @major: firmware major version
|
||||
+ * @minor: firmware minor version
|
||||
+ * @revision: firmware revision number
|
||||
+ * @raw: combined u32 for direct >= comparison (major most significant)
|
||||
+ *
|
||||
+ * The struct layout places major in the most-significant byte of the
|
||||
+ * u32 on both big- and little-endian machines, so raw values compare
|
||||
+ * with the natural major > minor > revision ordering.
|
||||
+ */
|
||||
+union mxl862xx_fw_version {
|
||||
+ struct {
|
||||
+#if defined(__BIG_ENDIAN)
|
||||
+ u8 major;
|
||||
+ u8 minor;
|
||||
+ u16 revision;
|
||||
+#elif defined(__LITTLE_ENDIAN)
|
||||
+ u16 revision;
|
||||
+ u8 minor;
|
||||
+ u8 major;
|
||||
+#endif
|
||||
+ };
|
||||
+ u32 raw;
|
||||
+struct mxl862xx_fw_version {
|
||||
+ u8 major;
|
||||
+ u8 minor;
|
||||
+ u16 revision;
|
||||
+};
|
||||
+
|
||||
+#define MXL862XX_FW_VER(maj, min, rev) \
|
||||
+ ((union mxl862xx_fw_version){ .major = (maj), .minor = (min), \
|
||||
+ .revision = (rev) }).raw
|
||||
+ (((u32)(maj) << 24) | ((u32)(min) << 16) | (rev))
|
||||
+#define MXL862XX_FW_VER_MIN(priv, maj, min, rev) \
|
||||
+ ((priv)->fw_version.raw >= MXL862XX_FW_VER(maj, min, rev))
|
||||
+ (MXL862XX_FW_VER((priv)->fw_version.major, (priv)->fw_version.minor, \
|
||||
+ (priv)->fw_version.revision) >= \
|
||||
+ MXL862XX_FW_VER(maj, min, rev))
|
||||
+
|
||||
/* Bit indices for struct mxl862xx_priv::flags */
|
||||
#define MXL862XX_FLAG_CRC_ERR 0
|
||||
#define MXL862XX_FLAG_WORK_STOPPED 1
|
||||
@@ -258,6 +291,8 @@ struct mxl862xx_port {
|
||||
@@ -258,6 +278,8 @@ struct mxl862xx_port {
|
||||
* @drop_meter: index of the single shared zero-rate firmware meter
|
||||
* used to unconditionally drop traffic (used to block
|
||||
* flooding)
|
||||
@@ -88,11 +75,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @ports: per-port state, indexed by switch port number
|
||||
* @bridges: maps DSA bridge number to firmware bridge ID;
|
||||
* zero means no firmware bridge allocated for that
|
||||
@@ -275,6 +310,7 @@ struct mxl862xx_priv {
|
||||
@@ -275,6 +297,7 @@ struct mxl862xx_priv {
|
||||
struct work_struct crc_err_work;
|
||||
unsigned long flags;
|
||||
u16 drop_meter;
|
||||
+ union mxl862xx_fw_version fw_version;
|
||||
+ struct mxl862xx_fw_version fw_version;
|
||||
struct mxl862xx_port ports[MXL862XX_MAX_PORTS];
|
||||
u16 bridges[MXL862XX_MAX_BRIDGES + 1];
|
||||
u16 evlan_ingress_size;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
From cefa0447dc95a4ddd5093f7b8cf35e654870283f Mon Sep 17 00:00:00 2001
|
||||
From eaf472bfc89692cd3cc5e0298c90791f4c1c3244 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 25 Mar 2026 21:39:30 +0000
|
||||
Subject: [PATCH 02/19] net: dsa: mxl862xx: move phylink stubs to
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
From 3c1d77006daca1df20d612850535bc6050e266ee Mon Sep 17 00:00:00 2001
|
||||
From 483be884b2fdee28ac70458067c45a1369939144 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Thu, 26 Mar 2026 01:50:00 +0000
|
||||
Subject: [PATCH 03/19] net: dsa: mxl862xx: move API macros to mxl862xx-host.h
|
||||
|
||||
+400
-602
File diff suppressed because it is too large
Load Diff
+82
-77
@@ -1,32 +1,54 @@
|
||||
From 3659914c43a587a1ca6418867834831aa518ac35 Mon Sep 17 00:00:00 2001
|
||||
From 74044a2d2e62fcc3ee2b6cf22742fa94609c529e Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 18:14:33 +0000
|
||||
Subject: [PATCH 05/19] net: dsa: mxl862xx: add SerDes ethtool statistics
|
||||
|
||||
Expose SerDes equalization and signal detect parameters as ethtool
|
||||
statistics on ports 9-16 (XPCS-backed ports). Uses the XPCS EQ_GET
|
||||
and SIGNAL_DETECT firmware commands to read TX/RX equalization
|
||||
coefficients, DFE taps, and link-level signal status.
|
||||
Expose SerDes equalization parameters as ethtool statistics on
|
||||
ports 9-16 (XPCS-backed ports). Uses the XPCS EQ_GET firmware
|
||||
command to read TX/RX equalization coefficients and DFE taps.
|
||||
|
||||
The 19 additional stats (serdes_tx_*, serdes_rx_*, serdes_pma_link,
|
||||
serdes_link_fault, serdes_in_reset) are appended after the standard
|
||||
RMON counters and gated on firmware >= 1.0.80.
|
||||
The 15 additional stats (serdes_tx_*, serdes_rx_*) are appended
|
||||
after the standard RMON counters and gated on firmware >= 1.0.84.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 88 +++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 2 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 93 +++++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 92 +++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 1 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 97 +++++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-phylink.h | 3 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 6 +-
|
||||
5 files changed, 191 insertions(+), 1 deletion(-)
|
||||
5 files changed, 198 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
@@ -1812,4 +1812,92 @@ struct mxl862xx_xpcs_reset_cfg {
|
||||
@@ -1668,4 +1668,96 @@ struct mxl862xx_xpcs_pcs_link_up {
|
||||
__le16 result;
|
||||
} __packed;
|
||||
|
||||
+/**
|
||||
+ * struct mxl862xx_xpcs_loopback_cfg - loopback control
|
||||
+ * @port_id: XPCS port index
|
||||
+ * @mode: loopback mode. See &enum mxl862xx_xpcs_loopback_mode
|
||||
+ * @result: firmware result
|
||||
+ */
|
||||
+struct mxl862xx_xpcs_loopback_cfg {
|
||||
+ u8 port_id;
|
||||
+ u8 mode; /* enum mxl862xx_xpcs_loopback_mode */
|
||||
+ __le16 result;
|
||||
+} __packed;
|
||||
+
|
||||
+/**
|
||||
+ * struct mxl862xx_xpcs_reset_cfg - XPCS reset
|
||||
+ * @port_id: XPCS port index
|
||||
+ * @reset_type: reset type. See &enum mxl862xx_xpcs_reset_type
|
||||
+ * @result: firmware result
|
||||
+ */
|
||||
+struct mxl862xx_xpcs_reset_cfg {
|
||||
+ u8 port_id;
|
||||
+ u8 reset_type; /* enum mxl862xx_xpcs_reset_type */
|
||||
+ __le16 result;
|
||||
+} __packed;
|
||||
+
|
||||
+/**
|
||||
+ * struct mxl862xx_xpcs_eq_item - single equalization parameter
|
||||
+ * @value: current initial value
|
||||
@@ -94,42 +116,21 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ struct mxl862xx_xpcs_tx_eq_info tx;
|
||||
+ struct mxl862xx_xpcs_rx_eq_info rx;
|
||||
+} __packed;
|
||||
+
|
||||
+/**
|
||||
+ * struct mxl862xx_xpcs_signal_detect - signal detect status
|
||||
+ * @port_id: XPCS port index (0 or 1)
|
||||
+ * @rx_signal: RX signal detected
|
||||
+ * @pma_link: PMA link up
|
||||
+ * @link_fault: PCS link fault
|
||||
+ * @in_reset: XPCS in reset
|
||||
+ * @result: firmware result
|
||||
+ */
|
||||
+struct mxl862xx_xpcs_signal_detect {
|
||||
+ u8 port_id:2;
|
||||
+ u8 rx_signal:1;
|
||||
+ u8 pma_link:1;
|
||||
+ u8 link_fault:1;
|
||||
+ u8 in_reset:1;
|
||||
+ u8 __rsv:2;
|
||||
+ u8 __pad;
|
||||
+ __le16 result;
|
||||
+} __packed;
|
||||
+
|
||||
#endif /* __MXL862XX_API_H */
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
||||
@@ -83,6 +83,8 @@
|
||||
#define MXL862XX_XPCS_FORCE_SPEED (MXL862XX_XPCS_MAGIC + 0x7)
|
||||
@@ -79,6 +79,7 @@
|
||||
#define MXL862XX_XPCS_PCS_LINK_UP (MXL862XX_XPCS_MAGIC + 0x7)
|
||||
#define MXL862XX_XPCS_LOOPBACK (MXL862XX_XPCS_MAGIC + 0x8)
|
||||
#define MXL862XX_XPCS_RESET (MXL862XX_XPCS_MAGIC + 0x9)
|
||||
+#define MXL862XX_XPCS_EQ_GET (MXL862XX_XPCS_MAGIC + 0xc)
|
||||
+#define MXL862XX_XPCS_SIGNAL_DETECT (MXL862XX_XPCS_MAGIC + 0xd)
|
||||
|
||||
#define MMD_API_MAXIMUM_ID 0x7fff
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
|
||||
@@ -456,3 +456,96 @@ const struct phylink_mac_ops mxl862xx_ph
|
||||
@@ -414,3 +414,100 @@ const struct phylink_mac_ops mxl862xx_ph
|
||||
.mac_link_up = mxl862xx_phylink_mac_link_up,
|
||||
.mac_select_pcs = mxl862xx_phylink_mac_select_pcs,
|
||||
};
|
||||
@@ -152,18 +153,19 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ "serdes_rx_dfe_bypass",
|
||||
+ "serdes_rx_adapt_mode",
|
||||
+ "serdes_rx_adapt_sel",
|
||||
+ "serdes_rx_signal",
|
||||
+ "serdes_pma_link",
|
||||
+ "serdes_link_fault",
|
||||
+ "serdes_in_reset",
|
||||
+};
|
||||
+
|
||||
+static bool mxl862xx_port_has_serdes_stats(struct dsa_switch *ds, int port)
|
||||
+{
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+
|
||||
+ return port >= 9 && port <= 16 &&
|
||||
+ MXL862XX_FW_VER_MIN(priv, 1, 0, 80);
|
||||
+ /* Firmware reads EQ/signal status per XPCS, not per lane. Expose
|
||||
+ * the stats only on the slot-0 port of each XPCS (9 and 13) so
|
||||
+ * users don't see four duplicate copies labelled as if they were
|
||||
+ * independent per-port readings.
|
||||
+ */
|
||||
+ return (port == 9 || port == 13) &&
|
||||
+ MXL862XX_FW_VER_MIN(priv, 1, 0, 84);
|
||||
+}
|
||||
+
|
||||
+int mxl862xx_serdes_stats_count(struct dsa_switch *ds, int port)
|
||||
@@ -185,50 +187,53 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ ethtool_puts(&data, mxl862xx_serdes_stats[i]);
|
||||
+}
|
||||
+
|
||||
+static u64 mxl862xx_eq_effective(const struct mxl862xx_xpcs_eq_item *it)
|
||||
+{
|
||||
+ return it->ovrd_en ? it->ovrd : it->value;
|
||||
+}
|
||||
+
|
||||
+void mxl862xx_serdes_get_stats(struct dsa_switch *ds, int port, u64 *data)
|
||||
+{
|
||||
+ struct mxl862xx_xpcs_eq_get eq = {
|
||||
+ .port_id = mxl862xx_xpcs_port_id(port),
|
||||
+ .port_id = MXL862XX_SERDES_PORT_ID(port),
|
||||
+ };
|
||||
+ struct mxl862xx_xpcs_signal_detect sig = {};
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!mxl862xx_port_has_serdes_stats(ds, port))
|
||||
+ return;
|
||||
+
|
||||
+ sig.port_id = mxl862xx_xpcs_port_id(port);
|
||||
+
|
||||
+ if (!MXL862XX_API_READ(ds->priv, MXL862XX_XPCS_EQ_GET, eq)) {
|
||||
+ *data++ = eq.tx.main.value;
|
||||
+ *data++ = eq.tx.pre.value;
|
||||
+ *data++ = eq.tx.post.value;
|
||||
+ *data++ = eq.tx.iboost_lvl.value;
|
||||
+ *data++ = eq.tx.vboost_lvl.value;
|
||||
+ *data++ = eq.tx.vboost_en.value;
|
||||
+ *data++ = eq.rx.att_lvl.value;
|
||||
+ *data++ = eq.rx.vga1_gain.value;
|
||||
+ *data++ = eq.rx.vga2_gain.value;
|
||||
+ *data++ = eq.rx.ctle_boost.value;
|
||||
+ *data++ = eq.rx.ctle_pole.value;
|
||||
+ *data++ = eq.rx.dfe_tap1.value;
|
||||
+ *data++ = eq.rx.dfe_bypass.value;
|
||||
+ *data++ = eq.rx.adapt_mode.value;
|
||||
+ *data++ = eq.rx.adapt_sel.value;
|
||||
+ } else {
|
||||
+ data += 15;
|
||||
+ ret = MXL862XX_API_READ(ds->priv, MXL862XX_XPCS_EQ_GET, eq);
|
||||
+ if (ret) {
|
||||
+ dev_err(ds->dev,
|
||||
+ "port %d: XPCS EQ_GET failed: %d\n", port, ret);
|
||||
+ return;
|
||||
+ }
|
||||
+ if ((s16)le16_to_cpu(eq.result) < 0) {
|
||||
+ dev_err(ds->dev,
|
||||
+ "port %d: XPCS EQ_GET firmware result: %d\n",
|
||||
+ port, (s16)le16_to_cpu(eq.result));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!MXL862XX_API_READ(ds->priv, MXL862XX_XPCS_SIGNAL_DETECT, sig)) {
|
||||
+ *data++ = sig.rx_signal;
|
||||
+ *data++ = sig.pma_link;
|
||||
+ *data++ = sig.link_fault;
|
||||
+ *data++ = sig.in_reset;
|
||||
+ } else {
|
||||
+ data += 4;
|
||||
+ }
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.tx.main);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.tx.pre);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.tx.post);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.tx.iboost_lvl);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.tx.vboost_lvl);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.tx.vboost_en);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.rx.att_lvl);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.rx.vga1_gain);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.rx.vga2_gain);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.rx.ctle_boost);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.rx.ctle_pole);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.rx.dfe_tap1);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.rx.dfe_bypass);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.rx.adapt_mode);
|
||||
+ *data++ = mxl862xx_eq_effective(&eq.rx.adapt_sel);
|
||||
+}
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
|
||||
@@ -12,5 +12,8 @@ void mxl862xx_phylink_get_caps(struct ds
|
||||
@@ -17,5 +17,8 @@ void mxl862xx_phylink_get_caps(struct ds
|
||||
struct phylink_config *config);
|
||||
void mxl862xx_setup_pcs(struct mxl862xx_priv *priv, struct mxl862xx_pcs *pcs,
|
||||
int port);
|
||||
@@ -239,7 +244,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
#endif /* __MXL862XX_PHYLINK_H */
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -1775,6 +1775,8 @@ static void mxl862xx_get_strings(struct
|
||||
@@ -1776,6 +1776,8 @@ static void mxl862xx_get_strings(struct
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mxl862xx_mib); i++)
|
||||
ethtool_puts(&data, mxl862xx_mib[i].name);
|
||||
@@ -248,7 +253,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
}
|
||||
|
||||
static int mxl862xx_get_sset_count(struct dsa_switch *ds, int port, int sset)
|
||||
@@ -1782,7 +1784,7 @@ static int mxl862xx_get_sset_count(struc
|
||||
@@ -1783,7 +1785,7 @@ static int mxl862xx_get_sset_count(struc
|
||||
if (sset != ETH_SS_STATS)
|
||||
return 0;
|
||||
|
||||
@@ -257,7 +262,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
}
|
||||
|
||||
static int mxl862xx_read_rmon(struct dsa_switch *ds, int port,
|
||||
@@ -1818,6 +1820,8 @@ static void mxl862xx_get_ethtool_stats(s
|
||||
@@ -1819,6 +1821,8 @@ static void mxl862xx_get_ethtool_stats(s
|
||||
else
|
||||
*data++ = le64_to_cpu(*(__le64 *)field);
|
||||
}
|
||||
|
||||
-208
@@ -1,208 +0,0 @@
|
||||
From ce66c0be462c8500dfc483395e68be4326ebf296 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 18:15:32 +0000
|
||||
Subject: [PATCH 06/19] net: dsa: mxl862xx: add SerDes self-test via PRBS and
|
||||
BERT
|
||||
|
||||
Implement the dsa_switch_ops.self_test callback for SerDes ports
|
||||
(9-16). Two loopback tests are run:
|
||||
|
||||
1. PCS-level PRBS31: enables TX/RX PRBS31 pattern at the PCS layer,
|
||||
waits 100ms, then reads the error counter.
|
||||
2. SerDes-level BERT PRBS31: enables TX/RX BERT with PRBS31 pattern
|
||||
at the SerDes layer, waits 100ms, then reads the error counter.
|
||||
|
||||
Both tests clean up (disable pattern generators) regardless of outcome.
|
||||
Gated on firmware >= 1.0.80 via mxl862xx_port_has_serdes_stats().
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 45 +++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 2 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 85 +++++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-phylink.h | 3 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 1 +
|
||||
5 files changed, 136 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
@@ -1900,4 +1900,49 @@ struct mxl862xx_xpcs_signal_detect {
|
||||
__le16 result;
|
||||
} __packed;
|
||||
|
||||
+/**
|
||||
+ * struct mxl862xx_xpcs_prbs_cfg - PCS-level PRBS31 test pattern
|
||||
+ * @port_id: XPCS port index (0 or 1)
|
||||
+ * @tx_en: TX PRBS31 enable
|
||||
+ * @rx_en: RX PRBS31 enable
|
||||
+ * @read_err: read error count
|
||||
+ * @rx_err_cnt: RX PRBS31 error count (valid when read_err=1)
|
||||
+ * @result: firmware result
|
||||
+ */
|
||||
+struct mxl862xx_xpcs_prbs_cfg {
|
||||
+ u8 port_id:2;
|
||||
+ u8 tx_en:1;
|
||||
+ u8 rx_en:1;
|
||||
+ u8 read_err:1;
|
||||
+ u8 __rsv:3;
|
||||
+ u8 __pad;
|
||||
+ __le16 rx_err_cnt;
|
||||
+ __le16 result;
|
||||
+} __packed;
|
||||
+
|
||||
+/**
|
||||
+ * struct mxl862xx_xpcs_bert_cfg - SerDes-level BERT test pattern
|
||||
+ * @port_id: XPCS port index (0 or 1)
|
||||
+ * @tx_en: TX BERT enable
|
||||
+ * @rx_en: RX BERT enable
|
||||
+ * @read_err: read RX error count
|
||||
+ * @clear_err: clear RX error counter
|
||||
+ * @insert_err: insert one TX error
|
||||
+ * @pattern: PRBS pattern type (1-7; 0 = disable)
|
||||
+ * @rx_err_cnt: RX BERT error count (valid when read_err=1)
|
||||
+ * @result: firmware result
|
||||
+ */
|
||||
+struct mxl862xx_xpcs_bert_cfg {
|
||||
+ u8 port_id:2;
|
||||
+ u8 tx_en:1;
|
||||
+ u8 rx_en:1;
|
||||
+ u8 read_err:1;
|
||||
+ u8 clear_err:1;
|
||||
+ u8 insert_err:1;
|
||||
+ u8 __rsv:1;
|
||||
+ u8 pattern;
|
||||
+ __le16 rx_err_cnt;
|
||||
+ __le16 result;
|
||||
+} __packed;
|
||||
+
|
||||
#endif /* __MXL862XX_API_H */
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
||||
@@ -83,6 +83,8 @@
|
||||
#define MXL862XX_XPCS_FORCE_SPEED (MXL862XX_XPCS_MAGIC + 0x7)
|
||||
#define MXL862XX_XPCS_LOOPBACK (MXL862XX_XPCS_MAGIC + 0x8)
|
||||
#define MXL862XX_XPCS_RESET (MXL862XX_XPCS_MAGIC + 0x9)
|
||||
+#define MXL862XX_XPCS_PRBS_CFG (MXL862XX_XPCS_MAGIC + 0xa)
|
||||
+#define MXL862XX_XPCS_BERT_CFG (MXL862XX_XPCS_MAGIC + 0xb)
|
||||
#define MXL862XX_XPCS_EQ_GET (MXL862XX_XPCS_MAGIC + 0xc)
|
||||
#define MXL862XX_XPCS_SIGNAL_DETECT (MXL862XX_XPCS_MAGIC + 0xd)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
|
||||
@@ -549,3 +549,88 @@ void mxl862xx_serdes_get_stats(struct ds
|
||||
data += 4;
|
||||
}
|
||||
}
|
||||
+
|
||||
+void mxl862xx_serdes_self_test(struct dsa_switch *ds, int port,
|
||||
+ struct ethtool_test *etest, u64 *data)
|
||||
+{
|
||||
+ struct mxl862xx_xpcs_prbs_cfg prbs = {};
|
||||
+ struct mxl862xx_xpcs_bert_cfg bert = {};
|
||||
+ struct mxl862xx_priv *priv = ds->priv;
|
||||
+ int xpcs_id = mxl862xx_xpcs_port_id(port);
|
||||
+ int i = 0;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!mxl862xx_port_has_serdes_stats(ds, port))
|
||||
+ return;
|
||||
+
|
||||
+ /* Test 1: PCS PRBS31 */
|
||||
+ prbs.port_id = xpcs_id;
|
||||
+ prbs.tx_en = 1;
|
||||
+ prbs.rx_en = 1;
|
||||
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_XPCS_PRBS_CFG, prbs);
|
||||
+ if (ret) {
|
||||
+ data[i++] = 1;
|
||||
+ goto skip_prbs;
|
||||
+ }
|
||||
+
|
||||
+ msleep(100);
|
||||
+
|
||||
+ memset(&prbs, 0, sizeof(prbs));
|
||||
+ prbs.port_id = xpcs_id;
|
||||
+ prbs.read_err = 1;
|
||||
+ ret = MXL862XX_API_READ(priv, MXL862XX_XPCS_PRBS_CFG, prbs);
|
||||
+
|
||||
+ /* Disable PRBS */
|
||||
+ memset(&prbs, 0, sizeof(prbs));
|
||||
+ prbs.port_id = xpcs_id;
|
||||
+ MXL862XX_API_WRITE(priv, MXL862XX_XPCS_PRBS_CFG, prbs);
|
||||
+
|
||||
+ if (ret) {
|
||||
+ data[i++] = 1;
|
||||
+ } else {
|
||||
+ data[i] = le16_to_cpu(prbs.rx_err_cnt) ? 1 : 0;
|
||||
+ if (data[i])
|
||||
+ etest->flags |= ETH_TEST_FL_FAILED;
|
||||
+ i++;
|
||||
+ }
|
||||
+
|
||||
+skip_prbs:
|
||||
+ /* Test 2: SerDes BERT PRBS31 -- clear error counter first */
|
||||
+ bert.port_id = xpcs_id;
|
||||
+ bert.clear_err = 1;
|
||||
+ MXL862XX_API_WRITE(priv, MXL862XX_XPCS_BERT_CFG, bert);
|
||||
+
|
||||
+ /* Enable BERT with PRBS31 pattern */
|
||||
+ memset(&bert, 0, sizeof(bert));
|
||||
+ bert.port_id = xpcs_id;
|
||||
+ bert.tx_en = 1;
|
||||
+ bert.rx_en = 1;
|
||||
+ bert.pattern = 6; /* PRBS31 */
|
||||
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_XPCS_BERT_CFG, bert);
|
||||
+ if (ret) {
|
||||
+ data[i++] = 1;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ msleep(100);
|
||||
+
|
||||
+ /* Read error count */
|
||||
+ memset(&bert, 0, sizeof(bert));
|
||||
+ bert.port_id = xpcs_id;
|
||||
+ bert.read_err = 1;
|
||||
+ ret = MXL862XX_API_READ(priv, MXL862XX_XPCS_BERT_CFG, bert);
|
||||
+
|
||||
+ /* Disable BERT */
|
||||
+ memset(&bert, 0, sizeof(bert));
|
||||
+ bert.port_id = xpcs_id;
|
||||
+ MXL862XX_API_WRITE(priv, MXL862XX_XPCS_BERT_CFG, bert);
|
||||
+
|
||||
+ if (ret) {
|
||||
+ data[i++] = 1;
|
||||
+ } else {
|
||||
+ data[i] = le16_to_cpu(bert.rx_err_cnt) ? 1 : 0;
|
||||
+ if (data[i])
|
||||
+ etest->flags |= ETH_TEST_FL_FAILED;
|
||||
+ i++;
|
||||
+ }
|
||||
+}
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
|
||||
@@ -3,6 +3,7 @@
|
||||
#ifndef __MXL862XX_PHYLINK_H
|
||||
#define __MXL862XX_PHYLINK_H
|
||||
|
||||
+#include <linux/ethtool.h>
|
||||
#include <linux/phylink.h>
|
||||
|
||||
#include "mxl862xx.h"
|
||||
@@ -15,5 +16,7 @@ void mxl862xx_setup_pcs(struct mxl862xx_
|
||||
int mxl862xx_serdes_stats_count(struct dsa_switch *ds, int port);
|
||||
void mxl862xx_serdes_get_strings(struct dsa_switch *ds, int port, u8 *data);
|
||||
void mxl862xx_serdes_get_stats(struct dsa_switch *ds, int port, u64 *data);
|
||||
+void mxl862xx_serdes_self_test(struct dsa_switch *ds, int port,
|
||||
+ struct ethtool_test *etest, u64 *data);
|
||||
|
||||
#endif /* __MXL862XX_PHYLINK_H */
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -2088,6 +2088,7 @@ static const struct dsa_switch_ops mxl86
|
||||
.get_pause_stats = mxl862xx_get_pause_stats,
|
||||
.get_rmon_stats = mxl862xx_get_rmon_stats,
|
||||
.get_stats64 = mxl862xx_get_stats64,
|
||||
+ .self_test = mxl862xx_serdes_self_test,
|
||||
};
|
||||
|
||||
static int mxl862xx_probe(struct mdio_device *mdiodev)
|
||||
+70
-46
@@ -1,7 +1,7 @@
|
||||
From e6defbd42db6e64c2bb203f82b7d7f8c0691a052 Mon Sep 17 00:00:00 2001
|
||||
From 50a84327282120a51af12da91214ed9e06f585cb Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 18:51:13 +0000
|
||||
Subject: [PATCH 07/19] net: dsa: mxl862xx: trap link-local and multicast
|
||||
Subject: [PATCH 06/19] net: dsa: mxl862xx: trap link-local and multicast
|
||||
snooping frames to CPU
|
||||
|
||||
Install per-CTP PCE rules on each user port that trap IEEE 802.1D
|
||||
@@ -19,10 +19,21 @@ all flood modes enabled. Each trap rule points the bridge engine at
|
||||
this FID via bFidEnable so that IGMP and MLD frames are never
|
||||
silently dropped by the ingress port's private flood policy.
|
||||
|
||||
Three multicast snooping rules are installed per port:
|
||||
offset 2 -- IPv4 IGMP (IP protocol 2, all versions)
|
||||
offset 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
|
||||
offset 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
|
||||
Rules are written through the firmware's logical-index API,
|
||||
GSW_TFLOW_PCERULELOGICWRITE. The firmware translates the logical
|
||||
index in @rule->pattern.index into a physical position within the
|
||||
per-CTP block selected by @rule->region and @rule->logicalportid,
|
||||
and grows the hardware block size on demand as rules are inserted.
|
||||
A single dispatch helper, mxl862xx_pce_rule_write(), centralises the
|
||||
firmware command so the trap callers do not need to know which API
|
||||
variant is used. Four logical indices are consumed in each port's
|
||||
per-CTP block (index 0 is reserved by the firmware for its
|
||||
flow-control marking rule):
|
||||
|
||||
index 1 -- IEEE 802.1D link-local (dst 01:80:c2:00:00:0x)
|
||||
index 2 -- IPv4 IGMP (IP protocol 2, all versions)
|
||||
index 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
|
||||
index 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
|
||||
|
||||
Add the PCE rule firmware API structures, command definitions, and
|
||||
the rule block allocation interface.
|
||||
@@ -30,15 +41,15 @@ the rule block allocation interface.
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 684 ++++++++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 5 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 186 +++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 6 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 198 +++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 8 +
|
||||
4 files changed, 883 insertions(+)
|
||||
4 files changed, 896 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
@@ -1420,6 +1420,690 @@ struct mxl862xx_port_link_cfg {
|
||||
u8 lpi;
|
||||
@@ -1184,6 +1184,690 @@ struct mxl862xx_ctp_port_assignment {
|
||||
__le16 bridge_port_id;
|
||||
} __packed;
|
||||
|
||||
+/* PCE (Packet Classification Engine) rule structures.
|
||||
@@ -694,7 +705,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ * @action: Forwarding action (portmap, cross-state, etc.)
|
||||
+ *
|
||||
+ * This structure is passed to the firmware via the MDIO data
|
||||
+ * buffer using the %MXL862XX_TFLOW_PCERULEWRITE command.
|
||||
+ * buffer using the %MXL862XX_TFLOW_PCERULELOGICWRITE command.
|
||||
+ * The binary layout must exactly match the firmware's
|
||||
+ * GSW_PCE_rule_t (466 bytes, packed, little-endian scalars).
|
||||
+ */
|
||||
@@ -738,13 +749,14 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
#define MXL862XX_BRDG_MAGIC 0x300
|
||||
#define MXL862XX_BRDGPORT_MAGIC 0x400
|
||||
#define MXL862XX_CTP_MAGIC 0x500
|
||||
@@ -31,6 +32,10 @@
|
||||
@@ -30,6 +31,11 @@
|
||||
#define MXL862XX_COMMON_CFGSET (MXL862XX_COMMON_MAGIC + 0xa)
|
||||
#define MXL862XX_COMMON_REGISTERMOD (MXL862XX_COMMON_MAGIC + 0x11)
|
||||
|
||||
+#define MXL862XX_TFLOW_PCERULEWRITE (MXL862XX_TFLOW_MAGIC + 0x2)
|
||||
+#define MXL862XX_TFLOW_PCERULEALLOC (MXL862XX_TFLOW_MAGIC + 0x4)
|
||||
+#define MXL862XX_TFLOW_PCERULEFREE (MXL862XX_TFLOW_MAGIC + 0x5)
|
||||
+#define MXL862XX_TFLOW_PCERULELOGICWRITE \
|
||||
+ (MXL862XX_TFLOW_MAGIC + 0xa)
|
||||
+
|
||||
#define MXL862XX_BRIDGE_ALLOC (MXL862XX_BRDG_MAGIC + 0x1)
|
||||
#define MXL862XX_BRIDGE_CONFIGSET (MXL862XX_BRDG_MAGIC + 0x2)
|
||||
@@ -771,21 +783,35 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return 0;
|
||||
|
||||
not_ready_yet:
|
||||
@@ -381,6 +384,158 @@ static int mxl862xx_setup_drop_meter(str
|
||||
@@ -381,6 +384,170 @@ static int mxl862xx_setup_drop_meter(str
|
||||
return MXL862XX_API_WRITE(priv, MXL862XX_COMMON_REGISTERMOD, reg);
|
||||
}
|
||||
|
||||
+
|
||||
+/* Per-CTP offsets for protocol trap rules. Each port's CTP flow-table
|
||||
+ * block is pre-allocated by the firmware during init (44 entries per
|
||||
+ * port on a 10-port SKU, of which offset 0 is reserved for flow-control
|
||||
+ * marking). Offsets 1-4 are used for link-local and multicast snooping
|
||||
+ * traps; all others remain free.
|
||||
+/* Per-CTP logical indices for protocol trap rules.
|
||||
+ *
|
||||
+ * The firmware pre-allocates a per-CTP PCE block for every port during
|
||||
+ * init and reserves logical index 0 for its flow-control marking rule.
|
||||
+ * Logical indices 1-4 are used here for link-local and multicast
|
||||
+ * snooping traps; the firmware grows the underlying hardware block on
|
||||
+ * demand as PCERULELOGICWRITE inserts new entries.
|
||||
+ */
|
||||
+#define MXL862XX_LINK_LOCAL_CTP_OFFSET 1
|
||||
+#define MXL862XX_IGMP_CTP_OFFSET 2
|
||||
+#define MXL862XX_MLDV1_CTP_OFFSET 3
|
||||
+#define MXL862XX_MLDV2_CTP_OFFSET 4
|
||||
+#define MXL862XX_LINK_LOCAL_CTP_INDEX 1
|
||||
+#define MXL862XX_IGMP_CTP_INDEX 2
|
||||
+#define MXL862XX_MLDV1_CTP_INDEX 3
|
||||
+#define MXL862XX_MLDV2_CTP_INDEX 4
|
||||
+
|
||||
+/* Install (or overwrite) a PCE rule via the firmware's logical-index
|
||||
+ * API. The firmware translates the logical index in @rule->pattern.index
|
||||
+ * to a physical position within the block selected by @rule->region and
|
||||
+ * @rule->logicalportid, and expands the hardware block size as needed.
|
||||
+ */
|
||||
+static int mxl862xx_pce_rule_write(struct mxl862xx_priv *priv,
|
||||
+ struct mxl862xx_pce_rule *rule)
|
||||
+{
|
||||
+ return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULELOGICWRITE,
|
||||
+ *rule);
|
||||
+}
|
||||
+
|
||||
+/* Fill the action fields of a PCE rule that traps ingress frames to
|
||||
+ * the CPU port. Used by both the link-local trap and the multicast
|
||||
@@ -826,12 +852,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ * The firmware does not install this rule by default because its own
|
||||
+ * STP module is not used when DSA manages STP.
|
||||
+ *
|
||||
+ * The rule is written into the port's per-CTP flow table at offset 1.
|
||||
+ * The firmware already allocates a 44-entry block for every CTP during
|
||||
+ * init (8 entries exposed initially, expandable), so no dynamic
|
||||
+ * allocation via PCERULEALLOC is needed. Using region=CTP causes the
|
||||
+ * firmware to translate the CTP-relative offset into an absolute
|
||||
+ * hardware index.
|
||||
+ * The rule is written into the port's per-CTP flow table at logical
|
||||
+ * index 1 using PCERULELOGICWRITE, which selects the per-CTP block via
|
||||
+ * @region and @logicalportid and grows the block on demand.
|
||||
+ *
|
||||
+ * Cross-state is enabled so that link-local frames reach the CPU even
|
||||
+ * when the bridge port is in BLOCKING or LEARNING state.
|
||||
@@ -844,7 +867,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ rule.logicalportid = port;
|
||||
+ rule.region = cpu_to_le32(MXL862XX_PCE_RULE_CTP);
|
||||
+
|
||||
+ rule.pattern.index = cpu_to_le16(MXL862XX_LINK_LOCAL_CTP_OFFSET);
|
||||
+ rule.pattern.index = cpu_to_le16(MXL862XX_LINK_LOCAL_CTP_INDEX);
|
||||
+ rule.pattern.enable = 1;
|
||||
+ rule.pattern.mac_dst_enable = 1;
|
||||
+ memcpy(rule.pattern.mac_dst, eth_reserved_addr_base, ETH_ALEN);
|
||||
@@ -852,7 +875,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+
|
||||
+ mxl862xx_fill_cpu_trap_action(ds, port, &rule);
|
||||
+
|
||||
+ return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
|
||||
+ return mxl862xx_pce_rule_write(priv, &rule);
|
||||
+}
|
||||
+
|
||||
+/* Install PCE rules that trap IGMP and MLD frames to the CPU port for
|
||||
@@ -862,10 +885,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ * never classified as blocked unknown MC regardless of the ingress
|
||||
+ * port's standalone flood policy.
|
||||
+ *
|
||||
+ * Three rules are installed per port:
|
||||
+ * offset 2 -- IPv4 IGMP (IP protocol 2, all versions)
|
||||
+ * offset 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
|
||||
+ * offset 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
|
||||
+ * Three rules are installed per port at logical indices in the per-CTP
|
||||
+ * block:
|
||||
+ * index 2 -- IPv4 IGMP (IP protocol 2, all versions)
|
||||
+ * index 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
|
||||
+ * index 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
|
||||
+ *
|
||||
+ * The MLDv1 rule uses range mode on the first two bytes after the IP
|
||||
+ * header (ICMPv6 type + code): lower bound 0x8200 (type 130, code 0)
|
||||
@@ -883,12 +907,12 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ mxl862xx_fill_cpu_trap_action(ds, port, &rule);
|
||||
+
|
||||
+ /* IGMP: IPv4 protocol 2, all versions */
|
||||
+ rule.pattern.index = cpu_to_le16(MXL862XX_IGMP_CTP_OFFSET);
|
||||
+ rule.pattern.index = cpu_to_le16(MXL862XX_IGMP_CTP_INDEX);
|
||||
+ rule.pattern.enable = 1;
|
||||
+ rule.pattern.protocol = IPPROTO_IGMP;
|
||||
+ rule.pattern.protocol_enable = 1;
|
||||
+
|
||||
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
|
||||
+ ret = mxl862xx_pce_rule_write(priv, &rule);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
@@ -896,7 +920,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ * Range mode covers all three types with any code value.
|
||||
+ */
|
||||
+ memset(&rule.pattern, 0, sizeof(rule.pattern));
|
||||
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV1_CTP_OFFSET);
|
||||
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV1_CTP_INDEX);
|
||||
+ rule.pattern.enable = 1;
|
||||
+ rule.pattern.protocol = IPPROTO_ICMPV6;
|
||||
+ rule.pattern.protocol_enable = 1;
|
||||
@@ -907,7 +931,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ rule.pattern.app_data_msb_enable = 1;
|
||||
+ rule.pattern.app_mask_range_msb_select = 1; /* range mode */
|
||||
+
|
||||
+ ret = MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
|
||||
+ ret = mxl862xx_pce_rule_write(priv, &rule);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
@@ -915,7 +939,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ * Nibble mask 0x3 masks nibbles 0-1 (lower byte = code field).
|
||||
+ */
|
||||
+ memset(&rule.pattern, 0, sizeof(rule.pattern));
|
||||
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV2_CTP_OFFSET);
|
||||
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV2_CTP_INDEX);
|
||||
+ rule.pattern.enable = 1;
|
||||
+ rule.pattern.protocol = IPPROTO_ICMPV6;
|
||||
+ rule.pattern.protocol_enable = 1;
|
||||
@@ -924,13 +948,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ rule.pattern.app_data_msb_enable = 1;
|
||||
+ /* app_mask_range_msb_select = 0: nibble mask mode (default) */
|
||||
+
|
||||
+ return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
|
||||
+ return mxl862xx_pce_rule_write(priv, &rule);
|
||||
+}
|
||||
+
|
||||
static int mxl862xx_set_bridge_port(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct mxl862xx_bridge_port_config br_port_cfg = {};
|
||||
@@ -683,6 +838,28 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
@@ -684,6 +851,28 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -959,7 +983,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
schedule_delayed_work(&priv->stats_work,
|
||||
MXL862XX_STATS_POLL_INTERVAL);
|
||||
|
||||
@@ -1382,6 +1559,15 @@ static int mxl862xx_port_setup(struct ds
|
||||
@@ -1383,6 +1572,15 @@ static int mxl862xx_port_setup(struct ds
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -977,7 +1001,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
if (ret)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -319,6 +319,13 @@ union mxl862xx_fw_version {
|
||||
@@ -317,6 +317,13 @@ struct mxl862xx_fw_version {
|
||||
* @evlan_ingress_size: per-port ingress Extended VLAN block size
|
||||
* @evlan_egress_size: per-port egress Extended VLAN block size
|
||||
* @vf_block_size: per-port VLAN Filter block size
|
||||
@@ -991,7 +1015,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @stats_work: periodic work item that polls RMON hardware counters
|
||||
* and accumulates them into 64-bit per-port stats
|
||||
*/
|
||||
@@ -335,6 +342,7 @@ struct mxl862xx_priv {
|
||||
@@ -334,6 +341,7 @@ struct mxl862xx_priv {
|
||||
u16 evlan_ingress_size;
|
||||
u16 evlan_egress_size;
|
||||
u16 vf_block_size;
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
From 264838ee8ee3ad611a84df96d889429f1ded2148 Mon Sep 17 00:00:00 2001
|
||||
From 6126dff8c28e71091c23fd0cc2f55b1a50e117a6 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 18:51:21 +0000
|
||||
Subject: [PATCH 08/19] net: dsa: mxl862xx: warn about old firmware default PCE
|
||||
Subject: [PATCH 07/19] net: dsa: mxl862xx: warn about old firmware default PCE
|
||||
rules
|
||||
|
||||
Firmware versions older than 1.0.80 install global PCE rules at
|
||||
@@ -19,7 +19,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -860,6 +860,10 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
@@ -873,6 +873,10 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
true, true, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
+63
-73
@@ -1,7 +1,7 @@
|
||||
From d7ed9b681298d206d81e9cf3c93558d6e912ae88 Mon Sep 17 00:00:00 2001
|
||||
From 69a0946ef48325b85f4a331152d6340f39083053 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Sun, 22 Mar 2026 00:58:04 +0000
|
||||
Subject: [PATCH 09/20] net: dsa: add 802.1Q VLAN-based tag driver for MxL862xx
|
||||
Subject: [PATCH 08/19] net: dsa: add 802.1Q VLAN-based tag driver for MxL862xx
|
||||
|
||||
The MxL862xx native 8-byte special tag (SpTag) requires firmware
|
||||
support on the switch CPU and is not compatible with all SoC Ethernet
|
||||
@@ -22,13 +22,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
drivers/net/dsa/mxl862xx/Kconfig | 1 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 221 +++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 2 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 1678 ++++++++++++++++++++---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 1677 ++++++++++++++++++++---
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 12 +
|
||||
include/net/dsa.h | 2 +
|
||||
net/dsa/Kconfig | 7 +
|
||||
net/dsa/Makefile | 1 +
|
||||
net/dsa/tag_mxl862xx_8021q.c | 65 +
|
||||
9 files changed, 1803 insertions(+), 186 deletions(-)
|
||||
9 files changed, 1804 insertions(+), 184 deletions(-)
|
||||
create mode 100644 net/dsa/tag_mxl862xx_8021q.c
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/Kconfig
|
||||
@@ -43,10 +43,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
These switches have two 10GE SerDes interfaces, one typically
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
@@ -1185,6 +1185,227 @@ struct mxl862xx_ctp_port_assignment {
|
||||
@@ -1184,6 +1184,227 @@ struct mxl862xx_ctp_port_assignment {
|
||||
__le16 bridge_port_id;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
+/**
|
||||
+ * enum mxl862xx_ctp_port_config_mask - CTP Port Configuration Mask
|
||||
+ * @MXL862XX_CTP_PORT_CONFIG_MASK_BRIDGE_PORT_ID:
|
||||
+ * Mask for bridge_port_id.
|
||||
@@ -267,10 +268,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ u8 egress_mirror_enable;
|
||||
+} __packed;
|
||||
+
|
||||
+/**
|
||||
* enum mxl862xx_port_duplex - Ethernet port duplex status
|
||||
* @MXL862XX_DUPLEX_FULL: Port operates in full-duplex mode
|
||||
* @MXL862XX_DUPLEX_HALF: Port operates in half-duplex mode
|
||||
/* PCE (Packet Classification Engine) rule structures.
|
||||
*
|
||||
* Binary layout must exactly match the firmware's GSW_PCE_rule_t
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
||||
@@ -47,12 +47,14 @@
|
||||
@@ -387,9 +387,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
}
|
||||
|
||||
/* PHY access via firmware relay */
|
||||
@@ -396,6 +459,78 @@ static int mxl862xx_setup_drop_meter(str
|
||||
#define MXL862XX_MLDV1_CTP_OFFSET 3
|
||||
#define MXL862XX_MLDV2_CTP_OFFSET 4
|
||||
@@ -410,6 +473,78 @@ static int mxl862xx_pce_rule_write(struc
|
||||
*rule);
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * mxl862xx_cpu_bridge_port_id - Get the bridge port ID for CPU-side forwarding
|
||||
@@ -466,7 +466,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
/* Fill the action fields of a PCE rule that traps ingress frames to
|
||||
* the CPU port. Used by both the link-local trap and the multicast
|
||||
* snooping traps. The caller must already have set the rule header
|
||||
@@ -404,24 +539,36 @@ static int mxl862xx_setup_drop_meter(str
|
||||
@@ -418,24 +553,36 @@ static int mxl862xx_pce_rule_write(struc
|
||||
* PORTMAP_ALTERNATIVE redirects the frame to the CPU port but does
|
||||
* not by itself bypass downstream flood gates. In SpTag mode the
|
||||
* ingress port's private FID may have forward_unknown_multicast=false,
|
||||
@@ -505,17 +505,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
rule->action.cross_state_action =
|
||||
cpu_to_le32(MXL862XX_PCE_ACTION_CROSS_STATE_CROSS);
|
||||
|
||||
@@ -441,9 +588,6 @@ static void mxl862xx_fill_cpu_trap_actio
|
||||
* allocation via PCERULEALLOC is needed. Using region=CTP causes the
|
||||
* firmware to translate the CTP-relative offset into an absolute
|
||||
* hardware index.
|
||||
- *
|
||||
- * Cross-state is enabled so that link-local frames reach the CPU even
|
||||
- * when the bridge port is in BLOCKING or LEARNING state.
|
||||
*/
|
||||
static int mxl862xx_setup_link_local_trap(struct dsa_switch *ds, int port)
|
||||
{
|
||||
@@ -552,11 +696,17 @@ static int mxl862xx_set_bridge_port(stru
|
||||
@@ -564,11 +711,17 @@ static int mxl862xx_set_bridge_port(stru
|
||||
return 0;
|
||||
|
||||
if (dsa_port_is_cpu(dp)) {
|
||||
@@ -538,7 +528,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
}
|
||||
} else if (dp->bridge) {
|
||||
dsa_switch_for_each_bridge_member(member_dp, ds,
|
||||
@@ -567,10 +717,10 @@ static int mxl862xx_set_bridge_port(stru
|
||||
@@ -579,10 +732,10 @@ static int mxl862xx_set_bridge_port(stru
|
||||
member_dp->index);
|
||||
}
|
||||
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
@@ -551,7 +541,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
p->flood_block = 0;
|
||||
p->learning = false;
|
||||
}
|
||||
@@ -774,10 +924,12 @@ static void mxl862xx_free_bridge(struct
|
||||
@@ -786,10 +939,12 @@ static void mxl862xx_free_bridge(struct
|
||||
static int mxl862xx_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
@@ -566,16 +556,16 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
ret = mxl862xx_reset(priv);
|
||||
if (ret)
|
||||
@@ -790,7 +942,7 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
for (i = 0; i < 8; i++)
|
||||
mxl862xx_setup_pcs(priv, &priv->serdes_ports[i], i + 9);
|
||||
@@ -803,7 +958,7 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
mxl862xx_setup_pcs(priv, &priv->serdes_ports[i],
|
||||
i + MXL862XX_FIRST_SERDES_PORT);
|
||||
|
||||
- /* Calculate Extended VLAN block sizes.
|
||||
+ /* Calculate Extended VLAN and VLAN Filter block sizes.
|
||||
* With VLAN Filter handling VID membership checks:
|
||||
* Ingress: only final catchall rules (PVID insertion, 802.1Q
|
||||
* accept, non-8021Q TPID handling, discard).
|
||||
@@ -798,46 +950,151 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
@@ -811,46 +966,151 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
* ingress EVLAN rules are needed. (7 entries.)
|
||||
* Egress: 2 rules per VID that needs tag stripping (untagged VIDs).
|
||||
* No egress final catchalls -- VLAN Filter does the discard.
|
||||
@@ -739,7 +729,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
/* Allocate a dedicated PCE snooping FID with all flood modes enabled.
|
||||
* Per-port PCE trap rules (link-local, IGMP, MLD) set bFidEnable to
|
||||
@@ -860,10 +1117,6 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
@@ -873,10 +1133,6 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
true, true, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -750,7 +740,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
schedule_delayed_work(&priv->stats_work,
|
||||
MXL862XX_STATS_POLL_INTERVAL);
|
||||
|
||||
@@ -944,10 +1197,71 @@ static int mxl862xx_configure_sp_tag_pro
|
||||
@@ -957,10 +1213,71 @@ static int mxl862xx_configure_sp_tag_pro
|
||||
return MXL862XX_API_WRITE(ds->priv, MXL862XX_SS_SPTAG_SET, tag);
|
||||
}
|
||||
|
||||
@@ -823,7 +813,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
{
|
||||
struct mxl862xx_extendedvlan_config cfg = {};
|
||||
struct mxl862xx_extendedvlan_filter_vlan *fv;
|
||||
@@ -1016,6 +1330,31 @@ static int mxl862xx_evlan_write_rule(str
|
||||
@@ -1029,6 +1346,31 @@ static int mxl862xx_evlan_write_rule(str
|
||||
cpu_to_le32(MXL862XX_EXTENDEDVLAN_TREATMENT_DISCARD_UPSTREAM);
|
||||
}
|
||||
break;
|
||||
@@ -855,7 +845,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
}
|
||||
|
||||
return MXL862XX_API_WRITE(priv, MXL862XX_EXTENDEDVLAN_SET, cfg);
|
||||
@@ -1054,7 +1393,7 @@ static int mxl862xx_evlan_write_final_ru
|
||||
@@ -1067,7 +1409,7 @@ static int mxl862xx_evlan_write_final_ru
|
||||
for (i = 0; i < n_rules; i++) {
|
||||
ret = mxl862xx_evlan_write_rule(priv, blk->block_id,
|
||||
start_idx + i, &rules[i],
|
||||
@@ -864,7 +854,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -1175,6 +1514,41 @@ static int mxl862xx_vf_del_vid(struct mx
|
||||
@@ -1188,6 +1530,41 @@ static int mxl862xx_vf_del_vid(struct mx
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -906,7 +896,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
static int mxl862xx_evlan_program_ingress(struct mxl862xx_priv *priv, int port)
|
||||
{
|
||||
struct mxl862xx_port *p = &priv->ports[port];
|
||||
@@ -1199,8 +1573,8 @@ static int mxl862xx_evlan_program_egress
|
||||
@@ -1212,8 +1589,8 @@ static int mxl862xx_evlan_program_egress
|
||||
const struct mxl862xx_evlan_rule_desc *vid_rules;
|
||||
struct mxl862xx_vf_vid *vfv;
|
||||
u16 old_active = blk->n_active;
|
||||
@@ -916,7 +906,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
if (p->vlan_filtering) {
|
||||
vid_rules = vid_accept_standard;
|
||||
@@ -1214,13 +1588,23 @@ static int mxl862xx_evlan_program_egress
|
||||
@@ -1227,13 +1604,23 @@ static int mxl862xx_evlan_program_egress
|
||||
if (!vfv->untagged)
|
||||
continue;
|
||||
|
||||
@@ -941,7 +931,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1229,7 +1613,29 @@ static int mxl862xx_evlan_program_egress
|
||||
@@ -1242,7 +1629,29 @@ static int mxl862xx_evlan_program_egress
|
||||
idx++, &vid_rules[1],
|
||||
vfv->vid,
|
||||
vfv->untagged,
|
||||
@@ -972,7 +962,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -1241,8 +1647,7 @@ static int mxl862xx_evlan_program_egress
|
||||
@@ -1254,8 +1663,7 @@ static int mxl862xx_evlan_program_egress
|
||||
*/
|
||||
for (i = idx; i < old_active; i++) {
|
||||
ret = mxl862xx_evlan_deactivate_entry(priv,
|
||||
@@ -982,7 +972,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -1267,13 +1672,16 @@ static int mxl862xx_port_vlan_filtering(
|
||||
@@ -1280,13 +1688,16 @@ static int mxl862xx_port_vlan_filtering(
|
||||
p->vlan_filtering = vlan_filtering;
|
||||
|
||||
if (changed) {
|
||||
@@ -1004,7 +994,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
ret = mxl862xx_evlan_program_ingress(priv, port);
|
||||
if (ret)
|
||||
@@ -1493,22 +1901,575 @@ static void mxl862xx_port_bridge_leave(s
|
||||
@@ -1506,22 +1917,575 @@ static void mxl862xx_port_bridge_leave(s
|
||||
port, ERR_PTR(err));
|
||||
|
||||
/* Revert leaving port, omitted by the sync above, to its
|
||||
@@ -1582,7 +1572,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
static int mxl862xx_port_setup(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
@@ -1530,33 +2491,52 @@ static int mxl862xx_port_setup(struct ds
|
||||
@@ -1543,33 +2507,52 @@ static int mxl862xx_port_setup(struct ds
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@@ -1651,7 +1641,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = mxl862xx_set_bridge_port(ds, port);
|
||||
@@ -1572,24 +2552,7 @@ static int mxl862xx_port_setup(struct ds
|
||||
@@ -1585,24 +2568,7 @@ static int mxl862xx_port_setup(struct ds
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1676,7 +1666,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1611,7 +2574,7 @@ static void mxl862xx_port_teardown(struc
|
||||
@@ -1624,7 +2590,7 @@ static void mxl862xx_port_teardown(struc
|
||||
priv->ports[port].setup_done = false;
|
||||
}
|
||||
|
||||
@@ -1685,7 +1675,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
{
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
|
||||
@@ -1629,23 +2592,247 @@ static int mxl862xx_get_fid(struct dsa_s
|
||||
@@ -1642,23 +2608,247 @@ static int mxl862xx_get_fid(struct dsa_s
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1718,12 +1708,12 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ if (dsa_is_cpu_port(ds, port) && priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q &&
|
||||
+ db.type == DSA_DB_PORT) {
|
||||
+ bp_cpu = priv->ports[db.dp->index].bridge_port_cpu;
|
||||
+
|
||||
|
||||
- param.port_id = cpu_to_le32(port);
|
||||
+ if (bp_cpu)
|
||||
+ return bp_cpu;
|
||||
+ }
|
||||
|
||||
- param.port_id = cpu_to_le32(port);
|
||||
+
|
||||
+ return port;
|
||||
+}
|
||||
+
|
||||
@@ -1941,7 +1931,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
if (ret)
|
||||
dev_err(ds->dev, "failed to add FDB entry on port %d\n", port);
|
||||
|
||||
@@ -1655,18 +2842,25 @@ static int mxl862xx_port_fdb_add(struct
|
||||
@@ -1668,18 +2858,25 @@ static int mxl862xx_port_fdb_add(struct
|
||||
static int mxl862xx_port_fdb_del(struct dsa_switch *ds, int port,
|
||||
const unsigned char *addr, u16 vid, const struct dsa_db db)
|
||||
{
|
||||
@@ -1950,7 +1940,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
+ struct dsa_port *target_dp;
|
||||
+ int fid, ret;
|
||||
+
|
||||
|
||||
+ /* Mirror of the standalone->bridge FID path in fdb_add */
|
||||
+ if (priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q && dsa_is_cpu_port(ds, port) &&
|
||||
+ db.type == DSA_DB_PORT && vid > 0) {
|
||||
@@ -1960,7 +1950,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ mxl862xx_fdb_del_per_fid(ds, addr, vid,
|
||||
+ priv->bridges[target_dp->bridge->num]);
|
||||
+ }
|
||||
|
||||
+
|
||||
+ fid = mxl862xx_get_fid(ds, db);
|
||||
if (fid < 0)
|
||||
return fid;
|
||||
@@ -1974,7 +1964,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
if (ret)
|
||||
dev_err(ds->dev, "failed to remove FDB entry on port %d\n", port);
|
||||
|
||||
@@ -1705,84 +2899,153 @@ static int mxl862xx_port_fdb_dump(struct
|
||||
@@ -1718,84 +2915,153 @@ static int mxl862xx_port_fdb_dump(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2075,7 +2065,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
- sizeof(aparam.port_map));
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
|
||||
- mxl862xx_fw_portmap_set_bit(aparam.port_map, port);
|
||||
+/**
|
||||
+ * mxl862xx_mac_del_host_bridge - Remove every user-port VBP bit from a host
|
||||
+ * FDB/MDB entry, dropping the entry when its
|
||||
@@ -2099,14 +2090,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ struct dsa_port *dp;
|
||||
+ u16 vbp;
|
||||
|
||||
- mxl862xx_fw_portmap_set_bit(aparam.port_map, port);
|
||||
- return MXL862XX_API_WRITE(priv, MXL862XX_MAC_TABLEENTRYADD, aparam);
|
||||
+ dsa_switch_for_each_user_port(dp, ds) {
|
||||
+ vbp = priv->ports[dp->index].bridge_port_cpu;
|
||||
+ if (vbp)
|
||||
+ mxl862xx_fw_portmap_set_bit(del_map, vbp);
|
||||
+ }
|
||||
|
||||
- return MXL862XX_API_WRITE(priv, MXL862XX_MAC_TABLEENTRYADD, aparam);
|
||||
+
|
||||
+ return mxl862xx_mac_portmap_del(priv, addr, fid, vid, del_map);
|
||||
}
|
||||
|
||||
@@ -2120,7 +2110,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
- int fid = mxl862xx_get_fid(ds, db), ret;
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
+ int fid, ret;
|
||||
|
||||
+
|
||||
+ /* tag_8021q host MDB for bridged ports: clear all VBP bits */
|
||||
+ if (priv->tag_proto == DSA_TAG_PROTO_MXL862_8021Q && dsa_is_cpu_port(ds, port) &&
|
||||
+ db.type == DSA_DB_BRIDGE) {
|
||||
@@ -2130,7 +2120,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return mxl862xx_mac_del_host_bridge(ds, mdb->addr,
|
||||
+ mdb->vid, &db.bridge);
|
||||
+ }
|
||||
+
|
||||
|
||||
+ fid = mxl862xx_get_fid(ds, db);
|
||||
if (fid < 0)
|
||||
return fid;
|
||||
@@ -2175,7 +2165,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1867,6 +3130,9 @@ static void mxl862xx_host_flood_work_fn(
|
||||
@@ -1880,6 +3146,9 @@ static void mxl862xx_host_flood_work_fn(
|
||||
host_flood_work);
|
||||
struct mxl862xx_priv *priv = p->priv;
|
||||
struct dsa_switch *ds = priv->ds;
|
||||
@@ -2185,7 +2175,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
@@ -1876,13 +3142,34 @@ static void mxl862xx_host_flood_work_fn(
|
||||
@@ -1889,13 +3158,34 @@ static void mxl862xx_host_flood_work_fn(
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2227,7 +2217,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
rtnl_unlock();
|
||||
}
|
||||
@@ -2248,7 +3535,9 @@ static void mxl862xx_get_stats64(struct
|
||||
@@ -2261,7 +3551,9 @@ static void mxl862xx_get_stats64(struct
|
||||
|
||||
static const struct dsa_switch_ops mxl862xx_switch_ops = {
|
||||
.get_tag_protocol = mxl862xx_get_tag_protocol,
|
||||
@@ -2237,7 +2227,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
.port_setup = mxl862xx_port_setup,
|
||||
.port_teardown = mxl862xx_port_teardown,
|
||||
.phylink_get_caps = mxl862xx_phylink_get_caps,
|
||||
@@ -2270,6 +3559,8 @@ static const struct dsa_switch_ops mxl86
|
||||
@@ -2283,6 +3575,8 @@ static const struct dsa_switch_ops mxl86
|
||||
.port_vlan_filtering = mxl862xx_port_vlan_filtering,
|
||||
.port_vlan_add = mxl862xx_port_vlan_add,
|
||||
.port_vlan_del = mxl862xx_port_vlan_del,
|
||||
@@ -2246,7 +2236,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
.get_strings = mxl862xx_get_strings,
|
||||
.get_sset_count = mxl862xx_get_sset_count,
|
||||
.get_ethtool_stats = mxl862xx_get_ethtool_stats,
|
||||
@@ -2318,6 +3609,8 @@ static int mxl862xx_probe(struct mdio_de
|
||||
@@ -2330,6 +3624,8 @@ static int mxl862xx_probe(struct mdio_de
|
||||
|
||||
INIT_DELAYED_WORK(&priv->stats_work, mxl862xx_stats_work_fn);
|
||||
|
||||
@@ -2255,7 +2245,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
dev_set_drvdata(dev, ds);
|
||||
|
||||
err = dsa_register_switch(ds);
|
||||
@@ -2346,6 +3639,19 @@ static void mxl862xx_remove(struct mdio_
|
||||
@@ -2358,6 +3654,19 @@ static void mxl862xx_remove(struct mdio_
|
||||
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
|
||||
cancel_delayed_work_sync(&priv->stats_work);
|
||||
|
||||
@@ -2277,7 +2267,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
mxl862xx_host_shutdown(priv);
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -209,6 +209,9 @@ struct mxl862xx_port_stats {
|
||||
@@ -212,6 +212,9 @@ struct mxl862xx_port_stats {
|
||||
* @vf: per-port VLAN Filter block state
|
||||
* @ingress_evlan: ingress extended VLAN block state
|
||||
* @egress_evlan: egress extended VLAN block state
|
||||
@@ -2287,7 +2277,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @host_flood_uc: desired host unicast flood state (true = flood);
|
||||
* updated atomically by port_set_host_flood, consumed
|
||||
* by the deferred host_flood_work
|
||||
@@ -223,6 +226,7 @@ struct mxl862xx_port_stats {
|
||||
@@ -226,6 +229,7 @@ struct mxl862xx_port_stats {
|
||||
* periodically by the stats polling work
|
||||
* @stats_lock: protects accumulator reads in .get_stats64 against
|
||||
* concurrent updates from the polling work
|
||||
@@ -2295,7 +2285,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
*/
|
||||
struct mxl862xx_port {
|
||||
struct mxl862xx_priv *priv;
|
||||
@@ -235,9 +239,13 @@ struct mxl862xx_port {
|
||||
@@ -238,9 +242,13 @@ struct mxl862xx_port {
|
||||
struct mxl862xx_vf_block vf;
|
||||
struct mxl862xx_evlan_block ingress_evlan;
|
||||
struct mxl862xx_evlan_block egress_evlan;
|
||||
@@ -2309,7 +2299,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
struct mxl862xx_port_stats stats;
|
||||
spinlock_t stats_lock; /* protects stats accumulators */
|
||||
};
|
||||
@@ -304,6 +312,7 @@ union mxl862xx_fw_version {
|
||||
@@ -298,6 +306,7 @@ struct mxl862xx_fw_version {
|
||||
* before CRC-triggered shutdown and cleared after;
|
||||
* %MXL862XX_FLAG_WORK_STOPPED is set before cancelling
|
||||
* stats_work to prevent rescheduling during teardown
|
||||
@@ -2317,7 +2307,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @drop_meter: index of the single shared zero-rate firmware meter
|
||||
* used to unconditionally drop traffic (used to block
|
||||
* flooding)
|
||||
@@ -318,6 +327,7 @@ union mxl862xx_fw_version {
|
||||
@@ -316,6 +325,7 @@ struct mxl862xx_fw_version {
|
||||
* (0 .. ds->max_num_bridges).
|
||||
* @evlan_ingress_size: per-port ingress Extended VLAN block size
|
||||
* @evlan_egress_size: per-port egress Extended VLAN block size
|
||||
@@ -2325,15 +2315,15 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @vf_block_size: per-port VLAN Filter block size
|
||||
* @cpu_trap_fid: firmware bridge FID allocated for PCE-trapped frames;
|
||||
* configured with uc/mc/bc flood all enabled so that
|
||||
@@ -334,6 +344,7 @@ struct mxl862xx_priv {
|
||||
@@ -332,6 +342,7 @@ struct mxl862xx_priv {
|
||||
struct mdio_device *mdiodev;
|
||||
struct work_struct crc_err_work;
|
||||
unsigned long flags;
|
||||
+ enum dsa_tag_protocol tag_proto;
|
||||
u16 drop_meter;
|
||||
union mxl862xx_fw_version fw_version;
|
||||
struct mxl862xx_fw_version fw_version;
|
||||
struct mxl862xx_pcs serdes_ports[8];
|
||||
@@ -341,6 +352,7 @@ struct mxl862xx_priv {
|
||||
@@ -340,6 +351,7 @@ struct mxl862xx_priv {
|
||||
u16 bridges[MXL862XX_MAX_BRIDGES + 1];
|
||||
u16 evlan_ingress_size;
|
||||
u16 evlan_egress_size;
|
||||
+22
-22
@@ -1,7 +1,7 @@
|
||||
From a32f6a9c09b90e767a03ddac34d061545a0cf15e Mon Sep 17 00:00:00 2001
|
||||
From 4220567bd18b2174c74e90d22f3bf47422c1fdf6 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 03:44:41 +0000
|
||||
Subject: [PATCH 10/20] net: dsa: mxl862xx: add link aggregation support
|
||||
Subject: [PATCH 09/19] net: dsa: mxl862xx: add link aggregation support
|
||||
|
||||
Implement LAG offloading via the firmware's trunking engine. A
|
||||
dedicated firmware bridge port is allocated per LAG and remains
|
||||
@@ -90,8 +90,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
#define INT_GPHY_READ (GPY_GPY2XX_MAGIC + 0x1)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -680,7 +680,42 @@ static int mxl862xx_setup_snooping_traps
|
||||
return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULEWRITE, rule);
|
||||
@@ -695,7 +695,42 @@ static int mxl862xx_setup_snooping_traps
|
||||
return mxl862xx_pce_rule_write(priv, &rule);
|
||||
}
|
||||
|
||||
-static int mxl862xx_set_bridge_port(struct dsa_switch *ds, int port)
|
||||
@@ -134,7 +134,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
{
|
||||
struct mxl862xx_bridge_port_config br_port_cfg = {};
|
||||
struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
@@ -713,8 +748,12 @@ static int mxl862xx_set_bridge_port(stru
|
||||
@@ -728,8 +763,12 @@ static int mxl862xx_set_bridge_port(stru
|
||||
dp->bridge->dev) {
|
||||
if (member_dp->index == port)
|
||||
continue;
|
||||
@@ -149,7 +149,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
}
|
||||
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
mxl862xx_cpu_bridge_port_id(ds, port));
|
||||
@@ -727,7 +766,7 @@ static int mxl862xx_set_bridge_port(stru
|
||||
@@ -742,7 +781,7 @@ static int mxl862xx_set_bridge_port(stru
|
||||
|
||||
bridge_id = dp->bridge ? priv->bridges[dp->bridge->num] : p->fid;
|
||||
|
||||
@@ -158,7 +158,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
br_port_cfg.bridge_id = cpu_to_le16(bridge_id);
|
||||
br_port_cfg.mask = cpu_to_le32(MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_ID |
|
||||
MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP |
|
||||
@@ -808,11 +847,38 @@ static int mxl862xx_set_bridge_port(stru
|
||||
@@ -823,11 +862,38 @@ static int mxl862xx_set_bridge_port(stru
|
||||
br_port_cfg);
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
dsa_switch_for_each_bridge_member(dp, ds, bridge->dev) {
|
||||
err = mxl862xx_set_bridge_port(ds, dp->index);
|
||||
@@ -820,6 +886,25 @@ static int mxl862xx_sync_bridge_members(
|
||||
@@ -835,6 +901,25 @@ static int mxl862xx_sync_bridge_members(
|
||||
ret = err;
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1859,6 +1944,408 @@ static int mxl862xx_setup_cpu_bridge(str
|
||||
@@ -1875,6 +1960,408 @@ static int mxl862xx_setup_cpu_bridge(str
|
||||
return mxl862xx_set_bridge_port(ds, port);
|
||||
}
|
||||
|
||||
@@ -633,7 +633,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
static int mxl862xx_port_bridge_join(struct dsa_switch *ds, int port,
|
||||
const struct dsa_bridge bridge,
|
||||
bool *tx_fwd_offload,
|
||||
@@ -1884,7 +2371,18 @@ static int mxl862xx_port_bridge_join(str
|
||||
@@ -1900,7 +2387,18 @@ static int mxl862xx_port_bridge_join(str
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -653,7 +653,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
}
|
||||
|
||||
static void mxl862xx_port_bridge_leave(struct dsa_switch *ds, int port,
|
||||
@@ -1935,6 +2433,17 @@ static void mxl862xx_port_bridge_leave(s
|
||||
@@ -1951,6 +2449,17 @@ static void mxl862xx_port_bridge_leave(s
|
||||
"failed to update CPU VBP for port %d: %pe\n", port,
|
||||
ERR_PTR(err));
|
||||
|
||||
@@ -671,7 +671,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
if (!dsa_bridge_ports(ds, bridge.dev))
|
||||
mxl862xx_free_bridge(ds, &bridge);
|
||||
}
|
||||
@@ -2593,18 +3102,17 @@ static int mxl862xx_get_fid(struct dsa_s
|
||||
@@ -2609,18 +3118,17 @@ static int mxl862xx_get_fid(struct dsa_s
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -697,7 +697,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
*/
|
||||
static int mxl862xx_fdb_bridge_port(struct dsa_switch *ds, int port,
|
||||
const struct dsa_db db)
|
||||
@@ -2620,7 +3128,7 @@ static int mxl862xx_fdb_bridge_port(stru
|
||||
@@ -2636,7 +3144,7 @@ static int mxl862xx_fdb_bridge_port(stru
|
||||
return bp_cpu;
|
||||
}
|
||||
|
||||
@@ -706,7 +706,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2867,11 +3375,43 @@ static int mxl862xx_port_fdb_del(struct
|
||||
@@ -2883,11 +3391,43 @@ static int mxl862xx_port_fdb_del(struct
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -750,7 +750,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
u32 entry_port_id;
|
||||
int ret;
|
||||
|
||||
@@ -2885,7 +3425,7 @@ static int mxl862xx_port_fdb_dump(struct
|
||||
@@ -2901,7 +3441,7 @@ static int mxl862xx_port_fdb_dump(struct
|
||||
|
||||
entry_port_id = le32_to_cpu(param.port_id);
|
||||
|
||||
@@ -759,7 +759,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
ret = cb(param.mac, FIELD_GET(MXL862XX_TCI_VLAN_ID,
|
||||
le16_to_cpu(param.tci)),
|
||||
param.static_entry, data);
|
||||
@@ -3556,6 +4096,11 @@ static const struct dsa_switch_ops mxl86
|
||||
@@ -3572,6 +4112,11 @@ static const struct dsa_switch_ops mxl86
|
||||
.port_fdb_dump = mxl862xx_port_fdb_dump,
|
||||
.port_mdb_add = mxl862xx_port_mdb_add,
|
||||
.port_mdb_del = mxl862xx_port_mdb_del,
|
||||
@@ -771,7 +771,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
.port_vlan_filtering = mxl862xx_port_vlan_filtering,
|
||||
.port_vlan_add = mxl862xx_port_vlan_add,
|
||||
.port_vlan_del = mxl862xx_port_vlan_del,
|
||||
@@ -3597,6 +4142,7 @@ static int mxl862xx_probe(struct mdio_de
|
||||
@@ -3612,6 +4157,7 @@ static int mxl862xx_probe(struct mdio_de
|
||||
ds->num_ports = MXL862XX_MAX_PORTS;
|
||||
ds->fdb_isolation = true;
|
||||
ds->max_num_bridges = MXL862XX_MAX_BRIDGES;
|
||||
@@ -781,7 +781,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -16,6 +16,19 @@ struct mxl862xx_priv;
|
||||
@@ -19,6 +19,19 @@ struct mxl862xx_priv;
|
||||
#define MXL862XX_MAX_BRIDGE_PORTS 128
|
||||
#define MXL862XX_TOTAL_EVLAN_ENTRIES 1024
|
||||
#define MXL862XX_TOTAL_VF_ENTRIES 1024
|
||||
@@ -801,7 +801,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
/* Number of __le16 words in a firmware portmap (128-bit bitmap). */
|
||||
#define MXL862XX_FW_PORTMAP_WORDS (MXL862XX_MAX_BRIDGE_PORTS / 16)
|
||||
@@ -227,6 +240,12 @@ struct mxl862xx_port_stats {
|
||||
@@ -230,6 +243,12 @@ struct mxl862xx_port_stats {
|
||||
* @stats_lock: protects accumulator reads in .get_stats64 against
|
||||
* concurrent updates from the polling work
|
||||
* @tag_8021q_vid: currently assigned tag_8021q management VID
|
||||
@@ -814,7 +814,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
*/
|
||||
struct mxl862xx_port {
|
||||
struct mxl862xx_priv *priv;
|
||||
@@ -246,6 +265,9 @@ struct mxl862xx_port {
|
||||
@@ -249,6 +268,9 @@ struct mxl862xx_port {
|
||||
struct work_struct host_flood_work;
|
||||
u16 tag_8021q_vid;
|
||||
struct mxl862xx_evlan_block cpu_egress_evlan;
|
||||
@@ -824,7 +824,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
struct mxl862xx_port_stats stats;
|
||||
spinlock_t stats_lock; /* protects stats accumulators */
|
||||
};
|
||||
@@ -336,6 +358,15 @@ union mxl862xx_fw_version {
|
||||
@@ -334,6 +356,15 @@ struct mxl862xx_fw_version {
|
||||
* policy. Set once in setup() and referenced by
|
||||
* fill_cpu_trap_action() via bFidEnable. The PCE FID
|
||||
* action field is 6 bits, so this value must be <= 63.
|
||||
@@ -840,7 +840,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @stats_work: periodic work item that polls RMON hardware counters
|
||||
* and accumulates them into 64-bit per-port stats
|
||||
*/
|
||||
@@ -355,6 +386,8 @@ struct mxl862xx_priv {
|
||||
@@ -354,6 +385,8 @@ struct mxl862xx_priv {
|
||||
u16 cpu_evlan_ingress_size;
|
||||
u16 vf_block_size;
|
||||
u16 cpu_trap_fid;
|
||||
+15
-15
@@ -1,7 +1,7 @@
|
||||
From d919c2f8da9dbd4dda57ceebb5c8b103805b58d1 Mon Sep 17 00:00:00 2001
|
||||
From 8f7296099da5eaedfe5108a6fe93296bcc0c4b45 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 12:05:29 +0000
|
||||
Subject: [PATCH 11/19] net: dsa: mxl862xx: add support for mirror port
|
||||
Subject: [PATCH 10/19] net: dsa: mxl862xx: add support for mirror port
|
||||
|
||||
The MxL862xx hardware supports a single monitor port which can be
|
||||
configured to mirror any other port's ingress and/or egress traffic.
|
||||
@@ -40,17 +40,17 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @age_timer: Custom MAC table aging timer in seconds
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
||||
@@ -30,6 +30,7 @@
|
||||
#define MXL862XX_COMMON_PORTCFGGET (MXL862XX_COMMON_MAGIC + 0x7)
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#define MXL862XX_COMMON_CFGGET (MXL862XX_COMMON_MAGIC + 0x9)
|
||||
#define MXL862XX_COMMON_CFGSET (MXL862XX_COMMON_MAGIC + 0xa)
|
||||
+#define MXL862XX_COMMON_MONITORPORTCFGSET (MXL862XX_COMMON_MAGIC + 0xe)
|
||||
#define MXL862XX_COMMON_REGISTERMOD (MXL862XX_COMMON_MAGIC + 0x11)
|
||||
|
||||
#define MXL862XX_TFLOW_PCERULEWRITE (MXL862XX_TFLOW_MAGIC + 0x2)
|
||||
#define MXL862XX_TFLOW_PCERULEALLOC (MXL862XX_TFLOW_MAGIC + 0x4)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -1100,6 +1100,8 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
@@ -1116,6 +1116,8 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
(n_user_ports + n_cpu_ports);
|
||||
}
|
||||
|
||||
@@ -59,8 +59,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
ret = mxl862xx_setup_drop_meter(ds);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -3167,6 +3169,120 @@ static int mxl862xx_fdb_del_per_fid(stru
|
||||
return MXL862XX_API_WRITE(priv, MXL862XX_MAC_TABLEENTRYREMOVE, param);
|
||||
@@ -1960,6 +1962,120 @@ static int mxl862xx_setup_cpu_bridge(str
|
||||
return mxl862xx_set_bridge_port(ds, port);
|
||||
}
|
||||
|
||||
+static int mxl862xx_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
@@ -178,9 +178,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* mxl862xx_mac_portmap_add - Set port bits in a MAC table entry's portmap
|
||||
* @priv: driver private data
|
||||
@@ -4096,6 +4212,8 @@ static const struct dsa_switch_ops mxl86
|
||||
* mxl862xx_lag_master_port - Find the LAG master (lowest-numbered member)
|
||||
* @ds: DSA switch
|
||||
@@ -4112,6 +4228,8 @@ static const struct dsa_switch_ops mxl86
|
||||
.port_fdb_dump = mxl862xx_port_fdb_dump,
|
||||
.port_mdb_add = mxl862xx_port_mdb_add,
|
||||
.port_mdb_del = mxl862xx_port_mdb_del,
|
||||
@@ -191,7 +191,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
.port_lag_change = mxl862xx_port_lag_change,
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -240,6 +240,8 @@ struct mxl862xx_port_stats {
|
||||
@@ -243,6 +243,8 @@ struct mxl862xx_port_stats {
|
||||
* @stats_lock: protects accumulator reads in .get_stats64 against
|
||||
* concurrent updates from the polling work
|
||||
* @tag_8021q_vid: currently assigned tag_8021q management VID
|
||||
@@ -200,7 +200,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @lag: non-NULL when port is member of a LAG group;
|
||||
* points to the DSA LAG structure
|
||||
* @lag_tx_enabled: true when this port is active for TX in its LAG
|
||||
@@ -265,6 +267,8 @@ struct mxl862xx_port {
|
||||
@@ -268,6 +270,8 @@ struct mxl862xx_port {
|
||||
struct work_struct host_flood_work;
|
||||
u16 tag_8021q_vid;
|
||||
struct mxl862xx_evlan_block cpu_egress_evlan;
|
||||
@@ -209,7 +209,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
struct dsa_lag *lag;
|
||||
bool lag_tx_enabled;
|
||||
u8 lag_hash_bits;
|
||||
@@ -367,6 +371,8 @@ union mxl862xx_fw_version {
|
||||
@@ -365,6 +369,8 @@ struct mxl862xx_fw_version {
|
||||
* @trunk_hash: current global hash field bitmask (6 bits,
|
||||
* MXL862XX_TRUNK_HASH_*); union of all active LAGs'
|
||||
* hash requirements
|
||||
@@ -218,7 +218,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @stats_work: periodic work item that polls RMON hardware counters
|
||||
* and accumulates them into 64-bit per-port stats
|
||||
*/
|
||||
@@ -388,6 +394,7 @@ struct mxl862xx_priv {
|
||||
@@ -387,6 +393,7 @@ struct mxl862xx_priv {
|
||||
u16 cpu_trap_fid;
|
||||
u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1];
|
||||
u8 trunk_hash;
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
From 64269d9d809962a0f7e68e9b618d81e561e3eb6f Mon Sep 17 00:00:00 2001
|
||||
From d11e0b07317e04f347de1b5053bb6720d72fd111 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 16:30:08 +0000
|
||||
Subject: [PATCH 12/19] net: dsa: wire flash_update devlink callback to drivers
|
||||
Subject: [PATCH 11/19] net: dsa: wire flash_update devlink callback to drivers
|
||||
|
||||
Add a devlink_flash_update callback to dsa_switch_ops so that DSA
|
||||
drivers can support devlink dev flash without open-coding the devlink
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
From fed4225f75b6fe6898e48f472cbbee0aaa046760 Mon Sep 17 00:00:00 2001
|
||||
From 4dd558c7422fcd2b5c76994928fe3a65e0059fb4 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 16:30:17 +0000
|
||||
Subject: [PATCH 13/19] net: dsa: mxl862xx: add SMDIO clause-22 register access
|
||||
Subject: [PATCH 12/19] net: dsa: mxl862xx: add SMDIO clause-22 register access
|
||||
|
||||
Add mxl862xx_smdio_read() and mxl862xx_smdio_write() for clause-22
|
||||
SMDIO register access. MCUboot rescue mode only exposes clause-22
|
||||
+8
-9
@@ -1,7 +1,7 @@
|
||||
From fa186b09e346e0b7f2504232731bc9e4dee0c600 Mon Sep 17 00:00:00 2001
|
||||
From 099e70920b16f5da14d34bc00ac58a5ca95c1e33 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 16:30:31 +0000
|
||||
Subject: [PATCH 14/19] net: dsa: mxl862xx: add devlink flash_update and
|
||||
Subject: [PATCH 13/19] net: dsa: mxl862xx: add devlink flash_update and
|
||||
info_get
|
||||
|
||||
Implement runtime firmware upgrade via "devlink dev flash" and version
|
||||
@@ -35,9 +35,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-fw.c | 434 +++++++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-fw.h | 15 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-host.c | 7 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 4 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 3 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.h | 2 +
|
||||
7 files changed, 464 insertions(+), 1 deletion(-)
|
||||
7 files changed, 463 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/net/dsa/mxl862xx/mxl862xx-fw.c
|
||||
create mode 100644 drivers/net/dsa/mxl862xx/mxl862xx-fw.h
|
||||
|
||||
@@ -57,7 +57,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+#define SYS_MISC_FW_UPDATE (SYS_MISC_MAGIC + 0x1)
|
||||
#define SYS_MISC_FW_VERSION (SYS_MISC_MAGIC + 0x2)
|
||||
|
||||
#define MXL862XX_XPCS_MAGIC 0x1a00
|
||||
#define MXL862XX_XPCS_PCS_CONFIG (MXL862XX_XPCS_MAGIC + 0x1)
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-fw.c
|
||||
@@ -0,0 +1,434 @@
|
||||
@@ -546,19 +546,18 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
#include "mxl862xx-host.h"
|
||||
#include "mxl862xx-phylink.h"
|
||||
|
||||
@@ -4233,6 +4234,9 @@ static const struct dsa_switch_ops mxl86
|
||||
@@ -4248,6 +4249,8 @@ static const struct dsa_switch_ops mxl86
|
||||
.get_pause_stats = mxl862xx_get_pause_stats,
|
||||
.get_rmon_stats = mxl862xx_get_rmon_stats,
|
||||
.get_stats64 = mxl862xx_get_stats64,
|
||||
.self_test = mxl862xx_serdes_self_test,
|
||||
+ .devlink_info_get = mxl862xx_devlink_info_get,
|
||||
+ .devlink_flash_update = mxl862xx_devlink_flash_update,
|
||||
+
|
||||
};
|
||||
|
||||
static int mxl862xx_probe(struct mdio_device *mdiodev)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -395,6 +395,8 @@ struct mxl862xx_priv {
|
||||
@@ -394,6 +394,8 @@ struct mxl862xx_priv {
|
||||
u16 lag_bridge_ports[MXL862XX_MAX_LAG_IDS + 1];
|
||||
u8 trunk_hash;
|
||||
int mirror_dest;
|
||||
+6
-6
@@ -1,7 +1,7 @@
|
||||
From 05bc981690d6ef03143a094f28714aa0171ab571 Mon Sep 17 00:00:00 2001
|
||||
From d27d60f42f5188d6cfcb771d2188633f1031646f Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 1 Apr 2026 13:43:08 +0100
|
||||
Subject: [PATCH 15/19] net: dsa: mxl862xx: implement port MTU configuration
|
||||
Subject: [PATCH 14/19] net: dsa: mxl862xx: implement port MTU configuration
|
||||
|
||||
The firmware exposes a global max_packet_len register via
|
||||
MXL862XX_COMMON_CFGSET. Since this is switch-wide rather than
|
||||
@@ -25,7 +25,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_mdio.h>
|
||||
@@ -3727,6 +3728,53 @@ static int mxl862xx_set_ageing_time(stru
|
||||
@@ -3743,6 +3744,53 @@ static int mxl862xx_set_ageing_time(stru
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
static void mxl862xx_port_stp_state_set(struct dsa_switch *ds, int port,
|
||||
u8 state)
|
||||
{
|
||||
@@ -4202,6 +4250,8 @@ static const struct dsa_switch_ops mxl86
|
||||
@@ -4218,6 +4266,8 @@ static const struct dsa_switch_ops mxl86
|
||||
.port_disable = mxl862xx_port_disable,
|
||||
.port_fast_age = mxl862xx_port_fast_age,
|
||||
.set_ageing_time = mxl862xx_set_ageing_time,
|
||||
@@ -90,7 +90,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
.port_pre_bridge_flags = mxl862xx_port_pre_bridge_flags,
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -248,6 +248,8 @@ struct mxl862xx_port_stats {
|
||||
@@ -251,6 +251,8 @@ struct mxl862xx_port_stats {
|
||||
* @lag_hash_bits: hash field bitmask (MXL862XX_TRUNK_HASH_*) requested
|
||||
* when this port joined its LAG; used to recompute the
|
||||
* global trunk_hash when a LAG is destroyed
|
||||
@@ -99,7 +99,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
*/
|
||||
struct mxl862xx_port {
|
||||
struct mxl862xx_priv *priv;
|
||||
@@ -272,6 +274,7 @@ struct mxl862xx_port {
|
||||
@@ -275,6 +277,7 @@ struct mxl862xx_port {
|
||||
struct dsa_lag *lag;
|
||||
bool lag_tx_enabled;
|
||||
u8 lag_hash_bits;
|
||||
+7
-7
@@ -1,7 +1,7 @@
|
||||
From b723f7484006aadbaa51e16b870f3c98390605b1 Mon Sep 17 00:00:00 2001
|
||||
From ba48edffc80f3dd676a9e8cf63aa4778a4ed0f0d Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 1 Apr 2026 13:43:12 +0100
|
||||
Subject: [PATCH 16/19] net: dsa: mxl862xx: support BR_HAIRPIN_MODE bridge flag
|
||||
Subject: [PATCH 15/19] net: dsa: mxl862xx: support BR_HAIRPIN_MODE bridge flag
|
||||
|
||||
Implement hairpin mode by including the port's own bridge port ID in
|
||||
its forwarding portmap. When hairpin is enabled, bridged frames whose
|
||||
@@ -24,7 +24,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -759,6 +759,10 @@ static int __mxl862xx_set_bridge_port(st
|
||||
@@ -774,6 +774,10 @@ static int __mxl862xx_set_bridge_port(st
|
||||
}
|
||||
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
mxl862xx_cpu_bridge_port_id(ds, port));
|
||||
@@ -35,7 +35,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
} else {
|
||||
mxl862xx_fw_portmap_set_bit(br_port_cfg.bridge_port_map,
|
||||
mxl862xx_cpu_bridge_port_id(ds, port));
|
||||
@@ -3895,7 +3899,7 @@ static int mxl862xx_port_pre_bridge_flag
|
||||
@@ -3911,7 +3915,7 @@ static int mxl862xx_port_pre_bridge_flag
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD |
|
||||
@@ -44,7 +44,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -3937,7 +3941,11 @@ static int mxl862xx_port_bridge_flags(st
|
||||
@@ -3953,7 +3957,11 @@ static int mxl862xx_port_bridge_flags(st
|
||||
if (flags.mask & BR_LEARNING)
|
||||
priv->ports[port].learning = !!(flags.val & BR_LEARNING);
|
||||
|
||||
@@ -59,7 +59,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
if (ret)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -240,6 +240,10 @@ struct mxl862xx_port_stats {
|
||||
@@ -243,6 +243,10 @@ struct mxl862xx_port_stats {
|
||||
* @stats_lock: protects accumulator reads in .get_stats64 against
|
||||
* concurrent updates from the polling work
|
||||
* @tag_8021q_vid: currently assigned tag_8021q management VID
|
||||
@@ -70,7 +70,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @ingress_mirror: true when ingress mirroring is active on this port
|
||||
* @egress_mirror: true when egress mirroring is active on this port
|
||||
* @lag: non-NULL when port is member of a LAG group;
|
||||
@@ -269,6 +273,7 @@ struct mxl862xx_port {
|
||||
@@ -272,6 +276,7 @@ struct mxl862xx_port {
|
||||
struct work_struct host_flood_work;
|
||||
u16 tag_8021q_vid;
|
||||
struct mxl862xx_evlan_block cpu_egress_evlan;
|
||||
+8
-8
@@ -1,7 +1,7 @@
|
||||
From d8f20ba50ce0f93f34a41a9b833be76a5d1d2714 Mon Sep 17 00:00:00 2001
|
||||
From 45fcd9669da62b27823004480c07854c54574a1a Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 25 Mar 2026 01:51:33 +0000
|
||||
Subject: [PATCH 17/19] net: dsa: mxl862xx: support BR_ISOLATED bridge flag
|
||||
Subject: [PATCH 16/19] net: dsa: mxl862xx: support BR_ISOLATED bridge flag
|
||||
|
||||
Implement port isolation by excluding isolated ports from each other's
|
||||
forwarding portmaps in sync_bridge_members. Non-isolated ports can
|
||||
@@ -19,7 +19,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -752,6 +752,8 @@ static int __mxl862xx_set_bridge_port(st
|
||||
@@ -767,6 +767,8 @@ static int __mxl862xx_set_bridge_port(st
|
||||
continue;
|
||||
if (!mxl862xx_is_lag_master(priv, member_dp->index))
|
||||
continue;
|
||||
@@ -28,7 +28,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
mxl862xx_fw_portmap_set_bit(
|
||||
br_port_cfg.bridge_port_map,
|
||||
mxl862xx_lag_bridge_port(priv,
|
||||
@@ -3899,7 +3901,7 @@ static int mxl862xx_port_pre_bridge_flag
|
||||
@@ -3915,7 +3917,7 @@ static int mxl862xx_port_pre_bridge_flag
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD |
|
||||
@@ -37,7 +37,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -3912,6 +3914,7 @@ static int mxl862xx_port_bridge_flags(st
|
||||
@@ -3928,6 +3930,7 @@ static int mxl862xx_port_bridge_flags(st
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
unsigned long old_block = priv->ports[port].flood_block;
|
||||
unsigned long block = old_block;
|
||||
@@ -45,7 +45,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
int ret;
|
||||
|
||||
if (flags.mask & BR_FLOOD) {
|
||||
@@ -3952,6 +3955,21 @@ static int mxl862xx_port_bridge_flags(st
|
||||
@@ -3968,6 +3971,21 @@ static int mxl862xx_port_bridge_flags(st
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
||||
@@ -213,6 +213,9 @@ struct mxl862xx_port_stats {
|
||||
@@ -216,6 +216,9 @@ struct mxl862xx_port_stats {
|
||||
* @flood_block: bitmask of firmware meter indices that are currently
|
||||
* rate-limiting flood traffic on this port (zero-rate
|
||||
* meters used to block flooding)
|
||||
@@ -79,7 +79,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
* @learning: true when address learning is enabled on this port
|
||||
* @setup_done: set at end of port_setup, cleared at start of
|
||||
* port_teardown; guards deferred work against
|
||||
@@ -259,6 +262,7 @@ struct mxl862xx_port {
|
||||
@@ -262,6 +265,7 @@ struct mxl862xx_port {
|
||||
struct mxl862xx_priv *priv;
|
||||
u16 fid;
|
||||
unsigned long flood_block;
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
From 8120b9b88ec47ee41b8350e3e4341839f5fdc28e Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 18:17:49 +0000
|
||||
Subject: [PATCH 17/19] DO NOT SUBMIT: net: dsa: mxl862xx: re-introduce PCE
|
||||
workaround for old firmware
|
||||
|
||||
Re-introduce the legacy PCE rule paths needed for firmware versions
|
||||
older than 1.0.83.
|
||||
|
||||
Firmware >= 1.0.83 exposes the new GSW_TFLOW_PCERULELOGICWRITE API
|
||||
which selects the per-CTP block via @region/@logicalportid and grows
|
||||
the hardware block on demand. Older firmware lacks that command and
|
||||
exposes only the legacy GSW_TFLOW_PCERULEWRITE call, where the rule
|
||||
index is a direct offset into a fixed-size pre-allocated CTP block.
|
||||
Add MXL862XX_TFLOW_PCERULEWRITE back to mxl862xx-cmd.h and make
|
||||
mxl862xx_pce_rule_write() pick the right command at runtime based on
|
||||
the cached firmware version.
|
||||
|
||||
In addition, firmware older than 1.0.80 still installs global PCE
|
||||
rules at boot that redirect link-local frames (BPDUs, LLDP, LACP) to
|
||||
port 0 (the on-chip microcontroller) instead of the DSA CPU port.
|
||||
With port 0 disabled under DSA these rules silently drop matching
|
||||
traffic. Re-introduce mxl862xx_disable_fw_global_rules() to clear
|
||||
them out during setup. The upstream submission replaced that call
|
||||
with a dev_warn() since firmware >= 1.0.80 no longer installs the
|
||||
problematic rules.
|
||||
|
||||
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-cmd.h | 1 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx.c | 61 +++++++++++++++++++++----
|
||||
2 files changed, 53 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
||||
@@ -32,6 +32,7 @@
|
||||
#define MXL862XX_COMMON_MONITORPORTCFGSET (MXL862XX_COMMON_MAGIC + 0xe)
|
||||
#define MXL862XX_COMMON_REGISTERMOD (MXL862XX_COMMON_MAGIC + 0x11)
|
||||
|
||||
+#define MXL862XX_TFLOW_PCERULEWRITE (MXL862XX_TFLOW_MAGIC + 0x2)
|
||||
#define MXL862XX_TFLOW_PCERULEALLOC (MXL862XX_TFLOW_MAGIC + 0x4)
|
||||
#define MXL862XX_TFLOW_PCERULEFREE (MXL862XX_TFLOW_MAGIC + 0x5)
|
||||
#define MXL862XX_TFLOW_PCERULELOGICWRITE \
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -449,6 +449,43 @@ static int mxl862xx_setup_drop_meter(str
|
||||
return MXL862XX_API_WRITE(priv, MXL862XX_COMMON_REGISTERMOD, reg);
|
||||
}
|
||||
|
||||
+/* Disable firmware global PCE rules that trap various protocols to the
|
||||
+ * on-die microcontroller (port 0) via PORTMAP_CPU. Under DSA, these
|
||||
+ * frames must either reach the host CPU via per-port rules (link-local)
|
||||
+ * or through the normal bridge forwarding path (ARP broadcast), so the
|
||||
+ * global firmware rules are not needed. With the microcontroller port
|
||||
+ * disabled they would silently drop matching traffic.
|
||||
+ *
|
||||
+ * Global rules have lower indices than CTP rules, hence higher priority
|
||||
+ * in the PCE pipeline -- they must be explicitly disabled or they will
|
||||
+ * shadow the per-CTP traps.
|
||||
+ *
|
||||
+ * Indices from gsw_flow_index.h:
|
||||
+ * 1 -- BPDU (STP/RSTP, dst 01:80:c2:00:00:00)
|
||||
+ * 3 -- LLDP (EtherType 0x88cc)
|
||||
+ * 4 -- OAM/LACP (EtherType 0x8809)
|
||||
+ * 6 -- System MAC (dst 02:e0:92:00:00:01, vendor management MAC)
|
||||
+ * 7 -- ARP Request (broadcast + EtherType 0x0806 + TPA 192.0.2.1)
|
||||
+ */
|
||||
+static int mxl862xx_disable_fw_global_rules(struct dsa_switch *ds)
|
||||
+{
|
||||
+ static const u16 indices[] = { 1, 3, 4, 6, 7 };
|
||||
+ struct mxl862xx_pce_rule rule;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(indices); i++) {
|
||||
+ memset(&rule, 0, sizeof(rule));
|
||||
+ rule.pattern.index = cpu_to_le16(indices[i]);
|
||||
+ /* pattern.enable == 0 -> rule is disabled */
|
||||
+
|
||||
+ ret = MXL862XX_API_WRITE(ds->priv,
|
||||
+ MXL862XX_TFLOW_PCERULEWRITE, rule);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
/* Per-CTP logical indices for protocol trap rules.
|
||||
*
|
||||
@@ -463,16 +500,20 @@ static int mxl862xx_setup_drop_meter(str
|
||||
#define MXL862XX_MLDV1_CTP_INDEX 3
|
||||
#define MXL862XX_MLDV2_CTP_INDEX 4
|
||||
|
||||
-/* Install (or overwrite) a PCE rule via the firmware's logical-index
|
||||
- * API. The firmware translates the logical index in @rule->pattern.index
|
||||
- * to a physical position within the block selected by @rule->region and
|
||||
- * @rule->logicalportid, and expands the hardware block size as needed.
|
||||
+/* Install (or overwrite) a PCE rule. On firmware >= 1.0.83 use the
|
||||
+ * logical-index API (PCERULELOGICWRITE), which grows the per-CTP block
|
||||
+ * on demand. On older firmware that API does not exist, so fall back
|
||||
+ * to the legacy PCERULEWRITE call which uses the rule index as a
|
||||
+ * direct offset into a fixed-size pre-allocated CTP block.
|
||||
*/
|
||||
static int mxl862xx_pce_rule_write(struct mxl862xx_priv *priv,
|
||||
struct mxl862xx_pce_rule *rule)
|
||||
{
|
||||
- return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULELOGICWRITE,
|
||||
- *rule);
|
||||
+ u16 cmd = MXL862XX_FW_VER_MIN(priv, 1, 0, 83) ?
|
||||
+ MXL862XX_TFLOW_PCERULELOGICWRITE :
|
||||
+ MXL862XX_TFLOW_PCERULEWRITE;
|
||||
+
|
||||
+ return MXL862XX_API_WRITE(priv, cmd, *rule);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1130,9 +1171,11 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
|
||||
- dev_warn(ds->dev, "firmware < 1.0.80 installs global PCE rules "
|
||||
- "that interfere with DSA operation, please update\n");
|
||||
+ if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80)) {
|
||||
+ ret = mxl862xx_disable_fw_global_rules(ds);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
/* Pre-allocate firmware resources for all ports. The DSA core
|
||||
* calls change_tag_protocol() between setup() and port_setup(),
|
||||
+491
@@ -0,0 +1,491 @@
|
||||
From 494a1eb62219d9ccb97a60e15ea59e7de2f5d9bc Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 18:19:56 +0000
|
||||
Subject: [PATCH 18/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.84 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 | 244 ++++++++++++++++++++
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 3 +
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 155 ++++++++++++-
|
||||
drivers/net/dsa/mxl862xx/mxl862xx-phylink.h | 3 +
|
||||
4 files changed, 401 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
||||
@@ -2164,6 +2164,18 @@ struct mxl862xx_sys_fw_image_version {
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
+ * enum mxl862xx_port_duplex - Ethernet port duplex status
|
||||
+ * @MXL862XX_DUPLEX_FULL: Port operates in full-duplex mode
|
||||
+ * @MXL862XX_DUPLEX_HALF: Port operates in half-duplex mode
|
||||
+ * @MXL862XX_DUPLEX_AUTO: Port operates in Auto mode
|
||||
+ */
|
||||
+enum mxl862xx_port_duplex {
|
||||
+ MXL862XX_DUPLEX_FULL = 0,
|
||||
+ MXL862XX_DUPLEX_HALF,
|
||||
+ MXL862XX_DUPLEX_AUTO,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
* enum mxl862xx_port_type - Port Type
|
||||
* @MXL862XX_LOGICAL_PORT: Logical Port
|
||||
* @MXL862XX_PHYSICAL_PORT: Physical Port
|
||||
@@ -2178,6 +2190,238 @@ enum mxl862xx_port_type {
|
||||
};
|
||||
|
||||
/**
|
||||
+ * enum mxl862xx_port_enable - port enable type selection.
|
||||
+ * @MXL862XX_PORT_DISABLE: the port is disabled in both directions
|
||||
+ * @MXL862XX_PORT_ENABLE_RXTX: the port is enabled in both directions
|
||||
+ * @MXL862XX_PORT_ENABLE_RX: the port is enabled in the receive direction
|
||||
+ * @MXL862XX_PORT_ENABLE_TX: the port is enabled in the transmit direction
|
||||
+ */
|
||||
+enum mxl862xx_port_enable {
|
||||
+ MXL862XX_PORT_DISABLE = 0,
|
||||
+ MXL862XX_PORT_ENABLE_RXTX,
|
||||
+ MXL862XX_PORT_ENABLE_RX,
|
||||
+ MXL862XX_PORT_ENABLE_TX,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * enum mxl862xx_port_flow - ethernet flow control status
|
||||
+ * @MXL862XX_FLOW_AUTO: automatic flow control
|
||||
+ * @MXL862XX_FLOW_RX: receive flow control only
|
||||
+ * @MXL862XX_FLOW_TX: transmit flow control only
|
||||
+ * @MXL862XX_FLOW_RXTX: receive and transmit flow control
|
||||
+ * @MXL862XX_FLOW_OFF: no flow control
|
||||
+ */
|
||||
+enum mxl862xx_port_flow {
|
||||
+ MXL862XX_FLOW_AUTO = 0,
|
||||
+ MXL862XX_FLOW_RX,
|
||||
+ MXL862XX_FLOW_TX,
|
||||
+ MXL862XX_FLOW_RXTX,
|
||||
+ MXL862XX_FLOW_OFF,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * enum mxl862xx_port_monitor - port mirror options
|
||||
+ * @MXL862XX_PORT_MONITOR_NONE: mirroring is disabled
|
||||
+ * @MXL862XX_PORT_MONITOR_RX: ingress packets are mirrored
|
||||
+ * @MXL862XX_PORT_MONITOR_TX: egress packets are mirrored
|
||||
+ * @MXL862XX_PORT_MONITOR_RXTX: ingress and egress packets are mirrored
|
||||
+ * @MXL862XX_PORT_MONITOR_VLAN_UNKNOWN: mirroring of 'unknown VLAN violation' frames
|
||||
+ * @MXL862XX_PORT_MONITOR_VLAN_MEMBERSHIP: mirroring of 'VLAN ingress or egress membership
|
||||
+ * violation' frames
|
||||
+ * @MXL862XX_PORT_MONITOR_PORT_STATE: mirroring of 'port state violation' frames
|
||||
+ * @MXL862XX_PORT_MONITOR_LEARNING_LIMIT: mirroring of 'MAC learning limit violation' frames
|
||||
+ * @MXL862XX_PORT_MONITOR_PORT_LOCK: mirroring of 'port lock violation' frames
|
||||
+ */
|
||||
+enum mxl862xx_port_monitor {
|
||||
+ MXL862XX_PORT_MONITOR_NONE = 0,
|
||||
+ MXL862XX_PORT_MONITOR_RX,
|
||||
+ MXL862XX_PORT_MONITOR_TX,
|
||||
+ MXL862XX_PORT_MONITOR_RXTX,
|
||||
+ MXL862XX_PORT_MONITOR_VLAN_UNKNOWN,
|
||||
+ MXL862XX_PORT_MONITOR_VLAN_MEMBERSHIP = 16,
|
||||
+ MXL862XX_PORT_MONITOR_PORT_STATE = 32,
|
||||
+ MXL862XX_PORT_MONITOR_LEARNING_LIMIT = 64,
|
||||
+ MXL862XX_PORT_MONITOR_PORT_LOCK = 128,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * enum mxl862xx_if_rmon_mode - interface RMON counter mode
|
||||
+ * @MXL862XX_IF_RMON_FID: FID based RMON counters
|
||||
+ * @MXL862XX_IF_RMON_SUBID: sub-interface ID based
|
||||
+ * @MXL862XX_IF_RMON_FLOWID_LSB: flow ID based (bits 3:0)
|
||||
+ * @MXL862XX_IF_RMON_FLOWID_MSB: flow ID based (bits 7:4)
|
||||
+ */
|
||||
+enum mxl862xx_if_rmon_mode {
|
||||
+ MXL862XX_IF_RMON_FID = 0,
|
||||
+ MXL862XX_IF_RMON_SUBID,
|
||||
+ MXL862XX_IF_RMON_FLOWID_LSB,
|
||||
+ MXL862XX_IF_RMON_FLOWID_MSB,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct mxl862xx_port_cfg - Port Configuration Parameters
|
||||
+ * @port_type: See &enum mxl862xx_port_type
|
||||
+ * @port_id: Ethernet Port number (zero-based counting)
|
||||
+ * @enable: See &enum mxl862xx_port_enable
|
||||
+ * @unicast_unknown_drop: Drop unknown unicast packets
|
||||
+ * @multicast_unknown_drop: Drop unknown multicast packets
|
||||
+ * @reserved_packet_drop: Drop reserved packet types
|
||||
+ * @broadcast_drop: Drop broadcast packets
|
||||
+ * @aging: Enables MAC address table aging.
|
||||
+ * @learning: MAC address table learning
|
||||
+ * @learning_mac_port_lock: Automatic MAC address table learning locking on the port
|
||||
+ * @learning_limit: Automatic MAC address table learning limitation on this port
|
||||
+ * @mac_spoofing_detection: MAC spoofing detection. Identifies ingress packets that carry
|
||||
+ * a MAC source address which was previously learned on a different ingress port
|
||||
+ * @flow_ctrl: See &enum mxl862xx_port_flow
|
||||
+ * @port_monitor: See &enum mxl862xx_port_monitor
|
||||
+ * @if_counters: Assign Interface RMON Counters for this Port
|
||||
+ * @if_count_start_idx: Interface RMON Counters Start Index
|
||||
+ * @if_rmonmode: See &enum mxl862xx_if_rmon_mode
|
||||
+ */
|
||||
+struct mxl862xx_port_cfg {
|
||||
+ __le32 port_type; /* enum mxl862xx_port_type */
|
||||
+ __le16 port_id;
|
||||
+ __le32 enable; /* enum mxl862xx_port_enable */
|
||||
+ u8 unicast_unknown_drop;
|
||||
+ u8 multicast_unknown_drop;
|
||||
+ u8 reserved_packet_drop;
|
||||
+ u8 broadcast_drop;
|
||||
+ u8 aging;
|
||||
+ u8 learning;
|
||||
+ u8 learning_mac_port_lock;
|
||||
+ __le16 learning_limit;
|
||||
+ u8 mac_spoofing_detection;
|
||||
+ __le32 flow_ctrl; /* enum mxl862xx_port_flow */
|
||||
+ __le32 port_monitor; /* enum mxl862xx_port_monitor */
|
||||
+ u8 if_counters;
|
||||
+ __le32 if_count_start_idx;
|
||||
+ __le32 if_rmonmode; /* enum mxl862xx_if_rmon_mode */
|
||||
+} __packed;
|
||||
+
|
||||
+/**
|
||||
+ * enum mxl862xx_port_speed - Ethernet port speed mode
|
||||
+ * @MXL862XX_PORT_SPEED_10: 10 Mbit/s
|
||||
+ * @MXL862XX_PORT_SPEED_100: 100 Mbit/s
|
||||
+ * @MXL862XX_PORT_SPEED_200: 200 Mbit/s
|
||||
+ * @MXL862XX_PORT_SPEED_1000: 1000 Mbit/s
|
||||
+ * @MXL862XX_PORT_SPEED_2500: 2.5 Gbit/s
|
||||
+ * @MXL862XX_PORT_SPEED_5000: 5 Gbit/s
|
||||
+ * @MXL862XX_PORT_SPEED_10000: 10 Gbit/s
|
||||
+ * @MXL862XX_PORT_SPEED_AUTO: Auto speed for XGMAC
|
||||
+ */
|
||||
+enum mxl862xx_port_speed {
|
||||
+ MXL862XX_PORT_SPEED_10 = 0,
|
||||
+ MXL862XX_PORT_SPEED_100,
|
||||
+ MXL862XX_PORT_SPEED_200,
|
||||
+ MXL862XX_PORT_SPEED_1000,
|
||||
+ MXL862XX_PORT_SPEED_2500,
|
||||
+ MXL862XX_PORT_SPEED_5000,
|
||||
+ MXL862XX_PORT_SPEED_10000,
|
||||
+ MXL862XX_PORT_SPEED_AUTO,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * enum mxl862xx_port_link - Force the MAC and PHY link modus
|
||||
+ * @MXL862XX_PORT_LINK_UP: Link up
|
||||
+ * @MXL862XX_PORT_LINK_DOWN: Link down
|
||||
+ * @MXL862XX_PORT_LINK_AUTO: Link Auto
|
||||
+ */
|
||||
+enum mxl862xx_port_link {
|
||||
+ MXL862XX_PORT_LINK_UP = 0,
|
||||
+ MXL862XX_PORT_LINK_DOWN,
|
||||
+ MXL862XX_PORT_LINK_AUTO,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * enum mxl862xx_mii_mode - Ethernet port interface mode
|
||||
+ * @MXL862XX_PORT_HW_MII: Normal PHY interface
|
||||
+ * @MXL862XX_PORT_HW_RMII: Reduced MII interface in normal mode
|
||||
+ * @MXL862XX_PORT_HW_GMII: GMII or MII, depending upon the speed
|
||||
+ * @MXL862XX_PORT_HW_RGMII: RGMII mode
|
||||
+ * @MXL862XX_PORT_HW_XGMII: XGMII mode
|
||||
+ */
|
||||
+enum mxl862xx_mii_mode {
|
||||
+ MXL862XX_PORT_HW_MII = 0,
|
||||
+ MXL862XX_PORT_HW_RMII,
|
||||
+ MXL862XX_PORT_HW_GMII,
|
||||
+ MXL862XX_PORT_HW_RGMII,
|
||||
+ MXL862XX_PORT_HW_XGMII,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * enum mxl862xx_mii_type - Ethernet port configuration for PHY or MAC mode
|
||||
+ * @MXL862XX_PORT_MAC: The Ethernet port is configured to work in MAC mode
|
||||
+ * @MXL862XX_PORT_PHY: The Ethernet port is configured to work in PHY mode
|
||||
+ */
|
||||
+enum mxl862xx_mii_type {
|
||||
+ MXL862XX_PORT_MAC = 0,
|
||||
+ MXL862XX_PORT_PHY,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * enum mxl862xx_clk_mode - Ethernet port clock source configuration
|
||||
+ * @MXL862XX_PORT_CLK_NA: Clock Mode not applicable
|
||||
+ * @MXL862XX_PORT_CLK_MASTER: Clock Master Mode.
|
||||
+ * @MXL862XX_PORT_CLK_SLAVE: Clock Slave Mode.
|
||||
+ */
|
||||
+enum mxl862xx_clk_mode {
|
||||
+ MXL862XX_PORT_CLK_NA = 0,
|
||||
+ MXL862XX_PORT_CLK_MASTER,
|
||||
+ MXL862XX_PORT_CLK_SLAVE,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct mxl862xx_port_link_cfg - Ethernet port link, speed status and flow control status
|
||||
+ * @port_id: Ethernet Port number
|
||||
+ * @duplex_force: Force Port Duplex Mode
|
||||
+ * @duplex: See &enum mxl862xx_port_duplex
|
||||
+ * @speed_force: Force Link Speed
|
||||
+ * @speed: See &enum mxl862xx_port_speed
|
||||
+ * @link_force: Force Link
|
||||
+ * @link: See &enum mxl862xx_port_link
|
||||
+ * @mii_mode: See &enum mxl862xx_mii_mode
|
||||
+ * @mii_type: See &enum mxl862xx_mii_type
|
||||
+ * @clk_mode: See &enum mxl862xx_clk_mode
|
||||
+ * @lpi: 'Low Power Idle' Support for 'Energy Efficient Ethernet'
|
||||
+ */
|
||||
+struct mxl862xx_port_link_cfg {
|
||||
+ __le16 port_id;
|
||||
+ u8 duplex_force;
|
||||
+ __le32 duplex; /* enum mxl862xx_port_duplex */
|
||||
+ u8 speed_force;
|
||||
+ __le32 speed; /* enum mxl862xx_port_speed */
|
||||
+ u8 link_force;
|
||||
+ __le32 link; /* enum mxl862xx_port_link */
|
||||
+ __le32 mii_mode; /* enum mxl862xx_mii_mode */
|
||||
+ __le32 mii_type; /* enum mxl862xx_mii_type */
|
||||
+ __le32 clk_mode; /* enum mxl862xx_clk_mode */
|
||||
+ u8 lpi;
|
||||
+} __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
|
||||
@@ -27,6 +27,8 @@
|
||||
#define SYS_MISC_MAGIC 0x1900
|
||||
#define MXL862XX_XPCS_MAGIC 0x1a00
|
||||
|
||||
+#define MXL862XX_COMMON_PORTLINKCFGGET (MXL862XX_COMMON_MAGIC + 0x5)
|
||||
+#define MXL862XX_COMMON_PORTCFGGET (MXL862XX_COMMON_MAGIC + 0x7)
|
||||
#define MXL862XX_COMMON_CFGGET (MXL862XX_COMMON_MAGIC + 0x9)
|
||||
#define MXL862XX_COMMON_CFGSET (MXL862XX_COMMON_MAGIC + 0xa)
|
||||
#define MXL862XX_COMMON_MONITORPORTCFGSET (MXL862XX_COMMON_MAGIC + 0xe)
|
||||
@@ -86,6 +88,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_PCS_CONFIG (MXL862XX_XPCS_MAGIC + 0x1)
|
||||
#define MXL862XX_XPCS_PCS_GET_STATE (MXL862XX_XPCS_MAGIC + 0x2)
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c
|
||||
@@ -62,6 +62,153 @@ static struct mxl862xx_pcs *pcs_to_mxl86
|
||||
return container_of(pcs, struct mxl862xx_pcs, pcs);
|
||||
}
|
||||
|
||||
+/* Legacy SFP-based PCS implementation for firmware < 1.0.84 */
|
||||
+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_pcs *mpcs = pcs_to_mxl862xx_pcs(pcs);
|
||||
+ struct mxl862xx_priv *priv = mpcs->priv;
|
||||
+ struct mxl862xx_sys_sfp_cfg ser_intf = {
|
||||
+ .option = 0,
|
||||
+ .mode = 1,
|
||||
+ };
|
||||
+
|
||||
+ if (mpcs->slot != 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ ser_intf.port_id = mpcs->serdes_id;
|
||||
+
|
||||
+ 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_pcs *mpcs = pcs_to_mxl862xx_pcs(pcs);
|
||||
+ struct mxl862xx_priv *priv = mpcs->priv;
|
||||
+ struct mxl862xx_port_link_cfg port_link_cfg = {
|
||||
+ .port_id = cpu_to_le16(MXL862XX_PCS_PORT(mpcs)),
|
||||
+ };
|
||||
+ struct mxl862xx_port_cfg port_cfg = {
|
||||
+ .port_id = cpu_to_le16(MXL862XX_PCS_PORT(mpcs)),
|
||||
+ };
|
||||
+ 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 = (le32_to_cpu(port_link_cfg.link) == MXL862XX_PORT_LINK_UP);
|
||||
+ state->an_complete = state->link;
|
||||
+
|
||||
+ switch (le32_to_cpu(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 (le32_to_cpu(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 (le32_to_cpu(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_if_mode(phy_interface_t interface)
|
||||
{
|
||||
switch (interface) {
|
||||
@@ -352,7 +499,10 @@ void mxl862xx_setup_pcs(struct mxl862xx_
|
||||
pcs->slot = MXL862XX_SERDES_SLOT(port);
|
||||
pcs->interface = PHY_INTERFACE_MODE_NA;
|
||||
|
||||
- pcs->pcs.ops = &mxl862xx_pcs_ops;
|
||||
+ if (MXL862XX_FW_VER_MIN(priv, 1, 0, 84))
|
||||
+ pcs->pcs.ops = &mxl862xx_pcs_ops;
|
||||
+ else
|
||||
+ pcs->pcs.ops = &mxl862xx_legacy_pcs_ops;
|
||||
pcs->pcs.poll = true;
|
||||
|
||||
__set_bit(PHY_INTERFACE_MODE_QSGMII, pcs->pcs.supported_interfaces);
|
||||
@@ -376,9 +526,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, 84))
|
||||
- return NULL;
|
||||
-
|
||||
switch (port) {
|
||||
case 9 ... 16:
|
||||
return &priv->serdes_ports[port - 9].pcs;
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.h
|
||||
@@ -11,6 +11,9 @@
|
||||
(((port) - MXL862XX_FIRST_SERDES_PORT) % MXL862XX_SERDES_SLOTS)
|
||||
#define MXL862XX_SERDES_PORT_ID(port) \
|
||||
(((port) - MXL862XX_FIRST_SERDES_PORT) / MXL862XX_SERDES_SLOTS)
|
||||
+#define MXL862XX_PCS_PORT(mpcs) \
|
||||
+ (MXL862XX_FIRST_SERDES_PORT + \
|
||||
+ (mpcs)->serdes_id * MXL862XX_SERDES_SLOTS + (mpcs)->slot)
|
||||
|
||||
extern const struct phylink_mac_ops mxl862xx_phylink_mac_ops;
|
||||
void mxl862xx_phylink_get_caps(struct dsa_switch *ds, int port,
|
||||
-81
@@ -1,81 +0,0 @@
|
||||
From 8856f7610167a3005ecef401c8528111d153b554 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 24 Mar 2026 18:17:49 +0000
|
||||
Subject: [PATCH 18/19] DO NOT SUBMIT: net: dsa: mxl862xx: re-introduce PCE
|
||||
workaround for old firmware
|
||||
|
||||
Re-introduce the mxl862xx_disable_fw_global_rules() function that
|
||||
disables firmware default global PCE rules for firmware versions
|
||||
older than 1.0.80. The upstream submission replaced this with a
|
||||
dev_warn() since firmware >= 1.0.80 no longer installs these rules,
|
||||
but downstream deployments may still run older firmware.
|
||||
|
||||
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.c | 45 +++++++++++++++++++++++++++--
|
||||
1 file changed, 42 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
||||
@@ -449,6 +449,43 @@ static int mxl862xx_setup_drop_meter(str
|
||||
return MXL862XX_API_WRITE(priv, MXL862XX_COMMON_REGISTERMOD, reg);
|
||||
}
|
||||
|
||||
+/* Disable firmware global PCE rules that trap various protocols to the
|
||||
+ * on-die microcontroller (port 0) via PORTMAP_CPU. Under DSA, these
|
||||
+ * frames must either reach the host CPU via per-port rules (link-local)
|
||||
+ * or through the normal bridge forwarding path (ARP broadcast), so the
|
||||
+ * global firmware rules are not needed. With the microcontroller port
|
||||
+ * disabled they would silently drop matching traffic.
|
||||
+ *
|
||||
+ * Global rules have lower indices than CTP rules, hence higher priority
|
||||
+ * in the PCE pipeline -- they must be explicitly disabled or they will
|
||||
+ * shadow the per-CTP traps.
|
||||
+ *
|
||||
+ * Indices from gsw_flow_index.h:
|
||||
+ * 1 -- BPDU (STP/RSTP, dst 01:80:c2:00:00:00)
|
||||
+ * 3 -- LLDP (EtherType 0x88cc)
|
||||
+ * 4 -- OAM/LACP (EtherType 0x8809)
|
||||
+ * 6 -- System MAC (dst 02:e0:92:00:00:01, vendor management MAC)
|
||||
+ * 7 -- ARP Request (broadcast + EtherType 0x0806 + TPA 192.0.2.1)
|
||||
+ */
|
||||
+static int mxl862xx_disable_fw_global_rules(struct dsa_switch *ds)
|
||||
+{
|
||||
+ static const u16 indices[] = { 1, 3, 4, 6, 7 };
|
||||
+ struct mxl862xx_pce_rule rule;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(indices); i++) {
|
||||
+ memset(&rule, 0, sizeof(rule));
|
||||
+ rule.pattern.index = cpu_to_le16(indices[i]);
|
||||
+ /* pattern.enable == 0 -> rule is disabled */
|
||||
+
|
||||
+ ret = MXL862XX_API_WRITE(ds->priv,
|
||||
+ MXL862XX_TFLOW_PCERULEWRITE, rule);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
/* Per-CTP offsets for protocol trap rules. Each port's CTP flow-table
|
||||
* block is pre-allocated by the firmware during init (44 entries per
|
||||
@@ -1114,9 +1151,11 @@ static int mxl862xx_setup(struct dsa_swi
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80))
|
||||
- dev_warn(ds->dev, "firmware < 1.0.80 installs global PCE rules "
|
||||
- "that interfere with DSA operation, please update\n");
|
||||
+ if (!MXL862XX_FW_VER_MIN(priv, 1, 0, 80)) {
|
||||
+ ret = mxl862xx_disable_fw_global_rules(ds);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
/* Pre-allocate firmware resources for all ports. The DSA core
|
||||
* calls change_tag_protocol() between setup() and port_setup(),
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
From df0c747216063041ba0d786b01f9b1e2aba5316a Mon Sep 17 00:00:00 2001
|
||||
From 332dd61f50b096256f889ecb4d730d385e58aec2 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 22 Apr 2026 15:15:52 +0100
|
||||
Subject: [PATCH] DO NOT SUBMIT: net: dsa: mxl862xx: increase CMD timeout
|
||||
Subject: [PATCH 19/19] DO NOT SUBMIT: net: dsa: mxl862xx: increase CMD timeout
|
||||
|
||||
Lift the command timeout by 10x from 500ms to 5s.
|
||||
This is done because older firmware can be extremely slow to respond
|
||||
-252
@@ -1,252 +0,0 @@
|
||||
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 = {};
|
||||
Reference in New Issue
Block a user