eth: fbnic: Add support to fetch group stats
authorMohsin Bashir <mohsin.bashr@gmail.com>
Mon, 2 Sep 2024 17:39:07 +0000 (10:39 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 4 Sep 2024 12:13:12 +0000 (13:13 +0100)
Add support for group stats for mac. The fbnic_set_counter help preserve
the default values for counters which are not touched by the driver.

The 'reset' flag in 'get_eth_mac_stats' allows to choose between
resetting the counter to recent most value or fetching the aggregated
values of the counter.

The 'fbnic_stat_rd64' read 64b stats counters in an atomic fashion using
read-read-read approach. This allows to isolate cases where counter is
moving too fast making accuracy of the counter questionable.

Command: ethtool -S eth0 --groups eth-mac
Example Output:
eth-mac-FramesTransmittedOK: 421644
eth-mac-FramesReceivedOK: 3849708
eth-mac-FrameCheckSequenceErrors: 0
eth-mac-AlignmentErrors: 0
eth-mac-OctetsTransmittedOK: 64799060
eth-mac-FramesLostDueToIntMACXmitError: 0
eth-mac-OctetsReceivedOK: 5134513531
eth-mac-FramesLostDueToIntMACRcvError: 0
eth-mac-MulticastFramesXmittedOK: 568
eth-mac-BroadcastFramesXmittedOK: 454
eth-mac-MulticastFramesReceivedOK: 276106
eth-mac-BroadcastFramesReceivedOK: 26119
eth-mac-FrameTooLongErrors: 0

Signed-off-by: Mohsin Bashir <mohsin.bashr@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/meta/fbnic/Makefile
drivers/net/ethernet/meta/fbnic/fbnic.h
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 [new file with mode: 0644]
drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h [new file with mode: 0644]
drivers/net/ethernet/meta/fbnic/fbnic_mac.c
drivers/net/ethernet/meta/fbnic/fbnic_mac.h

index 37cfc34..ed4533a 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_FBNIC) += fbnic.o
 fbnic-y := fbnic_devlink.o \
           fbnic_ethtool.o \
           fbnic_fw.o \
+          fbnic_hw_stats.o \
           fbnic_irq.o \
           fbnic_mac.o \
           fbnic_netdev.o \
index 28d970f..0f9e8d7 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "fbnic_csr.h"
 #include "fbnic_fw.h"
+#include "fbnic_hw_stats.h"
 #include "fbnic_mac.h"
 #include "fbnic_rpc.h"
 
@@ -47,6 +48,9 @@ struct fbnic_dev {
 
        /* Number of TCQs/RCQs available on hardware */
        u16 max_num_queues;
+
+       /* Local copy of hardware statistics */
+       struct fbnic_hw_stats hw_stats;
 };
 
 /* Reserve entry 0 in the MSI-X "others" array until we have filled all
index a64360d..21db509 100644 (file)
@@ -660,6 +660,43 @@ enum {
 #define FBNIC_SIG_PCS_INTR_MASK                0x11816         /* 0x46058 */
 #define FBNIC_CSR_END_SIG              0x1184e /* CSR section delimiter */
 
