diff options
author | Amit Kumar Salecha <amit.salecha@qlogic.com> | 2010-02-01 00:24:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-02 18:55:46 -0500 |
commit | 7eb9855d68faabe0004ed18c2af1f0974d3c2c63 (patch) | |
tree | 750382ba8db5b390847ce05fc4f216d1d7d7d533 /drivers/net/qlcnic/qlcnic_main.c | |
parent | 897d3596e0dfc4c25963cff00f1159c79eaf38d3 (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/qlcnic/qlcnic_main.c')
-rw-r--r-- | drivers/net/qlcnic/qlcnic_main.c | 112 |
1 files changed, 102 insertions, 10 deletions
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); | |||
88 | static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter); | 88 | static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter); |
89 | static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter); | 89 | static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter); |
90 | 90 | ||
91 | static irqreturn_t qlcnic_tmp_intr(int irq, void *data); | ||
91 | static irqreturn_t qlcnic_intr(int irq, void *data); | 92 | static irqreturn_t qlcnic_intr(int irq, void *data); |
92 | static irqreturn_t qlcnic_msi_intr(int irq, void *data); | 93 | static irqreturn_t qlcnic_msi_intr(int irq, void *data); |
93 | static irqreturn_t qlcnic_msix_intr(int irq, void *data); | 94 | static 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 | ||
934 | void 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 | |||
959 | int 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 | |||
926 | int | 988 | int |
927 | qlcnic_reset_context(struct qlcnic_adapter *adapter) | 989 | qlcnic_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 | ||
1692 | static irqreturn_t qlcnic_intr(int irq, void *data) | 1754 | static 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 | |||
1776 | static 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 | |||
1791 | done: | ||
1792 | adapter->diag_cnt++; | ||
1793 | qlcnic_enable_int(sds_ring); | ||
1794 | return IRQ_HANDLED; | ||
1795 | } | ||
1796 | |||
1797 | static 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; |