]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: dsa: mt7530: fix FDB entries not aging out with short timeout
authorDaniel Golle <daniel@makrotopia.org>
Thu, 14 May 2026 14:04:21 +0000 (15:04 +0100)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 19 May 2026 10:37:29 +0000 (12:37 +0200)
The DSA forwarding selftests bridge_vlan_aware.sh and
bridge_vlan_unaware.sh configure the bridge with ageing_time set to
LOW_AGEING_TIME (1000 centiseconds, i.e. 10 seconds) and then run
learning_test() in lib.sh, which expects a learned FDB entry to be
removed after ageing_time + 10 seconds. On MT7530/MT7531 the entry
persisted past the deadline and the "Found FDB record when should
not" assertion failed.

With msecs=10000, the algorithm in mt7530_set_ageing_time() finds
AGE_CNT=0 and AGE_UNIT=9 as the first exact match (starting the
search from tmp_age_count=0). The per-entry aging counter is
initialized to AGE_CNT when a MAC address is learned, so with
AGE_CNT=0 new entries start with a counter value of 0, which the
hardware treats as "already aged" and never removes, effectively
disabling aging.

Fix this by starting the search from tmp_age_count=1 to ensure
entries always have a non-zero initial aging counter. For a
10-second ageing time this yields AGE_CNT=1 and AGE_UNIT=4 instead:
the timer ticks every 5 seconds and entries are removed after 2
ticks.

Starting the search at AGE_CNT=1 raises the minimum representable
ageing time from 1 to 2 seconds. Without bounds, a stale ageing_time
of 1 second would now make the loop fall through without setting
age_count and age_unit, leaving them uninitialized when written to
the MT7530_AAC hardware register. Set ds->ageing_time_min and
ds->ageing_time_max so the DSA core validates the range before the
callback is invoked, and drop the now-redundant range check from
mt7530_set_ageing_time().

Fixes: ea6d5c924e39 ("net: dsa: mt7530: support setting ageing time")
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Link: https://patch.msgid.link/7788ded12dc07b1bce329ec35fa70f4b45f3f9b7.1778766629.git.daniel@makrotopia.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/dsa/mt7530.c

index 44d670904ad893aeb6b9fed96621dd021758d548..cd311dfd3600d24ff9dd531f494351c571a70ae2 100644 (file)
@@ -1023,12 +1023,16 @@ mt7530_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
        unsigned int age_count;
        unsigned int age_unit;
 
-       /* Applied timer is (AGE_CNT + 1) * (AGE_UNIT + 1) seconds */
-       if (secs < 1 || secs > (AGE_CNT_MAX + 1) * (AGE_UNIT_MAX + 1))
-               return -ERANGE;
-
-       /* iterate through all possible age_count to find the closest pair */
-       for (tmp_age_count = 0; tmp_age_count <= AGE_CNT_MAX; ++tmp_age_count) {
+       /* Applied timer is (AGE_CNT + 1) * (AGE_UNIT + 1) seconds.
+        * The DSA core has already validated the range using
+        * ds->ageing_time_min and ds->ageing_time_max.
+        *
+        * Iterate through all possible age_count values to find the closest
+        * pair. Start from 1 because the per-entry aging counter is
+        * initialized to AGE_CNT and a value of 0 means the entry will
+        * never be aged out.
+        */
+       for (tmp_age_count = 1; tmp_age_count <= AGE_CNT_MAX; ++tmp_age_count) {
                unsigned int tmp_age_unit = secs / (tmp_age_count + 1) - 1;
 
                if (tmp_age_unit <= AGE_UNIT_MAX) {
@@ -2428,6 +2432,8 @@ mt7530_setup(struct dsa_switch *ds)
 
        ds->assisted_learning_on_cpu_port = true;
        ds->mtu_enforcement_ingress = true;
+       ds->ageing_time_min = 2 * 1000;
+       ds->ageing_time_max = (AGE_CNT_MAX + 1) * (AGE_UNIT_MAX + 1) * 1000;
 
        if (priv->id == ID_MT7530) {
                regulator_set_voltage(priv->core_pwr, 1000000, 1000000);
@@ -2617,6 +2623,8 @@ mt7531_setup_common(struct dsa_switch *ds)
 
        ds->assisted_learning_on_cpu_port = true;
        ds->mtu_enforcement_ingress = true;
+       ds->ageing_time_min = 2 * 1000;
+       ds->ageing_time_max = (AGE_CNT_MAX + 1) * (AGE_UNIT_MAX + 1) * 1000;
 
        mt753x_trap_frames(priv);