]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
sfc: implement basic per-queue stats
authorEdward Cree <ecree.xilinx@gmail.com>
Mon, 30 Sep 2024 13:52:40 +0000 (14:52 +0100)
committerDavid S. Miller <davem@davemloft.net>
Sun, 6 Oct 2024 15:02:23 +0000 (16:02 +0100)
Just RX and TX packet counts and TX bytes for now.  We do not
 have per-queue RX byte counts, which causes us to fail
 stats.pkt_byte_sum selftest with "Drivers should always report
 basic keys" error.
Per-queue counts are since the last time the queue was inited
 (typically by efx_start_datapath(), on ifup or reconfiguration);
 device-wide total (efx_get_base_stats()) is since driver probe.
 This is not the same lifetime as rtnl_link_stats64, which uses
 firmware stats which count since FW (re)booted; this can cause a
 "Qstats are lower" or "RTNL stats are lower" failure in
 stats.pkt_byte_sum selftest.
Move the increment of rx_queue->rx_packets to match the semantics
 specified for netdev per-queue stats, i.e. just before handing
 the packet to XDP (if present) or the netstack (through GRO).
 This will affect the existing ethtool -S output which also
 reports these counters.
XDP TX packets are not yet counted into base_stats.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/ef100_rx.c
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/efx_channels.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sfc/rx.c
drivers/net/ethernet/sfc/rx_common.c
drivers/net/ethernet/sfc/tx_common.c

index 83d9db71d7d7e80d728ccc2139fe2e95f6a111a5..992151775cb83e75aff6a3975e90d41293401e27 100644 (file)
@@ -134,6 +134,8 @@ void __ef100_rx_packet(struct efx_channel *channel)
                goto free_rx_buffer;
        }
 
+       ++rx_queue->rx_packets;
+
        efx_rx_packet_gro(channel, rx_buf, channel->rx_pkt_n_frags, eh, csum);
        goto out;
 
@@ -149,8 +151,6 @@ static void ef100_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index)
        struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
        struct efx_nic *efx = rx_queue->efx;
 
-       ++rx_queue->rx_packets;
-
        netif_vdbg(efx, rx_status, efx->net_dev,
                   "RX queue %d received id %x\n",
                   efx_rx_queue_index(rx_queue), index);
index 36b3b57e20558ad41e23a192f65c8644adba185e..21dc4b885542099cce7f7cec8a538ed6d1f465f9 100644 (file)
@@ -22,6 +22,7 @@
 #include "net_driver.h"
 #include <net/gre.h>
 #include <net/udp_tunnel.h>
+#include <net/netdev_queues.h>
 #include "efx.h"
 #include "efx_common.h"
 #include "efx_channels.h"
@@ -626,6 +627,79 @@ static const struct net_device_ops efx_netdev_ops = {
        .ndo_bpf                = efx_xdp
 };
 
