net: dsa: qca8k: move port mirror functions to common code

The same port mirror functions are used by drivers based on qca8k family
switch. Move them to common code to make them accessible also by other
drivers.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Christian Marangi 2022-07-27 13:35:20 +02:00 committed by Jakub Kicinski
parent 2e5bd96eea
commit 742d37a84d
3 changed files with 98 additions and 93 deletions

View File

@ -1687,99 +1687,6 @@ exit:
return ret;
}
static int
qca8k_port_mirror_add(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror,
bool ingress, struct netlink_ext_ack *extack)
{
struct qca8k_priv *priv = ds->priv;
int monitor_port, ret;
u32 reg, val;
/* Check for existent entry */
if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
return -EEXIST;
ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val);
if (ret)
return ret;
/* QCA83xx can have only one port set to mirror mode.
* Check that the correct port is requested and return error otherwise.
* When no mirror port is set, the values is set to 0xF
*/
monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
if (monitor_port != 0xF && monitor_port != mirror->to_local_port)
return -EEXIST;
/* Set the monitor port */
val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM,
mirror->to_local_port);
ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
if (ret)
return ret;
if (ingress) {
reg = QCA8K_PORT_LOOKUP_CTRL(port);
val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
} else {
reg = QCA8K_REG_PORT_HOL_CTRL1(port);
val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
}
ret = regmap_update_bits(priv->regmap, reg, val, val);
if (ret)
return ret;
/* Track mirror port for tx and rx to decide when the
* mirror port has to be disabled.
*/
if (ingress)
priv->mirror_rx |= BIT(port);
else
priv->mirror_tx |= BIT(port);
return 0;
}
static void
qca8k_port_mirror_del(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror)
{
struct qca8k_priv *priv = ds->priv;
u32 reg, val;
int ret;
if (mirror->ingress) {
reg = QCA8K_PORT_LOOKUP_CTRL(port);
val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
} else {
reg = QCA8K_REG_PORT_HOL_CTRL1(port);
val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
}
ret = regmap_clear_bits(priv->regmap, reg, val);
if (ret)
goto err;
if (mirror->ingress)
priv->mirror_rx &= ~BIT(port);
else
priv->mirror_tx &= ~BIT(port);
/* No port set to send packet to mirror port. Disable mirror port */
if (!priv->mirror_rx && !priv->mirror_tx) {
val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF);
ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
if (ret)
goto err;
}
err:
dev_err(priv->dev, "Failed to del mirror port from %d", port);
}
static int
qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
struct netlink_ext_ack *extack)

View File

@ -746,3 +746,94 @@ int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
}
int qca8k_port_mirror_add(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror,
bool ingress, struct netlink_ext_ack *extack)
{
struct qca8k_priv *priv = ds->priv;
int monitor_port, ret;
u32 reg, val;
/* Check for existent entry */
if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
return -EEXIST;
ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val);
if (ret)
return ret;
/* QCA83xx can have only one port set to mirror mode.
* Check that the correct port is requested and return error otherwise.
* When no mirror port is set, the values is set to 0xF
*/
monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
if (monitor_port != 0xF && monitor_port != mirror->to_local_port)
return -EEXIST;
/* Set the monitor port */
val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM,
mirror->to_local_port);
ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
if (ret)
return ret;
if (ingress) {
reg = QCA8K_PORT_LOOKUP_CTRL(port);
val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
} else {
reg = QCA8K_REG_PORT_HOL_CTRL1(port);
val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
}
ret = regmap_update_bits(priv->regmap, reg, val, val);
if (ret)
return ret;
/* Track mirror port for tx and rx to decide when the
* mirror port has to be disabled.
*/
if (ingress)
priv->mirror_rx |= BIT(port);
else
priv->mirror_tx |= BIT(port);
return 0;
}
void qca8k_port_mirror_del(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror)
{
struct qca8k_priv *priv = ds->priv;
u32 reg, val;
int ret;
if (mirror->ingress) {
reg = QCA8K_PORT_LOOKUP_CTRL(port);
val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
} else {
reg = QCA8K_REG_PORT_HOL_CTRL1(port);
val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
}
ret = regmap_clear_bits(priv->regmap, reg, val);
if (ret)
goto err;
if (mirror->ingress)
priv->mirror_rx &= ~BIT(port);
else
priv->mirror_tx &= ~BIT(port);
/* No port set to send packet to mirror port. Disable mirror port */
if (!priv->mirror_rx && !priv->mirror_tx) {
val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF);
ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
if (ret)
goto err;
}
err:
dev_err(priv->dev, "Failed to del mirror port from %d", port);
}

View File

@ -494,4 +494,11 @@ int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db);
/* Common port mirror function */
int qca8k_port_mirror_add(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror,
bool ingress, struct netlink_ext_ack *extack);
void qca8k_port_mirror_del(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror);
#endif /* __QCA8K_H */