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: Shreyas N Bhatewara <sbhatewara@vmware.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Shreyas Bhatewara 2011-01-14 14:59:47 +00:00 committed by David S. Miller
parent 39d4a96fd7
commit 76d39dae0a

View file

@ -68,6 +68,7 @@ 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 */
{ "Tx Queue#", 0 },
{ " TSO pkts tx", offsetof(struct UPT1_TxStats, TSOPktsTxOK) }, { " TSO pkts tx", offsetof(struct UPT1_TxStats, TSOPktsTxOK) },
{ " TSO bytes tx", offsetof(struct UPT1_TxStats, TSOBytesTxOK) }, { " TSO bytes tx", offsetof(struct UPT1_TxStats, TSOBytesTxOK) },
{ " ucast pkts tx", offsetof(struct UPT1_TxStats, ucastPktsTxOK) }, { " ucast pkts tx", offsetof(struct UPT1_TxStats, ucastPktsTxOK) },
@ -107,6 +108,7 @@ vmxnet3_tq_driver_stats[] = {
/* 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[] = {
{ "Rx Queue#", 0 },
{ " LRO pkts rx", offsetof(struct UPT1_RxStats, LROPktsRxOK) }, { " LRO pkts rx", offsetof(struct UPT1_RxStats, LROPktsRxOK) },
{ " LRO byte rx", offsetof(struct UPT1_RxStats, LROBytesRxOK) }, { " LRO byte rx", offsetof(struct UPT1_RxStats, LROBytesRxOK) },
{ " ucast pkts rx", offsetof(struct UPT1_RxStats, ucastPktsRxOK) }, { " ucast pkts rx", offsetof(struct UPT1_RxStats, ucastPktsRxOK) },
@ -115,7 +117,7 @@ vmxnet3_rq_dev_stats[] = {
{ " mcast bytes rx", offsetof(struct UPT1_RxStats, mcastBytesRxOK) }, { " mcast bytes rx", offsetof(struct UPT1_RxStats, mcastBytesRxOK) },
{ " bcast pkts rx", offsetof(struct UPT1_RxStats, bcastPktsRxOK) }, { " bcast pkts rx", offsetof(struct UPT1_RxStats, bcastPktsRxOK) },
{ " bcast bytes rx", offsetof(struct UPT1_RxStats, bcastBytesRxOK) }, { " bcast bytes rx", offsetof(struct UPT1_RxStats, bcastBytesRxOK) },
{ "pkts rx out of buf", offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) }, { " pkts rx OOB", offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) },
{ " pkts rx err", offsetof(struct UPT1_RxStats, pktsRxError) }, { " pkts rx err", offsetof(struct UPT1_RxStats, pktsRxError) },
}; };
@ -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)
} }
/* 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)
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);
i++) {
memcpy(buf, vmxnet3_tq_driver_stats[i].desc, memcpy(buf, vmxnet3_tq_driver_stats[i].desc,
ETH_GSTRING_LEN); ETH_GSTRING_LEN);
buf += ETH_GSTRING_LEN; buf += ETH_GSTRING_LEN;
} }
}
for (j = 0; j < adapter->num_rx_queues; j++) {
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) { for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) {
memcpy(buf, vmxnet3_rq_dev_stats[i].desc, memcpy(buf, vmxnet3_rq_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_rq_driver_stats); i++) { for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats);
i++) {
memcpy(buf, vmxnet3_rq_driver_stats[i].desc, memcpy(buf, vmxnet3_rq_driver_stats[i].desc,
ETH_GSTRING_LEN); ETH_GSTRING_LEN);
buf += 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,
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;
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) *buf++ = (u64)j;
*buf++ = *(u64 *)(base + vmxnet3_tq_dev_stats[i].offset); for (i = 1; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
*buf++ = *(u64 *)(base +
vmxnet3_tq_dev_stats[i].offset);
base = (u8 *)&adapter->tx_queue[j].stats; base = (u8 *)&adapter->tx_queue[j].stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
*buf++ = *(u64 *)(base + vmxnet3_tq_driver_stats[i].offset); *buf++ = *(u64 *)(base +
vmxnet3_tq_driver_stats[i].offset);
}
for (j = 0; j < adapter->num_tx_queues; j++) {
base = (u8 *)&adapter->rqd_start[j].stats; base = (u8 *)&adapter->rqd_start[j].stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) *buf++ = (u64) j;
*buf++ = *(u64 *)(base + vmxnet3_rq_dev_stats[i].offset); 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; base = (u8 *)&adapter->rx_queue[j].stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
*buf++ = *(u64 *)(base + vmxnet3_rq_driver_stats[i].offset); *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)
{ {
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)
/* 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; for (i = 0; i < adapter->num_rx_queues; i++) {
buf[9] = adapter->rx_queue[i].rx_ring[0].next2comp; buf[j++] = adapter->rx_queue[i].rx_ring[0].next2fill;
buf[10] = adapter->rx_queue[i].rx_ring[0].gen; buf[j++] = adapter->rx_queue[i].rx_ring[0].next2comp;
buf[11] = 0; buf[j++] = adapter->rx_queue[i].rx_ring[0].gen;
buf[j++] = 0;
buf[12] = adapter->rx_queue[i].rx_ring[1].next2fill; buf[j++] = adapter->rx_queue[i].rx_ring[1].next2fill;
buf[13] = adapter->rx_queue[i].rx_ring[1].next2comp; buf[j++] = 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].gen;
buf[15] = 0; buf[j++] = 0;
buf[j++] = adapter->rx_queue[i].comp_ring.next2proc;
buf[j++] = adapter->rx_queue[i].comp_ring.gen;
buf[j++] = 0;
buf[j++] = 0;
}
buf[16] = adapter->rx_queue[i].comp_ring.next2proc;
buf[17] = adapter->rx_queue[i].comp_ring.gen;
buf[18] = 0;
buf[19] = 0;
} }