sfc: Add per-queue statistics in ethtool
authorAndrew Rybchenko <Andrew.Rybchenko@oktetlabs.ru>
Thu, 17 Jul 2014 11:10:43 +0000 (12:10 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 17 Jul 2014 23:48:36 +0000 (16:48 -0700)
Implement per channel software TX and RX packet counters
accessed as ethtool statistics.

This allows confirmation with MAC statistics.

Signed-off-by: Shradha Shah <sshah@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/ethtool.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sfc/rx.c
drivers/net/ethernet/sfc/tx.c

index 03fe4e7..cad258a 100644 (file)
@@ -359,6 +359,37 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
        return n;
 }
 
+static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings)
+{
+       size_t n_stats = 0;
+       struct efx_channel *channel;
+
+       efx_for_each_channel(channel, efx) {
+               if (efx_channel_has_tx_queues(channel)) {
+                       n_stats++;
+                       if (strings != NULL) {
+                               snprintf(strings, ETH_GSTRING_LEN,
+                                        "tx-%u.tx_packets",
+                                        channel->tx_queue[0].queue /
+                                        EFX_TXQ_TYPES);
+
+                               strings += ETH_GSTRING_LEN;
+                       }
+               }
+       }
+       efx_for_each_channel(channel, efx) {
+               if (efx_channel_has_rx_queue(channel)) {
+                       n_stats++;
+                       if (strings != NULL) {
+                               snprintf(strings, ETH_GSTRING_LEN,
+                                        "rx-%d.rx_packets", channel->channel);
+                               strings += ETH_GSTRING_LEN;
+                       }
+               }
+       }
+       return n_stats;
+}
+
 static int efx_ethtool_get_sset_count(struct net_device *net_dev,
                                      int string_set)
 {
@@ -367,8 +398,9 @@ static int efx_ethtool_get_sset_count(struct net_device *net_dev,
        switch (string_set) {
        case ETH_SS_STATS:
                return efx->type->describe_stats(efx, NULL) +
-                       EFX_ETHTOOL_SW_STAT_COUNT +
-                       efx_ptp_describe_stats(efx, NULL);
+                      EFX_ETHTOOL_SW_STAT_COUNT +
+                      efx_describe_per_queue_stats(efx, NULL) +
+                      efx_ptp_describe_stats(efx, NULL);
        case ETH_SS_TEST:
                return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL);
        default:
@@ -390,6 +422,8 @@ static void efx_ethtool_get_strings(struct net_device *net_dev,
                        strlcpy(strings + i * ETH_GSTRING_LEN,
                                efx_sw_stat_desc[i].name, ETH_GSTRING_LEN);
                strings += EFX_ETHTOOL_SW_STAT_COUNT * ETH_GSTRING_LEN;
+               strings += (efx_describe_per_queue_stats(efx, strings) *
+                           ETH_GSTRING_LEN);
                efx_ptp_describe_stats(efx, strings);
                break;
        case ETH_SS_TEST:
@@ -409,6 +443,7 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
        const struct efx_sw_stat_desc *stat;
        struct efx_channel *channel;
        struct efx_tx_queue *tx_queue;
+       struct efx_rx_queue *rx_queue;
        int i;
 
        spin_lock_bh(&efx->stats_lock);
@@ -444,6 +479,25 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
 
        spin_unlock_bh(&efx->stats_lock);
 
+       efx_for_each_channel(channel, efx) {
+               if (efx_channel_has_tx_queues(channel)) {
+                       *data = 0;
+                       efx_for_each_channel_tx_queue(tx_queue, channel) {
+                               *data += tx_queue->tx_packets;
+                       }
+                       data++;
+               }
+       }
+       efx_for_each_channel(channel, efx) {
+               if (efx_channel_has_rx_queue(channel)) {
+                       *data = 0;
+                       efx_for_each_channel_rx_queue(rx_queue, channel) {
+                               *data += rx_queue->rx_packets;
+                       }
+                       data++;
+               }
+       }
+
        efx_ptp_update_stats(efx, data);
 }
 
index 8a02d45..fb2e3bf 100644 (file)
@@ -249,6 +249,8 @@ struct efx_tx_queue {
        unsigned int tso_packets;
        unsigned int pushes;
        unsigned int pio_packets;
+       /* Statistics to supplement MAC stats */
+       unsigned long tx_packets;
 
        /* Members shared between paths and sometimes updated */
        unsigned int empty_read_count ____cacheline_aligned_in_smp;
@@ -358,6 +360,8 @@ struct efx_rx_queue {
        unsigned int recycle_count;
        struct timer_list slow_fill;
        unsigned int slow_fill_count;
+       /* Statistics to supplement MAC stats */
+       unsigned long rx_packets;
 };
 
 enum efx_sync_events_state {
index bf537a2..a7bb63a 100644 (file)
@@ -530,6 +530,8 @@ 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;
 
index ede8dcc..283e5f8 100644 (file)
@@ -452,6 +452,8 @@ finish_packet:
        /* Pass off to hardware */
        efx_nic_push_buffers(tx_queue);
 
+       tx_queue->tx_packets++;
+
        efx_tx_maybe_stop_queue(tx_queue);
 
        return NETDEV_TX_OK;
@@ -1245,6 +1247,8 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue,
 
        ++tx_queue->tso_packets;
 
+       ++tx_queue->tx_packets;
+
        return 0;
 }