diff options
author | Piotr Kwapulinski <piotr.kwapulinski@intel.com> | 2019-07-23 06:01:41 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2019-08-22 13:24:14 -0700 |
commit | a39f165db5c4f00becb3e50d65ea2321df64cdf3 (patch) | |
tree | 5e4de637a1bc592a9199e7bb03ff5c3a05b040af /drivers/net/ethernet/intel/i40e/i40e_main.c | |
parent | 541d97310ae3c02675578a236674e0bea1ad6483 (diff) | |
download | linux-a39f165db5c4f00becb3e50d65ea2321df64cdf3.tar.gz linux-a39f165db5c4f00becb3e50d65ea2321df64cdf3.tar.bz2 linux-a39f165db5c4f00becb3e50d65ea2321df64cdf3.zip |
i40e: allow reset in recovery mode
Driver waits after issuing a reset. When a reset takes too long a driver
gives up. Implemented by invoking PF reset in a loop. After defined
number of unsuccessful PF reset trials it returns error.
Without this patch PF reset fails when NIC is in recovery mode.
So make i40e_set_mac_type() public. i40e driver requires i40e_set_mac_type()
to be public. It is required for recovery mode handling. Without this patch
recovery mode could not be detected in i40e_probe().
Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/i40e/i40e_main.c')
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_main.c | 67 |
1 files changed, 60 insertions, 7 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 8d6b9515b595..fdf43d87e983 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -14565,6 +14565,51 @@ static bool i40e_check_recovery_mode(struct i40e_pf *pf) } /** + * i40e_pf_loop_reset - perform reset in a loop. + * @pf: board private structure + * + * This function is useful when a NIC is about to enter recovery mode. + * When a NIC's internal data structures are corrupted the NIC's + * firmware is going to enter recovery mode. + * Right after a POR it takes about 7 minutes for firmware to enter + * recovery mode. Until that time a NIC is in some kind of intermediate + * state. After that time period the NIC almost surely enters + * recovery mode. The only way for a driver to detect intermediate + * state is to issue a series of pf-resets and check a return value. + * If a PF reset returns success then the firmware could be in recovery + * mode so the caller of this code needs to check for recovery mode + * if this function returns success. There is a little chance that + * firmware will hang in intermediate state forever. + * Since waiting 7 minutes is quite a lot of time this function waits + * 10 seconds and then gives up by returning an error. + * + * Return 0 on success, negative on failure. + **/ +static i40e_status i40e_pf_loop_reset(struct i40e_pf *pf) +{ + const unsigned short MAX_CNT = 1000; + const unsigned short MSECS = 10; + struct i40e_hw *hw = &pf->hw; + i40e_status ret; + int cnt; + + for (cnt = 0; cnt < MAX_CNT; ++cnt) { + ret = i40e_pf_reset(hw); + if (!ret) + break; + msleep(MSECS); + } + + if (cnt == MAX_CNT) { + dev_info(&pf->pdev->dev, "PF reset failed: %d\n", ret); + return ret; + } + + pf->pfr_count++; + return ret; +} + +/** * i40e_init_recovery_mode - initialize subsystems needed in recovery mode * @pf: board private structure * @hw: ptr to the hardware info @@ -14792,14 +14837,22 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Reset here to make sure all is clean and to define PF 'n' */ i40e_clear_hw(hw); - if (!i40e_check_recovery_mode(pf)) { - err = i40e_pf_reset(hw); - if (err) { - dev_info(&pdev->dev, "Initial pf_reset failed: %d\n", err); - goto err_pf_reset; - } - pf->pfr_count++; + + err = i40e_set_mac_type(hw); + if (err) { + dev_warn(&pdev->dev, "unidentified MAC or BLANK NVM: %d\n", + err); + goto err_pf_reset; } + + err = i40e_pf_loop_reset(pf); + if (err) { + dev_info(&pdev->dev, "Initial pf_reset failed: %d\n", err); + goto err_pf_reset; + } + + i40e_check_recovery_mode(pf); + hw->aq.num_arq_entries = I40E_AQ_LEN; hw->aq.num_asq_entries = I40E_AQ_LEN; hw->aq.arq_buf_size = I40E_MAX_AQ_BUF_SIZE; |