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..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 @@ -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,24 @@ 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)); + + /* 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(); @@ -240,7 +245,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 +262,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(); @@ -981,14 +988,8 @@ 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); - mc_group++; // We cannot use group 0, as this is used for lookup miss flooding - portmask = BIT_ULL(port) | BIT_ULL(priv->cpu_port); + portmask = BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); return mc_group; @@ -999,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); @@ -1014,45 +1012,15 @@ 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 == 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; } -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) { @@ -1071,8 +1039,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; @@ -1108,7 +1074,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); @@ -1208,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) { @@ -1218,6 +1182,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; @@ -1227,7 +1195,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,20 +1213,22 @@ 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; + if (priv->r->set_static_move_action) + priv->r->set_static_move_action(port, true); + mutex_unlock(&priv->reg_mutex); } @@ -1436,6 +1406,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) { @@ -1454,20 +1438,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++) { @@ -1489,6 +1464,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); @@ -1523,12 +1500,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); @@ -1662,7 +1634,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 +1670,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; @@ -1800,7 +1772,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) { @@ -1860,7 +1832,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.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..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 @@ -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); @@ -1072,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.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 83a0441ce2..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 @@ -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,24 @@ 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)); + + /* 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(); @@ -229,7 +234,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 +251,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(); @@ -968,14 +975,8 @@ 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); - mc_group++; /* We cannot use group 0, as this is used for lookup miss flooding */ - portmask = BIT_ULL(port) | BIT_ULL(priv->cpu_port); + portmask = BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); return mc_group; @@ -986,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); @@ -1001,41 +999,15 @@ 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 == 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; } -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) { @@ -1054,8 +1026,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; @@ -1091,7 +1061,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); @@ -1193,7 +1162,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) { @@ -1203,6 +1171,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; @@ -1212,7 +1184,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,20 +1201,22 @@ 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; + if (priv->r->set_static_move_action) + priv->r->set_static_move_action(port, true); + mutex_unlock(&priv->reg_mutex); } @@ -1420,6 +1394,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) @@ -1442,17 +1430,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); @@ -1472,6 +1453,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); @@ -1504,12 +1487,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); @@ -1642,7 +1620,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); @@ -1680,7 +1658,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; @@ -1776,7 +1754,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) { @@ -1839,7 +1817,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/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..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 @@ -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); @@ -1068,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]; 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,