Hi, this patch adds the swlib attributes
enable_mirror_rx enable_mirror_tx mirror_monitor_port mirror_source_port to the AR8327 switch/PHY driver that allow to mirror Ethernet packets to a monitor port. Tested on a TL-WDR4300 router. Signed-off-by: Colin Leitner <colin.leit...@gmail.com> Index: target/linux/generic/files/drivers/net/phy/ar8216.c =================================================================== --- target/linux/generic/files/drivers/net/phy/ar8216.c (revision 34185) +++ target/linux/generic/files/drivers/net/phy/ar8216.c (working copy) @@ -88,6 +88,12 @@ u8 vlan_table[AR8X16_MAX_VLANS]; u8 vlan_tagged; u16 pvid[AR8X16_MAX_PORTS]; + + /* Mirroring */ + bool mirror_rx; + bool mirror_tx; + int source_port; + int monitor_port; }; #define to_ar8216(_dev) container_of(_dev, struct ar8216_priv, dev) @@ -1001,8 +1007,132 @@ return 0; } +static void +ar8327_set_mirror_regs(struct ar8216_priv *priv) +{ + int port; + /* Reset all mirror registers */ + ar8216_rmw(priv, AR8327_REG_FWD_CTRL0, + AR8327_FWD_CTRL0_MIRROR_PORT, + (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S)); + for (port = 0; port < AR8327_NUM_PORTS; port++) { + ar8216_rmw(priv, AR8327_REG_PORT_LOOKUP(port), + AR8327_PORT_LOOKUP_ING_MIRROR_EN, + 0); + + ar8216_rmw(priv, AR8327_REG_PORT_HOL_CTRL1(port), + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN, + 0); + } + + /* Now enable mirroring if necessary */ + if (priv->source_port >= AR8327_NUM_PORTS || + priv->monitor_port >= AR8327_NUM_PORTS || + priv->source_port == priv->monitor_port) { + return; + } + + ar8216_rmw(priv, AR8327_REG_FWD_CTRL0, + AR8327_FWD_CTRL0_MIRROR_PORT, + (priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S)); + + if (priv->mirror_tx) + ar8216_rmw(priv, AR8327_REG_PORT_LOOKUP(priv->source_port), + AR8327_PORT_LOOKUP_ING_MIRROR_EN, + AR8327_PORT_LOOKUP_ING_MIRROR_EN); + + if (priv->mirror_rx) + ar8216_rmw(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port), + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN, + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN); +} + static int +ar8327_sw_set_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8216_priv *priv = to_ar8216(dev); + priv->mirror_rx = !!val->value.i; + ar8327_set_mirror_regs(priv); + return 0; +} + +static int +ar8327_sw_get_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8216_priv *priv = to_ar8216(dev); + val->value.i = priv->mirror_rx; + return 0; +} + +static int +ar8327_sw_set_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8216_priv *priv = to_ar8216(dev); + priv->mirror_tx = !!val->value.i; + ar8327_set_mirror_regs(priv); + return 0; +} + +static int +ar8327_sw_get_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8216_priv *priv = to_ar8216(dev); + val->value.i = priv->mirror_tx; + return 0; +} + +static int +ar8327_sw_set_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8216_priv *priv = to_ar8216(dev); + priv->monitor_port = val->value.i; + ar8327_set_mirror_regs(priv); + return 0; +} + +static int +ar8327_sw_get_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8216_priv *priv = to_ar8216(dev); + val->value.i = priv->monitor_port; + return 0; +} + +static int +ar8327_sw_set_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8216_priv *priv = to_ar8216(dev); + priv->source_port = val->value.i; + ar8327_set_mirror_regs(priv); + return 0; +} + +static int +ar8327_sw_get_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8216_priv *priv = to_ar8216(dev); + val->value.i = priv->source_port; + return 0; +} + +static int ar8216_sw_set_pvid(struct switch_dev *dev, int port, int vlan) { struct ar8216_priv *priv = to_ar8216(dev); @@ -1192,6 +1322,9 @@ priv->chip->init_port(priv, i); priv->chip->init_globals(priv); + + ar8327_set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); return ar8216_sw_hw_apply(dev); @@ -1208,6 +1341,49 @@ }, }; +static struct switch_attr ar8327_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = ar8216_sw_set_vlan, + .get = ar8216_sw_get_vlan, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_rx", + .description = "Enable mirroring of RX packets", + .set = ar8327_sw_set_mirror_rx_enable, + .get = ar8327_sw_get_mirror_rx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_tx", + .description = "Enable mirroring of TX packets", + .set = ar8327_sw_set_mirror_tx_enable, + .get = ar8327_sw_get_mirror_tx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_monitor_port", + .description = "Mirror monitor port", + .set = ar8327_sw_set_mirror_monitor_port, + .get = ar8327_sw_get_mirror_monitor_port, + .max = AR8327_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_source_port", + .description = "Mirror source port", + .set = ar8327_sw_set_mirror_source_port, + .get = ar8327_sw_get_mirror_source_port, + .max = AR8327_NUM_PORTS - 1 + }, +}; + static struct switch_attr ar8216_port[] = { }; @@ -1244,6 +1420,28 @@ .get_port_link = ar8216_sw_get_port_link, }; +static const struct switch_dev_ops ar8327_sw_ops = { + .attr_global = { + .attr = ar8327_globals, + .n_attr = ARRAY_SIZE(ar8327_globals), + }, + .attr_port = { + .attr = ar8216_port, + .n_attr = ARRAY_SIZE(ar8216_port), + }, + .attr_vlan = { + .attr = ar8216_vlan, + .n_attr = ARRAY_SIZE(ar8216_vlan), + }, + .get_port_pvid = ar8216_sw_get_pvid, + .set_port_pvid = ar8216_sw_set_pvid, + .get_vlan_ports = ar8216_sw_get_ports, + .set_vlan_ports = ar8216_sw_set_ports, + .apply_config = ar8216_sw_hw_apply, + .reset_switch = ar8216_sw_reset_switch, + .get_port_link = ar8216_sw_get_port_link, +}; + static int ar8216_id_chip(struct ar8216_priv *priv) { @@ -1387,6 +1585,7 @@ swdev->name = "Atheros AR8327"; swdev->vlans = AR8X16_MAX_VLANS; swdev->ports = AR8327_NUM_PORTS; + swdev->ops = &ar8327_sw_ops; } else { swdev->name = "Atheros AR8216"; swdev->vlans = AR8216_NUM_VLANS; Index: target/linux/generic/files/drivers/net/phy/ar8216.h =================================================================== --- target/linux/generic/files/drivers/net/phy/ar8216.h (revision 34185) +++ target/linux/generic/files/drivers/net/phy/ar8216.h (working copy) @@ -303,9 +303,13 @@ #define AR8327_PORT_LOOKUP_STATE BITS(16, 3) #define AR8327_PORT_LOOKUP_STATE_S 16 #define AR8327_PORT_LOOKUP_LEARN BIT(20) +#define AR8327_PORT_LOOKUP_ING_MIRROR_EN BIT(25) #define AR8327_REG_PORT_PRIO(_i) (0x664 + (_i) * 0xc) +#define AR8327_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) +#define AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) + /* port speed */ enum { AR8216_PORT_SPEED_10M = 0, _______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel