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 <[email protected]>
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
[email protected]
https://lists.openwrt.org/mailman/listinfo/openwrt-devel