This commit defines a dsa_vlan_dump_cb_t callback, similar to the FDB
dump callback and partly reverts commit a0b6b8c9fa3c ("net: dsa: Remove
support for vlan dump from DSA's drivers") to restore the DSA drivers
VLAN dump operations.

Signed-off-by: Vivien Didelot <vivien.dide...@savoirfairelinux.com>
Reviewed-by: Florian Fainelli <f.faine...@gmail.com>
Reviewed-by: Andrew Lunn <and...@lunn.ch>
---
 drivers/net/dsa/b53/b53_common.c       | 41 ++++++++++++++++++++++++++++
 drivers/net/dsa/b53/b53_priv.h         |  2 ++
 drivers/net/dsa/bcm_sf2.c              |  1 +
 drivers/net/dsa/dsa_loop.c             | 38 ++++++++++++++++++++++++++
 drivers/net/dsa/microchip/ksz_common.c | 41 ++++++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx/chip.c       | 49 ++++++++++++++++++++++++++++++++++
 include/net/dsa.h                      |  5 ++++
 7 files changed, 177 insertions(+)

diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 274f3679f33d..be0c5fa8bd9b 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1053,6 +1053,46 @@ int b53_vlan_del(struct dsa_switch *ds, int port,
 }
 EXPORT_SYMBOL(b53_vlan_del);
 
+int b53_vlan_dump(struct dsa_switch *ds, int port, dsa_vlan_dump_cb_t *cb,
+                 void *data)
+{
+       struct b53_device *dev = ds->priv;
+       u16 vid, vid_start = 0, pvid;
+       struct b53_vlan *vl;
+       bool untagged;
+       int err = 0;
+
+       if (is5325(dev) || is5365(dev))
+               vid_start = 1;
+
+       b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), &pvid);
+
+       /* Use our software cache for dumps, since we do not have any HW
+        * operation returning only the used/valid VLANs
+        */
+       for (vid = vid_start; vid < dev->num_vlans; vid++) {
+               vl = &dev->vlans[vid];
+
+               if (!vl->valid)
+                       continue;
+
+               if (!(vl->members & BIT(port)))
+                       continue;
+
+               untagged = false;
+
+               if (vl->untag & BIT(port))
+                       untagged = true;
+
+               err = cb(vid, pvid == vid, untagged, data);
+               if (err)
+                       break;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(b53_vlan_dump);
+
 /* Address Resolution Logic routines */
 static int b53_arl_op_wait(struct b53_device *dev)
 {
@@ -1503,6 +1543,7 @@ static const struct dsa_switch_ops b53_switch_ops = {
        .port_vlan_prepare      = b53_vlan_prepare,
        .port_vlan_add          = b53_vlan_add,
        .port_vlan_del          = b53_vlan_del,
+       .port_vlan_dump         = b53_vlan_dump,
        .port_fdb_dump          = b53_fdb_dump,
        .port_fdb_add           = b53_fdb_add,
        .port_fdb_del           = b53_fdb_del,
diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h
index 01bd8cbe9a3f..2b3e59d80fdb 100644
--- a/drivers/net/dsa/b53/b53_priv.h
+++ b/drivers/net/dsa/b53/b53_priv.h
@@ -393,6 +393,8 @@ void b53_vlan_add(struct dsa_switch *ds, int port,
                  struct switchdev_trans *trans);
 int b53_vlan_del(struct dsa_switch *ds, int port,
                 const struct switchdev_obj_port_vlan *vlan);
+int b53_vlan_dump(struct dsa_switch *ds, int port, dsa_vlan_dump_cb_t *cb,
+                 void *data);
 int b53_fdb_add(struct dsa_switch *ds, int port,
                const unsigned char *addr, u16 vid);
 int b53_fdb_del(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index bbcb4053e04e..1907b27297c3 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -1021,6 +1021,7 @@ static const struct dsa_switch_ops bcm_sf2_ops = {
        .port_vlan_prepare      = b53_vlan_prepare,
        .port_vlan_add          = b53_vlan_add,
        .port_vlan_del          = b53_vlan_del,
+       .port_vlan_dump         = b53_vlan_dump,
        .port_fdb_dump          = b53_fdb_dump,
        .port_fdb_add           = b53_fdb_add,
        .port_fdb_del           = b53_fdb_del,
diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c
index 7819a9fe8321..0407533f725f 100644
--- a/drivers/net/dsa/dsa_loop.c
+++ b/drivers/net/dsa/dsa_loop.c
@@ -257,6 +257,43 @@ static int dsa_loop_port_vlan_del(struct dsa_switch *ds, 
int port,
        return 0;
 }
 
+static int dsa_loop_port_vlan_dump(struct dsa_switch *ds, int port,
+                                  dsa_vlan_dump_cb_t *cb, void *data)
+{
+       struct dsa_loop_priv *ps = ds->priv;
+       struct mii_bus *bus = ps->bus;
+       struct dsa_loop_vlan *vl;
+       u16 vid, vid_start = 0;
+       bool pvid, untagged;
+       int err = 0;
+
+       dev_dbg(ds->dev, "%s\n", __func__);
+
+       /* Just do a sleeping operation to make lockdep checks effective */
+       mdiobus_read(bus, ps->port_base + port, MII_BMSR);
+
+       for (vid = vid_start; vid < DSA_LOOP_VLANS; vid++) {
+               vl = &ps->vlans[vid];
+
+               if (!(vl->members & BIT(port)))
+                       continue;
+
+               untagged = false;
+               pvid = false;
+
+               if (vl->untagged & BIT(port))
+                       untagged = true;
+               if (ps->pvid == vid)
+                       pvid = true;
+
+               err = cb(vid, pvid, untagged, data);
+               if (err)
+                       break;
+       }
+
+       return err;
+}
+
 static const struct dsa_switch_ops dsa_loop_driver = {
        .get_tag_protocol       = dsa_loop_get_protocol,
        .setup                  = dsa_loop_setup,
@@ -273,6 +310,7 @@ static const struct dsa_switch_ops dsa_loop_driver = {
        .port_vlan_prepare      = dsa_loop_port_vlan_prepare,
        .port_vlan_add          = dsa_loop_port_vlan_add,
        .port_vlan_del          = dsa_loop_port_vlan_del,
+       .port_vlan_dump         = dsa_loop_port_vlan_dump,
 };
 
 static int dsa_loop_drv_probe(struct mdio_device *mdiodev)
diff --git a/drivers/net/dsa/microchip/ksz_common.c 
b/drivers/net/dsa/microchip/ksz_common.c
index 56cd6d365352..52c7849acc3c 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -638,6 +638,46 @@ static int ksz_port_vlan_del(struct dsa_switch *ds, int 
port,
        return 0;
 }
 
+static int ksz_port_vlan_dump(struct dsa_switch *ds, int port,
+                             dsa_vlan_dump_cb_t *cb, void *data)
+{
+       struct ksz_device *dev = ds->priv;
+       struct vlan_table *vlan_cache;
+       bool pvid, untagged;
+       u16 val;
+       int vid;
+       int err = 0;
+
+       mutex_lock(&dev->vlan_mutex);
+
+       /* use dev->vlan_cache due to lack of searching valid vlan entry */
+       for (vid = 0; vid < dev->num_vlans; vid++) {
+               vlan_cache = &dev->vlan_cache[vid];
+
+               if (!(vlan_cache->table[0] & VLAN_VALID))
+                       continue;
+
+               untagged = false;
+               pvid = false;
+
+               if (vlan_cache->table[2] & BIT(port)) {
+                       if (vlan_cache->table[1] & BIT(port))
+                               untagged = true;
+                       ksz_pread16(dev, port, REG_PORT_DEFAULT_VID, &val);
+                       if (vid == (val & 0xFFFFF))
+                               pvid = true;
+
+                       err = cb(vid, pvid, untagged, data);
+                       if (err)
+                               break;
+               }
+       }
+
+       mutex_unlock(&dev->vlan_mutex);
+
+       return err;
+}
+
 struct alu_struct {
        /* entry 1 */
        u8      is_static:1;
@@ -1068,6 +1108,7 @@ static const struct dsa_switch_ops ksz_switch_ops = {
        .port_vlan_prepare      = ksz_port_vlan_prepare,
        .port_vlan_add          = ksz_port_vlan_add,
        .port_vlan_del          = ksz_port_vlan_del,
+       .port_vlan_dump         = ksz_port_vlan_dump,
        .port_fdb_dump          = ksz_port_fdb_dump,
        .port_fdb_add           = ksz_port_fdb_add,
        .port_fdb_del           = ksz_port_fdb_del,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index c66204423641..3717ae098d58 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1011,6 +1011,54 @@ static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip 
*chip,
        return chip->info->ops->vtu_loadpurge(chip, entry);
 }
 
+static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
+                                   dsa_vlan_dump_cb_t *cb, void *data)
+{
+       struct mv88e6xxx_chip *chip = ds->priv;
+       struct mv88e6xxx_vtu_entry next = {
+               .vid = chip->info->max_vid,
+       };
+       bool untagged;
+       u16 pvid;
+       int err;
+
+       if (!chip->info->max_vid)
+               return -EOPNOTSUPP;
+
+       mutex_lock(&chip->reg_lock);
+
+       err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
+       if (err)
+               goto unlock;
+
+       do {
+               err = mv88e6xxx_vtu_getnext(chip, &next);
+               if (err)
+                       break;
+
+               if (!next.valid)
+                       break;
+
+               if (next.member[port] ==
+                   MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
+                       continue;
+
+               untagged = false;
+               if (next.member[port] ==
+                   MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED)
+                       untagged = true;
+
+               err = cb(next.vid, next.vid == pvid, untagged, data);
+               if (err)
+                       break;
+       } while (next.vid < chip->info->max_vid);
+
+unlock:
+       mutex_unlock(&chip->reg_lock);
+
+       return err;
+}
+
 static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
 {
        DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
@@ -3820,6 +3868,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = 
{
        .port_vlan_prepare      = mv88e6xxx_port_vlan_prepare,
        .port_vlan_add          = mv88e6xxx_port_vlan_add,
        .port_vlan_del          = mv88e6xxx_port_vlan_del,
+       .port_vlan_dump         = mv88e6xxx_port_vlan_dump,
        .port_fdb_add           = mv88e6xxx_port_fdb_add,
        .port_fdb_del           = mv88e6xxx_port_fdb_del,
        .port_fdb_dump          = mv88e6xxx_port_fdb_dump,
diff --git a/include/net/dsa.h b/include/net/dsa.h
index c0d1b6c47a50..b4994c58547f 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -315,6 +315,8 @@ static inline u8 dsa_upstream_port(struct dsa_switch *ds)
 /* FDB (and MDB) dump callback */
 typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid,
                              bool is_static, void *data);
+typedef int dsa_vlan_dump_cb_t(u16 vid, bool pvid, bool untagged, void *data);
+
 struct dsa_switch_ops {
        /*
         * Legacy probing.
@@ -421,6 +423,9 @@ struct dsa_switch_ops {
                                 struct switchdev_trans *trans);
        int     (*port_vlan_del)(struct dsa_switch *ds, int port,
                                 const struct switchdev_obj_port_vlan *vlan);
+       int     (*port_vlan_dump)(struct dsa_switch *ds, int port,
+                                 dsa_vlan_dump_cb_t *cb, void *data);
+
        /*
         * Forwarding database
         */
-- 
2.14.1

Reply via email to