Commit 7eb9855d authored by Amit Kumar Salecha's avatar Amit Kumar Salecha Committed by David S. Miller

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: default avatarSucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: default avatarAmit Kumar Salecha <amit.salecha@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 897d3596
...@@ -560,6 +560,8 @@ struct qlcnic_recv_context { ...@@ -560,6 +560,8 @@ struct qlcnic_recv_context {
/* /*
* Context state * Context state
*/ */
#define QLCHAL_VERSION 1
#define QLCNIC_HOST_CTX_STATE_ACTIVE 2 #define QLCNIC_HOST_CTX_STATE_ACTIVE 2
/* /*
...@@ -894,6 +896,8 @@ struct qlcnic_mac_req { ...@@ -894,6 +896,8 @@ struct qlcnic_mac_req {
#define __QLCNIC_RESETTING 2 #define __QLCNIC_RESETTING 2
#define __QLCNIC_START_FW 4 #define __QLCNIC_START_FW 4
#define QLCNIC_INTERRUPT_TEST 1
struct qlcnic_adapter { struct qlcnic_adapter {
struct qlcnic_hardware_context ahw; struct qlcnic_hardware_context ahw;
...@@ -946,9 +950,10 @@ struct qlcnic_adapter { ...@@ -946,9 +950,10 @@ struct qlcnic_adapter {
u32 heartbit; u32 heartbit;
u8 dev_state; u8 dev_state;
u8 diag_test;
u8 diag_cnt;
u8 rsrd1; u8 rsrd1;
u32 rsrd2; u16 rsrd2;
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
...@@ -1064,6 +1069,10 @@ int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac); ...@@ -1064,6 +1069,10 @@ int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac);
/* Functions from qlcnic_main.c */ /* Functions from qlcnic_main.c */
int qlcnic_reset_context(struct qlcnic_adapter *); int qlcnic_reset_context(struct qlcnic_adapter *);
u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd);
void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
/* /*
* QLOGIC Board information * QLOGIC Board information
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
#include "qlcnic.h" #include "qlcnic.h"
#define QLCHAL_VERSION 1
static u32 static u32
qlcnic_poll_rsp(struct qlcnic_adapter *adapter) qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
{ {
...@@ -45,7 +43,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter) ...@@ -45,7 +43,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
return rsp; return rsp;
} }
static u32 u32
qlcnic_issue_cmd(struct qlcnic_adapter *adapter, qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd) u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd)
{ {
......
...@@ -65,7 +65,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = { ...@@ -65,7 +65,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
"Register_Test_on_offline", "Register_Test_on_offline",
"Link_Test_on_offline" "Link_Test_on_offline",
"Interrupt_Test_offline"
}; };
#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test) #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,12 +614,50 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset)
} }
} }
static int qlcnic_irq_test(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int max_sds_rings = adapter->max_sds_rings;
int ret;
if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
return -EIO;
ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
if (ret)
goto clear_it;
adapter->diag_cnt = 0;
ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
QLCHAL_VERSION, adapter->portnum, 0, 0, 0x00000011);
if (ret)
goto done;
msleep(10);
ret = !adapter->diag_cnt;
done:
qlcnic_diag_free_res(netdev, max_sds_rings);
clear_it:
adapter->max_sds_rings = max_sds_rings;
clear_bit(__QLCNIC_RESETTING, &adapter->state);
return ret;
}
static void static void
qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
u64 *data) u64 *data)
{ {
memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN); memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
data[2] = qlcnic_irq_test(dev);
if (data[2])
eth_test->flags |= ETH_TEST_FL_FAILED;
}
data[0] = qlcnic_reg_test(dev); data[0] = qlcnic_reg_test(dev);
if (data[0]) if (data[0])
eth_test->flags |= ETH_TEST_FL_FAILED; eth_test->flags |= ETH_TEST_FL_FAILED;
......
...@@ -88,6 +88,7 @@ static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter); ...@@ -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 void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter);
static int qlcnic_can_start_firmware(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_intr(int irq, void *data);
static irqreturn_t qlcnic_msi_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); static irqreturn_t qlcnic_msix_intr(int irq, void *data);
...@@ -720,6 +721,12 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter) ...@@ -720,6 +721,12 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
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) if (adapter->flags & QLCNIC_MSIX_ENABLED)
handler = qlcnic_msix_intr; handler = qlcnic_msix_intr;
else if (adapter->flags & QLCNIC_MSI_ENABLED) else if (adapter->flags & QLCNIC_MSI_ENABLED)
...@@ -728,6 +735,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter) ...@@ -728,6 +735,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
flags |= IRQF_SHARED; flags |= IRQF_SHARED;
handler = qlcnic_intr; handler = qlcnic_intr;
} }
}
adapter->irq = netdev->irq; adapter->irq = netdev->irq;
for (ring = 0; ring < adapter->max_sds_rings; ring++) { for (ring = 0; ring < adapter->max_sds_rings; ring++) {
...@@ -923,6 +931,60 @@ qlcnic_detach(struct qlcnic_adapter *adapter) ...@@ -923,6 +931,60 @@ qlcnic_detach(struct qlcnic_adapter *adapter)
adapter->is_up = 0; 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 int
qlcnic_reset_context(struct qlcnic_adapter *adapter) qlcnic_reset_context(struct qlcnic_adapter *adapter)
{ {
...@@ -1689,10 +1751,8 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) ...@@ -1689,10 +1751,8 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
return stats; 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; u32 status;
status = readl(adapter->isr_int_vec); status = readl(adapter->isr_int_vec);
...@@ -1710,6 +1770,38 @@ static irqreturn_t qlcnic_intr(int irq, void *data) ...@@ -1710,6 +1770,38 @@ static irqreturn_t qlcnic_intr(int irq, void *data)
readl(adapter->isr_int_vec); readl(adapter->isr_int_vec);
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); napi_schedule(&sds_ring->napi);
return IRQ_HANDLED; return IRQ_HANDLED;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment