From: David Yang <mmyangfl@gmail.com>
To: netdev@vger.kernel.org
Cc: David Yang <mmyangfl@gmail.com>, Andrew Lunn <andrew@lunn.ch>,
Vladimir Oltean <olteanv@gmail.com>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Russell King <linux@armlinux.org.uk>,
linux-kernel@vger.kernel.org
Subject: [PATCH net-next v2 6/6] net: dsa: motorcomm: Use safe 64-bit counter reader
Date: Sat, 5 Sep 2026 00:29:48 +0800 [thread overview]
Message-ID: <20260904162952.709368-7-mmyangfl@gmail.com> (raw)
In-Reply-To: <20260904162952.709368-1-mmyangfl@gmail.com>
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>
---
drivers/net/dsa/motorcomm/mib.c | 19 +++++++++----------
drivers/net/dsa/motorcomm/smi.c | 30 ++++++++++++++++++++++++++++++
drivers/net/dsa/motorcomm/smi.h | 2 ++
3 files changed, 41 insertions(+), 10 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/mib.c b/drivers/net/dsa/motorcomm/mib.c
index 31d86c3122c7..8929476a976f 100644
--- a/drivers/net/dsa/motorcomm/mib.c
+++ b/drivers/net/dsa/motorcomm/mib.c
@@ -102,26 +102,25 @@ 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;
diff --git a/drivers/net/dsa/motorcomm/smi.c b/drivers/net/dsa/motorcomm/smi.c
index bf3adfd64165..27086602997b 100644
--- a/drivers/net/dsa/motorcomm/smi.c
+++ b/drivers/net/dsa/motorcomm/smi.c
@@ -63,6 +63,36 @@ 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 64bit counter */
+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;
+
+ for (int i = 0; i < 16; i++) {
+ 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) {
+ *valp = ((u64)hi << 32) | lo;
+ return 0;
+ }
+ old_lo = lo;
+ }
+
+ return -ETIMEDOUT;
+}
+
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
prev parent reply other threads:[~2026-09-04 16:31 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-04 16:29 [PATCH net-next v2 0/6] net: dsa: motorcomm: MIB fixup David Yang
2026-09-04 16:29 ` [PATCH net-next v2 1/6] net: dsa: motorcomm: Rename MIB stuffs David Yang
2026-09-04 16:29 ` [PATCH net-next v2 2/6] net: dsa: motorcomm: Split MIB buffers David Yang
2026-09-04 16:29 ` [PATCH net-next v2 3/6] net: dsa: motorcomm: Split MIB module David Yang
2026-09-04 16:29 ` [PATCH net-next v2 4/6] net: dsa: motorcomm: Use u64_stats_t for MIB stats David Yang
2026-09-04 16:29 ` [PATCH net-next v2 5/6] net: dsa: motorcomm: Fix MIB synchronization David Yang
2026-09-04 16:29 ` David Yang [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260904162952.709368-7-mmyangfl@gmail.com \
--to=mmyangfl@gmail.com \
--cc=andrew@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=netdev@vger.kernel.org \
--cc=olteanv@gmail.com \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®