Merge tag 'acpi-extra-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / net / dsa / mv88e6xxx / chip.c
index bf03504323374640a6057cabb05e83e60cefecac..19581d783d8ec7dc9ed9e5fd5a2891e8f2d22135 100644 (file)
@@ -677,31 +677,6 @@ static int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip,
        return err;
 }
 
-static bool mv88e6xxx_6097_family(struct mv88e6xxx_chip *chip)
-{
-       return chip->info->family == MV88E6XXX_FAMILY_6097;
-}
-
-static bool mv88e6xxx_6165_family(struct mv88e6xxx_chip *chip)
-{
-       return chip->info->family == MV88E6XXX_FAMILY_6165;
-}
-
-static bool mv88e6xxx_6341_family(struct mv88e6xxx_chip *chip)
-{
-       return chip->info->family == MV88E6XXX_FAMILY_6341;
-}
-
-static bool mv88e6xxx_6351_family(struct mv88e6xxx_chip *chip)
-{
-       return chip->info->family == MV88E6XXX_FAMILY_6351;
-}
-
-static bool mv88e6xxx_6352_family(struct mv88e6xxx_chip *chip)
-{
-       return chip->info->family == MV88E6XXX_FAMILY_6352;
-}
-
 static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
                                    int link, int speed, int duplex,
                                    phy_interface_t mode)
@@ -1263,153 +1238,30 @@ static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
                netdev_err(ds->ports[port].netdev, "failed to flush ATU\n");
 }
 
-static int _mv88e6xxx_vtu_stu_flush(struct mv88e6xxx_chip *chip)
+static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
 {
-       int ret;
-
-       ret = mv88e6xxx_g1_vtu_op_wait(chip);
-       if (ret < 0)
-               return ret;
+       if (!chip->info->max_vid)
+               return 0;
 
-       return mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_FLUSH_ALL);
+       return mv88e6xxx_g1_vtu_flush(chip);
 }
 
-static int _mv88e6xxx_vtu_stu_data_read(struct mv88e6xxx_chip *chip,
-                                       struct mv88e6xxx_vtu_entry *entry,
-                                       unsigned int nibble_offset)
+static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
+                                struct mv88e6xxx_vtu_entry *entry)
 {
-       u16 regs[3];
-       int i, err;
-
-       for (i = 0; i < 3; ++i) {
-               u16 *reg = &regs[i];
-
-               err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_DATA_0_3 + i, reg);
-               if (err)
-                       return err;
-       }
-
-       for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
-               unsigned int shift = (i % 4) * 4 + nibble_offset;
-               u16 reg = regs[i / 4];
-
-               entry->state[i] = (reg >> shift) & GLOBAL_VTU_STU_DATA_MASK;
-       }
-
-       return 0;
-}
+       if (!chip->info->ops->vtu_getnext)
+               return -EOPNOTSUPP;
 
-static int mv88e6xxx_vtu_data_read(struct mv88e6xxx_chip *chip,
-                                  struct mv88e6xxx_vtu_entry *entry)
-{
-       return _mv88e6xxx_vtu_stu_data_read(chip, entry, 0);
+       return chip->info->ops->vtu_getnext(chip, entry);
 }
 
