net: ti: icssg-prueth: Add support for PA Stats
authorMD Danish Anwar <danishanwar@ti.com>
Thu, 22 Aug 2024 12:26:52 +0000 (17:56 +0530)
committerJakub Kicinski <kuba@kernel.org>
Mon, 26 Aug 2024 16:35:49 +0000 (09:35 -0700)
Add support for dumping PA stats registers via ethtool.
Firmware maintained stats are stored at PA Stats registers.
Also modify emac_get_strings() API to use ethtool_puts().

This commit also maintains consistency between miig_stats and pa_stats by
- renaming the array icssg_all_stats to icssg_all_miig_stats
- renaming the structure icssg_stats to icssg_miig_stats
- renaming ICSSG_STATS() to ICSSG_MIIG_STATS()
- changing order of stats related data structures and arrays so that data
  structures of a certain stats type is clubbed together.

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
Link: https://patch.msgid.link/20240822122652.1071801-3-danishanwar@ti.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/ti/icssg/icssg_ethtool.c
drivers/net/ethernet/ti/icssg/icssg_prueth.c
drivers/net/ethernet/ti/icssg/icssg_prueth.h
drivers/net/ethernet/ti/icssg/icssg_stats.c
drivers/net/ethernet/ti/icssg/icssg_stats.h

index 5688f054cec5f90edf11bee9ba18684d2b6e9298..5073ec1958541eecf24a2d55a9802e7405d1f5a4 100644 (file)
@@ -83,13 +83,11 @@ static void emac_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
 
        switch (stringset) {
        case ETH_SS_STATS:
-               for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) {
-                       if (!icssg_all_stats[i].standard_stats) {
-                               memcpy(p, icssg_all_stats[i].name,
-                                      ETH_GSTRING_LEN);
-                               p += ETH_GSTRING_LEN;
-                       }
-               }
+               for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++)
+                       if (!icssg_all_miig_stats[i].standard_stats)
+                               ethtool_puts(&p, icssg_all_miig_stats[i].name);
+               for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++)
+                       ethtool_puts(&p, icssg_all_pa_stats[i].name);
                break;
        default:
                break;
@@ -104,9 +102,12 @@ static void emac_get_ethtool_stats(struct net_device *ndev,
 
        emac_update_hardware_stats(emac);
 
-       for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++)
-               if (!icssg_all_stats[i].standard_stats)
+       for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++)
+               if (!icssg_all_miig_stats[i].standard_stats)
                        *(data++) = emac->stats[i];
