From d3790c25a1072d3318c071099ca2024a218702bd Mon Sep 17 00:00:00 2001 From: Mihai Ordean Date: Mon, 3 Aug 2026 06:17:23 +0000 Subject: [PATCH 1/3] net: dsa: mxl862xx: do not count transmit drops as transmit errors mxl862xx_stats_poll() adds the delta of tx_dropped_pkts to both rtnl_link_stats64.tx_errors and rtnl_link_stats64.tx_dropped, so every frame the switch drops on egress is reported twice, once under a field that is meant for a different thing. A drop is not an error. tx_errors is defined as the number of packets that could not be transmitted because of a fault, while tx_dropped covers packets discarded for lack of a resource - a full queue being the normal case. Conflating them makes a congested port look like a failing one, and inflates the total error count that monitoring tools key on. Drop the tx_errors contribution and leave the counter in tx_dropped, where the hardware's own naming puts it. tx_errors then has no contributor; the natural source for it would be tx_excess_coll_count, which the poll does not currently read, and adding that is a separate change. The mxl862xx driver is not upstream, so there is no commit to name in a Fixes: tag. Signed-off-by: Mihai Ordean --- drivers/net/dsa/mxl862xx/mxl862xx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/dsa/mxl862xx/mxl862xx.c b/drivers/net/dsa/mxl862xx/mxl862xx.c index 5bde382a8290..eb4cc8c868c3 100644 --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c @@ -4412,8 +4412,6 @@ static void mxl862xx_stats_poll(struct dsa_switch *ds, int port) mxl862xx_delta32(rx_under, s->prev_rx_under_size_error_pkts) + mxl862xx_delta32(rx_over, s->prev_rx_oversize_error_pkts) + mxl862xx_delta32(rx_align, s->prev_rx_align_error_pkts); - s->tx_errors += - mxl862xx_delta32(tx_drop, s->prev_tx_dropped_pkts); s->rx_dropped += mxl862xx_delta32(rx_drop, s->prev_rx_dropped_pkts) + From 5146689887df15e554e27d04966f991a4e5dc26e Mon Sep 17 00:00:00 2001 From: Mihai Ordean Date: Wed, 5 Aug 2026 00:37:15 +0000 Subject: [PATCH 2/3] net: dsa: mxl862xx: report link down when the PCS state read fails phylink_mac_pcs_get_state() presets state->link = 1 before invoking the pcs_get_state() callback. Both the legacy and the XPCS implementations return early when the firmware mailbox read fails (or, in the XPCS path, when the interface mode is unknown), leaving the preset link-up in place with SPEED_UNKNOWN and no negotiated pause. A transient mailbox timeout is then reported to phylink as a valid link. Initialize state->link to false on entry in both implementations so any early exit reports link down, which phylink handles correctly by retrying on the next poll. Signed-off-by: Mihai Ordean --- drivers/net/dsa/mxl862xx/mxl862xx-phylink.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c index 8fdfb689333c..e64537b7b0e2 100644 --- a/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx-phylink.c @@ -114,6 +114,12 @@ static void mxl862xx_legacy_pcs_get_state(struct phylink_pcs *pcs, }; int ret; + /* phylink presets state->link = 1 before calling pcs_get_state(); + * make sure a failed firmware read reports link down instead of a + * spurious link up with SPEED_UNKNOWN. + */ + state->link = false; + ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTLINKCFGGET, port_link_cfg); if (ret) @@ -409,6 +415,12 @@ static void mxl862xx_pcs_get_state(struct phylink_pcs *pcs, int if_mode, ret; u16 fw_speed, lpa, bmsr; + /* phylink presets state->link = 1 before calling pcs_get_state(); + * make sure a failed firmware read reports link down instead of a + * spurious link up with SPEED_UNKNOWN. + */ + state->link = false; + if_mode = mxl862xx_xpcs_if_mode(state->interface); if (if_mode < 0) return; From 894796752b9044f9e75ab8a8ef1d7f18b895ba3b Mon Sep 17 00:00:00 2001 From: Mihai Ordean Date: Sat, 8 Aug 2026 12:12:18 +0000 Subject: [PATCH 3/3] net: dsa: tag_mxl862xx: assign per-port conduit TX queues mtk_eth_soc gives each DSA user port its own QDMA transmit queue: mtk_select_queue() maps a switch-bound frame onto queue skb_get_queue_mapping(skb) + 3, and mtk_device_event() programs that queue's scheduler entry (rate and WRR weight) from the user port's resolved link speed on every NETDEV_CHANGE. The contract, established by tag_mtk.c, is that the tagger stamps the originating port index into the skb queue mapping on xmit. Neither MxL862xx tagger does, so every frame reaches the conduit with the queue mapping still 0 from the single-queue user netdev: - all switch-bound traffic from every user port serialises onto QDMA queue 3 regardless of destination port or tagger; - queue 3 belongs to port index 0, which is not a user port on any MxL862xx board, so its scheduler entry is never programmed after mtk_dma_tx_alloc() and runs with a WRR weight of zero and no configured rate; - the per-port queues that mtk_device_event() does program (queues 4-7 for lan1-lan4 on the MxL86252C) carry no traffic at all. Stamp dp->index in both taggers, as tag_mtk does. Ports 0-12 then use their programmed per-port queues. Ports 13 and above still fold back to queue 0 in mtk_select_queue() because their queue index would exceed the 16-entry array; that is unchanged behaviour and a mtk_eth_soc limitation, not a tagger one. Signed-off-by: Mihai Ordean --- net/dsa/tag_mxl862xx.c | 3 +++ net/dsa/tag_mxl862xx_8021q.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/net/dsa/tag_mxl862xx.c b/net/dsa/tag_mxl862xx.c index 882415f46afb..0d81ae8df11c 100644 --- a/net/dsa/tag_mxl862xx.c +++ b/net/dsa/tag_mxl862xx.c @@ -53,6 +53,9 @@ static struct sk_buff *mxl862_tag_xmit(struct sk_buff *skb, mxl862_tag[2] = htons(FIELD_PREP(MXL862_SUBIF_ID, sub_interface)); mxl862_tag[3] = htons(FIELD_PREP(MXL862_IGP_EGP, cpu_port)); + /* Tag the frame for the conduit's per-port TX queue */ + skb_set_queue_mapping(skb, dp->index); + return skb; } diff --git a/net/dsa/tag_mxl862xx_8021q.c b/net/dsa/tag_mxl862xx_8021q.c index ba2bc52291bf..9b74de3c71ae 100644 --- a/net/dsa/tag_mxl862xx_8021q.c +++ b/net/dsa/tag_mxl862xx_8021q.c @@ -23,6 +23,9 @@ static struct sk_buff *mxl862_8021q_xmit(struct sk_buff *skb, u16 queue_mapping = skb_get_queue_mapping(skb); u8 pcp = netdev_txq_to_tc(netdev, queue_mapping); + /* Tag the frame for the conduit's per-port TX queue */ + skb_set_queue_mapping(skb, dp->index); + return dsa_8021q_xmit(skb, netdev, ETH_P_8021Q, (pcp << VLAN_PRIO_SHIFT) | tx_vid); }