-static int mv88e6xxx_stu_data_read(struct mv88e6xxx_chip *chip,
+static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
                                   struct mv88e6xxx_vtu_entry *entry)
 {
-       return _mv88e6xxx_vtu_stu_data_read(chip, entry, 2);
-}
-
-static int _mv88e6xxx_vtu_stu_data_write(struct mv88e6xxx_chip *chip,
-                                        struct mv88e6xxx_vtu_entry *entry,
-                                        unsigned int nibble_offset)
-{
-       u16 regs[3] = { 0 };
-       int i, err;
-
-       for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
-               unsigned int shift = (i % 4) * 4 + nibble_offset;
-               u8 data = entry->state[i];
-
-               regs[i / 4] |= (data & GLOBAL_VTU_STU_DATA_MASK) << shift;
-       }
-
-       for (i = 0; i < 3; ++i) {
-               u16 reg = regs[i];
-
-               err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_DATA_0_3 + i, reg);
-               if (err)
-                       return err;
-       }
-
-       return 0;
-}
-
-static int mv88e6xxx_vtu_data_write(struct mv88e6xxx_chip *chip,
-                                   struct mv88e6xxx_vtu_entry *entry)
-{
-       return _mv88e6xxx_vtu_stu_data_write(chip, entry, 0);
-}
-
-static int mv88e6xxx_stu_data_write(struct mv88e6xxx_chip *chip,
-                                   struct mv88e6xxx_vtu_entry *entry)
-{
-       return _mv88e6xxx_vtu_stu_data_write(chip, entry, 2);
-}
-
-static int _mv88e6xxx_vtu_vid_write(struct mv88e6xxx_chip *chip, u16 vid)
-{
-       return mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID,
-                                 vid & GLOBAL_VTU_VID_MASK);
-}
-
-static int _mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
-                                 struct mv88e6xxx_vtu_entry *entry)
-{
-       struct mv88e6xxx_vtu_entry next = { 0 };
-       u16 val;
-       int err;
-
-       err = mv88e6xxx_g1_vtu_op_wait(chip);
-       if (err)
-               return err;
-
-       err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_VTU_GET_NEXT);
-       if (err)
-               return err;
-
-       err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val);
-       if (err)
-               return err;
-
-       next.vid = val & GLOBAL_VTU_VID_MASK;
-       next.valid = !!(val & GLOBAL_VTU_VID_VALID);
-
-       if (next.valid) {
-               err = mv88e6xxx_vtu_data_read(chip, &next);
-               if (err)
-                       return err;
-
-               if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G1_VTU_FID)) {
-                       err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_FID, &val);
-                       if (err)
-                               return err;
-
-                       next.fid = val & GLOBAL_VTU_FID_MASK;
-               } else if (mv88e6xxx_num_databases(chip) == 256) {
-                       /* VTU DBNum[7:4] are located in VTU Operation 11:8, and
-                        * VTU DBNum[3:0] are located in VTU Operation 3:0
-                        */
-                       err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_OP, &val);
-                       if (err)
-                               return err;
-
-                       next.fid = (val & 0xf00) >> 4;
-                       next.fid |= val & 0xf;
-               }
-
-               if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_STU)) {
-                       err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_SID, &val);
-                       if (err)
-                               return err;
-
-                       next.sid = val & GLOBAL_VTU_SID_MASK;
-               }
-       }
+       if (!chip->info->ops->vtu_loadpurge)
+               return -EOPNOTSUPP;
 
-       *entry = next;
-       return 0;
+       return chip->info->ops->vtu_loadpurge(chip, entry);
 }
 
 static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