+#define FBNIC_CSR_START_MAC_STAT       0x11a00
+#define FBNIC_MAC_STAT_RX_BYTE_COUNT_L 0x11a08         /* 0x46820 */
+#define FBNIC_MAC_STAT_RX_BYTE_COUNT_H 0x11a09         /* 0x46824 */
+#define FBNIC_MAC_STAT_RX_ALIGN_ERROR_L \
+                                       0x11a0a         /* 0x46828 */
+#define FBNIC_MAC_STAT_RX_ALIGN_ERROR_H \
+                                       0x11a0b         /* 0x4682c */
+#define FBNIC_MAC_STAT_RX_TOOLONG_L    0x11a0e         /* 0x46838 */
+#define FBNIC_MAC_STAT_RX_TOOLONG_H    0x11a0f         /* 0x4683c */
+#define FBNIC_MAC_STAT_RX_RECEIVED_OK_L        \
+                                       0x11a12         /* 0x46848 */
+#define FBNIC_MAC_STAT_RX_RECEIVED_OK_H        \
+                                       0x11a13         /* 0x4684c */
+#define FBNIC_MAC_STAT_RX_PACKET_BAD_FCS_L \
+                                       0x11a14         /* 0x46850 */
+#define FBNIC_MAC_STAT_RX_PACKET_BAD_FCS_H \
+                                       0x11a15         /* 0x46854 */
+#define FBNIC_MAC_STAT_RX_IFINERRORS_L 0x11a18         /* 0x46860 */
+#define FBNIC_MAC_STAT_RX_IFINERRORS_H 0x11a19         /* 0x46864 */
+#define FBNIC_MAC_STAT_RX_MULTICAST_L  0x11a1c         /* 0x46870 */
+#define FBNIC_MAC_STAT_RX_MULTICAST_H  0x11a1d         /* 0x46874 */
+#define FBNIC_MAC_STAT_RX_BROADCAST_L  0x11a1e         /* 0x46878 */
+#define FBNIC_MAC_STAT_RX_BROADCAST_H  0x11a1f         /* 0x4687c */
+#define FBNIC_MAC_STAT_TX_BYTE_COUNT_L 0x11a3e         /* 0x468f8 */
+#define FBNIC_MAC_STAT_TX_BYTE_COUNT_H 0x11a3f         /* 0x468fc */
+#define FBNIC_MAC_STAT_TX_TRANSMITTED_OK_L \
+                                       0x11a42         /* 0x46908 */
+#define FBNIC_MAC_STAT_TX_TRANSMITTED_OK_H \
+                                       0x11a43         /* 0x4690c */
+#define FBNIC_MAC_STAT_TX_IFOUTERRORS_L \
+                                       0x11a46         /* 0x46918 */
+#define FBNIC_MAC_STAT_TX_IFOUTERRORS_H \
+                                       0x11a47         /* 0x4691c */
+#define FBNIC_MAC_STAT_TX_MULTICAST_L  0x11a4a         /* 0x46928 */
+#define FBNIC_MAC_STAT_TX_MULTICAST_H  0x11a4b         /* 0x4692c */
+#define FBNIC_MAC_STAT_TX_BROADCAST_L  0x11a4c         /* 0x46930 */
+#define FBNIC_MAC_STAT_TX_BROADCAST_H  0x11a4d         /* 0x46934 */
 /* PUL User Registers */
 #define FBNIC_CSR_START_PUL_USER       0x31000 /* CSR section delimiter */
 #define FBNIC_PUL_OB_TLP_HDR_AW_CFG    0x3103d         /* 0xc40f4 */
index 7064dfc..5d980e1 100644 (file)
@@ -16,8 +16,57 @@ fbnic_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
                                    sizeof(drvinfo->fw_version));
 }
 
+static void fbnic_set_counter(u64 *stat, struct fbnic_stat_counter *counter)
+{
+       if (counter->reported)
+               *stat = counter->value;
+}
+
+static void
+fbnic_get_eth_mac_stats(struct net_device *netdev,
+                       struct ethtool_eth_mac_stats *eth_mac_stats)
+{
+       struct fbnic_net *fbn = netdev_priv(netdev);
+       struct fbnic_mac_stats *mac_stats;
+       struct fbnic_dev *fbd = fbn->fbd;
+       const struct fbnic_mac *mac;
+
+       mac_stats = &fbd->hw_stats.mac;
+       mac = fbd->mac;
+
+       mac->get_eth_mac_stats(fbd, false, &mac_stats->eth_mac);
+
+       fbnic_set_counter(&eth_mac_stats->FramesTransmittedOK,
+                         &mac_stats->eth_mac.FramesTransmittedOK);
+       fbnic_set_counter(&eth_mac_stats->FramesReceivedOK,
+                         &mac_stats->eth_mac.FramesReceivedOK);
+       fbnic_set_counter(&eth_mac_stats->FrameCheckSequenceErrors,
+                         &mac_stats->eth_mac.FrameCheckSequenceErrors);
+       fbnic_set_counter(&eth_mac_stats->AlignmentErrors,
+                         &mac_stats->eth_mac.AlignmentErrors);
+       fbnic_set_counter(&eth_mac_stats->OctetsTransmittedOK,
+                         &mac_stats->eth_mac.OctetsTransmittedOK);
+       fbnic_set_counter(&eth_mac_stats->FramesLostDueToIntMACXmitError,
+                         &mac_stats->eth_mac.FramesLostDueToIntMACXmitError);
+       fbnic_set_counter(&eth_mac_stats->OctetsReceivedOK,
+                         &mac_stats->eth_mac.OctetsReceivedOK);
+       fbnic_set_counter(&eth_mac_stats->FramesLostDueToIntMACRcvError,
+                         &mac_stats->eth_mac.FramesLostDueToIntMACRcvError);
+       fbnic_set_counter(&eth_mac_stats->MulticastFramesXmittedOK,
+                         &mac_stats->eth_mac.MulticastFramesXmittedOK);
+       fbnic_set_counter(&eth_mac_stats->BroadcastFramesXmittedOK,
+                         &mac_stats->eth_mac.BroadcastFramesXmittedOK);
+       fbnic_set_counter(&eth_mac_stats->MulticastFramesReceivedOK,
+                         &mac_stats->eth_mac.MulticastFramesReceivedOK);
+       fbnic_set_counter(&eth_mac_stats->BroadcastFramesReceivedOK,
+                         &mac_stats->eth_mac.BroadcastFramesReceivedOK);
+       fbnic_set_counter(&eth_mac_stats->FrameTooLongErrors,
+                         &mac_stats->eth_mac.FrameTooLongErrors);
+}
+
 static const struct ethtool_ops fbnic_ethtool_ops = {
        .get_drvinfo            = fbnic_get_drvinfo,
+       .get_eth_mac_stats      = fbnic_get_eth_mac_stats,
 };
 
 void fbnic_set_ethtool_ops(struct net_device *dev)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.c b/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.c
