diff options
author | Amit Kumar Salecha <amit.salecha@qlogic.com> | 2010-04-22 06:51:37 +0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-23 02:28:27 +0400 |
commit | f73dfc50f14d5c4c7f6243a87a65b78aef6f3a48 (patch) | |
tree | 7b007ea5cc52cf7730b2fb548cba4961b0fd0b76 /drivers/net/qlcnic | |
parent | bbd8c6a45b0f8557a8fc38fc763d7a51fac4459d (diff) | |
download | linux-f73dfc50f14d5c4c7f6243a87a65b78aef6f3a48.tar.xz |
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>
Diffstat (limited to 'drivers/net/qlcnic')
-rw-r--r-- | drivers/net/qlcnic/qlcnic_main.c | 66 |
1 files changed, 37 insertions, 29 deletions
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index ff7705b26450..06349908092f 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"); } |