|
@@ -38,6 +38,7 @@
|
|
|
#include <linux/mlx4/device.h>
|
|
|
#include <linux/in.h>
|
|
|
#include <net/ip.h>
|
|
|
+#include <linux/bitmap.h>
|
|
|
|
|
|
#include "mlx4_en.h"
|
|
|
#include "en_port.h"
|
|
@@ -104,6 +105,7 @@ static const char mlx4_en_priv_flags[][ETH_GSTRING_LEN] = {
|
|
|
};
|
|
|
|
|
|
static const char main_strings[][ETH_GSTRING_LEN] = {
|
|
|
+ /* main statistics */
|
|
|
"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
|
|
|
"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
|
|
|
"rx_length_errors", "rx_over_errors", "rx_crc_errors",
|
|
@@ -117,14 +119,76 @@ static const char main_strings[][ETH_GSTRING_LEN] = {
|
|
|
"queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed",
|
|
|
"rx_csum_good", "rx_csum_none", "rx_csum_complete", "tx_chksum_offload",
|
|
|
|
|
|
+ /* priority flow control statistics rx */
|
|
|
+ "rx_pause_prio_0", "rx_pause_duration_prio_0",
|
|
|
+ "rx_pause_transition_prio_0",
|
|
|
+ "rx_pause_prio_1", "rx_pause_duration_prio_1",
|
|
|
+ "rx_pause_transition_prio_1",
|
|
|
+ "rx_pause_prio_2", "rx_pause_duration_prio_2",
|
|
|
+ "rx_pause_transition_prio_2",
|
|
|
+ "rx_pause_prio_3", "rx_pause_duration_prio_3",
|
|
|
+ "rx_pause_transition_prio_3",
|
|
|
+ "rx_pause_prio_4", "rx_pause_duration_prio_4",
|
|
|
+ "rx_pause_transition_prio_4",
|
|
|
+ "rx_pause_prio_5", "rx_pause_duration_prio_5",
|
|
|
+ "rx_pause_transition_prio_5",
|
|
|
+ "rx_pause_prio_6", "rx_pause_duration_prio_6",
|
|
|
+ "rx_pause_transition_prio_6",
|
|
|
+ "rx_pause_prio_7", "rx_pause_duration_prio_7",
|
|
|
+ "rx_pause_transition_prio_7",
|
|
|
+
|
|
|
+ /* flow control statistics rx */
|
|
|
+ "rx_pause", "rx_pause_duration", "rx_pause_transition",
|
|
|
+
|
|
|
+ /* priority flow control statistics tx */
|
|
|
+ "tx_pause_prio_0", "tx_pause_duration_prio_0",
|
|
|
+ "tx_pause_transition_prio_0",
|
|
|
+ "tx_pause_prio_1", "tx_pause_duration_prio_1",
|
|
|
+ "tx_pause_transition_prio_1",
|
|
|
+ "tx_pause_prio_2", "tx_pause_duration_prio_2",
|
|
|
+ "tx_pause_transition_prio_2",
|
|
|
+ "tx_pause_prio_3", "tx_pause_duration_prio_3",
|
|
|
+ "tx_pause_transition_prio_3",
|
|
|
+ "tx_pause_prio_4", "tx_pause_duration_prio_4",
|
|
|
+ "tx_pause_transition_prio_4",
|
|
|
+ "tx_pause_prio_5", "tx_pause_duration_prio_5",
|
|
|
+ "tx_pause_transition_prio_5",
|
|
|
+ "tx_pause_prio_6", "tx_pause_duration_prio_6",
|
|
|
+ "tx_pause_transition_prio_6",
|
|
|
+ "tx_pause_prio_7", "tx_pause_duration_prio_7",
|
|
|
+ "tx_pause_transition_prio_7",
|
|
|
+
|
|
|
+ /* flow control statistics tx */
|
|
|
+ "tx_pause", "tx_pause_duration", "tx_pause_transition",
|
|
|
+
|
|
|
/* packet statistics */
|
|
|
- "broadcast", "rx_prio_0", "rx_prio_1", "rx_prio_2", "rx_prio_3",
|
|
|
- "rx_prio_4", "rx_prio_5", "rx_prio_6", "rx_prio_7", "tx_prio_0",
|
|
|
- "tx_prio_1", "tx_prio_2", "tx_prio_3", "tx_prio_4", "tx_prio_5",
|
|
|
- "tx_prio_6", "tx_prio_7",
|
|
|
+ "rx_multicast_packets",
|
|
|
+ "rx_broadcast_packets",
|
|
|
+ "rx_jabbers",
|
|
|
+ "rx_in_range_length_error",
|
|
|
+ "rx_out_range_length_error",
|
|
|
+ "tx_multicast_packets",
|
|
|
+ "tx_broadcast_packets",
|
|
|
+ "rx_prio_0_packets", "rx_prio_0_bytes",
|
|
|
+ "rx_prio_1_packets", "rx_prio_1_bytes",
|
|
|
+ "rx_prio_2_packets", "rx_prio_2_bytes",
|
|
|
+ "rx_prio_3_packets", "rx_prio_3_bytes",
|
|
|
+ "rx_prio_4_packets", "rx_prio_4_bytes",
|
|
|
+ "rx_prio_5_packets", "rx_prio_5_bytes",
|
|
|
+ "rx_prio_6_packets", "rx_prio_6_bytes",
|
|
|
+ "rx_prio_7_packets", "rx_prio_7_bytes",
|
|
|
+ "rx_novlan_packets", "rx_novlan_bytes",
|
|
|
+ "tx_prio_0_packets", "tx_prio_0_bytes",
|
|
|
+ "tx_prio_1_packets", "tx_prio_1_bytes",
|
|
|
+ "tx_prio_2_packets", "tx_prio_2_bytes",
|
|
|
+ "tx_prio_3_packets", "tx_prio_3_bytes",
|
|
|
+ "tx_prio_4_packets", "tx_prio_4_bytes",
|
|
|
+ "tx_prio_5_packets", "tx_prio_5_bytes",
|
|
|
+ "tx_prio_6_packets", "tx_prio_6_bytes",
|
|
|
+ "tx_prio_7_packets", "tx_prio_7_bytes",
|
|
|
+ "tx_novlan_packets", "tx_novlan_bytes",
|
|
|
+
|
|
|
};
|
|
|
-#define NUM_MAIN_STATS 21
|
|
|
-#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS)
|
|
|
|
|
|
static const char mlx4_en_test_names[][ETH_GSTRING_LEN]= {
|
|
|
"Interrupt Test",
|
|
@@ -224,14 +288,50 @@ static int mlx4_en_set_wol(struct net_device *netdev,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+struct bitmap_iterator {
|
|
|
+ unsigned long *stats_bitmap;
|
|
|
+ unsigned int count;
|
|
|
+ unsigned int iterator;
|
|
|
+ bool advance_array; /* if set, force no increments */
|
|
|
+};
|
|
|
+
|
|
|
+static inline void bitmap_iterator_init(struct bitmap_iterator *h,
|
|
|
+ unsigned long *stats_bitmap,
|
|
|
+ int count)
|
|
|
+{
|
|
|
+ h->iterator = 0;
|
|
|
+ h->advance_array = !bitmap_empty(stats_bitmap, count);
|
|
|
+ h->count = h->advance_array ? bitmap_weight(stats_bitmap, count)
|
|
|
+ : count;
|
|
|
+ h->stats_bitmap = stats_bitmap;
|
|
|
+}
|
|
|
+
|
|
|
+static inline int bitmap_iterator_test(struct bitmap_iterator *h)
|
|
|
+{
|
|
|
+ return !h->advance_array ? 1 : test_bit(h->iterator, h->stats_bitmap);
|
|
|
+}
|
|
|
+
|
|
|
+static inline int bitmap_iterator_inc(struct bitmap_iterator *h)
|
|
|
+{
|
|
|
+ return h->iterator++;
|
|
|
+}
|
|
|
+
|
|
|
+static inline unsigned int
|
|
|
+bitmap_iterator_count(struct bitmap_iterator *h)
|
|
|
+{
|
|
|
+ return h->count;
|
|
|
+}
|
|
|
+
|
|
|
static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
|
|
|
{
|
|
|
struct mlx4_en_priv *priv = netdev_priv(dev);
|
|
|
- int bit_count = hweight64(priv->stats_bitmap);
|
|
|
+ struct bitmap_iterator it;
|
|
|
+
|
|
|
+ bitmap_iterator_init(&it, priv->stats_bitmap.bitmap, NUM_ALL_STATS);
|
|
|
|
|
|
switch (sset) {
|
|
|
case ETH_SS_STATS:
|
|
|
- return (priv->stats_bitmap ? bit_count : NUM_ALL_STATS) +
|
|
|
+ return bitmap_iterator_count(&it) +
|
|
|
(priv->tx_ring_num * 2) +
|
|
|
#ifdef CONFIG_NET_RX_BUSY_POLL
|
|
|
(priv->rx_ring_num * 5);
|
|
@@ -253,34 +353,45 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
|
|
|
{
|
|
|
struct mlx4_en_priv *priv = netdev_priv(dev);
|
|
|
int index = 0;
|
|
|
- int i, j = 0;
|
|
|
+ int i;
|
|
|
+ struct bitmap_iterator it;
|
|
|
+
|
|
|
+ bitmap_iterator_init(&it, priv->stats_bitmap.bitmap, NUM_ALL_STATS);
|
|
|
|
|
|
spin_lock_bh(&priv->stats_lock);
|
|
|
|
|
|
- if (!(priv->stats_bitmap)) {
|
|
|
- for (i = 0; i < NUM_MAIN_STATS; i++)
|
|
|
- data[index++] =
|
|
|
- ((unsigned long *) &priv->stats)[i];
|
|
|
- for (i = 0; i < NUM_PORT_STATS; i++)
|
|
|
+ for (i = 0; i < NUM_MAIN_STATS; i++, bitmap_iterator_inc(&it))
|
|
|
+ if (bitmap_iterator_test(&it))
|
|
|
+ data[index++] = ((unsigned long *)&priv->stats)[i];
|
|
|
+
|
|
|
+ for (i = 0; i < NUM_PORT_STATS; i++, bitmap_iterator_inc(&it))
|
|
|
+ if (bitmap_iterator_test(&it))
|
|
|
+ data[index++] = ((unsigned long *)&priv->port_stats)[i];
|
|
|
+
|
|
|
+ for (i = 0; i < NUM_FLOW_PRIORITY_STATS_RX;
|
|
|
+ i++, bitmap_iterator_inc(&it))
|
|
|
+ if (bitmap_iterator_test(&it))
|
|
|
data[index++] =
|
|
|
- ((unsigned long *) &priv->port_stats)[i];
|
|
|
- for (i = 0; i < NUM_PKT_STATS; i++)
|
|
|
+ ((u64 *)&priv->rx_priority_flowstats)[i];
|
|
|
+
|
|
|
+ for (i = 0; i < NUM_FLOW_STATS_RX; i++, bitmap_iterator_inc(&it))
|
|
|
+ if (bitmap_iterator_test(&it))
|
|
|
+ data[index++] = ((u64 *)&priv->rx_flowstats)[i];
|
|
|
+
|
|
|
+ for (i = 0; i < NUM_FLOW_PRIORITY_STATS_TX;
|
|
|
+ i++, bitmap_iterator_inc(&it))
|
|
|
+ if (bitmap_iterator_test(&it))
|
|
|
data[index++] =
|
|
|
- ((unsigned long *) &priv->pkstats)[i];
|
|
|
- } else {
|
|
|
- for (i = 0; i < NUM_MAIN_STATS; i++) {
|
|
|
- if ((priv->stats_bitmap >> j) & 1)
|
|
|
- data[index++] =
|
|
|
- ((unsigned long *) &priv->stats)[i];
|
|
|
- j++;
|
|
|
- }
|
|
|
- for (i = 0; i < NUM_PORT_STATS; i++) {
|
|
|
- if ((priv->stats_bitmap >> j) & 1)
|
|
|
- data[index++] =
|
|
|
- ((unsigned long *) &priv->port_stats)[i];
|
|
|
- j++;
|
|
|
- }
|
|
|
- }
|
|
|
+ ((u64 *)&priv->tx_priority_flowstats)[i];
|
|
|
+
|
|
|
+ for (i = 0; i < NUM_FLOW_STATS_TX; i++, bitmap_iterator_inc(&it))
|
|
|
+ if (bitmap_iterator_test(&it))
|
|
|
+ data[index++] = ((u64 *)&priv->tx_flowstats)[i];
|
|
|
+
|
|
|
+ for (i = 0; i < NUM_PKT_STATS; i++, bitmap_iterator_inc(&it))
|
|
|
+ if (bitmap_iterator_test(&it))
|
|
|
+ data[index++] = ((unsigned long *)&priv->pkstats)[i];
|
|
|
+
|
|
|
for (i = 0; i < priv->tx_ring_num; i++) {
|
|
|
data[index++] = priv->tx_ring[i]->packets;
|
|
|
data[index++] = priv->tx_ring[i]->bytes;
|
|
@@ -309,7 +420,10 @@ static void mlx4_en_get_strings(struct net_device *dev,
|
|
|
{
|
|
|
struct mlx4_en_priv *priv = netdev_priv(dev);
|
|
|
int index = 0;
|
|
|
- int i;
|
|
|
+ int i, strings = 0;
|
|
|
+ struct bitmap_iterator it;
|
|
|
+
|
|
|
+ bitmap_iterator_init(&it, priv->stats_bitmap.bitmap, NUM_ALL_STATS);
|
|
|
|
|
|
switch (stringset) {
|
|
|
case ETH_SS_TEST:
|
|
@@ -322,29 +436,30 @@ static void mlx4_en_get_strings(struct net_device *dev,
|
|
|
|
|
|
case ETH_SS_STATS:
|
|
|
/* Add main counters */
|
|
|
- if (!priv->stats_bitmap) {
|
|
|
- for (i = 0; i < NUM_MAIN_STATS; i++)
|
|
|
+ for (i = 0; i < NUM_MAIN_STATS; i++, strings++,
|
|
|
+ bitmap_iterator_inc(&it))
|
|
|
+ if (bitmap_iterator_test(&it))
|
|
|
strcpy(data + (index++) * ETH_GSTRING_LEN,
|
|
|
- main_strings[i]);
|
|
|
- for (i = 0; i < NUM_PORT_STATS; i++)
|
|
|
+ main_strings[strings]);
|
|
|
+
|
|
|
+ for (i = 0; i < NUM_PORT_STATS; i++, strings++,
|
|
|
+ bitmap_iterator_inc(&it))
|
|
|
+ if (bitmap_iterator_test(&it))
|
|
|
strcpy(data + (index++) * ETH_GSTRING_LEN,
|
|
|
- main_strings[i +
|
|
|
- NUM_MAIN_STATS]);
|
|
|
- for (i = 0; i < NUM_PKT_STATS; i++)
|
|
|
+ main_strings[strings]);
|
|
|
+
|
|
|
+ for (i = 0; i < NUM_FLOW_STATS; i++, strings++,
|
|
|
+ bitmap_iterator_inc(&it))
|
|
|
+ if (bitmap_iterator_test(&it))
|
|
|
strcpy(data + (index++) * ETH_GSTRING_LEN,
|
|
|
- main_strings[i +
|
|
|
- NUM_MAIN_STATS +
|
|
|
- NUM_PORT_STATS]);
|
|
|
- } else
|
|
|
- for (i = 0; i < NUM_MAIN_STATS + NUM_PORT_STATS; i++) {
|
|
|
- if ((priv->stats_bitmap >> i) & 1) {
|
|
|
- strcpy(data +
|
|
|
- (index++) * ETH_GSTRING_LEN,
|
|
|
- main_strings[i]);
|
|
|
- }
|
|
|
- if (!(priv->stats_bitmap >> i))
|
|
|
- break;
|
|
|
- }
|
|
|
+ main_strings[strings]);
|
|
|
+
|
|
|
+ for (i = 0; i < NUM_PKT_STATS; i++, strings++,
|
|
|
+ bitmap_iterator_inc(&it))
|
|
|
+ if (bitmap_iterator_test(&it))
|
|
|
+ strcpy(data + (index++) * ETH_GSTRING_LEN,
|
|
|
+ main_strings[strings]);
|
|
|
+
|
|
|
for (i = 0; i < priv->tx_ring_num; i++) {
|
|
|
sprintf(data + (index++) * ETH_GSTRING_LEN,
|
|
|
"tx%d_packets", i);
|
|
@@ -885,6 +1000,12 @@ static int mlx4_en_set_pauseparam(struct net_device *dev,
|
|
|
priv->prof->rx_ppp);
|
|
|
if (err)
|
|
|
en_err(priv, "Failed setting pause params\n");
|
|
|
+ else
|
|
|
+ mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
|
|
|
+ priv->prof->rx_ppp,
|
|
|
+ priv->prof->rx_pause,
|
|
|
+ priv->prof->tx_ppp,
|
|
|
+ priv->prof->tx_pause);
|
|
|
|
|
|
return err;
|
|
|
}
|