aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/vmxnet3
diff options
context:
space:
mode:
authorShreyas Bhatewara <sbhatewara@vmware.com>2011-01-14 09:59:47 -0500
committerDavid S. Miller <davem@davemloft.net>2011-01-16 00:21:13 -0500
commit76d39dae0ad47f51291b4dd146b10d71e8ae02f7 (patch)
treecd0e69b340f09ebe114b18001c746624e983f88e /drivers/net/vmxnet3
parent39d4a96fd7d2926e46151adbd18b810aeeea8ec0 (diff)
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>
Diffstat (limited to 'drivers/net/vmxnet3')
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c259
1 files changed, 145 insertions, 114 deletions
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 8e17fc8a7fe7..d70cee17384d 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -68,76 +68,78 @@ vmxnet3_set_rx_csum(struct net_device *netdev, u32 val)
68static const struct vmxnet3_stat_desc 68static const struct vmxnet3_stat_desc
69vmxnet3_tq_dev_stats[] = { 69vmxnet3_tq_dev_stats[] = {
70 /* description, offset */ 70 /* description, offset */
71 { "TSO pkts tx", offsetof(struct UPT1_TxStats, TSOPktsTxOK) }, 71 { "Tx Queue#", 0 },
72 { "TSO bytes tx", offsetof(struct UPT1_TxStats, TSOBytesTxOK) }, 72 { " TSO pkts tx", offsetof(struct UPT1_TxStats, TSOPktsTxOK) },
73 { "ucast pkts tx", offsetof(struct UPT1_TxStats, ucastPktsTxOK) }, 73 { " TSO bytes tx", offsetof(struct UPT1_TxStats, TSOBytesTxOK) },
74 { "ucast bytes tx", offsetof(struct UPT1_TxStats, ucastBytesTxOK) }, 74 { " ucast pkts tx", offsetof(struct UPT1_TxStats, ucastPktsTxOK) },
75 { "mcast pkts tx", offsetof(struct UPT1_TxStats, mcastPktsTxOK) }, 75 { " ucast bytes tx", offsetof(struct UPT1_TxStats, ucastBytesTxOK) },
76 { "mcast bytes tx", offsetof(struct UPT1_TxStats, mcastBytesTxOK) }, 76 { " mcast pkts tx", offsetof(struct UPT1_TxStats, mcastPktsTxOK) },
77 { "bcast pkts tx", offsetof(struct UPT1_TxStats, bcastPktsTxOK) }, 77 { " mcast bytes tx", offsetof(struct UPT1_TxStats, mcastBytesTxOK) },
78 { "bcast bytes tx", offsetof(struct UPT1_TxStats, bcastBytesTxOK) }, 78 { " bcast pkts tx", offsetof(struct UPT1_TxStats, bcastPktsTxOK) },
79 { "pkts tx err", offsetof(struct UPT1_TxStats, pktsTxError) }, 79 { " bcast bytes tx", offsetof(struct UPT1_TxStats, bcastBytesTxOK) },
80 { "pkts tx discard", offsetof(struct UPT1_TxStats, pktsTxDiscard) }, 80 { " pkts tx err", offsetof(struct UPT1_TxStats, pktsTxError) },
81 { " pkts tx discard", offsetof(struct UPT1_TxStats, pktsTxDiscard) },
81}; 82};
82 83
83/* per tq stats maintained by the driver */ 84/* per tq stats maintained by the driver */
84static const struct vmxnet3_stat_desc 85static const struct vmxnet3_stat_desc
85vmxnet3_tq_driver_stats[] = { 86vmxnet3_tq_driver_stats[] = {
86 /* description, offset */ 87 /* description, offset */
87 {"drv dropped tx total", offsetof(struct vmxnet3_tq_driver_stats, 88 {" drv dropped tx total", offsetof(struct vmxnet3_tq_driver_stats,
88 drop_total) }, 89 drop_total) },
89 { " too many frags", offsetof(struct vmxnet3_tq_driver_stats, 90 { " too many frags", offsetof(struct vmxnet3_tq_driver_stats,
90 drop_too_many_frags) }, 91 drop_too_many_frags) },
91 { " giant hdr", offsetof(struct vmxnet3_tq_driver_stats, 92 { " giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
92 drop_oversized_hdr) }, 93 drop_oversized_hdr) },
93 { " hdr err", offsetof(struct vmxnet3_tq_driver_stats, 94 { " hdr err", offsetof(struct vmxnet3_tq_driver_stats,
94 drop_hdr_inspect_err) }, 95 drop_hdr_inspect_err) },
95 { " tso", offsetof(struct vmxnet3_tq_driver_stats, 96 { " tso", offsetof(struct vmxnet3_tq_driver_stats,
96 drop_tso) }, 97 drop_tso) },
97 { "ring full", offsetof(struct vmxnet3_tq_driver_stats, 98 { " ring full", offsetof(struct vmxnet3_tq_driver_stats,
98 tx_ring_full) }, 99 tx_ring_full) },
99 { "pkts linearized", offsetof(struct vmxnet3_tq_driver_stats, 100 { " pkts linearized", offsetof(struct vmxnet3_tq_driver_stats,
100 linearized) }, 101 linearized) },
101 { "hdr cloned", offsetof(struct vmxnet3_tq_driver_stats, 102 { " hdr cloned", offsetof(struct vmxnet3_tq_driver_stats,
102 copy_skb_header) }, 103 copy_skb_header) },
103 { "giant hdr", offsetof(struct vmxnet3_tq_driver_stats, 104 { " giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
104 oversized_hdr) }, 105 oversized_hdr) },
105}; 106};
106 107
107/* per rq stats maintained by the device */ 108/* per rq stats maintained by the device */
108static const struct vmxnet3_stat_desc 109static const struct vmxnet3_stat_desc
109vmxnet3_rq_dev_stats[] = { 110vmxnet3_rq_dev_stats[] = {
110 { "LRO pkts rx", offsetof(struct UPT1_RxStats, LROPktsRxOK) }, 111 { "Rx Queue#", 0 },
111 { "LRO byte rx", offsetof(struct UPT1_RxStats, LROBytesRxOK) }, 112 { " LRO pkts rx", offsetof(struct UPT1_RxStats, LROPktsRxOK) },
112 { "ucast pkts rx", offsetof(struct UPT1_RxStats, ucastPktsRxOK) }, 113 { " LRO byte rx", offsetof(struct UPT1_RxStats, LROBytesRxOK) },
113 { "ucast bytes rx", offsetof(struct UPT1_RxStats, ucastBytesRxOK) }, 114 { " ucast pkts rx", offsetof(struct UPT1_RxStats, ucastPktsRxOK) },
114 { "mcast pkts rx", offsetof(struct UPT1_RxStats, mcastPktsRxOK) }, 115 { " ucast bytes rx", offsetof(struct UPT1_RxStats, ucastBytesRxOK) },
115 { "mcast bytes rx", offsetof(struct UPT1_RxStats, mcastBytesRxOK) }, 116 { " mcast pkts rx", offsetof(struct UPT1_RxStats, mcastPktsRxOK) },
116 { "bcast pkts rx", offsetof(struct UPT1_RxStats, bcastPktsRxOK) }, 117 { " mcast bytes rx", offsetof(struct UPT1_RxStats, mcastBytesRxOK) },
117 { "bcast bytes rx", offsetof(struct UPT1_RxStats, bcastBytesRxOK) }, 118 { " bcast pkts rx", offsetof(struct UPT1_RxStats, bcastPktsRxOK) },
118 { "pkts rx out of buf", offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) }, 119 { " bcast bytes rx", offsetof(struct UPT1_RxStats, bcastBytesRxOK) },
119 { "pkts rx err", offsetof(struct UPT1_RxStats, pktsRxError) }, 120 { " pkts rx OOB", offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) },
121 { " pkts rx err", offsetof(struct UPT1_RxStats, pktsRxError) },
120}; 122};
121 123
122/* per rq stats maintained by the driver */ 124/* per rq stats maintained by the driver */
123static const struct vmxnet3_stat_desc 125static const struct vmxnet3_stat_desc
124vmxnet3_rq_driver_stats[] = { 126vmxnet3_rq_driver_stats[] = {
125 /* description, offset */ 127 /* description, offset */
126 { "drv dropped rx total", offsetof(struct vmxnet3_rq_driver_stats, 128 { " drv dropped rx total", offsetof(struct vmxnet3_rq_driver_stats,
127 drop_total) }, 129 drop_total) },
128 { " err", offsetof(struct vmxnet3_rq_driver_stats, 130 { " err", offsetof(struct vmxnet3_rq_driver_stats,
129 drop_err) }, 131 drop_err) },
130 { " fcs", offsetof(struct vmxnet3_rq_driver_stats, 132 { " fcs", offsetof(struct vmxnet3_rq_driver_stats,
131 drop_fcs) }, 133 drop_fcs) },
132 { "rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats, 134 { " rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats,
133 rx_buf_alloc_failure) }, 135 rx_buf_alloc_failure) },
134}; 136};
135 137
136/* gloabl stats maintained by the driver */ 138/* gloabl stats maintained by the driver */
137static const struct vmxnet3_stat_desc 139static const struct vmxnet3_stat_desc
138vmxnet3_global_stats[] = { 140vmxnet3_global_stats[] = {
139 /* description, offset */ 141 /* description, offset */
140 { "tx timeout count", offsetof(struct vmxnet3_adapter, 142 { "tx timeout count", offsetof(struct vmxnet3_adapter,
141 tx_timeout_count) } 143 tx_timeout_count) }
142}; 144};
143 145
@@ -193,12 +195,15 @@ vmxnet3_get_stats(struct net_device *netdev)
193static int 195static int
194vmxnet3_get_sset_count(struct net_device *netdev, int sset) 196vmxnet3_get_sset_count(struct net_device *netdev, int sset)
195{ 197{
198 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
196 switch (sset) { 199 switch (sset) {
197 case ETH_SS_STATS: 200 case ETH_SS_STATS:
198 return ARRAY_SIZE(vmxnet3_tq_dev_stats) + 201 return (ARRAY_SIZE(vmxnet3_tq_dev_stats) +
199 ARRAY_SIZE(vmxnet3_tq_driver_stats) + 202 ARRAY_SIZE(vmxnet3_tq_driver_stats)) *
200 ARRAY_SIZE(vmxnet3_rq_dev_stats) + 203 adapter->num_tx_queues +
201 ARRAY_SIZE(vmxnet3_rq_driver_stats) + 204 (ARRAY_SIZE(vmxnet3_rq_dev_stats) +
205 ARRAY_SIZE(vmxnet3_rq_driver_stats)) *
206 adapter->num_rx_queues +
202 ARRAY_SIZE(vmxnet3_global_stats); 207 ARRAY_SIZE(vmxnet3_global_stats);
203 default: 208 default:
204 return -EOPNOTSUPP; 209 return -EOPNOTSUPP;
@@ -206,10 +211,16 @@ vmxnet3_get_sset_count(struct net_device *netdev, int sset)
206} 211}
207 212
208 213
214/* Should be multiple of 4 */
215#define NUM_TX_REGS 8
216#define NUM_RX_REGS 12
217
209static int 218static int
210vmxnet3_get_regs_len(struct net_device *netdev) 219vmxnet3_get_regs_len(struct net_device *netdev)
211{ 220{
212 return 20 * sizeof(u32); 221 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
222 return (adapter->num_tx_queues * NUM_TX_REGS * sizeof(u32) +
223 adapter->num_rx_queues * NUM_RX_REGS * sizeof(u32));
213} 224}
214 225
215 226
@@ -240,29 +251,37 @@ vmxnet3_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
240static void 251static void
241vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) 252vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
242{ 253{
254 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
243 if (stringset == ETH_SS_STATS) { 255 if (stringset == ETH_SS_STATS) {
244 int i; 256 int i, j;
245 257 for (j = 0; j < adapter->num_tx_queues; j++) {
246 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) { 258 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) {
247 memcpy(buf, vmxnet3_tq_dev_stats[i].desc, 259 memcpy(buf, vmxnet3_tq_dev_stats[i].desc,
248 ETH_GSTRING_LEN); 260 ETH_GSTRING_LEN);
249 buf += ETH_GSTRING_LEN; 261 buf += ETH_GSTRING_LEN;
250 } 262 }
251 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) { 263 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats);
252 memcpy(buf, vmxnet3_tq_driver_stats[i].desc, 264 i++) {
253 ETH_GSTRING_LEN); 265 memcpy(buf, vmxnet3_tq_driver_stats[i].desc,
254 buf += ETH_GSTRING_LEN; 266 ETH_GSTRING_LEN);
255 } 267 buf += ETH_GSTRING_LEN;
256 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) { 268 }
257 memcpy(buf, vmxnet3_rq_dev_stats[i].desc,
258 ETH_GSTRING_LEN);
259 buf += ETH_GSTRING_LEN;
260 } 269 }
261 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) { 270
262 memcpy(buf, vmxnet3_rq_driver_stats[i].desc, 271 for (j = 0; j < adapter->num_rx_queues; j++) {
263 ETH_GSTRING_LEN); 272 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) {
264 buf += ETH_GSTRING_LEN; 273 memcpy(buf, vmxnet3_rq_dev_stats[i].desc,
274 ETH_GSTRING_LEN);
275 buf += ETH_GSTRING_LEN;
276 }
277 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats);
278 i++) {
279 memcpy(buf, vmxnet3_rq_driver_stats[i].desc,
280 ETH_GSTRING_LEN);
281 buf += ETH_GSTRING_LEN;
282 }
265 } 283 }
284
266 for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) { 285 for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) {
267 memcpy(buf, vmxnet3_global_stats[i].desc, 286 memcpy(buf, vmxnet3_global_stats[i].desc,
268 ETH_GSTRING_LEN); 287 ETH_GSTRING_LEN);
@@ -310,23 +329,31 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev,
310 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS); 329 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
311 330
312 /* this does assume each counter is 64-bit wide */ 331 /* this does assume each counter is 64-bit wide */
313/* TODO change this for multiple queues */ 332 for (j = 0; j < adapter->num_tx_queues; j++) {
314 333 base = (u8 *)&adapter->tqd_start[j].stats;
315 base = (u8 *)&adapter->tqd_start[j].stats; 334 *buf++ = (u64)j;
316 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) 335 for (i = 1; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
317 *buf++ = *(u64 *)(base + vmxnet3_tq_dev_stats[i].offset); 336 *buf++ = *(u64 *)(base +
318 337 vmxnet3_tq_dev_stats[i].offset);
319 base = (u8 *)&adapter->tx_queue[j].stats; 338
320 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) 339 base = (u8 *)&adapter->tx_queue[j].stats;
321 *buf++ = *(u64 *)(base + vmxnet3_tq_driver_stats[i].offset); 340 for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
322 341 *buf++ = *(u64 *)(base +
323 base = (u8 *)&adapter->rqd_start[j].stats; 342 vmxnet3_tq_driver_stats[i].offset);
324 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) 343 }
325 *buf++ = *(u64 *)(base + vmxnet3_rq_dev_stats[i].offset);
326 344
327 base = (u8 *)&adapter->rx_queue[j].stats; 345 for (j = 0; j < adapter->num_tx_queues; j++) {
328 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) 346 base = (u8 *)&adapter->rqd_start[j].stats;
329 *buf++ = *(u64 *)(base + vmxnet3_rq_driver_stats[i].offset); 347 *buf++ = (u64) j;
348 for (i = 1; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
349 *buf++ = *(u64 *)(base +
350 vmxnet3_rq_dev_stats[i].offset);
351
352 base = (u8 *)&adapter->rx_queue[j].stats;
353 for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
354 *buf++ = *(u64 *)(base +
355 vmxnet3_rq_driver_stats[i].offset);
356 }
330 357
331 base = (u8 *)adapter; 358 base = (u8 *)adapter;
332 for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) 359 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{ 366{
340 struct vmxnet3_adapter *adapter = netdev_priv(netdev); 367 struct vmxnet3_adapter *adapter = netdev_priv(netdev);
341 u32 *buf = p; 368 u32 *buf = p;
342 int i = 0; 369 int i = 0, j = 0;
343 370
344 memset(p, 0, vmxnet3_get_regs_len(netdev)); 371 memset(p, 0, vmxnet3_get_regs_len(netdev));
345 372
@@ -348,31 +375,35 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
348 /* Update vmxnet3_get_regs_len if we want to dump more registers */ 375 /* Update vmxnet3_get_regs_len if we want to dump more registers */
349 376
350 /* make each ring use multiple of 16 bytes */ 377 /* make each ring use multiple of 16 bytes */
351/* TODO change this for multiple queues */ 378 for (i = 0; i < adapter->num_tx_queues; i++) {
352 buf[0] = adapter->tx_queue[i].tx_ring.next2fill; 379 buf[j++] = adapter->tx_queue[i].tx_ring.next2fill;
353 buf[1] = adapter->tx_queue[i].tx_ring.next2comp; 380 buf[j++] = adapter->tx_queue[i].tx_ring.next2comp;
354 buf[2] = adapter->tx_queue[i].tx_ring.gen; 381 buf[j++] = adapter->tx_queue[i].tx_ring.gen;
355 buf[3] = 0; 382 buf[j++] = 0;
356 383
357 buf[4] = adapter->tx_queue[i].comp_ring.next2proc; 384 buf[j++] = adapter->tx_queue[i].comp_ring.next2proc;
358 buf[5] = adapter->tx_queue[i].comp_ring.gen; 385 buf[j++] = adapter->tx_queue[i].comp_ring.gen;
359 buf[6] = adapter->tx_queue[i].stopped; 386 buf[j++] = adapter->tx_queue[i].stopped;
360 buf[7] = 0; 387 buf[j++] = 0;
361 388 }
362 buf[8] = adapter->rx_queue[i].rx_ring[0].next2fill; 389
363 buf[9] = adapter->rx_queue[i].rx_ring[0].next2comp; 390 for (i = 0; i < adapter->num_rx_queues; i++) {
364 buf[10] = adapter->rx_queue[i].rx_ring[0].gen; 391 buf[j++] = adapter->rx_queue[i].rx_ring[0].next2fill;
365 buf[11] = 0; 392 buf[j++] = adapter->rx_queue[i].rx_ring[0].next2comp;
366 393 buf[j++] = adapter->rx_queue[i].rx_ring[0].gen;
367 buf[12] = adapter->rx_queue[i].rx_ring[1].next2fill; 394 buf[j++] = 0;
368 buf[13] = adapter->rx_queue[i].rx_ring[1].next2comp; 395
369 buf[14] = adapter->rx_queue[i].rx_ring[1].gen; 396 buf[j++] = adapter->rx_queue[i].rx_ring[1].next2fill;
370 buf[15] = 0; 397 buf[j++] = adapter->rx_queue[i].rx_ring[1].next2comp;
371 398 buf[j++] = adapter->rx_queue[i].rx_ring[1].gen;
372 buf[16] = adapter->rx_queue[i].comp_ring.next2proc; 399 buf[j++] = 0;
373 buf[17] = adapter->rx_queue[i].comp_ring.gen; 400
374 buf[18] = 0; 401 buf[j++] = adapter->rx_queue[i].comp_ring.next2proc;
375 buf[19] = 0; 402 buf[j++] = adapter->rx_queue[i].comp_ring.gen;
403 buf[j++] = 0;
404 buf[j++] = 0;
405 }
406
376} 407}
377 408
378 409