]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: dsa: microchip: Fix KSZ9477 set_ageing_time function
authorTristram Ha <tristram.ha@microchip.com>
Wed, 18 Dec 2024 02:02:23 +0000 (18:02 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 9 Jan 2025 12:29:58 +0000 (13:29 +0100)
[ Upstream commit 262bfba8ab820641c8cfbbf03b86d6c00242c078 ]

The aging count is not a simple 11-bit value but comprises a 3-bit
multiplier and an 8-bit second count.  The code tries to use the
original multiplier which is 4 as the second count is still 300 seconds
by default.

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-2-Tristram.Ha@microchip.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/dsa/microchip/ksz9477.c
drivers/net/dsa/microchip/ksz9477_reg.h

index e9fa92a833227d879d29ccea7bc54ef039a9c570..b854ee425fcdd8b666a5e93090e428ae7d1f528c 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Microchip KSZ9477 switch driver main logic
  *
- * Copyright (C) 2017-2019 Microchip Technology Inc.
+ * Copyright (C) 2017-2024 Microchip Technology Inc.
  */
 
 #include <linux/kernel.h>
@@ -964,26 +964,51 @@ void ksz9477_get_caps(struct ksz_device *dev, int port,
 int ksz9477_set_ageing_time(struct ksz_device *dev, unsigned int msecs)
 {
        u32 secs = msecs / 1000;
-       u8 value;
-       u8 data;
+       u8 data, mult, value;
+       u32 max_val;
        int ret;
 
-       value = FIELD_GET(SW_AGE_PERIOD_7_0_M, secs);
+#define MAX_TIMER_VAL  ((1 << 8) - 1)
 
-       ret = ksz_write8(dev, REG_SW_LUE_CTRL_3, value);
-       if (ret < 0)
-               return ret;
+       /* The aging timer comprises a 3-bit multiplier and an 8-bit second
+        * value.  Either of them cannot be zero.  The maximum timer is then
+        * 7 * 255 = 1785 seconds.
+        */
+       if (!secs)
+               secs = 1;
 
-       data = FIELD_GET(SW_AGE_PERIOD_10_8_M, secs);
+       /* Return error if too large. */
+       else if (secs > 7 * MAX_TIMER_VAL)
+               return -EINVAL;
 
        ret = ksz_read8(dev, REG_SW_LUE_CTRL_0, &value);
        if (ret < 0)
                return ret;
 
-       value &= ~SW_AGE_CNT_M;
-       value |= FIELD_PREP(SW_AGE_CNT_M, data);
+       /* Check whether there is need to update the multiplier. */
+       mult = FIELD_GET(SW_AGE_CNT_M, value);
+       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) {
+               value &= ~SW_AGE_CNT_M;
+               value |= FIELD_PREP(SW_AGE_CNT_M, data);
+               ret = ksz_write8(dev, REG_SW_LUE_CTRL_0, value);
+               if (ret < 0)
+                       return ret;
+       }
 
-       return ksz_write8(dev, REG_SW_LUE_CTRL_0, value);
+       value = DIV_ROUND_UP(secs, data);
+       return ksz_write8(dev, REG_SW_LUE_CTRL_3, value);
 }
 
 void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
index 04086e9ab0a0fcea3977b34f42de72dfaa83ef07..ffb9484018ed5bb4a7d6090401cf61893dc2664b 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Microchip KSZ9477 register definitions
  *
- * Copyright (C) 2017-2018 Microchip Technology Inc.
+ * Copyright (C) 2017-2024 Microchip Technology Inc.
  */
 
 #ifndef __KSZ9477_REGS_H
 #define SW_VLAN_ENABLE                 BIT(7)
 #define SW_DROP_INVALID_VID            BIT(6)
 #define SW_AGE_CNT_M                   GENMASK(5, 3)
-#define SW_AGE_CNT_S                   3
-#define SW_AGE_PERIOD_10_8_M           GENMASK(10, 8)
 #define SW_RESV_MCAST_ENABLE           BIT(2)
 #define SW_HASH_OPTION_M               0x03
 #define SW_HASH_OPTION_CRC             1