* [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests
@ 2010-02-01 15:24 Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 1/7] qlcnic: use DEFINE_PCI_DEVICE_TABLE Amit Kumar Salecha
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: Amit Kumar Salecha @ 2010-02-01 15:24 UTC (permalink / raw)
To: davem; +Cc: netdev, dhananjay.phadke, ameen.rahman
Hi
Series of 7 patches to add diagnostic test, device identification support and bug fixes.
These are v2 patches, please ignore previous patches.
Apply them in net-next-2.6 tree.
Thanks
Amit Salecha
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCHv2 NEXT 1/7] qlcnic: use DEFINE_PCI_DEVICE_TABLE
2010-02-01 15:24 [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests Amit Kumar Salecha
@ 2010-02-01 15:24 ` Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 2/7] qlcnic: add ethernet identifier in board info Amit Kumar Salecha
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Amit Kumar Salecha @ 2010-02-01 15:24 UTC (permalink / raw)
To: davem; +Cc: netdev, dhananjay.phadke, ameen.rahman
Use DEFINE_PCI_DEVICE_TABLE() so we get place PCI ids table into
correct section in every case.
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
---
drivers/net/qlcnic/qlcnic_main.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 1698b6a..05275f2 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -102,7 +102,7 @@ static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
#define PCI_DEVICE_ID_QLOGIC_QLE824X 0x8020
-static const struct pci_device_id qlcnic_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = {
ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
{0,}
};
--
1.6.0.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCHv2 NEXT 2/7] qlcnic: add ethernet identifier in board info
2010-02-01 15:24 [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 1/7] qlcnic: use DEFINE_PCI_DEVICE_TABLE Amit Kumar Salecha
@ 2010-02-01 15:24 ` Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 3/7] qlcnic: clear device reset state after fw recovery Amit Kumar Salecha
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Amit Kumar Salecha @ 2010-02-01 15:24 UTC (permalink / raw)
To: davem; +Cc: netdev, dhananjay.phadke, ameen.rahman, Rajesh K Borundia
Added missing identifier that distinguishes between
FCOE/ISCSI/ETHERNET functions.
Signed-off-by: Rajesh K Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
---
drivers/net/qlcnic/qlcnic.h | 10 +++++++---
1 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index abec468..9662a37 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -1068,7 +1068,7 @@ int qlcnic_reset_context(struct qlcnic_adapter *);
* QLOGIC Board information
*/
-#define QLCNIC_MAX_BOARD_NAME_LEN 64
+#define QLCNIC_MAX_BOARD_NAME_LEN 100
struct qlcnic_brdinfo {
unsigned short vendor;
unsigned short device;
@@ -1078,8 +1078,12 @@ struct qlcnic_brdinfo {
};
static const struct qlcnic_brdinfo qlcnic_boards[] = {
- {0x1077, 0x8020, 0x1077, 0x203, "8200 Series Single Port 10GbE CNA"},
- {0x1077, 0x8020, 0x1077, 0x207, "8200 Series Dual Port 10GbE CNA"},
+ {0x1077, 0x8020, 0x1077, 0x203,
+ "8200 Series Single Port 10GbE Converged Network Adapter \
+ (TCP/IP Networking)"},
+ {0x1077, 0x8020, 0x1077, 0x207,
+ "8200 Series Dual Port 10GbE Converged Network Adapter \
+ (TCP/IP Networking)"},
{0x1077, 0x8020, 0x1077, 0x20b,
"3200 Series Dual Port 10Gb Intelligent Ethernet Adapter"},
{0x1077, 0x8020, 0x1077, 0x20c,
--
1.6.0.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCHv2 NEXT 3/7] qlcnic: clear device reset state after fw recovery
2010-02-01 15:24 [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 1/7] qlcnic: use DEFINE_PCI_DEVICE_TABLE Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 2/7] qlcnic: add ethernet identifier in board info Amit Kumar Salecha
@ 2010-02-01 15:24 ` Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 4/7] qlcnic: protect resoruce cleanup by rtnl lock Amit Kumar Salecha
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Amit Kumar Salecha @ 2010-02-01 15:24 UTC (permalink / raw)
To: davem; +Cc: netdev, dhananjay.phadke, ameen.rahman
o After firmware recovery, clear device reset state transition register.
Otherwise firmware reload can occur unnecessary.
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
---
drivers/net/qlcnic/qlcnic_main.c | 22 +++++++++++++++++++++-
1 files changed, 21 insertions(+), 1 deletions(-)
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 05275f2..9a98285 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -1866,6 +1866,23 @@ qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state)
qlcnic_api_unlock(adapter);
}
+static int
+qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+
+ if (qlcnic_api_lock(adapter))
+ return -EBUSY;
+
+ val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val &= ~((u32)0x3 << (adapter->portnum * 4));
+ QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+
+ qlcnic_api_unlock(adapter);
+
+ return 0;
+}
+
static void
qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter)
{
@@ -2119,7 +2136,10 @@ qlcnic_attach_work(struct work_struct *work)
done:
adapter->fw_fail_cnt = 0;
clear_bit(__QLCNIC_RESETTING, &adapter->state);
- qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
+
+ if (!qlcnic_clr_drv_state(adapter))
+ qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
+ FW_POLL_DELAY);
}
static int
--
1.6.0.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCHv2 NEXT 4/7] qlcnic: protect resoruce cleanup by rtnl lock
2010-02-01 15:24 [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests Amit Kumar Salecha
` (2 preceding siblings ...)
2010-02-01 15:24 ` [PATCHv2 NEXT 3/7] qlcnic: clear device reset state after fw recovery Amit Kumar Salecha
@ 2010-02-01 15:24 ` Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 5/7] qlcnic: support LED blink for device identification Amit Kumar Salecha
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Amit Kumar Salecha @ 2010-02-01 15:24 UTC (permalink / raw)
To: davem; +Cc: netdev, dhananjay.phadke, ameen.rahman
o context resources can be in used, while resoruce cleanup is in progress,
during fw recover.
o Null pointer execption can occur in send_cmd_desc, if fw recovery
module frees tx ring without rtnl lock.
o Same applies to ethtool register dump and FW health registers should be dump
in any case.
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
---
drivers/net/qlcnic/qlcnic_ethtool.c | 6 +++---
drivers/net/qlcnic/qlcnic_main.c | 2 ++
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 65e9620..37df5f6 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -326,12 +326,12 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) |
(adapter->pdev)->device;
- if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
- return;
-
for (i = 0; diag_registers[i] != -1; i++)
regs_buff[i] = QLCRD32(adapter, diag_registers[i]);
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return;
+
regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
regs_buff[i++] = 1; /* No. of tx ring */
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 9a98285..7259adc 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -2051,7 +2051,9 @@ qlcnic_detach_work(struct work_struct *work)
qlcnic_down(adapter, netdev);
+ rtnl_lock();
qlcnic_detach(adapter);
+ rtnl_unlock();
status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCHv2 NEXT 5/7] qlcnic: support LED blink for device identification
2010-02-01 15:24 [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests Amit Kumar Salecha
` (3 preceding siblings ...)
2010-02-01 15:24 ` [PATCHv2 NEXT 4/7] qlcnic: protect resoruce cleanup by rtnl lock Amit Kumar Salecha
@ 2010-02-01 15:24 ` Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 6/7] qlcnic: add interrupt diagnostic test Amit Kumar Salecha
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Amit Kumar Salecha @ 2010-02-01 15:24 UTC (permalink / raw)
To: davem
Cc: netdev, dhananjay.phadke, ameen.rahman, Sucheta Chakraborty,
Sucheta Chakraborty
From: Sucheta Chakraborty <sucheta@dut6195.unminc.com>
Added support of device identification by blinking LED for specified time.
Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
---
drivers/net/qlcnic/qlcnic.h | 1 +
drivers/net/qlcnic/qlcnic_ethtool.c | 26 ++++++++++++++++++++++++++
drivers/net/qlcnic/qlcnic_hw.c | 22 ++++++++++++++++++++++
3 files changed, 49 insertions(+), 0 deletions(-)
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 9662a37..514e805 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -1015,6 +1015,7 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
int qlcnic_get_board_info(struct qlcnic_adapter *adapter);
int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
+int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate);
/* Functions from qlcnic_init.c */
int qlcnic_phantom_init(struct qlcnic_adapter *adapter);
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 37df5f6..7212319 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -618,6 +618,7 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
u64 *data)
{
memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
+
data[0] = qlcnic_reg_test(dev);
if (data[0])
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -693,6 +694,30 @@ static int qlcnic_set_tso(struct net_device *dev, u32 data)
return 0;
}
+static int qlcnic_blink_led(struct net_device *dev, u32 val)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ int ret;
+
+ ret = qlcnic_config_led(adapter, 1, 0xf);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to set LED blink state.\n");
+ return ret;
+ }
+
+ msleep_interruptible(val * 1000);
+
+ ret = qlcnic_config_led(adapter, 0, 0xf);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to reset LED blink state.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static void
qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
@@ -867,4 +892,5 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
.set_coalesce = qlcnic_set_intr_coalesce,
.get_flags = ethtool_op_get_flags,
.set_flags = qlcnic_set_flags,
+ .phys_id = qlcnic_blink_led,
};
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
index 91234e7..8724e56 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -1199,3 +1199,25 @@ qlcnic_wol_supported(struct qlcnic_adapter *adapter)
return 0;
}
+
+int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+{
+ struct qlcnic_nic_req req;
+ int rv;
+ u64 word;
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+ req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+ word = QLCNIC_H2C_OPCODE_CONFIG_LED | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
+ req.words[0] = cpu_to_le64((u64)rate << 32);
+ req.words[1] = cpu_to_le64(state);
+
+ rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv)
+ dev_err(&adapter->pdev->dev, "LED configuration failed.\n");
+
+ return rv;
+}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCHv2 NEXT 6/7] qlcnic: add interrupt diagnostic test
2010-02-01 15:24 [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests Amit Kumar Salecha
` (4 preceding siblings ...)
2010-02-01 15:24 ` [PATCHv2 NEXT 5/7] qlcnic: support LED blink for device identification Amit Kumar Salecha
@ 2010-02-01 15:24 ` Amit Kumar Salecha
2010-02-01 15:25 ` [PATCHv2 NEXT 7/7] qlcnic: add loppback " Amit Kumar Salecha
2010-02-03 0:00 ` [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests David Miller
7 siblings, 0 replies; 9+ messages in thread
From: Amit Kumar Salecha @ 2010-02-01 15:24 UTC (permalink / raw)
To: davem; +Cc: netdev, dhananjay.phadke, ameen.rahman, Sucheta Chakraborty
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>
---
drivers/net/qlcnic/qlcnic.h | 13 ++++-
drivers/net/qlcnic/qlcnic_ctx.c | 4 +-
drivers/net/qlcnic/qlcnic_ethtool.c | 41 ++++++++++++-
drivers/net/qlcnic/qlcnic_main.c | 112 +++++++++++++++++++++++++++++++---
4 files changed, 154 insertions(+), 16 deletions(-)
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 514e805..a5a67e9 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -560,6 +560,8 @@ struct qlcnic_recv_context {
/*
* Context state
*/
+#define QLCHAL_VERSION 1
+
#define QLCNIC_HOST_CTX_STATE_ACTIVE 2
/*
@@ -894,6 +896,8 @@ struct qlcnic_mac_req {
#define __QLCNIC_RESETTING 2
#define __QLCNIC_START_FW 4
+#define QLCNIC_INTERRUPT_TEST 1
+
struct qlcnic_adapter {
struct qlcnic_hardware_context ahw;
@@ -946,9 +950,10 @@ struct qlcnic_adapter {
u32 heartbit;
u8 dev_state;
+ u8 diag_test;
+ u8 diag_cnt;
u8 rsrd1;
- u32 rsrd2;
-
+ u16 rsrd2;
u8 mac_addr[ETH_ALEN];
@@ -1064,6 +1069,10 @@ int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac);
/* Functions from qlcnic_main.c */
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
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index 71c16a1..0a6a399 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -24,8 +24,6 @@
#include "qlcnic.h"
-#define QLCHAL_VERSION 1
-
static u32
qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
{
@@ -45,7 +43,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
return rsp;
}
-static u32
+u32
qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd)
{
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 7212319..58c50ed 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[] = {
static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
"Register_Test_on_offline",
- "Link_Test_on_offline"
+ "Link_Test_on_offline",
+ "Interrupt_Test_offline"
};
#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)
}
}
+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
qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
u64 *data)
{
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);
if (data[0])
eth_test->flags |= ETH_TEST_FL_FAILED;
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 7259adc..a8b0712 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;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCHv2 NEXT 7/7] qlcnic: add loppback diagnostic test
2010-02-01 15:24 [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests Amit Kumar Salecha
` (5 preceding siblings ...)
2010-02-01 15:24 ` [PATCHv2 NEXT 6/7] qlcnic: add interrupt diagnostic test Amit Kumar Salecha
@ 2010-02-01 15:25 ` Amit Kumar Salecha
2010-02-03 0:00 ` [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests David Miller
7 siblings, 0 replies; 9+ messages in thread
From: Amit Kumar Salecha @ 2010-02-01 15:25 UTC (permalink / raw)
To: davem; +Cc: netdev, dhananjay.phadke, ameen.rahman
Loopback test (offline) added in ethtool self test.
o Set device in loopback mode
o Send packets
o Process receive packets in qlcnic_process_rcv_ring_diag()
o Compare packets
o Reset device in normal mode.
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
---
drivers/net/qlcnic/qlcnic.h | 6 +++
drivers/net/qlcnic/qlcnic_ethtool.c | 82 ++++++++++++++++++++++++++++++++++-
drivers/net/qlcnic/qlcnic_hw.c | 52 ++++++++++++++++++++++
drivers/net/qlcnic/qlcnic_init.c | 75 ++++++++++++++++++++++++++++++++
drivers/net/qlcnic/qlcnic_main.c | 20 +++++----
5 files changed, 225 insertions(+), 10 deletions(-)
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index a5a67e9..b40a851 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -897,6 +897,7 @@ struct qlcnic_mac_req {
#define __QLCNIC_START_FW 4
#define QLCNIC_INTERRUPT_TEST 1
+#define QLCNIC_LOOPBACK_TEST 2
struct qlcnic_adapter {
struct qlcnic_hardware_context ahw;
@@ -1066,6 +1067,8 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring);
int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac);
+void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter);
+int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
/* Functions from qlcnic_main.c */
int qlcnic_reset_context(struct qlcnic_adapter *);
@@ -1073,6 +1076,9 @@ 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);
+int qlcnic_check_loopback_buff(unsigned char *data);
+netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
/*
* QLOGIC Board information
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 58c50ed..8da6ec8 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -66,7 +66,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
"Register_Test_on_offline",
"Link_Test_on_offline",
- "Interrupt_Test_offline"
+ "Interrupt_Test_offline",
+ "Loopback_Test_offline"
};
#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
@@ -614,6 +615,80 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset)
}
}
+#define QLC_ILB_PKT_SIZE 64
+
+static void qlcnic_create_loopback_buff(unsigned char *data)
+{
+ unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
+ memset(data, 0x4e, QLC_ILB_PKT_SIZE);
+ memset(data, 0xff, 12);
+ memcpy(data + 12, random_data, sizeof(random_data));
+}
+
+int qlcnic_check_loopback_buff(unsigned char *data)
+{
+ unsigned char buff[QLC_ILB_PKT_SIZE];
+ qlcnic_create_loopback_buff(buff);
+ return memcmp(data, buff, QLC_ILB_PKT_SIZE);
+}
+
+static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
+ struct sk_buff *skb;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ skb = dev_alloc_skb(QLC_ILB_PKT_SIZE);
+ qlcnic_create_loopback_buff(skb->data);
+ skb_put(skb, QLC_ILB_PKT_SIZE);
+
+ adapter->diag_cnt = 0;
+
+ qlcnic_xmit_frame(skb, adapter->netdev);
+
+ msleep(5);
+
+ qlcnic_process_rcv_ring_diag(sds_ring);
+
+ dev_kfree_skb_any(skb);
+ if (!adapter->diag_cnt)
+ return -1;
+ }
+ return 0;
+}
+
+static int qlcnic_loopback_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_LOOPBACK_TEST);
+ if (ret)
+ goto clear_it;
+
+ ret = qlcnic_set_ilb_mode(adapter);
+ if (ret)
+ goto done;
+
+ ret = qlcnic_do_ilb_test(adapter);
+
+ qlcnic_clear_ilb_mode(adapter);
+
+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 int qlcnic_irq_test(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
@@ -656,6 +731,11 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
data[2] = qlcnic_irq_test(dev);
if (data[2])
eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ data[3] = qlcnic_loopback_test(dev);
+ if (data[3])
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
}
data[0] = qlcnic_reg_test(dev);
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
index 8724e56..dc6cd69 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -1221,3 +1221,55 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
return rv;
}
+
+static int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u32 flag)
+{
+ struct qlcnic_nic_req req;
+ int rv;
+ u64 word;
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+ req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+ word = QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK |
+ ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+ req.words[0] = cpu_to_le64(flag);
+
+ rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv)
+ dev_err(&adapter->pdev->dev,
+ "%sting loopback mode failed.\n",
+ flag ? "Set" : "Reset");
+ return rv;
+}
+
+int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter)
+{
+ if (qlcnic_set_fw_loopback(adapter, 1))
+ return -EIO;
+
+ if (qlcnic_nic_set_promisc(adapter,
+ VPORT_MISS_MODE_ACCEPT_ALL)) {
+ qlcnic_set_fw_loopback(adapter, 0);
+ return -EIO;
+ }
+
+ msleep(1000);
+ return 0;
+}
+
+void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter)
+{
+ int mode = VPORT_MISS_MODE_DROP;
+ struct net_device *netdev = adapter->netdev;
+
+ qlcnic_set_fw_loopback(adapter, 0);
+
+ if (netdev->flags & IFF_PROMISC)
+ mode = VPORT_MISS_MODE_ACCEPT_ALL;
+ else if (netdev->flags & IFF_ALLMULTI)
+ mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+
+ qlcnic_nic_set_promisc(adapter, mode);
+}
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index 7ae8bcc..ea00ab4 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -1464,3 +1464,78 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
spin_unlock(&rds_ring->lock);
}
+static struct qlcnic_rx_buffer *
+qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_sds_ring *sds_ring,
+ int ring, u64 sts_data0)
+{
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_rx_buffer *buffer;
+ struct sk_buff *skb;
+ struct qlcnic_host_rds_ring *rds_ring;
+ int index, length, cksum, pkt_offset;
+
+ if (unlikely(ring >= adapter->max_rds_rings))
+ return NULL;
+
+ rds_ring = &recv_ctx->rds_rings[ring];
+
+ index = qlcnic_get_sts_refhandle(sts_data0);
+ if (unlikely(index >= rds_ring->num_desc))
+ return NULL;
+
+ buffer = &rds_ring->rx_buf_arr[index];
+
+ length = qlcnic_get_sts_totallength(sts_data0);
+ cksum = qlcnic_get_sts_status(sts_data0);
+ pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
+
+ skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+ if (!skb)
+ return buffer;
+
+ skb_put(skb, rds_ring->skb_size);
+
+ if (pkt_offset)
+ skb_pull(skb, pkt_offset);
+
+ skb->truesize = skb->len + sizeof(struct sk_buff);
+
+ if (!qlcnic_check_loopback_buff(skb->data))
+ adapter->diag_cnt++;
+
+ dev_kfree_skb_any(skb);
+
+ return buffer;
+}
+
+void
+qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+ struct status_desc *desc;
+ struct qlcnic_rx_buffer *rxbuf;
+ u64 sts_data0;
+
+ int opcode, ring, desc_cnt;
+ u32 consumer = sds_ring->consumer;
+
+ desc = &sds_ring->desc_head[consumer];
+ sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
+
+ if (!(sts_data0 & STATUS_OWNER_HOST))
+ return;
+
+ desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
+ opcode = qlcnic_get_sts_opcode(sts_data0);
+
+ ring = qlcnic_get_sts_type(sts_data0);
+ rxbuf = qlcnic_process_rcv_diag(adapter, sds_ring,
+ ring, sts_data0);
+
+ desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
+ consumer = get_next_index(consumer, sds_ring->num_desc);
+
+ sds_ring->consumer = consumer;
+ writel(consumer, sds_ring->crb_sts_consumer);
+}
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index a8b0712..665e8e5 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -65,8 +65,6 @@ static int __devinit qlcnic_probe(struct pci_dev *pdev,
static void __devexit qlcnic_remove(struct pci_dev *pdev);
static int qlcnic_open(struct net_device *netdev);
static int qlcnic_close(struct net_device *netdev);
-static netdev_tx_t qlcnic_xmit_frame(struct sk_buff *,
- struct net_device *);
static void qlcnic_tx_timeout(struct net_device *netdev);
static void qlcnic_tx_timeout_task(struct work_struct *work);
static void qlcnic_attach_work(struct work_struct *work);
@@ -937,9 +935,11 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
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);
+ if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
+ 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);
@@ -977,9 +977,11 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
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);
+ if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &adapter->recv_ctx.sds_rings[ring];
+ qlcnic_enable_int(sds_ring);
+ }
}
return 0;
@@ -1549,7 +1551,7 @@ qlcnic_clear_cmddesc(u64 *desc)
desc[2] = 0ULL;
}
-static netdev_tx_t
+netdev_tx_t
qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests
2010-02-01 15:24 [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests Amit Kumar Salecha
` (6 preceding siblings ...)
2010-02-01 15:25 ` [PATCHv2 NEXT 7/7] qlcnic: add loppback " Amit Kumar Salecha
@ 2010-02-03 0:00 ` David Miller
7 siblings, 0 replies; 9+ messages in thread
From: David Miller @ 2010-02-03 0:00 UTC (permalink / raw)
To: amit.salecha; +Cc: netdev, dhananjay.phadke, ameen.rahman
From: Amit Kumar Salecha <amit.salecha@qlogic.com>
Date: Mon, 1 Feb 2010 07:24:53 -0800
> Hi
> Series of 7 patches to add diagnostic test, device identification support and bug fixes.
> These are v2 patches, please ignore previous patches.
> Apply them in net-next-2.6 tree.
All applied, thank you.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2010-02-03 0:00 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-02-01 15:24 [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 1/7] qlcnic: use DEFINE_PCI_DEVICE_TABLE Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 2/7] qlcnic: add ethernet identifier in board info Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 3/7] qlcnic: clear device reset state after fw recovery Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 4/7] qlcnic: protect resoruce cleanup by rtnl lock Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 5/7] qlcnic: support LED blink for device identification Amit Kumar Salecha
2010-02-01 15:24 ` [PATCHv2 NEXT 6/7] qlcnic: add interrupt diagnostic test Amit Kumar Salecha
2010-02-01 15:25 ` [PATCHv2 NEXT 7/7] qlcnic: add loppback " Amit Kumar Salecha
2010-02-03 0:00 ` [PATCHv2 NEXT 0/7]qlcnic: add diagnostic tests David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).