qlcnic: support quiescent mode
Put device in quiescent mode during internal loopback test. Before running test, set state to NEED_QUISCENT. After getting ack from all function, change state to QUISCENT and perform test. Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
f7ec804a3e
Коммит
b8c1762045
|
@ -1313,6 +1313,8 @@ int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
|
|||
void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);
|
||||
|
||||
/* Functions from qlcnic_main.c */
|
||||
int qlcnic_request_quiscent_mode(struct qlcnic_adapter *adapter);
|
||||
void qlcnic_clear_quiscent_mode(struct qlcnic_adapter *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);
|
||||
|
|
|
@ -706,6 +706,11 @@ static int qlcnic_loopback_test(struct net_device *netdev)
|
|||
if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
|
||||
return -EIO;
|
||||
|
||||
if (qlcnic_request_quiscent_mode(adapter)) {
|
||||
clear_bit(__QLCNIC_RESETTING, &adapter->state);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
|
||||
if (ret)
|
||||
goto clear_it;
|
||||
|
@ -722,6 +727,7 @@ done:
|
|||
qlcnic_diag_free_res(netdev, max_sds_rings);
|
||||
|
||||
clear_it:
|
||||
qlcnic_clear_quiscent_mode(adapter);
|
||||
adapter->max_sds_rings = max_sds_rings;
|
||||
clear_bit(__QLCNIC_RESETTING, &adapter->state);
|
||||
return ret;
|
||||
|
|
|
@ -2712,7 +2712,8 @@ qlcnic_fwinit_work(struct work_struct *work)
|
|||
goto err_ret;
|
||||
|
||||
dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
|
||||
if (dev_state == QLCNIC_DEV_QUISCENT) {
|
||||
if (dev_state == QLCNIC_DEV_QUISCENT ||
|
||||
dev_state == QLCNIC_DEV_NEED_QUISCENT) {
|
||||
qlcnic_api_unlock(adapter);
|
||||
qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
|
||||
FW_POLL_DELAY * 2);
|
||||
|
@ -2734,18 +2735,6 @@ qlcnic_fwinit_work(struct work_struct *work)
|
|||
skip_ack_check:
|
||||
dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
|
||||
|
||||
if (dev_state == QLCNIC_DEV_NEED_QUISCENT) {
|
||||
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
|
||||
QLCNIC_DEV_QUISCENT);
|
||||
qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
|
||||
FW_POLL_DELAY * 2);
|
||||
QLCDB(adapter, DRV, "Quiscing the driver\n");
|
||||
qlcnic_idc_debug_info(adapter, 0);
|
||||
|
||||
qlcnic_api_unlock(adapter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev_state == QLCNIC_DEV_NEED_RESET) {
|
||||
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
|
||||
QLCNIC_DEV_INITIALIZING);
|
||||
|
@ -2802,7 +2791,12 @@ qlcnic_detach_work(struct work_struct *work)
|
|||
|
||||
netif_device_detach(netdev);
|
||||
|
||||
qlcnic_down(adapter, netdev);
|
||||
/* Dont grab rtnl lock during Quiscent mode */
|
||||
if (adapter->dev_state == QLCNIC_DEV_NEED_QUISCENT) {
|
||||
if (netif_running(netdev))
|
||||
__qlcnic_down(adapter, netdev);
|
||||
} else
|
||||
qlcnic_down(adapter, netdev);
|
||||
|
||||
status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
|
||||
|
||||
|
@ -2844,6 +2838,61 @@ qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
|
|||
qlcnic_api_unlock(adapter);
|
||||
}
|
||||
|
||||
/* Caller should held RESETTING bit.
|
||||
* This should be call in sync with qlcnic_request_quiscent_mode.
|
||||
*/
|
||||
void qlcnic_clear_quiscent_mode(struct qlcnic_adapter *adapter)
|
||||
{
|
||||
qlcnic_clr_drv_state(adapter);
|
||||
qlcnic_api_lock(adapter);
|
||||
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
|
||||
qlcnic_api_unlock(adapter);
|
||||
}
|
||||
|
||||
/* Caller should held RESETTING bit.
|
||||
*/
|
||||
int qlcnic_request_quiscent_mode(struct qlcnic_adapter *adapter)
|
||||
{
|
||||
u8 timeo = adapter->dev_init_timeo / 2;
|
||||
u32 state;
|
||||
|
||||
if (qlcnic_api_lock(adapter))
|
||||
return -EIO;
|
||||
|
||||
state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
|
||||
if (state != QLCNIC_DEV_READY)
|
||||
return -EIO;
|
||||
|
||||
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_QUISCENT);
|
||||
qlcnic_api_unlock(adapter);
|
||||
QLCDB(adapter, DRV, "NEED QUISCENT state set\n");
|
||||
qlcnic_idc_debug_info(adapter, 0);
|
||||
|
||||
qlcnic_set_drv_state(adapter, QLCNIC_DEV_NEED_QUISCENT);
|
||||
|
||||
do {
|
||||
msleep(2000);
|
||||
state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
|
||||
if (state == QLCNIC_DEV_QUISCENT)
|
||||
return 0;
|
||||
if (!qlcnic_check_drv_state(adapter)) {
|
||||
if (qlcnic_api_lock(adapter))
|
||||
return -EIO;
|
||||
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
|
||||
QLCNIC_DEV_QUISCENT);
|
||||
qlcnic_api_unlock(adapter);
|
||||
QLCDB(adapter, DRV, "QUISCENT mode set\n");
|
||||
return 0;
|
||||
}
|
||||
} while (--timeo);
|
||||
|
||||
dev_err(&adapter->pdev->dev, "Failed to quiesce device, DRV_STATE=%08x"
|
||||
" DRV_ACTIVE=%08x\n", QLCRD32(adapter, QLCNIC_CRB_DRV_STATE),
|
||||
QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE));
|
||||
qlcnic_clear_quiscent_mode(adapter);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*Transit to RESET state from READY state only */
|
||||
static void
|
||||
qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
|
||||
|
@ -2951,11 +3000,11 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
|
|||
qlcnic_dev_request_reset(adapter);
|
||||
|
||||
state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
|
||||
if (state == QLCNIC_DEV_NEED_RESET ||
|
||||
state == QLCNIC_DEV_NEED_QUISCENT) {
|
||||
if (state == QLCNIC_DEV_NEED_RESET) {
|
||||
qlcnic_set_npar_non_operational(adapter);
|
||||
adapter->need_fw_reset = 1;
|
||||
}
|
||||
} else if (state == QLCNIC_DEV_NEED_QUISCENT)
|
||||
goto detach;
|
||||
|
||||
heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
|
||||
if (heartbeat != adapter->heartbeat) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче