generic: ar8216: add port mirroring
Tested on Buffalo WZR-600DHP with ar8316 switch. Commands used to mirror both RX and TX traffic from LAN port 1 to LAN port 4: $ swconfig dev switch0 set enable_mirror_rx 1 $ swconfig dev switch0 set enable_mirror_tx 1 $ swconfig dev switch0 set mirror_monitor_port 4 $ swconfig dev switch0 set mirror_source_port 1 Signed-off-by: Colin Leitner <colin.leitner@googlemail.com> Tested-by: Luka Perkov <luka@openwrt.org> SVN-Revision: 36713
This commit is contained in:
parent
90887b5fb3
commit
0998065a53
2 changed files with 318 additions and 0 deletions
|
@ -120,6 +120,12 @@ struct ar8xxx_priv {
|
||||||
u8 vlan_table[AR8X16_MAX_VLANS];
|
u8 vlan_table[AR8X16_MAX_VLANS];
|
||||||
u8 vlan_tagged;
|
u8 vlan_tagged;
|
||||||
u16 pvid[AR8X16_MAX_PORTS];
|
u16 pvid[AR8X16_MAX_PORTS];
|
||||||
|
|
||||||
|
/* mirroring */
|
||||||
|
bool mirror_rx;
|
||||||
|
bool mirror_tx;
|
||||||
|
int source_port;
|
||||||
|
int monitor_port;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MIB_DESC(_s , _o, _n) \
|
#define MIB_DESC(_s , _o, _n) \
|
||||||
|
@ -1457,6 +1463,98 @@ ar8xxx_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ar8327_set_mirror_regs(struct ar8xxx_priv *priv)
|
||||||
|
{
|
||||||
|
int port;
|
||||||
|
|
||||||
|
/* reset all mirror registers */
|
||||||
|
ar8xxx_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++) {
|
||||||
|
ar8xxx_rmw(priv, AR8327_REG_PORT_LOOKUP(port),
|
||||||
|
AR8327_PORT_LOOKUP_ING_MIRROR_EN,
|
||||||
|
0);
|
||||||
|
|
||||||
|
ar8xxx_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0,
|
||||||
|
AR8327_FWD_CTRL0_MIRROR_PORT,
|
||||||
|
(priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S));
|
||||||
|
|
||||||
|
if (priv->mirror_rx)
|
||||||
|
ar8xxx_rmw(priv, AR8327_REG_PORT_LOOKUP(priv->source_port),
|
||||||
|
AR8327_PORT_LOOKUP_ING_MIRROR_EN,
|
||||||
|
AR8327_PORT_LOOKUP_ING_MIRROR_EN);
|
||||||
|
|
||||||
|
if (priv->mirror_tx)
|
||||||
|
ar8xxx_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 void
|
||||||
|
ar8216_set_mirror_regs(struct ar8xxx_priv *priv)
|
||||||
|
{
|
||||||
|
int port;
|
||||||
|
|
||||||
|
/* reset all mirror registers */
|
||||||
|
ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT,
|
||||||
|
AR8216_GLOBAL_CPUPORT_MIRROR_PORT,
|
||||||
|
(0xF << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
|
||||||
|
for (port = 0; port < AR8216_NUM_PORTS; port++) {
|
||||||
|
ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
|
||||||
|
AR8216_PORT_CTRL_MIRROR_RX,
|
||||||
|
0);
|
||||||
|
|
||||||
|
ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
|
||||||
|
AR8216_PORT_CTRL_MIRROR_TX,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now enable mirroring if necessary */
|
||||||
|
if (priv->source_port >= AR8216_NUM_PORTS ||
|
||||||
|
priv->monitor_port >= AR8216_NUM_PORTS ||
|
||||||
|
priv->source_port == priv->monitor_port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT,
|
||||||
|
AR8216_GLOBAL_CPUPORT_MIRROR_PORT,
|
||||||
|
(priv->monitor_port << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
|
||||||
|
|
||||||
|
if (priv->mirror_rx)
|
||||||
|
ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(priv->source_port),
|
||||||
|
AR8216_PORT_CTRL_MIRROR_RX,
|
||||||
|
AR8216_PORT_CTRL_MIRROR_RX);
|
||||||
|
|
||||||
|
if (priv->mirror_tx)
|
||||||
|
ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(priv->source_port),
|
||||||
|
AR8216_PORT_CTRL_MIRROR_TX,
|
||||||
|
AR8216_PORT_CTRL_MIRROR_TX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ar8xxx_set_mirror_regs(struct ar8xxx_priv *priv)
|
||||||
|
{
|
||||||
|
if (chip_is_ar8327(priv)) {
|
||||||
|
ar8327_set_mirror_regs(priv);
|
||||||
|
} else {
|
||||||
|
ar8216_set_mirror_regs(priv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ar8xxx_sw_hw_apply(struct switch_dev *dev)
|
ar8xxx_sw_hw_apply(struct switch_dev *dev)
|
||||||
{
|
{
|
||||||
|
@ -1520,6 +1618,9 @@ ar8xxx_sw_hw_apply(struct switch_dev *dev)
|
||||||
priv->chip->setup_port(priv, i, egress, ingress, portmask[i],
|
priv->chip->setup_port(priv, i, egress, ingress, portmask[i],
|
||||||
pvid);
|
pvid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ar8xxx_set_mirror_regs(priv);
|
||||||
|
|
||||||
mutex_unlock(&priv->reg_mutex);
|
mutex_unlock(&priv->reg_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1541,7 +1642,13 @@ ar8xxx_sw_reset_switch(struct switch_dev *dev)
|
||||||
for (i = 0; i < dev->ports; i++)
|
for (i = 0; i < dev->ports; i++)
|
||||||
priv->chip->init_port(priv, i);
|
priv->chip->init_port(priv, i);
|
||||||
|
|
||||||
|
priv->mirror_rx = false;
|
||||||
|
priv->mirror_tx = false;
|
||||||
|
priv->source_port = 0;
|
||||||
|
priv->monitor_port = 0;
|
||||||
|
|
||||||
priv->chip->init_globals(priv);
|
priv->chip->init_globals(priv);
|
||||||
|
|
||||||
mutex_unlock(&priv->reg_mutex);
|
mutex_unlock(&priv->reg_mutex);
|
||||||
|
|
||||||
return ar8xxx_sw_hw_apply(dev);
|
return ar8xxx_sw_hw_apply(dev);
|
||||||
|
@ -1575,6 +1682,106 @@ unlock:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev,
|
||||||
|
const struct switch_attr *attr,
|
||||||
|
struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
|
||||||
|
|
||||||
|
mutex_lock(&priv->reg_mutex);
|
||||||
|
priv->mirror_rx = !!val->value.i;
|
||||||
|
ar8xxx_set_mirror_regs(priv);
|
||||||
|
mutex_unlock(&priv->reg_mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev,
|
||||||
|
const struct switch_attr *attr,
|
||||||
|
struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
|
||||||
|
val->value.i = priv->mirror_rx;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev,
|
||||||
|
const struct switch_attr *attr,
|
||||||
|
struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
|
||||||
|
|
||||||
|
mutex_lock(&priv->reg_mutex);
|
||||||
|
priv->mirror_tx = !!val->value.i;
|
||||||
|
ar8xxx_set_mirror_regs(priv);
|
||||||
|
mutex_unlock(&priv->reg_mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev,
|
||||||
|
const struct switch_attr *attr,
|
||||||
|
struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
|
||||||
|
val->value.i = priv->mirror_tx;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev,
|
||||||
|
const struct switch_attr *attr,
|
||||||
|
struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
|
||||||
|
|
||||||
|
mutex_lock(&priv->reg_mutex);
|
||||||
|
priv->monitor_port = val->value.i;
|
||||||
|
ar8xxx_set_mirror_regs(priv);
|
||||||
|
mutex_unlock(&priv->reg_mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev,
|
||||||
|
const struct switch_attr *attr,
|
||||||
|
struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
|
||||||
|
val->value.i = priv->monitor_port;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev,
|
||||||
|
const struct switch_attr *attr,
|
||||||
|
struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
|
||||||
|
|
||||||
|
mutex_lock(&priv->reg_mutex);
|
||||||
|
priv->source_port = val->value.i;
|
||||||
|
ar8xxx_set_mirror_regs(priv);
|
||||||
|
mutex_unlock(&priv->reg_mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev,
|
||||||
|
const struct switch_attr *attr,
|
||||||
|
struct switch_val *val)
|
||||||
|
{
|
||||||
|
struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
|
||||||
|
val->value.i = priv->source_port;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
|
ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
|
||||||
const struct switch_attr *attr,
|
const struct switch_attr *attr,
|
||||||
|
@ -1668,7 +1875,87 @@ static struct switch_attr ar8xxx_sw_attr_globals[] = {
|
||||||
.description = "Reset all MIB counters",
|
.description = "Reset all MIB counters",
|
||||||
.set = ar8xxx_sw_set_reset_mibs,
|
.set = ar8xxx_sw_set_reset_mibs,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.type = SWITCH_TYPE_INT,
|
||||||
|
.name = "enable_mirror_rx",
|
||||||
|
.description = "Enable mirroring of RX packets",
|
||||||
|
.set = ar8xxx_sw_set_mirror_rx_enable,
|
||||||
|
.get = ar8xxx_sw_get_mirror_rx_enable,
|
||||||
|
.max = 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = SWITCH_TYPE_INT,
|
||||||
|
.name = "enable_mirror_tx",
|
||||||
|
.description = "Enable mirroring of TX packets",
|
||||||
|
.set = ar8xxx_sw_set_mirror_tx_enable,
|
||||||
|
.get = ar8xxx_sw_get_mirror_tx_enable,
|
||||||
|
.max = 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = SWITCH_TYPE_INT,
|
||||||
|
.name = "mirror_monitor_port",
|
||||||
|
.description = "Mirror monitor port",
|
||||||
|
.set = ar8xxx_sw_set_mirror_monitor_port,
|
||||||
|
.get = ar8xxx_sw_get_mirror_monitor_port,
|
||||||
|
.max = AR8216_NUM_PORTS - 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = SWITCH_TYPE_INT,
|
||||||
|
.name = "mirror_source_port",
|
||||||
|
.description = "Mirror source port",
|
||||||
|
.set = ar8xxx_sw_set_mirror_source_port,
|
||||||
|
.get = ar8xxx_sw_get_mirror_source_port,
|
||||||
|
.max = AR8216_NUM_PORTS - 1
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct switch_attr ar8327_sw_attr_globals[] = {
|
||||||
|
{
|
||||||
|
.type = SWITCH_TYPE_INT,
|
||||||
|
.name = "enable_vlan",
|
||||||
|
.description = "Enable VLAN mode",
|
||||||
|
.set = ar8xxx_sw_set_vlan,
|
||||||
|
.get = ar8xxx_sw_get_vlan,
|
||||||
|
.max = 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = SWITCH_TYPE_NOVAL,
|
||||||
|
.name = "reset_mibs",
|
||||||
|
.description = "Reset all MIB counters",
|
||||||
|
.set = ar8xxx_sw_set_reset_mibs,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = SWITCH_TYPE_INT,
|
||||||
|
.name = "enable_mirror_rx",
|
||||||
|
.description = "Enable mirroring of RX packets",
|
||||||
|
.set = ar8xxx_sw_set_mirror_rx_enable,
|
||||||
|
.get = ar8xxx_sw_get_mirror_rx_enable,
|
||||||
|
.max = 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = SWITCH_TYPE_INT,
|
||||||
|
.name = "enable_mirror_tx",
|
||||||
|
.description = "Enable mirroring of TX packets",
|
||||||
|
.set = ar8xxx_sw_set_mirror_tx_enable,
|
||||||
|
.get = ar8xxx_sw_get_mirror_tx_enable,
|
||||||
|
.max = 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = SWITCH_TYPE_INT,
|
||||||
|
.name = "mirror_monitor_port",
|
||||||
|
.description = "Mirror monitor port",
|
||||||
|
.set = ar8xxx_sw_set_mirror_monitor_port,
|
||||||
|
.get = ar8xxx_sw_get_mirror_monitor_port,
|
||||||
|
.max = AR8327_NUM_PORTS - 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = SWITCH_TYPE_INT,
|
||||||
|
.name = "mirror_source_port",
|
||||||
|
.description = "Mirror source port",
|
||||||
|
.set = ar8xxx_sw_set_mirror_source_port,
|
||||||
|
.get = ar8xxx_sw_get_mirror_source_port,
|
||||||
|
.max = AR8327_NUM_PORTS - 1
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct switch_attr ar8xxx_sw_attr_port[] = {
|
static struct switch_attr ar8xxx_sw_attr_port[] = {
|
||||||
|
@ -1720,6 +2007,28 @@ static const struct switch_dev_ops ar8xxx_sw_ops = {
|
||||||
.get_port_link = ar8xxx_sw_get_port_link,
|
.get_port_link = ar8xxx_sw_get_port_link,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct switch_dev_ops ar8327_sw_ops = {
|
||||||
|
.attr_global = {
|
||||||
|
.attr = ar8327_sw_attr_globals,
|
||||||
|
.n_attr = ARRAY_SIZE(ar8327_sw_attr_globals),
|
||||||
|
},
|
||||||
|
.attr_port = {
|
||||||
|
.attr = ar8xxx_sw_attr_port,
|
||||||
|
.n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port),
|
||||||
|
},
|
||||||
|
.attr_vlan = {
|
||||||
|
.attr = ar8xxx_sw_attr_vlan,
|
||||||
|
.n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan),
|
||||||
|
},
|
||||||
|
.get_port_pvid = ar8xxx_sw_get_pvid,
|
||||||
|
.set_port_pvid = ar8xxx_sw_set_pvid,
|
||||||
|
.get_vlan_ports = ar8xxx_sw_get_ports,
|
||||||
|
.set_vlan_ports = ar8xxx_sw_set_ports,
|
||||||
|
.apply_config = ar8xxx_sw_hw_apply,
|
||||||
|
.reset_switch = ar8xxx_sw_reset_switch,
|
||||||
|
.get_port_link = ar8xxx_sw_get_port_link,
|
||||||
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ar8xxx_id_chip(struct ar8xxx_priv *priv)
|
ar8xxx_id_chip(struct ar8xxx_priv *priv)
|
||||||
{
|
{
|
||||||
|
@ -1900,6 +2209,7 @@ ar8xxx_probe_switch(struct ar8xxx_priv *priv)
|
||||||
swdev->name = "Atheros AR8327";
|
swdev->name = "Atheros AR8327";
|
||||||
swdev->vlans = AR8X16_MAX_VLANS;
|
swdev->vlans = AR8X16_MAX_VLANS;
|
||||||
swdev->ports = AR8327_NUM_PORTS;
|
swdev->ports = AR8327_NUM_PORTS;
|
||||||
|
swdev->ops = &ar8327_sw_ops;
|
||||||
} else {
|
} else {
|
||||||
swdev->name = "Atheros AR8216";
|
swdev->name = "Atheros AR8216";
|
||||||
swdev->vlans = AR8216_NUM_VLANS;
|
swdev->vlans = AR8216_NUM_VLANS;
|
||||||
|
|
|
@ -105,6 +105,10 @@
|
||||||
#define AR8216_MIB_FUNC_CAPTURE 0x3
|
#define AR8216_MIB_FUNC_CAPTURE 0x3
|
||||||
#define AR8236_MIB_EN BIT(30)
|
#define AR8236_MIB_EN BIT(30)
|
||||||
|
|
||||||
|
#define AR8216_REG_GLOBAL_CPUPORT 0x0078
|
||||||
|
#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT BITS(4, 4)
|
||||||
|
#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S 4
|
||||||
|
|
||||||
#define AR8216_PORT_OFFSET(_i) (0x0100 * (_i + 1))
|
#define AR8216_PORT_OFFSET(_i) (0x0100 * (_i + 1))
|
||||||
#define AR8216_REG_PORT_STATUS(_i) (AR8216_PORT_OFFSET(_i) + 0x0000)
|
#define AR8216_REG_PORT_STATUS(_i) (AR8216_PORT_OFFSET(_i) + 0x0000)
|
||||||
#define AR8216_PORT_STATUS_SPEED BITS(0,2)
|
#define AR8216_PORT_STATUS_SPEED BITS(0,2)
|
||||||
|
@ -433,9 +437,13 @@
|
||||||
#define AR8327_PORT_LOOKUP_STATE BITS(16, 3)
|
#define AR8327_PORT_LOOKUP_STATE BITS(16, 3)
|
||||||
#define AR8327_PORT_LOOKUP_STATE_S 16
|
#define AR8327_PORT_LOOKUP_STATE_S 16
|
||||||
#define AR8327_PORT_LOOKUP_LEARN BIT(20)
|
#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_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)
|
||||||
|
|
||||||
#define AR8327_REG_PORT_STATS_BASE(_i) (0x1000 + (_i) * 0x100)
|
#define AR8327_REG_PORT_STATS_BASE(_i) (0x1000 + (_i) * 0x100)
|
||||||
|
|
||||||
/* port speed */
|
/* port speed */
|
||||||
|
|
Loading…
Reference in a new issue