@@ -1417,7 +1269,9 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
                                    int (*cb)(struct switchdev_obj *obj))
 {
        struct mv88e6xxx_chip *chip = ds->priv;
-       struct mv88e6xxx_vtu_entry next;
+       struct mv88e6xxx_vtu_entry next = {
+               .vid = chip->info->max_vid,
+       };
        u16 pvid;
        int err;
 
@@ -1430,12 +1284,8 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
        if (err)
                goto unlock;
 
-       err = _mv88e6xxx_vtu_vid_write(chip, GLOBAL_VTU_VID_MASK);
-       if (err)
-               goto unlock;
-
        do {
-               err = _mv88e6xxx_vtu_getnext(chip, &next);
+               err = mv88e6xxx_vtu_getnext(chip, &next);
                if (err)
                        break;
 
@@ -1467,133 +1317,12 @@ unlock:
        return err;
 }
 
-static int _mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
-                                   struct mv88e6xxx_vtu_entry *entry)
-{
-       u16 op = GLOBAL_VTU_OP_VTU_LOAD_PURGE;
-       u16 reg = 0;
-       int err;
-
-       err = mv88e6xxx_g1_vtu_op_wait(chip);
-       if (err)
-               return err;
-
-       if (!entry->valid)
-               goto loadpurge;
-
-       /* Write port member tags */
-       err = mv88e6xxx_vtu_data_write(chip, entry);
-       if (err)
-               return err;
-
-       if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_STU)) {
-               reg = entry->sid & GLOBAL_VTU_SID_MASK;
-               err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, reg);
-               if (err)
-                       return err;
-       }
-
-       if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G1_VTU_FID)) {
-               reg = entry->fid & GLOBAL_VTU_FID_MASK;
-               err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_FID, reg);
-               if (err)
-                       return err;
-       } else if (mv88e6xxx_num_databases(chip) == 256) {
-               /* VTU DBNum[7:4] are located in VTU Operation 11:8, and
-                * VTU DBNum[3:0] are located in VTU Operation 3:0
-                */
-               op |= (entry->fid & 0xf0) << 8;
-               op |= entry->fid & 0xf;
-       }
-
-       reg = GLOBAL_VTU_VID_VALID;
-loadpurge:
-       reg |= entry->vid & GLOBAL_VTU_VID_MASK;
-       err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, reg);
-       if (err)
-               return err;
-
-       return mv88e6xxx_g1_vtu_op(chip, op);
-}
-
-static int _mv88e6xxx_stu_getnext(struct mv88e6xxx_chip *chip, u8 sid,
-                                 struct mv88e6xxx_vtu_entry *entry)
-{
-       struct mv88e6xxx_vtu_entry next = { 0 };
-       u16 val;
-       int err;
-
-       err = mv88e6xxx_g1_vtu_op_wait(chip);
-       if (err)
-               return err;
-
-       err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID,
-                                sid & GLOBAL_VTU_SID_MASK);
-       if (err)
-               return err;
-
-       err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_GET_NEXT);
-       if (err)
-               return err;
-
-       err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_SID, &val);
-       if (err)
-               return err;
-
-       next.sid = val & GLOBAL_VTU_SID_MASK;
-
-       err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val);
-       if (err)
-               return err;
-
-       next.valid = !!(val & GLOBAL_VTU_VID_VALID);
-
-       if (next.valid) {
-               err = mv88e6xxx_stu_data_read(chip, &next);
-               if (err)
-                       return err;
-       }
-
-       *entry = next;
-       return 0;
-}
-
-static int _mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip *chip,
-                                   struct mv88e6xxx_vtu_entry *entry)
-{
-       u16 reg = 0;
-       int err;
-
-       err = mv88e6xxx_g1_vtu_op_wait(chip);
-       if (err)
-               return err;
-
-       if (!entry->valid)
-               goto loadpurge;
-
-       /* Write port states */
-       err = mv88e6xxx_stu_data_write(chip, entry);
-       if (err)
-               return err;
-
-       reg = GLOBAL_VTU_VID_VALID;
-loadpurge:
-       err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, reg);
-       if (err)
-               return err;
-
-       reg = entry->sid & GLOBAL_VTU_SID_MASK;
-       err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, reg);
-       if (err)
-               return err;
-
-       return mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE);
-}
-
 static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
 {
        DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
-       struct mv88e6xxx_vtu_entry vlan;
+       struct mv88e6xxx_vtu_entry vlan = {
+               .vid = chip->info->max_vid,
+       };
        int i, err;
 
        bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
@@ -1608,12 +1337,8 @@ static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
        }
 
        /* Set every FID bit used by the VLAN entries */
-       err = _mv88e6xxx_vtu_vid_write(chip, GLOBAL_VTU_VID_MASK);
-       if (err)
-               return err;
-
        do {
-               err = _mv88e6xxx_vtu_getnext(chip, &vlan);
+               err = mv88e6xxx_vtu_getnext(chip, &vlan);
                if (err)
                        return err;
 
@@ -1634,90 +1359,52 @@ static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
        return mv88e6xxx_g1_atu_flush(chip, *fid, true);
 }
 
