]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
net: dsa: microchip: Fix LAN937X set_ageing_time function
authorTristram Ha <tristram.ha@microchip.com>
Wed, 18 Dec 2024 02:02:24 +0000 (18:02 -0800)
committerJakub Kicinski <kuba@kernel.org>
Fri, 20 Dec 2024 02:04:04 +0000 (18:04 -0800)
The aging count is not a simple 20-bit value but comprises a 3-bit
multiplier and a 20-bit second time.  The code tries to use the
original multiplier which is 4 as the second count is still 300 seconds
by default.

As the 20-bit number is now too large for practical use there is an option
to interpret it as microseconds instead of seconds.

Fixes: 2c119d9982b1 ("net: dsa: microchip: add the support for set_ageing_time")
Signed-off-by: Tristram Ha <tristram.ha@microchip.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20241218020224.70590-3-Tristram.Ha@microchip.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/microchip/lan937x_main.c
drivers/net/dsa/microchip/lan937x_reg.h

index b7652efd632ead8997088732fcda8bc98f3d0d82..b1ae3b9de3d16b885de33d26da0312106c043aae 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Microchip LAN937X switch driver main logic
- * Copyright (C) 2019-2022 Microchip Technology Inc.
+ * Copyright (C) 2019-2024 Microchip Technology Inc.
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -461,10 +461,66 @@ int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu)
 
 int lan937x_set_ageing_time(struct ksz_device *dev, unsigned int msecs)
 {
-       u32 secs = msecs / 1000;
-       u32 value;
+       u8 data, mult, value8;
+       bool in_msec = false;
+       u32 max_val, value;
+       u32 secs = msecs;
        int ret;
 
+#define MAX_TIMER_VAL  ((1 << 20) - 1)
+
+       /* The aging timer comprises a 3-bit multiplier and a 20-bit second
+        * value.  Either of them cannot be zero.  The maximum timer is then
+        * 7 * 1048575 = 7340025 seconds.  As this value is too large for
+        * practical use it can be interpreted as microseconds, making the
+        * maximum timer 7340 seconds with finer control.  This allows for
+        * maximum 122 minutes compared to 29 minutes in KSZ9477 switch.
+        */
+       if (msecs % 1000)
+               in_msec = true;
+       else
+               secs /= 1000;
+       if (!secs)
+               secs = 1;
+
+       /* Return error if too large. */
+       else if (secs > 7 * MAX_TIMER_VAL)
+               return -EINVAL;
+
+       /* Configure how to interpret the number value. */
+       ret = ksz_rmw8(dev, REG_SW_LUE_CTRL_2, SW_AGE_CNT_IN_MICROSEC,
+                      in_msec ? SW_AGE_CNT_IN_MICROSEC : 0);
+       if (ret < 0)
+               return ret;
+
+       ret = ksz_read8(dev, REG_SW_LUE_CTRL_0, &value8);
+       if (ret < 0)
+               return ret;
+
+       /* Check whether there is need to update the multiplier. */
+       mult = FIELD_GET(SW_AGE_CNT_M, value8);
+       max_val = MAX_TIMER_VAL;
+       if (mult > 0) {
+               /* Try to use the same multiplier already in the register as
+                * the hardware default uses multiplier 4 and 75 seconds for
+                * 300 seconds.
+                */
+               max_val = DIV_ROUND_UP(secs, mult);
+               if (max_val > MAX_TIMER_VAL || max_val * mult != secs)
+                       max_val = MAX_TIMER_VAL;
+       }
+
+       data = DIV_ROUND_UP(secs, max_val);
+       if (mult != data) {
+               value8 &= ~SW_AGE_CNT_M;
+               value8 |= FIELD_PREP(SW_AGE_CNT_M, data);
+               ret = ksz_write8(dev, REG_SW_LUE_CTRL_0, value8);
+               if (ret < 0)
+                       return ret;
+       }
+
+       secs = DIV_ROUND_UP(secs, data);
+
        value = FIELD_GET(SW_AGE_PERIOD_7_0_M, secs);
 
        ret = ksz_write8(dev, REG_SW_AGE_PERIOD__1, value);
index 4ec93e421da45158e69bf2df76a17b752cfdb88b..72042fd64e5b00c7d972baa0434bfd49244a1b2a 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /* Microchip LAN937X switch register definitions
- * Copyright (C) 2019-2021 Microchip Technology Inc.
+ * Copyright (C) 2019-2024 Microchip Technology Inc.
  */
 #ifndef __LAN937X_REG_H
 #define __LAN937X_REG_H
@@ -56,8 +56,7 @@
 
 #define SW_VLAN_ENABLE                 BIT(7)
 #define SW_DROP_INVALID_VID            BIT(6)
-#define SW_AGE_CNT_M                   0x7
-#define SW_AGE_CNT_S                   3
+#define SW_AGE_CNT_M                   GENMASK(5, 3)
 #define SW_RESV_MCAST_ENABLE           BIT(2)
 
 #define REG_SW_LUE_CTRL_1              0x0311
 #define SW_FAST_AGING                  BIT(1)
 #define SW_LINK_AUTO_AGING             BIT(0)
 
+#define REG_SW_LUE_CTRL_2              0x0312
+
+#define SW_AGE_CNT_IN_MICROSEC         BIT(7)
+
 #define REG_SW_AGE_PERIOD__1           0x0313
 #define SW_AGE_PERIOD_7_0_M            GENMASK(7, 0)