Commit 5a30833b authored by DENG Qingfang's avatar DENG Qingfang Committed by David S. Miller

net: dsa: mt7530: support MDB and bridge flag operations

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: default avatarDENG Qingfang <dqfext@gmail.com>
Reviewed-by: default avatarVladimir Oltean <olteanv@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4b9068b7
...@@ -999,8 +999,9 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port) ...@@ -999,8 +999,9 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
mt7530_write(priv, MT7530_PVC_P(port), mt7530_write(priv, MT7530_PVC_P(port),
PORT_SPEC_TAG); PORT_SPEC_TAG);
/* Unknown multicast frame forwarding to the cpu port */ /* Disable flooding by default */
mt7530_rmw(priv, MT7530_MFC, UNM_FFP_MASK, UNM_FFP(BIT(port))); 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 */ /* Set CPU port number */
if (priv->id == ID_MT7621) if (priv->id == ID_MT7621)
...@@ -1137,6 +1138,56 @@ mt7530_stp_state_set(struct dsa_switch *ds, int port, u8 state) ...@@ -1137,6 +1138,56 @@ mt7530_stp_state_set(struct dsa_switch *ds, int port, u8 state)
mt7530_rmw(priv, MT7530_SSP_P(port), FID_PST_MASK, stp_state); mt7530_rmw(priv, MT7530_SSP_P(port), FID_PST_MASK, stp_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 static int
mt7530_port_bridge_join(struct dsa_switch *ds, int port, mt7530_port_bridge_join(struct dsa_switch *ds, int port,
struct net_device *bridge) struct net_device *bridge)
...@@ -1348,6 +1399,59 @@ mt7530_port_fdb_dump(struct dsa_switch *ds, int port, ...@@ -1348,6 +1399,59 @@ mt7530_port_fdb_dump(struct dsa_switch *ds, int port,
return 0; return 0;
} }
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 static int
mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid) mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
{ {
...@@ -1820,9 +1924,12 @@ mt7530_setup(struct dsa_switch *ds) ...@@ -1820,9 +1924,12 @@ mt7530_setup(struct dsa_switch *ds)
ret = mt753x_cpu_port_enable(ds, i); ret = mt753x_cpu_port_enable(ds, i);
if (ret) if (ret)
return ret; return ret;
} else } else {
mt7530_port_disable(ds, i); 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 */ /* Enable consistent egress tag */
mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK, mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
...@@ -1984,9 +2091,13 @@ mt7531_setup(struct dsa_switch *ds) ...@@ -1984,9 +2091,13 @@ mt7531_setup(struct dsa_switch *ds)
ret = mt753x_cpu_port_enable(ds, i); ret = mt753x_cpu_port_enable(ds, i);
if (ret) if (ret)
return ret; return ret;
} else } else {
mt7530_port_disable(ds, i); 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 */ /* Enable consistent egress tag */
mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK, mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
...@@ -2708,11 +2819,16 @@ static const struct dsa_switch_ops mt7530_switch_ops = { ...@@ -2708,11 +2819,16 @@ static const struct dsa_switch_ops mt7530_switch_ops = {
.port_change_mtu = mt7530_port_change_mtu, .port_change_mtu = mt7530_port_change_mtu,
.port_max_mtu = mt7530_port_max_mtu, .port_max_mtu = mt7530_port_max_mtu,
.port_stp_state_set = mt7530_stp_state_set, .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_join = mt7530_port_bridge_join,
.port_bridge_leave = mt7530_port_bridge_leave, .port_bridge_leave = mt7530_port_bridge_leave,
.port_fdb_add = mt7530_port_fdb_add, .port_fdb_add = mt7530_port_fdb_add,
.port_fdb_del = mt7530_port_fdb_del, .port_fdb_del = mt7530_port_fdb_del,
.port_fdb_dump = mt7530_port_fdb_dump, .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_filtering = mt7530_port_vlan_filtering,
.port_vlan_add = mt7530_port_vlan_add, .port_vlan_add = mt7530_port_vlan_add,
.port_vlan_del = mt7530_port_vlan_del, .port_vlan_del = mt7530_port_vlan_del,
......
...@@ -34,6 +34,7 @@ enum mt753x_id { ...@@ -34,6 +34,7 @@ enum mt753x_id {
/* Registers to mac forward control for unknown frames */ /* Registers to mac forward control for unknown frames */
#define MT7530_MFC 0x10 #define MT7530_MFC 0x10
#define BC_FFP(x) (((x) & 0xff) << 24) #define BC_FFP(x) (((x) & 0xff) << 24)
#define BC_FFP_MASK BC_FFP(~0)
#define UNM_FFP(x) (((x) & 0xff) << 16) #define UNM_FFP(x) (((x) & 0xff) << 16)
#define UNM_FFP_MASK UNM_FFP(~0) #define UNM_FFP_MASK UNM_FFP(~0)
#define UNU_FFP(x) (((x) & 0xff) << 8) #define UNU_FFP(x) (((x) & 0xff) << 8)
......
...@@ -24,9 +24,6 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb, ...@@ -24,9 +24,6 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_port *dp = dsa_slave_to_port(dev);
u8 xmit_tpid; u8 xmit_tpid;
u8 *mtk_tag; 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 /* Build the special tag after the MAC Source Address. If VLAN header
* is present, it's required that VLAN header and special tag is * 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, ...@@ -55,10 +52,6 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
mtk_tag[0] = xmit_tpid; mtk_tag[0] = xmit_tpid;
mtk_tag[1] = (1 << dp->index) & MTK_HDR_XMIT_DP_BIT_MASK; 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 */ /* Tag control information is kept for 802.1Q */
if (xmit_tpid == MTK_HDR_XMIT_UNTAGGED) { if (xmit_tpid == MTK_HDR_XMIT_UNTAGGED) {
mtk_tag[2] = 0; mtk_tag[2] = 0;
...@@ -74,9 +67,6 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -74,9 +67,6 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev,
u16 hdr; u16 hdr;
int port; int port;
__be16 *phdr; __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))) if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
return NULL; return NULL;
...@@ -102,9 +92,7 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -102,9 +92,7 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev,
if (!skb->dev) if (!skb->dev)
return NULL; return NULL;
/* Only unicast or broadcast frames are offloaded */ skb->offload_fwd_mark = 1;
if (likely(!is_multicast_skb))
skb->offload_fwd_mark = 1;
return skb; return skb;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment