* [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup
@ 2026-11-07 13:20 David Yang
2026-11-07 13:20 ` [PATCH net-next 1/4] net: dsa: motorcomm: Fix stats64 error counter mapping David Yang
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: David Yang @ 2026-11-07 13:20 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
Various MIB defects reported by LLM. While they do actually "fix"
something, the odds are extremely low and all depend on very specified
transient conditions. Since MIBs are not control path related and nearly
nobody would notice them, target them to net-next.
David Yang (4):
net: dsa: motorcomm: Fix stats64 error counter mapping
net: dsa: motorcomm: Fix RMON fragments stat
net: dsa: motorcomm: Use safe 64-bit counter reader
net: dsa: motorcomm: Prevent rx_bytes/tx_bytes underflow
drivers/net/dsa/motorcomm/mib.c | 62 ++++++++++++++++++---------------
drivers/net/dsa/motorcomm/mib.h | 2 ++
drivers/net/dsa/motorcomm/smi.c | 35 +++++++++++++++++++
drivers/net/dsa/motorcomm/smi.h | 2 ++
4 files changed, 73 insertions(+), 28 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next 1/4] net: dsa: motorcomm: Fix stats64 error counter mapping
2026-11-07 13:20 [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup David Yang
@ 2026-11-07 13:20 ` David Yang
2026-11-07 13:20 ` [PATCH net-next 2/4] net: dsa: motorcomm: Fix RMON fragments stat David Yang
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: David Yang @ 2026-11-07 13:20 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
rtnl_link_stats64 wants aFrameTooLongErrors in rx_length_errors, and the
eth-mac stats already report the oversize counter there as
FrameTooLongErrors; move it from rx_over_errors, which is a RX FIFO
overflow counter.
Drop the tx_undersize to tx_fifo_errors mapping as well; a runt frame is
not a FIFO underrun. Report it as a TxUndersize ethtool stat instead.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/mib.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/mib.c b/drivers/net/dsa/motorcomm/mib.c
index 6b170fc6e187..5c027edb71e3 100644
--- a/drivers/net/dsa/motorcomm/mib.c
+++ b/drivers/net/dsa/motorcomm/mib.c
@@ -50,7 +50,7 @@ static const struct yt921x_mib_desc yt921x_mib_descs[] = {
MIB_DESC(1, YT921X_MIB_DATA_TX_PAUSE, NULL),
MIB_DESC(1, YT921X_MIB_DATA_TX_MULTICAST, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_TX_UNDERSIZE_ERR, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_TX_UNDERSIZE_ERR, "TxUndersize"),
MIB_DESC(1, YT921X_MIB_DATA_TX_PKT_SZ_64, NULL),
MIB_DESC(1, YT921X_MIB_DATA_TX_PKT_SZ_65_TO_127, NULL),
MIB_DESC(1, YT921X_MIB_DATA_TX_PKT_SZ_128_TO_255, NULL),
@@ -376,8 +376,9 @@ yt921x_dsa_get_stats64(struct dsa_switch *ds, int port,
start = u64_stats_fetch_begin(&pm->syncp);
stats->rx_length_errors = u64_stats_read(&mib->rx_undersize_errors) +
- u64_stats_read(&mib->rx_fragment_errors);
- stats->rx_over_errors = u64_stats_read(&mib->rx_oversize_errors);
+ u64_stats_read(&mib->rx_fragment_errors) +
+ u64_stats_read(&mib->rx_oversize_errors);
+ /* stats->rx_over_errors */
stats->rx_crc_errors = u64_stats_read(&mib->rx_crc_errors);
stats->rx_frame_errors = u64_stats_read(&mib->rx_alignment_errors);
/* stats->rx_fifo_errors */
@@ -385,7 +386,7 @@ yt921x_dsa_get_stats64(struct dsa_switch *ds, int port,
stats->tx_aborted_errors = u64_stats_read(&mib->tx_aborted_errors);
/* stats->tx_carrier_errors */
- stats->tx_fifo_errors = u64_stats_read(&mib->tx_undersize_errors);
+ /* stats->tx_fifo_errors */
/* stats->tx_heartbeat_errors */
stats->tx_window_errors = u64_stats_read(&mib->tx_late_collisions);
@@ -401,10 +402,9 @@ yt921x_dsa_get_stats64(struct dsa_switch *ds, int port,
stats->collisions = u64_stats_read(&mib->tx_collisions);
} while (u64_stats_fetch_retry(&pm->syncp, start));
- stats->rx_errors = stats->rx_length_errors + stats->rx_over_errors +
- stats->rx_crc_errors + stats->rx_frame_errors;
- stats->tx_errors = stats->tx_aborted_errors + stats->tx_fifo_errors +
- stats->tx_window_errors;
+ stats->rx_errors = stats->rx_length_errors + stats->rx_crc_errors +
+ stats->rx_frame_errors;
+ stats->tx_errors = stats->tx_aborted_errors + stats->tx_window_errors;
}
void
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next 2/4] net: dsa: motorcomm: Fix RMON fragments stat
2026-11-07 13:20 [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup David Yang
2026-11-07 13:20 ` [PATCH net-next 1/4] net: dsa: motorcomm: Fix stats64 error counter mapping David Yang
@ 2026-11-07 13:20 ` David Yang
2026-11-07 13:20 ` [PATCH net-next 3/4] net: dsa: motorcomm: Use safe 64-bit counter reader David Yang
2026-11-07 13:20 ` [PATCH net-next 4/4] net: dsa: motorcomm: Prevent rx_bytes/tx_bytes underflow David Yang
3 siblings, 0 replies; 6+ messages in thread
From: David Yang @ 2026-11-07 13:20 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
etherStatsFragments counts frames with a bad FCS due to fragmentation;
report the dedicated RX fragment error counter instead of the alignment
error one, which is already exported as AlignmentErrors and
rx_frame_errors.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/mib.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/dsa/motorcomm/mib.c b/drivers/net/dsa/motorcomm/mib.c
index 5c027edb71e3..90b0ef670aa3 100644
--- a/drivers/net/dsa/motorcomm/mib.c
+++ b/drivers/net/dsa/motorcomm/mib.c
@@ -336,7 +336,7 @@ yt921x_dsa_get_rmon_stats(struct dsa_switch *ds, int port,
rmon_stats->undersize_pkts = u64_stats_read(&mib->rx_undersize_errors);
rmon_stats->oversize_pkts = u64_stats_read(&mib->rx_oversize_errors);
- rmon_stats->fragments = u64_stats_read(&mib->rx_alignment_errors);
+ rmon_stats->fragments = u64_stats_read(&mib->rx_fragment_errors);
/* rmon_stats->jabbers */
rmon_stats->hist[0] = u64_stats_read(&mib->rx_64byte);
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next 3/4] net: dsa: motorcomm: Use safe 64-bit counter reader
2026-11-07 13:20 [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup David Yang
2026-11-07 13:20 ` [PATCH net-next 1/4] net: dsa: motorcomm: Fix stats64 error counter mapping David Yang
2026-11-07 13:20 ` [PATCH net-next 2/4] net: dsa: motorcomm: Fix RMON fragments stat David Yang
@ 2026-11-07 13:20 ` David Yang
2026-11-07 13:20 ` [PATCH net-next 4/4] net: dsa: motorcomm: Prevent rx_bytes/tx_bytes underflow David Yang
3 siblings, 0 replies; 6+ messages in thread
From: David Yang @ 2026-11-07 13:20 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
64-bit counter registers are read as two separate 32-bit transactions.
If the low word wraps from about 0xffffffff to a small value while the
high word increments between the two transactions, the recombined value
becomes ((new_high << 32) | old_low), producing a spurious ~4 GiB jump.
Use a safe counter reader for this.
Signed-off-by: David Yang <mmyangfl@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/motorcomm/mib.c | 21 +++++++++-----------
drivers/net/dsa/motorcomm/smi.c | 35 +++++++++++++++++++++++++++++++++
drivers/net/dsa/motorcomm/smi.h | 2 ++
3 files changed, 46 insertions(+), 12 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/mib.c b/drivers/net/dsa/motorcomm/mib.c
index 90b0ef670aa3..b45bc8211741 100644
--- a/drivers/net/dsa/motorcomm/mib.c
+++ b/drivers/net/dsa/motorcomm/mib.c
@@ -102,29 +102,26 @@ static int yt921x_mib_read(struct yt921x_priv *priv, int port)
for (size_t i = 0; i < ARRAY_SIZE(yt921x_mib_descs); i++) {
const struct yt921x_mib_desc *desc = &yt921x_mib_descs[i];
u32 reg = YT921X_MIBn_DATA0(port) + desc->offset;
- u32 val0;
- u64 val;
-
- res = yt921x_reg_read(priv, reg, &val0);
- if (res)
- break;
if (desc->size <= 1) {
u64 old_val = buf[i];
+ u32 val0;
+ u64 val;
+
+ res = yt921x_reg_read(priv, reg, &val0);
+ if (res)
+ break;
val = (old_val & ~(u64)U32_MAX) | val0;
if (val < old_val)
val += 1ull << 32;
- } else {
- u32 val1;
- res = yt921x_reg_read(priv, reg + 4, &val1);
+ buf[i] = val;
+ } else {
+ res = yt921x_counter_read(priv, reg, &buf[i]);
if (res)
break;
- val = ((u64)val1 << 32) | val0;
}
-
- buf[i] = val;
}
flags = u64_stats_update_begin_irqsave(&pm->syncp);
diff --git a/drivers/net/dsa/motorcomm/smi.c b/drivers/net/dsa/motorcomm/smi.c
index bf3adfd64165..16f62409422d 100644
--- a/drivers/net/dsa/motorcomm/smi.c
+++ b/drivers/net/dsa/motorcomm/smi.c
@@ -63,6 +63,41 @@ int yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)
return yt921x_reg_write(priv, reg, u);
}
+/* Reliably read a 64-bit counter, assuming the counter isn't that "fast" */
+int yt921x_counter_read(struct yt921x_priv *priv, u32 reg, u64 *valp)
+{
+ u32 old_lo;
+ int res;
+ u32 hi;
+ u32 lo;
+
+ res = yt921x_reg_read(priv, reg, &old_lo);
+ if (res)
+ return res;
+
+ res = yt921x_reg_read(priv, reg + 4, &hi);
+ if (res)
+ return res;
+
+ res = yt921x_reg_read(priv, reg, &lo);
+ if (res)
+ return res;
+
+ if (lo < old_lo) {
+ u32 new_hi;
+
+ res = yt921x_reg_read(priv, reg + 4, &new_hi);
+ if (res)
+ return res;
+ if (new_hi != hi + 1)
+ return -EIO;
+ hi = new_hi;
+ }
+
+ *valp = ((u64)hi << 32) | lo;
+ return 0;
+}
+
static int
yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
unsigned int num_regs)
diff --git a/drivers/net/dsa/motorcomm/smi.h b/drivers/net/dsa/motorcomm/smi.h
index 212e20f71d80..d34240548af7 100644
--- a/drivers/net/dsa/motorcomm/smi.h
+++ b/drivers/net/dsa/motorcomm/smi.h
@@ -35,6 +35,8 @@ yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)
return yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);
}
+int yt921x_counter_read(struct yt921x_priv *priv, u32 reg, u64 *valp);
+
/* Some multi-word registers, like VLANn_CTRL, should be treated as a single
* long register. More specifically, writes to parts of its words won't become
* visible, until the last word is written.
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next 4/4] net: dsa: motorcomm: Prevent rx_bytes/tx_bytes underflow
2026-11-07 13:20 [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup David Yang
` (2 preceding siblings ...)
2026-11-07 13:20 ` [PATCH net-next 3/4] net: dsa: motorcomm: Use safe 64-bit counter reader David Yang
@ 2026-11-07 13:20 ` David Yang
3 siblings, 0 replies; 6+ messages in thread
From: David Yang @ 2026-11-07 13:20 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
There is no direct rx_bytes/tx_bytes counter excluding the FCS; both
have to be derived as good_bytes - ETH_FCS_LEN * frames. Three hazards
can pair a frame count with a mismatched byte count and make the
subtraction underflow, reporting rx_bytes or tx_bytes as about 2^64:
- a register read fails midway and the half-refreshed buffer is
published as is, pairing fresh frame counters with stale byte
counters;
- get_stats64() on 64-bit kernels reads the published counters without
any sequencing across fields (u64_stats_sync is a no-op there), so a
writer update can slip between the frame and byte reads;
- the MIB bank cannot be read as a whole; counters keep counting while
the read loop walks the table.
Handle this in the writer: do not publish a half-read buffer, keep the
last complete sample on read failure, do the arithmetic on the complete
sample under priv->reg_lock, and publish the derived byte counters only
when check_sub_overflow() succeeds, so that get_stats64() copies plain
published values.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/mib.c | 25 +++++++++++++++++--------
drivers/net/dsa/motorcomm/mib.h | 2 ++
2 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/mib.c b/drivers/net/dsa/motorcomm/mib.c
index b45bc8211741..cb3912493cfb 100644
--- a/drivers/net/dsa/motorcomm/mib.c
+++ b/drivers/net/dsa/motorcomm/mib.c
@@ -95,6 +95,8 @@ static int yt921x_mib_read(struct yt921x_priv *priv, int port)
unsigned long flags;
u64 rx_frames;
u64 tx_frames;
+ u64 rx_bytes;
+ u64 tx_bytes;
int res = 0;
mib = &pm->stats;
@@ -124,6 +126,12 @@ static int yt921x_mib_read(struct yt921x_priv *priv, int port)
}
}
+ if (res) {
+ dev_err(dev, "Failed to %s port %d: %i\n", "read stats for",
+ port, res);
+ return res;
+ }
+
flags = u64_stats_update_begin_irqsave(&pm->syncp);
for (size_t i = 0; i < ARRAY_SIZE(yt921x_mib_descs); i++)
u64_stats_set(&((u64_stats_t *)mib)[i], buf[i]);
@@ -143,12 +151,15 @@ static int yt921x_mib_read(struct yt921x_priv *priv, int port)
u64_stats_read(&mib->tx_jumbo);
u64_stats_set(&pm->rx_frames, rx_frames);
u64_stats_set(&pm->tx_frames, tx_frames);
+ if (!check_sub_overflow(u64_stats_read(&mib->rx_good_bytes),
+ ETH_FCS_LEN * rx_frames, &rx_bytes))
+ u64_stats_set(&pm->rx_bytes, rx_bytes);
+ if (!check_sub_overflow(u64_stats_read(&mib->tx_good_bytes),
+ ETH_FCS_LEN * tx_frames, &tx_bytes))
+ u64_stats_set(&pm->tx_bytes, tx_bytes);
u64_stats_update_end_irqrestore(&pm->syncp, flags);
- if (res)
- dev_err(dev, "Failed to %s port %d: %i\n", "read stats for",
- port, res);
- return res;
+ return 0;
}
void yt921x_mib_poll(struct work_struct *work)
@@ -389,10 +400,8 @@ yt921x_dsa_get_stats64(struct dsa_switch *ds, int port,
stats->rx_packets = u64_stats_read(&pm->rx_frames);
stats->tx_packets = u64_stats_read(&pm->tx_frames);
- stats->rx_bytes = u64_stats_read(&mib->rx_good_bytes) -
- ETH_FCS_LEN * stats->rx_packets;
- stats->tx_bytes = u64_stats_read(&mib->tx_good_bytes) -
- ETH_FCS_LEN * stats->tx_packets;
+ stats->rx_bytes = u64_stats_read(&pm->rx_bytes);
+ stats->tx_bytes = u64_stats_read(&pm->tx_bytes);
stats->rx_dropped = u64_stats_read(&mib->rx_dropped);
/* stats->tx_dropped */
stats->multicast = u64_stats_read(&mib->rx_multicast);
diff --git a/drivers/net/dsa/motorcomm/mib.h b/drivers/net/dsa/motorcomm/mib.h
index 9c24a52d46cc..2e2b832cb245 100644
--- a/drivers/net/dsa/motorcomm/mib.h
+++ b/drivers/net/dsa/motorcomm/mib.h
@@ -136,6 +136,8 @@ struct yt921x_mib {
struct yt921x_mib_stats stats;
u64_stats_t rx_frames;
u64_stats_t tx_frames;
+ u64_stats_t rx_bytes;
+ u64_stats_t tx_bytes;
/* protected by priv->reg_lock */
u64 data[YT921X_MIB_STAT_NUM];
};
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup
@ 2026-09-03 14:35 David Yang
0 siblings, 0 replies; 6+ messages in thread
From: David Yang @ 2026-09-03 14:35 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Russell King,
linux-kernel
Fix (theoretical) MIB inconsistency. No new features are introduced.
David Yang (4):
net: dsa: motorcomm: Split MIB module
net: dsa: motorcomm: Split MIB buffers
net: dsa: motorcomm: Use u64_stats_t for MIB stats
net: dsa: motorcomm: Use safe 64-bit counter reader
drivers/net/dsa/motorcomm/Makefile | 1 +
drivers/net/dsa/motorcomm/chip.c | 408 +++------------------------
drivers/net/dsa/motorcomm/chip.h | 126 +--------
drivers/net/dsa/motorcomm/mib.c | 430 +++++++++++++++++++++++++++++
drivers/net/dsa/motorcomm/mib.h | 167 +++++++++++
drivers/net/dsa/motorcomm/smi.c | 30 ++
drivers/net/dsa/motorcomm/smi.h | 2 +
7 files changed, 670 insertions(+), 494 deletions(-)
create mode 100644 drivers/net/dsa/motorcomm/mib.c
create mode 100644 drivers/net/dsa/motorcomm/mib.h
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-07 13:21 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-07 13:20 [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup David Yang
2026-11-07 13:20 ` [PATCH net-next 1/4] net: dsa: motorcomm: Fix stats64 error counter mapping David Yang
2026-11-07 13:20 ` [PATCH net-next 2/4] net: dsa: motorcomm: Fix RMON fragments stat David Yang
2026-11-07 13:20 ` [PATCH net-next 3/4] net: dsa: motorcomm: Use safe 64-bit counter reader David Yang
2026-11-07 13:20 ` [PATCH net-next 4/4] net: dsa: motorcomm: Prevent rx_bytes/tx_bytes underflow David Yang
-- strict thread matches above, loose matches on Subject: below --
2026-09-03 14:35 [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup David Yang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®