[openwrt/openwrt] realtek: dsa: Select counter lock based on sleeping behavior
LEDE Commits
lede-commits at lists.infradead.org
Sat Nov 15 15:18:29 PST 2025
hauke pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/bd78eeb53f85a87f2a29218661a1a3f1d754fd40
commit bd78eeb53f85a87f2a29218661a1a3f1d754fd40
Author: Sven Eckelmann <se at simonwunderlich.de>
AuthorDate: Mon Nov 3 18:19:14 2025 +0100
realtek: dsa: Select counter lock based on sleeping behavior
On many architectures, retrieving the HW counters from the switch is not
potentially sleeping. This would potentially allow these architectures to
retrieve the most recent values from the HW when .get_stats64 is called.
But because of the global mutex (which may sleep on lock), this would no
longer be possible.
Reintroduce the per port counters lock which protects from parallel
writes+reads of the non-link_stat counters. The locking is made abstract by
using helpers which identify the correct locking mechanism based on the
used read methods of the SoC.
Signed-off-by: Sven Eckelmann <se at simonwunderlich.de>
Link: https://github.com/openwrt/openwrt/pull/20631
Signed-off-by: Hauke Mehrtens <hauke at hauke-m.de>
---
.../files-6.12/drivers/net/dsa/rtl83xx/dsa.c | 59 +++++++++++++++++-----
.../files-6.12/drivers/net/dsa/rtl83xx/rtl838x.c | 2 +
.../files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h | 16 ++++++
.../files-6.12/drivers/net/dsa/rtl83xx/rtl839x.c | 2 +
.../files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c | 2 +
.../files-6.12/drivers/net/dsa/rtl83xx/rtl931x.c | 2 +
6 files changed, 71 insertions(+), 12 deletions(-)
diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c
index bed9198603..d34dd3b03b 100644
--- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c
+++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c
@@ -1163,6 +1163,40 @@ static void rtldsa_update_port_counters(struct rtl838x_switch_priv *priv, int po
spin_unlock(&counters->link_stat_lock);
}
+void rtldsa_counters_lock_register(struct rtl838x_switch_priv *priv, int port)
+ __acquires(&priv->ports[port].counters.lock)
+{
+ spin_lock(&priv->ports[port].counters.lock);
+}
+
+void rtldsa_counters_unlock_register(struct rtl838x_switch_priv *priv, int port)
+ __releases(&priv->ports[port].counters.lock)
+{
+ spin_unlock(&priv->ports[port].counters.lock);
+}
+
+void rtldsa_counters_lock_table(struct rtl838x_switch_priv *priv, int port __maybe_unused)
+ __acquires(&priv->counters_lock)
+{
+ mutex_lock(&priv->counters_lock);
+}
+
+void rtldsa_counters_unlock_table(struct rtl838x_switch_priv *priv, int port __maybe_unused)
+ __releases(&priv->ports[port].counters.lock)
+{
+ mutex_unlock(&priv->counters_lock);
+}
+
+static void rtldsa_counters_lock(struct rtl838x_switch_priv *priv, int port)
+{
+ priv->r->stat_counters_lock(priv, port);
+}
+
+static void rtldsa_counters_unlock(struct rtl838x_switch_priv *priv, int port)
+{
+ priv->r->stat_counters_unlock(priv, port);
+}
+
static void rtldsa_poll_counters(struct work_struct *work)
{
struct rtl838x_switch_priv *priv = container_of(to_delayed_work(work),
@@ -1173,9 +1207,9 @@ static void rtldsa_poll_counters(struct work_struct *work)
if (!priv->ports[i].phy && !priv->pcs[i])
continue;
- mutex_lock(&priv->counters_lock);
+ rtldsa_counters_lock(priv, i);
rtldsa_update_port_counters(priv, i);
- mutex_unlock(&priv->counters_lock);
+ rtldsa_counters_unlock(priv, i);
}
queue_delayed_work(priv->wq, &priv->counters_work,
@@ -1193,6 +1227,7 @@ static void rtldsa_init_counters(struct rtl838x_switch_priv *priv)
counters = &priv->ports[i].counters;
memset(counters, 0, sizeof(*counters));
+ spin_lock_init(&counters->lock);
spin_lock_init(&counters->link_stat_lock);
}
@@ -1272,13 +1307,13 @@ static void rtldsa_get_eth_phy_stats(struct dsa_switch *ds, int port,
if (!rtldsa_get_mib_desc(priv))
return;
- mutex_lock(&priv->counters_lock);
+ rtldsa_counters_lock(priv, port);
rtldsa_update_port_counters(priv, port);
phy_stats->SymbolErrorDuringCarrier = counters->symbol_errors.val;
- mutex_unlock(&priv->counters_lock);
+ rtldsa_counters_unlock(priv, port);
}
static void rtldsa_get_eth_mac_stats(struct dsa_switch *ds, int port,
@@ -1293,7 +1328,7 @@ static void rtldsa_get_eth_mac_stats(struct dsa_switch *ds, int port,
if (!rtldsa_get_mib_desc(priv))
return;
- mutex_lock(&priv->counters_lock);
+ rtldsa_counters_lock(priv, port);
rtldsa_update_port_counters(priv, port);
@@ -1327,7 +1362,7 @@ static void rtldsa_get_eth_mac_stats(struct dsa_switch *ds, int port,
mac_stats->FrameCheckSequenceErrors = counters->crc_align_errors.val;
- mutex_unlock(&priv->counters_lock);
+ rtldsa_counters_unlock(priv, port);
}
static void rtldsa_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
@@ -1342,13 +1377,13 @@ static void rtldsa_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
if (!rtldsa_get_mib_desc(priv))
return;
- mutex_lock(&priv->counters_lock);
+ rtldsa_counters_lock(priv, port);
rtldsa_update_port_counters(priv, port);
ctrl_stats->UnsupportedOpcodesReceived = counters->unsupported_opcodes.val;
- mutex_unlock(&priv->counters_lock);
+ rtldsa_counters_unlock(priv, port);
}
static void rtldsa_get_rmon_stats(struct dsa_switch *ds, int port,
@@ -1366,7 +1401,7 @@ static void rtldsa_get_rmon_stats(struct dsa_switch *ds, int port,
if (!mib_desc)
return;
- mutex_lock(&priv->counters_lock);
+ rtldsa_counters_lock(priv, port);
rtldsa_update_port_counters(priv, port);
@@ -1392,7 +1427,7 @@ static void rtldsa_get_rmon_stats(struct dsa_switch *ds, int port,
*ranges = mib_desc->rmon_ranges;
- mutex_unlock(&priv->counters_lock);
+ rtldsa_counters_unlock(priv, port);
}
static void rtldsa_get_stats64(struct dsa_switch *ds, int port,
@@ -1427,14 +1462,14 @@ static void rtldsa_get_pause_stats(struct dsa_switch *ds, int port,
if (!rtldsa_get_mib_desc(priv))
return;
- mutex_lock(&priv->counters_lock);
+ rtldsa_counters_lock(priv, port);
rtldsa_update_port_counters(priv, port);
pause_stats->tx_pause_frames = counters->tx_pause_frames.val;
pause_stats->rx_pause_frames = counters->rx_pause_frames.val;
- mutex_unlock(&priv->counters_lock);
+ rtldsa_counters_unlock(priv, port);
}
static int rtl83xx_mc_group_alloc(struct rtl838x_switch_priv *priv, int port)
diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.c
index 4cecf181bb..c57027ed1d 100644
--- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.c
+++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.c
@@ -1673,6 +1673,8 @@ const struct rtl838x_reg rtl838x_reg = {
.stat_port_rst = RTL838X_STAT_PORT_RST,
.stat_rst = RTL838X_STAT_RST,
.stat_port_std_mib = RTL838X_STAT_PORT_STD_MIB,
+ .stat_counters_lock = rtldsa_counters_lock_register,
+ .stat_counters_unlock = rtldsa_counters_unlock_register,
.port_iso_ctrl = rtl838x_port_iso_ctrl,
.traffic_enable = rtl838x_traffic_enable,
.traffic_disable = rtl838x_traffic_disable,
diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h
index e3f894ad6d..bca2d8a1f7 100644
--- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h
+++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h
@@ -710,6 +710,11 @@ struct rtldsa_counter {
};
struct rtldsa_counter_state {
+ /**
+ * @lock: protect updates to members of the structure when the
+ * priv->counters_lock is not used.
+ */
+ spinlock_t lock;
ktime_t last_update;
struct rtldsa_counter symbol_errors;
@@ -1122,6 +1127,8 @@ struct rtl838x_reg {
int stat_port_std_mib;
int stat_port_prv_mib;
u64 (*stat_port_table_read)(int port, unsigned int mib_size, unsigned int offset, bool is_pvt);
+ void (*stat_counters_lock)(struct rtl838x_switch_priv *priv, int port);
+ void (*stat_counters_unlock)(struct rtl838x_switch_priv *priv, int port);
int (*port_iso_ctrl)(int p);
void (*traffic_enable)(int source, int dest);
void (*traffic_disable)(int source, int dest);
@@ -1284,6 +1291,15 @@ struct rtl838x_switch_priv {
void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv);
void rtl930x_dbgfs_init(struct rtl838x_switch_priv *priv);
+void rtldsa_counters_lock_register(struct rtl838x_switch_priv *priv, int port)
+ __acquires(&priv->ports[port].counters.lock);
+void rtldsa_counters_unlock_register(struct rtl838x_switch_priv *priv, int port)
+ __releases(&priv->ports[port].counters.lock);
+void rtldsa_counters_lock_table(struct rtl838x_switch_priv *priv, int port)
+ __acquires(&priv->counters_lock);
+void rtldsa_counters_unlock_table(struct rtl838x_switch_priv *priv, int port)
+ __releases(&priv->ports[port].counters.lock);
+
extern int rtldsa_max_available_queue[];
extern int rtldsa_default_queue_weights[];
diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl839x.c
index c98a8c90d4..e3adefcd10 100644
--- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl839x.c
+++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl839x.c
@@ -1647,6 +1647,8 @@ const struct rtl838x_reg rtl839x_reg = {
.stat_port_rst = RTL839X_STAT_PORT_RST,
.stat_rst = RTL839X_STAT_RST,
.stat_port_std_mib = RTL839X_STAT_PORT_STD_MIB,
+ .stat_counters_lock = rtldsa_counters_lock_register,
+ .stat_counters_unlock = rtldsa_counters_unlock_register,
.traffic_enable = rtl839x_traffic_enable,
.traffic_disable = rtl839x_traffic_disable,
.traffic_set = rtl839x_traffic_set,
diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c
index babb014a90..f835681541 100644
--- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c
+++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c
@@ -2616,6 +2616,8 @@ const struct rtl838x_reg rtl930x_reg = {
.stat_rst = RTL930X_STAT_RST,
.stat_port_std_mib = RTL930X_STAT_PORT_MIB_CNTR,
.stat_port_prv_mib = RTL930X_STAT_PORT_PRVTE_CNTR,
+ .stat_counters_lock = rtldsa_counters_lock_register,
+ .stat_counters_unlock = rtldsa_counters_unlock_register,
.traffic_enable = rtl930x_traffic_enable,
.traffic_disable = rtl930x_traffic_disable,
.traffic_set = rtl930x_traffic_set,
diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl931x.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl931x.c
index 45daf6b0f0..f0817e7f45 100644
--- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl931x.c
+++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl931x.c
@@ -1775,6 +1775,8 @@ const struct rtl838x_reg rtl931x_reg = {
.stat_rst = RTL931X_STAT_RST,
.stat_port_std_mib = 0, /* Not defined */
.stat_port_table_read = rtldsa_931x_stat_port_table_read,
+ .stat_counters_lock = rtldsa_counters_lock_table,
+ .stat_counters_unlock = rtldsa_counters_unlock_table,
.traffic_enable = rtl931x_traffic_enable,
.traffic_disable = rtl931x_traffic_disable,
.traffic_set = rtl931x_traffic_set,
More information about the lede-commits
mailing list