aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/qlge
diff options
context:
space:
mode:
authorRon Mercer <ron.mercer@qlogic.com>2009-10-30 08:13:33 -0400
committerDavid S. Miller <davem@davemloft.net>2009-11-02 07:25:40 -0500
commit9dfbbaa6b0b9f7c4d6c9dc3a59006f44e6521138 (patch)
treed0c93bae849fc79ab01c38974b02b949f1b623ec /drivers/net/qlge
parent536b2e92f1b7a86e177aeced097e4c051eeebe7d (diff)
qlge: Add ethtool self-test.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/qlge')
-rw-r--r--drivers/net/qlge/qlge.h6
-rw-r--r--drivers/net/qlge/qlge_ethtool.c112
-rw-r--r--drivers/net/qlge/qlge_main.c20
3 files changed, 137 insertions, 1 deletions
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 73c7fd2badcd..872e95ee40ee 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -1581,6 +1581,8 @@ enum {
1581 QL_ALLMULTI = 6, 1581 QL_ALLMULTI = 6,
1582 QL_PORT_CFG = 7, 1582 QL_PORT_CFG = 7,
1583 QL_CAM_RT_SET = 8, 1583 QL_CAM_RT_SET = 8,
1584 QL_SELFTEST = 9,
1585 QL_LB_LINK_UP = 10,
1584}; 1586};
1585 1587
1586/* link_status bit definitions */ 1588/* link_status bit definitions */
@@ -1717,6 +1719,7 @@ struct ql_adapter {
1717 struct completion ide_completion; 1719 struct completion ide_completion;
1718 struct nic_operations *nic_ops; 1720 struct nic_operations *nic_ops;
1719 u16 device_id; 1721 u16 device_id;
1722 atomic_t lb_count;
1720}; 1723};
1721 1724
1722/* 1725/*
@@ -1808,6 +1811,9 @@ int ql_mb_set_port_cfg(struct ql_adapter *qdev);
1808int ql_wait_fifo_empty(struct ql_adapter *qdev); 1811int ql_wait_fifo_empty(struct ql_adapter *qdev);
1809void ql_gen_reg_dump(struct ql_adapter *qdev, 1812void ql_gen_reg_dump(struct ql_adapter *qdev,
1810 struct ql_reg_dump *mpi_coredump); 1813 struct ql_reg_dump *mpi_coredump);
1814netdev_tx_t ql_lb_send(struct sk_buff *skb, struct net_device *ndev);
1815void ql_check_lb_frame(struct ql_adapter *, struct sk_buff *);
1816int ql_clean_lb_rx_ring(struct rx_ring *rx_ring, int budget);
1811 1817
1812#if 1 1818#if 1
1813#define QL_ALL_DUMP 1819#define QL_ALL_DUMP
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,
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 42ad811ec313..4de054505ec6 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -1680,6 +1680,13 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
1680 return; 1680 return;
1681 } 1681 }
1682 1682
1683 /* loopback self test for ethtool */
1684 if (test_bit(QL_SELFTEST, &qdev->flags)) {
1685 ql_check_lb_frame(qdev, skb);
1686 dev_kfree_skb_any(skb);
1687 return;
1688 }
1689
1683 prefetch(skb->data); 1690 prefetch(skb->data);
1684 skb->dev = ndev; 1691 skb->dev = ndev;
1685 if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) { 1692 if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) {
@@ -2248,6 +2255,7 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev)
2248 return NETDEV_TX_OK; 2255 return NETDEV_TX_OK;
2249} 2256}
2250 2257
2258
2251static void ql_free_shadow_space(struct ql_adapter *qdev) 2259static void ql_free_shadow_space(struct ql_adapter *qdev)
2252{ 2260{
2253 if (qdev->rx_ring_shadow_reg_area) { 2261 if (qdev->rx_ring_shadow_reg_area) {
@@ -4174,7 +4182,6 @@ err_out:
4174 return err; 4182 return err;
4175} 4183}
4176 4184
4177
4178static const struct net_device_ops qlge_netdev_ops = { 4185static const struct net_device_ops qlge_netdev_ops = {
4179 .ndo_open = qlge_open, 4186 .ndo_open = qlge_open,
4180 .ndo_stop = qlge_close, 4187 .ndo_stop = qlge_close,
@@ -4243,10 +4250,21 @@ static int __devinit qlge_probe(struct pci_dev *pdev,
4243 } 4250 }
4244 ql_link_off(qdev); 4251 ql_link_off(qdev);
4245 ql_display_dev_info(ndev); 4252 ql_display_dev_info(ndev);
4253 atomic_set(&qdev->lb_count, 0);
4246 cards_found++; 4254 cards_found++;
4247 return 0; 4255 return 0;
4248} 4256}
4249 4257
4258netdev_tx_t ql_lb_send(struct sk_buff *skb, struct net_device *ndev)
4259{
4260 return qlge_send(skb, ndev);
4261}
4262
4263int ql_clean_lb_rx_ring(struct rx_ring *rx_ring, int budget)
4264{
4265 return ql_clean_inbound_rx_ring(rx_ring, budget);
4266}
4267
4250static void __devexit qlge_remove(struct pci_dev *pdev) 4268static void __devexit qlge_remove(struct pci_dev *pdev)
4251{ 4269{
4252 struct net_device *ndev = pci_get_drvdata(pdev); 4270 struct net_device *ndev = pci_get_drvdata(pdev);