OSDN Git Service

net: dsa: mt7530: support MDB and bridge flag operations
authorDENG Qingfang <dqfext@gmail.com>
Mon, 15 Mar 2021 17:09:40 +0000 (01:09 +0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 Mar 2021 18:54:41 +0000 (11:54 -0700)
Support port MDB and bridge flag operations.

As the hardware can manage multicast forwarding itself, offload_fwd_mark
can be unconditionally set to true.

Signed-off-by: DENG Qingfang <dqfext@gmail.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/mt7530.c
drivers/net/dsa/mt7530.h
net/dsa/tag_mtk.c

index f06f5fa..1278568 100644 (file)
@@ -999,8 +999,9 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
        mt7530_write(priv, MT7530_PVC_P(port),
                     PORT_SPEC_TAG);
 
-       /* Unknown multicast frame forwarding to the cpu port */
-       mt7530_rmw(priv, MT7530_MFC, UNM_FFP_MASK, UNM_FFP(BIT(port)));
+       /* Disable flooding by default */
+       mt7530_rmw(priv, MT7530_MFC, BC_FFP_MASK | UNM_FFP_MASK | UNU_FFP_MASK,
+                  BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) | UNU_FFP(BIT(port)));
 
        /* Set CPU port number */
        if (priv->id == ID_MT7621)
@@ -1138,6 +1139,56 @@ mt7530_stp_state_set(struct dsa_switch *ds, int port, u8 state)
 }
 
 static int
+mt7530_port_pre_bridge_flags(struct dsa_switch *ds, int port,
+                            struct switchdev_brport_flags flags,
+                            struct netlink_ext_ack *extack)
+{
+       if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
+                          BR_BCAST_FLOOD))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int
+mt7530_port_bridge_flags(struct dsa_switch *ds, int port,
+                        struct switchdev_brport_flags flags,
+                        struct netlink_ext_ack *extack)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       if (flags.mask & BR_LEARNING)
+               mt7530_rmw(priv, MT7530_PSC_P(port), SA_DIS,
+                          flags.val & BR_LEARNING ? 0 : SA_DIS);
+
+       if (flags.mask & BR_FLOOD)
+               mt7530_rmw(priv, MT7530_MFC, UNU_FFP(BIT(port)),
+                          flags.val & BR_FLOOD ? UNU_FFP(BIT(port)) : 0);
+
+       if (flags.mask & BR_MCAST_FLOOD)
+               mt7530_rmw(priv, MT7530_MFC, UNM_FFP(BIT(port)),
+                          flags.val & BR_MCAST_FLOOD ? UNM_FFP(BIT(port)) : 0);
+
+       if (flags.mask & BR_BCAST_FLOOD)
+               mt7530_rmw(priv, MT7530_MFC, BC_FFP(BIT(port)),
+                          flags.val & BR_BCAST_FLOOD ? BC_FFP(BIT(port)) : 0);
+
+       return 0;
+}
+
+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)
 {
@@ -1349,6 +1400,59 @@ err:
 }
 
 static int
