summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmit Kumar Salecha <amit.salecha@qlogic.com>2010-04-22 02:51:37 +0000
committerDavid S. Miller <davem@davemloft.net>2010-04-22 15:28:27 -0700
commitf73dfc50f14d5c4c7f6243a87a65b78aef6f3a48 (patch)
tree7b007ea5cc52cf7730b2fb548cba4961b0fd0b76
parentbbd8c6a45b0f8557a8fc38fc763d7a51fac4459d (diff)
downloadlinux-3.10-f73dfc50f14d5c4c7f6243a87a65b78aef6f3a48.tar.gz
linux-3.10-f73dfc50f14d5c4c7f6243a87a65b78aef6f3a48.tar.bz2
linux-3.10-f73dfc50f14d5c4c7f6243a87a65b78aef6f3a48.zip
qlcnic: fix fw initialization responsibility
Now any pci-func can start fw, whoever sees the reset ack first. Before this, pci-func which sets the RESET state has the responsibility to start fw. Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/qlcnic/qlcnic_main.c66
1 files changed, 37 insertions, 29 deletions
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index ff7705b2645..06349908092 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -2015,6 +2015,7 @@ err:
clear_bit(__QLCNIC_RESETTING, &adapter->state);
}
+/* Grab api lock, before checking state */
static int
qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
{
@@ -2037,6 +2038,9 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
u8 dev_init_timeo = adapter->dev_init_timeo;
int portnum = adapter->portnum;
+ if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state))
+ return 1;
+
if (qlcnic_api_lock(adapter))
return -1;
@@ -2044,8 +2048,6 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
if (!(val & ((int)0x1 << (portnum * 4)))) {
val |= ((u32)0x1 << (portnum * 4));
QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
- } else if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state)) {
- goto start_fw;
}
prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
@@ -2053,7 +2055,6 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
switch (prev_state) {
case QLCNIC_DEV_COLD:
-start_fw:
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
qlcnic_api_unlock(adapter);
return 1;
@@ -2113,51 +2114,59 @@ qlcnic_fwinit_work(struct work_struct *work)
{
struct qlcnic_adapter *adapter = container_of(work,
struct qlcnic_adapter, fw_work.work);
- int dev_state;
+ u32 dev_state = 0xf;
- if (test_bit(__QLCNIC_START_FW, &adapter->state)) {
+ if (qlcnic_api_lock(adapter))
+ goto err_ret;
- if (qlcnic_check_drv_state(adapter) &&
- (adapter->fw_wait_cnt++ < adapter->reset_ack_timeo)) {
- qlcnic_schedule_work(adapter,
- qlcnic_fwinit_work, FW_POLL_DELAY);
- return;
+ if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
+ dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
+ adapter->reset_ack_timeo);
+ goto skip_ack_check;
+ }
+
+ if (!qlcnic_check_drv_state(adapter)) {
+skip_ack_check:
+ dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ if (dev_state == QLCNIC_DEV_NEED_RESET) {
+ QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
+ QLCNIC_DEV_INITIALIZING);
+ set_bit(__QLCNIC_START_FW, &adapter->state);
+ QLCDB(adapter, DRV, "Restarting fw\n");
}
- QLCDB(adapter, DRV, "Resetting FW\n");
+ qlcnic_api_unlock(adapter);
+
if (!qlcnic_start_firmware(adapter)) {
qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
return;
}
-
goto err_ret;
}
- if (adapter->fw_wait_cnt++ > (adapter->dev_init_timeo / 2)) {
- dev_err(&adapter->pdev->dev,
- "Waiting for device to reset timeout\n");
- goto err_ret;
- }
+ qlcnic_api_unlock(adapter);
dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
- QLCDB(adapter, HW, "Func waiting: Device state=%d\n", dev_state);
+ QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
switch (dev_state) {
- case QLCNIC_DEV_READY:
- if (!qlcnic_start_firmware(adapter)) {
- qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
- return;
- }
+ case QLCNIC_DEV_NEED_RESET:
+ qlcnic_schedule_work(adapter,
+ qlcnic_fwinit_work, FW_POLL_DELAY);
+ return;
case QLCNIC_DEV_FAILED:
break;
default:
- qlcnic_schedule_work(adapter,
- qlcnic_fwinit_work, 2 * FW_POLL_DELAY);
- return;
+ if (!qlcnic_start_firmware(adapter)) {
+ qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
+ return;
+ }
}
err_ret:
+ dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u "
+ "fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt);
netif_device_attach(adapter->netdev);
qlcnic_clr_all_drv_state(adapter);
}
@@ -2202,6 +2211,7 @@ err_ret:
}
+/*Transit to RESET state from READY state only */
static void
qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
{
@@ -2212,10 +2222,8 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
- if (state != QLCNIC_DEV_INITIALIZING &&
- state != QLCNIC_DEV_NEED_RESET) {
+ if (state == QLCNIC_DEV_READY) {
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
- set_bit(__QLCNIC_START_FW, &adapter->state);
QLCDB(adapter, DRV, "NEED_RESET state set\n");
}