aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/qlogic/qlcnic
diff options
context:
space:
mode:
authorRajesh Borundia <rajesh.borundia@qlogic.com>2013-04-19 03:01:10 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-19 16:02:38 -0400
commitf036e4f44ef04ffd78ffc2f515ebf60ffa543d21 (patch)
treea324729191ae609eb5fcaadf6f6157edbea51037 /drivers/net/ethernet/qlogic/qlcnic
parent97d8105cf3fb1eb84351ff4b69287ef7d25a4422 (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.h1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c11
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h13
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c27
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h5
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c384
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c40
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
342inline void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *adapter) 342void 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
350static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter, 351static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter,
@@ -453,17 +454,15 @@ done:
453 454
454void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter) 455void 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 */
321enum 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 *);
536irqreturn_t qlcnic_83xx_handle_aen(int, void *); 548irqreturn_t qlcnic_83xx_handle_aen(int, void *);
537int qlcnic_83xx_get_port_info(struct qlcnic_adapter *); 549int qlcnic_83xx_get_port_info(struct qlcnic_adapter *);
538void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *); 550void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *);
551void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *);
539irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *); 552irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *);
540irqreturn_t qlcnic_83xx_intr(int, void *); 553irqreturn_t qlcnic_83xx_intr(int, void *);
541irqreturn_t qlcnic_83xx_tmp_intr(int, void *); 554irqreturn_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 */
119enum 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
130static int 118static int
131qlcnic_83xx_idc_check_driver_presence_reg(struct qlcnic_adapter *adapter) 119qlcnic_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
611static int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter) 604static 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 *);
197bool qlcnic_sriov_soft_flr_check(struct qlcnic_adapter *, 197bool 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 *);
200void qlcnic_sriov_pf_reset(struct qlcnic_adapter *);
201int qlcnic_sriov_pf_reinit(struct qlcnic_adapter *);
200#else 202#else
201static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {} 203static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {}
202static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {} 204static 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; }
232static inline void qlcnic_sriov_pf_reset(struct qlcnic_adapter *adapter) {}
233static 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
31static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *);
32static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *);
28static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *); 33static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *);
29static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *, 34static 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 = {
64static struct qlcnic_nic_template qlcnic_sriov_vf_ops = { 69static 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
447err_out_send_channel_term: 454err_out_send_channel_term:
@@ -461,27 +468,47 @@ err_out_disable_msi:
461 return err; 468 return err;
462} 469}
463 470
471static 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
464int qlcnic_sriov_vf_init(struct qlcnic_adapter *adapter, int pci_using_dac) 485int 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
1221static 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
1186static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter, 1241static 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
1260retry:
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
1232err_out: 1300err_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
1307cleanup_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
1457static 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
1478err_out_term_channel:
1479 qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
1480
1481err_out_cleanup_bc_intr:
1482 qlcnic_sriov_cfg_bc_intr(adapter, 0);
1483 return err;
1484}
1485
1486static 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
1498static 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
1518static 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
1547static 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
1606static 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
1620static 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
1633static int
1634qlcnic_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
1650static 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
1667static 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
1673static 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
1709static 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
1380void 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
1401int 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}