Commit 76d39dae authored by Shreyas Bhatewara's avatar Shreyas Bhatewara Committed by David S. Miller

vmxnet3: Make ethtool handlers multiqueue aware

Show per-queue stats in ethtool -S output for vmxnet3 interface. Register dump
of ethtool should dump registers for all tx and rx queues.
Signed-off-by: default avatarShreyas N Bhatewara <sbhatewara@vmware.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 39d4a96f
...@@ -68,76 +68,78 @@ vmxnet3_set_rx_csum(struct net_device *netdev, u32 val) ...@@ -68,76 +68,78 @@ vmxnet3_set_rx_csum(struct net_device *netdev, u32 val)
static const struct vmxnet3_stat_desc static const struct vmxnet3_stat_desc
vmxnet3_tq_dev_stats[] = { vmxnet3_tq_dev_stats[] = {
/* description, offset */ /* description, offset */
{ "TSO pkts tx", offsetof(struct UPT1_TxStats, TSOPktsTxOK) }, { "Tx Queue#", 0 },
{ "TSO bytes tx", offsetof(struct UPT1_TxStats, TSOBytesTxOK) }, { " TSO pkts tx", offsetof(struct UPT1_TxStats, TSOPktsTxOK) },
{ "ucast pkts tx", offsetof(struct UPT1_TxStats, ucastPktsTxOK) }, { " TSO bytes tx", offsetof(struct UPT1_TxStats, TSOBytesTxOK) },
{ "ucast bytes tx", offsetof(struct UPT1_TxStats, ucastBytesTxOK) }, { " ucast pkts tx", offsetof(struct UPT1_TxStats, ucastPktsTxOK) },
{ "mcast pkts tx", offsetof(struct UPT1_TxStats, mcastPktsTxOK) }, { " ucast bytes tx", offsetof(struct UPT1_TxStats, ucastBytesTxOK) },
{ "mcast bytes tx", offsetof(struct UPT1_TxStats, mcastBytesTxOK) }, { " mcast pkts tx", offsetof(struct UPT1_TxStats, mcastPktsTxOK) },
{ "bcast pkts tx", offsetof(struct UPT1_TxStats, bcastPktsTxOK) }, { " mcast bytes tx", offsetof(struct UPT1_TxStats, mcastBytesTxOK) },
{ "bcast bytes tx", offsetof(struct UPT1_TxStats, bcastBytesTxOK) }, { " bcast pkts tx", offsetof(struct UPT1_TxStats, bcastPktsTxOK) },
{ "pkts tx err", offsetof(struct UPT1_TxStats, pktsTxError) }, { " bcast bytes tx", offsetof(struct UPT1_TxStats, bcastBytesTxOK) },
{ "pkts tx discard", offsetof(struct UPT1_TxStats, pktsTxDiscard) }, { " pkts tx err", offsetof(struct UPT1_TxStats, pktsTxError) },
{ " pkts tx discard", offsetof(struct UPT1_TxStats, pktsTxDiscard) },
}; };
/* per tq stats maintained by the driver */ /* per tq stats maintained by the driver */
static const struct vmxnet3_stat_desc static const struct vmxnet3_stat_desc
vmxnet3_tq_driver_stats[] = { vmxnet3_tq_driver_stats[] = {
/* description, offset */ /* description, offset */
{"drv dropped tx total", offsetof(struct vmxnet3_tq_driver_stats, {" drv dropped tx total", offsetof(struct vmxnet3_tq_driver_stats,
drop_total) }, drop_total) },
{ " too many frags", offsetof(struct vmxnet3_tq_driver_stats, { " too many frags", offsetof(struct vmxnet3_tq_driver_stats,
drop_too_many_frags) }, drop_too_many_frags) },
{ " giant hdr", offsetof(struct vmxnet3_tq_driver_stats, { " giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
drop_oversized_hdr) }, drop_oversized_hdr) },
{ " hdr err", offsetof(struct vmxnet3_tq_driver_stats, { " hdr err", offsetof(struct vmxnet3_tq_driver_stats,
drop_hdr_inspect_err) }, drop_hdr_inspect_err) },
{ " tso", offsetof(struct vmxnet3_tq_driver_stats, { " tso", offsetof(struct vmxnet3_tq_driver_stats,
drop_tso) }, drop_tso) },
{ "ring full", offsetof(struct vmxnet3_tq_driver_stats, { " ring full", offsetof(struct vmxnet3_tq_driver_stats,
tx_ring_full) }, tx_ring_full) },
{ "pkts linearized", offsetof(struct vmxnet3_tq_driver_stats, { " pkts linearized", offsetof(struct vmxnet3_tq_driver_stats,
linearized) }, linearized) },
{ "hdr cloned", offsetof(struct vmxnet3_tq_driver_stats, { " hdr cloned", offsetof(struct vmxnet3_tq_driver_stats,
copy_skb_header) }, copy_skb_header) },
{ "giant hdr", offsetof(struct vmxnet3_tq_driver_stats, { " giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
oversized_hdr) }, oversized_hdr) },
}; };
/* per rq stats maintained by the device */ /* per rq stats maintained by the device */
static const struct vmxnet3_stat_desc static const struct vmxnet3_stat_desc
vmxnet3_rq_dev_stats[] = { vmxnet3_rq_dev_stats[] = {
{ "LRO pkts rx", offsetof(struct UPT1_RxStats, LROPktsRxOK) }, { "Rx Queue#", 0 },
{ "LRO byte rx", offsetof(struct UPT1_RxStats, LROBytesRxOK) }, { " LRO pkts rx", offsetof(struct UPT1_RxStats, LROPktsRxOK) },
{ "ucast pkts rx", offsetof(struct UPT1_RxStats, ucastPktsRxOK) }, { " LRO byte rx", offsetof(struct UPT1_RxStats, LROBytesRxOK) },
{ "ucast bytes rx", offsetof(struct UPT1_RxStats, ucastBytesRxOK) }, { " ucast pkts rx", offsetof(struct UPT1_RxStats, ucastPktsRxOK) },
{ "mcast pkts rx", offsetof(struct UPT1_RxStats, mcastPktsRxOK) }, { " ucast bytes rx", offsetof(struct UPT1_RxStats, ucastBytesRxOK) },
{ "mcast bytes rx", offsetof(struct UPT1_RxStats, mcastBytesRxOK) }, { " mcast pkts rx", offsetof(struct UPT1_RxStats, mcastPktsRxOK) },
{ "bcast pkts rx", offsetof(struct UPT1_RxStats, bcastPktsRxOK) }, { " mcast bytes rx", offsetof(struct UPT1_RxStats, mcastBytesRxOK) },
{ "bcast bytes rx", offsetof(struct UPT1_RxStats, bcastBytesRxOK) }, { " bcast pkts rx", offsetof(struct UPT1_RxStats, bcastPktsRxOK) },
{ "pkts rx out of buf", offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) }, { " bcast bytes rx", offsetof(struct UPT1_RxStats, bcastBytesRxOK) },
{ "pkts rx err", offsetof(struct UPT1_RxStats, pktsRxError) }, { " pkts rx OOB", offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) },
{ " pkts rx err", offsetof(struct UPT1_RxStats, pktsRxError) },
}; };
/* per rq stats maintained by the driver */ /* per rq stats maintained by the driver */
static const struct vmxnet3_stat_desc static const struct vmxnet3_stat_desc
vmxnet3_rq_driver_stats[] = { vmxnet3_rq_driver_stats[] = {
/* description, offset */ /* description, offset */
{ "drv dropped rx total", offsetof(struct vmxnet3_rq_driver_stats, { " drv dropped rx total", offsetof(struct vmxnet3_rq_driver_stats,
drop_total) }, drop_total) },
{ " err", offsetof(struct vmxnet3_rq_driver_stats, { " err", offsetof(struct vmxnet3_rq_driver_stats,
drop_err) }, drop_err) },
{ " fcs", offsetof(struct vmxnet3_rq_driver_stats, { " fcs", offsetof(struct vmxnet3_rq_driver_stats,
drop_fcs) }, drop_fcs) },
{ "rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats, { " rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats,
rx_buf_alloc_failure) }, rx_buf_alloc_failure) },
}; };
/* gloabl stats maintained by the driver */ /* gloabl stats maintained by the driver */
static const struct vmxnet3_stat_desc static const struct vmxnet3_stat_desc
vmxnet3_global_stats[] = { vmxnet3_global_stats[] = {
/* description, offset */ /* description, offset */
{ "tx timeout count", offsetof(struct vmxnet3_adapter, { "tx timeout count", offsetof(struct vmxnet3_adapter,
tx_timeout_count) } tx_timeout_count) }
}; };
...@@ -193,12 +195,15 @@ vmxnet3_get_stats(struct net_device *netdev) ...@@ -193,12 +195,15 @@ vmxnet3_get_stats(struct net_device *netdev)
static int static int
vmxnet3_get_sset_count(struct net_device *netdev, int sset) vmxnet3_get_sset_count(struct net_device *netdev, int sset)
{ {
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
switch (sset) { switch (sset) {
case ETH_SS_STATS: case ETH_SS_STATS:
return ARRAY_SIZE(vmxnet3_tq_dev_stats) + return (ARRAY_SIZE(vmxnet3_tq_dev_stats) +
ARRAY_SIZE(vmxnet3_tq_driver_stats) + ARRAY_SIZE(vmxnet3_tq_driver_stats)) *
ARRAY_SIZE(vmxnet3_rq_dev_stats) + adapter->num_tx_queues +
ARRAY_SIZE(vmxnet3_rq_driver_stats) + (ARRAY_SIZE(vmxnet3_rq_dev_stats) +
ARRAY_SIZE(vmxnet3_rq_driver_stats)) *
adapter->num_rx_queues +
ARRAY_SIZE(vmxnet3_global_stats); ARRAY_SIZE(vmxnet3_global_stats);
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -206,10 +211,16 @@ vmxnet3_get_sset_count(struct net_device *netdev, int sset) ...@@ -206,10 +211,16 @@ vmxnet3_get_sset_count(struct net_device *netdev, int sset)
} }
/* Should be multiple of 4 */
#define NUM_TX_REGS 8
#define NUM_RX_REGS 12
static int static int
vmxnet3_get_regs_len(struct net_device *netdev) vmxnet3_get_regs_len(struct net_device *netdev)
{ {
return 20 * sizeof(u32); struct vmxnet3_adapter *adapter = netdev_priv(netdev);
return (adapter->num_tx_queues * NUM_TX_REGS * sizeof(u32) +
adapter->num_rx_queues * NUM_RX_REGS * sizeof(u32));
} }
...@@ -240,29 +251,37 @@ vmxnet3_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) ...@@ -240,29 +251,37 @@ vmxnet3_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
static void static void
vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
{ {
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
if (stringset == ETH_SS_STATS) { if (stringset == ETH_SS_STATS) {
int i; int i, j;
for (j = 0; j < adapter->num_tx_queues; j++) {
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) { for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) {
memcpy(buf, vmxnet3_tq_dev_stats[i].desc, memcpy(buf, vmxnet3_tq_dev_stats[i].desc,
ETH_GSTRING_LEN); ETH_GSTRING_LEN);
buf += ETH_GSTRING_LEN; buf += ETH_GSTRING_LEN;
} }
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) { for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats);
memcpy(buf, vmxnet3_tq_driver_stats[i].desc, i++) {
ETH_GSTRING_LEN); memcpy(buf, vmxnet3_tq_driver_stats[i].desc,
buf += ETH_GSTRING_LEN; ETH_GSTRING_LEN);
} buf += ETH_GSTRING_LEN;
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) { }
memcpy(buf, vmxnet3_rq_dev_stats[i].desc,
ETH_GSTRING_LEN);
buf += ETH_GSTRING_LEN;
} }
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) {
memcpy(buf, vmxnet3_rq_driver_stats[i].desc, for (j = 0; j < adapter->num_rx_queues; j++) {
ETH_GSTRING_LEN); for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) {
buf += ETH_GSTRING_LEN; memcpy(buf, vmxnet3_rq_dev_stats[i].desc,
ETH_GSTRING_LEN);
buf += ETH_GSTRING_LEN;
}
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats);
i++) {
memcpy(buf, vmxnet3_rq_driver_stats[i].desc,
ETH_GSTRING_LEN);
buf += ETH_GSTRING_LEN;
}
} }
for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) { for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) {
memcpy(buf, vmxnet3_global_stats[i].desc, memcpy(buf, vmxnet3_global_stats[i].desc,
ETH_GSTRING_LEN); ETH_GSTRING_LEN);
...@@ -310,23 +329,31 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev, ...@@ -310,23 +329,31 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev,
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
/* this does assume each counter is 64-bit wide */ /* this does assume each counter is 64-bit wide */
/* TODO change this for multiple queues */ for (j = 0; j < adapter->num_tx_queues; j++) {
base = (u8 *)&adapter->tqd_start[j].stats;
base = (u8 *)&adapter->tqd_start[j].stats; *buf++ = (u64)j;
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) for (i = 1; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
*buf++ = *(u64 *)(base + vmxnet3_tq_dev_stats[i].offset); *buf++ = *(u64 *)(base +
vmxnet3_tq_dev_stats[i].offset);
base = (u8 *)&adapter->tx_queue[j].stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) base = (u8 *)&adapter->tx_queue[j].stats;
*buf++ = *(u64 *)(base + vmxnet3_tq_driver_stats[i].offset); for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
*buf++ = *(u64 *)(base +
base = (u8 *)&adapter->rqd_start[j].stats; vmxnet3_tq_driver_stats[i].offset);
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) }
*buf++ = *(u64 *)(base + vmxnet3_rq_dev_stats[i].offset);
base = (u8 *)&adapter->rx_queue[j].stats; for (j = 0; j < adapter->num_tx_queues; j++) {
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) base = (u8 *)&adapter->rqd_start[j].stats;
*buf++ = *(u64 *)(base + vmxnet3_rq_driver_stats[i].offset); *buf++ = (u64) j;
for (i = 1; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
*buf++ = *(u64 *)(base +
vmxnet3_rq_dev_stats[i].offset);
base = (u8 *)&adapter->rx_queue[j].stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
*buf++ = *(u64 *)(base +
vmxnet3_rq_driver_stats[i].offset);
}
base = (u8 *)adapter; base = (u8 *)adapter;
for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++)
...@@ -339,7 +366,7 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) ...@@ -339,7 +366,7 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
{ {
struct vmxnet3_adapter *adapter = netdev_priv(netdev); struct vmxnet3_adapter *adapter = netdev_priv(netdev);
u32 *buf = p; u32 *buf = p;
int i = 0; int i = 0, j = 0;
memset(p, 0, vmxnet3_get_regs_len(netdev)); memset(p, 0, vmxnet3_get_regs_len(netdev));
...@@ -348,31 +375,35 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) ...@@ -348,31 +375,35 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
/* Update vmxnet3_get_regs_len if we want to dump more registers */ /* Update vmxnet3_get_regs_len if we want to dump more registers */
/* make each ring use multiple of 16 bytes */ /* make each ring use multiple of 16 bytes */
/* TODO change this for multiple queues */ for (i = 0; i < adapter->num_tx_queues; i++) {
buf[0] = adapter->tx_queue[i].tx_ring.next2fill; buf[j++] = adapter->tx_queue[i].tx_ring.next2fill;
buf[1] = adapter->tx_queue[i].tx_ring.next2comp; buf[j++] = adapter->tx_queue[i].tx_ring.next2comp;
buf[2] = adapter->tx_queue[i].tx_ring.gen; buf[j++] = adapter->tx_queue[i].tx_ring.gen;
buf[3] = 0; buf[j++] = 0;
buf[4] = adapter->tx_queue[i].comp_ring.next2proc; buf[j++] = adapter->tx_queue[i].comp_ring.next2proc;
buf[5] = adapter->tx_queue[i].comp_ring.gen; buf[j++] = adapter->tx_queue[i].comp_ring.gen;
buf[6] = adapter->tx_queue[i].stopped; buf[j++] = adapter->tx_queue[i].stopped;
buf[7] = 0; buf[j++] = 0;
}
buf[8] = adapter->rx_queue[i].rx_ring[0].next2fill;
buf[9] = adapter->rx_queue[i].rx_ring[0].next2comp; for (i = 0; i < adapter->num_rx_queues; i++) {
buf[10] = adapter->rx_queue[i].rx_ring[0].gen; buf[j++] = adapter->rx_queue[i].rx_ring[0].next2fill;
buf[11] = 0; buf[j++] = adapter->rx_queue[i].rx_ring[0].next2comp;
buf[j++] = adapter->rx_queue[i].rx_ring[0].gen;
buf[12] = adapter->rx_queue[i].rx_ring[1].next2fill; buf[j++] = 0;
buf[13] = adapter->rx_queue[i].rx_ring[1].next2comp;
buf[14] = adapter->rx_queue[i].rx_ring[1].gen; buf[j++] = adapter->rx_queue[i].rx_ring[1].next2fill;
buf[15] = 0; buf[j++] = adapter->rx_queue[i].rx_ring[1].next2comp;
buf[j++] = adapter->rx_queue[i].rx_ring[1].gen;
buf[16] = adapter->rx_queue[i].comp_ring.next2proc; buf[j++] = 0;
buf[17] = adapter->rx_queue[i].comp_ring.gen;
buf[18] = 0; buf[j++] = adapter->rx_queue[i].comp_ring.next2proc;
buf[19] = 0; buf[j++] = adapter->rx_queue[i].comp_ring.gen;
buf[j++] = 0;
buf[j++] = 0;
}
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment