return err;
 }
 
+static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
+                                    struct dsa_mall_mirror_tc_entry *mirror,
+                                    bool ingress)
+{
+       enum mv88e6xxx_egress_direction direction = ingress ?
+                                               MV88E6XXX_EGRESS_DIR_INGRESS :
+                                               MV88E6XXX_EGRESS_DIR_EGRESS;
+       struct mv88e6xxx_chip *chip = ds->priv;
+       bool other_mirrors = false;
+       int i;
+       int err;
+
+       if (!chip->info->ops->set_egress_port)
+               return -EOPNOTSUPP;
+
+       mutex_lock(&chip->reg_lock);
+       if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
+           mirror->to_local_port) {
+               for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
+                       other_mirrors |= ingress ?
+                                        chip->ports[i].mirror_ingress :
+                                        chip->ports[i].mirror_egress;
+
+               /* Can't change egress port when other mirror is active */
+               if (other_mirrors) {
+                       err = -EBUSY;
+                       goto out;
+               }
+
+               err = chip->info->ops->set_egress_port(chip,
+                                                      direction,
+                                                      mirror->to_local_port);
+               if (err)
+                       goto out;
+       }
+
+       err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
+out:
+       mutex_unlock(&chip->reg_lock);
+
+       return err;
+}
+
+static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
+                                     struct dsa_mall_mirror_tc_entry *mirror)
+{
+       enum mv88e6xxx_egress_direction direction = mirror->ingress ?
+                                               MV88E6XXX_EGRESS_DIR_INGRESS :
+                                               MV88E6XXX_EGRESS_DIR_EGRESS;
+       struct mv88e6xxx_chip *chip = ds->priv;
+       bool other_mirrors = false;
+       int i;
+
+       mutex_lock(&chip->reg_lock);
+       if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
+               dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);
+
+       for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
+               other_mirrors |= mirror->ingress ?
+                                chip->ports[i].mirror_ingress :
+                                chip->ports[i].mirror_egress;
+
+       /* Reset egress port when no other mirror is active */
+       if (!other_mirrors) {
+               if (chip->info->ops->set_egress_port(chip,
+                                                    direction,
+                                                    dsa_upstream_port(ds,
+                                                                      port)));
+                       dev_err(ds->dev, "failed to set egress port\n");
+       }
+
+       mutex_unlock(&chip->reg_lock);
+}
+
 static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
                                         bool unicast, bool multicast)
 {
        .port_mdb_prepare       = mv88e6xxx_port_mdb_prepare,
        .port_mdb_add           = mv88e6xxx_port_mdb_add,
        .port_mdb_del           = mv88e6xxx_port_mdb_del,
+       .port_mirror_add        = mv88e6xxx_port_mirror_add,
+       .port_mirror_del        = mv88e6xxx_port_mirror_del,
        .crosschip_bridge_join  = mv88e6xxx_crosschip_bridge_join,
        .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave,
        .port_hwtstamp_set      = mv88e6xxx_port_hwtstamp_set,
 
                                 enum mv88e6xxx_egress_direction direction,
                                 int port)
 {
+       int *dest_port_chip;
        u16 reg;
        int err;
 
 
        switch (direction) {
        case MV88E6XXX_EGRESS_DIR_INGRESS:
+               dest_port_chip = &chip->ingress_dest_port;
                reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK;
                reg |= port <<
                       __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK);
                break;
        case MV88E6XXX_EGRESS_DIR_EGRESS:
+               dest_port_chip = &chip->egress_dest_port;
                reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK;
                reg |= port <<
                       __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK);
                return -EINVAL;
        }
 
-       return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg);
+       err = mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg);
+       if (!err)
+               *dest_port_chip = port;
+
+       return err;
 }
 
 /* Older generations also call this the ARP destination. It has been
                                 enum mv88e6xxx_egress_direction direction,
                                 int port)
 {
+       int *dest_port_chip;
        u16 ptr;
        int err;
 
        switch (direction) {
        case MV88E6XXX_EGRESS_DIR_INGRESS:
+               dest_port_chip = &chip->ingress_dest_port;
                ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST;
                break;
        case MV88E6XXX_EGRESS_DIR_EGRESS:
+               dest_port_chip = &chip->egress_dest_port;
                ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST;
                break;
        default:
        }
 
        err = mv88e6390_g1_monitor_write(chip, ptr, port);
-       if (err)
-               return err;
+       if (!err)
+               *dest_port_chip = port;
 
-       return 0;
+       return err;
 }
 
 int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
 
        return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
 }
 
+int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
+                             enum mv88e6xxx_egress_direction direction,
+                             bool mirror)
+{
+       bool *mirror_port;
+       u16 reg;
+       u16 bit;
+       int err;
+
+       err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®);
+       if (err)
+               return err;
+
+       switch (direction) {
+       case MV88E6XXX_EGRESS_DIR_INGRESS:
+               bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR;
+               mirror_port = &chip->ports[port].mirror_ingress;
+               break;
+       case MV88E6XXX_EGRESS_DIR_EGRESS:
+               bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR;
+               mirror_port = &chip->ports[port].mirror_egress;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       reg &= ~bit;
+       if (mirror)
+               reg |= bit;
+
+       err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
+       if (!err)
+               *mirror_port = mirror;
+
+       return err;
+}
+
 int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
                                  u16 mode)
 {