new file mode 100644 (file)
index 0000000..a0acc76
--- /dev/null
@@ -0,0 +1,27 @@
+#include "fbnic.h"
+
+u64 fbnic_stat_rd64(struct fbnic_dev *fbd, u32 reg, u32 offset)
+{
+       u32 prev_upper, upper, lower, diff;
+
+       prev_upper = rd32(fbd, reg + offset);
+       lower = rd32(fbd, reg);
+       upper = rd32(fbd, reg + offset);
+
+       diff = upper - prev_upper;
+       if (!diff)
+               return ((u64)upper << 32) | lower;
+
+       if (diff > 1)
+               dev_warn_once(fbd->dev,
+                             "Stats inconsistent, upper 32b of %#010x updating too quickly\n",
+                             reg * 4);
+
+       /* Return only the upper bits as we cannot guarantee
+        * the accuracy of the lower bits. We will add them in
+        * when the counter slows down enough that we can get
+        * a snapshot with both upper values being the same
+        * between reads.
+        */
+       return ((u64)upper << 32);
+}
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h b/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h
new file mode 100644 (file)
index 0000000..3034890
--- /dev/null
@@ -0,0 +1,40 @@
+#include <linux/ethtool.h>
+
+#include "fbnic_csr.h"
+
+struct fbnic_stat_counter {
+       u64 value;
+       union {
+               u32 old_reg_value_32;
+               u64 old_reg_value_64;
+       } u;
+       bool reported;
+};
+
+struct fbnic_eth_mac_stats {
+       struct fbnic_stat_counter FramesTransmittedOK;
+       struct fbnic_stat_counter FramesReceivedOK;
+       struct fbnic_stat_counter FrameCheckSequenceErrors;
+       struct fbnic_stat_counter AlignmentErrors;
+       struct fbnic_stat_counter OctetsTransmittedOK;
+       struct fbnic_stat_counter FramesLostDueToIntMACXmitError;
+       struct fbnic_stat_counter OctetsReceivedOK;
+       struct fbnic_stat_counter FramesLostDueToIntMACRcvError;
+       struct fbnic_stat_counter MulticastFramesXmittedOK;
+       struct fbnic_stat_counter BroadcastFramesXmittedOK;
+       struct fbnic_stat_counter MulticastFramesReceivedOK;
+       struct fbnic_stat_counter BroadcastFramesReceivedOK;
+       struct fbnic_stat_counter FrameTooLongErrors;
+};
+
+struct fbnic_mac_stats {
+       struct fbnic_eth_mac_stats eth_mac;
+};
+
+struct fbnic_hw_stats {
+       struct fbnic_mac_stats mac;
+};
+
+u64 fbnic_stat_rd64(struct fbnic_dev *fbd, u32 reg, u32 offset);
+
+void fbnic_get_hw_stats(struct fbnic_dev *fbd);
index 7920e7a..7b654d0 100644 (file)
@@ -403,6 +403,21 @@ static void fbnic_mac_init_regs(struct fbnic_dev *fbd)
        fbnic_mac_init_txb(fbd);
 }
 
