realtek: dsa: Refresh link_stats in .get_stats64
authorSven Eckelmann <[email protected]>
Mon, 3 Nov 2025 17:19:14 +0000 (18:19 +0100)
committerHauke Mehrtens <[email protected]>
Sat, 15 Nov 2025 23:10:56 +0000 (00:10 +0100)
If an architecture doesn't need to sleep for retrieving the current
statistics from the HW, it is possible to directly retrieve the last values
from the HW when .get_stats64 is called. This avoids the stale counters
with the current refresh interval of 60 seconds.

Signed-off-by: Sven Eckelmann <[email protected]>
Link: https://github.com/openwrt/openwrt/pull/20631
Signed-off-by: Hauke Mehrtens <[email protected]>
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl839x.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c

index d34dd3b03bf4e7650e625fa30b1a72a822d3d61f..6786abbe74a24de7a3583bf2ef78d6fc14479530 100644 (file)
@@ -1430,6 +1430,13 @@ static void rtldsa_get_rmon_stats(struct dsa_switch *ds, int port,
        rtldsa_counters_unlock(priv, port);
 }
 
+void rtldsa_update_counters_atomically(struct rtl838x_switch_priv *priv, int port)
+{
+       rtldsa_counters_lock(priv, port);
+       rtldsa_update_port_counters(priv, port);
+       rtldsa_counters_unlock(priv, port);
+}
+
 static void rtldsa_get_stats64(struct dsa_switch *ds, int port,
                               struct rtnl_link_stats64 *s)
 {
@@ -1444,6 +1451,9 @@ static void rtldsa_get_stats64(struct dsa_switch *ds, int port,
                return;
        }
 
+       if (priv->r->stat_update_counters_atomically)
+               priv->r->stat_update_counters_atomically(priv, port);
+
        /* retrieve prepared return data without potentially sleeping via mutex */
        spin_lock(&counters->link_stat_lock);
        memcpy(s, &counters->link_stat, sizeof(*s));
index c57027ed1da60d7e322ad57ea4a5e285bd75fb6e..af3e88a632cc7046daa1569d655ee0017b14163d 100644 (file)
@@ -1675,6 +1675,7 @@ const struct rtl838x_reg rtl838x_reg = {
        .stat_port_std_mib = RTL838X_STAT_PORT_STD_MIB,
        .stat_counters_lock = rtldsa_counters_lock_register,
        .stat_counters_unlock = rtldsa_counters_unlock_register,
+       .stat_update_counters_atomically = rtldsa_update_counters_atomically,
        .port_iso_ctrl = rtl838x_port_iso_ctrl,
        .traffic_enable = rtl838x_traffic_enable,
        .traffic_disable = rtl838x_traffic_disable,
index bca2d8a1f7b4dc90b55c573da2ca15741a5547f3..267a6b80f77ef3e9e2fc690bee8ee17467c2c9eb 100644 (file)
@@ -712,7 +712,7 @@ struct rtldsa_counter {
 struct rtldsa_counter_state {
        /**
         * @lock: protect updates to members of the structure when the
-        * priv->counters_lock is not used.
+        * priv->counters_lock is not used. (see rtl931x_reg->stat_update_counters_atomically)
         */
        spinlock_t lock;
        ktime_t last_update;
@@ -1129,6 +1129,17 @@ struct rtl838x_reg {
        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);
+
+       /**
+        * @stat_update_counters_atomically: When set, the SoC family allows atomically retrieving
+        * of statistic counters using this function.  This function must not require "might_sleep"
+        * code.
+        *
+        * Any SoC family which requires stat_port_table_read must use the table
+        * rtldsa_counters_(un)lock_table helpers. They are using a mutex for locking. The counters
+        * update is therefore not atomic.
+        */
+       void (*stat_update_counters_atomically)(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);
@@ -1300,6 +1311,8 @@ void rtldsa_counters_lock_table(struct rtl838x_switch_priv *priv, int port)
 void rtldsa_counters_unlock_table(struct rtl838x_switch_priv *priv, int port)
        __releases(&priv->ports[port].counters.lock);
 
+void rtldsa_update_counters_atomically(struct rtl838x_switch_priv *priv, int port);
+
 extern int rtldsa_max_available_queue[];
 extern int rtldsa_default_queue_weights[];
 
index e3adefcd10042f9bf9cefe24fd66ac3b5a937b9c..c421fb819db797a877d423d41595db3266a7d4b3 100644 (file)
@@ -1649,6 +1649,7 @@ const struct rtl838x_reg rtl839x_reg = {
        .stat_port_std_mib = RTL839X_STAT_PORT_STD_MIB,
        .stat_counters_lock = rtldsa_counters_lock_register,
        .stat_counters_unlock = rtldsa_counters_unlock_register,
+       .stat_update_counters_atomically = rtldsa_update_counters_atomically,
        .traffic_enable = rtl839x_traffic_enable,
        .traffic_disable = rtl839x_traffic_disable,
        .traffic_set = rtl839x_traffic_set,
index f8356815419db629e262690f6e9731437292f63b..8f190560726875d3d365923612b20b09dc9d79b5 100644 (file)
@@ -2618,6 +2618,7 @@ const struct rtl838x_reg rtl930x_reg = {
        .stat_port_prv_mib = RTL930X_STAT_PORT_PRVTE_CNTR,
        .stat_counters_lock = rtldsa_counters_lock_register,
        .stat_counters_unlock = rtldsa_counters_unlock_register,
+       .stat_update_counters_atomically = rtldsa_update_counters_atomically,
        .traffic_enable = rtl930x_traffic_enable,
        .traffic_disable = rtl930x_traffic_disable,
        .traffic_set = rtl930x_traffic_set,