Commit 742d37a8 authored by Christian Marangi's avatar Christian Marangi Committed by Jakub Kicinski

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: default avatarChristian Marangi <ansuelsmth@gmail.com>
Reviewed-by: default avatarVladimir Oltean <olteanv@gmail.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 2e5bd96e
...@@ -1687,99 +1687,6 @@ qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) ...@@ -1687,99 +1687,6 @@ qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data)
return ret; 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 static int
qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
......
...@@ -746,3 +746,94 @@ int qca8k_port_mdb_del(struct dsa_switch *ds, int port, ...@@ -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); 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);
}
...@@ -494,4 +494,11 @@ int qca8k_port_mdb_del(struct dsa_switch *ds, int port, ...@@ -494,4 +494,11 @@ int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb, const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db); 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 */ #endif /* __QCA8K_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment