i40e: use separate state bit for miscellaneous IRQ setup
We currently (mis)use the __I40E_RECOVERY_PENDING bit to determine when we should actually request a new IRQ in i40e_setup_misc_vector(). This led to a design mistake where we open-coded the re-setup of the miscellaneous vector in i40e_resume() instead of using the function provided. If we did not open-code this and instead tried to use the i40e_setup_misc_vector() function, it would lead to never reallocating the IRQ. This would lead to a second i40e_suspend() call failing to free the vector due to a NULL pointer dereference. A future patch is going to re-work how the i40e_suspend() and i40e_resume() flows work to clear all IRQ vectors, which would require us to use i40e_setup_misc_vector() directly. Since during this time the __I40E_RECOVERY_PENDING bit is set, we'll never re-allocate the vector. Rather than leaving the open-coded setup in i40e_resume() lets just fix the problem properly in i40e_setup_misc_vector(). Introduce a new state bit which indicates when the IRQ has been assigned, which will be set when i40e_setup_misc_vector is first called. This ultimately resolves the issue of re-requesting the vector, without overloading the __I40E_RECOVERY_PENDING state. This ensures that the suspend/resume cycle can use the setup function instead of open-coding the re-request during resume. Additionally, since the only callers of i40e_stop_misc_vector also want to free it, move this code directly into the function to avoid duplication. Due to the new functionality, rename it to i40e_free_misc_vector(). This lets us drop the extra calls to free and re-enable the vector during i40e_suspend() and i40e_resume(). We don't need to call i40e_setup_misc_Vector() in i40e_resume() because it gets called by the i40e_rebuild() call. Signed-off-by: Jacob Keller <jacob.e.keller@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:
parent
905770fa3e
commit
c17401a1dd
|
@ -136,6 +136,7 @@ enum i40e_state_t {
|
|||
__I40E_MDD_EVENT_PENDING,
|
||||
__I40E_VFLR_EVENT_PENDING,
|
||||
__I40E_RESET_RECOVERY_PENDING,
|
||||
__I40E_MISC_IRQ_REQUESTED,
|
||||
__I40E_RESET_INTR_RECEIVED,
|
||||
__I40E_REINIT_REQUESTED,
|
||||
__I40E_PF_RESET_REQUESTED,
|
||||
|
|
|
@ -3604,14 +3604,20 @@ static int i40e_vsi_enable_irq(struct i40e_vsi *vsi)
|
|||
}
|
||||
|
||||
/**
|
||||
* i40e_stop_misc_vector - Stop the vector that handles non-queue events
|
||||
* i40e_free_misc_vector - Free the vector that handles non-queue events
|
||||
* @pf: board private structure
|
||||
**/
|
||||
static void i40e_stop_misc_vector(struct i40e_pf *pf)
|
||||
static void i40e_free_misc_vector(struct i40e_pf *pf)
|
||||
{
|
||||
/* Disable ICR 0 */
|
||||
wr32(&pf->hw, I40E_PFINT_ICR0_ENA, 0);
|
||||
i40e_flush(&pf->hw);
|
||||
|
||||
if (pf->flags & I40E_FLAG_MSIX_ENABLED && pf->msix_entries) {
|
||||
synchronize_irq(pf->msix_entries[0].vector);
|
||||
free_irq(pf->msix_entries[0].vector, pf);
|
||||
clear_bit(__I40E_MISC_IRQ_REQUESTED, pf->state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4466,11 +4472,7 @@ static void i40e_clear_interrupt_scheme(struct i40e_pf *pf)
|
|||
{
|
||||
int i;
|
||||
|
||||
i40e_stop_misc_vector(pf);
|
||||
if (pf->flags & I40E_FLAG_MSIX_ENABLED && pf->msix_entries) {
|
||||
synchronize_irq(pf->msix_entries[0].vector);
|
||||
free_irq(pf->msix_entries[0].vector, pf);
|
||||
}
|
||||
i40e_free_misc_vector(pf);
|
||||
|
||||
i40e_put_lump(pf->irq_pile, pf->iwarp_base_vector,
|
||||
I40E_IWARP_IRQ_PILE_ID);
|
||||
|
@ -8365,13 +8367,12 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
|
|||
struct i40e_hw *hw = &pf->hw;
|
||||
int err = 0;
|
||||
|
||||
/* Only request the irq if this is the first time through, and
|
||||
* not when we're rebuilding after a Reset
|
||||
*/
|
||||
if (!test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state)) {
|
||||
/* Only request the IRQ once, the first time through. */
|
||||
if (!test_and_set_bit(__I40E_MISC_IRQ_REQUESTED, pf->state)) {
|
||||
err = request_irq(pf->msix_entries[0].vector,
|
||||
i40e_intr, 0, pf->int_name, pf);
|
||||
if (err) {
|
||||
clear_bit(__I40E_MISC_IRQ_REQUESTED, pf->state);
|
||||
dev_info(&pf->pdev->dev,
|
||||
"request_irq for %s failed: %d\n",
|
||||
pf->int_name, err);
|
||||
|
@ -12069,11 +12070,8 @@ static int i40e_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
|
||||
wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
|
||||
|
||||
i40e_stop_misc_vector(pf);
|
||||
if (pf->msix_entries) {
|
||||
synchronize_irq(pf->msix_entries[0].vector);
|
||||
free_irq(pf->msix_entries[0].vector, pf);
|
||||
}
|
||||
i40e_free_misc_vector(pf);
|
||||
|
||||
retval = pci_save_state(pdev);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
@ -12113,15 +12111,6 @@ static int i40e_resume(struct pci_dev *pdev)
|
|||
/* handling the reset will rebuild the device state */
|
||||
if (test_and_clear_bit(__I40E_SUSPENDED, pf->state)) {
|
||||
clear_bit(__I40E_DOWN, pf->state);
|
||||
if (pf->msix_entries) {
|
||||
err = request_irq(pf->msix_entries[0].vector,
|
||||
i40e_intr, 0, pf->int_name, pf);
|
||||
if (err) {
|
||||
dev_err(&pf->pdev->dev,
|
||||
"request_irq for %s failed: %d\n",
|
||||
pf->int_name, err);
|
||||
}
|
||||
}
|
||||
i40e_reset_and_rebuild(pf, false, false);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue