diff options
author | Amit Kumar Salecha <amit.salecha@qlogic.com> | 2010-02-01 05:24:59 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-02 15:55:46 -0800 |
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 7259adc3263..a8b07120d36 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); static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter); static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter); +static irqreturn_t qlcnic_tmp_intr(int irq, void *data); static irqreturn_t qlcnic_intr(int irq, void *data); static irqreturn_t qlcnic_msi_intr(int irq, void *data); static irqreturn_t qlcnic_msix_intr(int irq, void *data); @@ -720,13 +721,20 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter) struct net_device *netdev = adapter->netdev; struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; - if (adapter->flags & QLCNIC_MSIX_ENABLED) - handler = qlcnic_msix_intr; - else if (adapter->flags & QLCNIC_MSI_ENABLED) - handler = qlcnic_msi_intr; - else { - flags |= IRQF_SHARED; - handler = qlcnic_intr; + if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { + handler = qlcnic_tmp_intr; + if (!QLCNIC_IS_MSI_FAMILY(adapter)) + flags |= IRQF_SHARED; + + } else { + if (adapter->flags & QLCNIC_MSIX_ENABLED) + handler = qlcnic_msix_intr; + else if (adapter->flags & QLCNIC_MSI_ENABLED) + handler = qlcnic_msi_intr; + else { + flags |= IRQF_SHARED; + handler = qlcnic_intr; + } } adapter->irq = netdev->irq; @@ -923,6 +931,60 @@ qlcnic_detach(struct qlcnic_adapter *adapter) adapter->is_up = 0; } +void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_host_sds_ring *sds_ring; + int ring; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &adapter->recv_ctx.sds_rings[ring]; + qlcnic_disable_int(sds_ring); + } + + qlcnic_detach(adapter); + + adapter->diag_test = 0; + adapter->max_sds_rings = max_sds_rings; + + if (qlcnic_attach(adapter)) + return; + + if (netif_running(netdev)) + __qlcnic_up(adapter, netdev); + + netif_device_attach(netdev); +} + +int qlcnic_diag_alloc_res(struct net_device *netdev, int test) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_host_sds_ring *sds_ring; + int ring; + int ret; + + netif_device_detach(netdev); + + if (netif_running(netdev)) + __qlcnic_down(adapter, netdev); + + qlcnic_detach(adapter); + + adapter->max_sds_rings = 1; + adapter->diag_test = test; + + ret = qlcnic_attach(adapter); + if (ret) + return ret; + + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &adapter->recv_ctx.sds_rings[ring]; + qlcnic_enable_int(sds_ring); + } + + return 0; +} + int qlcnic_reset_context(struct qlcnic_adapter *adapter) { @@ -1689,10 +1751,8 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) return stats; } -static irqreturn_t qlcnic_intr(int irq, void *data) +static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter) { - struct qlcnic_host_sds_ring *sds_ring = data; - struct qlcnic_adapter *adapter = sds_ring->adapter; u32 status; status = readl(adapter->isr_int_vec); @@ -1710,6 +1770,38 @@ static irqreturn_t qlcnic_intr(int irq, void *data) readl(adapter->isr_int_vec); readl(adapter->isr_int_vec); + return IRQ_HANDLED; +} + +static irqreturn_t qlcnic_tmp_intr(int irq, void *data) +{ + struct qlcnic_host_sds_ring *sds_ring = data; + struct qlcnic_adapter *adapter = sds_ring->adapter; + + if (adapter->flags & QLCNIC_MSIX_ENABLED) + goto done; + else if (adapter->flags & QLCNIC_MSI_ENABLED) { + writel(0xffffffff, adapter->tgt_status_reg); + goto done; + } + + if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE) + return IRQ_NONE; + +done: + adapter->diag_cnt++; + qlcnic_enable_int(sds_ring); + return IRQ_HANDLED; +} + +static irqreturn_t qlcnic_intr(int irq, void *data) +{ + struct qlcnic_host_sds_ring *sds_ring = data; + struct qlcnic_adapter *adapter = sds_ring->adapter; + + if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE) + return IRQ_NONE; + napi_schedule(&sds_ring->napi); return IRQ_HANDLED; |