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>
This commit is contained in:
Amit Kumar Salecha 2010-04-22 02:51:37 +00:00 committed by David S. Miller
parent bbd8c6a45b
commit f73dfc50f1

View File

@ -2015,6 +2015,7 @@ qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter)
clear_bit(__QLCNIC_RESETTING, &adapter->state); clear_bit(__QLCNIC_RESETTING, &adapter->state);
} }
/* Grab api lock, before checking state */
static int static int
qlcnic_check_drv_state(struct qlcnic_adapter *adapter) 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; u8 dev_init_timeo = adapter->dev_init_timeo;
int portnum = adapter->portnum; int portnum = adapter->portnum;
if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state))
return 1;
if (qlcnic_api_lock(adapter)) if (qlcnic_api_lock(adapter))
return -1; return -1;
@ -2044,8 +2048,6 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
if (!(val & ((int)0x1 << (portnum * 4)))) { if (!(val & ((int)0x1 << (portnum * 4)))) {
val |= ((u32)0x1 << (portnum * 4)); val |= ((u32)0x1 << (portnum * 4));
QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val); 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); prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
@ -2053,7 +2055,6 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
switch (prev_state) { switch (prev_state) {
case QLCNIC_DEV_COLD: case QLCNIC_DEV_COLD:
start_fw:
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING); QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
qlcnic_api_unlock(adapter); qlcnic_api_unlock(adapter);
return 1; return 1;
@ -2113,51 +2114,59 @@ qlcnic_fwinit_work(struct work_struct *work)
{ {
struct qlcnic_adapter *adapter = container_of(work, struct qlcnic_adapter *adapter = container_of(work,
struct qlcnic_adapter, fw_work.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) && if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
(adapter->fw_wait_cnt++ < adapter->reset_ack_timeo)) { dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
qlcnic_schedule_work(adapter, adapter->reset_ack_timeo);
qlcnic_fwinit_work, FW_POLL_DELAY); goto skip_ack_check;
return; }
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)) { if (!qlcnic_start_firmware(adapter)) {
qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
return; return;
} }
goto err_ret; goto err_ret;
} }
if (adapter->fw_wait_cnt++ > (adapter->dev_init_timeo / 2)) { qlcnic_api_unlock(adapter);
dev_err(&adapter->pdev->dev,
"Waiting for device to reset timeout\n");
goto err_ret;
}
dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); 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) { switch (dev_state) {
case QLCNIC_DEV_READY: case QLCNIC_DEV_NEED_RESET:
if (!qlcnic_start_firmware(adapter)) { qlcnic_schedule_work(adapter,
qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); qlcnic_fwinit_work, FW_POLL_DELAY);
return; return;
}
case QLCNIC_DEV_FAILED: case QLCNIC_DEV_FAILED:
break; break;
default: default:
qlcnic_schedule_work(adapter, if (!qlcnic_start_firmware(adapter)) {
qlcnic_fwinit_work, 2 * FW_POLL_DELAY); qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
return; return;
}
} }
err_ret: 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); netif_device_attach(adapter->netdev);
qlcnic_clr_all_drv_state(adapter); qlcnic_clr_all_drv_state(adapter);
} }
@ -2202,6 +2211,7 @@ qlcnic_detach_work(struct work_struct *work)
} }
/*Transit to RESET state from READY state only */
static void static void
qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) 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); state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
if (state != QLCNIC_DEV_INITIALIZING && if (state == QLCNIC_DEV_READY) {
state != QLCNIC_DEV_NEED_RESET) {
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET); 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"); QLCDB(adapter, DRV, "NEED_RESET state set\n");
} }