diff options
author | Rajesh Borundia <rajesh.borundia@qlogic.com> | 2013-04-19 03:01:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-19 16:02:38 -0400 |
commit | f036e4f44ef04ffd78ffc2f515ebf60ffa543d21 (patch) | |
tree | a324729191ae609eb5fcaadf6f6157edbea51037 /drivers/net/ethernet/qlogic/qlcnic | |
parent | 97d8105cf3fb1eb84351ff4b69287ef7d25a4422 (diff) |
qlcnic: VF reset recovery implementation.
o Implement recovery mechanism for VF to recover from
adapter resets.
Signed-off-by: Manish Chopra <manish.chopra@qlogic.com>
Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/qlogic/qlcnic')
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 13 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 27 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 384 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 40 |
8 files changed, 440 insertions, 43 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 43311ffdf361..2b13bd0495ea 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | |||
@@ -976,6 +976,7 @@ struct qlcnic_adapter { | |||
976 | u8 fw_fail_cnt; | 976 | u8 fw_fail_cnt; |
977 | u8 tx_timeo_cnt; | 977 | u8 tx_timeo_cnt; |
978 | u8 need_fw_reset; | 978 | u8 need_fw_reset; |
979 | u8 reset_ctx_cnt; | ||
979 | 980 | ||
980 | u16 is_up; | 981 | u16 is_up; |
981 | u16 pvid; | 982 | u16 pvid; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 2f4691cbd7d1..4035e82167a8 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | |||
@@ -339,12 +339,13 @@ inline void qlcnic_83xx_enable_legacy_msix_mbx_intr(struct qlcnic_adapter | |||
339 | writel(0, adapter->ahw->pci_base0 + mask); | 339 | writel(0, adapter->ahw->pci_base0 + mask); |
340 | } | 340 | } |
341 | 341 | ||
342 | inline void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *adapter) | 342 | void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *adapter) |
343 | { | 343 | { |
344 | u32 mask; | 344 | u32 mask; |
345 | 345 | ||
346 | mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK); | 346 | mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK); |
347 | writel(1, adapter->ahw->pci_base0 + mask); | 347 | writel(1, adapter->ahw->pci_base0 + mask); |
348 | QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, 0); | ||
348 | } | 349 | } |
349 | 350 | ||
350 | static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter, | 351 | static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter, |
@@ -453,17 +454,15 @@ done: | |||
453 | 454 | ||
454 | void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter) | 455 | void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter) |
455 | { | 456 | { |
456 | u32 val = 0, num_msix = adapter->ahw->num_msix - 1; | 457 | u32 num_msix; |
458 | |||
459 | qlcnic_83xx_disable_mbx_intr(adapter); | ||
457 | 460 | ||
458 | if (adapter->flags & QLCNIC_MSIX_ENABLED) | 461 | if (adapter->flags & QLCNIC_MSIX_ENABLED) |
459 | num_msix = adapter->ahw->num_msix - 1; | 462 | num_msix = adapter->ahw->num_msix - 1; |
460 | else | 463 | else |
461 | num_msix = 0; | 464 | num_msix = 0; |
462 | 465 | ||
463 | QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val); | ||
464 | |||
465 | qlcnic_83xx_disable_mbx_intr(adapter); | ||
466 | |||
467 | msleep(20); | 466 | msleep(20); |
468 | synchronize_irq(adapter->msix_entries[num_msix].vector); | 467 | synchronize_irq(adapter->msix_entries[num_msix].vector); |
469 | free_irq(adapter->msix_entries[num_msix].vector, adapter); | 468 | free_irq(adapter->msix_entries[num_msix].vector, adapter); |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 7e201cd617ea..96f834445bff 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | |||
@@ -317,6 +317,18 @@ struct qlc_83xx_idc { | |||
317 | char **name; | 317 | char **name; |
318 | }; | 318 | }; |
319 | 319 | ||
320 | /* Device States */ | ||
321 | enum qlcnic_83xx_states { | ||
322 | QLC_83XX_IDC_DEV_UNKNOWN, | ||
323 | QLC_83XX_IDC_DEV_COLD, | ||
324 | QLC_83XX_IDC_DEV_INIT, | ||
325 | QLC_83XX_IDC_DEV_READY, | ||
326 | QLC_83XX_IDC_DEV_NEED_RESET, | ||
327 | QLC_83XX_IDC_DEV_NEED_QUISCENT, | ||
328 | QLC_83XX_IDC_DEV_FAILED, | ||
329 | QLC_83XX_IDC_DEV_QUISCENT | ||
330 | }; | ||
331 | |||
320 | #define QLCNIC_MBX_RSP(reg) LSW(reg) | 332 | #define QLCNIC_MBX_RSP(reg) LSW(reg) |
321 | #define QLCNIC_MBX_NUM_REGS(reg) (MSW(reg) & 0x1FF) | 333 | #define QLCNIC_MBX_NUM_REGS(reg) (MSW(reg) & 0x1FF) |
322 | #define QLCNIC_MBX_STATUS(reg) (((reg) >> 25) & 0x7F) | 334 | #define QLCNIC_MBX_STATUS(reg) (((reg) >> 25) & 0x7F) |
@@ -536,6 +548,7 @@ void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *); | |||
536 | irqreturn_t qlcnic_83xx_handle_aen(int, void *); | 548 | irqreturn_t qlcnic_83xx_handle_aen(int, void *); |
537 | int qlcnic_83xx_get_port_info(struct qlcnic_adapter *); | 549 | int qlcnic_83xx_get_port_info(struct qlcnic_adapter *); |
538 | void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *); | 550 | void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *); |
551 | void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *); | ||
539 | irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *); | 552 | irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *); |
540 | irqreturn_t qlcnic_83xx_intr(int, void *); | 553 | irqreturn_t qlcnic_83xx_intr(int, void *); |
541 | irqreturn_t qlcnic_83xx_tmp_intr(int, void *); | 554 | irqreturn_t qlcnic_83xx_tmp_intr(int, void *); |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index c302d118a0d0..6ea3a096054c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | |||
@@ -115,18 +115,6 @@ static const char *const qlc_83xx_idc_states[] = { | |||
115 | "Quiesce" | 115 | "Quiesce" |
116 | }; | 116 | }; |
117 | 117 | ||
118 | /* Device States */ | ||
119 | enum qlcnic_83xx_states { | ||
120 | QLC_83XX_IDC_DEV_UNKNOWN, | ||
121 | QLC_83XX_IDC_DEV_COLD, | ||
122 | QLC_83XX_IDC_DEV_INIT, | ||
123 | QLC_83XX_IDC_DEV_READY, | ||
124 | QLC_83XX_IDC_DEV_NEED_RESET, | ||
125 | QLC_83XX_IDC_DEV_NEED_QUISCENT, | ||
126 | QLC_83XX_IDC_DEV_FAILED, | ||
127 | QLC_83XX_IDC_DEV_QUISCENT | ||
128 | }; | ||
129 | |||
130 | static int | 118 | static int |
131 | qlcnic_83xx_idc_check_driver_presence_reg(struct qlcnic_adapter *adapter) | 119 | qlcnic_83xx_idc_check_driver_presence_reg(struct qlcnic_adapter *adapter) |
132 | { | 120 | { |
@@ -162,7 +150,8 @@ static int qlcnic_83xx_idc_update_audit_reg(struct qlcnic_adapter *adapter, | |||
162 | return -EBUSY; | 150 | return -EBUSY; |
163 | } | 151 | } |
164 | 152 | ||
165 | val = adapter->portnum & 0xf; | 153 | val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT); |
154 | val |= (adapter->portnum & 0xf); | ||
166 | val |= mode << 7; | 155 | val |= mode << 7; |
167 | if (mode) | 156 | if (mode) |
168 | seconds = jiffies / HZ - adapter->ahw->idc.sec_counter; | 157 | seconds = jiffies / HZ - adapter->ahw->idc.sec_counter; |
@@ -401,14 +390,18 @@ static void qlcnic_83xx_idc_detach_driver(struct qlcnic_adapter *adapter) | |||
401 | struct net_device *netdev = adapter->netdev; | 390 | struct net_device *netdev = adapter->netdev; |
402 | 391 | ||
403 | netif_device_detach(netdev); | 392 | netif_device_detach(netdev); |
393 | |||
404 | /* Disable mailbox interrupt */ | 394 | /* Disable mailbox interrupt */ |
405 | QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, 0); | 395 | qlcnic_83xx_disable_mbx_intr(adapter); |
406 | qlcnic_down(adapter, netdev); | 396 | qlcnic_down(adapter, netdev); |
407 | for (i = 0; i < adapter->ahw->num_msix; i++) { | 397 | for (i = 0; i < adapter->ahw->num_msix; i++) { |
408 | adapter->ahw->intr_tbl[i].id = i; | 398 | adapter->ahw->intr_tbl[i].id = i; |
409 | adapter->ahw->intr_tbl[i].enabled = 0; | 399 | adapter->ahw->intr_tbl[i].enabled = 0; |
410 | adapter->ahw->intr_tbl[i].src = 0; | 400 | adapter->ahw->intr_tbl[i].src = 0; |
411 | } | 401 | } |
402 | |||
403 | if (qlcnic_sriov_pf_check(adapter)) | ||
404 | qlcnic_sriov_pf_reset(adapter); | ||
412 | } | 405 | } |
413 | 406 | ||
414 | /** | 407 | /** |
@@ -610,9 +603,15 @@ static int qlcnic_83xx_idc_check_fan_failure(struct qlcnic_adapter *adapter) | |||
610 | 603 | ||
611 | static int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter) | 604 | static int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter) |
612 | { | 605 | { |
606 | int err; | ||
607 | |||
613 | /* register for NIC IDC AEN Events */ | 608 | /* register for NIC IDC AEN Events */ |
614 | qlcnic_83xx_register_nic_idc_func(adapter, 1); | 609 | qlcnic_83xx_register_nic_idc_func(adapter, 1); |
615 | 610 | ||
611 | err = qlcnic_sriov_pf_reinit(adapter); | ||
612 | if (err) | ||
613 | return err; | ||
614 | |||
616 | qlcnic_83xx_enable_mbx_intrpt(adapter); | 615 | qlcnic_83xx_enable_mbx_intrpt(adapter); |
617 | 616 | ||
618 | if (qlcnic_83xx_configure_opmode(adapter)) { | 617 | if (qlcnic_83xx_configure_opmode(adapter)) { |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h index 1cebd8900cf9..c0f0c0d0a790 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h | |||
@@ -669,7 +669,7 @@ enum { | |||
669 | #define QLCNIC_CMDPEG_CHECK_RETRY_COUNT 60 | 669 | #define QLCNIC_CMDPEG_CHECK_RETRY_COUNT 60 |
670 | #define QLCNIC_CMDPEG_CHECK_DELAY 500 | 670 | #define QLCNIC_CMDPEG_CHECK_DELAY 500 |
671 | #define QLCNIC_HEARTBEAT_PERIOD_MSECS 200 | 671 | #define QLCNIC_HEARTBEAT_PERIOD_MSECS 200 |
672 | #define QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT 45 | 672 | #define QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT 10 |
673 | 673 | ||
674 | #define QLCNIC_MAX_MC_COUNT 38 | 674 | #define QLCNIC_MAX_MC_COUNT 38 |
675 | #define QLCNIC_WATCHDOG_TIMEOUTVALUE 5 | 675 | #define QLCNIC_WATCHDOG_TIMEOUTVALUE 5 |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h index 7fda5d4625b0..72db8b135dc7 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h | |||
@@ -197,6 +197,8 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *, struct qlcnic_vf_info *); | |||
197 | bool qlcnic_sriov_soft_flr_check(struct qlcnic_adapter *, | 197 | bool qlcnic_sriov_soft_flr_check(struct qlcnic_adapter *, |
198 | struct qlcnic_bc_trans *, | 198 | struct qlcnic_bc_trans *, |
199 | struct qlcnic_vf_info *); | 199 | struct qlcnic_vf_info *); |
200 | void qlcnic_sriov_pf_reset(struct qlcnic_adapter *); | ||
201 | int qlcnic_sriov_pf_reinit(struct qlcnic_adapter *); | ||
200 | #else | 202 | #else |
201 | static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {} | 203 | static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {} |
202 | static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {} | 204 | static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {} |
@@ -227,6 +229,9 @@ static inline bool qlcnic_sriov_soft_flr_check(struct qlcnic_adapter *adapter, | |||
227 | struct qlcnic_bc_trans *trans, | 229 | struct qlcnic_bc_trans *trans, |
228 | struct qlcnic_vf_info *vf) | 230 | struct qlcnic_vf_info *vf) |
229 | { return false; } | 231 | { return false; } |
232 | static inline void qlcnic_sriov_pf_reset(struct qlcnic_adapter *adapter) {} | ||
233 | static inline int qlcnic_sriov_pf_reinit(struct qlcnic_adapter *adapter) | ||
234 | { return 0; } | ||
230 | #endif | 235 | #endif |
231 | 236 | ||
232 | #endif | 237 | #endif |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 2346b16b7869..305c7cd1e56e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | |||
@@ -25,6 +25,11 @@ | |||
25 | #define QLC_DEFAULT_RCV_DESCRIPTORS_SRIOV_VF 2048 | 25 | #define QLC_DEFAULT_RCV_DESCRIPTORS_SRIOV_VF 2048 |
26 | #define QLC_DEFAULT_JUMBO_RCV_DESCRIPTORS_SRIOV_VF 512 | 26 | #define QLC_DEFAULT_JUMBO_RCV_DESCRIPTORS_SRIOV_VF 512 |
27 | 27 | ||
28 | #define QLC_83XX_VF_RESET_FAIL_THRESH 8 | ||
29 | #define QLC_BC_CMD_MAX_RETRY_CNT 5 | ||
30 | |||
31 | static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *); | ||
32 | static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *); | ||
28 | static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *); | 33 | static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *); |
29 | static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *, | 34 | static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *, |
30 | struct qlcnic_cmd_args *); | 35 | struct qlcnic_cmd_args *); |
@@ -64,7 +69,7 @@ static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = { | |||
64 | static struct qlcnic_nic_template qlcnic_sriov_vf_ops = { | 69 | static struct qlcnic_nic_template qlcnic_sriov_vf_ops = { |
65 | .config_bridged_mode = qlcnic_config_bridged_mode, | 70 | .config_bridged_mode = qlcnic_config_bridged_mode, |
66 | .config_led = qlcnic_config_led, | 71 | .config_led = qlcnic_config_led, |
67 | .cancel_idc_work = qlcnic_83xx_idc_exit, | 72 | .cancel_idc_work = qlcnic_sriov_vf_cancel_fw_work, |
68 | .napi_add = qlcnic_83xx_napi_add, | 73 | .napi_add = qlcnic_83xx_napi_add, |
69 | .napi_del = qlcnic_83xx_napi_del, | 74 | .napi_del = qlcnic_83xx_napi_del, |
70 | .config_ipaddr = qlcnic_83xx_config_ipaddr, | 75 | .config_ipaddr = qlcnic_83xx_config_ipaddr, |
@@ -442,6 +447,8 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, | |||
442 | pci_set_drvdata(adapter->pdev, adapter); | 447 | pci_set_drvdata(adapter->pdev, adapter); |
443 | dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n", | 448 | dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n", |
444 | adapter->netdev->name); | 449 | adapter->netdev->name); |
450 | qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state, | ||
451 | adapter->ahw->idc.delay); | ||
445 | return 0; | 452 | return 0; |
446 | 453 | ||
447 | err_out_send_channel_term: | 454 | err_out_send_channel_term: |
@@ -461,27 +468,47 @@ err_out_disable_msi: | |||
461 | return err; | 468 | return err; |
462 | } | 469 | } |
463 | 470 | ||
471 | static int qlcnic_sriov_check_dev_ready(struct qlcnic_adapter *adapter) | ||
472 | { | ||
473 | u32 state; | ||
474 | |||
475 | do { | ||
476 | msleep(20); | ||
477 | if (++adapter->fw_fail_cnt > QLC_BC_CMD_MAX_RETRY_CNT) | ||
478 | return -EIO; | ||
479 | state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE); | ||
480 | } while (state != QLC_83XX_IDC_DEV_READY); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
464 | int qlcnic_sriov_vf_init(struct qlcnic_adapter *adapter, int pci_using_dac) | 485 | int qlcnic_sriov_vf_init(struct qlcnic_adapter *adapter, int pci_using_dac) |
465 | { | 486 | { |
466 | struct qlcnic_hardware_context *ahw = adapter->ahw; | 487 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
488 | int err; | ||
467 | 489 | ||
468 | spin_lock_init(&ahw->mbx_lock); | 490 | spin_lock_init(&ahw->mbx_lock); |
469 | set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status); | 491 | set_bit(QLC_83XX_MBX_READY, &ahw->idc.status); |
492 | set_bit(QLC_83XX_MODULE_LOADED, &ahw->idc.status); | ||
493 | ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY; | ||
494 | ahw->reset_context = 0; | ||
495 | adapter->fw_fail_cnt = 0; | ||
470 | ahw->msix_supported = 1; | 496 | ahw->msix_supported = 1; |
497 | adapter->need_fw_reset = 0; | ||
471 | adapter->flags |= QLCNIC_TX_INTR_SHARED; | 498 | adapter->flags |= QLCNIC_TX_INTR_SHARED; |
472 | 499 | ||
473 | if (qlcnic_sriov_setup_vf(adapter, pci_using_dac)) | 500 | err = qlcnic_sriov_check_dev_ready(adapter); |
474 | return -EIO; | 501 | if (err) |
502 | return err; | ||
503 | |||
504 | err = qlcnic_sriov_setup_vf(adapter, pci_using_dac); | ||
505 | if (err) | ||
506 | return err; | ||
475 | 507 | ||
476 | if (qlcnic_read_mac_addr(adapter)) | 508 | if (qlcnic_read_mac_addr(adapter)) |
477 | dev_warn(&adapter->pdev->dev, "failed to read mac addr\n"); | 509 | dev_warn(&adapter->pdev->dev, "failed to read mac addr\n"); |
478 | 510 | ||
479 | set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status); | ||
480 | adapter->ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY; | ||
481 | adapter->ahw->reset_context = 0; | ||
482 | adapter->fw_fail_cnt = 0; | ||
483 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | 511 | clear_bit(__QLCNIC_RESETTING, &adapter->state); |
484 | adapter->need_fw_reset = 0; | ||
485 | return 0; | 512 | return 0; |
486 | } | 513 | } |
487 | 514 | ||
@@ -689,7 +716,8 @@ static void qlcnic_sriov_schedule_bc_cmd(struct qlcnic_sriov *sriov, | |||
689 | struct qlcnic_vf_info *vf, | 716 | struct qlcnic_vf_info *vf, |
690 | work_func_t func) | 717 | work_func_t func) |
691 | { | 718 | { |
692 | if (test_bit(QLC_BC_VF_FLR, &vf->state)) | 719 | if (test_bit(QLC_BC_VF_FLR, &vf->state) || |
720 | vf->adapter->need_fw_reset) | ||
693 | return; | 721 | return; |
694 | 722 | ||
695 | INIT_WORK(&vf->trans_work, func); | 723 | INIT_WORK(&vf->trans_work, func); |
@@ -813,7 +841,8 @@ static int __qlcnic_sriov_send_bc_msg(struct qlcnic_bc_trans *trans, | |||
813 | int err = -EIO; | 841 | int err = -EIO; |
814 | 842 | ||
815 | while (flag) { | 843 | while (flag) { |
816 | if (test_bit(QLC_BC_VF_FLR, &vf->state)) | 844 | if (test_bit(QLC_BC_VF_FLR, &vf->state) || |
845 | vf->adapter->need_fw_reset) | ||
817 | trans->trans_state = QLC_ABORT; | 846 | trans->trans_state = QLC_ABORT; |
818 | 847 | ||
819 | switch (trans->trans_state) { | 848 | switch (trans->trans_state) { |
@@ -897,6 +926,9 @@ static void qlcnic_sriov_process_bc_cmd(struct work_struct *work) | |||
897 | struct qlcnic_cmd_args cmd; | 926 | struct qlcnic_cmd_args cmd; |
898 | u8 req; | 927 | u8 req; |
899 | 928 | ||
929 | if (adapter->need_fw_reset) | ||
930 | return; | ||
931 | |||
900 | if (test_bit(QLC_BC_VF_FLR, &vf->state)) | 932 | if (test_bit(QLC_BC_VF_FLR, &vf->state)) |
901 | return; | 933 | return; |
902 | 934 | ||
@@ -1036,6 +1068,9 @@ static void qlcnic_sriov_handle_bc_cmd(struct qlcnic_sriov *sriov, | |||
1036 | int err; | 1068 | int err; |
1037 | u8 cmd_op; | 1069 | u8 cmd_op; |
1038 | 1070 | ||
1071 | if (adapter->need_fw_reset) | ||
1072 | return; | ||
1073 | |||
1039 | if (!test_bit(QLC_BC_VF_STATE, &vf->state) && | 1074 | if (!test_bit(QLC_BC_VF_STATE, &vf->state) && |
1040 | hdr->op_type != QLC_BC_CMD && | 1075 | hdr->op_type != QLC_BC_CMD && |
1041 | hdr->cmd_op != QLCNIC_BC_CMD_CHANNEL_INIT) | 1076 | hdr->cmd_op != QLCNIC_BC_CMD_CHANNEL_INIT) |
@@ -1183,33 +1218,66 @@ int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *adapter, u8 enable) | |||
1183 | return err; | 1218 | return err; |
1184 | } | 1219 | } |
1185 | 1220 | ||
1221 | static int qlcnic_sriov_retry_bc_cmd(struct qlcnic_adapter *adapter, | ||
1222 | struct qlcnic_bc_trans *trans) | ||
1223 | { | ||
1224 | u8 max = QLC_BC_CMD_MAX_RETRY_CNT; | ||
1225 | u32 state; | ||
1226 | |||
1227 | state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE); | ||
1228 | if (state == QLC_83XX_IDC_DEV_READY) { | ||
1229 | msleep(20); | ||
1230 | clear_bit(QLC_BC_VF_CHANNEL, &trans->vf->state); | ||
1231 | trans->trans_state = QLC_INIT; | ||
1232 | if (++adapter->fw_fail_cnt > max) | ||
1233 | return -EIO; | ||
1234 | else | ||
1235 | return 0; | ||
1236 | } | ||
1237 | |||
1238 | return -EIO; | ||
1239 | } | ||
1240 | |||
1186 | static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter, | 1241 | static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter, |
1187 | struct qlcnic_cmd_args *cmd) | 1242 | struct qlcnic_cmd_args *cmd) |
1188 | { | 1243 | { |
1244 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
1245 | struct device *dev = &adapter->pdev->dev; | ||
1189 | struct qlcnic_bc_trans *trans; | 1246 | struct qlcnic_bc_trans *trans; |
1190 | int err; | 1247 | int err; |
1191 | u32 rsp_data, opcode, mbx_err_code, rsp; | 1248 | u32 rsp_data, opcode, mbx_err_code, rsp; |
1192 | u16 seq = ++adapter->ahw->sriov->bc.trans_counter; | 1249 | u16 seq = ++adapter->ahw->sriov->bc.trans_counter; |
1250 | u8 func = ahw->pci_func; | ||
1193 | 1251 | ||
1194 | if (qlcnic_sriov_alloc_bc_trans(&trans)) | 1252 | rsp = qlcnic_sriov_alloc_bc_trans(&trans); |
1195 | return -ENOMEM; | 1253 | if (rsp) |
1254 | return rsp; | ||
1196 | 1255 | ||
1197 | if (qlcnic_sriov_prepare_bc_hdr(trans, cmd, seq, QLC_BC_COMMAND)) | 1256 | rsp = qlcnic_sriov_prepare_bc_hdr(trans, cmd, seq, QLC_BC_COMMAND); |
1198 | return -ENOMEM; | 1257 | if (rsp) |
1258 | goto cleanup_transaction; | ||
1199 | 1259 | ||
1260 | retry: | ||
1200 | if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) { | 1261 | if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) { |
1201 | rsp = -EIO; | 1262 | rsp = -EIO; |
1202 | QLCDB(adapter, DRV, "MBX not Ready!(cmd 0x%x) for VF 0x%x\n", | 1263 | QLCDB(adapter, DRV, "MBX not Ready!(cmd 0x%x) for VF 0x%x\n", |
1203 | QLCNIC_MBX_RSP(cmd->req.arg[0]), adapter->ahw->pci_func); | 1264 | QLCNIC_MBX_RSP(cmd->req.arg[0]), func); |
1204 | goto err_out; | 1265 | goto err_out; |
1205 | } | 1266 | } |
1206 | 1267 | ||
1207 | err = qlcnic_sriov_send_bc_cmd(adapter, trans, adapter->ahw->pci_func); | 1268 | err = qlcnic_sriov_send_bc_cmd(adapter, trans, func); |
1208 | if (err) { | 1269 | if (err) { |
1209 | dev_err(&adapter->pdev->dev, | 1270 | dev_err(dev, "MBX command 0x%x timed out for VF %d\n", |
1210 | "MBX command 0x%x timed out for VF %d\n", | 1271 | (cmd->req.arg[0] & 0xffff), func); |
1211 | (cmd->req.arg[0] & 0xffff), adapter->ahw->pci_func); | ||
1212 | rsp = QLCNIC_RCODE_TIMEOUT; | 1272 | rsp = QLCNIC_RCODE_TIMEOUT; |
1273 | |||
1274 | /* After adapter reset PF driver may take some time to | ||
1275 | * respond to VF's request. Retry request till maximum retries. | ||
1276 | */ | ||
1277 | if ((trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) && | ||
1278 | !qlcnic_sriov_retry_bc_cmd(adapter, trans)) | ||
1279 | goto retry; | ||
1280 | |||
1213 | goto err_out; | 1281 | goto err_out; |
1214 | } | 1282 | } |
1215 | 1283 | ||
@@ -1224,12 +1292,19 @@ static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter, | |||
1224 | rsp = mbx_err_code; | 1292 | rsp = mbx_err_code; |
1225 | if (!rsp) | 1293 | if (!rsp) |
1226 | rsp = 1; | 1294 | rsp = 1; |
1227 | dev_err(&adapter->pdev->dev, | 1295 | dev_err(dev, |
1228 | "MBX command 0x%x failed with err:0x%x for VF %d\n", | 1296 | "MBX command 0x%x failed with err:0x%x for VF %d\n", |
1229 | opcode, mbx_err_code, adapter->ahw->pci_func); | 1297 | opcode, mbx_err_code, func); |
1230 | } | 1298 | } |
1231 | 1299 | ||
1232 | err_out: | 1300 | err_out: |
1301 | if (rsp == QLCNIC_RCODE_TIMEOUT) { | ||
1302 | ahw->reset_context = 1; | ||
1303 | adapter->need_fw_reset = 1; | ||
1304 | clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status); | ||
1305 | } | ||
1306 | |||
1307 | cleanup_transaction: | ||
1233 | qlcnic_sriov_cleanup_transaction(trans); | 1308 | qlcnic_sriov_cleanup_transaction(trans); |
1234 | return rsp; | 1309 | return rsp; |
1235 | } | 1310 | } |
@@ -1372,6 +1447,271 @@ void qlcnic_sriov_vf_schedule_multi(struct net_device *netdev) | |||
1372 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | 1447 | struct qlcnic_adapter *adapter = netdev_priv(netdev); |
1373 | struct qlcnic_back_channel *bc = &adapter->ahw->sriov->bc; | 1448 | struct qlcnic_back_channel *bc = &adapter->ahw->sriov->bc; |
1374 | 1449 | ||
1450 | if (adapter->need_fw_reset) | ||
1451 | return; | ||
1452 | |||
1375 | qlcnic_sriov_schedule_bc_async_work(bc, qlcnic_sriov_handle_async_multi, | 1453 | qlcnic_sriov_schedule_bc_async_work(bc, qlcnic_sriov_handle_async_multi, |
1376 | netdev); | 1454 | netdev); |
1377 | } | 1455 | } |
1456 | |||
1457 | static int qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter *adapter) | ||
1458 | { | ||
1459 | int err; | ||
1460 | |||
1461 | set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status); | ||
1462 | qlcnic_83xx_enable_mbx_intrpt(adapter); | ||
1463 | |||
1464 | err = qlcnic_sriov_cfg_bc_intr(adapter, 1); | ||
1465 | if (err) | ||
1466 | return err; | ||
1467 | |||
1468 | err = qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_INIT); | ||
1469 | if (err) | ||
1470 | goto err_out_cleanup_bc_intr; | ||
1471 | |||
1472 | err = qlcnic_sriov_vf_init_driver(adapter); | ||
1473 | if (err) | ||
1474 | goto err_out_term_channel; | ||
1475 | |||
1476 | return 0; | ||
1477 | |||
1478 | err_out_term_channel: | ||
1479 | qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM); | ||
1480 | |||
1481 | err_out_cleanup_bc_intr: | ||
1482 | qlcnic_sriov_cfg_bc_intr(adapter, 0); | ||
1483 | return err; | ||
1484 | } | ||
1485 | |||
1486 | static void qlcnic_sriov_vf_attach(struct qlcnic_adapter *adapter) | ||
1487 | { | ||
1488 | struct net_device *netdev = adapter->netdev; | ||
1489 | |||
1490 | if (netif_running(netdev)) { | ||
1491 | if (!qlcnic_up(adapter, netdev)) | ||
1492 | qlcnic_restore_indev_addr(netdev, NETDEV_UP); | ||
1493 | } | ||
1494 | |||
1495 | netif_device_attach(netdev); | ||
1496 | } | ||
1497 | |||
1498 | static void qlcnic_sriov_vf_detach(struct qlcnic_adapter *adapter) | ||
1499 | { | ||
1500 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
1501 | struct qlcnic_intrpt_config *intr_tbl = ahw->intr_tbl; | ||
1502 | struct net_device *netdev = adapter->netdev; | ||
1503 | u8 i, max_ints = ahw->num_msix - 1; | ||
1504 | |||
1505 | qlcnic_83xx_disable_mbx_intr(adapter); | ||
1506 | netif_device_detach(netdev); | ||
1507 | if (netif_running(netdev)) | ||
1508 | qlcnic_down(adapter, netdev); | ||
1509 | |||
1510 | for (i = 0; i < max_ints; i++) { | ||
1511 | intr_tbl[i].id = i; | ||
1512 | intr_tbl[i].enabled = 0; | ||
1513 | intr_tbl[i].src = 0; | ||
1514 | } | ||
1515 | ahw->reset_context = 0; | ||
1516 | } | ||
1517 | |||
1518 | static int qlcnic_sriov_vf_handle_dev_ready(struct qlcnic_adapter *adapter) | ||
1519 | { | ||
1520 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
1521 | struct device *dev = &adapter->pdev->dev; | ||
1522 | struct qlc_83xx_idc *idc = &ahw->idc; | ||
1523 | u8 func = ahw->pci_func; | ||
1524 | u32 state; | ||
1525 | |||
1526 | if ((idc->prev_state == QLC_83XX_IDC_DEV_NEED_RESET) || | ||
1527 | (idc->prev_state == QLC_83XX_IDC_DEV_INIT)) { | ||
1528 | if (!qlcnic_sriov_vf_reinit_driver(adapter)) { | ||
1529 | qlcnic_sriov_vf_attach(adapter); | ||
1530 | adapter->fw_fail_cnt = 0; | ||
1531 | dev_info(dev, | ||
1532 | "%s: Reinitalization of VF 0x%x done after FW reset\n", | ||
1533 | __func__, func); | ||
1534 | } else { | ||
1535 | dev_err(dev, | ||
1536 | "%s: Reinitialization of VF 0x%x failed after FW reset\n", | ||
1537 | __func__, func); | ||
1538 | state = QLCRDX(ahw, QLC_83XX_IDC_DEV_STATE); | ||
1539 | dev_info(dev, "Current state 0x%x after FW reset\n", | ||
1540 | state); | ||
1541 | } | ||
1542 | } | ||
1543 | |||
1544 | return 0; | ||
1545 | } | ||
1546 | |||
1547 | static int qlcnic_sriov_vf_handle_context_reset(struct qlcnic_adapter *adapter) | ||
1548 | { | ||
1549 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
1550 | struct device *dev = &adapter->pdev->dev; | ||
1551 | struct qlc_83xx_idc *idc = &ahw->idc; | ||
1552 | u8 func = ahw->pci_func; | ||
1553 | u32 state; | ||
1554 | |||
1555 | adapter->reset_ctx_cnt++; | ||
1556 | |||
1557 | /* Skip the context reset and check if FW is hung */ | ||
1558 | if (adapter->reset_ctx_cnt < 3) { | ||
1559 | adapter->need_fw_reset = 1; | ||
1560 | clear_bit(QLC_83XX_MBX_READY, &idc->status); | ||
1561 | dev_info(dev, | ||
1562 | "Resetting context, wait here to check if FW is in failed state\n"); | ||
1563 | return 0; | ||
1564 | } | ||
1565 | |||
1566 | /* Check if number of resets exceed the threshold. | ||
1567 | * If it exceeds the threshold just fail the VF. | ||
1568 | */ | ||
1569 | if (adapter->reset_ctx_cnt > QLC_83XX_VF_RESET_FAIL_THRESH) { | ||
1570 | clear_bit(QLC_83XX_MODULE_LOADED, &idc->status); | ||
1571 | adapter->tx_timeo_cnt = 0; | ||
1572 | adapter->fw_fail_cnt = 0; | ||
1573 | adapter->reset_ctx_cnt = 0; | ||
1574 | qlcnic_sriov_vf_detach(adapter); | ||
1575 | dev_err(dev, | ||
1576 | "Device context resets have exceeded the threshold, device interface will be shutdown\n"); | ||
1577 | return -EIO; | ||
1578 | } | ||
1579 | |||
1580 | dev_info(dev, "Resetting context of VF 0x%x\n", func); | ||
1581 | dev_info(dev, "%s: Context reset count %d for VF 0x%x\n", | ||
1582 | __func__, adapter->reset_ctx_cnt, func); | ||
1583 | set_bit(__QLCNIC_RESETTING, &adapter->state); | ||
1584 | adapter->need_fw_reset = 1; | ||
1585 | clear_bit(QLC_83XX_MBX_READY, &idc->status); | ||
1586 | qlcnic_sriov_vf_detach(adapter); | ||
1587 | adapter->need_fw_reset = 0; | ||
1588 | |||
1589 | if (!qlcnic_sriov_vf_reinit_driver(adapter)) { | ||
1590 | qlcnic_sriov_vf_attach(adapter); | ||
1591 | adapter->netdev->trans_start = jiffies; | ||
1592 | adapter->tx_timeo_cnt = 0; | ||
1593 | adapter->reset_ctx_cnt = 0; | ||
1594 | adapter->fw_fail_cnt = 0; | ||
1595 | dev_info(dev, "Done resetting context for VF 0x%x\n", func); | ||
1596 | } else { | ||
1597 | dev_err(dev, "%s: Reinitialization of VF 0x%x failed\n", | ||
1598 | __func__, func); | ||
1599 | state = QLCRDX(ahw, QLC_83XX_IDC_DEV_STATE); | ||
1600 | dev_info(dev, "%s: Current state 0x%x\n", __func__, state); | ||
1601 | } | ||
1602 | |||
1603 | return 0; | ||
1604 | } | ||
1605 | |||
1606 | static int qlcnic_sriov_vf_idc_ready_state(struct qlcnic_adapter *adapter) | ||
1607 | { | ||
1608 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
1609 | int ret = 0; | ||
1610 | |||
1611 | if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_READY) | ||
1612 | ret = qlcnic_sriov_vf_handle_dev_ready(adapter); | ||
1613 | else if (ahw->reset_context) | ||
1614 | ret = qlcnic_sriov_vf_handle_context_reset(adapter); | ||
1615 | |||
1616 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | ||
1617 | return ret; | ||
1618 | } | ||
1619 | |||
1620 | static int qlcnic_sriov_vf_idc_failed_state(struct qlcnic_adapter *adapter) | ||
1621 | { | ||
1622 | struct qlc_83xx_idc *idc = &adapter->ahw->idc; | ||
1623 | |||
1624 | dev_err(&adapter->pdev->dev, "Device is in failed state\n"); | ||
1625 | if (idc->prev_state == QLC_83XX_IDC_DEV_READY) | ||
1626 | qlcnic_sriov_vf_detach(adapter); | ||
1627 | |||
1628 | clear_bit(QLC_83XX_MODULE_LOADED, &idc->status); | ||
1629 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | ||
1630 | return -EIO; | ||
1631 | } | ||
1632 | |||
1633 | static int | ||
1634 | qlcnic_sriov_vf_idc_need_quiescent_state(struct qlcnic_adapter *adapter) | ||
1635 | { | ||
1636 | struct qlc_83xx_idc *idc = &adapter->ahw->idc; | ||
1637 | |||
1638 | dev_info(&adapter->pdev->dev, "Device is in quiescent state\n"); | ||
1639 | if (idc->prev_state == QLC_83XX_IDC_DEV_READY) { | ||
1640 | set_bit(__QLCNIC_RESETTING, &adapter->state); | ||
1641 | adapter->tx_timeo_cnt = 0; | ||
1642 | adapter->reset_ctx_cnt = 0; | ||
1643 | clear_bit(QLC_83XX_MBX_READY, &idc->status); | ||
1644 | qlcnic_sriov_vf_detach(adapter); | ||
1645 | } | ||
1646 | |||
1647 | return 0; | ||
1648 | } | ||
1649 | |||
1650 | static int qlcnic_sriov_vf_idc_init_reset_state(struct qlcnic_adapter *adapter) | ||
1651 | { | ||
1652 | struct qlc_83xx_idc *idc = &adapter->ahw->idc; | ||
1653 | u8 func = adapter->ahw->pci_func; | ||
1654 | |||
1655 | if (idc->prev_state == QLC_83XX_IDC_DEV_READY) { | ||
1656 | dev_err(&adapter->pdev->dev, | ||
1657 | "Firmware hang detected by VF 0x%x\n", func); | ||
1658 | set_bit(__QLCNIC_RESETTING, &adapter->state); | ||
1659 | adapter->tx_timeo_cnt = 0; | ||
1660 | adapter->reset_ctx_cnt = 0; | ||
1661 | clear_bit(QLC_83XX_MBX_READY, &idc->status); | ||
1662 | qlcnic_sriov_vf_detach(adapter); | ||
1663 | } | ||
1664 | return 0; | ||
1665 | } | ||
1666 | |||
1667 | static int qlcnic_sriov_vf_idc_unknown_state(struct qlcnic_adapter *adapter) | ||
1668 | { | ||
1669 | dev_err(&adapter->pdev->dev, "%s: Device in unknown state\n", __func__); | ||
1670 | return 0; | ||
1671 | } | ||
1672 | |||
1673 | static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *work) | ||
1674 | { | ||
1675 | struct qlcnic_adapter *adapter; | ||
1676 | struct qlc_83xx_idc *idc; | ||
1677 | int ret = 0; | ||
1678 | |||
1679 | adapter = container_of(work, struct qlcnic_adapter, fw_work.work); | ||
1680 | idc = &adapter->ahw->idc; | ||
1681 | idc->curr_state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE); | ||
1682 | |||
1683 | switch (idc->curr_state) { | ||
1684 | case QLC_83XX_IDC_DEV_READY: | ||
1685 | ret = qlcnic_sriov_vf_idc_ready_state(adapter); | ||
1686 | break; | ||
1687 | case QLC_83XX_IDC_DEV_NEED_RESET: | ||
1688 | case QLC_83XX_IDC_DEV_INIT: | ||
1689 | ret = qlcnic_sriov_vf_idc_init_reset_state(adapter); | ||
1690 | break; | ||
1691 | case QLC_83XX_IDC_DEV_NEED_QUISCENT: | ||
1692 | ret = qlcnic_sriov_vf_idc_need_quiescent_state(adapter); | ||
1693 | break; | ||
1694 | case QLC_83XX_IDC_DEV_FAILED: | ||
1695 | ret = qlcnic_sriov_vf_idc_failed_state(adapter); | ||
1696 | break; | ||
1697 | case QLC_83XX_IDC_DEV_QUISCENT: | ||
1698 | break; | ||
1699 | default: | ||
1700 | ret = qlcnic_sriov_vf_idc_unknown_state(adapter); | ||
1701 | } | ||
1702 | |||
1703 | idc->prev_state = idc->curr_state; | ||
1704 | if (!ret && test_bit(QLC_83XX_MODULE_LOADED, &idc->status)) | ||
1705 | qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state, | ||
1706 | idc->delay); | ||
1707 | } | ||
1708 | |||
1709 | static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *adapter) | ||
1710 | { | ||
1711 | while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) | ||
1712 | msleep(20); | ||
1713 | |||
1714 | clear_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status); | ||
1715 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | ||
1716 | cancel_delayed_work_sync(&adapter->fw_work); | ||
1717 | } | ||
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index 50cdd510421a..a0135297b1c6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | |||
@@ -1376,3 +1376,43 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov, | |||
1376 | qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr); | 1376 | qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr); |
1377 | netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func); | 1377 | netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func); |
1378 | } | 1378 | } |
1379 | |||
1380 | void qlcnic_sriov_pf_reset(struct qlcnic_adapter *adapter) | ||
1381 | { | ||
1382 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
1383 | struct qlcnic_sriov *sriov = ahw->sriov; | ||
1384 | struct qlcnic_vf_info *vf; | ||
1385 | u16 num_vfs = sriov->num_vfs; | ||
1386 | int i; | ||
1387 | |||
1388 | for (i = 0; i < num_vfs; i++) { | ||
1389 | vf = &sriov->vf_info[i]; | ||
1390 | vf->rx_ctx_id = 0; | ||
1391 | vf->tx_ctx_id = 0; | ||
1392 | cancel_work_sync(&vf->flr_work); | ||
1393 | __qlcnic_sriov_process_flr(vf); | ||
1394 | clear_bit(QLC_BC_VF_STATE, &vf->state); | ||
1395 | } | ||
1396 | |||
1397 | qlcnic_sriov_pf_reset_vport_handle(adapter, ahw->pci_func); | ||
1398 | QLCWRX(ahw, QLCNIC_MBX_INTR_ENBL, (ahw->num_msix - 1) << 8); | ||
1399 | } | ||
1400 | |||
1401 | int qlcnic_sriov_pf_reinit(struct qlcnic_adapter *adapter) | ||
1402 | { | ||
1403 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
1404 | int err; | ||
1405 | |||
1406 | if (!qlcnic_sriov_enable_check(adapter)) | ||
1407 | return 0; | ||
1408 | |||
1409 | ahw->op_mode = QLCNIC_SRIOV_PF_FUNC; | ||
1410 | |||
1411 | err = qlcnic_sriov_pf_init(adapter); | ||
1412 | if (err) | ||
1413 | return err; | ||
1414 | |||
1415 | dev_info(&adapter->pdev->dev, "%s: op_mode %d\n", | ||
1416 | __func__, ahw->op_mode); | ||
1417 | return err; | ||
1418 | } | ||