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

Reply via email to