Commit c0cc1268 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

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/20241218020224.70590-1-Tristram.Ha@microchip.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 25c6a5ab bb986904
Loading
Loading
Loading
Loading
+36 −11
Original line number Diff line number Diff line
@@ -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>
@@ -983,26 +983,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;

	/* 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_queue_split(struct ksz_device *dev, int port)
+1 −3
Original line number Diff line number Diff line
@@ -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
@@ -165,8 +165,6 @@
#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
+59 −3
Original line number Diff line number Diff line
// 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);
+6 −3
Original line number Diff line number Diff line
/* 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
@@ -70,6 +69,10 @@
#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)