]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
net: dsa: mv88e6xxx: Export cross-chip PVT as devlink region
authorTobias Waldekranz <tobias@waldekranz.com>
Wed, 21 Apr 2021 12:04:54 +0000 (14:04 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 21 Apr 2021 17:25:09 +0000 (10:25 -0700)
Export the raw PVT data in a devlink region so that it can be
inspected from userspace and compared to the current bridge
configuration.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/mv88e6xxx/chip.h
drivers/net/dsa/mv88e6xxx/devlink.c
drivers/net/dsa/mv88e6xxx/global2.c
drivers/net/dsa/mv88e6xxx/global2.h

index 4f116f73a74be2098102bbd55ef6d6c442c72e10..675b1f3e43b7bfc16694b226341710d06ab7744d 100644 (file)
@@ -23,6 +23,8 @@
 /* PVT limits for 4-bit port and 5-bit switch */
 #define MV88E6XXX_MAX_PVT_SWITCHES     32
 #define MV88E6XXX_MAX_PVT_PORTS                16
+#define MV88E6XXX_MAX_PVT_ENTRIES      \
+       (MV88E6XXX_MAX_PVT_SWITCHES * MV88E6XXX_MAX_PVT_PORTS)
 
 #define MV88E6XXX_MAX_GPIO     16
 
@@ -266,6 +268,7 @@ enum mv88e6xxx_region_id {
        MV88E6XXX_REGION_GLOBAL2,
        MV88E6XXX_REGION_ATU,
        MV88E6XXX_REGION_VTU,
+       MV88E6XXX_REGION_PVT,
 
        _MV88E6XXX_REGION_MAX,
 };
index ada7a38d4d313971a51376f013d6359eea8088f0..0c0f5ea6680c3ccd33c4f7d1bd7a22a1185ea647 100644 (file)
@@ -503,6 +503,44 @@ static int mv88e6xxx_region_vtu_snapshot(struct devlink *dl,
        return 0;
 }
 
+static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl,
+                                        const struct devlink_region_ops *ops,
+                                        struct netlink_ext_ack *extack,
+                                        u8 **data)
+{
+       struct dsa_switch *ds = dsa_devlink_to_ds(dl);
+       struct mv88e6xxx_chip *chip = ds->priv;
+       int dev, port, err;
+       u16 *pvt, *cur;
+
+       pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL);
+       if (!pvt)
+               return -ENOMEM;
+
+       mv88e6xxx_reg_lock(chip);
+
+       cur = pvt;
+       for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; dev++) {
+               for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; port++) {
+                       err = mv88e6xxx_g2_pvt_read(chip, dev, port, cur);
+                       if (err)
+                               break;
+
+                       cur++;
+               }
+       }
+
+       mv88e6xxx_reg_unlock(chip);
+
+       if (err) {
+               kfree(pvt);
+               return err;
+       }
+
+       *data = (u8 *)pvt;
+       return 0;
+}
+
 static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port,
                                          const struct devlink_port_region_ops *ops,
                                          struct netlink_ext_ack *extack,
@@ -567,6 +605,12 @@ static struct devlink_region_ops mv88e6xxx_region_vtu_ops = {
        .destructor = kfree,
 };
 
+static struct devlink_region_ops mv88e6xxx_region_pvt_ops = {
+       .name = "pvt",
+       .snapshot = mv88e6xxx_region_pvt_snapshot,
+       .destructor = kfree,
+};
+
 static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
        .name = "port",
        .snapshot = mv88e6xxx_region_port_snapshot,
@@ -576,6 +620,8 @@ static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
 struct mv88e6xxx_region {
        struct devlink_region_ops *ops;
        u64 size;
+
+       bool (*cond)(struct mv88e6xxx_chip *chip);
 };
 
 static struct mv88e6xxx_region mv88e6xxx_regions[] = {
@@ -594,6 +640,11 @@ static struct mv88e6xxx_region mv88e6xxx_regions[] = {
                .ops = &mv88e6xxx_region_vtu_ops
          /* calculated at runtime */
        },
+       [MV88E6XXX_REGION_PVT] = {
+               .ops = &mv88e6xxx_region_pvt_ops,
+               .size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16),
+               .cond = mv88e6xxx_has_pvt,
+       },
 };
 
 static void
@@ -663,6 +714,7 @@ out:
 static int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds,
                                                  struct mv88e6xxx_chip *chip)
 {
+       bool (*cond)(struct mv88e6xxx_chip *chip);
        struct devlink_region_ops *ops;
        struct devlink_region *region;
        u64 size;
@@ -671,6 +723,10 @@ static int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds,
        for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) {
                ops = mv88e6xxx_regions[i].ops;
                size = mv88e6xxx_regions[i].size;
+               cond = mv88e6xxx_regions[i].cond;
+
+               if (cond && !cond(chip))
+                       continue;
 
                switch (i) {
                case MV88E6XXX_REGION_ATU:
index da8bac8813e14c32fceb806b1d14b95ce8398014..fa65ecd9cb85364cdbec3077303dd90fbe79f35c 100644 (file)
@@ -239,6 +239,23 @@ static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev,
        return mv88e6xxx_g2_pvt_op_wait(chip);
 }
 
+int mv88e6xxx_g2_pvt_read(struct mv88e6xxx_chip *chip, int src_dev,
+                         int src_port, u16 *data)
+{
+       int err;
+
+       err = mv88e6xxx_g2_pvt_op_wait(chip);
+       if (err)
+               return err;
+
+       err = mv88e6xxx_g2_pvt_op(chip, src_dev, src_port,
+                                 MV88E6XXX_G2_PVT_ADDR_OP_READ);
+       if (err)
+               return err;
+
+       return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_PVT_DATA, data);
+}
+
 int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev,
                           int src_port, u16 data)
 {
index 8f85c23ec9c7b8497e18bb8b3adf5d2a0cb1b298..f3e27573a3864d124d4c7757e2b9445946e512ac 100644 (file)
@@ -330,6 +330,8 @@ int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
 int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
                              struct ethtool_eeprom *eeprom, u8 *data);
 
+int mv88e6xxx_g2_pvt_read(struct mv88e6xxx_chip *chip, int src_dev,
+                         int src_port, u16 *data);
 int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev,
                           int src_port, u16 data);
 int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip);