|
|
@@ -0,0 +1,116 @@
|
|
|
+From 5e5502e012b8129e11be616acb0f9c34bc8f8adb Mon Sep 17 00:00:00 2001
|
|
|
+From: DENG Qingfang <[email protected]>
|
|
|
+Date: Wed, 13 May 2020 23:10:16 +0800
|
|
|
+Subject: net: dsa: mt7530: fix roaming from DSA user ports
|
|
|
+
|
|
|
+When a client moves from a DSA user port to a software port in a bridge,
|
|
|
+it cannot reach any other clients that connected to the DSA user ports.
|
|
|
+That is because SA learning on the CPU port is disabled, so the switch
|
|
|
+ignores the client's frames from the CPU port and still thinks it is at
|
|
|
+the user port.
|
|
|
+
|
|
|
+Fix it by enabling SA learning on the CPU port.
|
|
|
+
|
|
|
+To prevent the switch from learning from flooding frames from the CPU
|
|
|
+port, set skb->offload_fwd_mark to 1 for unicast and broadcast frames,
|
|
|
+and let the switch flood them instead of trapping to the CPU port.
|
|
|
+Multicast frames still need to be trapped to the CPU port for snooping,
|
|
|
+so set the SA_DIS bit of the MTK tag to 1 when transmitting those frames
|
|
|
+to disable SA learning.
|
|
|
+
|
|
|
+Fixes: b8f126a8d543 ("net-next: dsa: add dsa support for Mediatek MT7530 switch")
|
|
|
+Signed-off-by: DENG Qingfang <[email protected]>
|
|
|
+Signed-off-by: David S. Miller <[email protected]>
|
|
|
+---
|
|
|
+ drivers/net/dsa/mt7530.c | 9 ++-------
|
|
|
+ drivers/net/dsa/mt7530.h | 1 +
|
|
|
+ net/dsa/tag_mtk.c | 15 +++++++++++++++
|
|
|
+ 3 files changed, 18 insertions(+), 7 deletions(-)
|
|
|
+
|
|
|
+--- a/drivers/net/dsa/mt7530.c
|
|
|
++++ b/drivers/net/dsa/mt7530.c
|
|
|
+@@ -639,11 +639,8 @@ mt7530_cpu_port_enable(struct mt7530_pri
|
|
|
+ mt7530_write(priv, MT7530_PVC_P(port),
|
|
|
+ PORT_SPEC_TAG);
|
|
|
+
|
|
|
+- /* Disable auto learning on the cpu port */
|
|
|
+- mt7530_set(priv, MT7530_PSC_P(port), SA_DIS);
|
|
|
+-
|
|
|
+- /* Unknown unicast frame fordwarding to the cpu port */
|
|
|
+- mt7530_set(priv, MT7530_MFC, UNU_FFP(BIT(port)));
|
|
|
++ /* Unknown multicast frame forwarding to the cpu port */
|
|
|
++ mt7530_rmw(priv, MT7530_MFC, UNM_FFP_MASK, UNM_FFP(BIT(port)));
|
|
|
+
|
|
|
+ /* Set CPU port number */
|
|
|
+ if (priv->id == ID_MT7621)
|
|
|
+@@ -1298,8 +1295,6 @@ mt7530_setup(struct dsa_switch *ds)
|
|
|
+ /* Enable and reset MIB counters */
|
|
|
+ mt7530_mib_reset(ds);
|
|
|
+
|
|
|
+- mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK);
|
|
|
+-
|
|
|
+ for (i = 0; i < MT7530_NUM_PORTS; i++) {
|
|
|
+ /* Disable forwarding by default on all ports */
|
|
|
+ mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
|
|
|
+--- a/drivers/net/dsa/mt7530.h
|
|
|
++++ b/drivers/net/dsa/mt7530.h
|
|
|
+@@ -31,6 +31,7 @@ enum {
|
|
|
+ #define MT7530_MFC 0x10
|
|
|
+ #define BC_FFP(x) (((x) & 0xff) << 24)
|
|
|
+ #define UNM_FFP(x) (((x) & 0xff) << 16)
|
|
|
++#define UNM_FFP_MASK UNM_FFP(~0)
|
|
|
+ #define UNU_FFP(x) (((x) & 0xff) << 8)
|
|
|
+ #define UNU_FFP_MASK UNU_FFP(~0)
|
|
|
+ #define CPU_EN BIT(7)
|
|
|
+--- a/net/dsa/tag_mtk.c
|
|
|
++++ b/net/dsa/tag_mtk.c
|
|
|
+@@ -15,6 +15,7 @@
|
|
|
+ #define MTK_HDR_XMIT_TAGGED_TPID_8100 1
|
|
|
+ #define MTK_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0)
|
|
|
+ #define MTK_HDR_XMIT_DP_BIT_MASK GENMASK(5, 0)
|
|
|
++#define MTK_HDR_XMIT_SA_DIS BIT(6)
|
|
|
+
|
|
|
+ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
|
|
|
+ struct net_device *dev)
|
|
|
+@@ -22,6 +23,9 @@ static struct sk_buff *mtk_tag_xmit(stru
|
|
|
+ struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
+ u8 *mtk_tag;
|
|
|
+ bool is_vlan_skb = true;
|
|
|
++ unsigned char *dest = eth_hdr(skb)->h_dest;
|
|
|
++ bool is_multicast_skb = is_multicast_ether_addr(dest) &&
|
|
|
++ !is_broadcast_ether_addr(dest);
|
|
|
+
|
|
|
+ /* Build the special tag after the MAC Source Address. If VLAN header
|
|
|
+ * is present, it's required that VLAN header and special tag is
|
|
|
+@@ -47,6 +51,10 @@ static struct sk_buff *mtk_tag_xmit(stru
|
|
|
+ MTK_HDR_XMIT_UNTAGGED;
|
|
|
+ mtk_tag[1] = (1 << dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
|
|
|
+
|
|
|
++ /* Disable SA learning for multicast frames */
|
|
|
++ if (unlikely(is_multicast_skb))
|
|
|
++ mtk_tag[1] |= MTK_HDR_XMIT_SA_DIS;
|
|
|
++
|
|
|
+ /* Tag control information is kept for 802.1Q */
|
|
|
+ if (!is_vlan_skb) {
|
|
|
+ mtk_tag[2] = 0;
|
|
|
+@@ -61,6 +69,9 @@ static struct sk_buff *mtk_tag_rcv(struc
|
|
|
+ {
|
|
|
+ int port;
|
|
|
+ __be16 *phdr, hdr;
|
|
|
++ unsigned char *dest = eth_hdr(skb)->h_dest;
|
|
|
++ bool is_multicast_skb = is_multicast_ether_addr(dest) &&
|
|
|
++ !is_broadcast_ether_addr(dest);
|
|
|
+
|
|
|
+ if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
|
|
|
+ return NULL;
|
|
|
+@@ -86,6 +97,10 @@ static struct sk_buff *mtk_tag_rcv(struc
|
|
|
+ if (!skb->dev)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
++ /* Only unicast or broadcast frames are offloaded */
|
|
|
++ if (likely(!is_multicast_skb))
|
|
|
++ skb->offload_fwd_mark = 1;
|
|
|
++
|
|
|
+ return skb;
|
|
|
+ }
|
|
|
+
|