ag71xx: add support for port mirroring

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

Signed-off-by: Milan Krstić <milan.krstic@gmail.com>
This commit is contained in:
Milan Krstić 2017-04-26 21:52:44 +02:00 committed by Jo-Philipp Wich
parent d0f6a514b1
commit 4c1ce83548

View file

@ -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,33 @@ 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[] = {