This exposes hardware port mirroring in ag71xx driver (e.g. TL-WR841ND) via 
swconfig API.

Signed-off-by: Milan Krstic <[email protected]>
---
 .../net/ethernet/atheros/ag71xx/ag71xx_ar7240.c    | 154 +++++++++++++++++++++
 1 file changed, 154 insertions(+)

diff --git 
a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c 
b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c
index c5aed0d..da9c0dd 100644
--- 
a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c
+++ 
b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c
@@ -77,6 +77,7 @@
 
 #define AR7240_REG_CPU_PORT            0x78
 #define AR7240_MIRROR_PORT_S           4
+#define AR7240_MIRROR_PORT_M           BITM(4)
 #define AR7240_CPU_PORT_EN             BIT(8)
 
 #define AR7240_REG_MIB_FUNCTION0       0x80
@@ -1013,6 +1014,134 @@ ar7240_get_port_stats(struct switch_dev *dev, int port,
        return 0;
 }
 
+static int
+ar7240_set_mirror_monitor_port(struct switch_dev *dev,
+                              const struct switch_attr *attr,
+                              struct switch_val *val)
+{
+       struct ar7240sw *as = sw_to_ar7240(dev);
+       struct mii_bus *mii = as->mii_bus;
+
+       int port = val->value.i;
+
+       if (port > 15)
+               return -EINVAL;
+
+       ar7240sw_reg_rmw(mii, AR7240_REG_CPU_PORT,
+                       AR7240_MIRROR_PORT_M << AR7240_MIRROR_PORT_S,
+                       port << AR7240_MIRROR_PORT_S);
+
+       return 0;
+}
+
+static int
+ar7240_get_mirror_monitor_port(struct switch_dev *dev,
+                              const struct switch_attr *attr,
+                              struct switch_val *val)
+{
+       struct ar7240sw *as = sw_to_ar7240(dev);
+       struct mii_bus *mii = as->mii_bus;
+
+       u32 ret;
+
+       ret = ar7240sw_reg_read(mii, AR7240_REG_CPU_PORT);
+       val->value.i = (ret >> AR7240_MIRROR_PORT_S) & AR7240_MIRROR_PORT_M;
+
+       return 0;
+}
+
+static int
+ar7240_set_mirror_rx(struct switch_dev *dev, const struct switch_attr *attr,
+                    struct switch_val *val)
+{
+       struct ar7240sw *as = sw_to_ar7240(dev);
+       struct mii_bus *mii = as->mii_bus;
+
+       int port = val->port_vlan;
+
+       if (port >= dev->ports)
+               return -EINVAL;
+
+       if (val && val->value.i == 1)
+               ar7240sw_reg_set(mii, AR7240_REG_PORT_CTRL(port),
+                       AR7240_PORT_CTRL_MIRROR_RX);
+       else
+               ar7240sw_reg_rmw(mii, AR7240_REG_PORT_CTRL(port),
+                       AR7240_PORT_CTRL_MIRROR_RX, 0);
+
+       return 0;
+}
+
+static int
+ar7240_get_mirror_rx(struct switch_dev *dev, const struct switch_attr *attr,
+                    struct switch_val *val)
+{
+       struct ar7240sw *as = sw_to_ar7240(dev);
+       struct mii_bus *mii = as->mii_bus;
+
+       u32 ctrl;
+
+       int port = val->port_vlan;
+
+       if (port >= dev->ports)
+               return -EINVAL;
+
+       ctrl = ar7240sw_reg_read(mii, AR7240_REG_PORT_CTRL(port));
+
+       if ((ctrl & AR7240_PORT_CTRL_MIRROR_RX) == AR7240_PORT_CTRL_MIRROR_RX)
+               val->value.i = 1;
+       else
+               val->value.i = 0;
+
+       return 0;
+}
+
+static int
+ar7240_set_mirror_tx(struct switch_dev *dev, const struct switch_attr *attr,
+                    struct switch_val *val)
+{
+       struct ar7240sw *as = sw_to_ar7240(dev);
+       struct mii_bus *mii = as->mii_bus;
+
+       int port = val->port_vlan;
+
+       if (port >= dev->ports)
+               return -EINVAL;
+
+       if (val && val->value.i == 1)
+               ar7240sw_reg_set(mii, AR7240_REG_PORT_CTRL(port),
+                       AR7240_PORT_CTRL_MIRROR_TX);
+       else
+               ar7240sw_reg_rmw(mii, AR7240_REG_PORT_CTRL(port),
+                       AR7240_PORT_CTRL_MIRROR_TX, 0);
+
+       return 0;
+}
+
+static int
+ar7240_get_mirror_tx(struct switch_dev *dev, const struct switch_attr *attr,
+                    struct switch_val *val)
+{
+       struct ar7240sw *as = sw_to_ar7240(dev);
+       struct mii_bus *mii = as->mii_bus;
+
+       u32 ctrl;
+
+       int port = val->port_vlan;
+
+       if (port >= dev->ports)
+               return -EINVAL;
+
+       ctrl = ar7240sw_reg_read(mii, AR7240_REG_PORT_CTRL(port));
+
+       if ((ctrl & AR7240_PORT_CTRL_MIRROR_TX) == AR7240_PORT_CTRL_MIRROR_TX)
+               val->value.i = 1;
+       else
+               val->value.i = 0;
+
+       return 0;
+}
+
 static struct switch_attr ar7240_globals[] = {
        {
                .type = SWITCH_TYPE_INT,
@@ -1022,9 +1151,34 @@ static struct switch_attr ar7240_globals[] = {
                .get = ar7240_get_vlan,
                .max = 1
        },
+       {
+               .type = SWITCH_TYPE_INT,
+               .name = "mirror_monitor_port",
+               .description = "Mirror monitor port",
+               .set = ar7240_set_mirror_monitor_port,
+               .get = ar7240_get_mirror_monitor_port,
+               .max = 15
+       },
 };
 
 static struct switch_attr ar7240_port[] = {
+       {
+               .type = SWITCH_TYPE_INT,
+               .name = "enable_mirror_rx",
+               .description = "Enable mirroring of RX packets",
+               .set = ar7240_set_mirror_rx,
+               .get = ar7240_get_mirror_rx,
+               .max = 1
+       },
+       {
+
+               .type = SWITCH_TYPE_INT,
+               .name = "enable_mirror_tx",
+               .description = "Enable mirroring of TX packets",
+               .set = ar7240_set_mirror_tx,
+               .get = ar7240_get_mirror_tx,
+               .max = 1
+       },
 };
 
 static struct switch_attr ar7240_vlan[] = {
-- 
1.8.3.1
_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to