-static int _mv88e6xxx_vtu_new(struct mv88e6xxx_chip *chip, u16 vid,
-                             struct mv88e6xxx_vtu_entry *entry)
-{
-       struct dsa_switch *ds = chip->ds;
-       struct mv88e6xxx_vtu_entry vlan = {
-               .valid = true,
-               .vid = vid,
-       };
-       int i, err;
-
-       err = mv88e6xxx_atu_new(chip, &vlan.fid);
-       if (err)
-               return err;
-
-       /* exclude all ports except the CPU and DSA ports */
-       for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
-               vlan.member[i] = dsa_is_cpu_port(ds, i) ||
-                       dsa_is_dsa_port(ds, i)
-                       ? GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED
-                       : GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
-
-       if (mv88e6xxx_6097_family(chip) || mv88e6xxx_6165_family(chip) ||
-           mv88e6xxx_6351_family(chip) || mv88e6xxx_6352_family(chip) ||
-           mv88e6xxx_6341_family(chip)) {
-               struct mv88e6xxx_vtu_entry vstp;
-
-               /* Adding a VTU entry requires a valid STU entry. As VSTP is not
-                * implemented, only one STU entry is needed to cover all VTU
-                * entries. Thus, validate the SID 0.
-                */
-               vlan.sid = 0;
-               err = _mv88e6xxx_stu_getnext(chip, GLOBAL_VTU_SID_MASK, &vstp);
-               if (err)
-                       return err;
-
-               if (vstp.sid != vlan.sid || !vstp.valid) {
-                       memset(&vstp, 0, sizeof(vstp));
-                       vstp.valid = true;
-                       vstp.sid = vlan.sid;
-
-                       err = _mv88e6xxx_stu_loadpurge(chip, &vstp);
-                       if (err)
-                               return err;
-               }
-       }
-
-       *entry = vlan;
-       return 0;
-}
-
-static int _mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
-                             struct mv88e6xxx_vtu_entry *entry, bool creat)
+static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
+                            struct mv88e6xxx_vtu_entry *entry, bool new)
 {
        int err;
 
        if (!vid)
                return -EINVAL;
 
-       err = _mv88e6xxx_vtu_vid_write(chip, vid - 1);
-       if (err)
-               return err;
+       entry->vid = vid - 1;
+       entry->valid = false;
 
-       err = _mv88e6xxx_vtu_getnext(chip, entry);
+       err = mv88e6xxx_vtu_getnext(chip, entry);
        if (err)
                return err;
 
-       if (entry->vid != vid || !entry->valid) {
-               if (!creat)
-                       return -EOPNOTSUPP;
-               /* -ENOENT would've been more appropriate, but switchdev expects
-                * -EOPNOTSUPP to inform bridge about an eventual software VLAN.
-                */
+       if (entry->vid == vid && entry->valid)
+               return 0;
+
+       if (new) {
+               int i;
 
-               err = _mv88e6xxx_vtu_new(chip, vid, entry);
+               /* Initialize a fresh VLAN entry */
+               memset(entry, 0, sizeof(*entry));
+               entry->valid = true;
+               entry->vid = vid;
+
+               /* Include only CPU and DSA ports */
+               for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
+                       entry->member[i] = dsa_is_normal_port(chip->ds, i) ?
+                               GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER :
+                               GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED;
+
+               return mv88e6xxx_atu_new(chip, &entry->fid);
        }
 
-       return err;
+       /* switchdev expects -EOPNOTSUPP to honor software VLANs */
+       return -EOPNOTSUPP;
 }
 
 static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
                                        u16 vid_begin, u16 vid_end)
 {
        struct mv88e6xxx_chip *chip = ds->priv;
-       struct mv88e6xxx_vtu_entry vlan;
+       struct mv88e6xxx_vtu_entry vlan = {
+               .vid = vid_begin - 1,
+       };
        int i, err;
 
        if (!vid_begin)
@@ -1725,12 +1412,8 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
 
        mutex_lock(&chip->reg_lock);
 
-       err = _mv88e6xxx_vtu_vid_write(chip, vid_begin - 1);
-       if (err)
-               goto unlock;
-
        do {
-               err = _mv88e6xxx_vtu_getnext(chip, &vlan);
+               err = mv88e6xxx_vtu_getnext(chip, &vlan);
                if (err)
                        goto unlock;
 
@@ -1822,7 +1505,7 @@ static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
        struct mv88e6xxx_vtu_entry vlan;
        int err;
 
-       err = _mv88e6xxx_vtu_get(chip, vid, &vlan, true);
+       err = mv88e6xxx_vtu_get(chip, vid, &vlan, true);
        if (err)
                return err;
 
@@ -1830,7 +1513,7 @@ static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
                GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED :
                GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
 
-       return _mv88e6xxx_vtu_loadpurge(chip, &vlan);
+       return mv88e6xxx_vtu_loadpurge(chip, &vlan);
 }
 
 static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
@@ -1867,7 +1550,7 @@ static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
        struct mv88e6xxx_vtu_entry vlan;
        int i, err;
 
-       err = _mv88e6xxx_vtu_get(chip, vid, &vlan, false);
+       err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
        if (err)
                return err;
 
@@ -1889,7 +1572,7 @@ static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
                }
        }
 
