|
|
@@ -933,6 +933,86 @@ static int rtl83xx_get_sset_count(struct dsa_switch *ds, int port, int sset)
|
|
|
return ARRAY_SIZE(rtl83xx_mib);
|
|
|
}
|
|
|
|
|
|
+static int rtl83xx_mc_group_alloc(struct rtl838x_switch_priv *priv, int port)
|
|
|
+{
|
|
|
+ int mc_group = find_first_zero_bit(priv->mc_group_bm, MAX_MC_GROUPS - 1);
|
|
|
+ u64 portmask;
|
|
|
+
|
|
|
+ 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);
|
|
|
+ priv->r->write_mcast_pmask(mc_group, portmask);
|
|
|
+
|
|
|
+ return mc_group;
|
|
|
+}
|
|
|
+
|
|
|
+static u64 rtl83xx_mc_group_add_port(struct rtl838x_switch_priv *priv, int mc_group, int port)
|
|
|
+{
|
|
|
+ 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);
|
|
|
+
|
|
|
+ return portmask;
|
|
|
+}
|
|
|
+
|
|
|
+static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_group, int port)
|
|
|
+{
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ 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);
|
|
|
+ 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)
|
|
|
{
|
|
|
@@ -954,6 +1034,8 @@ 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;
|
|
|
@@ -988,6 +1070,7 @@ 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);
|
|
|
@@ -1087,6 +1170,7 @@ 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) {
|
|
|
@@ -1127,6 +1211,7 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port,
|
|
|
port_bitmap &= ~BIT_ULL(i);
|
|
|
}
|
|
|
}
|
|
|
+ store_mcgroups(priv, port);
|
|
|
|
|
|
/* Add all other ports to this port matrix. */
|
|
|
if (priv->ports[port].enable) {
|
|
|
@@ -1653,61 +1738,6 @@ static int rtl83xx_port_mdb_prepare(struct dsa_switch *ds, int port,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int rtl83xx_mc_group_alloc(struct rtl838x_switch_priv *priv, int port)
|
|
|
-{
|
|
|
- int mc_group = find_first_zero_bit(priv->mc_group_bm, MAX_MC_GROUPS - 1);
|
|
|
- u64 portmask;
|
|
|
-
|
|
|
- if (mc_group >= MAX_MC_GROUPS - 1)
|
|
|
- return -1;
|
|
|
-
|
|
|
- pr_debug("Using MC group %d\n", mc_group);
|
|
|
-
|
|
|
- if (priv->is_lagmember[port]) {
|
|
|
- pr_debug("%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);
|
|
|
- priv->r->write_mcast_pmask(mc_group, portmask);
|
|
|
-
|
|
|
- return mc_group;
|
|
|
-}
|
|
|
-
|
|
|
-static u64 rtl83xx_mc_group_add_port(struct rtl838x_switch_priv *priv, int mc_group, int port)
|
|
|
-{
|
|
|
- u64 portmask = priv->r->read_mcast_pmask(mc_group);
|
|
|
-
|
|
|
- if (priv->is_lagmember[port]) {
|
|
|
- pr_debug("%s: %d is lag slave. ignore\n", __func__, port);
|
|
|
- return portmask;
|
|
|
- }
|
|
|
-
|
|
|
- portmask |= BIT_ULL(port);
|
|
|
- priv->r->write_mcast_pmask(mc_group, portmask);
|
|
|
-
|
|
|
- return portmask;
|
|
|
-}
|
|
|
-
|
|
|
-static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_group, int port)
|
|
|
-{
|
|
|
- u64 portmask = priv->r->read_mcast_pmask(mc_group);
|
|
|
-
|
|
|
- if (priv->is_lagmember[port]) {
|
|
|
- pr_debug("%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)
|
|
|
- clear_bit(mc_group, priv->mc_group_bm);
|
|
|
-
|
|
|
- return portmask;
|
|
|
-}
|
|
|
-
|
|
|
static void rtl83xx_port_mdb_add(struct dsa_switch *ds, int port,
|
|
|
const struct switchdev_obj_port_mdb *mdb)
|
|
|
{
|