+mt7530_port_mdb_add(struct dsa_switch *ds, int port,
+                   const struct switchdev_obj_port_mdb *mdb)
+{
+       struct mt7530_priv *priv = ds->priv;
+       const u8 *addr = mdb->addr;
+       u16 vid = mdb->vid;
+       u8 port_mask = 0;
+       int ret;
+
+       mutex_lock(&priv->reg_mutex);
+
+       mt7530_fdb_write(priv, vid, 0, addr, 0, STATIC_EMP);
+       if (!mt7530_fdb_cmd(priv, MT7530_FDB_READ, NULL))
+               port_mask = (mt7530_read(priv, MT7530_ATRD) >> PORT_MAP)
+                           & PORT_MAP_MASK;
+
+       port_mask |= BIT(port);
+       mt7530_fdb_write(priv, vid, port_mask, addr, -1, STATIC_ENT);
+       ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, NULL);
+
+       mutex_unlock(&priv->reg_mutex);
+
+       return ret;
+}
+
+static int
+mt7530_port_mdb_del(struct dsa_switch *ds, int port,
+                   const struct switchdev_obj_port_mdb *mdb)
+{
+       struct mt7530_priv *priv = ds->priv;
+       const u8 *addr = mdb->addr;
+       u16 vid = mdb->vid;
+       u8 port_mask = 0;
+       int ret;
+
+       mutex_lock(&priv->reg_mutex);
+
+       mt7530_fdb_write(priv, vid, 0, addr, 0, STATIC_EMP);
+       if (!mt7530_fdb_cmd(priv, MT7530_FDB_READ, NULL))
+               port_mask = (mt7530_read(priv, MT7530_ATRD) >> PORT_MAP)
+                           & PORT_MAP_MASK;
+
+       port_mask &= ~BIT(port);
+       mt7530_fdb_write(priv, vid, port_mask, addr, -1,
+                        port_mask ? STATIC_ENT : STATIC_EMP);
+       ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, NULL);
+
+       mutex_unlock(&priv->reg_mutex);
+
+       return ret;
+}
+
+static int
 mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
 {
        struct mt7530_dummy_poll p;
@@ -1820,9 +1924,12 @@ mt7530_setup(struct dsa_switch *ds)
                        ret = mt753x_cpu_port_enable(ds, i);
                        if (ret)
                                return ret;
-               } else
+               } else {
                        mt7530_port_disable(ds, i);
 
+                       /* Disable learning by default on all user ports */
+                       mt7530_set(priv, MT7530_PSC_P(i), SA_DIS);
+               }
                /* Enable consistent egress tag */
                mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
                           PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
@@ -1984,9 +2091,13 @@ mt7531_setup(struct dsa_switch *ds)
                        ret = mt753x_cpu_port_enable(ds, i);
                        if (ret)
                                return ret;
-               } else
+               } else {
                        mt7530_port_disable(ds, i);
 
+                       /* Disable learning by default on all user ports */
+                       mt7530_set(priv, MT7530_PSC_P(i), SA_DIS);
+               }
+
                /* Enable consistent egress tag */
                mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
                           PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
@@ -2708,11 +2819,16 @@ static const struct dsa_switch_ops mt7530_switch_ops = {
        .port_change_mtu        = mt7530_port_change_mtu,
        .port_max_mtu           = mt7530_port_max_mtu,
        .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,
        .port_fdb_del           = mt7530_port_fdb_del,
        .port_fdb_dump          = mt7530_port_fdb_dump,
+       .port_mdb_add           = mt7530_port_mdb_add,
+       .port_mdb_del           = mt7530_port_mdb_del,
        .port_vlan_filtering    = mt7530_port_vlan_filtering,
        .port_vlan_add          = mt7530_port_vlan_add,
        .port_vlan_del          = mt7530_port_vlan_del,
index 64a9bb3..ec36ea5 100644 (file)
@@ -34,6 +34,7 @@ enum mt753x_id {
 /* Registers to mac forward control for unknown frames */
 #define MT7530_MFC                     0x10
 #define  BC_FFP(x)                     (((x) & 0xff) << 24)
+#define  BC_FFP_MASK                   BC_FFP(~0)
 #define  UNM_FFP(x)                    (((x) & 0xff) << 16)
 #define  UNM_FFP_MASK                  UNM_FFP(~0)
 #define  UNU_FFP(x)                    (((x) & 0xff) << 8)
index 5974848..f9b2966 100644 (file)
@@ -24,9 +24,6 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
        struct dsa_port *dp = dsa_slave_to_port(dev);
        u8 xmit_tpid;
        u8 *mtk_tag;
-       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
@@ -55,10 +52,6 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
        mtk_tag[0] = xmit_tpid;
        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 (xmit_tpid == MTK_HDR_XMIT_UNTAGGED) {
                mtk_tag[2] = 0;
@@ -74,9 +67,6 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev,
        u16 hdr;
        int port;
        __be16 *phdr;
-       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;
@@ -102,9 +92,7 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev,
        if (!skb->dev)
                return NULL;
 
-       /* Only unicast or broadcast frames are offloaded */
-       if (likely(!is_multicast_skb))
-               skb->offload_fwd_mark = 1;
+       skb->offload_fwd_mark = 1;
 
        return skb;
 }