realtek: rtl93xx: trap IGMP and MLD to the CPU

On RTL838x and RTL839x, SPCL_TRAP_IGMP_CTRL traps IGMP and MLD to the
CPU, and the receive path hands trapped frames to the bridge unmarked,
so the bridge sees every report and forwards it itself. The RTL93xx
setup aims at the same but does neither:

- rteth_930x/931x_hw_init() write VLAN_APP_PKT_CTRL = 0x12, which puts
  2 in IGMP_ACT and MLD_ACT. The action encoding in dal_longan_trap.c
  of the Zyxel XMG1915 GPL U-Boot is 0 forward, 1 trap, 2 copy, 3 trap
  to master, 4 copy to master, so 2 is a copy.
- The actions only apply in a VLAN whose GROUP_MASK selects them, and
  the VLAN writers leave that mask at 0 (RTL930x) or at whatever the
  entry held (RTL931x).

On an RTL9303, VLAN_APP_PKT_CTRL reads back 0x12, every VLAN write the
driver makes carries GROUP_MASK 0, and IGMPv3 and MLDv2 reports reach
the CPU as normal forwarding (reason 63). Forcing one group mask bit at
a time shows bit 2 selecting IGMP and bit 3 MLD.

Trap both (0x9), set bits 2 and 3 in every VLAN entry, and count reason
55 (IGMP_MLD) as trapped, so that the reports reach the bridge unmarked,
as on RTL83xx, and are forwarded by the CPU rather than flooded by the
switch. RTL931x has the same IGMP_ACT and MLD_ACT fields
(rtk_mango_regField_list.c in the D-Link DMS-1250 GPL SDK), and its
VLAN entry carries the 16-bit GROUP_MASK in multicast_grp_mask; that
bits 2 and 3 select IGMP and MLD there as well is taken from RTL930x.

Tested on an RTL9303 (Hasivo S1100W-8XGT-SE), main against this change,
with a bench-only print of the CPU reason and of the DSA mark. On main:
VLAN_APP_PKT_CTRL 0x12, GROUP_MASK 0 in all 21 VLAN writes, 16 IGMPv3
reports with reason 63 and 8 MLDv2 reports with reason 36 (IPv6
hop-by-hop option), all forwarded by the switch and marked. With this
change: 0x9, GROUP_MASK 0x0c in all 21 writes, and the 16 IGMP and 8
MLD reports all arrive with reason 55, trapped and unmarked; tcpdump on
the user port still sees them. RTL931x was not tested.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25660
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
This commit is contained in:
Gennaro Cimmino authored and Markus Stockhausen committed 2026-10-06 15:45:08 +02:00
1 parent 612347cb3b
commit edc6b8f160
2 files changed
+14 -6

No files matched your search

@@ -469,6 +469,9 @@ void rtl930x_vlan_tables_read(u32 vlan, struct rtldsa_vlan_info *info)
info->untagged_ports = v >> 3;
}
/* Group mask bits for the IGMP and MLD actions of VLAN_APP_PKT_CTRL */
#define RTLDSA_93XX_VLAN_GROUP_IGMP_MLD (BIT(2) | BIT(3))
void rtl930x_vlan_set_tagged(u32 vlan, struct rtldsa_vlan_info *info)
{
u32 v, w;
@@ -481,6 +484,7 @@ void rtl930x_vlan_set_tagged(u32 vlan, struct rtldsa_vlan_info *info)
w |= info->hash_mc_fid ? BIT(27) : 0;
w |= info->hash_uc_fid ? BIT(28) : 0;
w |= info->profile_id << 24;
w |= RTLDSA_93XX_VLAN_GROUP_IGMP_MLD << 16;
buf[0] = v;
buf[1] = w;
@@ -688,7 +692,7 @@ void rtl931x_vlan_set_tagged(u32 vlan, struct rtldsa_vlan_info *info)
x |= info->hash_mc_fid ? BIT(30) : 0;
x |= ((u32)info->if_id & 0x3ff) << 20;
x |= (info->profile_id & 0xf) << 16;
x |= info->multicast_grp_mask & 0xffff;
x |= (info->multicast_grp_mask | RTLDSA_93XX_VLAN_GROUP_IGMP_MLD) & 0xffff;
if (info->l2_tunnel_list_id >= 0) {
y = info->l2_tunnel_list_id << 18;
y |= BIT(31);
@@ -231,7 +231,7 @@ static bool rteth_93xx_decode_tag(struct rteth_frag *frag, struct rteth_dsa_tag
t->queue = (frag->cpu_tag[2] >> 11) & 0x1f;
t->reason = frag->cpu_tag[7] & 0x3f;
t->crc_error = frag->cpu_tag[1] & BIT(6);
t->l2_offloaded = (t->reason >= 19 && t->reason <= 28) ? 0 : 1;
t->l2_offloaded = (t->reason >= 19 && t->reason <= 28) || t->reason == 55 ? 0 : 1;
if (t->reason != 63)
pr_debug("%s: Reason %d, port %d, queue %d\n", __func__, t->reason, t->port, t->queue);
@@ -778,16 +778,20 @@ static void rteth_839x_hw_init(struct rteth_ctrl *ctrl)
static void rteth_930x_hw_init(struct rteth_ctrl *ctrl)
{
/* Trap MLD and IGMP messages to CPU_PORT */
regmap_write(ctrl->map, RTETH_930X_VLAN_APP_PKT_CTRL, 0x12);
/* Trap IGMP and MLD to the CPU (IGMP_ACT = MLD_ACT = 1) in every VLAN
* whose group mask selects them
*/
regmap_write(ctrl->map, RTETH_930X_VLAN_APP_PKT_CTRL, 0x9);
/* Flush learned FDB entries on link down of a port */
regmap_set_bits(ctrl->map, RTETH_930X_L2_CTRL, BIT(7));
}
static void rteth_931x_hw_init(struct rteth_ctrl *ctrl)
{
/* Trap MLD and IGMP messages to CPU_PORT */
regmap_write(ctrl->map, RTETH_931X_VLAN_APP_PKT_CTRL, 0x12);
/* Trap IGMP and MLD to the CPU (IGMP_ACT = MLD_ACT = 1) in every VLAN
* whose group mask selects them
*/
regmap_write(ctrl->map, RTETH_931X_VLAN_APP_PKT_CTRL, 0x9);
/* Set PCIE_PWR_DOWN */
regmap_set_bits(ctrl->map, RTETH_931X_PS_SOC_CTRL, BIT(1));
}