+static void __fbnic_mac_stat_rd64(struct fbnic_dev *fbd, bool reset, u32 reg,
+                                 struct fbnic_stat_counter *stat)
+{
+       u64 new_reg_value;
+
+       new_reg_value = fbnic_stat_rd64(fbd, reg, 1);
+       if (!reset)
+               stat->value += new_reg_value - stat->u.old_reg_value_64;
+       stat->u.old_reg_value_64 = new_reg_value;
+       stat->reported = true;
+}
+
+#define fbnic_mac_stat_rd64(fbd, reset, __stat, __CSR) \
+       __fbnic_mac_stat_rd64(fbd, reset, FBNIC_##__CSR##_L, &(__stat))
+
 static void fbnic_mac_tx_pause_config(struct fbnic_dev *fbd, bool tx_pause)
 {
        u32 rxb_pause_ctrl;
@@ -637,12 +652,47 @@ static void fbnic_mac_link_up_asic(struct fbnic_dev *fbd,
        wr32(fbd, FBNIC_MAC_COMMAND_CONFIG, cmd_cfg);
 }
 
+static void
+fbnic_mac_get_eth_mac_stats(struct fbnic_dev *fbd, bool reset,
+                           struct fbnic_eth_mac_stats *mac_stats)
+{
+       fbnic_mac_stat_rd64(fbd, reset, mac_stats->OctetsReceivedOK,
+                           MAC_STAT_RX_BYTE_COUNT);
+       fbnic_mac_stat_rd64(fbd, reset, mac_stats->AlignmentErrors,
+                           MAC_STAT_RX_ALIGN_ERROR);
+       fbnic_mac_stat_rd64(fbd, reset, mac_stats->FrameTooLongErrors,
+                           MAC_STAT_RX_TOOLONG);
+       fbnic_mac_stat_rd64(fbd, reset, mac_stats->FramesReceivedOK,
+                           MAC_STAT_RX_RECEIVED_OK);
+       fbnic_mac_stat_rd64(fbd, reset, mac_stats->FrameCheckSequenceErrors,
+                           MAC_STAT_RX_PACKET_BAD_FCS);
+       fbnic_mac_stat_rd64(fbd, reset,
+                           mac_stats->FramesLostDueToIntMACRcvError,
+                           MAC_STAT_RX_IFINERRORS);
+       fbnic_mac_stat_rd64(fbd, reset, mac_stats->MulticastFramesReceivedOK,
+                           MAC_STAT_RX_MULTICAST);
+       fbnic_mac_stat_rd64(fbd, reset, mac_stats->BroadcastFramesReceivedOK,
+                           MAC_STAT_RX_BROADCAST);
+       fbnic_mac_stat_rd64(fbd, reset, mac_stats->OctetsTransmittedOK,
+                           MAC_STAT_TX_BYTE_COUNT);
+       fbnic_mac_stat_rd64(fbd, reset, mac_stats->FramesTransmittedOK,
+                           MAC_STAT_TX_TRANSMITTED_OK);
+       fbnic_mac_stat_rd64(fbd, reset,
+                           mac_stats->FramesLostDueToIntMACXmitError,
+                           MAC_STAT_TX_IFOUTERRORS);
+       fbnic_mac_stat_rd64(fbd, reset, mac_stats->MulticastFramesXmittedOK,
+                           MAC_STAT_TX_MULTICAST);
+       fbnic_mac_stat_rd64(fbd, reset, mac_stats->BroadcastFramesXmittedOK,
+                           MAC_STAT_TX_BROADCAST);
+}
+
 static const struct fbnic_mac fbnic_mac_asic = {
        .init_regs = fbnic_mac_init_regs,
        .pcs_enable = fbnic_pcs_enable_asic,
        .pcs_disable = fbnic_pcs_disable_asic,
        .pcs_get_link = fbnic_pcs_get_link_asic,
        .pcs_get_link_event = fbnic_pcs_get_link_event_asic,
+       .get_eth_mac_stats = fbnic_mac_get_eth_mac_stats,
        .link_down = fbnic_mac_link_down_asic,
        .link_up = fbnic_mac_link_up_asic,
 };
index f53be6e..476239a 100644 (file)
@@ -78,6 +78,9 @@ struct fbnic_mac {
        bool (*pcs_get_link)(struct fbnic_dev *fbd);
        int (*pcs_get_link_event)(struct fbnic_dev *fbd);
 
+       void (*get_eth_mac_stats)(struct fbnic_dev *fbd, bool reset,
+                                 struct fbnic_eth_mac_stats *mac_stats);
+
        void (*link_down)(struct fbnic_dev *fbd);
        void (*link_up)(struct fbnic_dev *fbd, bool tx_pause, bool rx_pause);
 };