return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
 }
 
+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)
        .port_fdb_dump          = qca8k_port_fdb_dump,
        .port_mdb_add           = qca8k_port_mdb_add,
        .port_mdb_del           = qca8k_port_mdb_del,
+       .port_mirror_add        = qca8k_port_mirror_add,
+       .port_mirror_del        = qca8k_port_mirror_del,
        .port_vlan_filtering    = qca8k_port_vlan_filtering,
        .port_vlan_add          = qca8k_port_vlan_add,
        .port_vlan_del          = qca8k_port_vlan_del,
 
 #define   QCA8K_ATU_AGE_TIME(x)                                FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x))
 #define QCA8K_REG_GLOBAL_FW_CTRL0                      0x620
 #define   QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN            BIT(10)
+#define   QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM                GENMASK(7, 4)
 #define QCA8K_REG_GLOBAL_FW_CTRL1                      0x624
 #define   QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK           GENMASK(30, 24)
 #define   QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK             GENMASK(22, 16)
 #define   QCA8K_PORT_LOOKUP_STATE_LEARNING             QCA8K_PORT_LOOKUP_STATE(0x3)
 #define   QCA8K_PORT_LOOKUP_STATE_FORWARD              QCA8K_PORT_LOOKUP_STATE(0x4)
 #define   QCA8K_PORT_LOOKUP_LEARN                      BIT(20)
+#define   QCA8K_PORT_LOOKUP_ING_MIRROR_EN              BIT(25)
 
 #define QCA8K_REG_GLOBAL_FC_THRESH                     0x800
 #define   QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK           GENMASK(24, 16)
 struct qca8k_priv {
        u8 switch_id;
        u8 switch_revision;
+       u8 mirror_rx;
+       u8 mirror_tx;
        bool legacy_phy_port_mapping;
        struct qca8k_ports_config ports_config;
        struct regmap *regmap;