+static void efx_get_queue_stats_rx(struct net_device *net_dev, int idx,
+                                  struct netdev_queue_stats_rx *stats)
+{
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
+       struct efx_rx_queue *rx_queue;
+       struct efx_channel *channel;
+
+       channel = efx_get_channel(efx, idx);
+       rx_queue = efx_channel_get_rx_queue(channel);
+       /* Count only packets since last time datapath was started */
+       stats->packets = rx_queue->rx_packets - rx_queue->old_rx_packets;
+}
+
+static void efx_get_queue_stats_tx(struct net_device *net_dev, int idx,
+                                  struct netdev_queue_stats_tx *stats)
+{
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
+       struct efx_tx_queue *tx_queue;
+       struct efx_channel *channel;
+
+       channel = efx_get_tx_channel(efx, idx);
+       stats->packets = 0;
+       stats->bytes = 0;
+       efx_for_each_channel_tx_queue(tx_queue, channel) {
+               stats->packets += tx_queue->complete_packets -
+                                 tx_queue->old_complete_packets;
+               stats->bytes += tx_queue->complete_bytes -
+                               tx_queue->old_complete_bytes;
+       }
+}
+
+static void efx_get_base_stats(struct net_device *net_dev,
+                              struct netdev_queue_stats_rx *rx,
+                              struct netdev_queue_stats_tx *tx)
+{
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
+       struct efx_tx_queue *tx_queue;
+       struct efx_rx_queue *rx_queue;
+       struct efx_channel *channel;
+
+       rx->packets = 0;
+       tx->packets = 0;
+       tx->bytes = 0;
+
+       /* Count all packets on non-core queues, and packets before last
+        * datapath start on core queues.
+        */
+       efx_for_each_channel(channel, efx) {
+               rx_queue = efx_channel_get_rx_queue(channel);
+               if (channel->channel >= net_dev->real_num_rx_queues)
+                       rx->packets += rx_queue->rx_packets;
+               else
+                       rx->packets += rx_queue->old_rx_packets;
+               efx_for_each_channel_tx_queue(tx_queue, channel) {
+                       if (channel->channel < efx->tx_channel_offset ||
+                           channel->channel >= efx->tx_channel_offset +
+                                               net_dev->real_num_tx_queues) {
+                               tx->packets += tx_queue->complete_packets;
+                               tx->bytes += tx_queue->complete_bytes;
+                       } else {
+                               tx->packets += tx_queue->old_complete_packets;
+                               tx->bytes += tx_queue->old_complete_bytes;
+                       }
+               }
+       }
+}
+
+static const struct netdev_stat_ops efx_stat_ops = {
+       .get_queue_stats_rx     = efx_get_queue_stats_rx,
+       .get_queue_stats_tx     = efx_get_queue_stats_tx,
+       .get_base_stats         = efx_get_base_stats,
+};
+
 static int efx_xdp_setup_prog(struct efx_nic *efx, struct bpf_prog *prog)
 {
        struct bpf_prog *old_prog;
@@ -716,6 +790,7 @@ static int efx_register_netdev(struct efx_nic *efx)
        net_dev->watchdog_timeo = 5 * HZ;
        net_dev->irq = efx->pci_dev->irq;
        net_dev->netdev_ops = &efx_netdev_ops;
+       net_dev->stat_ops = &efx_stat_ops;
        if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0)
                net_dev->priv_flags |= IFF_UNICAST_FLT;
        net_dev->ethtool_ops = &efx_ethtool_ops;
index c9e17a8208a90177c45a507ee433a050f606aecd..834d51812e2b1bbefb9840690e4e2a41fd69f073 100644 (file)
@@ -1209,6 +1209,8 @@ static int efx_process_channel(struct efx_channel *channel, int budget)
                                                  tx_queue->pkts_compl,
                                                  tx_queue->bytes_compl);
                }
+               tx_queue->complete_packets += tx_queue->pkts_compl;
+               tx_queue->complete_bytes += tx_queue->bytes_compl;
        }
 
        /* Receive any packets we queued up */
