aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorAmit Kumar Salecha <amit.salecha@qlogic.com>2010-02-01 00:24:59 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-02 18:55:46 -0500
commit7eb9855d68faabe0004ed18c2af1f0974d3c2c63 (patch)
tree750382ba8db5b390847ce05fc4f216d1d7d7d533 /drivers/net
parent897d3596e0dfc4c25963cff00f1159c79eaf38d3 (diff)
qlcnic: add interrupt diagnostic test
Interrupt test (offline) added in ethtool self test. Register a temporary interrupt handler and then send command to fw to raise an interrupt. Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com> Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/qlcnic/qlcnic.h13
-rw-r--r--drivers/net/qlcnic/qlcnic_ctx.c4
-rw-r--r--drivers/net/qlcnic/qlcnic_ethtool.c41
-rw-r--r--drivers/net/qlcnic/qlcnic_main.c112
4 files changed, 154 insertions, 16 deletions
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 514e805f3ab3..a5a67e9b5e10 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -560,6 +560,8 @@ struct qlcnic_recv_context {
560/* 560/*
561 * Context state 561 * Context state
562 */ 562 */
563#define QLCHAL_VERSION 1
564
563#define QLCNIC_HOST_CTX_STATE_ACTIVE 2 565#define QLCNIC_HOST_CTX_STATE_ACTIVE 2
564 566
565/* 567/*
@@ -894,6 +896,8 @@ struct qlcnic_mac_req {
894#define __QLCNIC_RESETTING 2 896#define __QLCNIC_RESETTING 2
895#define __QLCNIC_START_FW 4 897#define __QLCNIC_START_FW 4
896 898
899#define QLCNIC_INTERRUPT_TEST 1
900
897struct qlcnic_adapter { 901struct qlcnic_adapter {
898 struct qlcnic_hardware_context ahw; 902 struct qlcnic_hardware_context ahw;
899 903
@@ -946,9 +950,10 @@ struct qlcnic_adapter {
946 u32 heartbit; 950 u32 heartbit;
947 951
948 u8 dev_state; 952 u8 dev_state;
953 u8 diag_test;
954 u8 diag_cnt;
949 u8 rsrd1; 955 u8 rsrd1;
950 u32 rsrd2; 956 u16 rsrd2;
951
952 957
953 u8 mac_addr[ETH_ALEN]; 958 u8 mac_addr[ETH_ALEN];
954 959
@@ -1064,6 +1069,10 @@ int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac);
1064 1069
1065/* Functions from qlcnic_main.c */ 1070/* Functions from qlcnic_main.c */
1066int qlcnic_reset_context(struct qlcnic_adapter *); 1071int qlcnic_reset_context(struct qlcnic_adapter *);
1072u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
1073 u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd);
1074void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
1075int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
1067 1076
1068/* 1077/*
1069 * QLOGIC Board information 1078 * QLOGIC Board information
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index 71c16a183458..0a6a39914aec 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -24,8 +24,6 @@
24 24
25#include "qlcnic.h" 25#include "qlcnic.h"
26 26
27#define QLCHAL_VERSION 1
28
29static u32 27static u32
30qlcnic_poll_rsp(struct qlcnic_adapter *adapter) 28qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
31{ 29{
@@ -45,7 +43,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
45 return rsp; 43 return rsp;
46} 44}
47 45
48static u32 46u32
49qlcnic_issue_cmd(struct qlcnic_adapter *adapter, 47qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
50 u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd) 48 u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd)
51{ 49{
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 7212319760ba..58c50ed791de 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -65,7 +65,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
65 65
66static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { 66static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
67 "Register_Test_on_offline", 67 "Register_Test_on_offline",
68 "Link_Test_on_offline" 68 "Link_Test_on_offline",
69 "Interrupt_Test_offline"
69}; 70};
70 71
71#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test) 72#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
@@ -613,12 +614,50 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset)
613 } 614 }
614} 615}
615 616
617static int qlcnic_irq_test(struct net_device *netdev)
618{
619 struct qlcnic_adapter *adapter = netdev_priv(netdev);
620 int max_sds_rings = adapter->max_sds_rings;
621 int ret;
622
623 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
624 return -EIO;
625
626 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
627 if (ret)
628 goto clear_it;
629
630 adapter->diag_cnt = 0;
631 ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
632 QLCHAL_VERSION, adapter->portnum, 0, 0, 0x00000011);
633 if (ret)
634 goto done;
635
636 msleep(10);
637
638 ret = !adapter->diag_cnt;
639
640done:
641 qlcnic_diag_free_res(netdev, max_sds_rings);
642
643clear_it:
644 adapter->max_sds_rings = max_sds_rings;
645 clear_bit(__QLCNIC_RESETTING, &adapter->state);
646 return ret;
647}
648
616static void 649static void
617qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, 650qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
618 u64 *data) 651 u64 *data)
619{ 652{
620 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN); 653 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
621 654
655 if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
656 data[2] = qlcnic_irq_test(dev);
657 if (data[2])
658 eth_test->flags |= ETH_TEST_FL_FAILED;
659 }
660
622 data[0] = qlcnic_reg_test(dev); 661 data[0] = qlcnic_reg_test(dev);
623 if (data[0]) 662 if (data[0])
624 eth_test->flags |= ETH_TEST_FL_FAILED; 663 eth_test->flags |= ETH_TEST_FL_FAILED;
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 7259adc32631..a8b07120d362 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -88,6 +88,7 @@ static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
88static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter); 88static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter);
89static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter); 89static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
90 90
91static irqreturn_t qlcnic_tmp_intr(int irq, void *data);
91static irqreturn_t qlcnic_intr(int irq, void *data); 92static irqreturn_t qlcnic_intr(int irq, void *data);
92static irqreturn_t qlcnic_msi_intr(int irq, void *data); 93static irqreturn_t qlcnic_msi_intr(int irq, void *data);
93static irqreturn_t qlcnic_msix_intr(int irq, void *data); 94static irqreturn_t qlcnic_msix_intr(int irq, void *data);
@@ -720,13 +721,20 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
720 struct net_device *netdev = adapter->netdev; 721 struct net_device *netdev = adapter->netdev;
721 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; 722 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
722 723
723 if (adapter->flags & QLCNIC_MSIX_ENABLED) 724 if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
724 handler = qlcnic_msix_intr; 725 handler = qlcnic_tmp_intr;
725 else if (adapter->flags & QLCNIC_MSI_ENABLED) 726 if (!QLCNIC_IS_MSI_FAMILY(adapter))
726 handler = qlcnic_msi_intr; 727 flags |= IRQF_SHARED;
727 else { 728
728 flags |= IRQF_SHARED; 729 } else {
729 handler = qlcnic_intr; 730 if (adapter->flags & QLCNIC_MSIX_ENABLED)
731 handler = qlcnic_msix_intr;
732 else if (adapter->flags & QLCNIC_MSI_ENABLED)
733 handler = qlcnic_msi_intr;
734 else {
735 flags |= IRQF_SHARED;
736 handler = qlcnic_intr;
737 }
730 } 738 }
731 adapter->irq = netdev->irq; 739 adapter->irq = netdev->irq;
732 740
@@ -923,6 +931,60 @@ qlcnic_detach(struct qlcnic_adapter *adapter)
923 adapter->is_up = 0; 931 adapter->is_up = 0;
924} 932}
925 933
934void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
935{
936 struct qlcnic_adapter *adapter = netdev_priv(netdev);
937 struct qlcnic_host_sds_ring *sds_ring;
938 int ring;
939
940 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
941 sds_ring = &adapter->recv_ctx.sds_rings[ring];
942 qlcnic_disable_int(sds_ring);
943 }
944
945 qlcnic_detach(adapter);
946
947 adapter->diag_test = 0;
948 adapter->max_sds_rings = max_sds_rings;
949
950 if (qlcnic_attach(adapter))
951 return;
952
953 if (netif_running(netdev))
954 __qlcnic_up(adapter, netdev);
955
956 netif_device_attach(netdev);
957}
958
959int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
960{
961 struct qlcnic_adapter *adapter = netdev_priv(netdev);
962 struct qlcnic_host_sds_ring *sds_ring;
963 int ring;
964 int ret;
965
966 netif_device_detach(netdev);
967
968 if (netif_running(netdev))
969 __qlcnic_down(adapter, netdev);
970
971 qlcnic_detach(adapter);
972
973 adapter->max_sds_rings = 1;
974 adapter->diag_test = test;
975
976 ret = qlcnic_attach(adapter);
977 if (ret)
978 return ret;
979
980 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
981 sds_ring = &adapter->recv_ctx.sds_rings[ring];
982 qlcnic_enable_int(sds_ring);
983 }
984
985 return 0;
986}
987
926int 988int
927qlcnic_reset_context(struct qlcnic_adapter *adapter) 989qlcnic_reset_context(struct qlcnic_adapter *adapter)
928{ 990{
@@ -1689,10 +1751,8 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
1689 return stats; 1751 return stats;
1690} 1752}
1691 1753
1692static irqreturn_t qlcnic_intr(int irq, void *data) 1754static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
1693{ 1755{
1694 struct qlcnic_host_sds_ring *sds_ring = data;
1695 struct qlcnic_adapter *adapter = sds_ring->adapter;
1696 u32 status; 1756 u32 status;
1697 1757
1698 status = readl(adapter->isr_int_vec); 1758 status = readl(adapter->isr_int_vec);
@@ -1710,6 +1770,38 @@ static irqreturn_t qlcnic_intr(int irq, void *data)
1710 readl(adapter->isr_int_vec); 1770 readl(adapter->isr_int_vec);
1711 readl(adapter->isr_int_vec); 1771 readl(adapter->isr_int_vec);
1712 1772
1773 return IRQ_HANDLED;
1774}
1775
1776static irqreturn_t qlcnic_tmp_intr(int irq, void *data)
1777{
1778 struct qlcnic_host_sds_ring *sds_ring = data;
1779 struct qlcnic_adapter *adapter = sds_ring->adapter;
1780
1781 if (adapter->flags & QLCNIC_MSIX_ENABLED)
1782 goto done;
1783 else if (adapter->flags & QLCNIC_MSI_ENABLED) {
1784 writel(0xffffffff, adapter->tgt_status_reg);
1785 goto done;
1786 }
1787
1788 if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
1789 return IRQ_NONE;
1790
1791done:
1792 adapter->diag_cnt++;
1793 qlcnic_enable_int(sds_ring);
1794 return IRQ_HANDLED;
1795}
1796
1797static irqreturn_t qlcnic_intr(int irq, void *data)
1798{
1799 struct qlcnic_host_sds_ring *sds_ring = data;
1800 struct qlcnic_adapter *adapter = sds_ring->adapter;
1801
1802 if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
1803 return IRQ_NONE;
1804
1713 napi_schedule(&sds_ring->napi); 1805 napi_schedule(&sds_ring->napi);
1714 1806
1715 return IRQ_HANDLED; 1807 return IRQ_HANDLED;