diff options
Diffstat (limited to 'drivers/net/ethernet/emulex/benet/be_main.c')
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_main.c | 203 |
1 files changed, 141 insertions, 62 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index a3641baa8604..9e7dbd59b57e 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c | |||
@@ -155,7 +155,7 @@ static void be_intr_set(struct be_adapter *adapter, bool enable) | |||
155 | { | 155 | { |
156 | u32 reg, enabled; | 156 | u32 reg, enabled; |
157 | 157 | ||
158 | if (adapter->eeh_err) | 158 | if (adapter->eeh_error) |
159 | return; | 159 | return; |
160 | 160 | ||
161 | pci_read_config_dword(adapter->pdev, PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET, | 161 | pci_read_config_dword(adapter->pdev, PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET, |
@@ -201,7 +201,7 @@ static void be_eq_notify(struct be_adapter *adapter, u16 qid, | |||
201 | val |= ((qid & DB_EQ_RING_ID_EXT_MASK) << | 201 | val |= ((qid & DB_EQ_RING_ID_EXT_MASK) << |
202 | DB_EQ_RING_ID_EXT_MASK_SHIFT); | 202 | DB_EQ_RING_ID_EXT_MASK_SHIFT); |
203 | 203 | ||
204 | if (adapter->eeh_err) | 204 | if (adapter->eeh_error) |
205 | return; | 205 | return; |
206 | 206 | ||
207 | if (arm) | 207 | if (arm) |
@@ -220,7 +220,7 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped) | |||
220 | val |= ((qid & DB_CQ_RING_ID_EXT_MASK) << | 220 | val |= ((qid & DB_CQ_RING_ID_EXT_MASK) << |
221 | DB_CQ_RING_ID_EXT_MASK_SHIFT); | 221 | DB_CQ_RING_ID_EXT_MASK_SHIFT); |
222 | 222 | ||
223 | if (adapter->eeh_err) | 223 | if (adapter->eeh_error) |
224 | return; | 224 | return; |
225 | 225 | ||
226 | if (arm) | 226 | if (arm) |
@@ -2098,13 +2098,13 @@ int be_poll(struct napi_struct *napi, int budget) | |||
2098 | return max_work; | 2098 | return max_work; |
2099 | } | 2099 | } |
2100 | 2100 | ||
2101 | void be_detect_dump_ue(struct be_adapter *adapter) | 2101 | void be_detect_error(struct be_adapter *adapter) |
2102 | { | 2102 | { |
2103 | u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0; | 2103 | u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0; |
2104 | u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; | 2104 | u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; |
2105 | u32 i; | 2105 | u32 i; |
2106 | 2106 | ||
2107 | if (adapter->eeh_err || adapter->ue_detected) | 2107 | if (be_crit_error(adapter)) |
2108 | return; | 2108 | return; |
2109 | 2109 | ||
2110 | if (lancer_chip(adapter)) { | 2110 | if (lancer_chip(adapter)) { |
@@ -2125,16 +2125,24 @@ void be_detect_dump_ue(struct be_adapter *adapter) | |||
2125 | pci_read_config_dword(adapter->pdev, | 2125 | pci_read_config_dword(adapter->pdev, |
2126 | PCICFG_UE_STATUS_HI_MASK, &ue_hi_mask); | 2126 | PCICFG_UE_STATUS_HI_MASK, &ue_hi_mask); |
2127 | 2127 | ||
2128 | ue_lo = (ue_lo & (~ue_lo_mask)); | 2128 | ue_lo = (ue_lo & ~ue_lo_mask); |
2129 | ue_hi = (ue_hi & (~ue_hi_mask)); | 2129 | ue_hi = (ue_hi & ~ue_hi_mask); |
2130 | } | 2130 | } |
2131 | 2131 | ||
2132 | if (ue_lo || ue_hi || | 2132 | if (ue_lo || ue_hi || |
2133 | sliport_status & SLIPORT_STATUS_ERR_MASK) { | 2133 | sliport_status & SLIPORT_STATUS_ERR_MASK) { |
2134 | adapter->ue_detected = true; | 2134 | adapter->hw_error = true; |
2135 | adapter->eeh_err = true; | ||
2136 | dev_err(&adapter->pdev->dev, | 2135 | dev_err(&adapter->pdev->dev, |
2137 | "Unrecoverable error in the card\n"); | 2136 | "Error detected in the card\n"); |
2137 | } | ||
2138 | |||
2139 | if (sliport_status & SLIPORT_STATUS_ERR_MASK) { | ||
2140 | dev_err(&adapter->pdev->dev, | ||
2141 | "ERR: sliport status 0x%x\n", sliport_status); | ||
2142 | dev_err(&adapter->pdev->dev, | ||
2143 | "ERR: sliport error1 0x%x\n", sliport_err1); | ||
2144 | dev_err(&adapter->pdev->dev, | ||
2145 | "ERR: sliport error2 0x%x\n", sliport_err2); | ||
2138 | } | 2146 | } |
2139 | 2147 | ||
2140 | if (ue_lo) { | 2148 | if (ue_lo) { |
@@ -2144,6 +2152,7 @@ void be_detect_dump_ue(struct be_adapter *adapter) | |||
2144 | "UE: %s bit set\n", ue_status_low_desc[i]); | 2152 | "UE: %s bit set\n", ue_status_low_desc[i]); |
2145 | } | 2153 | } |
2146 | } | 2154 | } |
2155 | |||
2147 | if (ue_hi) { | 2156 | if (ue_hi) { |
2148 | for (i = 0; ue_hi; ue_hi >>= 1, i++) { | 2157 | for (i = 0; ue_hi; ue_hi >>= 1, i++) { |
2149 | if (ue_hi & 1) | 2158 | if (ue_hi & 1) |
@@ -2152,14 +2161,6 @@ void be_detect_dump_ue(struct be_adapter *adapter) | |||
2152 | } | 2161 | } |
2153 | } | 2162 | } |
2154 | 2163 | ||
2155 | if (sliport_status & SLIPORT_STATUS_ERR_MASK) { | ||
2156 | dev_err(&adapter->pdev->dev, | ||
2157 | "sliport status 0x%x\n", sliport_status); | ||
2158 | dev_err(&adapter->pdev->dev, | ||
2159 | "sliport error1 0x%x\n", sliport_err1); | ||
2160 | dev_err(&adapter->pdev->dev, | ||
2161 | "sliport error2 0x%x\n", sliport_err2); | ||
2162 | } | ||
2163 | } | 2164 | } |
2164 | 2165 | ||
2165 | static void be_msix_disable(struct be_adapter *adapter) | 2166 | static void be_msix_disable(struct be_adapter *adapter) |
@@ -3067,6 +3068,40 @@ static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr) | |||
3067 | return 0; | 3068 | return 0; |
3068 | } | 3069 | } |
3069 | 3070 | ||
3071 | static int lancer_wait_idle(struct be_adapter *adapter) | ||
3072 | { | ||
3073 | #define SLIPORT_IDLE_TIMEOUT 30 | ||
3074 | u32 reg_val; | ||
3075 | int status = 0, i; | ||
3076 | |||
3077 | for (i = 0; i < SLIPORT_IDLE_TIMEOUT; i++) { | ||
3078 | reg_val = ioread32(adapter->db + PHYSDEV_CONTROL_OFFSET); | ||
3079 | if ((reg_val & PHYSDEV_CONTROL_INP_MASK) == 0) | ||
3080 | break; | ||
3081 | |||
3082 | ssleep(1); | ||
3083 | } | ||
3084 | |||
3085 | if (i == SLIPORT_IDLE_TIMEOUT) | ||
3086 | status = -1; | ||
3087 | |||
3088 | return status; | ||
3089 | } | ||
3090 | |||
3091 | static int lancer_fw_reset(struct be_adapter *adapter) | ||
3092 | { | ||
3093 | int status = 0; | ||
3094 | |||
3095 | status = lancer_wait_idle(adapter); | ||
3096 | if (status) | ||
3097 | return status; | ||
3098 | |||
3099 | iowrite32(PHYSDEV_CONTROL_FW_RESET_MASK, adapter->db + | ||
3100 | PHYSDEV_CONTROL_OFFSET); | ||
3101 | |||
3102 | return status; | ||
3103 | } | ||
3104 | |||
3070 | static int lancer_fw_download(struct be_adapter *adapter, | 3105 | static int lancer_fw_download(struct be_adapter *adapter, |
3071 | const struct firmware *fw) | 3106 | const struct firmware *fw) |
3072 | { | 3107 | { |
@@ -3081,6 +3116,7 @@ static int lancer_fw_download(struct be_adapter *adapter, | |||
3081 | u32 offset = 0; | 3116 | u32 offset = 0; |
3082 | int status = 0; | 3117 | int status = 0; |
3083 | u8 add_status = 0; | 3118 | u8 add_status = 0; |
3119 | u8 change_status; | ||
3084 | 3120 | ||
3085 | if (!IS_ALIGNED(fw->size, sizeof(u32))) { | 3121 | if (!IS_ALIGNED(fw->size, sizeof(u32))) { |
3086 | dev_err(&adapter->pdev->dev, | 3122 | dev_err(&adapter->pdev->dev, |
@@ -3113,9 +3149,10 @@ static int lancer_fw_download(struct be_adapter *adapter, | |||
3113 | memcpy(dest_image_ptr, data_ptr, chunk_size); | 3149 | memcpy(dest_image_ptr, data_ptr, chunk_size); |
3114 | 3150 | ||
3115 | status = lancer_cmd_write_object(adapter, &flash_cmd, | 3151 | status = lancer_cmd_write_object(adapter, &flash_cmd, |
3116 | chunk_size, offset, LANCER_FW_DOWNLOAD_LOCATION, | 3152 | chunk_size, offset, |
3117 | &data_written, &add_status); | 3153 | LANCER_FW_DOWNLOAD_LOCATION, |
3118 | 3154 | &data_written, &change_status, | |
3155 | &add_status); | ||
3119 | if (status) | 3156 | if (status) |
3120 | break; | 3157 | break; |
3121 | 3158 | ||
@@ -3127,8 +3164,10 @@ static int lancer_fw_download(struct be_adapter *adapter, | |||
3127 | if (!status) { | 3164 | if (!status) { |
3128 | /* Commit the FW written */ | 3165 | /* Commit the FW written */ |
3129 | status = lancer_cmd_write_object(adapter, &flash_cmd, | 3166 | status = lancer_cmd_write_object(adapter, &flash_cmd, |
3130 | 0, offset, LANCER_FW_DOWNLOAD_LOCATION, | 3167 | 0, offset, |
3131 | &data_written, &add_status); | 3168 | LANCER_FW_DOWNLOAD_LOCATION, |
3169 | &data_written, &change_status, | ||
3170 | &add_status); | ||
3132 | } | 3171 | } |
3133 | 3172 | ||
3134 | dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va, | 3173 | dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va, |
@@ -3141,6 +3180,20 @@ static int lancer_fw_download(struct be_adapter *adapter, | |||
3141 | goto lancer_fw_exit; | 3180 | goto lancer_fw_exit; |
3142 | } | 3181 | } |
3143 | 3182 | ||
3183 | if (change_status == LANCER_FW_RESET_NEEDED) { | ||
3184 | status = lancer_fw_reset(adapter); | ||
3185 | if (status) { | ||
3186 | dev_err(&adapter->pdev->dev, | ||
3187 | "Adapter busy for FW reset.\n" | ||
3188 | "New FW will not be active.\n"); | ||
3189 | goto lancer_fw_exit; | ||
3190 | } | ||
3191 | } else if (change_status != LANCER_NO_RESET_NEEDED) { | ||
3192 | dev_err(&adapter->pdev->dev, | ||
3193 | "System reboot required for new FW" | ||
3194 | " to be active\n"); | ||
3195 | } | ||
3196 | |||
3144 | dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n"); | 3197 | dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n"); |
3145 | lancer_fw_exit: | 3198 | lancer_fw_exit: |
3146 | return status; | 3199 | return status; |
@@ -3469,6 +3522,8 @@ static void __devexit be_remove(struct pci_dev *pdev) | |||
3469 | 3522 | ||
3470 | be_roce_dev_remove(adapter); | 3523 | be_roce_dev_remove(adapter); |
3471 | 3524 | ||
3525 | cancel_delayed_work_sync(&adapter->func_recovery_work); | ||
3526 | |||
3472 | unregister_netdev(adapter->netdev); | 3527 | unregister_netdev(adapter->netdev); |
3473 | 3528 | ||
3474 | be_clear(adapter); | 3529 | be_clear(adapter); |
@@ -3625,53 +3680,68 @@ static int be_dev_type_check(struct be_adapter *adapter) | |||
3625 | return 0; | 3680 | return 0; |
3626 | } | 3681 | } |
3627 | 3682 | ||
3628 | static void lancer_test_and_recover_fn_err(struct be_adapter *adapter) | 3683 | static int lancer_recover_func(struct be_adapter *adapter) |
3629 | { | 3684 | { |
3630 | int status; | 3685 | int status; |
3631 | u32 sliport_status; | ||
3632 | 3686 | ||
3633 | if (adapter->eeh_err || adapter->ue_detected) | 3687 | status = lancer_test_and_set_rdy_state(adapter); |
3634 | return; | 3688 | if (status) |
3689 | goto err; | ||
3635 | 3690 | ||
3636 | sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); | 3691 | if (netif_running(adapter->netdev)) |
3692 | be_close(adapter->netdev); | ||
3637 | 3693 | ||
3638 | if (sliport_status & SLIPORT_STATUS_ERR_MASK) { | 3694 | be_clear(adapter); |
3639 | dev_err(&adapter->pdev->dev, | 3695 | |
3640 | "Adapter in error state." | 3696 | adapter->hw_error = false; |
3641 | "Trying to recover.\n"); | 3697 | adapter->fw_timeout = false; |
3698 | |||
3699 | status = be_setup(adapter); | ||
3700 | if (status) | ||
3701 | goto err; | ||
3642 | 3702 | ||
3643 | status = lancer_test_and_set_rdy_state(adapter); | 3703 | if (netif_running(adapter->netdev)) { |
3704 | status = be_open(adapter->netdev); | ||
3644 | if (status) | 3705 | if (status) |
3645 | goto err; | 3706 | goto err; |
3707 | } | ||
3646 | 3708 | ||
3647 | netif_device_detach(adapter->netdev); | 3709 | dev_err(&adapter->pdev->dev, |
3710 | "Adapter SLIPORT recovery succeeded\n"); | ||
3711 | return 0; | ||
3712 | err: | ||
3713 | dev_err(&adapter->pdev->dev, | ||
3714 | "Adapter SLIPORT recovery failed\n"); | ||
3648 | 3715 | ||
3649 | if (netif_running(adapter->netdev)) | 3716 | return status; |
3650 | be_close(adapter->netdev); | 3717 | } |
3718 | |||
3719 | static void be_func_recovery_task(struct work_struct *work) | ||
3720 | { | ||
3721 | struct be_adapter *adapter = | ||
3722 | container_of(work, struct be_adapter, func_recovery_work.work); | ||
3723 | int status; | ||
3651 | 3724 | ||
3652 | be_clear(adapter); | 3725 | be_detect_error(adapter); |
3653 | 3726 | ||
3654 | adapter->fw_timeout = false; | 3727 | if (adapter->hw_error && lancer_chip(adapter)) { |
3655 | 3728 | ||
3656 | status = be_setup(adapter); | 3729 | if (adapter->eeh_error) |
3657 | if (status) | 3730 | goto out; |
3658 | goto err; | ||
3659 | 3731 | ||
3660 | if (netif_running(adapter->netdev)) { | 3732 | rtnl_lock(); |
3661 | status = be_open(adapter->netdev); | 3733 | netif_device_detach(adapter->netdev); |
3662 | if (status) | 3734 | rtnl_unlock(); |
3663 | goto err; | ||
3664 | } | ||
3665 | 3735 | ||
3666 | netif_device_attach(adapter->netdev); | 3736 | status = lancer_recover_func(adapter); |
3667 | 3737 | ||
3668 | dev_err(&adapter->pdev->dev, | 3738 | if (!status) |
3669 | "Adapter error recovery succeeded\n"); | 3739 | netif_device_attach(adapter->netdev); |
3670 | } | 3740 | } |
3671 | return; | 3741 | |
3672 | err: | 3742 | out: |
3673 | dev_err(&adapter->pdev->dev, | 3743 | schedule_delayed_work(&adapter->func_recovery_work, |
3674 | "Adapter error recovery failed\n"); | 3744 | msecs_to_jiffies(1000)); |
3675 | } | 3745 | } |
3676 | 3746 | ||
3677 | static void be_worker(struct work_struct *work) | 3747 | static void be_worker(struct work_struct *work) |
@@ -3682,11 +3752,6 @@ static void be_worker(struct work_struct *work) | |||
3682 | struct be_eq_obj *eqo; | 3752 | struct be_eq_obj *eqo; |
3683 | int i; | 3753 | int i; |
3684 | 3754 | ||
3685 | if (lancer_chip(adapter)) | ||
3686 | lancer_test_and_recover_fn_err(adapter); | ||
3687 | |||
3688 | be_detect_dump_ue(adapter); | ||
3689 | |||
3690 | /* when interrupts are not yet enabled, just reap any pending | 3755 | /* when interrupts are not yet enabled, just reap any pending |
3691 | * mcc completions */ | 3756 | * mcc completions */ |
3692 | if (!netif_running(adapter->netdev)) { | 3757 | if (!netif_running(adapter->netdev)) { |
@@ -3805,6 +3870,7 @@ static int __devinit be_probe(struct pci_dev *pdev, | |||
3805 | goto stats_clean; | 3870 | goto stats_clean; |
3806 | 3871 | ||
3807 | INIT_DELAYED_WORK(&adapter->work, be_worker); | 3872 | INIT_DELAYED_WORK(&adapter->work, be_worker); |
3873 | INIT_DELAYED_WORK(&adapter->func_recovery_work, be_func_recovery_task); | ||
3808 | adapter->rx_fc = adapter->tx_fc = true; | 3874 | adapter->rx_fc = adapter->tx_fc = true; |
3809 | 3875 | ||
3810 | status = be_setup(adapter); | 3876 | status = be_setup(adapter); |
@@ -3818,6 +3884,8 @@ static int __devinit be_probe(struct pci_dev *pdev, | |||
3818 | 3884 | ||
3819 | be_roce_dev_add(adapter); | 3885 | be_roce_dev_add(adapter); |
3820 | 3886 | ||
3887 | schedule_delayed_work(&adapter->func_recovery_work, | ||
3888 | msecs_to_jiffies(1000)); | ||
3821 | dev_info(&pdev->dev, "%s: %s port %d\n", netdev->name, nic_name(pdev), | 3889 | dev_info(&pdev->dev, "%s: %s port %d\n", netdev->name, nic_name(pdev), |
3822 | adapter->port_num); | 3890 | adapter->port_num); |
3823 | 3891 | ||
@@ -3851,6 +3919,8 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) | |||
3851 | if (adapter->wol) | 3919 | if (adapter->wol) |
3852 | be_setup_wol(adapter, true); | 3920 | be_setup_wol(adapter, true); |
3853 | 3921 | ||
3922 | cancel_delayed_work_sync(&adapter->func_recovery_work); | ||
3923 | |||
3854 | netif_device_detach(netdev); | 3924 | netif_device_detach(netdev); |
3855 | if (netif_running(netdev)) { | 3925 | if (netif_running(netdev)) { |
3856 | rtnl_lock(); | 3926 | rtnl_lock(); |
@@ -3891,6 +3961,9 @@ static int be_resume(struct pci_dev *pdev) | |||
3891 | be_open(netdev); | 3961 | be_open(netdev); |
3892 | rtnl_unlock(); | 3962 | rtnl_unlock(); |
3893 | } | 3963 | } |
3964 | |||
3965 | schedule_delayed_work(&adapter->func_recovery_work, | ||
3966 | msecs_to_jiffies(1000)); | ||
3894 | netif_device_attach(netdev); | 3967 | netif_device_attach(netdev); |
3895 | 3968 | ||
3896 | if (adapter->wol) | 3969 | if (adapter->wol) |
@@ -3910,6 +3983,7 @@ static void be_shutdown(struct pci_dev *pdev) | |||
3910 | return; | 3983 | return; |
3911 | 3984 | ||
3912 | cancel_delayed_work_sync(&adapter->work); | 3985 | cancel_delayed_work_sync(&adapter->work); |
3986 | cancel_delayed_work_sync(&adapter->func_recovery_work); | ||
3913 | 3987 | ||
3914 | netif_device_detach(adapter->netdev); | 3988 | netif_device_detach(adapter->netdev); |
3915 | 3989 | ||
@@ -3929,9 +4003,13 @@ static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev, | |||
3929 | 4003 | ||
3930 | dev_err(&adapter->pdev->dev, "EEH error detected\n"); | 4004 | dev_err(&adapter->pdev->dev, "EEH error detected\n"); |
3931 | 4005 | ||
3932 | adapter->eeh_err = true; | 4006 | adapter->eeh_error = true; |
4007 | |||
4008 | cancel_delayed_work_sync(&adapter->func_recovery_work); | ||
3933 | 4009 | ||
4010 | rtnl_lock(); | ||
3934 | netif_device_detach(netdev); | 4011 | netif_device_detach(netdev); |
4012 | rtnl_unlock(); | ||
3935 | 4013 | ||
3936 | if (netif_running(netdev)) { | 4014 | if (netif_running(netdev)) { |
3937 | rtnl_lock(); | 4015 | rtnl_lock(); |
@@ -3959,9 +4037,7 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev) | |||
3959 | int status; | 4037 | int status; |
3960 | 4038 | ||
3961 | dev_info(&adapter->pdev->dev, "EEH reset\n"); | 4039 | dev_info(&adapter->pdev->dev, "EEH reset\n"); |
3962 | adapter->eeh_err = false; | 4040 | be_clear_all_error(adapter); |
3963 | adapter->ue_detected = false; | ||
3964 | adapter->fw_timeout = false; | ||
3965 | 4041 | ||
3966 | status = pci_enable_device(pdev); | 4042 | status = pci_enable_device(pdev); |
3967 | if (status) | 4043 | if (status) |
@@ -4007,6 +4083,9 @@ static void be_eeh_resume(struct pci_dev *pdev) | |||
4007 | if (status) | 4083 | if (status) |
4008 | goto err; | 4084 | goto err; |
4009 | } | 4085 | } |
4086 | |||
4087 | schedule_delayed_work(&adapter->func_recovery_work, | ||
4088 | msecs_to_jiffies(1000)); | ||
4010 | netif_device_attach(netdev); | 4089 | netif_device_attach(netdev); |
4011 | return; | 4090 | return; |
4012 | err: | 4091 | err: |