diff options
Diffstat (limited to 'drivers/net/dsa/mt7530.c')
| -rw-r--r-- | drivers/net/dsa/mt7530.c | 172 | 
1 files changed, 119 insertions, 53 deletions
| diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 93136f7e69f5..d0cba2d1cd68 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -47,6 +47,7 @@ static const struct mt7530_mib_desc mt7530_mib[] = {  	MIB_DESC(2, 0x48, "TxBytes"),  	MIB_DESC(1, 0x60, "RxDrop"),  	MIB_DESC(1, 0x64, "RxFiltering"), +	MIB_DESC(1, 0x68, "RxUnicast"),  	MIB_DESC(1, 0x6c, "RxMulticast"),  	MIB_DESC(1, 0x70, "RxBroadcast"),  	MIB_DESC(1, 0x74, "RxAlignErr"), @@ -366,6 +367,8 @@ mt7530_fdb_write(struct mt7530_priv *priv, u16 vid,  	int i;  	reg[1] |= vid & CVID_MASK; +	reg[1] |= ATA2_IVL; +	reg[1] |= ATA2_FID(FID_BRIDGED);  	reg[2] |= (aging & AGE_TIMER_MASK) << AGE_TIMER;  	reg[2] |= (port_mask & PORT_MAP_MASK) << PORT_MAP;  	/* STATIC_ENT indicate that entry is static wouldn't @@ -1019,6 +1022,10 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)  	mt7530_write(priv, MT7530_PCR_P(port),  		     PCR_MATRIX(dsa_user_ports(priv->ds))); +	/* Set to fallback mode for independent VLAN learning */ +	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK, +		   MT7530_PORT_FALLBACK_MODE); +  	return 0;  } @@ -1141,7 +1148,8 @@ mt7530_stp_state_set(struct dsa_switch *ds, int port, u8 state)  		break;  	} -	mt7530_rmw(priv, MT7530_SSP_P(port), FID_PST_MASK, stp_state); +	mt7530_rmw(priv, MT7530_SSP_P(port), FID_PST_MASK(FID_BRIDGED), +		   FID_PST(FID_BRIDGED, stp_state));  }  static int @@ -1183,18 +1191,6 @@ mt7530_port_bridge_flags(struct dsa_switch *ds, int port,  }  static int -mt7530_port_set_mrouter(struct dsa_switch *ds, int port, bool mrouter, -			struct netlink_ext_ack *extack) -{ -	struct mt7530_priv *priv = ds->priv; - -	mt7530_rmw(priv, MT7530_MFC, UNM_FFP(BIT(port)), -		   mrouter ? UNM_FFP(BIT(port)) : 0); - -	return 0; -} - -static int  mt7530_port_bridge_join(struct dsa_switch *ds, int port,  			struct net_device *bridge)  { @@ -1227,6 +1223,10 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port,  			   PCR_MATRIX_MASK, PCR_MATRIX(port_bitmap));  	priv->ports[port].pm |= PCR_MATRIX(port_bitmap); +	/* Set to fallback mode for independent VLAN learning */ +	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK, +		   MT7530_PORT_FALLBACK_MODE); +  	mutex_unlock(&priv->reg_mutex);  	return 0; @@ -1239,15 +1239,22 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)  	bool all_user_ports_removed = true;  	int i; -	/* When a port is removed from the bridge, the port would be set up -	 * back to the default as is at initial boot which is a VLAN-unaware -	 * port. +	/* This is called after .port_bridge_leave when leaving a VLAN-aware +	 * bridge. Don't set standalone ports to fallback mode.  	 */ -	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK, -		   MT7530_PORT_MATRIX_MODE); -	mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK | PVC_EG_TAG_MASK, +	if (dsa_to_port(ds, port)->bridge_dev) +		mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK, +			   MT7530_PORT_FALLBACK_MODE); + +	mt7530_rmw(priv, MT7530_PVC_P(port), +		   VLAN_ATTR_MASK | PVC_EG_TAG_MASK | ACC_FRM_MASK,  		   VLAN_ATTR(MT7530_VLAN_TRANSPARENT) | -		   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); +		   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT) | +		   MT7530_VLAN_ACC_ALL); + +	/* Set PVID to 0 */ +	mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, +		   G0_PORT_VID_DEF);  	for (i = 0; i < MT7530_NUM_PORTS; i++) {  		if (dsa_is_user_port(ds, i) && @@ -1274,15 +1281,19 @@ mt7530_port_set_vlan_aware(struct dsa_switch *ds, int port)  	struct mt7530_priv *priv = ds->priv;  	/* Trapped into security mode allows packet forwarding through VLAN -	 * table lookup. CPU port is set to fallback mode to let untagged -	 * frames pass through. +	 * table lookup.  	 */ -	if (dsa_is_cpu_port(ds, port)) -		mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK, -			   MT7530_PORT_FALLBACK_MODE); -	else +	if (dsa_is_user_port(ds, port)) {  		mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,  			   MT7530_PORT_SECURITY_MODE); +		mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, +			   G0_PORT_VID(priv->ports[port].pvid)); + +		/* Only accept tagged frames if PVID is not set */ +		if (!priv->ports[port].pvid) +			mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK, +				   MT7530_VLAN_ACC_TAGGED); +	}  	/* Set the port as a user port which is to be able to recognize VID  	 * from incoming packets before fetching entry within the VLAN table. @@ -1305,11 +1316,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,  		/* Remove this port from the port matrix of the other ports  		 * in the same bridge. If the port is disabled, port matrix  		 * is kept and not being setup until the port becomes enabled. -		 * And the other port's port matrix cannot be broken when the -		 * other port is still a VLAN-aware port.  		 */ -		if (dsa_is_user_port(ds, i) && i != port && -		   !dsa_port_is_vlan_filtering(dsa_to_port(ds, i))) { +		if (dsa_is_user_port(ds, i) && i != port) {  			if (dsa_to_port(ds, i)->bridge_dev != bridge)  				continue;  			if (priv->ports[i].enable) @@ -1327,6 +1335,13 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,  			   PCR_MATRIX(BIT(MT7530_CPU_PORT)));  	priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); +	/* When a port is removed from the bridge, the port would be set up +	 * back to the default as is at initial boot which is a VLAN-unaware +	 * port. +	 */ +	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK, +		   MT7530_PORT_MATRIX_MODE); +  	mutex_unlock(&priv->reg_mutex);  } @@ -1509,7 +1524,8 @@ mt7530_hw_vlan_add(struct mt7530_priv *priv,  	/* Validate the entry with independent learning, create egress tag per  	 * VLAN and joining the port as one of the port members.  	 */ -	val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) | VLAN_VALID; +	val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) | FID(FID_BRIDGED) | +	      VLAN_VALID;  	mt7530_write(priv, MT7530_VAWD1, val);  	/* Decide whether adding tag or not for those outgoing packets from the @@ -1584,6 +1600,21 @@ mt7530_hw_vlan_update(struct mt7530_priv *priv, u16 vid,  }  static int +mt7530_setup_vlan0(struct mt7530_priv *priv) +{ +	u32 val; + +	/* Validate the entry with independent learning, keep the original +	 * ingress tag attribute. +	 */ +	val = IVL_MAC | EG_CON | PORT_MEM(MT7530_ALL_MEMBERS) | FID(FID_BRIDGED) | +	      VLAN_VALID; +	mt7530_write(priv, MT7530_VAWD1, val); + +	return mt7530_vlan_cmd(priv, MT7530_VTCR_WR_VID, 0); +} + +static int  mt7530_port_vlan_add(struct dsa_switch *ds, int port,  		     const struct switchdev_obj_port_vlan *vlan,  		     struct netlink_ext_ack *extack) @@ -1599,9 +1630,28 @@ mt7530_port_vlan_add(struct dsa_switch *ds, int port,  	mt7530_hw_vlan_update(priv, vlan->vid, &new_entry, mt7530_hw_vlan_add);  	if (pvid) { -		mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, -			   G0_PORT_VID(vlan->vid));  		priv->ports[port].pvid = vlan->vid; + +		/* Accept all frames if PVID is set */ +		mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK, +			   MT7530_VLAN_ACC_ALL); + +		/* Only configure PVID if VLAN filtering is enabled */ +		if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) +			mt7530_rmw(priv, MT7530_PPBV1_P(port), +				   G0_PORT_VID_MASK, +				   G0_PORT_VID(vlan->vid)); +	} else if (vlan->vid && priv->ports[port].pvid == vlan->vid) { +		/* This VLAN is overwritten without PVID, so unset it */ +		priv->ports[port].pvid = G0_PORT_VID_DEF; + +		/* Only accept tagged frames if the port is VLAN-aware */ +		if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) +			mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK, +				   MT7530_VLAN_ACC_TAGGED); + +		mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, +			   G0_PORT_VID_DEF);  	}  	mutex_unlock(&priv->reg_mutex); @@ -1615,11 +1665,9 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port,  {  	struct mt7530_hw_vlan_entry target_entry;  	struct mt7530_priv *priv = ds->priv; -	u16 pvid;  	mutex_lock(&priv->reg_mutex); -	pvid = priv->ports[port].pvid;  	mt7530_hw_vlan_entry_init(&target_entry, port, 0);  	mt7530_hw_vlan_update(priv, vlan->vid, &target_entry,  			      mt7530_hw_vlan_del); @@ -1627,11 +1675,18 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port,  	/* PVID is being restored to the default whenever the PVID port  	 * is being removed from the VLAN.  	 */ -	if (pvid == vlan->vid) -		pvid = G0_PORT_VID_DEF; +	if (priv->ports[port].pvid == vlan->vid) { +		priv->ports[port].pvid = G0_PORT_VID_DEF; + +		/* Only accept tagged frames if the port is VLAN-aware */ +		if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) +			mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK, +				   MT7530_VLAN_ACC_TAGGED); + +		mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, +			   G0_PORT_VID_DEF); +	} -	mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, pvid); -	priv->ports[port].pvid = pvid;  	mutex_unlock(&priv->reg_mutex); @@ -1715,15 +1770,7 @@ static enum dsa_tag_protocol  mtk_get_tag_protocol(struct dsa_switch *ds, int port,  		     enum dsa_tag_protocol mp)  { -	struct mt7530_priv *priv = ds->priv; - -	if (port != MT7530_CPU_PORT) { -		dev_warn(priv->dev, -			 "port not matched with tagging CPU port\n"); -		return DSA_TAG_PROTO_NONE; -	} else { -		return DSA_TAG_PROTO_MTK; -	} +	return DSA_TAG_PROTO_MTK;  }  #ifdef CONFIG_GPIOLIB @@ -2052,6 +2099,7 @@ mt7530_setup(struct dsa_switch *ds)  	 * as two netdev instances.  	 */  	dn = dsa_to_port(ds, MT7530_CPU_PORT)->master->dev.of_node->parent; +	ds->assisted_learning_on_cpu_port = true;  	ds->mtu_enforcement_ingress = true;  	if (priv->id == ID_MT7530) { @@ -2122,6 +2170,9 @@ mt7530_setup(struct dsa_switch *ds)  		mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,  			   PCR_MATRIX_CLR); +		/* Disable learning by default on all ports */ +		mt7530_set(priv, MT7530_PSC_P(i), SA_DIS); +  		if (dsa_is_cpu_port(ds, i)) {  			ret = mt753x_cpu_port_enable(ds, i);  			if (ret) @@ -2129,14 +2180,20 @@ mt7530_setup(struct dsa_switch *ds)  		} else {  			mt7530_port_disable(ds, i); -			/* Disable learning by default on all user ports */ -			mt7530_set(priv, MT7530_PSC_P(i), SA_DIS); +			/* Set default PVID to 0 on all user ports */ +			mt7530_rmw(priv, MT7530_PPBV1_P(i), G0_PORT_VID_MASK, +				   G0_PORT_VID_DEF);  		}  		/* Enable consistent egress tag */  		mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,  			   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));  	} +	/* Setup VLAN ID 0 for VLAN-unaware bridges */ +	ret = mt7530_setup_vlan0(priv); +	if (ret) +		return ret; +  	/* Setup port 5 */  	priv->p5_intf_sel = P5_DISABLED;  	interface = PHY_INTERFACE_MODE_NA; @@ -2287,6 +2344,9 @@ mt7531_setup(struct dsa_switch *ds)  		mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,  			   PCR_MATRIX_CLR); +		/* Disable learning by default on all ports */ +		mt7530_set(priv, MT7530_PSC_P(i), SA_DIS); +  		mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);  		if (dsa_is_cpu_port(ds, i)) { @@ -2296,8 +2356,9 @@ mt7531_setup(struct dsa_switch *ds)  		} else {  			mt7530_port_disable(ds, i); -			/* Disable learning by default on all user ports */ -			mt7530_set(priv, MT7530_PSC_P(i), SA_DIS); +			/* Set default PVID to 0 on all user ports */ +			mt7530_rmw(priv, MT7530_PPBV1_P(i), G0_PORT_VID_MASK, +				   G0_PORT_VID_DEF);  		}  		/* Enable consistent egress tag */ @@ -2305,6 +2366,12 @@ mt7531_setup(struct dsa_switch *ds)  			   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));  	} +	/* Setup VLAN ID 0 for VLAN-unaware bridges */ +	ret = mt7530_setup_vlan0(priv); +	if (ret) +		return ret; + +	ds->assisted_learning_on_cpu_port = true;  	ds->mtu_enforcement_ingress = true;  	/* Flush the FDB table */ @@ -3058,7 +3125,6 @@ static const struct dsa_switch_ops mt7530_switch_ops = {  	.port_stp_state_set	= mt7530_stp_state_set,  	.port_pre_bridge_flags	= mt7530_port_pre_bridge_flags,  	.port_bridge_flags	= mt7530_port_bridge_flags, -	.port_set_mrouter	= mt7530_port_set_mrouter,  	.port_bridge_join	= mt7530_port_bridge_join,  	.port_bridge_leave	= mt7530_port_bridge_leave,  	.port_fdb_add		= mt7530_port_fdb_add, |