+
+       for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++)
+               *(data++) = emac->pa_stats[i];
 }
 
 static int emac_get_ts_info(struct net_device *ndev,
index 53a3e44b99a203beaaa59856c79b8415aeae26b0..f623a0f603fc74c0a69a234b026cc0d1a08f8d38 100644 (file)
@@ -1182,6 +1182,12 @@ static int prueth_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
+       prueth->pa_stats = syscon_regmap_lookup_by_phandle(np, "ti,pa-stats");
+       if (IS_ERR(prueth->pa_stats)) {
+               dev_err(dev, "couldn't get ti,pa-stats syscon regmap\n");
+               return -ENODEV;
+       }
+
        if (eth0_node) {
                ret = prueth_get_cores(prueth, ICSS_SLICE0, false);
                if (ret)
index f678d656a3ed3a775293c6b157d2f3b797ab345e..786bd1ba34ab3fa7ce5a9020053265fbabdaa8a8 100644 (file)
 
 #define ICSSG_MAX_RFLOWS       8       /* per slice */
 
+#define ICSSG_NUM_PA_STATS     4
+#define ICSSG_NUM_MIIG_STATS   60
 /* Number of ICSSG related stats */
-#define ICSSG_NUM_STATS 60
+#define ICSSG_NUM_STATS (ICSSG_NUM_MIIG_STATS + ICSSG_NUM_PA_STATS)
 #define ICSSG_NUM_STANDARD_STATS 31
 #define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS)
 
@@ -190,7 +192,8 @@ struct prueth_emac {
        int port_vlan;
 
        struct delayed_work stats_work;
-       u64 stats[ICSSG_NUM_STATS];
+       u64 stats[ICSSG_NUM_MIIG_STATS];
+       u64 pa_stats[ICSSG_NUM_PA_STATS];
 
        /* RX IRQ Coalescing Related */
        struct hrtimer rx_hrtimer;
@@ -230,6 +233,7 @@ struct icssg_firmwares {
  * @registered_netdevs: list of registered netdevs
  * @miig_rt: regmap to mii_g_rt block
  * @mii_rt: regmap to mii_rt block
+ * @pa_stats: regmap to pa_stats block
  * @pru_id: ID for each of the PRUs
  * @pdev: pointer to ICSSG platform device
  * @pdata: pointer to platform data for ICSSG driver
@@ -263,6 +267,7 @@ struct prueth {
        struct net_device *registered_netdevs[PRUETH_NUM_MACS];
        struct regmap *miig_rt;
        struct regmap *mii_rt;
+       struct regmap *pa_stats;
 
        enum pruss_pru_id pru_id[PRUSS_NUM_PRUS];
        struct platform_device *pdev;
index 2fb150c13078b7ae56c00ea807221d861079a657..06a15c0b2accc57be5620c2b3b24291a703d7b5a 100644 (file)
@@ -11,6 +11,7 @@
 
 #define ICSSG_TX_PACKET_OFFSET 0xA0
 #define ICSSG_TX_BYTE_OFFSET   0xEC
+#define ICSSG_FW_STATS_BASE    0x0248
 
 static u32 stats_base[] = {    0x54c,  /* Slice 0 stats start */
                                0xb18,  /* Slice 1 stats start */
@@ -22,24 +23,31 @@ void emac_update_hardware_stats(struct prueth_emac *emac)
        int slice = prueth_emac_slice(emac);
        u32 base = stats_base[slice];
        u32 tx_pkt_cnt = 0;
-       u32 val;
+       u32 val, reg;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) {
+       for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++) {
                regmap_read(prueth->miig_rt,
-                           base + icssg_all_stats[i].offset,
+                           base + icssg_all_miig_stats[i].offset,
                            &val);
                regmap_write(prueth->miig_rt,
-                            base + icssg_all_stats[i].offset,
+                            base + icssg_all_miig_stats[i].offset,
                             val);
 
-               if (icssg_all_stats[i].offset == ICSSG_TX_PACKET_OFFSET)
+               if (icssg_all_miig_stats[i].offset == ICSSG_TX_PACKET_OFFSET)
                        tx_pkt_cnt = val;
 
                emac->stats[i] += val;
-               if (icssg_all_stats[i].offset == ICSSG_TX_BYTE_OFFSET)
+               if (icssg_all_miig_stats[i].offset == ICSSG_TX_BYTE_OFFSET)
                        emac->stats[i] -= tx_pkt_cnt * 8;
        }
+
+       for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++) {
+               reg = ICSSG_FW_STATS_BASE + icssg_all_pa_stats[i].offset *
+                     PRUETH_NUM_MACS + slice * sizeof(u32);
+               regmap_read(prueth->pa_stats, reg, &val);
+               emac->pa_stats[i] += val;
+       }
 }
 
 void icssg_stats_work_handler(struct work_struct *work)
@@ -57,9 +65,14 @@ int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) {
-               if (!strcmp(icssg_all_stats[i].name, stat_name))
-                       return emac->stats[icssg_all_stats[i].offset / sizeof(u32)];
+       for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++) {
+               if (!strcmp(icssg_all_miig_stats[i].name, stat_name))
+                       return emac->stats[icssg_all_miig_stats[i].offset / sizeof(u32)];
+       }
+
+       for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++) {
+               if (!strcmp(icssg_all_pa_stats[i].name, stat_name))
+                       return emac->pa_stats[icssg_all_pa_stats[i].offset / sizeof(u32)];
        }
 
        netdev_err(emac->ndev, "Invalid stats %s\n", stat_name);
index 999a4a91276c3ff211b13514bb3c1225659ae7b0..e88b919f532cdb545f773b9351828636ef9e2ac0 100644 (file)
@@ -77,82 +77,114 @@ struct miig_stats_regs {
        u32 tx_bytes;
 };
 
-#define ICSSG_STATS(field, stats_type)                 \
+#define ICSSG_MIIG_STATS(field, stats_type)                    \
 {                                                      \
        #field,                                         \
        offsetof(struct miig_stats_regs, field),        \
        stats_type                                      \
 }
 
-struct icssg_stats {
+struct icssg_miig_stats {
        char name[ETH_GSTRING_LEN];
        u32 offset;
        bool standard_stats;
 };
 
-static const struct icssg_stats icssg_all_stats[] = {
+static const struct icssg_miig_stats icssg_all_miig_stats[] = {
        /* Rx */
-       ICSSG_STATS(rx_packets, true),
-       ICSSG_STATS(rx_broadcast_frames, false),
-       ICSSG_STATS(rx_multicast_frames, true),
-       ICSSG_STATS(rx_crc_errors, true),
-       ICSSG_STATS(rx_mii_error_frames, false),
-       ICSSG_STATS(rx_odd_nibble_frames, false),
-       ICSSG_STATS(rx_frame_max_size, true),
-       ICSSG_STATS(rx_max_size_error_frames, false),
-       ICSSG_STATS(rx_frame_min_size, true),
-       ICSSG_STATS(rx_min_size_error_frames, false),
-       ICSSG_STATS(rx_over_errors, true),
-       ICSSG_STATS(rx_class0_hits, false),
-       ICSSG_STATS(rx_class1_hits, false),
-       ICSSG_STATS(rx_class2_hits, false),
-       ICSSG_STATS(rx_class3_hits, false),
-       ICSSG_STATS(rx_class4_hits, false),
-       ICSSG_STATS(rx_class5_hits, false),
-       ICSSG_STATS(rx_class6_hits, false),
-       ICSSG_STATS(rx_class7_hits, false),
-       ICSSG_STATS(rx_class8_hits, false),
-       ICSSG_STATS(rx_class9_hits, false),
-       ICSSG_STATS(rx_class10_hits, false),
-       ICSSG_STATS(rx_class11_hits, false),
-       ICSSG_STATS(rx_class12_hits, false),
-       ICSSG_STATS(rx_class13_hits, false),
-       ICSSG_STATS(rx_class14_hits, false),
-       ICSSG_STATS(rx_class15_hits, false),
-       ICSSG_STATS(rx_smd_frags, false),
-       ICSSG_STATS(rx_bucket1_size, true),
-       ICSSG_STATS(rx_bucket2_size, true),
-       ICSSG_STATS(rx_bucket3_size, true),
-       ICSSG_STATS(rx_bucket4_size, true),
-       ICSSG_STATS(rx_64B_frames, true),
-       ICSSG_STATS(rx_bucket1_frames, true),
-       ICSSG_STATS(rx_bucket2_frames, true),
-       ICSSG_STATS(rx_bucket3_frames, true),
-       ICSSG_STATS(rx_bucket4_frames, true),
-       ICSSG_STATS(rx_bucket5_frames, true),
-       ICSSG_STATS(rx_bytes, true),
-       ICSSG_STATS(rx_tx_total_bytes, false),
+       ICSSG_MIIG_STATS(rx_packets, true),
+       ICSSG_MIIG_STATS(rx_broadcast_frames, false),
+       ICSSG_MIIG_STATS(rx_multicast_frames, true),
+       ICSSG_MIIG_STATS(rx_crc_errors, true),
+       ICSSG_MIIG_STATS(rx_mii_error_frames, false),
+       ICSSG_MIIG_STATS(rx_odd_nibble_frames, false),
+       ICSSG_MIIG_STATS(rx_frame_max_size, true),
+       ICSSG_MIIG_STATS(rx_max_size_error_frames, false),
+       ICSSG_MIIG_STATS(rx_frame_min_size, true),
+       ICSSG_MIIG_STATS(rx_min_size_error_frames, false),
+       ICSSG_MIIG_STATS(rx_over_errors, true),
+       ICSSG_MIIG_STATS(rx_class0_hits, false),
+       ICSSG_MIIG_STATS(rx_class1_hits, false),
+       ICSSG_MIIG_STATS(rx_class2_hits, false),
+       ICSSG_MIIG_STATS(rx_class3_hits, false),
+       ICSSG_MIIG_STATS(rx_class4_hits, false),
+       ICSSG_MIIG_STATS(rx_class5_hits, false),
+       ICSSG_MIIG_STATS(rx_class6_hits, false),
+       ICSSG_MIIG_STATS(rx_class7_hits, false),
+       ICSSG_MIIG_STATS(rx_class8_hits, false),
+       ICSSG_MIIG_STATS(rx_class9_hits, false),
+       ICSSG_MIIG_STATS(rx_class10_hits, false),
+       ICSSG_MIIG_STATS(rx_class11_hits, false),
+       ICSSG_MIIG_STATS(rx_class12_hits, false),
+       ICSSG_MIIG_STATS(rx_class13_hits, false),
+       ICSSG_MIIG_STATS(rx_class14_hits, false),
+       ICSSG_MIIG_STATS(rx_class15_hits, false),
+       ICSSG_MIIG_STATS(rx_smd_frags, false),
+       ICSSG_MIIG_STATS(rx_bucket1_size, true),
+       ICSSG_MIIG_STATS(rx_bucket2_size, true),
+       ICSSG_MIIG_STATS(rx_bucket3_size, true),
+       ICSSG_MIIG_STATS(rx_bucket4_size, true),
+       ICSSG_MIIG_STATS(rx_64B_frames, true),
+       ICSSG_MIIG_STATS(rx_bucket1_frames, true),
+       ICSSG_MIIG_STATS(rx_bucket2_frames, true),
+       ICSSG_MIIG_STATS(rx_bucket3_frames, true),
+       ICSSG_MIIG_STATS(rx_bucket4_frames, true),
+       ICSSG_MIIG_STATS(rx_bucket5_frames, true),
+       ICSSG_MIIG_STATS(rx_bytes, true),
+       ICSSG_MIIG_STATS(rx_tx_total_bytes, false),
        /* Tx */
-       ICSSG_STATS(tx_packets, true),
-       ICSSG_STATS(tx_broadcast_frames, false),
-       ICSSG_STATS(tx_multicast_frames, false),
-       ICSSG_STATS(tx_odd_nibble_frames, false),
-       ICSSG_STATS(tx_underflow_errors, false),
-       ICSSG_STATS(tx_frame_max_size, true),
-       ICSSG_STATS(tx_max_size_error_frames, false),
-       ICSSG_STATS(tx_frame_min_size, true),
-       ICSSG_STATS(tx_min_size_error_frames, false),
-       ICSSG_STATS(tx_bucket1_size, true),
-       ICSSG_STATS(tx_bucket2_size, true),
-       ICSSG_STATS(tx_bucket3_size, true),
-       ICSSG_STATS(tx_bucket4_size, true),
-       ICSSG_STATS(tx_64B_frames, true),
-       ICSSG_STATS(tx_bucket1_frames, true),
-       ICSSG_STATS(tx_bucket2_frames, true),
-       ICSSG_STATS(tx_bucket3_frames, true),
-       ICSSG_STATS(tx_bucket4_frames, true),
-       ICSSG_STATS(tx_bucket5_frames, true),
-       ICSSG_STATS(tx_bytes, true),
+       ICSSG_MIIG_STATS(tx_packets, true),
+       ICSSG_MIIG_STATS(tx_broadcast_frames, false),
+       ICSSG_MIIG_STATS(tx_multicast_frames, false),
+       ICSSG_MIIG_STATS(tx_odd_nibble_frames, false),
+       ICSSG_MIIG_STATS(tx_underflow_errors, false),
+       ICSSG_MIIG_STATS(tx_frame_max_size, true),
+       ICSSG_MIIG_STATS(tx_max_size_error_frames, false),
+       ICSSG_MIIG_STATS(tx_frame_min_size, true),
+       ICSSG_MIIG_STATS(tx_min_size_error_frames, false),
+       ICSSG_MIIG_STATS(tx_bucket1_size, true),
+       ICSSG_MIIG_STATS(tx_bucket2_size, true),
+       ICSSG_MIIG_STATS(tx_bucket3_size, true),
+       ICSSG_MIIG_STATS(tx_bucket4_size, true),
+       ICSSG_MIIG_STATS(tx_64B_frames, true),
+       ICSSG_MIIG_STATS(tx_bucket1_frames, true),
+       ICSSG_MIIG_STATS(tx_bucket2_frames, true),
+       ICSSG_MIIG_STATS(tx_bucket3_frames, true),
+       ICSSG_MIIG_STATS(tx_bucket4_frames, true),
+       ICSSG_MIIG_STATS(tx_bucket5_frames, true),
+       ICSSG_MIIG_STATS(tx_bytes, true),
+};
+
+/**
+ * struct pa_stats_regs - ICSSG Firmware maintained PA Stats register
+ * @fw_rx_cnt: Number of valid packets sent by Rx PRU to Host on PSI
+ * @fw_tx_cnt: Number of valid packets copied by RTU0 to Tx queues
+ * @fw_tx_pre_overflow: Host Egress Q (Pre-emptible) Overflow Counter
+ * @fw_tx_exp_overflow: Host Egress Q (Express) Overflow Counter
+ */
+struct pa_stats_regs {
+       u32 fw_rx_cnt;
+       u32 fw_tx_cnt;
+       u32 fw_tx_pre_overflow;
+       u32 fw_tx_exp_overflow;
+};
+
+#define ICSSG_PA_STATS(field)                  \
+{                                              \
+       #field,                                 \
+       offsetof(struct pa_stats_regs, field),  \
+}
+
+struct icssg_pa_stats {
+       char name[ETH_GSTRING_LEN];
+       u32 offset;
+};
+
+static const struct icssg_pa_stats icssg_all_pa_stats[] = {
+       ICSSG_PA_STATS(fw_rx_cnt),
+       ICSSG_PA_STATS(fw_tx_cnt),
+       ICSSG_PA_STATS(fw_tx_pre_overflow),
+       ICSSG_PA_STATS(fw_tx_exp_overflow),
 };
 
 #endif /* __NET_TI_ICSSG_STATS_H */