Skip to content

Commit c0cc126

Browse files
committed
Merge branch 'net-dsa-microchip-fix-set_ageing_time-function-for-ksz9477-and-lan937x-switches'
Tristram Ha says: ==================== net: dsa: microchip: Fix set_ageing_time function for KSZ9477 and LAN937X switches The aging count is not a simple number that is broken into two parts and programmed into 2 registers. These patches correct the programming for KSZ9477 and LAN937X switches. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 25c6a5a + bb98690 commit c0cc126

File tree

4 files changed

+102
-20
lines changed

4 files changed

+102
-20
lines changed

drivers/net/dsa/microchip/ksz9477.c

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/*
33
* Microchip KSZ9477 switch driver main logic
44
*
5-
* Copyright (C) 2017-2019 Microchip Technology Inc.
5+
* Copyright (C) 2017-2024 Microchip Technology Inc.
66
*/
77

88
#include <linux/kernel.h>
@@ -983,26 +983,51 @@ void ksz9477_get_caps(struct ksz_device *dev, int port,
983983
int ksz9477_set_ageing_time(struct ksz_device *dev, unsigned int msecs)
984984
{
985985
u32 secs = msecs / 1000;
986-
u8 value;
987-
u8 data;
986+
u8 data, mult, value;
987+
u32 max_val;
988988
int ret;
989989

990-
value = FIELD_GET(SW_AGE_PERIOD_7_0_M, secs);
990+
#define MAX_TIMER_VAL ((1 << 8) - 1)
991991

992-
ret = ksz_write8(dev, REG_SW_LUE_CTRL_3, value);
993-
if (ret < 0)
994-
return ret;
992+
/* The aging timer comprises a 3-bit multiplier and an 8-bit second
993+
* value. Either of them cannot be zero. The maximum timer is then
994+
* 7 * 255 = 1785 seconds.
995+
*/
996+
if (!secs)
997+
secs = 1;
995998

996-
data = FIELD_GET(SW_AGE_PERIOD_10_8_M, secs);
999+
/* Return error if too large. */
1000+
else if (secs > 7 * MAX_TIMER_VAL)
1001+
return -EINVAL;
9971002

9981003
ret = ksz_read8(dev, REG_SW_LUE_CTRL_0, &value);
9991004
if (ret < 0)
10001005
return ret;
10011006

1002-
value &= ~SW_AGE_CNT_M;
1003-
value |= FIELD_PREP(SW_AGE_CNT_M, data);
1007+
/* Check whether there is need to update the multiplier. */
1008+
mult = FIELD_GET(SW_AGE_CNT_M, value);
1009+
max_val = MAX_TIMER_VAL;
1010+
if (mult > 0) {
1011+
/* Try to use the same multiplier already in the register as
1012+
* the hardware default uses multiplier 4 and 75 seconds for
1013+
* 300 seconds.
1014+
*/
1015+
max_val = DIV_ROUND_UP(secs, mult);
1016+
if (max_val > MAX_TIMER_VAL || max_val * mult != secs)
1017+
max_val = MAX_TIMER_VAL;
1018+
}
1019+
1020+
data = DIV_ROUND_UP(secs, max_val);
1021+
if (mult != data) {
1022+
value &= ~SW_AGE_CNT_M;
1023+
value |= FIELD_PREP(SW_AGE_CNT_M, data);
1024+
ret = ksz_write8(dev, REG_SW_LUE_CTRL_0, value);
1025+
if (ret < 0)
1026+
return ret;
1027+
}
10041028

1005-
return ksz_write8(dev, REG_SW_LUE_CTRL_0, value);
1029+
value = DIV_ROUND_UP(secs, data);
1030+
return ksz_write8(dev, REG_SW_LUE_CTRL_3, value);
10061031
}
10071032

10081033
void ksz9477_port_queue_split(struct ksz_device *dev, int port)

drivers/net/dsa/microchip/ksz9477_reg.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/*
33
* Microchip KSZ9477 register definitions
44
*
5-
* Copyright (C) 2017-2018 Microchip Technology Inc.
5+
* Copyright (C) 2017-2024 Microchip Technology Inc.
66
*/
77

88
#ifndef __KSZ9477_REGS_H
@@ -165,8 +165,6 @@
165165
#define SW_VLAN_ENABLE BIT(7)
166166
#define SW_DROP_INVALID_VID BIT(6)
167167
#define SW_AGE_CNT_M GENMASK(5, 3)
168-
#define SW_AGE_CNT_S 3
169-
#define SW_AGE_PERIOD_10_8_M GENMASK(10, 8)
170168
#define SW_RESV_MCAST_ENABLE BIT(2)
171169
#define SW_HASH_OPTION_M 0x03
172170
#define SW_HASH_OPTION_CRC 1

drivers/net/dsa/microchip/lan937x_main.c

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0
22
/* Microchip LAN937X switch driver main logic
3-
* Copyright (C) 2019-2022 Microchip Technology Inc.
3+
* Copyright (C) 2019-2024 Microchip Technology Inc.
44
*/
55
#include <linux/kernel.h>
66
#include <linux/module.h>
@@ -461,10 +461,66 @@ int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu)
461461