-       err = _mv88e6xxx_vtu_loadpurge(chip, &vlan);
+       err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
        if (err)
                return err;
 
@@ -1942,7 +1625,7 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
        if (vid == 0)
                err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
        else
-               err = _mv88e6xxx_vtu_get(chip, vid, &vlan, false);
+               err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
        if (err)
                return err;
 
@@ -2087,12 +1770,8 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
                return err;
 
        /* Dump VLANs' Filtering Information Databases */
-       err = _mv88e6xxx_vtu_vid_write(chip, vlan.vid);
-       if (err)
-               return err;
-
        do {
-               err = _mv88e6xxx_vtu_getnext(chip, &vlan);
+               err = mv88e6xxx_vtu_getnext(chip, &vlan);
                if (err)
                        return err;
 
@@ -2599,11 +2278,6 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip)
        if (err)
                return err;
 
-       /* Clear all the VTU and STU entries */
-       err = _mv88e6xxx_vtu_stu_flush(chip);
-       if (err < 0)
-               return err;
-
        /* Configure the IP ToS mapping registers. */
        err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_0, 0x0000);
        if (err)
@@ -2684,6 +2358,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
                        goto unlock;
        }
 
+       err = mv88e6xxx_vtu_setup(chip);
+       if (err)
+               goto unlock;
+
        err = mv88e6xxx_pvt_setup(chip);
        if (err)
                goto unlock;
