[PATCH net v2 4/4] net: sb1250-mac: Fix RX checksum status and header offset setup
From: Florian Fainelli
Date: Tue Nov 10 2026 - 18:59:03 EST
The receive path tests M_DMA_ETHRX_BADTCPCS in descriptor A, but the
hardware reports it in descriptor B. Bit zero of descriptor A belongs
to the buffer address and is clear for the aligned receive buffers.
Consequently, a frame with a valid IPv4 checksum and a bad TCP checksum
can be marked CHECKSUM_UNNECESSARY. Read the TCP status from descriptor B.
The IP header offset setup also only masks the old register value due
to the combined AND/OR expression. Split the mask and field assignment
so that the intended offset of 15 is actually programmed.
Channel startup clears the receive filter register, losing any offset
set during probe. Program it again before enabling reception on every
channel start, including link changes, and preserve it when enabling
unicast and broadcast reception.
Both bugs predate the RX checksum feature advertisement. Sashiko AI
reported them during review of that change.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Florian Fainelli <f.fainelli@xxxxxxxxx>
---
drivers/net/ethernet/broadcom/sb1250-mac.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c
index 433aa1e24439..7998ab9fc46c 100644
--- a/drivers/net/ethernet/broadcom/sb1250-mac.c
+++ b/drivers/net/ethernet/broadcom/sb1250-mac.c
@@ -280,6 +280,7 @@ static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d,
int poll);
static int sbmac_initctx(struct sbmac_softc *s);
static void sbmac_channel_start(struct sbmac_softc *s);
+static void sbmac_set_iphdr_offset(struct sbmac_softc *sc);
static void sbmac_channel_stop(struct sbmac_softc *s);
static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *,
enum sbmac_state);
@@ -1145,7 +1146,7 @@ static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d,
/* Honor the RX checksum offload feature setting. */
if (dev->features & NETIF_F_RXCSUM) {
if (!((dsc->dscr_a) & M_DMA_ETHRX_BADIP4CS) &&
- !((dsc->dscr_a) & M_DMA_ETHRX_BADTCPCS)) {
+ !((dsc->dscr_b) & M_DMA_ETHRX_BADTCPCS)) {
sb->ip_summed = CHECKSUM_UNNECESSARY;
/* don't need to set sb->csum */
} else {
@@ -1496,6 +1497,7 @@ static void sbmac_channel_start(struct sbmac_softc *s)
*/
__raw_writeq(0, s->sbm_rxfilter);
+ sbmac_set_iphdr_offset(s);
__raw_writeq(0, s->sbm_imr);
__raw_writeq(framecfg, s->sbm_framecfg);
__raw_writeq(fifo, s->sbm_fifocfg);
@@ -1549,7 +1551,9 @@ static void sbmac_channel_start(struct sbmac_softc *s)
* Enable receiving unicasts and broadcasts
*/
- __raw_writeq(M_MAC_UCAST_EN | M_MAC_BCAST_EN, s->sbm_rxfilter);
+ reg = __raw_readq(s->sbm_rxfilter);
+ reg |= M_MAC_UCAST_EN | M_MAC_BCAST_EN;
+ __raw_writeq(reg, s->sbm_rxfilter);
/*
* we're running now.
@@ -1717,7 +1721,8 @@ static void sbmac_set_iphdr_offset(struct sbmac_softc *sc)
/* Hard code the off set to 15 for now */
reg = __raw_readq(sc->sbm_rxfilter);
- reg &= ~M_MAC_IPHDR_OFFSET | V_MAC_IPHDR_OFFSET(15);
+ reg &= ~M_MAC_IPHDR_OFFSET;
+ reg |= V_MAC_IPHDR_OFFSET(15);
__raw_writeq(reg, sc->sbm_rxfilter);
/* BCM1250 pass1 didn't have hardware checksum. Everything
--
2.53.0