qlcnic: Enhance ethtool Statistics for Multiple Tx queue.

o Enhance ethtool statistics to display multiple Tx queue stats for
  all supported adapters.

Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Himanshu Madhani 2013-11-04 13:31:30 -05:00 committed by David S. Miller
parent 78ea2d977a
commit f27c75b390
4 changed files with 99 additions and 67 deletions

View File

@ -533,6 +533,14 @@ struct qlcnic_host_sds_ring {
char name[IFNAMSIZ + 12]; char name[IFNAMSIZ + 12];
} ____cacheline_internodealigned_in_smp; } ____cacheline_internodealigned_in_smp;
struct qlcnic_tx_queue_stats {
u64 xmit_on;
u64 xmit_off;
u64 xmit_called;
u64 xmit_finished;
u64 tx_bytes;
};
struct qlcnic_host_tx_ring { struct qlcnic_host_tx_ring {
int irq; int irq;
void __iomem *crb_intr_mask; void __iomem *crb_intr_mask;
@ -544,10 +552,7 @@ struct qlcnic_host_tx_ring {
u32 sw_consumer; u32 sw_consumer;
u32 num_desc; u32 num_desc;
u64 xmit_on; struct qlcnic_tx_queue_stats tx_stats;
u64 xmit_off;
u64 xmit_called;
u64 xmit_finished;
void __iomem *crb_cmd_producer; void __iomem *crb_cmd_producer;
struct cmd_desc_type0 *desc_head; struct cmd_desc_type0 *desc_head;

View File

@ -27,43 +27,36 @@ static const u32 qlcnic_fw_dump_level[] = {
}; };
static const struct qlcnic_stats qlcnic_gstrings_stats[] = { static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
{"xmit_called", QLC_SIZEOF(stats.xmitcalled),
QLC_OFF(stats.xmitcalled)},
{"xmit_finished", QLC_SIZEOF(stats.xmitfinished),
QLC_OFF(stats.xmitfinished)},
{"rx_dropped", QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
{"tx_dropped", QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
{"csummed", QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
{"rx_pkts", QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
{"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
{"rx_bytes", QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
{"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
{"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
{"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
{"xmit_on", QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)}, {"xmit_on", QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
{"xmit_off", QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)}, {"xmit_off", QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
{"xmit_called", QLC_SIZEOF(stats.xmitcalled),
QLC_OFF(stats.xmitcalled)},
{"xmit_finished", QLC_SIZEOF(stats.xmitfinished),
QLC_OFF(stats.xmitfinished)},
{"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
QLC_OFF(stats.tx_dma_map_error)},
{"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
{"tx_dropped", QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
{"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
QLC_OFF(stats.rx_dma_map_error)},
{"rx_pkts", QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
{"rx_bytes", QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
{"rx_dropped", QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
{"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
{"csummed", QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
{"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
{"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
{"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
{"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure), {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
QLC_OFF(stats.skb_alloc_failure)}, QLC_OFF(stats.skb_alloc_failure)},
{"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
{"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
QLC_OFF(stats.rx_dma_map_error)},
{"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
QLC_OFF(stats.tx_dma_map_error)},
{"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun), {"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun),
QLC_OFF(stats.mac_filter_limit_overrun)}, QLC_OFF(stats.mac_filter_limit_overrun)},
{"spurious intr", QLC_SIZEOF(stats.spurious_intr), {"spurious intr", QLC_SIZEOF(stats.spurious_intr),
QLC_OFF(stats.spurious_intr)}, QLC_OFF(stats.spurious_intr)},
}; };
static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = { static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
"rx unicast frames",
"rx multicast frames",
"rx broadcast frames",
"rx dropped frames",
"rx errors",
"rx local frames",
"rx numbytes",
"tx unicast frames", "tx unicast frames",
"tx multicast frames", "tx multicast frames",
"tx broadcast frames", "tx broadcast frames",
@ -71,6 +64,13 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
"tx errors", "tx errors",
"tx local frames", "tx local frames",
"tx numbytes", "tx numbytes",
"rx unicast frames",
"rx multicast frames",
"rx broadcast frames",
"rx dropped frames",
"rx errors",
"rx local frames",
"rx numbytes",
}; };
static const char qlcnic_83xx_tx_stats_strings[][ETH_GSTRING_LEN] = { static const char qlcnic_83xx_tx_stats_strings[][ETH_GSTRING_LEN] = {
@ -126,13 +126,16 @@ static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = {
#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats) #define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
static const char qlcnic_tx_ring_stats_strings[][ETH_GSTRING_LEN] = { static const char qlcnic_tx_queue_stats_strings[][ETH_GSTRING_LEN] = {
"xmit_on", "xmit_on",
"xmit_off", "xmit_off",
"xmit_called", "xmit_called",
"xmit_finished", "xmit_finished",
"tx_bytes",
}; };
#define QLCNIC_TX_STATS_LEN ARRAY_SIZE(qlcnic_tx_queue_stats_strings)
static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = { static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {
"ctx_rx_bytes", "ctx_rx_bytes",
"ctx_rx_pkts", "ctx_rx_pkts",
@ -1123,11 +1126,11 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
QLCNIC_TEST_LEN * ETH_GSTRING_LEN); QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
break; break;
case ETH_SS_STATS: case ETH_SS_STATS:
num_stats = ARRAY_SIZE(qlcnic_tx_ring_stats_strings); num_stats = ARRAY_SIZE(qlcnic_tx_queue_stats_strings);
for (i = 0; i < adapter->max_drv_tx_rings; i++) { for (i = 0; i < adapter->max_drv_tx_rings; i++) {
for (index = 0; index < num_stats; index++) { for (index = 0; index < num_stats; index++) {
sprintf(data, "tx_ring_%d %s", i, sprintf(data, "tx_queue_%d %s", i,
qlcnic_tx_ring_stats_strings[index]); qlcnic_tx_queue_stats_strings[index]);
data += ETH_GSTRING_LEN; data += ETH_GSTRING_LEN;
} }
} }
@ -1225,6 +1228,36 @@ static u64 *qlcnic_fill_stats(u64 *data, void *stats, int type)
return data; return data;
} }
static void qlcnic_update_stats(struct qlcnic_adapter *adapter)
{
struct qlcnic_host_tx_ring *tx_ring;
int ring;
for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
tx_ring = &adapter->tx_ring[ring];
adapter->stats.xmit_on += tx_ring->tx_stats.xmit_on;
adapter->stats.xmit_off += tx_ring->tx_stats.xmit_off;
adapter->stats.xmitcalled += tx_ring->tx_stats.xmit_called;
adapter->stats.xmitfinished += tx_ring->tx_stats.xmit_finished;
adapter->stats.txbytes += tx_ring->tx_stats.tx_bytes;
}
}
static u64 *qlcnic_fill_tx_queue_stats(u64 *data, void *stats)
{
struct qlcnic_host_tx_ring *tx_ring;
tx_ring = (struct qlcnic_host_tx_ring *)stats;
*data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_on);
*data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_off);
*data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_called);
*data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_finished);
*data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.tx_bytes);
return data;
}
static void qlcnic_get_ethtool_stats(struct net_device *dev, static void qlcnic_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data) struct ethtool_stats *stats, u64 *data)
{ {
@ -1232,19 +1265,20 @@ static void qlcnic_get_ethtool_stats(struct net_device *dev,
struct qlcnic_host_tx_ring *tx_ring; struct qlcnic_host_tx_ring *tx_ring;
struct qlcnic_esw_statistics port_stats; struct qlcnic_esw_statistics port_stats;
struct qlcnic_mac_statistics mac_stats; struct qlcnic_mac_statistics mac_stats;
int index, ret, length, size, ring; int index, ret, length, size, tx_size, ring;
char *p; char *p;
memset(data, 0, adapter->max_drv_tx_rings * 4 * sizeof(u64)); tx_size = adapter->max_drv_tx_rings * QLCNIC_TX_STATS_LEN;
memset(data, 0, tx_size * sizeof(u64));
for (ring = 0, index = 0; ring < adapter->max_drv_tx_rings; ring++) { for (ring = 0, index = 0; ring < adapter->max_drv_tx_rings; ring++) {
if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
tx_ring = &adapter->tx_ring[ring]; tx_ring = &adapter->tx_ring[ring];
*data++ = tx_ring->xmit_on; data = qlcnic_fill_tx_queue_stats(data, tx_ring);
*data++ = tx_ring->xmit_off; qlcnic_update_stats(adapter);
*data++ = tx_ring->xmit_called;
*data++ = tx_ring->xmit_finished;
} }
} }
memset(data, 0, stats->n_stats * sizeof(u64)); memset(data, 0, stats->n_stats * sizeof(u64));
length = QLCNIC_STATS_LEN; length = QLCNIC_STATS_LEN;
for (index = 0; index < length; index++) { for (index = 0; index < length; index++) {

View File

@ -607,8 +607,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) { if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
netif_tx_start_queue(tx_ring->txq); netif_tx_start_queue(tx_ring->txq);
} else { } else {
adapter->stats.xmit_off++; tx_ring->tx_stats.xmit_off++;
tx_ring->xmit_off++;
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
} }
@ -669,9 +668,8 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (adapter->drv_mac_learn) if (adapter->drv_mac_learn)
qlcnic_send_filter(adapter, first_desc, skb); qlcnic_send_filter(adapter, first_desc, skb);
adapter->stats.txbytes += skb->len; tx_ring->tx_stats.tx_bytes += skb->len;
adapter->stats.xmitcalled++; tx_ring->tx_stats.xmit_called++;
tx_ring->xmit_called++;
qlcnic_update_cmd_producer(tx_ring); qlcnic_update_cmd_producer(tx_ring);
@ -805,8 +803,7 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
frag->dma = 0ULL; frag->dma = 0ULL;
} }
adapter->stats.xmitfinished++; tx_ring->tx_stats.xmit_finished++;
tx_ring->xmit_finished++;
dev_kfree_skb_any(buffer->skb); dev_kfree_skb_any(buffer->skb);
buffer->skb = NULL; buffer->skb = NULL;
} }
@ -823,8 +820,7 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
netif_carrier_ok(netdev)) { netif_carrier_ok(netdev)) {
if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) { if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
netif_tx_wake_queue(tx_ring->txq); netif_tx_wake_queue(tx_ring->txq);
adapter->stats.xmit_on++; tx_ring->tx_stats.xmit_on++;
tx_ring->xmit_on++;
} }
} }
adapter->tx_timeo_cnt = 0; adapter->tx_timeo_cnt = 0;

View File

@ -2722,24 +2722,21 @@ static void qlcnic_tx_timeout(struct net_device *netdev)
QLCNIC_FORCE_FW_DUMP_KEY); QLCNIC_FORCE_FW_DUMP_KEY);
} else { } else {
netdev_info(netdev, "Tx timeout, reset adapter context.\n"); netdev_info(netdev, "Tx timeout, reset adapter context.\n");
if (qlcnic_82xx_check(adapter)) { for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
for (ring = 0; ring < adapter->max_drv_tx_rings; tx_ring = &adapter->tx_ring[ring];
ring++) { netdev_info(netdev, "Tx ring=%d\n", ring);
tx_ring = &adapter->tx_ring[ring]; netdev_info(netdev,
dev_info(&netdev->dev, "ring=%d\n", ring); "crb_intr_mask=%d, producer=%d, sw_consumer=%d, hw_consumer=%d\n",
dev_info(&netdev->dev, "crb_intr_mask=%d\n", readl(tx_ring->crb_intr_mask),
readl(tx_ring->crb_intr_mask)); readl(tx_ring->crb_cmd_producer),
dev_info(&netdev->dev, "producer=%d\n", tx_ring->sw_consumer,
readl(tx_ring->crb_cmd_producer)); le32_to_cpu(*(tx_ring->hw_consumer)));
dev_info(&netdev->dev, "sw_consumer = %d\n", netdev_info(netdev,
tx_ring->sw_consumer); "xmit_finished=%llu, xmit_called=%llu, xmit_on=%llu, xmit_off=%llu\n",
dev_info(&netdev->dev, "hw_consumer = %d\n", tx_ring->tx_stats.xmit_finished,
le32_to_cpu(*(tx_ring->hw_consumer))); tx_ring->tx_stats.xmit_called,
dev_info(&netdev->dev, "xmit-on=%llu\n", tx_ring->tx_stats.xmit_on,
tx_ring->xmit_on); tx_ring->tx_stats.xmit_off);
dev_info(&netdev->dev, "xmit-off=%llu\n",
tx_ring->xmit_off);
}
} }
adapter->ahw->reset_context = 1; adapter->ahw->reset_context = 1;
} }