lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251102141801.63dc212c@wsk>
Date: Sun, 2 Nov 2025 14:18:01 +0100
From: Łukasz Majewski <lukma@...ladev.com>
To: <Tristram.Ha@...rochip.com>
Cc: Woojung Huh <woojung.huh@...rochip.com>, Arun Ramadoss
 <arun.ramadoss@...rochip.com>, Andrew Lunn <andrew@...n.ch>, Vladimir
 Oltean <olteanv@...il.com>, Oleksij Rempel <linux@...pel-privat.de>, "David
 S. Miller" <davem@...emloft.net>, Eric Dumazet <edumazet@...gle.com>, Jakub
 Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>,
 <UNGLinuxDriver@...rochip.com>, <netdev@...r.kernel.org>,
 <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH net] net: dsa: microchip: Fix reserved multicast address
 table programming

Hi Tristram,

> From: Tristram Ha <tristram.ha@...rochip.com>
> 
> KSZ9477/KSZ9897 and LAN937X families of switches use a reserved
> multicast address table for some specific forwarding with some
> multicast addresses, like the one used in STP.  The hardware assumes
> the host port is the last port in KSZ9897 family and port 5 in
> LAN937X family.  Most of the time this assumption is correct but not
> in other cases like KSZ9477. Originally the function just setups the
> first entry, but the others still need update, especially for one
> common multicast address that is used by PTP operation.
> 
> LAN937x also uses different register bits when accessing the reserved
> table.
> 
> Fixes: 457c182af597 ("net: dsa: microchip: generic access to ksz9477
> static and reserved table") Signed-off-by: Tristram Ha
> <tristram.ha@...rochip.com> ---
>  drivers/net/dsa/microchip/ksz9477.c     | 103
> ++++++++++++++++++++---- drivers/net/dsa/microchip/ksz9477_reg.h |
> 3 +- drivers/net/dsa/microchip/ksz_common.c  |   4 +
>  drivers/net/dsa/microchip/ksz_common.h  |   2 +
>  4 files changed, 96 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/net/dsa/microchip/ksz9477.c
> b/drivers/net/dsa/microchip/ksz9477.c index
> d747ea1c41a7..9b6731de52a7 100644 ---
> a/drivers/net/dsa/microchip/ksz9477.c +++
> b/drivers/net/dsa/microchip/ksz9477.c @@ -1355,8 +1355,12 @@ void
> ksz9477_config_cpu_port(struct dsa_switch *ds) }
>  }
>  
> +static u8 reserved_mcast_map[8] = { 0, 1, 3, 16, 32, 33, 2, 17 };
> +
>  int ksz9477_enable_stp_addr(struct ksz_device *dev)
>  {
> +	u8 all_ports = (1 << dev->info->port_cnt) - 1;
> +	u8 i, def_port, ports, update;
>  	const u32 *masks;
>  	u32 data;
>  	int ret;
> @@ -1366,23 +1370,94 @@ int ksz9477_enable_stp_addr(struct ksz_device
> *dev) /* Enable Reserved multicast table */
>  	ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_RESV_MCAST_ENABLE, true);
>  
> -	/* Set the Override bit for forwarding BPDU packet to CPU */
> -	ret = ksz_write32(dev, REG_SW_ALU_VAL_B,
> -			  ALU_V_OVERRIDE | BIT(dev->cpu_port));
> -	if (ret < 0)
> -		return ret;
> +	/* The reserved multicast address table has 8 entries.  Each
> entry has
> +	 * a default value of which port to forward.  It is assumed
> the host
> +	 * port is the last port in most of the switches, but that
> is not the
> +	 * case for KSZ9477 or maybe KSZ9897.  For LAN937X family
> the default
> +	 * port is port 5, the first RGMII port.  It is okay for
> LAN9370, a
> +	 * 5-port switch, but may not be correct for the other 8-port
> +	 * versions.  It is necessary to update the whole table to
> forward to
> +	 * the right ports.
> +	 * Furthermore PTP messages can use a reserved multicast
> address and
> +	 * the host will not receive them if this table is not
> correct.
> +	 */
> +	def_port = BIT(dev->info->port_cnt - 1);
> +	if (is_lan937x(dev))
> +		def_port = BIT(4);
> +	for (i = 0; i < 8; i++) {
> +		data = reserved_mcast_map[i] <<
> +			dev->info->shifts[ALU_STAT_INDEX];
> +		data |= ALU_STAT_START |
> +			masks[ALU_STAT_DIRECT] |
> +			masks[ALU_RESV_MCAST_ADDR] |
> +			masks[ALU_STAT_READ];
> +		ret = ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4,
> data);
> +		if (ret < 0)
> +			return ret;
>  
> -	data = ALU_STAT_START | ALU_RESV_MCAST_ADDR |
> masks[ALU_STAT_WRITE];
> +		/* wait to be finished */
> +		ret = ksz9477_wait_alu_sta_ready(dev);
> +		if (ret < 0)
> +			return ret;
>  
> -	ret = ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
> -	if (ret < 0)
> -		return ret;
> +		ret = ksz_read32(dev, REG_SW_ALU_VAL_B, &data);
> +		if (ret < 0)
> +			return ret;
>  
> -	/* wait to be finished */
> -	ret = ksz9477_wait_alu_sta_ready(dev);
> -	if (ret < 0) {
> -		dev_err(dev->dev, "Failed to update Reserved
> Multicast table\n");
> -		return ret;
> +		ports = data & dev->port_mask;
> +		if (ports == def_port) {
> +			/* Change the host port. */
> +			update = BIT(dev->cpu_port);
> +
> +			/* The host port is correct so no need to
> update the
> +			 * the whole table but the first entry still
> needs to
> +			 * set the Override bit for STP.
> +			 */
> +			if (update == def_port && i == 0)
> +				ports = 0;
> +		} else if (ports == 0) {
> +			/* No change to entry. */
> +			update = 0;
> +		} else if (ports == (all_ports & ~def_port)) {
> +			/* This entry does not forward to host port.
>  But if
> +			 * the host needs to process protocols like
> MVRP and
> +			 * MMRP the host port needs to be set.
> +			 */
> +			update = ports & ~BIT(dev->cpu_port);
> +			update |= def_port;
> +		} else {
> +			/* No change to entry. */
> +			update = ports;
> +		}
> +		if (update != ports) {
> +			data &= ~dev->port_mask;
> +			data |= update;
> +			/* Set Override bit for STP in the first
> entry. */
> +			if (i == 0)
> +				data |= ALU_V_OVERRIDE;
> +			ret = ksz_write32(dev, REG_SW_ALU_VAL_B,
> data);
> +			if (ret < 0)
> +				return ret;
> +
> +			data = reserved_mcast_map[i] <<
> +			       dev->info->shifts[ALU_STAT_INDEX];
> +			data |= ALU_STAT_START |
> +				masks[ALU_STAT_DIRECT] |
> +				masks[ALU_RESV_MCAST_ADDR] |
> +				masks[ALU_STAT_WRITE];
> +			ret = ksz_write32(dev,
> REG_SW_ALU_STAT_CTRL__4, data);
> +			if (ret < 0)
> +				return ret;
> +
> +			/* wait to be finished */
> +			ret = ksz9477_wait_alu_sta_ready(dev);
> +			if (ret < 0)
> +				return ret;
> +
> +			/* No need to check the whole table. */
> +			if (i == 0 && !ports)
> +				break;
> +		}
>  	}
>  
>  	return 0;
> diff --git a/drivers/net/dsa/microchip/ksz9477_reg.h
> b/drivers/net/dsa/microchip/ksz9477_reg.h index
> ff579920078e..61ea11e3338e 100644 ---
> a/drivers/net/dsa/microchip/ksz9477_reg.h +++
> b/drivers/net/dsa/microchip/ksz9477_reg.h @@ -2,7 +2,7 @@
>  /*
>   * Microchip KSZ9477 register definitions
>   *
> - * Copyright (C) 2017-2024 Microchip Technology Inc.
> + * Copyright (C) 2017-2025 Microchip Technology Inc.
>   */
>  
>  #ifndef __KSZ9477_REGS_H
> @@ -397,7 +397,6 @@
>  
>  #define ALU_RESV_MCAST_INDEX_M		(BIT(6) - 1)
>  #define ALU_STAT_START			BIT(7)
> -#define ALU_RESV_MCAST_ADDR		BIT(1)
>  
>  #define REG_SW_ALU_VAL_A		0x0420
>  
> diff --git a/drivers/net/dsa/microchip/ksz_common.c
> b/drivers/net/dsa/microchip/ksz_common.c index
> a962055bfdbd..933ae8dc6337 100644 ---
> a/drivers/net/dsa/microchip/ksz_common.c +++
> b/drivers/net/dsa/microchip/ksz_common.c @@ -808,6 +808,8 @@ static
> const u16 ksz9477_regs[] = { static const u32 ksz9477_masks[] = {
>  	[ALU_STAT_WRITE]		= 0,
>  	[ALU_STAT_READ]			= 1,
> +	[ALU_STAT_DIRECT]		= 0,
> +	[ALU_RESV_MCAST_ADDR]		= BIT(1),
>  	[P_MII_TX_FLOW_CTRL]		= BIT(5),
>  	[P_MII_RX_FLOW_CTRL]		= BIT(3),
>  };
> @@ -835,6 +837,8 @@ static const u8 ksz9477_xmii_ctrl1[] = {
>  static const u32 lan937x_masks[] = {
>  	[ALU_STAT_WRITE]		= 1,
>  	[ALU_STAT_READ]			= 2,
> +	[ALU_STAT_DIRECT]		= BIT(3),
> +	[ALU_RESV_MCAST_ADDR]		= BIT(2),
>  	[P_MII_TX_FLOW_CTRL]		= BIT(5),
>  	[P_MII_RX_FLOW_CTRL]		= BIT(3),
>  };
> diff --git a/drivers/net/dsa/microchip/ksz_common.h
> b/drivers/net/dsa/microchip/ksz_common.h index
> a1eb39771bb9..c65188cd3c0a 100644 ---
> a/drivers/net/dsa/microchip/ksz_common.h +++
> b/drivers/net/dsa/microchip/ksz_common.h @@ -294,6 +294,8 @@ enum
> ksz_masks { DYNAMIC_MAC_TABLE_TIMESTAMP,
>  	ALU_STAT_WRITE,
>  	ALU_STAT_READ,
> +	ALU_STAT_DIRECT,
> +	ALU_RESV_MCAST_ADDR,
>  	P_MII_TX_FLOW_CTRL,
>  	P_MII_RX_FLOW_CTRL,
>  };

Thank you for the patch.

Now I'm able to synchronize device connected to KSZ9477 (port6 host
port).
I've applied and tested this patch on v6.6. LTS kernel (and hopefully
it can be backported to LTS kernels as well).

Tested-by: Łukasz Majewski <lukma@...ladev.com>

-- 
Best regards,

Lukasz Majewski

--
Nabla Software Engineering GmbH
HRB 40522 Augsburg
Phone: +49 821 45592596
E-Mail: office@...ladev.com
Geschftsfhrer : Stefano Babic

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