aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/qlcnic/qlcnic_ethtool.c
diff options
context:
space:
mode:
authorSucheta Chakraborty <sucheta.chakraborty@qlogic.com>2011-06-21 22:52:23 -0400
committerDavid S. Miller <davem@davemloft.net>2011-06-24 04:17:07 -0400
commit22c8c9343258feda9ea9ebb9e5f8cbb727b69454 (patch)
treefac14dcf287c032ff83c832a253178b90a2228b3 /drivers/net/qlcnic/qlcnic_ethtool.c
parent9d6a6440fe30132e4d1f1aadd099345ced9178fb (diff)
qlcnic: multi protocol internal loopback support added.
Driver will generate loopback traffic pattern and do the test. And returns result of the test to application. Updated driver version to 5.0.19. Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com> Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/qlcnic/qlcnic_ethtool.c')
-rw-r--r--drivers/net/qlcnic/qlcnic_ethtool.c123
1 files changed, 122 insertions, 1 deletions
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 31f5cba62223..743035e4538d 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -84,7 +84,8 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
84static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { 84static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
85 "Register_Test_on_offline", 85 "Register_Test_on_offline",
86 "Link_Test_on_offline", 86 "Link_Test_on_offline",
87 "Interrupt_Test_offline" 87 "Interrupt_Test_offline",
88 "Loopback_Test_offline"
88}; 89};
89 90
90#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test) 91#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
@@ -685,6 +686,123 @@ clear_it:
685 return ret; 686 return ret;
686} 687}
687 688
689#define QLCNIC_ILB_PKT_SIZE 64
690#define QLCNIC_NUM_ILB_PKT 16
691#define QLCNIC_ILB_MAX_RCV_LOOP 10
692
693static void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[])
694{
695 unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
696
697 memset(data, 0x4e, QLCNIC_ILB_PKT_SIZE);
698
699 memcpy(data, mac, ETH_ALEN);
700 memcpy(data + ETH_ALEN, mac, ETH_ALEN);
701
702 memcpy(data + 2 * ETH_ALEN, random_data, sizeof(random_data));
703}
704
705int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
706{
707 unsigned char buff[QLCNIC_ILB_PKT_SIZE];
708 qlcnic_create_loopback_buff(buff, mac);
709 return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
710}
711
712static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter)
713{
714 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
715 struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
716 struct sk_buff *skb;
717 int i, loop, cnt = 0;
718
719 for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
720 skb = dev_alloc_skb(QLCNIC_ILB_PKT_SIZE);
721 qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
722 skb_put(skb, QLCNIC_ILB_PKT_SIZE);
723
724 adapter->diag_cnt = 0;
725 qlcnic_xmit_frame(skb, adapter->netdev);
726
727 loop = 0;
728 do {
729 msleep(1);
730 qlcnic_process_rcv_ring_diag(sds_ring);
731 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
732 break;
733 } while (!adapter->diag_cnt);
734
735 dev_kfree_skb_any(skb);
736
737 if (!adapter->diag_cnt)
738 dev_warn(&adapter->pdev->dev, "ILB Test: %dth packet"
739 " not recevied\n", i + 1);
740 else
741 cnt++;
742 }
743 if (cnt != i) {
744 dev_warn(&adapter->pdev->dev, "ILB Test failed\n");
745 return -1;
746 }
747 return 0;
748}
749
750static int qlcnic_iloopback_test(struct net_device *netdev)
751{
752 struct qlcnic_adapter *adapter = netdev_priv(netdev);
753 int max_sds_rings = adapter->max_sds_rings;
754 struct qlcnic_host_sds_ring *sds_ring;
755 int loop = 0;
756 int ret;
757
758 netdev_info(netdev, "%s: in progress\n", __func__);
759 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
760 netdev_warn(netdev, "Loopback test not supported for non "
761 "privilege function\n");
762 return 0;
763 }
764
765 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
766 return -EIO;
767
768
769 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
770 if (ret)
771 goto clear_it;
772
773 sds_ring = &adapter->recv_ctx->sds_rings[0];
774
775 ret = qlcnic_set_lb_mode(adapter, QLCNIC_ILB_MODE);
776 if (ret)
777 goto free_res;
778
779 do {
780 msleep(500);
781 qlcnic_process_rcv_ring_diag(sds_ring);
782 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
783 break;
784 } while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));
785
786 if (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state)) {
787 netdev_info(netdev, "firmware didnt respond to loopback "
788 "configure request\n");
789 ret = adapter->ahw->loopback_state;
790 goto free_res;
791 }
792
793 ret = qlcnic_do_ilb_test(adapter);
794
795 qlcnic_clear_lb_mode(adapter);
796
797 free_res:
798 qlcnic_diag_free_res(netdev, max_sds_rings);
799
800 clear_it:
801 adapter->max_sds_rings = max_sds_rings;
802 clear_bit(__QLCNIC_RESETTING, &adapter->state);
803 return ret;
804}
805
688static void 806static void
689qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, 807qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
690 u64 *data) 808 u64 *data)
@@ -704,6 +822,9 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
704 if (data[2]) 822 if (data[2])
705 eth_test->flags |= ETH_TEST_FL_FAILED; 823 eth_test->flags |= ETH_TEST_FL_FAILED;
706 824
825 data[3] = qlcnic_iloopback_test(dev);
826 if (data[3])
827 eth_test->flags |= ETH_TEST_FL_FAILED;
707 828
708 } 829 }
709} 830}