|
@@ -8354,6 +8354,57 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef CONFIG_PM
|
|
|
|
+/**
|
|
|
|
+ * i40e_restore_interrupt_scheme - Restore the interrupt scheme
|
|
|
|
+ * @pf: private board data structure
|
|
|
|
+ *
|
|
|
|
+ * Restore the interrupt scheme that was cleared when we suspended the
|
|
|
|
+ * device. This should be called during resume to re-allocate the q_vectors
|
|
|
|
+ * and reacquire IRQs.
|
|
|
|
+ */
|
|
|
|
+static int i40e_restore_interrupt_scheme(struct i40e_pf *pf)
|
|
|
|
+{
|
|
|
|
+ int err, i;
|
|
|
|
+
|
|
|
|
+ /* We cleared the MSI and MSI-X flags when disabling the old interrupt
|
|
|
|
+ * scheme. We need to re-enabled them here in order to attempt to
|
|
|
|
+ * re-acquire the MSI or MSI-X vectors
|
|
|
|
+ */
|
|
|
|
+ pf->flags |= (I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED);
|
|
|
|
+
|
|
|
|
+ err = i40e_init_interrupt_scheme(pf);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ /* Now that we've re-acquired IRQs, we need to remap the vectors and
|
|
|
|
+ * rings together again.
|
|
|
|
+ */
|
|
|
|
+ for (i = 0; i < pf->num_alloc_vsi; i++) {
|
|
|
|
+ if (pf->vsi[i]) {
|
|
|
|
+ err = i40e_vsi_alloc_q_vectors(pf->vsi[i]);
|
|
|
|
+ if (err)
|
|
|
|
+ goto err_unwind;
|
|
|
|
+ i40e_vsi_map_rings_to_vectors(pf->vsi[i]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err = i40e_setup_misc_vector(pf);
|
|
|
|
+ if (err)
|
|
|
|
+ goto err_unwind;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+err_unwind:
|
|
|
|
+ while (i--) {
|
|
|
|
+ if (pf->vsi[i])
|
|
|
|
+ i40e_vsi_free_q_vectors(pf->vsi[i]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return err;
|
|
|
|
+}
|
|
|
|
+#endif /* CONFIG_PM */
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* i40e_setup_misc_vector - Setup the misc vector to handle non queue events
|
|
* i40e_setup_misc_vector - Setup the misc vector to handle non queue events
|
|
* @pf: board private structure
|
|
* @pf: board private structure
|
|
@@ -12077,7 +12128,12 @@ static int i40e_suspend(struct device *dev)
|
|
wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
|
|
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));
|
|
wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
|
|
|
|
|
|
- i40e_free_misc_vector(pf);
|
|
|
|
|
|
+ /* Clear the interrupt scheme and release our IRQs so that the system
|
|
|
|
+ * can safely hibernate even when there are a large number of CPUs.
|
|
|
|
+ * Otherwise hibernation might fail when mapping all the vectors back
|
|
|
|
+ * to CPU0.
|
|
|
|
+ */
|
|
|
|
+ i40e_clear_interrupt_scheme(pf);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -12090,11 +12146,21 @@ static int i40e_resume(struct device *dev)
|
|
{
|
|
{
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
struct i40e_pf *pf = pci_get_drvdata(pdev);
|
|
struct i40e_pf *pf = pci_get_drvdata(pdev);
|
|
|
|
+ int err;
|
|
|
|
|
|
/* If we're not suspended, then there is nothing to do */
|
|
/* If we're not suspended, then there is nothing to do */
|
|
if (!test_bit(__I40E_SUSPENDED, pf->state))
|
|
if (!test_bit(__I40E_SUSPENDED, pf->state))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ /* We cleared the interrupt scheme when we suspended, so we need to
|
|
|
|
+ * restore it now to resume device functionality.
|
|
|
|
+ */
|
|
|
|
+ err = i40e_restore_interrupt_scheme(pf);
|
|
|
|
+ if (err) {
|
|
|
|
+ dev_err(&pdev->dev, "Cannot restore interrupt scheme: %d\n",
|
|
|
|
+ err);
|
|
|
|
+ }
|
|
|
|
+
|
|
clear_bit(__I40E_DOWN, pf->state);
|
|
clear_bit(__I40E_DOWN, pf->state);
|
|
i40e_reset_and_rebuild(pf, false, false);
|
|
i40e_reset_and_rebuild(pf, false, false);
|
|
|
|
|