From 37feab6076aa816ed72fe836759a485353241916 Mon Sep 17 00:00:00 2001 From: DENG Qingfang Date: Fri, 6 Mar 2020 20:35:35 +0800 Subject: net: dsa: mt7530: add support for port mirroring Add support for configuring port mirroring through the cls_matchall classifier. We do a full ingress and/or egress capture towards a capture port. MT7530 supports one monitor port and multiple mirrored ports. Signed-off-by: DENG Qingfang Signed-off-by: David S. Miller --- drivers/net/dsa/mt7530.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/dsa/mt7530.h | 7 ++++++ 2 files changed, 67 insertions(+) --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -1151,6 +1151,64 @@ mt7530_port_vlan_del(struct dsa_switch * return 0; } +static int mt7530_port_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress) +{ + struct mt7530_priv *priv = ds->priv; + u32 val; + + /* Check for existent entry */ + if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) + return -EEXIST; + + val = mt7530_read(priv, MT7530_MFC); + + /* MT7530 only supports one monitor port */ + if (val & MIRROR_EN && MIRROR_PORT(val) != mirror->to_local_port) + return -EEXIST; + + val |= MIRROR_EN; + val &= ~MIRROR_MASK; + val |= mirror->to_local_port; + mt7530_write(priv, MT7530_MFC, val); + + val = mt7530_read(priv, MT7530_PCR_P(port)); + if (ingress) { + val |= PORT_RX_MIR; + priv->mirror_rx |= BIT(port); + } else { + val |= PORT_TX_MIR; + priv->mirror_tx |= BIT(port); + } + mt7530_write(priv, MT7530_PCR_P(port), val); + + return 0; +} + +static void mt7530_port_mirror_del(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror) +{ + struct mt7530_priv *priv = ds->priv; + u32 val; + + val = mt7530_read(priv, MT7530_PCR_P(port)); + if (mirror->ingress) { + val &= ~PORT_RX_MIR; + priv->mirror_rx &= ~BIT(port); + } else { + val &= ~PORT_TX_MIR; + priv->mirror_tx &= ~BIT(port); + } + mt7530_write(priv, MT7530_PCR_P(port), val); + + if (!priv->mirror_rx && !priv->mirror_tx) { + val = mt7530_read(priv, MT7530_MFC); + val &= ~MIRROR_EN; + mt7530_write(priv, MT7530_MFC, val); + } +} + static enum dsa_tag_protocol mtk_get_tag_protocol(struct dsa_switch *ds, int port) { @@ -1530,6 +1588,8 @@ static const struct dsa_switch_ops mt753 .port_vlan_prepare = mt7530_port_vlan_prepare, .port_vlan_add = mt7530_port_vlan_add, .port_vlan_del = mt7530_port_vlan_del, + .port_mirror_add = mt7530_port_mirror_add, + .port_mirror_del = mt7530_port_mirror_del, .phylink_validate = mt7530_phylink_validate, .phylink_mac_link_state = mt7530_phylink_mac_link_state, .phylink_mac_config = mt7530_phylink_mac_config, --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -36,6 +36,9 @@ enum { #define CPU_EN BIT(7) #define CPU_PORT(x) ((x) << 4) #define CPU_MASK (0xf << 4) +#define MIRROR_EN BIT(3) +#define MIRROR_PORT(x) ((x) & 0x7) +#define MIRROR_MASK 0x7 /* Registers for address table access */ #define MT7530_ATA1 0x74 @@ -141,6 +144,8 @@ enum mt7530_stp_state { /* Register for port control */ #define MT7530_PCR_P(x) (0x2004 + ((x) * 0x100)) +#define PORT_TX_MIR BIT(9) +#define PORT_RX_MIR BIT(8) #define PORT_VLAN(x) ((x) & 0x3) enum mt7530_port_mode { @@ -457,6 +462,8 @@ struct mt7530_priv { phy_interface_t p6_interface; phy_interface_t p5_interface; unsigned int p5_intf_sel; + u8 mirror_rx; + u8 mirror_tx; struct mt7530_port ports[MT7530_NUM_PORTS]; /* protect among processes for registers access*/