@@ -2938,6 +2616,8 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
        .ppu_enable = mv88e6185_g1_ppu_enable,
        .ppu_disable = mv88e6185_g1_ppu_disable,
        .reset = mv88e6185_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6095_ops = {
@@ -2959,6 +2639,8 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
        .ppu_enable = mv88e6185_g1_ppu_enable,
        .ppu_disable = mv88e6185_g1_ppu_disable,
        .reset = mv88e6185_g1_reset,
+       .vtu_getnext = mv88e6185_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6097_ops = {
@@ -2987,6 +2669,8 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6123_ops = {
@@ -3010,6 +2694,8 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6131_ops = {
@@ -3039,6 +2725,8 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
        .ppu_enable = mv88e6185_g1_ppu_enable,
        .ppu_disable = mv88e6185_g1_ppu_disable,
        .reset = mv88e6185_g1_reset,
+       .vtu_getnext = mv88e6185_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6141_ops = {
@@ -3070,6 +2758,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
        .watchdog_ops = &mv88e6390_watchdog_ops,
        .mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -3098,6 +2788,8 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6165_ops = {
@@ -3119,6 +2811,8 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6171_ops = {
@@ -3148,6 +2842,8 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6172_ops = {
@@ -3179,6 +2875,8 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -3208,6 +2906,8 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6176_ops = {
@@ -3239,6 +2939,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -3264,6 +2966,8 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
        .ppu_enable = mv88e6185_g1_ppu_enable,
        .ppu_disable = mv88e6185_g1_ppu_disable,
        .reset = mv88e6185_g1_reset,
+       .vtu_getnext = mv88e6185_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6190_ops = {
@@ -3294,6 +2998,8 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
        .watchdog_ops = &mv88e6390_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6390_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6190x_ops = {
@@ -3324,6 +3030,8 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
        .watchdog_ops = &mv88e6390_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6390_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6191_ops = {
@@ -3354,6 +3062,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
        .watchdog_ops = &mv88e6390_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6390_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -3385,6 +3095,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6290_ops = {
@@ -3416,6 +3128,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
        .watchdog_ops = &mv88e6390_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6390_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -3445,6 +3159,8 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
        .g1_set_egress_port = mv88e6095_g1_set_egress_port,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6185_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -3473,6 +3189,8 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
        .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
        .g1_set_egress_port = mv88e6095_g1_set_egress_port,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6185_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6341_ops = {
@@ -3504,6 +3222,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
        .watchdog_ops = &mv88e6390_watchdog_ops,
        .mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -3533,6 +3253,8 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6351_ops = {
@@ -3562,6 +3284,8 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -3593,6 +3317,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
        .watchdog_ops = &mv88e6097_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6352_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6390_ops = {
@@ -3626,6 +3352,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
        .watchdog_ops = &mv88e6390_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6390_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -3658,6 +3386,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
        .watchdog_ops = &mv88e6390_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
        .reset = mv88e6352_g1_reset,
+       .vtu_getnext = mv88e6390_g1_vtu_getnext,
+       .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
 };
 
 static const struct mv88e6xxx_info mv88e6xxx_table[] = {
@@ -3897,6 +3627,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
                .name = "Marvell 88E6190",
                .num_databases = 4096,
                .num_ports = 11,        /* 10 + Z80 */
+               .max_vid = 8191,
                .port_base_addr = 0x0,
                .global1_addr = 0x1b,
                .tag_protocol = DSA_TAG_PROTO_DSA,
@@ -3914,6 +3645,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
                .name = "Marvell 88E6190X",
                .num_databases = 4096,
                .num_ports = 11,        /* 10 + Z80 */
+               .max_vid = 8191,
                .port_base_addr = 0x0,
                .global1_addr = 0x1b,
                .age_time_coeff = 3750,
@@ -3931,6 +3663,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
                .name = "Marvell 88E6191",
                .num_databases = 4096,
                .num_ports = 11,        /* 10 + Z80 */
+               .max_vid = 8191,
                .port_base_addr = 0x0,
                .global1_addr = 0x1b,
                .age_time_coeff = 3750,
@@ -3966,6 +3699,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
                .name = "Marvell 88E6290",
                .num_databases = 4096,
                .num_ports = 11,        /* 10 + Z80 */
+               .max_vid = 8191,
                .port_base_addr = 0x0,
                .global1_addr = 0x1b,
                .age_time_coeff = 3750,
@@ -4088,6 +3822,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
                .name = "Marvell 88E6390",
                .num_databases = 4096,
                .num_ports = 11,        /* 10 + Z80 */
+               .max_vid = 8191,
                .port_base_addr = 0x0,
                .global1_addr = 0x1b,
                .age_time_coeff = 3750,
@@ -4104,6 +3839,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
                .name = "Marvell 88E6390X",
                .num_databases = 4096,
                .num_ports = 11,        /* 10 + Z80 */
+               .max_vid = 8191,
                .port_base_addr = 0x0,
                .global1_addr = 0x1b,
                .age_time_coeff = 3750,