mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-23 23:42:43 +00:00
233 lines
6.7 KiB
Diff
233 lines
6.7 KiB
Diff
|
From 742d37a84d3f7bb60d9b2d9ada9ad4e599f65ebf Mon Sep 17 00:00:00 2001
|
||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||
|
Date: Wed, 27 Jul 2022 13:35:20 +0200
|
||
|
Subject: [PATCH 11/14] 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>
|
||
|
---
|
||
|
drivers/net/dsa/qca/qca8k-8xxx.c | 93 ------------------------------
|
||
|
drivers/net/dsa/qca/qca8k-common.c | 91 +++++++++++++++++++++++++++++
|
||
|
drivers/net/dsa/qca/qca8k.h | 7 +++
|
||
|
3 files changed, 98 insertions(+), 93 deletions(-)
|
||
|
|
||
|
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||
|
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||
|
@@ -1838,99 +1838,6 @@ exit:
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
-qca8k_port_mirror_add(struct dsa_switch *ds, int port,
|
||
|
- struct dsa_mall_mirror_tc_entry *mirror,
|
||
|
- bool ingress)
|
||
|
-{
|
||
|
- 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)
|
||
|
{
|
||
|
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||
|
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||
|
@@ -741,3 +741,94 @@ int qca8k_port_mdb_del(struct dsa_switch
|
||
|
|
||
|
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 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);
|
||
|
+}
|
||
|
--- a/drivers/net/dsa/qca/qca8k.h
|
||
|
+++ b/drivers/net/dsa/qca/qca8k.h
|
||
|
@@ -480,4 +480,11 @@ int qca8k_port_mdb_add(struct dsa_switch
|
||
|
int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
|
||
|
const struct switchdev_obj_port_mdb *mdb);
|
||
|
|
||
|
+/* Common port mirror function */
|
||
|
+int qca8k_port_mirror_add(struct dsa_switch *ds, int port,
|
||
|
+ struct dsa_mall_mirror_tc_entry *mirror,
|
||
|
+ bool ingress);
|
||
|
+void qca8k_port_mirror_del(struct dsa_switch *ds, int port,
|
||
|
+ struct dsa_mall_mirror_tc_entry *mirror);
|
||
|
+
|
||
|
#endif /* __QCA8K_H */
|