]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
eth: fbnic: add RPC hardware statistics
authorSanman Pradhan <sanman.p211993@gmail.com>
Fri, 15 Nov 2024 01:53:44 +0000 (17:53 -0800)
committerJakub Kicinski <kuba@kernel.org>
Tue, 19 Nov 2024 02:43:41 +0000 (18:43 -0800)
Report Rx parser statistics via ethtool -S.

The parser stats are 32b, so we need to add refresh to the service
task to make sure we don't miss overflows.

Signed-off-by: Sanman Pradhan <sanman.p211993@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20241115015344.757567-6-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Documentation/networking/device_drivers/ethernet/meta/fbnic.rst
drivers/net/ethernet/meta/fbnic/fbnic_csr.h
drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.c
drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h
drivers/net/ethernet/meta/fbnic/fbnic_pci.c

index 14f2834d86d16affdc4542262b9114291553c04c..04e0595bb0a77e170bb35aff71f8057ae6badb74 100644 (file)
@@ -31,6 +31,19 @@ separate entry.
 Statistics
 ----------
 
+RPC (Rx parser)
+~~~~~~~~~~~~~~~
+
+ - ``rpc_unkn_etype``: frames containing unknown EtherType
+ - ``rpc_unkn_ext_hdr``: frames containing unknown IPv6 extension header
+ - ``rpc_ipv4_frag``: frames containing IPv4 fragment
+ - ``rpc_ipv6_frag``: frames containing IPv6 fragment
+ - ``rpc_ipv4_esp``: frames with IPv4 ESP encapsulation
+ - ``rpc_ipv6_esp``: frames with IPv6 ESP encapsulation
+ - ``rpc_tcp_opt_err``: frames which encountered TCP option parsing error
+ - ``rpc_out_of_hdr_err``: frames where header was larger than parsable region
+ - ``ovr_size_err``: oversized frames
+
 PCIe
 ~~~~
 
index dac9a4879e525ffcca0104410a01329081daf2b4..02bb81b3c50632a5ce8a8f8066c8d1931c438a2a 100644 (file)
@@ -638,6 +638,16 @@ enum {
                    FBNIC_RPC_RSS_KEY_DWORD_LEN * 32 - \
                    FBNIC_RPC_RSS_KEY_BIT_LEN)
 
+#define FBNIC_RPC_CNTR_TCP_OPT_ERR     0x0849e         /* 0x21278 */
+#define FBNIC_RPC_CNTR_UNKN_ETYPE      0x0849f         /* 0x2127c */
+#define FBNIC_RPC_CNTR_IPV4_FRAG       0x084a0         /* 0x21280 */
+#define FBNIC_RPC_CNTR_IPV6_FRAG       0x084a1         /* 0x21284 */
+#define FBNIC_RPC_CNTR_IPV4_ESP                0x084a2         /* 0x21288 */
+#define FBNIC_RPC_CNTR_IPV6_ESP                0x084a3         /* 0x2128c */
+#define FBNIC_RPC_CNTR_UNKN_EXT_HDR    0x084a4         /* 0x21290 */
+#define FBNIC_RPC_CNTR_OUT_OF_HDR_ERR  0x084a5         /* 0x21294 */
+#define FBNIC_RPC_CNTR_OVR_SIZE_ERR    0x084a6         /* 0x21298 */
+
 #define FBNIC_RPC_TCAM_MACDA_VALIDATE  0x0852d         /* 0x214b4 */
 #define FBNIC_CSR_END_RPC              0x0856b /* CSR section delimiter */
 
index 589cc7c2ee521b88a7af66bb475aaf60396d8e36..cc8ca94529ca10654f6b810ed847eeda7bffbd37 100644 (file)
@@ -9,6 +9,37 @@
 #include "fbnic_netdev.h"
 #include "fbnic_tlv.h"
 
+struct fbnic_stat {
+       u8 string[ETH_GSTRING_LEN];
+       unsigned int size;
+       unsigned int offset;
+};
+
+#define FBNIC_STAT_FIELDS(type, name, stat) { \
+       .string = name, \
+       .size = sizeof_field(struct type, stat), \
+       .offset = offsetof(struct type, stat), \
+}
+
+/* Hardware statistics not captured in rtnl_link_stats */
+#define FBNIC_HW_STAT(name, stat) \
+       FBNIC_STAT_FIELDS(fbnic_hw_stats, name, stat)
+
+static const struct fbnic_stat fbnic_gstrings_hw_stats[] = {
+       /* RPC */
+       FBNIC_HW_STAT("rpc_unkn_etype", rpc.unkn_etype),
+       FBNIC_HW_STAT("rpc_unkn_ext_hdr", rpc.unkn_ext_hdr),
+       FBNIC_HW_STAT("rpc_ipv4_frag", rpc.ipv4_frag),
+       FBNIC_HW_STAT("rpc_ipv6_frag", rpc.ipv6_frag),
+       FBNIC_HW_STAT("rpc_ipv4_esp", rpc.ipv4_esp),
+       FBNIC_HW_STAT("rpc_ipv6_esp", rpc.ipv6_esp),
+       FBNIC_HW_STAT("rpc_tcp_opt_err", rpc.tcp_opt_err),
+       FBNIC_HW_STAT("rpc_out_of_hdr_err", rpc.out_of_hdr_err),
+};
+
+#define FBNIC_HW_FIXED_STATS_LEN ARRAY_SIZE(fbnic_gstrings_hw_stats)
+#define FBNIC_HW_STATS_LEN     FBNIC_HW_FIXED_STATS_LEN
+
 static int
 fbnic_get_ts_info(struct net_device *netdev,
                  struct kernel_ethtool_ts_info *tsinfo)