index 4d904e1404d43da59b7edb4a7fd50df31aafb56c..83c33c1ca12000d454c874ef8a936204f8b1350d 100644 (file)
@@ -193,6 +193,10 @@ struct efx_tx_buffer {
  * @initialised: Has hardware queue been initialised?
  * @timestamping: Is timestamping enabled for this channel?
  * @xdp_tx: Is this an XDP tx queue?
+ * @old_complete_packets: Value of @complete_packets as of last
+ *     efx_init_tx_queue()
+ * @old_complete_bytes: Value of @complete_bytes as of last
+ *     efx_init_tx_queue()
  * @read_count: Current read pointer.
  *     This is the number of buffers that have been removed from both rings.
  * @old_write_count: The value of @write_count when last checked.
@@ -202,6 +206,16 @@ struct efx_tx_buffer {
  *     avoid cache-line ping-pong between the xmit path and the
  *     completion path.
  * @merge_events: Number of TX merged completion events
+ * @bytes_compl: Number of bytes completed during this NAPI poll
+ *     (efx_process_channel()).  For BQL.
+ * @pkts_compl: Number of packets completed during this NAPI poll.
+ * @complete_packets: Number of packets completed since this struct was
+ *     created.  Only counts SKB packets, not XDP TX (it accumulates
+ *     the same values that are reported to BQL).
+ * @complete_bytes: Number of bytes completed since this struct was
+ *     created.  For TSO, counts the superframe size, not the sizes of
+ *     generated frames on the wire (i.e. the headers are only counted
+ *     once)
  * @completed_timestamp_major: Top part of the most recent tx timestamp.
  * @completed_timestamp_minor: Low part of the most recent tx timestamp.
  * @insert_count: Current insert pointer
@@ -232,6 +246,7 @@ struct efx_tx_buffer {
  * @xmit_pending: Are any packets waiting to be pushed to the NIC
  * @cb_packets: Number of times the TX copybreak feature has been used
  * @notify_count: Count of notified descriptors to the NIC
+ * @tx_packets: Number of packets sent since this struct was created
  * @empty_read_count: If the completion path has seen the queue as empty
  *     and the transmission path has not yet checked this, the value of
  *     @read_count bitwise-added to %EFX_EMPTY_COUNT_VALID; otherwise 0.
@@ -255,6 +270,8 @@ struct efx_tx_queue {
        bool initialised;
        bool timestamping;
        bool xdp_tx;
+       unsigned long old_complete_packets;
+       unsigned long old_complete_bytes;
 
        /* Members used mainly on the completion path */
        unsigned int read_count ____cacheline_aligned_in_smp;
@@ -262,6 +279,8 @@ struct efx_tx_queue {
        unsigned int merge_events;
        unsigned int bytes_compl;
        unsigned int pkts_compl;
+       unsigned long complete_packets;
+       unsigned long complete_bytes;
        u32 completed_timestamp_major;
        u32 completed_timestamp_minor;
 
@@ -370,6 +389,8 @@ struct efx_rx_page_state {
  * @recycle_count: RX buffer recycle counter.
  * @slow_fill: Timer used to defer efx_nic_generate_fill_event().
  * @grant_work: workitem used to grant credits to the MAE if @grant_credits
+ * @rx_packets: Number of packets received since this struct was created
+ * @old_rx_packets: Value of @rx_packets as of last efx_init_rx_queue()
  * @xdp_rxq_info: XDP specific RX queue information.
  * @xdp_rxq_info_valid: Is xdp_rxq_info valid data?.
  */
@@ -406,6 +427,7 @@ struct efx_rx_queue {
        struct work_struct grant_work;
        /* Statistics to supplement MAC stats */
        unsigned long rx_packets;
+       unsigned long old_rx_packets;
        struct xdp_rxq_info xdp_rxq_info;
        bool xdp_rxq_info_valid;
 };
index f77a2d3ef37ecaa566be2458df36b56499984818..f074955821253627ba6c7f8f92e2909b1e32cf12 100644 (file)
@@ -125,8 +125,6 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
        struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
        struct efx_rx_buffer *rx_buf;
 
-       rx_queue->rx_packets++;
-
        rx_buf = efx_rx_buffer(rx_queue, index);
        rx_buf->flags |= flags;
 
@@ -394,6 +392,8 @@ void __efx_rx_packet(struct efx_channel *channel)
                goto out;
        }
 
+       rx_queue->rx_packets++;
+
        if (!efx_do_xdp(efx, channel, rx_buf, &eh))
                goto out;
 
index 0b7dc75c40f9275d6b9fc9e620c4c5ad31bf78a2..bdb4325a7c2c59df87e2f896da94705d64469128 100644 (file)
@@ -241,6 +241,8 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue)
        rx_queue->page_recycle_failed = 0;
        rx_queue->page_recycle_full = 0;
 
+       rx_queue->old_rx_packets = rx_queue->rx_packets;
+
        /* Initialise limit fields */
        max_fill = efx->rxq_entries - EFX_RXD_HEAD_ROOM;
        max_trigger =
index 2adb132b2f7e46951dbe65c4394741a072e63baf..6d47927e1c2c58ab270d5e6a79ee6f53264194e2 100644 (file)
@@ -86,6 +86,9 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue)
        tx_queue->completed_timestamp_major = 0;
        tx_queue->completed_timestamp_minor = 0;
 
+       tx_queue->old_complete_packets = tx_queue->complete_packets;
+       tx_queue->old_complete_bytes = tx_queue->complete_bytes;
+
        tx_queue->xdp_tx = efx_channel_is_xdp_tx(tx_queue->channel);
        tx_queue->tso_version = 0;