realtek: Store and Restore MC memberships for port enable/disable
We need to store and restore MC memberships in HW when a port joins or leaves a bridge as well as when it is enabled or disabled, as these properties should not change in these situations. Signed-off-by: Sebastian Gottschall <s.gottschall@dd-wrt.com> Signed-off-by: Birger Koblitz <git@birger-koblitz.de>
This commit is contained in:
		 Birger Koblitz
					Birger Koblitz
				
			
				
					committed by
					
						 Daniel Golle
						Daniel Golle
					
				
			
			
				
	
			
			
			 Daniel Golle
						Daniel Golle
					
				
			
						parent
						
							d22923be66
						
					
				
				
					commit
					724e4af530
				
			| @@ -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) | ||||
| { | ||||
|   | ||||
| @@ -1044,6 +1044,7 @@ 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]; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user