mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
net: dsa: microchip: Fix reserved multicast address table programming
[ Upstream commit96baf482ca] 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:457c182af5("net: dsa: microchip: generic access to ksz9477 static and reserved table") Signed-off-by: Tristram Ha <tristram.ha@microchip.com> Tested-by: Łukasz Majewski <lukma@nabladev.com> Link: https://patch.msgid.link/20251105033741.6455-1-Tristram.Ha@microchip.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
6f0295765f
commit
8803d2f90c
@@ -1355,9 +1355,15 @@ void ksz9477_config_cpu_port(struct dsa_switch *ds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define RESV_MCAST_CNT 8
|
||||||
|
|
||||||
|
static u8 reserved_mcast_map[RESV_MCAST_CNT] = { 0, 1, 3, 16, 32, 33, 2, 17 };
|
||||||
|
|
||||||
int ksz9477_enable_stp_addr(struct ksz_device *dev)
|
int ksz9477_enable_stp_addr(struct ksz_device *dev)
|
||||||
{
|
{
|
||||||
|
u8 i, ports, update;
|
||||||
const u32 *masks;
|
const u32 *masks;
|
||||||
|
bool override;
|
||||||
u32 data;
|
u32 data;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -1366,23 +1372,87 @@ int ksz9477_enable_stp_addr(struct ksz_device *dev)
|
|||||||
/* Enable Reserved multicast table */
|
/* Enable Reserved multicast table */
|
||||||
ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_RESV_MCAST_ENABLE, true);
|
ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_RESV_MCAST_ENABLE, true);
|
||||||
|
|
||||||
/* Set the Override bit for forwarding BPDU packet to CPU */
|
/* The reserved multicast address table has 8 entries. Each entry has
|
||||||
ret = ksz_write32(dev, REG_SW_ALU_VAL_B,
|
* a default value of which port to forward. It is assumed the host
|
||||||
ALU_V_OVERRIDE | BIT(dev->cpu_port));
|
* port is the last port in most of the switches, but that is not the
|
||||||
if (ret < 0)
|
* case for KSZ9477 or maybe KSZ9897. For LAN937X family the default
|
||||||
return ret;
|
* 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
|
||||||
data = ALU_STAT_START | ALU_RESV_MCAST_ADDR | masks[ALU_STAT_WRITE];
|
* 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.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < RESV_MCAST_CNT; 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);
|
ret = ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* wait to be finished */
|
/* wait to be finished */
|
||||||
ret = ksz9477_wait_alu_sta_ready(dev);
|
ret = ksz9477_wait_alu_sta_ready(dev);
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
dev_err(dev->dev, "Failed to update Reserved Multicast table\n");
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = ksz_read32(dev, REG_SW_ALU_VAL_B, &data);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
override = false;
|
||||||
|
ports = data & dev->port_mask;
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
case 6:
|
||||||
|
/* Change the host port. */
|
||||||
|
update = BIT(dev->cpu_port);
|
||||||
|
override = true;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* Change the host port. */
|
||||||
|
update = BIT(dev->cpu_port);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 7:
|
||||||
|
/* Skip the host port. */
|
||||||
|
update = dev->port_mask & ~BIT(dev->cpu_port);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
update = ports;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (update != ports || override) {
|
||||||
|
data &= ~dev->port_mask;
|
||||||
|
data |= update;
|
||||||
|
/* Set Override bit to receive frame even when port is
|
||||||
|
* closed.
|
||||||
|
*/
|
||||||
|
if (override)
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Microchip KSZ9477 register definitions
|
* Microchip KSZ9477 register definitions
|
||||||
*
|
*
|
||||||
* Copyright (C) 2017-2024 Microchip Technology Inc.
|
* Copyright (C) 2017-2025 Microchip Technology Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __KSZ9477_REGS_H
|
#ifndef __KSZ9477_REGS_H
|
||||||
@@ -397,7 +397,6 @@
|
|||||||
|
|
||||||
#define ALU_RESV_MCAST_INDEX_M (BIT(6) - 1)
|
#define ALU_RESV_MCAST_INDEX_M (BIT(6) - 1)
|
||||||
#define ALU_STAT_START BIT(7)
|
#define ALU_STAT_START BIT(7)
|
||||||
#define ALU_RESV_MCAST_ADDR BIT(1)
|
|
||||||
|
|
||||||
#define REG_SW_ALU_VAL_A 0x0420
|
#define REG_SW_ALU_VAL_A 0x0420
|
||||||
|
|
||||||
|
|||||||
@@ -808,6 +808,8 @@ static const u16 ksz9477_regs[] = {
|
|||||||
static const u32 ksz9477_masks[] = {
|
static const u32 ksz9477_masks[] = {
|
||||||
[ALU_STAT_WRITE] = 0,
|
[ALU_STAT_WRITE] = 0,
|
||||||
[ALU_STAT_READ] = 1,
|
[ALU_STAT_READ] = 1,
|
||||||
|
[ALU_STAT_DIRECT] = 0,
|
||||||
|
[ALU_RESV_MCAST_ADDR] = BIT(1),
|
||||||
[P_MII_TX_FLOW_CTRL] = BIT(5),
|
[P_MII_TX_FLOW_CTRL] = BIT(5),
|
||||||
[P_MII_RX_FLOW_CTRL] = BIT(3),
|
[P_MII_RX_FLOW_CTRL] = BIT(3),
|
||||||
};
|
};
|
||||||
@@ -835,6 +837,8 @@ static const u8 ksz9477_xmii_ctrl1[] = {
|
|||||||
static const u32 lan937x_masks[] = {
|
static const u32 lan937x_masks[] = {
|
||||||
[ALU_STAT_WRITE] = 1,
|
[ALU_STAT_WRITE] = 1,
|
||||||
[ALU_STAT_READ] = 2,
|
[ALU_STAT_READ] = 2,
|
||||||
|
[ALU_STAT_DIRECT] = BIT(3),
|
||||||
|
[ALU_RESV_MCAST_ADDR] = BIT(2),
|
||||||
[P_MII_TX_FLOW_CTRL] = BIT(5),
|
[P_MII_TX_FLOW_CTRL] = BIT(5),
|
||||||
[P_MII_RX_FLOW_CTRL] = BIT(3),
|
[P_MII_RX_FLOW_CTRL] = BIT(3),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -294,6 +294,8 @@ enum ksz_masks {
|
|||||||
DYNAMIC_MAC_TABLE_TIMESTAMP,
|
DYNAMIC_MAC_TABLE_TIMESTAMP,
|
||||||
ALU_STAT_WRITE,
|
ALU_STAT_WRITE,
|
||||||
ALU_STAT_READ,
|
ALU_STAT_READ,
|
||||||
|
ALU_STAT_DIRECT,
|
||||||
|
ALU_RESV_MCAST_ADDR,
|
||||||
P_MII_TX_FLOW_CTRL,
|
P_MII_TX_FLOW_CTRL,
|
||||||
P_MII_RX_FLOW_CTRL,
|
P_MII_RX_FLOW_CTRL,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user