462462
int lan937x_set_ageing_time(struct ksz_device *dev, unsigned int msecs)
463463
{
464-
u32 secs = msecs / 1000;
465-
u32 value;
464+
u8 data, mult, value8;
465+
bool in_msec = false;
466+
u32 max_val, value;
467+
u32 secs = msecs;
466468
int ret;
467469

470+
#define MAX_TIMER_VAL ((1 << 20) - 1)
471+
472+
/* The aging timer comprises a 3-bit multiplier and a 20-bit second
473+
* value. Either of them cannot be zero. The maximum timer is then
474+
* 7 * 1048575 = 7340025 seconds. As this value is too large for
475+
* practical use it can be interpreted as microseconds, making the
476+
* maximum timer 7340 seconds with finer control. This allows for
477+
* maximum 122 minutes compared to 29 minutes in KSZ9477 switch.
478+
*/
479+
if (msecs % 1000)
480+
in_msec = true;
481+
else
482+
secs /= 1000;
483+
if (!secs)
484+
secs = 1;
485+
486+
/* Return error if too large. */
487+
else if (secs > 7 * MAX_TIMER_VAL)
488+
return -EINVAL;
489+
490+
/* Configure how to interpret the number value. */
491+
ret = ksz_rmw8(dev, REG_SW_LUE_CTRL_2, SW_AGE_CNT_IN_MICROSEC,
492+
in_msec ? SW_AGE_CNT_IN_MICROSEC : 0);
493+
if (ret < 0)
494+
return ret;
495+
496+
ret = ksz_read8(dev, REG_SW_LUE_CTRL_0, &value8);
497+
if (ret < 0)
498+
return ret;
499+
500+
/* Check whether there is need to update the multiplier. */
501+
mult = FIELD_GET(SW_AGE_CNT_M, value8);
502+
max_val = MAX_TIMER_VAL;
503+
if (mult > 0) {
504+
/* Try to use the same multiplier already in the register as
505+
* the hardware default uses multiplier 4 and 75 seconds for
506+
* 300 seconds.
507+
*/
508+
max_val = DIV_ROUND_UP(secs, mult);
509+
if (max_val > MAX_TIMER_VAL || max_val * mult != secs)
510+
max_val = MAX_TIMER_VAL;
511+
}
512+
513+
data = DIV_ROUND_UP(secs, max_val);
514+
if (mult != data) {
515+
value8 &= ~SW_AGE_CNT_M;
516+
value8 |= FIELD_PREP(SW_AGE_CNT_M, data);
517+
ret = ksz_write8(dev, REG_SW_LUE_CTRL_0, value8);
518+
if (ret < 0)
519+
return ret;
520+
}
521+
522+
secs = DIV_ROUND_UP(secs, data);
523+
468524
value = FIELD_GET(SW_AGE_PERIOD_7_0_M, secs);
469525

470526
ret = ksz_write8(dev, REG_SW_AGE_PERIOD__1, value);

drivers/net/dsa/microchip/lan937x_reg.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* SPDX-License-Identifier: GPL-2.0 */
22
/* Microchip LAN937X switch register definitions
3-
* Copyright (C) 2019-2021 Microchip Technology Inc.
3+
* Copyright (C) 2019-2024 Microchip Technology Inc.
44
*/
55
#ifndef __LAN937X_REG_H
66
#define __LAN937X_REG_H
@@ -56,8 +56,7 @@
5656

5757
#define SW_VLAN_ENABLE BIT(7)
5858
#define SW_DROP_INVALID_VID BIT(6)
59-
#define SW_AGE_CNT_M 0x7
60-
#define SW_AGE_CNT_S 3
59+
#define SW_AGE_CNT_M GENMASK(5, 3)
6160
#define SW_RESV_MCAST_ENABLE BIT(2)
6261

6362
#define REG_SW_LUE_CTRL_1 0x0311
@@ -70,6 +69,10 @@
7069
#define SW_FAST_AGING BIT(1)
7170
#define SW_LINK_AUTO_AGING BIT(0)
7271

72+
#define REG_SW_LUE_CTRL_2 0x0312
73+
74+
#define SW_AGE_CNT_IN_MICROSEC BIT(7)
75+
7376
#define REG_SW_AGE_PERIOD__1 0x0313
7477
#define SW_AGE_PERIOD_7_0_M GENMASK(7, 0)
7578

0 commit comments

Comments
 (0)