* [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup
@ 2026-09-03 14:35 David Yang
2026-09-03 14:35 ` [PATCH net-next 1/4] net: dsa: motorcomm: Split MIB module David Yang
` (3 more replies)
0 siblings, 4 replies; 10+ 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] 10+ messages in thread
* [PATCH net-next 1/4] net: dsa: motorcomm: Split MIB module
2026-09-03 14:35 [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup David Yang
@ 2026-09-03 14:35 ` David Yang
2026-09-03 15:01 ` Andrew Lunn
2026-09-03 14:35 ` [PATCH net-next 2/4] net: dsa: motorcomm: Split MIB buffers David Yang
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ 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
yt922x is going to use a different MIB scheme, split it to reduce the
length of chip.c.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/Makefile | 1 +
drivers/net/dsa/motorcomm/chip.c | 366 +---------------------------
drivers/net/dsa/motorcomm/chip.h | 63 -----
drivers/net/dsa/motorcomm/mib.c | 373 +++++++++++++++++++++++++++++
drivers/net/dsa/motorcomm/mib.h | 98 ++++++++
5 files changed, 474 insertions(+), 427 deletions(-)
create mode 100644 drivers/net/dsa/motorcomm/mib.c
create mode 100644 drivers/net/dsa/motorcomm/mib.h
diff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile
index aeb12cb91f93..5c2d34ec05fc 100644
--- a/drivers/net/dsa/motorcomm/Makefile
+++ b/drivers/net/dsa/motorcomm/Makefile
@@ -2,4 +2,5 @@
obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
yt921x-objs := chip.o
yt921x-$(CONFIG_NET_DSA_YT921X_LEDS) += leds.o
+yt921x-objs += mib.o
yt921x-objs += smi.o
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index d663af010f43..77440bf5fa7a 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -27,75 +27,9 @@
#include "chip.h"
#include "leds.h"
+#include "mib.h"
#include "smi.h"
-struct yt921x_mib_desc {
- unsigned int size;
- unsigned int offset;
- const char *name;
-};
-
-#define MIB_DESC(_size, _offset, _name) \
- {_size, _offset, _name}
-
-/* Must agree with yt921x_mib
- *
- * Unstructured fields (name != NULL) will appear in get_ethtool_stats(),
- * structured go to their *_stats() methods, but we need their sizes and offsets
- * to perform 32bit MIB overflow wraparound.
- */
-static const struct yt921x_mib_desc yt921x_mib_descs[] = {
- MIB_DESC(1, YT921X_MIB_DATA_RX_BROADCAST, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_RX_PAUSE, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_RX_MULTICAST, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_RX_CRC_ERR, NULL),
-
- MIB_DESC(1, YT921X_MIB_DATA_RX_ALIGN_ERR, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_RX_UNDERSIZE_ERR, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_RX_FRAG_ERR, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_64, NULL),
-
- MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_65_TO_127, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_128_TO_255, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_256_TO_511, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_512_TO_1023, NULL),
-
- MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_1024_TO_1518, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_1519_TO_MAX, NULL),
- MIB_DESC(2, YT921X_MIB_DATA_RX_GOOD_BYTES, NULL),
-
- MIB_DESC(2, YT921X_MIB_DATA_RX_BAD_BYTES, "RxBadBytes"),
- MIB_DESC(1, YT921X_MIB_DATA_RX_OVERSIZE_ERR, NULL),
-
- MIB_DESC(1, YT921X_MIB_DATA_RX_DROPPED, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_TX_BROADCAST, NULL),
- 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_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),
-
- MIB_DESC(1, YT921X_MIB_DATA_TX_PKT_SZ_256_TO_511, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_TX_PKT_SZ_512_TO_1023, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_TX_PKT_SZ_1024_TO_1518, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_TX_PKT_SZ_1519_TO_MAX, NULL),
-
- MIB_DESC(2, YT921X_MIB_DATA_TX_GOOD_BYTES, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_TX_COLLISION, NULL),
-
- MIB_DESC(1, YT921X_MIB_DATA_TX_EXCESSIVE_COLLISION, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_TX_MULTIPLE_COLLISION, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_TX_SINGLE_COLLISION, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_TX_PKT, NULL),
-
- MIB_DESC(1, YT921X_MIB_DATA_TX_DEFERRED, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_TX_LATE_COLLISION, NULL),
- MIB_DESC(1, YT921X_MIB_DATA_RX_OAM, "RxOAM"),
- MIB_DESC(1, YT921X_MIB_DATA_TX_OAM, "TxOAM"),
-};
-
struct yt921x_info {
const char *name;
u16 major;
@@ -154,14 +88,6 @@ static const struct yt921x_info yt921x_infos[] = {
#define YT921X_VID_UNWARE 4095
-/* The interval should be small enough to avoid overflow of 32bit MIBs.
- *
- * Until we can read MIBs from stats64 call directly (i.e. sleep
- * there), we have to poll stats more frequently then it is actually needed.
- * For overflow protection, normally, 100 sec interval should have been OK.
- */
-#define YT921X_STATS_INTERVAL_JIFFIES (3 * HZ)
-
struct yt921x_reg_mdio {
struct mii_bus *bus;
int addr;
@@ -544,294 +470,6 @@ yt921x_mbus_ext_init(struct yt921x_priv *priv, struct device_node *mnp)
return 0;
}
-/* Read and handle overflow of 32bit MIBs. MIB buffer must be zeroed before. */
-static int yt921x_read_mib(struct yt921x_priv *priv, int port)
-{
- struct yt921x_port *pp = &priv->ports[port];
- struct device *dev = to_device(priv);
- struct yt921x_mib *mib = &pp->mib;
- int res = 0;
-
- /* Reading of yt921x_port::mib is not protected by a lock and it's vain
- * to keep its consistency, since we have to read registers one by one
- * and there is no way to make a snapshot of MIB stats.
- *
- * Writing (by this function only) is and should be protected by
- * reg_lock.
- */
-
- 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;
- u64 *valp = &((u64 *)mib)[i];
- u32 val0;
- u64 val;
-
- res = yt921x_reg_read(priv, reg, &val0);
- if (res)
- break;
-
- if (desc->size <= 1) {
- u64 old_val = *valp;
-
- 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);
- if (res)
- break;
- val = ((u64)val1 << 32) | val0;
- }
-
- WRITE_ONCE(*valp, val);
- }
-
- pp->rx_frames = mib->rx_64byte + mib->rx_65_127byte +
- mib->rx_128_255byte + mib->rx_256_511byte +
- mib->rx_512_1023byte + mib->rx_1024_1518byte +
- mib->rx_jumbo;
- pp->tx_frames = mib->tx_64byte + mib->tx_65_127byte +
- mib->tx_128_255byte + mib->tx_256_511byte +
- mib->tx_512_1023byte + mib->tx_1024_1518byte +
- mib->tx_jumbo;
-
- if (res)
- dev_err(dev, "Failed to %s port %d: %i\n", "read stats for",
- port, res);
- return res;
-}
-
-static void yt921x_poll_mib(struct work_struct *work)
-{
- struct yt921x_port *pp = container_of_const(work, struct yt921x_port,
- mib_read.work);
- struct yt921x_priv *priv = (void *)(pp - pp->index) -
- offsetof(struct yt921x_priv, ports);
- unsigned long delay = YT921X_STATS_INTERVAL_JIFFIES;
- int port = pp->index;
- int res;
-
- mutex_lock(&priv->reg_lock);
- res = yt921x_read_mib(priv, port);
- mutex_unlock(&priv->reg_lock);
- if (res)
- delay *= 4;
-
- schedule_delayed_work(&pp->mib_read, delay);
-}
-
-static void
-yt921x_dsa_get_strings(struct dsa_switch *ds, int port, u32 stringset,
- uint8_t *data)
-{
- if (stringset != ETH_SS_STATS)
- return;
-
- for (size_t i = 0; i < ARRAY_SIZE(yt921x_mib_descs); i++) {
- const struct yt921x_mib_desc *desc = &yt921x_mib_descs[i];
-
- if (desc->name)
- ethtool_puts(&data, desc->name);
- }
-}
-
-static void
-yt921x_dsa_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
-{
- struct yt921x_priv *priv = to_yt921x_priv(ds);
- struct yt921x_port *pp = &priv->ports[port];
- struct yt921x_mib *mib = &pp->mib;
- size_t j;
-
- mutex_lock(&priv->reg_lock);
- yt921x_read_mib(priv, port);
- mutex_unlock(&priv->reg_lock);
-
- j = 0;
- for (size_t i = 0; i < ARRAY_SIZE(yt921x_mib_descs); i++) {
- const struct yt921x_mib_desc *desc = &yt921x_mib_descs[i];
-
- if (!desc->name)
- continue;
-
- data[j] = ((u64 *)mib)[i];
- j++;
- }
-}
-
-static int yt921x_dsa_get_sset_count(struct dsa_switch *ds, int port, int sset)
-{
- int cnt = 0;
-
- if (sset != ETH_SS_STATS)
- return 0;
-
- for (size_t i = 0; i < ARRAY_SIZE(yt921x_mib_descs); i++) {
- const struct yt921x_mib_desc *desc = &yt921x_mib_descs[i];
-
- if (desc->name)
- cnt++;
- }
-
- return cnt;
-}
-
-static void
-yt921x_dsa_get_eth_mac_stats(struct dsa_switch *ds, int port,
- struct ethtool_eth_mac_stats *mac_stats)
-{
- struct yt921x_priv *priv = to_yt921x_priv(ds);
- struct yt921x_port *pp = &priv->ports[port];
- struct yt921x_mib *mib = &pp->mib;
-
- mutex_lock(&priv->reg_lock);
- yt921x_read_mib(priv, port);
- mutex_unlock(&priv->reg_lock);
-
- mac_stats->FramesTransmittedOK = pp->tx_frames;
- mac_stats->SingleCollisionFrames = mib->tx_single_collisions;
- mac_stats->MultipleCollisionFrames = mib->tx_multiple_collisions;
- mac_stats->FramesReceivedOK = pp->rx_frames;
- mac_stats->FrameCheckSequenceErrors = mib->rx_crc_errors;
- mac_stats->AlignmentErrors = mib->rx_alignment_errors;
- mac_stats->OctetsTransmittedOK = mib->tx_good_bytes;
- mac_stats->FramesWithDeferredXmissions = mib->tx_deferred;
- mac_stats->LateCollisions = mib->tx_late_collisions;
- mac_stats->FramesAbortedDueToXSColls = mib->tx_aborted_errors;
- /* mac_stats->FramesLostDueToIntMACXmitError */
- /* mac_stats->CarrierSenseErrors */
- mac_stats->OctetsReceivedOK = mib->rx_good_bytes;
- /* mac_stats->FramesLostDueToIntMACRcvError */
- mac_stats->MulticastFramesXmittedOK = mib->tx_multicast;
- mac_stats->BroadcastFramesXmittedOK = mib->tx_broadcast;
- /* mac_stats->FramesWithExcessiveDeferral */
- mac_stats->MulticastFramesReceivedOK = mib->rx_multicast;
- mac_stats->BroadcastFramesReceivedOK = mib->rx_broadcast;
- /* mac_stats->InRangeLengthErrors */
- /* mac_stats->OutOfRangeLengthField */
- mac_stats->FrameTooLongErrors = mib->rx_oversize_errors;
-}
-
-static void
-yt921x_dsa_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
- struct ethtool_eth_ctrl_stats *ctrl_stats)
-{
- struct yt921x_priv *priv = to_yt921x_priv(ds);
- struct yt921x_port *pp = &priv->ports[port];
- struct yt921x_mib *mib = &pp->mib;
-
- mutex_lock(&priv->reg_lock);
- yt921x_read_mib(priv, port);
- mutex_unlock(&priv->reg_lock);
-
- ctrl_stats->MACControlFramesTransmitted = mib->tx_pause;
- ctrl_stats->MACControlFramesReceived = mib->rx_pause;
- /* ctrl_stats->UnsupportedOpcodesReceived */
-}
-
-static const struct ethtool_rmon_hist_range yt921x_rmon_ranges[] = {
- { 0, 64 },
- { 65, 127 },
- { 128, 255 },
- { 256, 511 },
- { 512, 1023 },
- { 1024, 1518 },
- { 1519, YT921X_FRAME_SIZE_MAX },
- {}
-};
-
-static void
-yt921x_dsa_get_rmon_stats(struct dsa_switch *ds, int port,
- struct ethtool_rmon_stats *rmon_stats,
- const struct ethtool_rmon_hist_range **ranges)
-{
- struct yt921x_priv *priv = to_yt921x_priv(ds);
- struct yt921x_port *pp = &priv->ports[port];
- struct yt921x_mib *mib = &pp->mib;
-
- mutex_lock(&priv->reg_lock);
- yt921x_read_mib(priv, port);
- mutex_unlock(&priv->reg_lock);
-
- *ranges = yt921x_rmon_ranges;
-
- rmon_stats->undersize_pkts = mib->rx_undersize_errors;
- rmon_stats->oversize_pkts = mib->rx_oversize_errors;
- rmon_stats->fragments = mib->rx_alignment_errors;
- /* rmon_stats->jabbers */
-
- rmon_stats->hist[0] = mib->rx_64byte;
- rmon_stats->hist[1] = mib->rx_65_127byte;
- rmon_stats->hist[2] = mib->rx_128_255byte;
- rmon_stats->hist[3] = mib->rx_256_511byte;
- rmon_stats->hist[4] = mib->rx_512_1023byte;
- rmon_stats->hist[5] = mib->rx_1024_1518byte;
- rmon_stats->hist[6] = mib->rx_jumbo;
-
- rmon_stats->hist_tx[0] = mib->tx_64byte;
- rmon_stats->hist_tx[1] = mib->tx_65_127byte;
- rmon_stats->hist_tx[2] = mib->tx_128_255byte;
- rmon_stats->hist_tx[3] = mib->tx_256_511byte;
- rmon_stats->hist_tx[4] = mib->tx_512_1023byte;
- rmon_stats->hist_tx[5] = mib->tx_1024_1518byte;
- rmon_stats->hist_tx[6] = mib->tx_jumbo;
-}
-
-static void
-yt921x_dsa_get_stats64(struct dsa_switch *ds, int port,
- struct rtnl_link_stats64 *stats)
-{
- struct yt921x_priv *priv = to_yt921x_priv(ds);
- struct yt921x_port *pp = &priv->ports[port];
- struct yt921x_mib *mib = &pp->mib;
-
- stats->rx_length_errors = mib->rx_undersize_errors +
- mib->rx_fragment_errors;
- stats->rx_over_errors = mib->rx_oversize_errors;
- stats->rx_crc_errors = mib->rx_crc_errors;
- stats->rx_frame_errors = mib->rx_alignment_errors;
- /* stats->rx_fifo_errors */
- /* stats->rx_missed_errors */
-
- stats->tx_aborted_errors = mib->tx_aborted_errors;
- /* stats->tx_carrier_errors */
- stats->tx_fifo_errors = mib->tx_undersize_errors;
- /* stats->tx_heartbeat_errors */
- stats->tx_window_errors = mib->tx_late_collisions;
-
- stats->rx_packets = pp->rx_frames;
- stats->tx_packets = pp->tx_frames;
- stats->rx_bytes = mib->rx_good_bytes - ETH_FCS_LEN * stats->rx_packets;
- stats->tx_bytes = mib->tx_good_bytes - ETH_FCS_LEN * stats->tx_packets;
- 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_dropped = mib->rx_dropped;
- /* stats->tx_dropped */
- stats->multicast = mib->rx_multicast;
- stats->collisions = mib->tx_collisions;
-}
-
-static void
-yt921x_dsa_get_pause_stats(struct dsa_switch *ds, int port,
- struct ethtool_pause_stats *pause_stats)
-{
- struct yt921x_priv *priv = to_yt921x_priv(ds);
- struct yt921x_port *pp = &priv->ports[port];
- struct yt921x_mib *mib = &pp->mib;
-
- mutex_lock(&priv->reg_lock);
- yt921x_read_mib(priv, port);
- mutex_unlock(&priv->reg_lock);
-
- pause_stats->tx_pause_frames = mib->tx_pause;
- pause_stats->rx_pause_frames = mib->rx_pause;
-}
-
static int
yt921x_set_eee(struct yt921x_priv *priv, int port, struct ethtool_keee *e)
{
@@ -4749,7 +4387,7 @@ static int yt921x_mdio_probe(struct mdio_device *mdiodev)
struct yt921x_port *pp = &priv->ports[i];
pp->index = i;
- INIT_DELAYED_WORK(&pp->mib_read, yt921x_poll_mib);
+ INIT_DELAYED_WORK(&pp->mib_read, yt921x_mib_poll);
}
ds = &priv->ds;
diff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h
index 83cd454955dd..84c7065b1cd4 100644
--- a/drivers/net/dsa/motorcomm/chip.h
+++ b/drivers/net/dsa/motorcomm/chip.h
@@ -167,69 +167,6 @@
#define YT921X_EEE_CTRL 0xb0000
#define YT921X_EEE_CTRL_ENn(port) BIT(port)
-#define YT921X_MIB_CTRL 0xc0004
-#define YT921X_MIB_CTRL_CLEAN BIT(30)
-#define YT921X_MIB_CTRL_PORT_M GENMASK(6, 3)
-#define YT921X_MIB_CTRL_PORT(x) FIELD_PREP(YT921X_MIB_CTRL_PORT_M, (x))
-#define YT921X_MIB_CTRL_ONE_PORT BIT(1)
-#define YT921X_MIB_CTRL_ALL_PORT BIT(0)
-#define YT921X_MIBn_DATA0(port) (0xc0100 + 0x100 * (port))
-#define YT921X_MIBn_DATAm(port, x) (YT921X_MIBn_DATA0(port) + 4 * (x))
-#define YT921X_MIB_DATA_RX_BROADCAST 0x00
-#define YT921X_MIB_DATA_RX_PAUSE 0x04
-#define YT921X_MIB_DATA_RX_MULTICAST 0x08
-#define YT921X_MIB_DATA_RX_CRC_ERR 0x0c
-
-#define YT921X_MIB_DATA_RX_ALIGN_ERR 0x10
-#define YT921X_MIB_DATA_RX_UNDERSIZE_ERR 0x14
-#define YT921X_MIB_DATA_RX_FRAG_ERR 0x18
-#define YT921X_MIB_DATA_RX_PKT_SZ_64 0x1c
-
-#define YT921X_MIB_DATA_RX_PKT_SZ_65_TO_127 0x20
-#define YT921X_MIB_DATA_RX_PKT_SZ_128_TO_255 0x24
-#define YT921X_MIB_DATA_RX_PKT_SZ_256_TO_511 0x28
-#define YT921X_MIB_DATA_RX_PKT_SZ_512_TO_1023 0x2c
-
-#define YT921X_MIB_DATA_RX_PKT_SZ_1024_TO_1518 0x30
-#define YT921X_MIB_DATA_RX_PKT_SZ_1519_TO_MAX 0x34
-/* 0x38: unused */
-#define YT921X_MIB_DATA_RX_GOOD_BYTES 0x3c
-
-/* 0x40: 64 bytes */
-#define YT921X_MIB_DATA_RX_BAD_BYTES 0x44
-/* 0x48: 64 bytes */
-#define YT921X_MIB_DATA_RX_OVERSIZE_ERR 0x4c
-
-#define YT921X_MIB_DATA_RX_DROPPED 0x50
-#define YT921X_MIB_DATA_TX_BROADCAST 0x54
-#define YT921X_MIB_DATA_TX_PAUSE 0x58
-#define YT921X_MIB_DATA_TX_MULTICAST 0x5c
-
-#define YT921X_MIB_DATA_TX_UNDERSIZE_ERR 0x60
-#define YT921X_MIB_DATA_TX_PKT_SZ_64 0x64
-#define YT921X_MIB_DATA_TX_PKT_SZ_65_TO_127 0x68
-#define YT921X_MIB_DATA_TX_PKT_SZ_128_TO_255 0x6c
-
-#define YT921X_MIB_DATA_TX_PKT_SZ_256_TO_511 0x70
-#define YT921X_MIB_DATA_TX_PKT_SZ_512_TO_1023 0x74
-#define YT921X_MIB_DATA_TX_PKT_SZ_1024_TO_1518 0x78
-#define YT921X_MIB_DATA_TX_PKT_SZ_1519_TO_MAX 0x7c
-
-/* 0x80: unused */
-#define YT921X_MIB_DATA_TX_GOOD_BYTES 0x84
-/* 0x88: 64 bytes */
-#define YT921X_MIB_DATA_TX_COLLISION 0x8c
-
-#define YT921X_MIB_DATA_TX_EXCESSIVE_COLLISION 0x90
-#define YT921X_MIB_DATA_TX_MULTIPLE_COLLISION 0x94
-#define YT921X_MIB_DATA_TX_SINGLE_COLLISION 0x98
-#define YT921X_MIB_DATA_TX_PKT 0x9c
-
-#define YT921X_MIB_DATA_TX_DEFERRED 0xa0
-#define YT921X_MIB_DATA_TX_LATE_COLLISION 0xa4
-#define YT921X_MIB_DATA_RX_OAM 0xa8
-#define YT921X_MIB_DATA_TX_OAM 0xac
-
#define YT921X_EDATA_CTRL 0xe0000
#define YT921X_EDATA_CTRL_ADDR_M GENMASK(15, 8)
#define YT921X_EDATA_CTRL_ADDR(x) FIELD_PREP(YT921X_EDATA_CTRL_ADDR_M, (x))
diff --git a/drivers/net/dsa/motorcomm/mib.c b/drivers/net/dsa/motorcomm/mib.c
new file mode 100644
index 000000000000..74728b1ed777
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/mib.c
@@ -0,0 +1,373 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#include "chip.h"
+#include "mib.h"
+#include "smi.h"
+
+struct yt921x_mib_desc {
+ unsigned char size;
+ unsigned char offset;
+ const char *name;
+};
+
+#define MIB_DESC(_size, _offset, _name) {_size, _offset, _name}
+
+/* Must agree with yt921x_mib
+ *
+ * Unstructured fields (name != NULL) will appear in get_ethtool_stats(),
+ * structured go to their *_stats() methods, but we need their sizes and offsets
+ * to perform 32bit MIB overflow wraparound.
+ */
+static const struct yt921x_mib_desc yt921x_mib_descs[] = {
+ MIB_DESC(1, YT921X_MIB_DATA_RX_BROADCAST, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_RX_PAUSE, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_RX_MULTICAST, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_RX_CRC_ERR, NULL),
+
+ MIB_DESC(1, YT921X_MIB_DATA_RX_ALIGN_ERR, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_RX_UNDERSIZE_ERR, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_RX_FRAG_ERR, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_64, NULL),
+
+ MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_65_TO_127, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_128_TO_255, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_256_TO_511, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_512_TO_1023, NULL),
+
+ MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_1024_TO_1518, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_RX_PKT_SZ_1519_TO_MAX, NULL),
+ MIB_DESC(2, YT921X_MIB_DATA_RX_GOOD_BYTES, NULL),
+
+ MIB_DESC(2, YT921X_MIB_DATA_RX_BAD_BYTES, "RxBadBytes"),
+ MIB_DESC(1, YT921X_MIB_DATA_RX_OVERSIZE_ERR, NULL),
+
+ MIB_DESC(1, YT921X_MIB_DATA_RX_DROPPED, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_TX_BROADCAST, NULL),
+ 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_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),
+
+ MIB_DESC(1, YT921X_MIB_DATA_TX_PKT_SZ_256_TO_511, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_TX_PKT_SZ_512_TO_1023, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_TX_PKT_SZ_1024_TO_1518, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_TX_PKT_SZ_1519_TO_MAX, NULL),
+
+ MIB_DESC(2, YT921X_MIB_DATA_TX_GOOD_BYTES, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_TX_COLLISION, NULL),
+
+ MIB_DESC(1, YT921X_MIB_DATA_TX_EXCESSIVE_COLLISION, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_TX_MULTIPLE_COLLISION, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_TX_SINGLE_COLLISION, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_TX_PKT, NULL),
+
+ MIB_DESC(1, YT921X_MIB_DATA_TX_DEFERRED, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_TX_LATE_COLLISION, NULL),
+ MIB_DESC(1, YT921X_MIB_DATA_RX_OAM, "RxOAM"),
+ MIB_DESC(1, YT921X_MIB_DATA_TX_OAM, "TxOAM"),
+};
+
+/* The interval should be small enough to avoid overflow of 32bit MIBs.
+ *
+ * Until we can read MIBs from stats64 call directly (i.e. sleep
+ * there), we have to poll stats more frequently then it is actually needed.
+ * For overflow protection, normally, 100 sec interval should have been OK.
+ */
+#define YT921X_STATS_INTERVAL_JIFFIES (3 * HZ)
+
+#define to_yt921x_priv(_ds) container_of_const(_ds, struct yt921x_priv, ds)
+#define to_device(priv) ((priv)->ds.dev)
+
+/* Read and handle overflow of 32bit MIBs. MIB buffer must be zeroed before. */
+static int yt921x_mib_read(struct yt921x_priv *priv, int port)
+{
+ struct yt921x_port *pp = &priv->ports[port];
+ struct device *dev = to_device(priv);
+ struct yt921x_mib *mib = &pp->mib;
+ int res = 0;
+
+ /* Reading of yt921x_port::mib is not protected by a lock and it's vain
+ * to keep its consistency, since we have to read registers one by one
+ * and there is no way to make a snapshot of MIB stats.
+ *
+ * Writing (by this function only) is and should be protected by
+ * reg_lock.
+ */
+
+ 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;
+ u64 *valp = &((u64 *)mib)[i];
+ u32 val0;
+ u64 val;
+
+ res = yt921x_reg_read(priv, reg, &val0);
+ if (res)
+ break;
+
+ if (desc->size <= 1) {
+ u64 old_val = *valp;
+
+ 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);
+ if (res)
+ break;
+ val = ((u64)val1 << 32) | val0;
+ }
+
+ WRITE_ONCE(*valp, val);
+ }
+
+ pp->rx_frames = mib->rx_64byte + mib->rx_65_127byte +
+ mib->rx_128_255byte + mib->rx_256_511byte +
+ mib->rx_512_1023byte + mib->rx_1024_1518byte +
+ mib->rx_jumbo;
+ pp->tx_frames = mib->tx_64byte + mib->tx_65_127byte +
+ mib->tx_128_255byte + mib->tx_256_511byte +
+ mib->tx_512_1023byte + mib->tx_1024_1518byte +
+ mib->tx_jumbo;
+
+ if (res)
+ dev_err(dev, "Failed to %s port %d: %i\n", "read stats for",
+ port, res);
+ return res;
+}
+
+void yt921x_mib_poll(struct work_struct *work)
+{
+ struct yt921x_port *pp = container_of_const(work, struct yt921x_port,
+ mib_read.work);
+ struct yt921x_priv *priv = (void *)(pp - pp->index) -
+ offsetof(struct yt921x_priv, ports);
+ unsigned long delay = YT921X_STATS_INTERVAL_JIFFIES;
+ int port = pp->index;
+ int res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt921x_mib_read(priv, port);
+ mutex_unlock(&priv->reg_lock);
+ if (res)
+ delay *= 4;
+
+ schedule_delayed_work(&pp->mib_read, delay);
+}
+
+void
+yt921x_dsa_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+ uint8_t *data)
+{
+ if (stringset != ETH_SS_STATS)
+ return;
+
+ for (size_t i = 0; i < ARRAY_SIZE(yt921x_mib_descs); i++) {
+ const struct yt921x_mib_desc *desc = &yt921x_mib_descs[i];
+
+ if (desc->name)
+ ethtool_puts(&data, desc->name);
+ }
+}
+
+void
+yt921x_dsa_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
+{
+ struct yt921x_priv *priv = to_yt921x_priv(ds);
+ struct yt921x_port *pp = &priv->ports[port];
+ struct yt921x_mib *mib = &pp->mib;
+ size_t j;
+
+ mutex_lock(&priv->reg_lock);
+ yt921x_mib_read(priv, port);
+ mutex_unlock(&priv->reg_lock);
+
+ j = 0;
+ for (size_t i = 0; i < ARRAY_SIZE(yt921x_mib_descs); i++) {
+ const struct yt921x_mib_desc *desc = &yt921x_mib_descs[i];
+
+ if (!desc->name)
+ continue;
+
+ data[j] = ((u64 *)mib)[i];
+ j++;
+ }
+}
+
+int yt921x_dsa_get_sset_count(struct dsa_switch *ds, int port, int sset)
+{
+ int cnt = 0;
+
+ if (sset != ETH_SS_STATS)
+ return 0;
+
+ for (size_t i = 0; i < ARRAY_SIZE(yt921x_mib_descs); i++) {
+ const struct yt921x_mib_desc *desc = &yt921x_mib_descs[i];
+
+ if (desc->name)
+ cnt++;
+ }
+
+ return cnt;
+}
+
+void
+yt921x_dsa_get_eth_mac_stats(struct dsa_switch *ds, int port,
+ struct ethtool_eth_mac_stats *mac_stats)
+{
+ struct yt921x_priv *priv = to_yt921x_priv(ds);
+ struct yt921x_port *pp = &priv->ports[port];
+ struct yt921x_mib *mib = &pp->mib;
+
+ mutex_lock(&priv->reg_lock);
+ yt921x_mib_read(priv, port);
+ mutex_unlock(&priv->reg_lock);
+
+ mac_stats->FramesTransmittedOK = pp->tx_frames;
+ mac_stats->SingleCollisionFrames = mib->tx_single_collisions;
+ mac_stats->MultipleCollisionFrames = mib->tx_multiple_collisions;
+ mac_stats->FramesReceivedOK = pp->rx_frames;
+ mac_stats->FrameCheckSequenceErrors = mib->rx_crc_errors;
+ mac_stats->AlignmentErrors = mib->rx_alignment_errors;
+ mac_stats->OctetsTransmittedOK = mib->tx_good_bytes;
+ mac_stats->FramesWithDeferredXmissions = mib->tx_deferred;
+ mac_stats->LateCollisions = mib->tx_late_collisions;
+ mac_stats->FramesAbortedDueToXSColls = mib->tx_aborted_errors;
+ /* mac_stats->FramesLostDueToIntMACXmitError */
+ /* mac_stats->CarrierSenseErrors */
+ mac_stats->OctetsReceivedOK = mib->rx_good_bytes;
+ /* mac_stats->FramesLostDueToIntMACRcvError */
+ mac_stats->MulticastFramesXmittedOK = mib->tx_multicast;
+ mac_stats->BroadcastFramesXmittedOK = mib->tx_broadcast;
+ /* mac_stats->FramesWithExcessiveDeferral */
+ mac_stats->MulticastFramesReceivedOK = mib->rx_multicast;
+ mac_stats->BroadcastFramesReceivedOK = mib->rx_broadcast;
+ /* mac_stats->InRangeLengthErrors */
+ /* mac_stats->OutOfRangeLengthField */
+ mac_stats->FrameTooLongErrors = mib->rx_oversize_errors;
+}
+
+void
+yt921x_dsa_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
+ struct ethtool_eth_ctrl_stats *ctrl_stats)
+{
+ struct yt921x_priv *priv = to_yt921x_priv(ds);
+ struct yt921x_port *pp = &priv->ports[port];
+ struct yt921x_mib *mib = &pp->mib;
+
+ mutex_lock(&priv->reg_lock);
+ yt921x_mib_read(priv, port);
+ mutex_unlock(&priv->reg_lock);
+
+ ctrl_stats->MACControlFramesTransmitted = mib->tx_pause;
+ ctrl_stats->MACControlFramesReceived = mib->rx_pause;
+ /* ctrl_stats->UnsupportedOpcodesReceived */
+}
+
+static const struct ethtool_rmon_hist_range yt921x_rmon_ranges[] = {
+ { 0, 64 },
+ { 65, 127 },
+ { 128, 255 },
+ { 256, 511 },
+ { 512, 1023 },
+ { 1024, 1518 },
+ { 1519, YT921X_FRAME_SIZE_MAX },
+ {}
+};
+
+void
+yt921x_dsa_get_rmon_stats(struct dsa_switch *ds, int port,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
+{
+ struct yt921x_priv *priv = to_yt921x_priv(ds);
+ struct yt921x_port *pp = &priv->ports[port];
+ struct yt921x_mib *mib = &pp->mib;
+
+ mutex_lock(&priv->reg_lock);
+ yt921x_mib_read(priv, port);
+ mutex_unlock(&priv->reg_lock);
+
+ *ranges = yt921x_rmon_ranges;
+
+ rmon_stats->undersize_pkts = mib->rx_undersize_errors;
+ rmon_stats->oversize_pkts = mib->rx_oversize_errors;
+ rmon_stats->fragments = mib->rx_alignment_errors;
+ /* rmon_stats->jabbers */
+
+ rmon_stats->hist[0] = mib->rx_64byte;
+ rmon_stats->hist[1] = mib->rx_65_127byte;
+ rmon_stats->hist[2] = mib->rx_128_255byte;
+ rmon_stats->hist[3] = mib->rx_256_511byte;
+ rmon_stats->hist[4] = mib->rx_512_1023byte;
+ rmon_stats->hist[5] = mib->rx_1024_1518byte;
+ rmon_stats->hist[6] = mib->rx_jumbo;
+
+ rmon_stats->hist_tx[0] = mib->tx_64byte;
+ rmon_stats->hist_tx[1] = mib->tx_65_127byte;
+ rmon_stats->hist_tx[2] = mib->tx_128_255byte;
+ rmon_stats->hist_tx[3] = mib->tx_256_511byte;
+ rmon_stats->hist_tx[4] = mib->tx_512_1023byte;
+ rmon_stats->hist_tx[5] = mib->tx_1024_1518byte;
+ rmon_stats->hist_tx[6] = mib->tx_jumbo;
+}
+
+void
+yt921x_dsa_get_stats64(struct dsa_switch *ds, int port,
+ struct rtnl_link_stats64 *stats)
+{
+ struct yt921x_priv *priv = to_yt921x_priv(ds);
+ struct yt921x_port *pp = &priv->ports[port];
+ struct yt921x_mib *mib = &pp->mib;
+
+ stats->rx_length_errors = mib->rx_undersize_errors +
+ mib->rx_fragment_errors;
+ stats->rx_over_errors = mib->rx_oversize_errors;
+ stats->rx_crc_errors = mib->rx_crc_errors;
+ stats->rx_frame_errors = mib->rx_alignment_errors;
+ /* stats->rx_fifo_errors */
+ /* stats->rx_missed_errors */
+
+ stats->tx_aborted_errors = mib->tx_aborted_errors;
+ /* stats->tx_carrier_errors */
+ stats->tx_fifo_errors = mib->tx_undersize_errors;
+ /* stats->tx_heartbeat_errors */
+ stats->tx_window_errors = mib->tx_late_collisions;
+
+ stats->rx_packets = pp->rx_frames;
+ stats->tx_packets = pp->tx_frames;
+ stats->rx_bytes = mib->rx_good_bytes - ETH_FCS_LEN * stats->rx_packets;
+ stats->tx_bytes = mib->tx_good_bytes - ETH_FCS_LEN * stats->tx_packets;
+ 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_dropped = mib->rx_dropped;
+ /* stats->tx_dropped */
+ stats->multicast = mib->rx_multicast;
+ stats->collisions = mib->tx_collisions;
+}
+
+void
+yt921x_dsa_get_pause_stats(struct dsa_switch *ds, int port,
+ struct ethtool_pause_stats *pause_stats)
+{
+ struct yt921x_priv *priv = to_yt921x_priv(ds);
+ struct yt921x_port *pp = &priv->ports[port];
+ struct yt921x_mib *mib = &pp->mib;
+
+ mutex_lock(&priv->reg_lock);
+ yt921x_mib_read(priv, port);
+ mutex_unlock(&priv->reg_lock);
+
+ pause_stats->tx_pause_frames = mib->tx_pause;
+ pause_stats->rx_pause_frames = mib->rx_pause;
+}
diff --git a/drivers/net/dsa/motorcomm/mib.h b/drivers/net/dsa/motorcomm/mib.h
new file mode 100644
index 000000000000..c6728366df6e
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/mib.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#ifndef _YT_MIB_H
+#define _YT_MIB_H
+
+#include <net/dsa.h>
+
+#define YT921X_MIB_CTRL 0xc0004
+#define YT921X_MIB_CTRL_CLEAN BIT(30)
+#define YT921X_MIB_CTRL_PORT_M GENMASK(6, 3)
+#define YT921X_MIB_CTRL_PORT(x) FIELD_PREP(YT921X_MIB_CTRL_PORT_M, (x))
+#define YT921X_MIB_CTRL_ONE_PORT BIT(1)
+#define YT921X_MIB_CTRL_ALL_PORT BIT(0)
+#define YT921X_MIBn_DATA0(port) (0xc0100 + 0x100 * (port))
+#define YT921X_MIBn_DATAm(port, x) (YT921X_MIBn_DATA0(port) + 4 * (x))
+#define YT921X_MIB_DATA_RX_BROADCAST 0x00
+#define YT921X_MIB_DATA_RX_PAUSE 0x04
+#define YT921X_MIB_DATA_RX_MULTICAST 0x08
+#define YT921X_MIB_DATA_RX_CRC_ERR 0x0c
+
+#define YT921X_MIB_DATA_RX_ALIGN_ERR 0x10
+#define YT921X_MIB_DATA_RX_UNDERSIZE_ERR 0x14
+#define YT921X_MIB_DATA_RX_FRAG_ERR 0x18
+#define YT921X_MIB_DATA_RX_PKT_SZ_64 0x1c
+
+#define YT921X_MIB_DATA_RX_PKT_SZ_65_TO_127 0x20
+#define YT921X_MIB_DATA_RX_PKT_SZ_128_TO_255 0x24
+#define YT921X_MIB_DATA_RX_PKT_SZ_256_TO_511 0x28
+#define YT921X_MIB_DATA_RX_PKT_SZ_512_TO_1023 0x2c
+
+#define YT921X_MIB_DATA_RX_PKT_SZ_1024_TO_1518 0x30
+#define YT921X_MIB_DATA_RX_PKT_SZ_1519_TO_MAX 0x34
+/* 0x38: unused */
+#define YT921X_MIB_DATA_RX_GOOD_BYTES 0x3c
+
+/* 0x40: 64 bytes */
+#define YT921X_MIB_DATA_RX_BAD_BYTES 0x44
+/* 0x48: 64 bytes */
+#define YT921X_MIB_DATA_RX_OVERSIZE_ERR 0x4c
+
+#define YT921X_MIB_DATA_RX_DROPPED 0x50
+#define YT921X_MIB_DATA_TX_BROADCAST 0x54
+#define YT921X_MIB_DATA_TX_PAUSE 0x58
+#define YT921X_MIB_DATA_TX_MULTICAST 0x5c
+
+#define YT921X_MIB_DATA_TX_UNDERSIZE_ERR 0x60
+#define YT921X_MIB_DATA_TX_PKT_SZ_64 0x64
+#define YT921X_MIB_DATA_TX_PKT_SZ_65_TO_127 0x68
+#define YT921X_MIB_DATA_TX_PKT_SZ_128_TO_255 0x6c
+
+#define YT921X_MIB_DATA_TX_PKT_SZ_256_TO_511 0x70
+#define YT921X_MIB_DATA_TX_PKT_SZ_512_TO_1023 0x74
+#define YT921X_MIB_DATA_TX_PKT_SZ_1024_TO_1518 0x78
+#define YT921X_MIB_DATA_TX_PKT_SZ_1519_TO_MAX 0x7c
+
+/* 0x80: unused */
+#define YT921X_MIB_DATA_TX_GOOD_BYTES 0x84
+/* 0x88: 64 bytes */
+#define YT921X_MIB_DATA_TX_COLLISION 0x8c
+
+#define YT921X_MIB_DATA_TX_EXCESSIVE_COLLISION 0x90
+#define YT921X_MIB_DATA_TX_MULTIPLE_COLLISION 0x94
+#define YT921X_MIB_DATA_TX_SINGLE_COLLISION 0x98
+#define YT921X_MIB_DATA_TX_PKT 0x9c
+
+#define YT921X_MIB_DATA_TX_DEFERRED 0xa0
+#define YT921X_MIB_DATA_TX_LATE_COLLISION 0xa4
+#define YT921X_MIB_DATA_RX_OAM 0xa8
+#define YT921X_MIB_DATA_TX_OAM 0xac
+
+void yt921x_mib_poll(struct work_struct *work);
+void
+yt921x_dsa_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+ uint8_t *data);
+void
+yt921x_dsa_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
+int yt921x_dsa_get_sset_count(struct dsa_switch *ds, int port, int sset);
+void
+yt921x_dsa_get_eth_mac_stats(struct dsa_switch *ds, int port,
+ struct ethtool_eth_mac_stats *mac_stats);
+void
+yt921x_dsa_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
+ struct ethtool_eth_ctrl_stats *ctrl_stats);
+void
+yt921x_dsa_get_rmon_stats(struct dsa_switch *ds, int port,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges);
+void
+yt921x_dsa_get_stats64(struct dsa_switch *ds, int port,
+ struct rtnl_link_stats64 *stats);
+void
+yt921x_dsa_get_pause_stats(struct dsa_switch *ds, int port,
+ struct ethtool_pause_stats *pause_stats);
+
+#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 2/4] net: dsa: motorcomm: Split MIB buffers
2026-09-03 14:35 [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup David Yang
2026-09-03 14:35 ` [PATCH net-next 1/4] net: dsa: motorcomm: Split MIB module David Yang
@ 2026-09-03 14:35 ` David Yang
2026-09-03 16:17 ` Andrew Lunn
2026-09-03 14:35 ` [PATCH net-next 3/4] net: dsa: motorcomm: Use u64_stats_t for MIB stats David Yang
2026-09-03 14:35 ` [PATCH net-next 4/4] net: dsa: motorcomm: Use safe 64-bit counter reader David Yang
3 siblings, 1 reply; 10+ 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
With MIB improvement introduced later, struct yt921x_priv will be over
20k which is not very good for a single kmalloc(). Dynamically allocate
the MIB structures to reduce the size of struct yt921x_priv, and do not
waste memory on dummy ports.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/chip.c | 42 +++++++++++++++----
drivers/net/dsa/motorcomm/chip.h | 63 ++--------------------------
drivers/net/dsa/motorcomm/mib.c | 70 ++++++++++++++++++++++++--------
drivers/net/dsa/motorcomm/mib.h | 61 ++++++++++++++++++++++++++++
4 files changed, 150 insertions(+), 86 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index 77440bf5fa7a..d8520c38f9c7 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -3591,11 +3591,14 @@ yt921x_phylink_mac_link_down(struct phylink_config *config, unsigned int mode,
{
struct dsa_port *dp = dsa_phylink_to_port(config);
struct yt921x_priv *priv = to_yt921x_priv(dp->ds);
+ struct yt921x_mib *pm;
int port = dp->index;
int res;
/* No need to sync; port control block is hold until device remove */
- cancel_delayed_work(&priv->ports[port].mib_read);
+ pm = priv->ports[port].mib;
+ if (pm)
+ cancel_delayed_work(&pm->work);
mutex_lock(&priv->reg_lock);
res = yt921x_port_down(priv, port);
@@ -3614,6 +3617,7 @@ yt921x_phylink_mac_link_up(struct phylink_config *config,
{
struct dsa_port *dp = dsa_phylink_to_port(config);
struct yt921x_priv *priv = to_yt921x_priv(dp->ds);
+ struct yt921x_mib *pm;
int port = dp->index;
int res;
@@ -3626,7 +3630,9 @@ yt921x_phylink_mac_link_up(struct phylink_config *config,
dev_err(dp->ds->dev, "Failed to %s port %d: %i\n", "bring up",
port, res);
- schedule_delayed_work(&priv->ports[port].mib_read, 0);
+ pm = priv->ports[port].mib;
+ if (pm)
+ schedule_delayed_work(&pm->work, 0);
}
static void
@@ -3746,11 +3752,35 @@ yt921x_dsa_get_tag_protocol(struct dsa_switch *ds, int port,
return DSA_TAG_PROTO_YT921X;
}
+static void yt921x_dsa_port_teardown(struct dsa_switch *ds, int port)
+{
+ struct yt921x_priv *priv = to_yt921x_priv(ds);
+ struct yt921x_port *pp = &priv->ports[port];
+ struct yt921x_mib *pm = pp->mib;
+
+ if (pm)
+ disable_delayed_work_sync(&pm->work);
+}
+
static int yt921x_dsa_port_setup(struct dsa_switch *ds, int port)
{
struct yt921x_priv *priv = to_yt921x_priv(ds);
+ struct yt921x_port *pp = &priv->ports[port];
+ struct device *dev = to_device(priv);
+ struct yt921x_mib *pm = pp->mib;
int res;
+ if (!pm && !(BIT(port) & (priv->info->internal_mask |
+ priv->info->external_mask))) {
+ pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL);
+ if (!pm)
+ return -ENOMEM;
+ pp->mib = pm;
+
+ pm->port = pp;
+ INIT_DELAYED_WORK(&pm->work, yt921x_mib_poll);
+ }
+
mutex_lock(&priv->reg_lock);
res = yt921x_port_setup(priv, port);
mutex_unlock(&priv->reg_lock);
@@ -4305,6 +4335,7 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = {
/* port */
.get_tag_protocol = yt921x_dsa_get_tag_protocol,
.phylink_get_caps = yt921x_dsa_phylink_get_caps,
+ .port_teardown = yt921x_dsa_port_teardown,
.port_setup = yt921x_dsa_port_setup,
#if IS_ENABLED(CONFIG_DCB)
/* dscp */
@@ -4334,12 +4365,6 @@ static void yt921x_mdio_remove(struct mdio_device *mdiodev)
if (!priv)
return;
- for (size_t i = ARRAY_SIZE(priv->ports); i-- > 0; ) {
- struct yt921x_port *pp = &priv->ports[i];
-
- disable_delayed_work_sync(&pp->mib_read);
- }
-
dsa_unregister_switch(&priv->ds);
for (unsigned int i = 0; i < ARRAY_SIZE(priv->acl_blks); i++) {
@@ -4387,7 +4412,6 @@ static int yt921x_mdio_probe(struct mdio_device *mdiodev)
struct yt921x_port *pp = &priv->ports[i];
pp->index = i;
- INIT_DELAYED_WORK(&pp->mib_read, yt921x_mib_poll);
}
ds = &priv->ds;
diff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h
index 84c7065b1cd4..ce2015026849 100644
--- a/drivers/net/dsa/motorcomm/chip.h
+++ b/drivers/net/dsa/motorcomm/chip.h
@@ -798,58 +798,6 @@ enum yt921x_fdb_entry_status {
#define yt921x_port_is_internal(port) ((port) < 8)
#define yt921x_port_is_external(port) ((port) == 8 || (port) == 9)
-struct yt921x_mib {
- u64 rx_broadcast;
- u64 rx_pause;
- u64 rx_multicast;
- u64 rx_crc_errors;
-
- u64 rx_alignment_errors;
- u64 rx_undersize_errors;
- u64 rx_fragment_errors;
- u64 rx_64byte;
-
- u64 rx_65_127byte;
- u64 rx_128_255byte;
- u64 rx_256_511byte;
- u64 rx_512_1023byte;
-
- u64 rx_1024_1518byte;
- u64 rx_jumbo;
- u64 rx_good_bytes;
-
- u64 rx_bad_bytes;
- u64 rx_oversize_errors;
-
- u64 rx_dropped;
- u64 tx_broadcast;
- u64 tx_pause;
- u64 tx_multicast;
-
- u64 tx_undersize_errors;
- u64 tx_64byte;
- u64 tx_65_127byte;
- u64 tx_128_255byte;
-
- u64 tx_256_511byte;
- u64 tx_512_1023byte;
- u64 tx_1024_1518byte;
- u64 tx_jumbo;
-
- u64 tx_good_bytes;
- u64 tx_collisions;
-
- u64 tx_aborted_errors;
- u64 tx_multiple_collisions;
- u64 tx_single_collisions;
- u64 tx_good;
-
- u64 tx_deferred;
- u64 tx_late_collisions;
- u64 rx_oam;
- u64 tx_oam;
-};
-
struct yt921x_acl_entry {
u32 key[2];
u32 mask[2];
@@ -873,13 +821,8 @@ struct yt921x_acl_blk {
struct yt921x_port {
unsigned char index;
- bool hairpin;
- bool isolated;
-
- struct delayed_work mib_read;
- struct yt921x_mib mib;
- u64 rx_frames;
- u64 tx_frames;
+ bool hairpin:1;
+ bool isolated:1;
#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
unsigned char led_duty;
@@ -890,6 +833,8 @@ struct yt921x_port {
struct yt921x_led *leds[YT921X_LED_GROUP_NUM];
#endif
+
+ struct yt921x_mib *mib;
};
struct yt921x_reg_ops {
diff --git a/drivers/net/dsa/motorcomm/mib.c b/drivers/net/dsa/motorcomm/mib.c
index 74728b1ed777..ee76cdf216e6 100644
--- a/drivers/net/dsa/motorcomm/mib.c
+++ b/drivers/net/dsa/motorcomm/mib.c
@@ -89,9 +89,12 @@ static int yt921x_mib_read(struct yt921x_priv *priv, int port)
{
struct yt921x_port *pp = &priv->ports[port];
struct device *dev = to_device(priv);
- struct yt921x_mib *mib = &pp->mib;
+ struct yt921x_mib *pm = pp->mib;
+ struct yt921x_mib_stats *mib;
int res = 0;
+ mib = &pm->stats;
+
/* Reading of yt921x_port::mib is not protected by a lock and it's vain
* to keep its consistency, since we have to read registers one by one
* and there is no way to make a snapshot of MIB stats.
@@ -129,11 +132,11 @@ static int yt921x_mib_read(struct yt921x_priv *priv, int port)
WRITE_ONCE(*valp, val);
}
- pp->rx_frames = mib->rx_64byte + mib->rx_65_127byte +
+ pm->rx_frames = mib->rx_64byte + mib->rx_65_127byte +
mib->rx_128_255byte + mib->rx_256_511byte +
mib->rx_512_1023byte + mib->rx_1024_1518byte +
mib->rx_jumbo;
- pp->tx_frames = mib->tx_64byte + mib->tx_65_127byte +
+ pm->tx_frames = mib->tx_64byte + mib->tx_65_127byte +
mib->tx_128_255byte + mib->tx_256_511byte +
mib->tx_512_1023byte + mib->tx_1024_1518byte +
mib->tx_jumbo;
@@ -146,10 +149,11 @@ static int yt921x_mib_read(struct yt921x_priv *priv, int port)
void yt921x_mib_poll(struct work_struct *work)
{
- struct yt921x_port *pp = container_of_const(work, struct yt921x_port,
- mib_read.work);
- struct yt921x_priv *priv = (void *)(pp - pp->index) -
- offsetof(struct yt921x_priv, ports);
+ struct yt921x_mib *pm = container_of_const(work, struct yt921x_mib,
+ work.work);
+ struct yt921x_port *pp = pm->port;
+ struct yt921x_priv *priv = container_of_const(pp, struct yt921x_priv,
+ ports[pp->index]);
unsigned long delay = YT921X_STATS_INTERVAL_JIFFIES;
int port = pp->index;
int res;
@@ -160,7 +164,7 @@ void yt921x_mib_poll(struct work_struct *work)
if (res)
delay *= 4;
- schedule_delayed_work(&pp->mib_read, delay);
+ schedule_delayed_work(&pm->work, delay);
}
void
@@ -183,9 +187,14 @@ yt921x_dsa_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
{
struct yt921x_priv *priv = to_yt921x_priv(ds);
struct yt921x_port *pp = &priv->ports[port];
- struct yt921x_mib *mib = &pp->mib;
+ struct yt921x_mib *pm = pp->mib;
+ struct yt921x_mib_stats *mib;
size_t j;
+ if (!pm)
+ return;
+ mib = &pm->stats;
+
mutex_lock(&priv->reg_lock);
yt921x_mib_read(priv, port);
mutex_unlock(&priv->reg_lock);
@@ -225,16 +234,21 @@ yt921x_dsa_get_eth_mac_stats(struct dsa_switch *ds, int port,
{
struct yt921x_priv *priv = to_yt921x_priv(ds);
struct yt921x_port *pp = &priv->ports[port];
- struct yt921x_mib *mib = &pp->mib;
+ struct yt921x_mib *pm = pp->mib;
+ struct yt921x_mib_stats *mib;
+
+ if (!pm)
+ return;
+ mib = &pm->stats;
mutex_lock(&priv->reg_lock);
yt921x_mib_read(priv, port);
mutex_unlock(&priv->reg_lock);
- mac_stats->FramesTransmittedOK = pp->tx_frames;
+ mac_stats->FramesTransmittedOK = pm->tx_frames;
mac_stats->SingleCollisionFrames = mib->tx_single_collisions;
mac_stats->MultipleCollisionFrames = mib->tx_multiple_collisions;
- mac_stats->FramesReceivedOK = pp->rx_frames;
+ mac_stats->FramesReceivedOK = pm->rx_frames;
mac_stats->FrameCheckSequenceErrors = mib->rx_crc_errors;
mac_stats->AlignmentErrors = mib->rx_alignment_errors;
mac_stats->OctetsTransmittedOK = mib->tx_good_bytes;
@@ -261,7 +275,12 @@ yt921x_dsa_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
{
struct yt921x_priv *priv = to_yt921x_priv(ds);
struct yt921x_port *pp = &priv->ports[port];
- struct yt921x_mib *mib = &pp->mib;
+ struct yt921x_mib *pm = pp->mib;
+ struct yt921x_mib_stats *mib;
+
+ if (!pm)
+ return;
+ mib = &pm->stats;
mutex_lock(&priv->reg_lock);
yt921x_mib_read(priv, port);
@@ -290,7 +309,12 @@ yt921x_dsa_get_rmon_stats(struct dsa_switch *ds, int port,
{
struct yt921x_priv *priv = to_yt921x_priv(ds);
struct yt921x_port *pp = &priv->ports[port];
- struct yt921x_mib *mib = &pp->mib;
+ struct yt921x_mib *pm = pp->mib;
+ struct yt921x_mib_stats *mib;
+
+ if (!pm)
+ return;
+ mib = &pm->stats;
mutex_lock(&priv->reg_lock);
yt921x_mib_read(priv, port);
@@ -326,7 +350,12 @@ yt921x_dsa_get_stats64(struct dsa_switch *ds, int port,
{
struct yt921x_priv *priv = to_yt921x_priv(ds);
struct yt921x_port *pp = &priv->ports[port];
- struct yt921x_mib *mib = &pp->mib;
+ struct yt921x_mib *pm = pp->mib;
+ struct yt921x_mib_stats *mib;
+
+ if (!pm)
+ return;
+ mib = &pm->stats;
stats->rx_length_errors = mib->rx_undersize_errors +
mib->rx_fragment_errors;
@@ -342,8 +371,8 @@ yt921x_dsa_get_stats64(struct dsa_switch *ds, int port,
/* stats->tx_heartbeat_errors */
stats->tx_window_errors = mib->tx_late_collisions;
- stats->rx_packets = pp->rx_frames;
- stats->tx_packets = pp->tx_frames;
+ stats->rx_packets = pm->rx_frames;
+ stats->tx_packets = pm->tx_frames;
stats->rx_bytes = mib->rx_good_bytes - ETH_FCS_LEN * stats->rx_packets;
stats->tx_bytes = mib->tx_good_bytes - ETH_FCS_LEN * stats->tx_packets;
stats->rx_errors = stats->rx_length_errors + stats->rx_over_errors +
@@ -362,7 +391,12 @@ yt921x_dsa_get_pause_stats(struct dsa_switch *ds, int port,
{
struct yt921x_priv *priv = to_yt921x_priv(ds);
struct yt921x_port *pp = &priv->ports[port];
- struct yt921x_mib *mib = &pp->mib;
+ struct yt921x_mib *pm = pp->mib;
+ struct yt921x_mib_stats *mib;
+
+ if (!pm)
+ return;
+ mib = &pm->stats;
mutex_lock(&priv->reg_lock);
yt921x_mib_read(priv, port);
diff --git a/drivers/net/dsa/motorcomm/mib.h b/drivers/net/dsa/motorcomm/mib.h
index c6728366df6e..cfad0665baae 100644
--- a/drivers/net/dsa/motorcomm/mib.h
+++ b/drivers/net/dsa/motorcomm/mib.h
@@ -71,6 +71,67 @@
#define YT921X_MIB_DATA_RX_OAM 0xa8
#define YT921X_MIB_DATA_TX_OAM 0xac
+struct yt921x_mib_stats {
+ u64 rx_broadcast;
+ u64 rx_pause;
+ u64 rx_multicast;
+ u64 rx_crc_errors;
+
+ u64 rx_alignment_errors;
+ u64 rx_undersize_errors;
+ u64 rx_fragment_errors;
+ u64 rx_64byte;
+
+ u64 rx_65_127byte;
+ u64 rx_128_255byte;
+ u64 rx_256_511byte;
+ u64 rx_512_1023byte;
+
+ u64 rx_1024_1518byte;
+ u64 rx_jumbo;
+ u64 rx_good_bytes;
+
+ u64 rx_bad_bytes;
+ u64 rx_oversize_errors;
+
+ u64 rx_dropped;
+ u64 tx_broadcast;
+ u64 tx_pause;
+ u64 tx_multicast;
+
+ u64 tx_undersize_errors;
+ u64 tx_64byte;
+ u64 tx_65_127byte;
+ u64 tx_128_255byte;
+
+ u64 tx_256_511byte;
+ u64 tx_512_1023byte;
+ u64 tx_1024_1518byte;
+ u64 tx_jumbo;
+
+ u64 tx_good_bytes;
+ u64 tx_collisions;
+
+ u64 tx_aborted_errors;
+ u64 tx_multiple_collisions;
+ u64 tx_single_collisions;
+ u64 tx_good;
+
+ u64 tx_deferred;
+ u64 tx_late_collisions;
+ u64 rx_oam;
+ u64 tx_oam;
+};
+
+struct yt921x_mib {
+ struct yt921x_port *port;
+
+ struct delayed_work work;
+ struct yt921x_mib_stats stats;
+ u64 rx_frames;
+ u64 tx_frames;
+};
+
void yt921x_mib_poll(struct work_struct *work);
void
yt921x_dsa_get_strings(struct dsa_switch *ds, int port, u32 stringset,
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 3/4] net: dsa: motorcomm: Use u64_stats_t for MIB stats
2026-09-03 14:35 [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup David Yang
2026-09-03 14:35 ` [PATCH net-next 1/4] net: dsa: motorcomm: Split MIB module David Yang
2026-09-03 14:35 ` [PATCH net-next 2/4] net: dsa: motorcomm: Split MIB buffers David Yang
@ 2026-09-03 14:35 ` David Yang
2026-09-03 16:25 ` Andrew Lunn
2026-09-03 14:35 ` [PATCH net-next 4/4] net: dsa: motorcomm: Use safe 64-bit counter reader David Yang
3 siblings, 1 reply; 10+ 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
64-bit variables might not be atomic on 32-bit architectures, and could
lead to load/store tearing. Use u64_stats_t to ensure consistency.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/chip.c | 2 +
drivers/net/dsa/motorcomm/mib.c | 196 +++++++++++++++++--------------
drivers/net/dsa/motorcomm/mib.h | 110 +++++++++--------
3 files changed, 172 insertions(+), 136 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index d8520c38f9c7..b4059053ef15 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -19,6 +19,7 @@
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/sort.h>
+#include <linux/u64_stats_sync.h>
#include <net/dsa.h>
#include <net/dscp.h>
@@ -3778,6 +3779,7 @@ static int yt921x_dsa_port_setup(struct dsa_switch *ds, int port)
pp->mib = pm;
pm->port = pp;
+ u64_stats_init(&pm->syncp);
INIT_DELAYED_WORK(&pm->work, yt921x_mib_poll);
}
diff --git a/drivers/net/dsa/motorcomm/mib.c b/drivers/net/dsa/motorcomm/mib.c
index ee76cdf216e6..73b2a9f52996 100644
--- a/drivers/net/dsa/motorcomm/mib.c
+++ b/drivers/net/dsa/motorcomm/mib.c
@@ -91,22 +91,16 @@ static int yt921x_mib_read(struct yt921x_priv *priv, int port)
struct device *dev = to_device(priv);
struct yt921x_mib *pm = pp->mib;
struct yt921x_mib_stats *mib;
+ u64 *buf = pm->data;
+ u64 rx_frames;
+ u64 tx_frames;
int res = 0;
mib = &pm->stats;
- /* Reading of yt921x_port::mib is not protected by a lock and it's vain
- * to keep its consistency, since we have to read registers one by one
- * and there is no way to make a snapshot of MIB stats.
- *
- * Writing (by this function only) is and should be protected by
- * reg_lock.
- */
-
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;
- u64 *valp = &((u64 *)mib)[i];
u32 val0;
u64 val;
@@ -115,7 +109,7 @@ static int yt921x_mib_read(struct yt921x_priv *priv, int port)
break;
if (desc->size <= 1) {
- u64 old_val = *valp;
+ u64 old_val = buf[i];
val = (old_val & ~(u64)U32_MAX) | val0;
if (val < old_val)
@@ -129,17 +123,29 @@ static int yt921x_mib_read(struct yt921x_priv *priv, int port)
val = ((u64)val1 << 32) | val0;
}
- WRITE_ONCE(*valp, val);
+ buf[i] = val;
}
- pm->rx_frames = mib->rx_64byte + mib->rx_65_127byte +
- mib->rx_128_255byte + mib->rx_256_511byte +
- mib->rx_512_1023byte + mib->rx_1024_1518byte +
- mib->rx_jumbo;
- pm->tx_frames = mib->tx_64byte + mib->tx_65_127byte +
- mib->tx_128_255byte + mib->tx_256_511byte +
- mib->tx_512_1023byte + mib->tx_1024_1518byte +
- mib->tx_jumbo;
+ u64_stats_update_begin(&pm->syncp);
+ for (size_t i = 0; i < ARRAY_SIZE(yt921x_mib_descs); i++)
+ u64_stats_set(&((u64_stats_t *)mib)[i], buf[i]);
+ rx_frames = u64_stats_read(&mib->rx_64byte) +
+ u64_stats_read(&mib->rx_65_127byte) +
+ u64_stats_read(&mib->rx_128_255byte) +
+ u64_stats_read(&mib->rx_256_511byte) +
+ u64_stats_read(&mib->rx_512_1023byte) +
+ u64_stats_read(&mib->rx_1024_1518byte) +
+ u64_stats_read(&mib->rx_jumbo);
+ tx_frames = u64_stats_read(&mib->tx_64byte) +
+ u64_stats_read(&mib->tx_65_127byte) +
+ u64_stats_read(&mib->tx_128_255byte) +
+ u64_stats_read(&mib->tx_256_511byte) +
+ u64_stats_read(&mib->tx_512_1023byte) +
+ u64_stats_read(&mib->tx_1024_1518byte) +
+ u64_stats_read(&mib->tx_jumbo);
+ u64_stats_set(&pm->rx_frames, rx_frames);
+ u64_stats_set(&pm->tx_frames, tx_frames);
+ u64_stats_update_end(&pm->syncp);
if (res)
dev_err(dev, "Failed to %s port %d: %i\n", "read stats for",
@@ -189,15 +195,17 @@ yt921x_dsa_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
struct yt921x_port *pp = &priv->ports[port];
struct yt921x_mib *pm = pp->mib;
struct yt921x_mib_stats *mib;
+ u64 *buf;
size_t j;
if (!pm)
return;
mib = &pm->stats;
+ buf = pm->data;
mutex_lock(&priv->reg_lock);
+
yt921x_mib_read(priv, port);
- mutex_unlock(&priv->reg_lock);
j = 0;
for (size_t i = 0; i < ARRAY_SIZE(yt921x_mib_descs); i++) {
@@ -206,9 +214,11 @@ yt921x_dsa_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
if (!desc->name)
continue;
- data[j] = ((u64 *)mib)[i];
+ data[j] = buf[i];
j++;
}
+
+ mutex_unlock(&priv->reg_lock);
}
int yt921x_dsa_get_sset_count(struct dsa_switch *ds, int port, int sset)
@@ -242,31 +252,33 @@ yt921x_dsa_get_eth_mac_stats(struct dsa_switch *ds, int port,
mib = &pm->stats;
mutex_lock(&priv->reg_lock);
+
yt921x_mib_read(priv, port);
- mutex_unlock(&priv->reg_lock);
- mac_stats->FramesTransmittedOK = pm->tx_frames;
- mac_stats->SingleCollisionFrames = mib->tx_single_collisions;
- mac_stats->MultipleCollisionFrames = mib->tx_multiple_collisions;
- mac_stats->FramesReceivedOK = pm->rx_frames;
- mac_stats->FrameCheckSequenceErrors = mib->rx_crc_errors;
- mac_stats->AlignmentErrors = mib->rx_alignment_errors;
- mac_stats->OctetsTransmittedOK = mib->tx_good_bytes;
- mac_stats->FramesWithDeferredXmissions = mib->tx_deferred;
- mac_stats->LateCollisions = mib->tx_late_collisions;
- mac_stats->FramesAbortedDueToXSColls = mib->tx_aborted_errors;
+ mac_stats->FramesTransmittedOK = u64_stats_read(&pm->tx_frames);
+ mac_stats->SingleCollisionFrames = u64_stats_read(&mib->tx_single_collisions);
+ mac_stats->MultipleCollisionFrames = u64_stats_read(&mib->tx_multiple_collisions);
+ mac_stats->FramesReceivedOK = u64_stats_read(&pm->rx_frames);
+ mac_stats->FrameCheckSequenceErrors = u64_stats_read(&mib->rx_crc_errors);
+ mac_stats->AlignmentErrors = u64_stats_read(&mib->rx_alignment_errors);
+ mac_stats->OctetsTransmittedOK = u64_stats_read(&mib->tx_good_bytes);
+ mac_stats->FramesWithDeferredXmissions = u64_stats_read(&mib->tx_deferred);
+ mac_stats->LateCollisions = u64_stats_read(&mib->tx_late_collisions);
+ mac_stats->FramesAbortedDueToXSColls = u64_stats_read(&mib->tx_aborted_errors);
/* mac_stats->FramesLostDueToIntMACXmitError */
/* mac_stats->CarrierSenseErrors */
- mac_stats->OctetsReceivedOK = mib->rx_good_bytes;
+ mac_stats->OctetsReceivedOK = u64_stats_read(&mib->rx_good_bytes);
/* mac_stats->FramesLostDueToIntMACRcvError */
- mac_stats->MulticastFramesXmittedOK = mib->tx_multicast;
- mac_stats->BroadcastFramesXmittedOK = mib->tx_broadcast;
+ mac_stats->MulticastFramesXmittedOK = u64_stats_read(&mib->tx_multicast);
+ mac_stats->BroadcastFramesXmittedOK = u64_stats_read(&mib->tx_broadcast);
/* mac_stats->FramesWithExcessiveDeferral */
- mac_stats->MulticastFramesReceivedOK = mib->rx_multicast;
- mac_stats->BroadcastFramesReceivedOK = mib->rx_broadcast;
+ mac_stats->MulticastFramesReceivedOK = u64_stats_read(&mib->rx_multicast);
+ mac_stats->BroadcastFramesReceivedOK = u64_stats_read(&mib->rx_broadcast);
/* mac_stats->InRangeLengthErrors */
/* mac_stats->OutOfRangeLengthField */
- mac_stats->FrameTooLongErrors = mib->rx_oversize_errors;
+ mac_stats->FrameTooLongErrors = u64_stats_read(&mib->rx_oversize_errors);
+
+ mutex_unlock(&priv->reg_lock);
}
void
@@ -283,12 +295,14 @@ yt921x_dsa_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
mib = &pm->stats;
mutex_lock(&priv->reg_lock);
+
yt921x_mib_read(priv, port);
- mutex_unlock(&priv->reg_lock);
- ctrl_stats->MACControlFramesTransmitted = mib->tx_pause;
- ctrl_stats->MACControlFramesReceived = mib->rx_pause;
+ ctrl_stats->MACControlFramesTransmitted = u64_stats_read(&mib->tx_pause);
+ ctrl_stats->MACControlFramesReceived = u64_stats_read(&mib->rx_pause);
/* ctrl_stats->UnsupportedOpcodesReceived */
+
+ mutex_unlock(&priv->reg_lock);
}
static const struct ethtool_rmon_hist_range yt921x_rmon_ranges[] = {
@@ -317,31 +331,33 @@ yt921x_dsa_get_rmon_stats(struct dsa_switch *ds, int port,
mib = &pm->stats;
mutex_lock(&priv->reg_lock);
+
yt921x_mib_read(priv, port);
- mutex_unlock(&priv->reg_lock);
*ranges = yt921x_rmon_ranges;
- rmon_stats->undersize_pkts = mib->rx_undersize_errors;
- rmon_stats->oversize_pkts = mib->rx_oversize_errors;
- rmon_stats->fragments = mib->rx_alignment_errors;
+ 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->jabbers */
- rmon_stats->hist[0] = mib->rx_64byte;
- rmon_stats->hist[1] = mib->rx_65_127byte;
- rmon_stats->hist[2] = mib->rx_128_255byte;
- rmon_stats->hist[3] = mib->rx_256_511byte;
- rmon_stats->hist[4] = mib->rx_512_1023byte;
- rmon_stats->hist[5] = mib->rx_1024_1518byte;
- rmon_stats->hist[6] = mib->rx_jumbo;
-
- rmon_stats->hist_tx[0] = mib->tx_64byte;
- rmon_stats->hist_tx[1] = mib->tx_65_127byte;
- rmon_stats->hist_tx[2] = mib->tx_128_255byte;
- rmon_stats->hist_tx[3] = mib->tx_256_511byte;
- rmon_stats->hist_tx[4] = mib->tx_512_1023byte;
- rmon_stats->hist_tx[5] = mib->tx_1024_1518byte;
- rmon_stats->hist_tx[6] = mib->tx_jumbo;
+ rmon_stats->hist[0] = u64_stats_read(&mib->rx_64byte);
+ rmon_stats->hist[1] = u64_stats_read(&mib->rx_65_127byte);
+ rmon_stats->hist[2] = u64_stats_read(&mib->rx_128_255byte);
+ rmon_stats->hist[3] = u64_stats_read(&mib->rx_256_511byte);
+ rmon_stats->hist[4] = u64_stats_read(&mib->rx_512_1023byte);
+ rmon_stats->hist[5] = u64_stats_read(&mib->rx_1024_1518byte);
+ rmon_stats->hist[6] = u64_stats_read(&mib->rx_jumbo);
+
+ rmon_stats->hist_tx[0] = u64_stats_read(&mib->tx_64byte);
+ rmon_stats->hist_tx[1] = u64_stats_read(&mib->tx_65_127byte);
+ rmon_stats->hist_tx[2] = u64_stats_read(&mib->tx_128_255byte);
+ rmon_stats->hist_tx[3] = u64_stats_read(&mib->tx_256_511byte);
+ rmon_stats->hist_tx[4] = u64_stats_read(&mib->tx_512_1023byte);
+ rmon_stats->hist_tx[5] = u64_stats_read(&mib->tx_1024_1518byte);
+ rmon_stats->hist_tx[6] = u64_stats_read(&mib->tx_jumbo);
+
+ mutex_unlock(&priv->reg_lock);
}
void
@@ -352,37 +368,45 @@ yt921x_dsa_get_stats64(struct dsa_switch *ds, int port,
struct yt921x_port *pp = &priv->ports[port];
struct yt921x_mib *pm = pp->mib;
struct yt921x_mib_stats *mib;
+ unsigned int start;
if (!pm)
return;
mib = &pm->stats;
- stats->rx_length_errors = mib->rx_undersize_errors +
- mib->rx_fragment_errors;
- stats->rx_over_errors = mib->rx_oversize_errors;
- stats->rx_crc_errors = mib->rx_crc_errors;
- stats->rx_frame_errors = mib->rx_alignment_errors;
- /* stats->rx_fifo_errors */
- /* stats->rx_missed_errors */
-
- stats->tx_aborted_errors = mib->tx_aborted_errors;
- /* stats->tx_carrier_errors */
- stats->tx_fifo_errors = mib->tx_undersize_errors;
- /* stats->tx_heartbeat_errors */
- stats->tx_window_errors = mib->tx_late_collisions;
-
- stats->rx_packets = pm->rx_frames;
- stats->tx_packets = pm->tx_frames;
- stats->rx_bytes = mib->rx_good_bytes - ETH_FCS_LEN * stats->rx_packets;
- stats->tx_bytes = mib->tx_good_bytes - ETH_FCS_LEN * stats->tx_packets;
+ do {
+ 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);
+ 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 */
+ /* stats->rx_missed_errors */
+
+ 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_heartbeat_errors */
+ stats->tx_window_errors = u64_stats_read(&mib->tx_late_collisions);
+
+ 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_dropped = u64_stats_read(&mib->rx_dropped);
+ /* stats->tx_dropped */
+ stats->multicast = u64_stats_read(&mib->rx_multicast);
+ 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_dropped = mib->rx_dropped;
- /* stats->tx_dropped */
- stats->multicast = mib->rx_multicast;
- stats->collisions = mib->tx_collisions;
}
void
@@ -399,9 +423,11 @@ yt921x_dsa_get_pause_stats(struct dsa_switch *ds, int port,
mib = &pm->stats;
mutex_lock(&priv->reg_lock);
+
yt921x_mib_read(priv, port);
- mutex_unlock(&priv->reg_lock);
- pause_stats->tx_pause_frames = mib->tx_pause;
- pause_stats->rx_pause_frames = mib->rx_pause;
+ pause_stats->tx_pause_frames = u64_stats_read(&mib->tx_pause);
+ pause_stats->rx_pause_frames = u64_stats_read(&mib->rx_pause);
+
+ mutex_unlock(&priv->reg_lock);
}
diff --git a/drivers/net/dsa/motorcomm/mib.h b/drivers/net/dsa/motorcomm/mib.h
index cfad0665baae..33992a5f9bdc 100644
--- a/drivers/net/dsa/motorcomm/mib.h
+++ b/drivers/net/dsa/motorcomm/mib.h
@@ -6,6 +6,8 @@
#ifndef _YT_MIB_H
#define _YT_MIB_H
+#include <linux/u64_stats_sync.h>
+
#include <net/dsa.h>
#define YT921X_MIB_CTRL 0xc0004
@@ -72,64 +74,70 @@
#define YT921X_MIB_DATA_TX_OAM 0xac
struct yt921x_mib_stats {
- u64 rx_broadcast;
- u64 rx_pause;
- u64 rx_multicast;
- u64 rx_crc_errors;
-
- u64 rx_alignment_errors;
- u64 rx_undersize_errors;
- u64 rx_fragment_errors;
- u64 rx_64byte;
-
- u64 rx_65_127byte;
- u64 rx_128_255byte;
- u64 rx_256_511byte;
- u64 rx_512_1023byte;
-
- u64 rx_1024_1518byte;
- u64 rx_jumbo;
- u64 rx_good_bytes;
-
- u64 rx_bad_bytes;
- u64 rx_oversize_errors;
-
- u64 rx_dropped;
- u64 tx_broadcast;
- u64 tx_pause;
- u64 tx_multicast;
-
- u64 tx_undersize_errors;
- u64 tx_64byte;
- u64 tx_65_127byte;
- u64 tx_128_255byte;
-
- u64 tx_256_511byte;
- u64 tx_512_1023byte;
- u64 tx_1024_1518byte;
- u64 tx_jumbo;
-
- u64 tx_good_bytes;
- u64 tx_collisions;
-
- u64 tx_aborted_errors;
- u64 tx_multiple_collisions;
- u64 tx_single_collisions;
- u64 tx_good;
-
- u64 tx_deferred;
- u64 tx_late_collisions;
- u64 rx_oam;
- u64 tx_oam;
+ u64_stats_t rx_broadcast;
+ u64_stats_t rx_pause;
+ u64_stats_t rx_multicast;
+ u64_stats_t rx_crc_errors;
+
+ u64_stats_t rx_alignment_errors;
+ u64_stats_t rx_undersize_errors;
+ u64_stats_t rx_fragment_errors;
+ u64_stats_t rx_64byte;
+
+ u64_stats_t rx_65_127byte;
+ u64_stats_t rx_128_255byte;
+ u64_stats_t rx_256_511byte;
+ u64_stats_t rx_512_1023byte;
+
+ u64_stats_t rx_1024_1518byte;
+ u64_stats_t rx_jumbo;
+ u64_stats_t rx_good_bytes;
+
+ u64_stats_t rx_bad_bytes;
+ u64_stats_t rx_oversize_errors;
+
+ u64_stats_t rx_dropped;
+ u64_stats_t tx_broadcast;
+ u64_stats_t tx_pause;
+ u64_stats_t tx_multicast;
+
+ u64_stats_t tx_undersize_errors;
+ u64_stats_t tx_64byte;
+ u64_stats_t tx_65_127byte;
+ u64_stats_t tx_128_255byte;
+
+ u64_stats_t tx_256_511byte;
+ u64_stats_t tx_512_1023byte;
+ u64_stats_t tx_1024_1518byte;
+ u64_stats_t tx_jumbo;
+
+ u64_stats_t tx_good_bytes;
+ u64_stats_t tx_collisions;
+
+ u64_stats_t tx_aborted_errors;
+ u64_stats_t tx_multiple_collisions;
+ u64_stats_t tx_single_collisions;
+ u64_stats_t tx_good;
+
+ u64_stats_t tx_deferred;
+ u64_stats_t tx_late_collisions;
+ u64_stats_t rx_oam;
+ u64_stats_t tx_oam;
};
+#define YT921X_MIB_NUM (sizeof(struct yt921x_mib_stats) / sizeof(u64_stats_t))
+
struct yt921x_mib {
struct yt921x_port *port;
struct delayed_work work;
+ struct u64_stats_sync syncp;
+ /* protected by syncp OR priv->reg_lock */
struct yt921x_mib_stats stats;
- u64 rx_frames;
- u64 tx_frames;
+ u64_stats_t rx_frames;
+ u64_stats_t tx_frames;
+ /* protected by priv->reg_lock */
+ u64 data[YT921X_MIB_NUM];
};
void yt921x_mib_poll(struct work_struct *work);
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 4/4] net: dsa: motorcomm: Use safe 64-bit counter reader
2026-09-03 14:35 [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup David Yang
` (2 preceding siblings ...)
2026-09-03 14:35 ` [PATCH net-next 3/4] net: dsa: motorcomm: Use u64_stats_t for MIB stats David Yang
@ 2026-09-03 14:35 ` David Yang
3 siblings, 0 replies; 10+ 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
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 | 21 +++++++++------------
drivers/net/dsa/motorcomm/smi.c | 30 ++++++++++++++++++++++++++++++
drivers/net/dsa/motorcomm/smi.h | 2 ++
3 files changed, 41 insertions(+), 12 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/mib.c b/drivers/net/dsa/motorcomm/mib.c
index 73b2a9f52996..30478ce71c10 100644
--- a/drivers/net/dsa/motorcomm/mib.c
+++ b/drivers/net/dsa/motorcomm/mib.c
@@ -101,29 +101,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;
}
u64_stats_update_begin(&pm->syncp);
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
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH net-next 1/4] net: dsa: motorcomm: Split MIB module
2026-09-03 14:35 ` [PATCH net-next 1/4] net: dsa: motorcomm: Split MIB module David Yang
@ 2026-09-03 15:01 ` Andrew Lunn
0 siblings, 0 replies; 10+ messages in thread
From: Andrew Lunn @ 2026-09-03 15:01 UTC (permalink / raw)
To: David Yang
Cc: netdev, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Russell King, linux-kernel
On Thu, Sep 03, 2026 at 10:35:06PM +0800, David Yang wrote:
> yt922x is going to use a different MIB scheme, split it to reduce the
> length of chip.c.
>
> pp->index = i;
> - INIT_DELAYED_WORK(&pp->mib_read, yt921x_poll_mib);
> + INIT_DELAYED_WORK(&pp->mib_read, yt921x_mib_poll);
This suggests the change is not purely moving code around, but also a
rename? I then ask myself, do i need to review the code in detail?
Please try to make patches which move code only move code. Then add
patches which do renames.
Andrew
---
pw-bot: cr
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next 2/4] net: dsa: motorcomm: Split MIB buffers
2026-09-03 14:35 ` [PATCH net-next 2/4] net: dsa: motorcomm: Split MIB buffers David Yang
@ 2026-09-03 16:17 ` Andrew Lunn
0 siblings, 0 replies; 10+ messages in thread
From: Andrew Lunn @ 2026-09-03 16:17 UTC (permalink / raw)
To: David Yang
Cc: netdev, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Russell King, linux-kernel
On Thu, Sep 03, 2026 at 10:35:07PM +0800, David Yang wrote:
> With MIB improvement introduced later, struct yt921x_priv will be over
> 20k which is not very good for a single kmalloc(). Dynamically allocate
> the MIB structures to reduce the size of struct yt921x_priv, and do not
> waste memory on dummy ports.
When you read this....
>
> -struct yt921x_mib {
> - u64 rx_broadcast;
> - u64 rx_pause;
> - u64 rx_multicast;
> - u64 rx_crc_errors;
> -
>
> +struct yt921x_mib_stats {
> + u64 rx_broadcast;
> + u64 rx_pause;
> + u64 rx_multicast;
> + u64 rx_crc_errors;
It does not explain "Why?" this structure got renamed.
> +struct yt921x_mib {
> + struct yt921x_port *port;
> +
> + struct delayed_work work;
> + struct yt921x_mib_stats stats;
> + u64 rx_frames;
> + u64 tx_frames;
> +};
And the old structure gets new contents.
I find this confusing, and not easy to review.
Maybe avoid the rename, and call this new structure something else?
Maybe break this up into a number of patches, do things one step at a
time, making it easier to review, lots of small changes which are
obviously correct?
Andrew
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next 3/4] net: dsa: motorcomm: Use u64_stats_t for MIB stats
2026-09-03 14:35 ` [PATCH net-next 3/4] net: dsa: motorcomm: Use u64_stats_t for MIB stats David Yang
@ 2026-09-03 16:25 ` Andrew Lunn
2026-09-04 2:58 ` David Yang
0 siblings, 1 reply; 10+ messages in thread
From: Andrew Lunn @ 2026-09-03 16:25 UTC (permalink / raw)
To: David Yang
Cc: netdev, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Russell King, linux-kernel
On Thu, Sep 03, 2026 at 10:35:08PM +0800, David Yang wrote:
> 64-bit variables might not be atomic on 32-bit architectures, and could
> lead to load/store tearing. Use u64_stats_t to ensure consistency.
Can this patch also be broken up. It should be possible to use
u64_stats_read() without changing the locking? So one patch which only
does u64_stats_read(). You should then be able to add the syncp
code. And lastly the mutex changes. That then allows you to explain
why the mutex changes are safe in the commit message.
Andrew
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next 3/4] net: dsa: motorcomm: Use u64_stats_t for MIB stats
2026-09-03 16:25 ` Andrew Lunn
@ 2026-09-04 2:58 ` David Yang
2026-09-04 13:03 ` Andrew Lunn
0 siblings, 1 reply; 10+ messages in thread
From: David Yang @ 2026-09-04 2:58 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Russell King, linux-kernel
On Fri, Sep 4, 2026 at 12:25 AM Andrew Lunn <andrew@lunn.ch> wrote:
>
> On Thu, Sep 03, 2026 at 10:35:08PM +0800, David Yang wrote:
> > 64-bit variables might not be atomic on 32-bit architectures, and could
> > lead to load/store tearing. Use u64_stats_t to ensure consistency.
>
> Can this patch also be broken up. It should be possible to use
> u64_stats_read() without changing the locking? So one patch which only
> does u64_stats_read(). You should then be able to add the syncp
> code. And lastly the mutex changes. That then allows you to explain
> why the mutex changes are safe in the commit message.
>
> Andrew
u64_stats_read are meant to be used with syncp. This sounds like an
incorrect partial patch, works only because of the internal
implementation of u64_stats_t.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next 3/4] net: dsa: motorcomm: Use u64_stats_t for MIB stats
2026-09-04 2:58 ` David Yang
@ 2026-09-04 13:03 ` Andrew Lunn
0 siblings, 0 replies; 10+ messages in thread
From: Andrew Lunn @ 2026-09-04 13:03 UTC (permalink / raw)
To: David Yang
Cc: netdev, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Russell King, linux-kernel
On Fri, Sep 04, 2026 at 10:58:06AM +0800, David Yang wrote:
> On Fri, Sep 4, 2026 at 12:25 AM Andrew Lunn <andrew@lunn.ch> wrote:
> >
> > On Thu, Sep 03, 2026 at 10:35:08PM +0800, David Yang wrote:
> > > 64-bit variables might not be atomic on 32-bit architectures, and could
> > > lead to load/store tearing. Use u64_stats_t to ensure consistency.
> >
> > Can this patch also be broken up. It should be possible to use
> > u64_stats_read() without changing the locking? So one patch which only
> > does u64_stats_read(). You should then be able to add the syncp
> > code. And lastly the mutex changes. That then allows you to explain
> > why the mutex changes are safe in the commit message.
> >
> > Andrew
>
> u64_stats_read are meant to be used with syncp. This sounds like an
> incorrect partial patch, works only because of the internal
> implementation of u64_stats_t.
What is making the current code correct? The mutex? So long as you
have the mutex, the code is still correct?
You can say in the commit message this is an intermediary step doing
the mechanical work of introducing u64_stats_t. The following patches
will then change the locking to be more efficient.
Andrew
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-09-04 13:03 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 14:35 [PATCH net-next 0/4] net: dsa: motorcomm: MIB fixup David Yang
2026-09-03 14:35 ` [PATCH net-next 1/4] net: dsa: motorcomm: Split MIB module David Yang
2026-09-03 15:01 ` Andrew Lunn
2026-09-03 14:35 ` [PATCH net-next 2/4] net: dsa: motorcomm: Split MIB buffers David Yang
2026-09-03 16:17 ` Andrew Lunn
2026-09-03 14:35 ` [PATCH net-next 3/4] net: dsa: motorcomm: Use u64_stats_t for MIB stats David Yang
2026-09-03 16:25 ` Andrew Lunn
2026-09-04 2:58 ` David Yang
2026-09-04 13:03 ` Andrew Lunn
2026-09-03 14:35 ` [PATCH net-next 4/4] net: dsa: motorcomm: Use safe 64-bit counter reader David Yang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox