aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/qlge/qlge_ethtool.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/qlge/qlge_ethtool.c')
-rw-r--r--drivers/net/qlge/qlge_ethtool.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index 62c4af057800..058fa0a48c6f 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -36,6 +36,11 @@
36 36
37#include "qlge.h" 37#include "qlge.h"
38 38
39static const char ql_gstrings_test[][ETH_GSTRING_LEN] = {
40 "Loopback test (offline)"
41};
42#define QLGE_TEST_LEN (sizeof(ql_gstrings_test) / ETH_GSTRING_LEN)
43
39static int ql_update_ring_coalescing(struct ql_adapter *qdev) 44static int ql_update_ring_coalescing(struct ql_adapter *qdev)
40{ 45{
41 int i, status = 0; 46 int i, status = 0;
@@ -251,6 +256,8 @@ static void ql_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
251static int ql_get_sset_count(struct net_device *dev, int sset) 256static int ql_get_sset_count(struct net_device *dev, int sset)
252{ 257{
253 switch (sset) { 258 switch (sset) {
259 case ETH_SS_TEST:
260 return QLGE_TEST_LEN;
254 case ETH_SS_STATS: 261 case ETH_SS_STATS:
255 return ARRAY_SIZE(ql_stats_str_arr); 262 return ARRAY_SIZE(ql_stats_str_arr);
256 default: 263 default:
@@ -429,6 +436,110 @@ static int ql_phys_id(struct net_device *ndev, u32 data)
429 return 0; 436 return 0;
430} 437}
431 438
439static int ql_start_loopback(struct ql_adapter *qdev)
440{
441 if (netif_carrier_ok(qdev->ndev)) {
442 set_bit(QL_LB_LINK_UP, &qdev->flags);
443 netif_carrier_off(qdev->ndev);
444 } else
445 clear_bit(QL_LB_LINK_UP, &qdev->flags);
446 qdev->link_config |= CFG_LOOPBACK_PCS;
447 return ql_mb_set_port_cfg(qdev);
448}
449
450static void ql_stop_loopback(struct ql_adapter *qdev)
451{
452 qdev->link_config &= ~CFG_LOOPBACK_PCS;
453 ql_mb_set_port_cfg(qdev);
454 if (test_bit(QL_LB_LINK_UP, &qdev->flags)) {
455 netif_carrier_on(qdev->ndev);
456 clear_bit(QL_LB_LINK_UP, &qdev->flags);
457 }
458}
459
460static void ql_create_lb_frame(struct sk_buff *skb,
461 unsigned int frame_size)
462{
463 memset(skb->data, 0xFF, frame_size);
464 frame_size &= ~1;
465 memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
466 memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
467 memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
468}
469
470void ql_check_lb_frame(struct ql_adapter *qdev,
471 struct sk_buff *skb)
472{
473 unsigned int frame_size = skb->len;
474
475 if ((*(skb->data + 3) == 0xFF) &&
476 (*(skb->data + frame_size / 2 + 10) == 0xBE) &&
477 (*(skb->data + frame_size / 2 + 12) == 0xAF)) {
478 atomic_dec(&qdev->lb_count);
479 return;
480 }
481}
482
483static int ql_run_loopback_test(struct ql_adapter *qdev)
484{
485 int i;
486 netdev_tx_t rc;
487 struct sk_buff *skb;
488 unsigned int size = SMALL_BUF_MAP_SIZE;
489
490 for (i = 0; i < 64; i++) {
491 skb = netdev_alloc_skb(qdev->ndev, size);
492 if (!skb)
493 return -ENOMEM;
494
495 skb->queue_mapping = 0;
496 skb_put(skb, size);
497 ql_create_lb_frame(skb, size);
498 rc = ql_lb_send(skb, qdev->ndev);
499 if (rc != NETDEV_TX_OK)
500 return -EPIPE;
501 atomic_inc(&qdev->lb_count);
502 }
503
504 ql_clean_lb_rx_ring(&qdev->rx_ring[0], 128);
505 return atomic_read(&qdev->lb_count) ? -EIO : 0;
506}
507
508static int ql_loopback_test(struct ql_adapter *qdev, u64 *data)
509{
510 *data = ql_start_loopback(qdev);
511 if (*data)
512 goto out;
513 *data = ql_run_loopback_test(qdev);
514out:
515 ql_stop_loopback(qdev);
516 return *data;
517}
518
519static void ql_self_test(struct net_device *ndev,
520 struct ethtool_test *eth_test, u64 *data)
521{
522 struct ql_adapter *qdev = netdev_priv(ndev);
523
524 if (netif_running(ndev)) {
525 set_bit(QL_SELFTEST, &qdev->flags);
526 if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
527 /* Offline tests */
528 if (ql_loopback_test(qdev, &data[0]))
529 eth_test->flags |= ETH_TEST_FL_FAILED;
530
531 } else {
532 /* Online tests */
533 data[0] = 0;
534 }
535 clear_bit(QL_SELFTEST, &qdev->flags);
536 } else {
537 QPRINTK(qdev, DRV, ERR,
538 "%s: is down, Loopback test will fail.\n", ndev->name);
539 eth_test->flags |= ETH_TEST_FL_FAILED;
540 }
541}
542
432static int ql_get_regs_len(struct net_device *ndev) 543static int ql_get_regs_len(struct net_device *ndev)
433{ 544{
434 return sizeof(struct ql_reg_dump); 545 return sizeof(struct ql_reg_dump);
@@ -575,6 +686,7 @@ const struct ethtool_ops qlge_ethtool_ops = {
575 .set_msglevel = ql_set_msglevel, 686 .set_msglevel = ql_set_msglevel,
576 .get_link = ethtool_op_get_link, 687 .get_link = ethtool_op_get_link,
577 .phys_id = ql_phys_id, 688 .phys_id = ql_phys_id,
689 .self_test = ql_self_test,
578 .get_pauseparam = ql_get_pauseparam, 690 .get_pauseparam = ql_get_pauseparam,
579 .set_pauseparam = ql_set_pauseparam, 691 .set_pauseparam = ql_set_pauseparam,
580 .get_rx_csum = ql_get_rx_csum, 692 .get_rx_csum = ql_get_rx_csum,