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>
This commit is contained in:
Piotr Kwapulinski 2019-07-23 06:01:41 -04:00 committed by Jeff Kirsher
parent 541d97310a
commit a39f165db5
3 changed files with 63 additions and 8 deletions

View File

@ -13,7 +13,7 @@
* This function sets the mac type of the adapter based on the
* vendor ID and device ID stored in the hw structure.
**/
static i40e_status i40e_set_mac_type(struct i40e_hw *hw)
i40e_status i40e_set_mac_type(struct i40e_hw *hw)
{
i40e_status status = 0;

View File

@ -14564,6 +14564,51 @@ static bool i40e_check_recovery_mode(struct i40e_pf *pf)
return false;
}
/**
* 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
@ -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;

View File

@ -326,6 +326,8 @@ void i40e_nvmupd_check_wait_event(struct i40e_hw *hw, u16 opcode,
void i40e_nvmupd_clear_wait_state(struct i40e_hw *hw);
void i40e_set_pci_config_data(struct i40e_hw *hw, u16 link_status);
i40e_status i40e_set_mac_type(struct i40e_hw *hw);
extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[];
static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype)