From 3af984e46e37d5fa2e700143d85a199c85653872 Mon Sep 17 00:00:00 2001 From: Jan Hoffmann Date: Sat, 6 May 2023 19:28:52 +0200 Subject: [PATCH 01/10] realtek: properly update port masks when port leaves bridge Correctly update the isolation mask of the port being configured. The port_bitmap variable should contain all other bridge members and needs to be actually removed from the isolation mask instead of added to it. Also actually remove the port being configured from the pm field of the other ports, so that any other ports that are currently disabled will be configured correctly when they are enabled. Fixes: df8e6be59a1f ("rtl838x: add new architecture") [fixed updating pm field of other ports] Fixes: 2b88563ee5aa ("realtek: update the tree to the latest refactored version") [reintroduced incorrect pm field update] Fixes: 27029277f98d ("realtek: add switch driver support for the RTL93XX based switches") Signed-off-by: Jan Hoffmann --- .../realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c | 10 +++++----- .../realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index 63461ff573..220f1d5d28 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -1227,7 +1227,7 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *bridge) { struct rtl838x_switch_priv *priv = ds->priv; - u64 port_bitmap = BIT_ULL(priv->cpu_port), v; + u64 port_bitmap = 0, v; int i; pr_debug("%s %x: %d", __func__, (u32)priv, port); @@ -1245,16 +1245,16 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, if (priv->ports[i].enable) priv->r->traffic_disable(i, port); - priv->ports[i].pm |= BIT_ULL(port); - port_bitmap &= ~BIT_ULL(i); + priv->ports[i].pm &= ~BIT_ULL(port); + port_bitmap |= BIT_ULL(i); } } store_mcgroups(priv, port); - /* Add all other ports to this port matrix. */ + /* Remove all other ports from this port matrix. */ if (priv->ports[port].enable) { v = priv->r->traffic_get(port); - v |= port_bitmap; + v &= ~port_bitmap; priv->r->traffic_set(port, v); } priv->ports[port].pm &= ~port_bitmap; diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c index 83a0441ce2..7eebb2107f 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c @@ -1212,7 +1212,7 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *bridge) { struct rtl838x_switch_priv *priv = ds->priv; - u64 port_bitmap = BIT_ULL(priv->cpu_port), v; + u64 port_bitmap = 0, v; pr_debug("%s %x: %d", __func__, (u32)priv, port); mutex_lock(&priv->reg_mutex); @@ -1229,16 +1229,16 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, if (priv->ports[i].enable) priv->r->traffic_disable(i, port); - priv->ports[i].pm |= BIT_ULL(port); - port_bitmap &= ~BIT_ULL(i); + priv->ports[i].pm &= ~BIT_ULL(port); + port_bitmap |= BIT_ULL(i); } } store_mcgroups(priv, port); - /* Add all other ports to this port matrix. */ + /* Remove all other ports from this port matrix. */ if (priv->ports[port].enable) { v = priv->r->traffic_get(port); - v |= port_bitmap; + v &= ~port_bitmap; priv->r->traffic_set(port, v); } priv->ports[port].pm &= ~port_bitmap; From 4c0a1667f3e752d31b22ca699a9a3fda5eb47dc7 Mon Sep 17 00:00:00 2001 From: Jan Hoffmann Date: Sat, 6 May 2023 19:28:53 +0200 Subject: [PATCH 02/10] realtek: initialize port masks to match the default state All ports are disabled by default, so configure the port isolation masks and the pm field accordingly in the setup function. When port_enable is called for a port, the isolation masks will be set up so that traffic can flow between the port and the CPU. While at it, change the code to also use the traffic_set method in rtl83xx_setup, instead of writing to the RTL838x_PORT_ISO_CTRL(i) registers directly. Signed-off-by: Jan Hoffmann --- .../files-5.10/drivers/net/dsa/rtl83xx/dsa.c | 23 +++++++++---------- .../files-5.15/drivers/net/dsa/rtl83xx/dsa.c | 23 +++++++++---------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index 220f1d5d28..b5b39336a6 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -176,7 +176,6 @@ static int rtl83xx_setup(struct dsa_switch *ds) { int i; struct rtl838x_switch_priv *priv = ds->priv; - u64 port_bitmap = BIT_ULL(priv->cpu_port); pr_debug("%s called\n", __func__); @@ -187,18 +186,16 @@ static int rtl83xx_setup(struct dsa_switch *ds) priv->ports[i].enable = false; priv->ports[priv->cpu_port].enable = true; - /* Isolate ports from each other: traffic only CPU <-> port */ - /* Setting bit j in register RTL838X_PORT_ISO_CTRL(i) allows - * traffic from source port i to destination port j + /* Configure ports so they are disabled by default, but once enabled + * they will work in isolated mode (only traffic between port and CPU). */ for (i = 0; i < priv->cpu_port; i++) { if (priv->ports[i].phy) { - priv->r->set_port_reg_be(BIT_ULL(priv->cpu_port) | BIT_ULL(i), - priv->r->port_iso_ctrl(i)); - port_bitmap |= BIT_ULL(i); + priv->ports[i].pm = BIT_ULL(priv->cpu_port); + priv->r->traffic_set(i, BIT_ULL(i)); } } - priv->r->set_port_reg_be(port_bitmap, priv->r->port_iso_ctrl(priv->cpu_port)); + priv->r->traffic_set(priv->cpu_port, BIT_ULL(priv->cpu_port)); if (priv->family_id == RTL8380_FAMILY_ID) rtl838x_print_matrix(); @@ -240,7 +237,6 @@ static int rtl93xx_setup(struct dsa_switch *ds) { int i; struct rtl838x_switch_priv *priv = ds->priv; - u32 port_bitmap = BIT(priv->cpu_port); pr_info("%s called\n", __func__); @@ -258,13 +254,16 @@ static int rtl93xx_setup(struct dsa_switch *ds) priv->ports[i].enable = false; priv->ports[priv->cpu_port].enable = true; + /* Configure ports so they are disabled by default, but once enabled + * they will work in isolated mode (only traffic between port and CPU). + */ for (i = 0; i < priv->cpu_port; i++) { if (priv->ports[i].phy) { - priv->r->traffic_set(i, BIT_ULL(priv->cpu_port) | BIT_ULL(i)); - port_bitmap |= BIT_ULL(i); + priv->ports[i].pm = BIT_ULL(priv->cpu_port); + priv->r->traffic_set(i, BIT_ULL(i)); } } - priv->r->traffic_set(priv->cpu_port, port_bitmap); + priv->r->traffic_set(priv->cpu_port, BIT_ULL(priv->cpu_port)); rtl930x_print_matrix(); diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c index 7eebb2107f..3ecdda205f 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c @@ -167,7 +167,6 @@ static void rtl83xx_port_set_salrn(struct rtl838x_switch_priv *priv, static int rtl83xx_setup(struct dsa_switch *ds) { struct rtl838x_switch_priv *priv = ds->priv; - u64 port_bitmap = BIT_ULL(priv->cpu_port); pr_debug("%s called\n", __func__); @@ -178,18 +177,16 @@ static int rtl83xx_setup(struct dsa_switch *ds) priv->ports[i].enable = false; priv->ports[priv->cpu_port].enable = true; - /* Isolate ports from each other: traffic only CPU <-> port */ - /* Setting bit j in register RTL838X_PORT_ISO_CTRL(i) allows - * traffic from source port i to destination port j + /* Configure ports so they are disabled by default, but once enabled + * they will work in isolated mode (only traffic between port and CPU). */ for (int i = 0; i < priv->cpu_port; i++) { if (priv->ports[i].phy) { - priv->r->set_port_reg_be(BIT_ULL(priv->cpu_port) | BIT_ULL(i), - priv->r->port_iso_ctrl(i)); - port_bitmap |= BIT_ULL(i); + priv->ports[i].pm = BIT_ULL(priv->cpu_port); + priv->r->traffic_set(i, BIT_ULL(i)); } } - priv->r->set_port_reg_be(port_bitmap, priv->r->port_iso_ctrl(priv->cpu_port)); + priv->r->traffic_set(priv->cpu_port, BIT_ULL(priv->cpu_port)); if (priv->family_id == RTL8380_FAMILY_ID) rtl838x_print_matrix(); @@ -229,7 +226,6 @@ static int rtl83xx_setup(struct dsa_switch *ds) static int rtl93xx_setup(struct dsa_switch *ds) { struct rtl838x_switch_priv *priv = ds->priv; - u32 port_bitmap = BIT(priv->cpu_port); pr_info("%s called\n", __func__); @@ -247,13 +243,16 @@ static int rtl93xx_setup(struct dsa_switch *ds) priv->ports[i].enable = false; priv->ports[priv->cpu_port].enable = true; + /* Configure ports so they are disabled by default, but once enabled + * they will work in isolated mode (only traffic between port and CPU). + */ for (int i = 0; i < priv->cpu_port; i++) { if (priv->ports[i].phy) { - priv->r->traffic_set(i, BIT_ULL(priv->cpu_port) | BIT_ULL(i)); - port_bitmap |= BIT_ULL(i); + priv->ports[i].pm = BIT_ULL(priv->cpu_port); + priv->r->traffic_set(i, BIT_ULL(i)); } } - priv->r->traffic_set(priv->cpu_port, port_bitmap); + priv->r->traffic_set(priv->cpu_port, BIT_ULL(priv->cpu_port)); rtl930x_print_matrix(); From 5d34fc92eccc7d8f3fd35fd5841c110ca1aefc13 Mon Sep 17 00:00:00 2001 From: Jan Hoffmann Date: Sat, 6 May 2023 19:28:54 +0200 Subject: [PATCH 03/10] realtek: fix standalone ports in presence of static fdb entries The registers L2_PORT_STATIC_MV_ACT seem to specify the action to take when the source address of a packet exists as a static fdb entry on another port. By default the configured action is to drop such packets. For standalone ports, this behaviour is undesired, as all traffic should be forwarded to the CPU. So change the action to forward on standalone ports. A situation where this issue can occur is when a non-offloaded bond interface is part of a bridge. In that case, the CPU port will have fdb entries for devices connected to the bond interface, which are managed by the assisted learning feature. For now, this is only implemented for RTL838x/RTL839x, as the available set of registers differs for the other devices. Signed-off-by: Jan Hoffmann --- .../files-5.10/drivers/net/dsa/rtl83xx/dsa.c | 15 +++++++++++++++ .../files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c | 10 ++++++++++ .../files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h | 14 ++++++++++++++ .../files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c | 11 +++++++++++ .../files-5.15/drivers/net/dsa/rtl83xx/dsa.c | 15 +++++++++++++++ .../files-5.15/drivers/net/dsa/rtl83xx/rtl838x.c | 10 ++++++++++ .../files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h | 14 ++++++++++++++ .../files-5.15/drivers/net/dsa/rtl83xx/rtl839x.c | 11 +++++++++++ 8 files changed, 100 insertions(+) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index b5b39336a6..2d603cd42c 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -197,6 +197,14 @@ static int rtl83xx_setup(struct dsa_switch *ds) } priv->r->traffic_set(priv->cpu_port, BIT_ULL(priv->cpu_port)); + /* For standalone ports, forward packets even if a static fdb + * entry for the source address exists on another port. + */ + if (priv->r->set_static_move_action) { + for (i = 0; i <= priv->cpu_port; i++) + priv->r->set_static_move_action(i, true); + } + if (priv->family_id == RTL8380_FAMILY_ID) rtl838x_print_matrix(); else @@ -1217,6 +1225,10 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port, priv->r->traffic_set(port, v); } priv->ports[port].pm |= port_bitmap; + + if (priv->r->set_static_move_action) + priv->r->set_static_move_action(port, false); + mutex_unlock(&priv->reg_mutex); return 0; @@ -1258,6 +1270,9 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, } priv->ports[port].pm &= ~port_bitmap; + if (priv->r->set_static_move_action) + priv->r->set_static_move_action(port, true); + mutex_unlock(&priv->reg_mutex); } diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c index 9ce5098979..74ad031276 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c @@ -559,6 +559,15 @@ static void rtl838x_enable_bcast_flood(int port, bool enable) } +static void rtl838x_set_static_move_action(int port, bool forward) +{ + int shift = MV_ACT_PORT_SHIFT(port); + u32 val = forward ? MV_ACT_FORWARD : MV_ACT_DROP; + + sw_w32_mask(MV_ACT_MASK << shift, val << shift, + RTL838X_L2_PORT_STATIC_MV_ACT(port)); +} + static void rtl838x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) { int i; @@ -1750,6 +1759,7 @@ const struct rtl838x_reg rtl838x_reg = { .enable_flood = rtl838x_enable_flood, .enable_mcast_flood = rtl838x_enable_mcast_flood, .enable_bcast_flood = rtl838x_enable_bcast_flood, + .set_static_move_action = rtl838x_set_static_move_action, .stp_get = rtl838x_stp_get, .stp_set = rtl838x_stp_set, .mac_port_ctrl = rtl838x_mac_port_ctrl, diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h index 19049e4c95..3f1f1d49f8 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h @@ -251,6 +251,19 @@ #define RTL930X_L2_PORT_NEW_SA_FWD(p) (0x8FF4 + (((p / 10) << 2))) #define RTL931X_L2_PORT_NEW_SA_FWD(p) (0xC830 + (((p / 10) << 2))) +#define RTL838X_L2_PORT_MV_ACT(p) (0x335c + (((p >> 4) << 2))) +#define RTL839X_L2_PORT_MV_ACT(p) (0x3b80 + (((p >> 4) << 2))) + +#define RTL838X_L2_PORT_STATIC_MV_ACT(p) (0x327c + (((p >> 4) << 2))) +#define RTL839X_L2_PORT_STATIC_MV_ACT(p) (0x38dc + (((p >> 4) << 2))) + +#define MV_ACT_PORT_SHIFT(p) ((p % 16) * 2) +#define MV_ACT_MASK 0x3 +#define MV_ACT_FORWARD 0 +#define MV_ACT_DROP 1 +#define MV_ACT_TRAP2CPU 2 +#define MV_ACT_COPY2CPU 3 + #define RTL930X_ST_CTRL (0x8798) #define RTL930X_L2_PORT_SABLK_CTRL (0x905c) @@ -982,6 +995,7 @@ struct rtl838x_reg { void (*enable_flood)(int port, bool enable); void (*enable_mcast_flood)(int port, bool enable); void (*enable_bcast_flood)(int port, bool enable); + void (*set_static_move_action)(int port, bool forward); void (*stp_get)(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]); void (*stp_set)(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]); int (*mac_force_mode_ctrl)(int port); diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c index 986a4b5f45..c34bff78d7 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c @@ -602,6 +602,16 @@ static void rtl839x_enable_bcast_flood(int port, bool enable) { } + +static void rtl839x_set_static_move_action(int port, bool forward) +{ + int shift = MV_ACT_PORT_SHIFT(port); + u32 val = forward ? MV_ACT_FORWARD : MV_ACT_DROP; + + sw_w32_mask(MV_ACT_MASK << shift, val << shift, + RTL839X_L2_PORT_STATIC_MV_ACT(port)); +} + irqreturn_t rtl839x_switch_irq(int irq, void *dev_id) { struct dsa_switch *ds = dev_id; @@ -1893,6 +1903,7 @@ const struct rtl838x_reg rtl839x_reg = { .enable_flood = rtl839x_enable_flood, .enable_mcast_flood = rtl839x_enable_mcast_flood, .enable_bcast_flood = rtl839x_enable_bcast_flood, + .set_static_move_action = rtl839x_set_static_move_action, .stp_get = rtl839x_stp_get, .stp_set = rtl839x_stp_set, .mac_force_mode_ctrl = rtl839x_mac_force_mode_ctrl, diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c index 3ecdda205f..703306498e 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c @@ -188,6 +188,14 @@ static int rtl83xx_setup(struct dsa_switch *ds) } priv->r->traffic_set(priv->cpu_port, BIT_ULL(priv->cpu_port)); + /* For standalone ports, forward packets even if a static fdb + * entry for the source address exists on another port. + */ + if (priv->r->set_static_move_action) { + for (int i = 0; i <= priv->cpu_port; i++) + priv->r->set_static_move_action(i, true); + } + if (priv->family_id == RTL8380_FAMILY_ID) rtl838x_print_matrix(); else @@ -1202,6 +1210,10 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port, priv->r->traffic_set(port, v); } priv->ports[port].pm |= port_bitmap; + + if (priv->r->set_static_move_action) + priv->r->set_static_move_action(port, false); + mutex_unlock(&priv->reg_mutex); return 0; @@ -1242,6 +1254,9 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, } priv->ports[port].pm &= ~port_bitmap; + if (priv->r->set_static_move_action) + priv->r->set_static_move_action(port, true); + mutex_unlock(&priv->reg_mutex); } diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.c index 504b29822a..606066aeea 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.c @@ -543,6 +543,15 @@ static void rtl838x_enable_bcast_flood(int port, bool enable) } +static void rtl838x_set_static_move_action(int port, bool forward) +{ + int shift = MV_ACT_PORT_SHIFT(port); + u32 val = forward ? MV_ACT_FORWARD : MV_ACT_DROP; + + sw_w32_mask(MV_ACT_MASK << shift, val << shift, + RTL838X_L2_PORT_STATIC_MV_ACT(port)); +} + static void rtl838x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) { u32 cmd = 1 << 15 | /* Execute cmd */ @@ -1717,6 +1726,7 @@ const struct rtl838x_reg rtl838x_reg = { .enable_flood = rtl838x_enable_flood, .enable_mcast_flood = rtl838x_enable_mcast_flood, .enable_bcast_flood = rtl838x_enable_bcast_flood, + .set_static_move_action = rtl838x_set_static_move_action, .stp_get = rtl838x_stp_get, .stp_set = rtl838x_stp_set, .mac_port_ctrl = rtl838x_mac_port_ctrl, diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h index a4bfc285a6..bfab576e06 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h @@ -249,6 +249,19 @@ #define RTL930X_L2_PORT_NEW_SA_FWD(p) (0x8FF4 + (((p / 10) << 2))) #define RTL931X_L2_PORT_NEW_SA_FWD(p) (0xC830 + (((p / 10) << 2))) +#define RTL838X_L2_PORT_MV_ACT(p) (0x335c + (((p >> 4) << 2))) +#define RTL839X_L2_PORT_MV_ACT(p) (0x3b80 + (((p >> 4) << 2))) + +#define RTL838X_L2_PORT_STATIC_MV_ACT(p) (0x327c + (((p >> 4) << 2))) +#define RTL839X_L2_PORT_STATIC_MV_ACT(p) (0x38dc + (((p >> 4) << 2))) + +#define MV_ACT_PORT_SHIFT(p) ((p % 16) * 2) +#define MV_ACT_MASK 0x3 +#define MV_ACT_FORWARD 0 +#define MV_ACT_DROP 1 +#define MV_ACT_TRAP2CPU 2 +#define MV_ACT_COPY2CPU 3 + #define RTL930X_ST_CTRL (0x8798) #define RTL930X_L2_PORT_SABLK_CTRL (0x905c) @@ -978,6 +991,7 @@ struct rtl838x_reg { void (*enable_flood)(int port, bool enable); void (*enable_mcast_flood)(int port, bool enable); void (*enable_bcast_flood)(int port, bool enable); + void (*set_static_move_action)(int port, bool forward); void (*stp_get)(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]); void (*stp_set)(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]); int (*mac_force_mode_ctrl)(int port); diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl839x.c index 06fdbd8936..fe5572a447 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl839x.c @@ -590,6 +590,16 @@ static void rtl839x_enable_bcast_flood(int port, bool enable) { } + +static void rtl839x_set_static_move_action(int port, bool forward) +{ + int shift = MV_ACT_PORT_SHIFT(port); + u32 val = forward ? MV_ACT_FORWARD : MV_ACT_DROP; + + sw_w32_mask(MV_ACT_MASK << shift, val << shift, + RTL839X_L2_PORT_STATIC_MV_ACT(port)); +} + irqreturn_t rtl839x_switch_irq(int irq, void *dev_id) { struct dsa_switch *ds = dev_id; @@ -1855,6 +1865,7 @@ const struct rtl838x_reg rtl839x_reg = { .enable_flood = rtl839x_enable_flood, .enable_mcast_flood = rtl839x_enable_mcast_flood, .enable_bcast_flood = rtl839x_enable_bcast_flood, + .set_static_move_action = rtl839x_set_static_move_action, .stp_get = rtl839x_stp_get, .stp_set = rtl839x_stp_set, .mac_force_mode_ctrl = rtl839x_mac_force_mode_ctrl, From 8ea27bb959b2181a3f3ca08d3f11b2a116960c87 Mon Sep 17 00:00:00 2001 From: Jan Hoffmann Date: Sat, 6 May 2023 19:28:55 +0200 Subject: [PATCH 04/10] realtek: handle changed flags in VLAN configuration The port_vlan_add method may be called while a port is already a member of that VLAN, so it needs to be able to handle changed flags. Fix it to properly handle when the PVID or UNTAGGED flag was previously set, but now no longer is. To reduce duplication, move PVID configuration to a separate function. Signed-off-by: Jan Hoffmann --- .../files-5.10/drivers/net/dsa/rtl83xx/dsa.c | 42 ++++++++++--------- .../files-5.15/drivers/net/dsa/rtl83xx/dsa.c | 38 +++++++++-------- 2 files changed, 43 insertions(+), 37 deletions(-) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index 2d603cd42c..e9fc6f15ed 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -1450,6 +1450,20 @@ static int rtl83xx_vlan_prepare(struct dsa_switch *ds, int port, return 0; } +static void rtl83xx_vlan_set_pvid(struct rtl838x_switch_priv *priv, + int port, int pvid) +{ + /* Set both inner and outer PVID of the port */ + priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_INNER, pvid); + priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, pvid); + priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER, + PBVLAN_MODE_UNTAG_AND_PRITAG); + priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_OUTER, + PBVLAN_MODE_UNTAG_AND_PRITAG); + + priv->ports[port].pvid = pvid; +} + static void rtl83xx_vlan_add(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan) { @@ -1468,20 +1482,11 @@ static void rtl83xx_vlan_add(struct dsa_switch *ds, int port, mutex_lock(&priv->reg_mutex); - if (vlan->flags & BRIDGE_VLAN_INFO_PVID) { - for (v = vlan->vid_begin; v <= vlan->vid_end; v++) { - if (!v) - continue; - /* Set both inner and outer PVID of the port */ - priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_INNER, v); - priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, v); - priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER, - PBVLAN_MODE_UNTAG_AND_PRITAG); - priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_OUTER, - PBVLAN_MODE_UNTAG_AND_PRITAG); - - priv->ports[port].pvid = vlan->vid_end; - } + for (v = vlan->vid_begin; v <= vlan->vid_end; v++) { + if (vlan->flags & BRIDGE_VLAN_INFO_PVID) + rtl83xx_vlan_set_pvid(priv, port, v); + else if (priv->ports[port].pvid == v) + rtl83xx_vlan_set_pvid(priv, port, 0); } for (v = vlan->vid_begin; v <= vlan->vid_end; v++) { @@ -1503,6 +1508,8 @@ static void rtl83xx_vlan_add(struct dsa_switch *ds, int port, info.tagged_ports |= BIT_ULL(port); if (vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED) info.untagged_ports |= BIT_ULL(port); + else + info.untagged_ports &= ~BIT_ULL(port); priv->r->vlan_set_untagged(v, info.untagged_ports); pr_debug("Untagged ports, VLAN %d: %llx\n", v, info.untagged_ports); @@ -1537,12 +1544,7 @@ static int rtl83xx_vlan_del(struct dsa_switch *ds, int port, for (v = vlan->vid_begin; v <= vlan->vid_end; v++) { /* Reset to default if removing the current PVID */ if (v == pvid) { - priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_INNER, 0); - priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, 0); - priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER, - PBVLAN_MODE_UNTAG_AND_PRITAG); - priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_OUTER, - PBVLAN_MODE_UNTAG_AND_PRITAG); + rtl83xx_vlan_set_pvid(priv, port, 0); } /* Get port memberships of this vlan */ priv->r->vlan_tables_read(v, &info); diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c index 703306498e..b50330e1b9 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c @@ -1434,6 +1434,20 @@ static int rtl83xx_vlan_prepare(struct dsa_switch *ds, int port, return 0; } +static void rtl83xx_vlan_set_pvid(struct rtl838x_switch_priv *priv, + int port, int pvid) +{ + /* Set both inner and outer PVID of the port */ + priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_INNER, pvid); + priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, pvid); + priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER, + PBVLAN_MODE_UNTAG_AND_PRITAG); + priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_OUTER, + PBVLAN_MODE_UNTAG_AND_PRITAG); + + priv->ports[port].pvid = pvid; +} + static int rtl83xx_vlan_add(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan, struct netlink_ext_ack *extack) @@ -1456,17 +1470,10 @@ static int rtl83xx_vlan_add(struct dsa_switch *ds, int port, mutex_lock(&priv->reg_mutex); - if (vlan->flags & BRIDGE_VLAN_INFO_PVID && vlan->vid) { - /* Set both inner and outer PVID of the port */ - priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_INNER, vlan->vid); - priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, vlan->vid); - priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER, - PBVLAN_MODE_UNTAG_AND_PRITAG); - priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_OUTER, - PBVLAN_MODE_UNTAG_AND_PRITAG); - - priv->ports[port].pvid = vlan->vid; - } + if (vlan->flags & BRIDGE_VLAN_INFO_PVID) + rtl83xx_vlan_set_pvid(priv, port, vlan->vid); + else if (priv->ports[port].pvid == vlan->vid) + rtl83xx_vlan_set_pvid(priv, port, 0); /* Get port memberships of this vlan */ priv->r->vlan_tables_read(vlan->vid, &info); @@ -1486,6 +1493,8 @@ static int rtl83xx_vlan_add(struct dsa_switch *ds, int port, info.tagged_ports |= BIT_ULL(port); if (vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED) info.untagged_ports |= BIT_ULL(port); + else + info.untagged_ports &= ~BIT_ULL(port); priv->r->vlan_set_untagged(vlan->vid, info.untagged_ports); pr_debug("Untagged ports, VLAN %d: %llx\n", vlan->vid, info.untagged_ports); @@ -1518,12 +1527,7 @@ static int rtl83xx_vlan_del(struct dsa_switch *ds, int port, /* Reset to default if removing the current PVID */ if (vlan->vid == pvid) { - priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_INNER, 0); - priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, 0); - priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER, - PBVLAN_MODE_UNTAG_AND_PRITAG); - priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_OUTER, - PBVLAN_MODE_UNTAG_AND_PRITAG); + rtl83xx_vlan_set_pvid(priv, port, 0); } /* Get port memberships of this vlan */ priv->r->vlan_tables_read(vlan->vid, &info); From 81931756e1490547f8a6e1ef510b52af28c60909 Mon Sep 17 00:00:00 2001 From: Jan Hoffmann Date: Sun, 7 May 2023 01:05:30 +0200 Subject: [PATCH 05/10] realtek: fix writing/deletion of CAM entries Actually use the index returned by rtl83xx_find_l2_cam_entry. Fixes: cde31976e375 ("realtek: Add support for Layer 2 Multicast") Signed-off-by: Jan Hoffmann --- .../realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c | 8 ++++---- .../realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index e9fc6f15ed..672675e884 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -1678,7 +1678,7 @@ static int rtl83xx_port_fdb_add(struct dsa_switch *ds, int port, } // Hash buckets full, try CAM - rtl83xx_find_l2_cam_entry(priv, seed, false, &e); + idx = rtl83xx_find_l2_cam_entry(priv, seed, false, &e); if (idx >= 0) { rtl83xx_setup_l2_uc_entry(&e, port, vid, mac); @@ -1714,7 +1714,7 @@ static int rtl83xx_port_fdb_del(struct dsa_switch *ds, int port, } /* Check CAM for spillover from hash buckets */ - rtl83xx_find_l2_cam_entry(priv, seed, true, &e); + idx = rtl83xx_find_l2_cam_entry(priv, seed, true, &e); if (idx >= 0) { e.valid = false; @@ -1816,7 +1816,7 @@ static void rtl83xx_port_mdb_add(struct dsa_switch *ds, int port, } // Hash buckets full, try CAM - rtl83xx_find_l2_cam_entry(priv, seed, false, &e); + idx = rtl83xx_find_l2_cam_entry(priv, seed, false, &e); if (idx >= 0) { if (e.valid) { @@ -1876,7 +1876,7 @@ int rtl83xx_port_mdb_del(struct dsa_switch *ds, int port, } /* Check CAM for spillover from hash buckets */ - rtl83xx_find_l2_cam_entry(priv, seed, true, &e); + idx = rtl83xx_find_l2_cam_entry(priv, seed, true, &e); if (idx >= 0) { portmask = rtl83xx_mc_group_del_port(priv, e.mc_portmask_index, port); diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c index b50330e1b9..dbf87a6072 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c @@ -1660,7 +1660,7 @@ static int rtl83xx_port_fdb_add(struct dsa_switch *ds, int port, } /* Hash buckets full, try CAM */ - rtl83xx_find_l2_cam_entry(priv, seed, false, &e); + idx = rtl83xx_find_l2_cam_entry(priv, seed, false, &e); if (idx >= 0) { rtl83xx_setup_l2_uc_entry(&e, port, vid, mac); @@ -1698,7 +1698,7 @@ static int rtl83xx_port_fdb_del(struct dsa_switch *ds, int port, } /* Check CAM for spillover from hash buckets */ - rtl83xx_find_l2_cam_entry(priv, seed, true, &e); + idx = rtl83xx_find_l2_cam_entry(priv, seed, true, &e); if (idx >= 0) { e.valid = false; @@ -1794,7 +1794,7 @@ static int rtl83xx_port_mdb_add(struct dsa_switch *ds, int port, } /* Hash buckets full, try CAM */ - rtl83xx_find_l2_cam_entry(priv, seed, false, &e); + idx = rtl83xx_find_l2_cam_entry(priv, seed, false, &e); if (idx >= 0) { if (e.valid) { @@ -1857,7 +1857,7 @@ int rtl83xx_port_mdb_del(struct dsa_switch *ds, int port, } /* Check CAM for spillover from hash buckets */ - rtl83xx_find_l2_cam_entry(priv, seed, true, &e); + idx = rtl83xx_find_l2_cam_entry(priv, seed, true, &e); if (idx >= 0) { portmask = rtl83xx_mc_group_del_port(priv, e.mc_portmask_index, port); From 57df840670b6038866ebed877ed9827276b730fe Mon Sep 17 00:00:00 2001 From: Jan Hoffmann Date: Sun, 7 May 2023 01:05:31 +0200 Subject: [PATCH 06/10] realtek: don't treat first multicast portmask entry as reserved There doesn't appear to be a reason to do this, as only the last entry is actually reserved for unknown multicast. This also fixes two issues: - As the increment happened after the bounds check, the value of the actually reserved last entry could be overwritten. - On deletion of entries, a corresponding decrement was missing, causing the wrong entry to be marked as free. Fixes: cde31976e375 ("realtek: Add support for Layer 2 Multicast") Signed-off-by: Jan Hoffmann --- target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c | 1 - target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c | 1 - 2 files changed, 2 deletions(-) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index 672675e884..e45919d8b5 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -994,7 +994,6 @@ static int rtl83xx_mc_group_alloc(struct rtl838x_switch_priv *priv, int port) } set_bit(mc_group, priv->mc_group_bm); - mc_group++; // We cannot use group 0, as this is used for lookup miss flooding portmask = BIT_ULL(port) | BIT_ULL(priv->cpu_port); priv->r->write_mcast_pmask(mc_group, portmask); diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c index dbf87a6072..43b6d502f7 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c @@ -981,7 +981,6 @@ static int rtl83xx_mc_group_alloc(struct rtl838x_switch_priv *priv, int port) } set_bit(mc_group, priv->mc_group_bm); - mc_group++; /* We cannot use group 0, as this is used for lookup miss flooding */ portmask = BIT_ULL(port) | BIT_ULL(priv->cpu_port); priv->r->write_mcast_pmask(mc_group, portmask); From 3356126b8263a5176bd1b633d428865fb0a4ced5 Mon Sep 17 00:00:00 2001 From: Jan Hoffmann Date: Sun, 7 May 2023 01:05:32 +0200 Subject: [PATCH 07/10] realtek: actually remove port from multicast portmask Fixes: 724e4af530cd ("realtek: Store and Restore MC memberships for port enable/disable") Signed-off-by: Jan Hoffmann --- target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c | 1 + target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c | 1 + 2 files changed, 2 insertions(+) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index e45919d8b5..bdcbb0a074 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -1024,6 +1024,7 @@ static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_gr pr_info("%s: %d is lag slave. ignore\n", __func__, port); return portmask; } + portmask &= ~BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); if (portmask == BIT_ULL(priv->cpu_port)) { portmask &= ~BIT_ULL(priv->cpu_port); diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c index 43b6d502f7..811c897234 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c @@ -1011,6 +1011,7 @@ static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_gr pr_info("%s: %d is lag slave. ignore\n", __func__, port); return portmask; } + portmask &= ~BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); if (portmask == BIT_ULL(priv->cpu_port)) { portmask &= ~BIT_ULL(priv->cpu_port); From 6772ae1172ad12cf81b141fd9c5441ad18c0dddf Mon Sep 17 00:00:00 2001 From: Jan Hoffmann Date: Sun, 7 May 2023 01:05:33 +0200 Subject: [PATCH 08/10] realtek: don't add CPU port to multicast portmasks There shouldn't be any reason to forward all multicast to the CPU. The original commit message also doesn't provide a reason for this seemingly unrelated change. The current implementation of the delete method is also broken, as it entirely removes any entry when the portmask contains only the CPU port, even if it was explicitly created. Fixes: 724e4af530cd ("realtek: Store and Restore MC memberships for port enable/disable") Signed-off-by: Jan Hoffmann --- .../linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c | 7 ++----- .../linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index bdcbb0a074..270ec172e3 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -994,7 +994,7 @@ static int rtl83xx_mc_group_alloc(struct rtl838x_switch_priv *priv, int port) } set_bit(mc_group, priv->mc_group_bm); - portmask = BIT_ULL(port) | BIT_ULL(priv->cpu_port); + portmask = BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); return mc_group; @@ -1026,11 +1026,8 @@ static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_gr } portmask &= ~BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); - if (portmask == BIT_ULL(priv->cpu_port)) { - portmask &= ~BIT_ULL(priv->cpu_port); - priv->r->write_mcast_pmask(mc_group, portmask); + if (!portmask) clear_bit(mc_group, priv->mc_group_bm); - } return portmask; } diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c index 811c897234..b4cb39ed5d 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c @@ -981,7 +981,7 @@ static int rtl83xx_mc_group_alloc(struct rtl838x_switch_priv *priv, int port) } set_bit(mc_group, priv->mc_group_bm); - portmask = BIT_ULL(port) | BIT_ULL(priv->cpu_port); + portmask = BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); return mc_group; @@ -1013,11 +1013,8 @@ static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_gr } portmask &= ~BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); - if (portmask == BIT_ULL(priv->cpu_port)) { - portmask &= ~BIT_ULL(priv->cpu_port); - priv->r->write_mcast_pmask(mc_group, portmask); + if (!portmask) clear_bit(mc_group, priv->mc_group_bm); - } return portmask; } From 98a3b52380b7c2632c60c54d86d5c562f5eabfe4 Mon Sep 17 00:00:00 2001 From: Jan Hoffmann Date: Sun, 7 May 2023 01:05:34 +0200 Subject: [PATCH 09/10] realtek: remove store_mcgroups/load_mcgroups The current implementation only works when store and load are called for the same port without any other calls in between. This is because the store function only saves a single port number instead of a portmask for each group. It also doesn't take into account that the allocation of multicast group entries might change between store/load calls. As a result, the multicast port mask table gets corrupted. This also includes the reserved entry for unknown multicast, which gets corrupted even when no other mdb entries have been added. Remove the code for storing/loading multicast groups entirely, as the original commit message doesn't offer a convincing reason why this would be necessary in the first place. Fixes: 724e4af530cd ("realtek: Store and Restore MC memberships for port enable/disable") Signed-off-by: Jan Hoffmann --- .../files-5.10/drivers/net/dsa/rtl83xx/dsa.c | 30 ------------------- .../drivers/net/dsa/rtl83xx/rtl838x.h | 1 - .../files-5.15/drivers/net/dsa/rtl83xx/dsa.c | 26 ---------------- .../drivers/net/dsa/rtl83xx/rtl838x.h | 1 - 4 files changed, 58 deletions(-) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index 270ec172e3..6e615be0e5 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -1032,31 +1032,6 @@ static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_gr return portmask; } -static void store_mcgroups(struct rtl838x_switch_priv *priv, int port) -{ - int mc_group; - - for (mc_group = 0; mc_group < MAX_MC_GROUPS; mc_group++) { - u64 portmask = priv->r->read_mcast_pmask(mc_group); - if (portmask & BIT_ULL(port)) { - priv->mc_group_saves[mc_group] = port; - rtl83xx_mc_group_del_port(priv, mc_group, port); - } - } -} - -static void load_mcgroups(struct rtl838x_switch_priv *priv, int port) -{ - int mc_group; - - for (mc_group = 0; mc_group < MAX_MC_GROUPS; mc_group++) { - if (priv->mc_group_saves[mc_group] == port) { - rtl83xx_mc_group_add_port(priv, mc_group, port); - priv->mc_group_saves[mc_group] = -1; - } - } -} - static int rtl83xx_port_enable(struct dsa_switch *ds, int port, struct phy_device *phydev) { @@ -1075,8 +1050,6 @@ static int rtl83xx_port_enable(struct dsa_switch *ds, int port, /* add port to switch mask of CPU_PORT */ priv->r->traffic_enable(priv->cpu_port, port); - load_mcgroups(priv, port); - if (priv->is_lagmember[port]) { pr_debug("%s: %d is lag slave. ignore\n", __func__, port); return 0; @@ -1112,7 +1085,6 @@ static void rtl83xx_port_disable(struct dsa_switch *ds, int port) // BUG: This does not work on RTL931X /* remove port from switch mask of CPU_PORT */ priv->r->traffic_disable(priv->cpu_port, port); - store_mcgroups(priv, port); /* remove all other ports in the same bridge from switch mask of port */ v = priv->r->traffic_get(port); @@ -1212,7 +1184,6 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port, port_bitmap |= BIT_ULL(i); } } - load_mcgroups(priv, port); /* Add all other ports to this port matrix. */ if (priv->ports[port].enable) { @@ -1257,7 +1228,6 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, port_bitmap |= BIT_ULL(i); } } - store_mcgroups(priv, port); /* Remove all other ports from this port matrix. */ if (priv->ports[port].enable) { diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h index 3f1f1d49f8..81656799a7 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h @@ -1086,7 +1086,6 @@ struct rtl838x_switch_priv { struct notifier_block fib_nb; bool eee_enabled; unsigned long int mc_group_bm[MAX_MC_GROUPS >> 5]; - int mc_group_saves[MAX_MC_GROUPS]; int n_pie_blocks; struct rhashtable tc_ht; unsigned long int pie_use_bm[MAX_PIE_ENTRIES >> 5]; diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c index b4cb39ed5d..df78aa3737 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c @@ -1019,27 +1019,6 @@ static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_gr return portmask; } -static void store_mcgroups(struct rtl838x_switch_priv *priv, int port) -{ - for (int mc_group = 0; mc_group < MAX_MC_GROUPS; mc_group++) { - u64 portmask = priv->r->read_mcast_pmask(mc_group); - if (portmask & BIT_ULL(port)) { - priv->mc_group_saves[mc_group] = port; - rtl83xx_mc_group_del_port(priv, mc_group, port); - } - } -} - -static void load_mcgroups(struct rtl838x_switch_priv *priv, int port) -{ - for (int mc_group = 0; mc_group < MAX_MC_GROUPS; mc_group++) { - if (priv->mc_group_saves[mc_group] == port) { - rtl83xx_mc_group_add_port(priv, mc_group, port); - priv->mc_group_saves[mc_group] = -1; - } - } -} - static int rtl83xx_port_enable(struct dsa_switch *ds, int port, struct phy_device *phydev) { @@ -1058,8 +1037,6 @@ static int rtl83xx_port_enable(struct dsa_switch *ds, int port, /* add port to switch mask of CPU_PORT */ priv->r->traffic_enable(priv->cpu_port, port); - load_mcgroups(priv, port); - if (priv->is_lagmember[port]) { pr_debug("%s: %d is lag slave. ignore\n", __func__, port); return 0; @@ -1095,7 +1072,6 @@ static void rtl83xx_port_disable(struct dsa_switch *ds, int port) /* BUG: This does not work on RTL931X */ /* remove port from switch mask of CPU_PORT */ priv->r->traffic_disable(priv->cpu_port, port); - store_mcgroups(priv, port); /* remove all other ports in the same bridge from switch mask of port */ v = priv->r->traffic_get(port); @@ -1197,7 +1173,6 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port, port_bitmap |= BIT_ULL(i); } } - load_mcgroups(priv, port); /* Add all other ports to this port matrix. */ if (priv->ports[port].enable) { @@ -1241,7 +1216,6 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, port_bitmap |= BIT_ULL(i); } } - store_mcgroups(priv, port); /* Remove all other ports from this port matrix. */ if (priv->ports[port].enable) { diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h index bfab576e06..24d18d61fa 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h @@ -1082,7 +1082,6 @@ struct rtl838x_switch_priv { struct notifier_block fib_nb; bool eee_enabled; unsigned long int mc_group_bm[MAX_MC_GROUPS >> 5]; - int mc_group_saves[MAX_MC_GROUPS]; int n_pie_blocks; struct rhashtable tc_ht; unsigned long int pie_use_bm[MAX_PIE_ENTRIES >> 5]; From a872570c043f5beee21c3af695f1a5a77f7eab04 Mon Sep 17 00:00:00 2001 From: Jan Hoffmann Date: Sun, 7 May 2023 01:05:35 +0200 Subject: [PATCH 10/10] realtek: remove redundant is_lagmember checks All callers of the rtl83xx_mc_group_* functions already do the same check, so these aren't needed. For rtl83xx_mc_group_alloc, this branch also incorrectly returned 0 instead of a negative value. If the branch wasn't effectively dead code anyway, this could potentially have caused bugs, as 0 is a valid multicast group entry index. Fixes: cde31976e375 ("realtek: Add support for Layer 2 Multicast") Signed-off-by: Jan Hoffmann --- .../files-5.10/drivers/net/dsa/rtl83xx/dsa.c | 15 ++------------- .../files-5.15/drivers/net/dsa/rtl83xx/dsa.c | 15 ++------------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index 6e615be0e5..bff42b088a 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -988,11 +988,6 @@ static int rtl83xx_mc_group_alloc(struct rtl838x_switch_priv *priv, int port) if (mc_group >= MAX_MC_GROUPS - 1) return -1; - if (priv->is_lagmember[port]) { - pr_info("%s: %d is lag slave. ignore\n", __func__, port); - return 0; - } - set_bit(mc_group, priv->mc_group_bm); portmask = BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); @@ -1005,10 +1000,7 @@ static u64 rtl83xx_mc_group_add_port(struct rtl838x_switch_priv *priv, int mc_gr u64 portmask = priv->r->read_mcast_pmask(mc_group); pr_debug("%s: %d\n", __func__, port); - if (priv->is_lagmember[port]) { - pr_info("%s: %d is lag slave. ignore\n", __func__, port); - return portmask; - } + portmask |= BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); @@ -1020,10 +1012,7 @@ static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_gr u64 portmask = priv->r->read_mcast_pmask(mc_group); pr_debug("%s: %d\n", __func__, port); - if (priv->is_lagmember[port]) { - pr_info("%s: %d is lag slave. ignore\n", __func__, port); - return portmask; - } + portmask &= ~BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); if (!portmask) diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c index df78aa3737..3c67ce5adb 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c @@ -975,11 +975,6 @@ static int rtl83xx_mc_group_alloc(struct rtl838x_switch_priv *priv, int port) if (mc_group >= MAX_MC_GROUPS - 1) return -1; - if (priv->is_lagmember[port]) { - pr_info("%s: %d is lag slave. ignore\n", __func__, port); - return 0; - } - set_bit(mc_group, priv->mc_group_bm); portmask = BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); @@ -992,10 +987,7 @@ static u64 rtl83xx_mc_group_add_port(struct rtl838x_switch_priv *priv, int mc_gr u64 portmask = priv->r->read_mcast_pmask(mc_group); pr_debug("%s: %d\n", __func__, port); - if (priv->is_lagmember[port]) { - pr_info("%s: %d is lag slave. ignore\n", __func__, port); - return portmask; - } + portmask |= BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); @@ -1007,10 +999,7 @@ static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_gr u64 portmask = priv->r->read_mcast_pmask(mc_group); pr_debug("%s: %d\n", __func__, port); - if (priv->is_lagmember[port]) { - pr_info("%s: %d is lag slave. ignore\n", __func__, port); - return portmask; - } + portmask &= ~BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); if (!portmask)