@@ -54,6 +85,43 @@ static void fbnic_set_counter(u64 *stat, struct fbnic_stat_counter *counter)
                *stat = counter->value;
 }
 
+static void fbnic_get_strings(struct net_device *dev, u32 sset, u8 *data)
+{
+       int i;
+
+       switch (sset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < FBNIC_HW_STATS_LEN; i++)
+                       ethtool_puts(&data, fbnic_gstrings_hw_stats[i].string);
+               break;
+       }
+}
+
+static int fbnic_get_sset_count(struct net_device *dev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return FBNIC_HW_STATS_LEN;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void fbnic_get_ethtool_stats(struct net_device *dev,
+                                   struct ethtool_stats *stats, u64 *data)
+{
+       struct fbnic_net *fbn = netdev_priv(dev);
+       const struct fbnic_stat *stat;
+       int i;
+
+       fbnic_get_hw_stats(fbn->fbd);
+
+       for (i = 0; i < FBNIC_HW_STATS_LEN; i++) {
+               stat = &fbnic_gstrings_hw_stats[i];
+               data[i] = *(u64 *)((u8 *)&fbn->fbd->hw_stats + stat->offset);
+       }
+}
+
 static void
 fbnic_get_eth_mac_stats(struct net_device *netdev,
                        struct ethtool_eth_mac_stats *eth_mac_stats)
@@ -138,6 +206,9 @@ static const struct ethtool_ops fbnic_ethtool_ops = {
        .get_drvinfo            = fbnic_get_drvinfo,
        .get_regs_len           = fbnic_get_regs_len,
        .get_regs               = fbnic_get_regs,
+       .get_strings            = fbnic_get_strings,
+       .get_ethtool_stats      = fbnic_get_ethtool_stats,
+       .get_sset_count         = fbnic_get_sset_count,
        .get_ts_info            = fbnic_get_ts_info,
        .get_ts_stats           = fbnic_get_ts_stats,
        .get_eth_mac_stats      = fbnic_get_eth_mac_stats,
index c391f2155054e331fc32e2e9b82973a76d2b67c7..89ac6bc8c7fc3c3a6e944889946270bc6fd5afcf 100644 (file)
@@ -3,6 +3,27 @@
 
 #include "fbnic.h"
 
+static void fbnic_hw_stat_rst32(struct fbnic_dev *fbd, u32 reg,
+                               struct fbnic_stat_counter *stat)
+{
+       /* We do not touch the "value" field here.
+        * It gets zeroed out on fbd structure allocation.
+        * After that we want it to grow continuously
+        * through device resets and power state changes.
+        */
+       stat->u.old_reg_value_32 = rd32(fbd, reg);
+}
+
+static void fbnic_hw_stat_rd32(struct fbnic_dev *fbd, u32 reg,
+                              struct fbnic_stat_counter *stat)
+{
+       u32 new_reg_value;
+
+       new_reg_value = rd32(fbd, reg);
+       stat->value += new_reg_value - stat->u.old_reg_value_32;
+       stat->u.old_reg_value_32 = new_reg_value;
+}
+
 u64 fbnic_stat_rd64(struct fbnic_dev *fbd, u32 reg, u32 offset)
 {
        u32 prev_upper, upper, lower, diff;
@@ -49,6 +70,53 @@ static void fbnic_hw_stat_rd64(struct fbnic_dev *fbd, u32 reg, s32 offset,
        stat->u.old_reg_value_64 = new_reg_value;
 }
 
+static void fbnic_reset_rpc_stats(struct fbnic_dev *fbd,
+                                 struct fbnic_rpc_stats *rpc)
+{
+       fbnic_hw_stat_rst32(fbd,
+                           FBNIC_RPC_CNTR_UNKN_ETYPE,
+                           &rpc->unkn_etype);
+       fbnic_hw_stat_rst32(fbd,
+                           FBNIC_RPC_CNTR_UNKN_EXT_HDR,
+                           &rpc->unkn_ext_hdr);
+       fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV4_FRAG, &rpc->ipv4_frag);
+       fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV6_FRAG, &rpc->ipv6_frag);
+       fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV4_ESP, &rpc->ipv4_esp);
+       fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV6_ESP, &rpc->ipv6_esp);
+       fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_TCP_OPT_ERR, &rpc->tcp_opt_err);
+       fbnic_hw_stat_rst32(fbd,
+                           FBNIC_RPC_CNTR_OUT_OF_HDR_ERR,
+                           &rpc->out_of_hdr_err);
+       fbnic_hw_stat_rst32(fbd,
+                           FBNIC_RPC_CNTR_OVR_SIZE_ERR,
+                           &rpc->ovr_size_err);
+}
+
+static void fbnic_get_rpc_stats32(struct fbnic_dev *fbd,
+                                 struct fbnic_rpc_stats *rpc)
+{
+       fbnic_hw_stat_rd32(fbd,
+                          FBNIC_RPC_CNTR_UNKN_ETYPE,
+                          &rpc->unkn_etype);
+       fbnic_hw_stat_rd32(fbd,
+                          FBNIC_RPC_CNTR_UNKN_EXT_HDR,
+                          &rpc->unkn_ext_hdr);
+
+       fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV4_FRAG, &rpc->ipv4_frag);
+       fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV6_FRAG, &rpc->ipv6_frag);
+
+       fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV4_ESP, &rpc->ipv4_esp);
+       fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV6_ESP, &rpc->ipv6_esp);
+
+       fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_TCP_OPT_ERR, &rpc->tcp_opt_err);
+       fbnic_hw_stat_rd32(fbd,
+                          FBNIC_RPC_CNTR_OUT_OF_HDR_ERR,
+                          &rpc->out_of_hdr_err);
+       fbnic_hw_stat_rd32(fbd,
+                          FBNIC_RPC_CNTR_OVR_SIZE_ERR,
+                          &rpc->ovr_size_err);
+}
+
 static void fbnic_reset_pcie_stats_asic(struct fbnic_dev *fbd,
                                        struct fbnic_pcie_stats *pcie)
 {
@@ -135,10 +203,18 @@ static void fbnic_get_pcie_stats_asic64(struct fbnic_dev *fbd,
 
 void fbnic_reset_hw_stats(struct fbnic_dev *fbd)
 {
+       fbnic_reset_rpc_stats(fbd, &fbd->hw_stats.rpc);
        fbnic_reset_pcie_stats_asic(fbd, &fbd->hw_stats.pcie);
 }
 
+void fbnic_get_hw_stats32(struct fbnic_dev *fbd)
+{
+       fbnic_get_rpc_stats32(fbd, &fbd->hw_stats.rpc);
+}
+
 void fbnic_get_hw_stats(struct fbnic_dev *fbd)
 {
+       fbnic_get_hw_stats32(fbd);
+
        fbnic_get_pcie_stats_asic64(fbd, &fbd->hw_stats.pcie);
 }
index b152c6b1b4ab98d67ba1098630379ade3117c48e..78df56b8774569bd803e28467733be2e414b1922 100644 (file)
@@ -37,6 +37,12 @@ struct fbnic_mac_stats {
        struct fbnic_eth_mac_stats eth_mac;
 };
 
+struct fbnic_rpc_stats {
+       struct fbnic_stat_counter unkn_etype, unkn_ext_hdr;
+       struct fbnic_stat_counter ipv4_frag, ipv6_frag, ipv4_esp, ipv6_esp;
+       struct fbnic_stat_counter tcp_opt_err, out_of_hdr_err, ovr_size_err;
+};
+
 struct fbnic_pcie_stats {
        struct fbnic_stat_counter ob_rd_tlp, ob_rd_dword;
        struct fbnic_stat_counter ob_wr_tlp, ob_wr_dword;
@@ -49,12 +55,14 @@ struct fbnic_pcie_stats {
 
 struct fbnic_hw_stats {
        struct fbnic_mac_stats mac;
+       struct fbnic_rpc_stats rpc;
        struct fbnic_pcie_stats pcie;
 };
 
 u64 fbnic_stat_rd64(struct fbnic_dev *fbd, u32 reg, u32 offset);
 
 void fbnic_reset_hw_stats(struct fbnic_dev *fbd);
+void fbnic_get_hw_stats32(struct fbnic_dev *fbd);
 void fbnic_get_hw_stats(struct fbnic_dev *fbd);
 
 #endif /* _FBNIC_HW_STATS_H_ */
index f913a87c78a21b979cc66df4b2281cc7d5b912b2..e110c2ceafcf424b29cecfabea709dca68ddfe2d 100644 (file)
@@ -199,6 +199,8 @@ static void fbnic_service_task(struct work_struct *work)
 
        rtnl_lock();
 
+       fbnic_get_hw_stats32(fbd);
+
        fbnic_fw_check_heartbeat(fbd);
 
        fbnic_health_check(fbd);