Merge branch 'pci/err'

- For drivers using PCI legacy suspend, save config state at suspend so
  that state (not any earlier state from enumeration, probe, or error
  recovery) will be restored when resuming (Lukas Wunner)

- For devices with no driver or a driver that lacks PM, save config state
  at hibernate so that state (not any earlier state from enumeration,
  probe, or error recovery) will be restored when resuming (Lukas Wunner)

- Save device config space on device addition, before driver binding, so
  error recovery works more reliably (Lukas Wunner)

- Drop pci_save_state() from several drivers that no longer need it since
  the PCI core always does it and pci_restore_state() no longer invalidates
  the saved state (Lukas Wunner)

- Document use of pci_save_state() by drivers to capture the state they
  want restored during error recovery (Lukas Wunner)

* pci/err:
  Documentation: PCI: Amend error recovery doc with pci_save_state() rules
  treewide: Drop pci_save_state() after pci_restore_state()
  PCI/ERR: Ensure error recoverability at all times
  PCI/PM: Stop needlessly clearing state_saved on enumeration and thaw
  PCI/PM: Reinstate clearing state_saved in legacy and !PM codepaths
This commit is contained in:
Bjorn Helgaas
2025-12-03 14:18:31 -06:00
35 changed files with 22 additions and 64 deletions

View File

@@ -326,6 +326,21 @@ be recovered, there is nothing more that can be done; the platform
will typically report a "permanent failure" in such a case. The
device will be considered "dead" in this case.
Drivers typically need to call pci_restore_state() after reset to
re-initialize the device's config space registers and thereby
bring it from D0\ :sub:`uninitialized` into D0\ :sub:`active` state
(PCIe r7.0 sec 5.3.1.1). The PCI core invokes pci_save_state()
on enumeration after initializing config space to ensure that a
saved state is available for subsequent error recovery.
Drivers which modify config space on probe may need to invoke
pci_save_state() afterwards to record those changes for later
error recovery. When going into system suspend, pci_save_state()
is called for every PCI device and that state will be restored
not only on resume, but also on any subsequent error recovery.
In the unlikely event that the saved state recorded on suspend
is unsuitable for error recovery, drivers should call
pci_save_state() on resume.
Drivers for multi-function cards will need to coordinate among
themselves as to which driver instance will perform any "one-shot"
or global device initialization. For example, the Symbios sym53cxx2

View File

@@ -105,7 +105,6 @@ void adf_dev_restore(struct adf_accel_dev *accel_dev)
accel_dev->accel_id);
hw_device->reset_device(accel_dev);
pci_restore_state(pdev);
pci_save_state(pdev);
}
}
@@ -204,7 +203,6 @@ static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev)
if (!pdev->is_busmaster)
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
res = adf_dev_up(accel_dev, false);
if (res && res != -EALREADY)
return PCI_ERS_RESULT_DISCONNECT;

View File

@@ -1286,7 +1286,6 @@ static pci_ers_result_t ioat_pcie_error_slot_reset(struct pci_dev *pdev)
} else {
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
pci_wake_from_d3(pdev, false);
}

View File

@@ -6444,7 +6444,6 @@ bnx2_reset_task(struct work_struct *work)
if (!(pcicmd & PCI_COMMAND_MEMORY)) {
/* in case PCI block has reset */
pci_restore_state(bp->pdev);
pci_save_state(bp->pdev);
}
rc = bnx2_init_nic(bp, 1);
if (rc) {
@@ -8718,7 +8717,6 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
} else {
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
if (netif_running(dev))
err = bnx2_init_nic(bp, 1);

View File

@@ -14216,7 +14216,6 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
if (netif_running(dev))
bnx2x_set_power_state(bp, PCI_D0);

View File

@@ -18352,7 +18352,6 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
if (!netdev || !netif_running(netdev)) {
rc = PCI_ERS_RESULT_RECOVERED;

View File

@@ -2933,7 +2933,6 @@ static int t3_reenable_adapter(struct adapter *adapter)
}
pci_set_master(adapter->pdev);
pci_restore_state(adapter->pdev);
pci_save_state(adapter->pdev);
/* Free sge resources */
t3_free_sge_resources(adapter);

View File

@@ -5456,7 +5456,6 @@ static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev)
if (!adap) {
pci_restore_state(pdev);
pci_save_state(pdev);
return PCI_ERS_RESULT_RECOVERED;
}
@@ -5471,7 +5470,6 @@ static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
if (t4_wait_dev_ready(adap->regs) < 0)
return PCI_ERS_RESULT_DISCONNECT;

View File

@@ -158,7 +158,6 @@ static pci_ers_result_t hbg_pci_err_slot_reset(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
hbg_err_reset(priv);
return PCI_ERS_RESULT_RECOVERED;

View File

@@ -7195,7 +7195,6 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
"Cannot re-enable PCI device after reset.\n");
result = PCI_ERS_RESULT_DISCONNECT;
} else {
pdev->state_saved = true;
pci_restore_state(pdev);
pci_set_master(pdev);

View File

@@ -2423,12 +2423,6 @@ static pci_ers_result_t fm10k_io_slot_reset(struct pci_dev *pdev)
} else {
pci_set_master(pdev);
pci_restore_state(pdev);
/* After second error pci->state_saved is false, this
* resets it so EEH doesn't break.
*/
pci_save_state(pdev);
pci_wake_from_d3(pdev, false);
result = PCI_ERS_RESULT_RECOVERED;

View File

@@ -16455,7 +16455,6 @@ static pci_ers_result_t i40e_pci_error_slot_reset(struct pci_dev *pdev)
} else {
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
pci_wake_from_d3(pdev, false);
reg = rd32(&pf->hw, I40E_GLGEN_RTRIG);

View File

@@ -5663,7 +5663,6 @@ static int ice_resume(struct device *dev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_save_state(pdev);
if (!pci_device_is_present(pdev))
return -ENODEV;
@@ -5763,7 +5762,6 @@ static pci_ers_result_t ice_pci_err_slot_reset(struct pci_dev *pdev)
} else {
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
pci_wake_from_d3(pdev, false);
/* Check for life */

View File

@@ -9599,7 +9599,6 @@ static int __igb_resume(struct device *dev, bool rpm)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_save_state(pdev);
if (!pci_device_is_present(pdev))
return -ENODEV;
@@ -9754,7 +9753,6 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev)
} else {
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_enable_wake(pdev, PCI_D3cold, 0);

View File

@@ -7530,7 +7530,6 @@ static int __igc_resume(struct device *dev, bool rpm)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_save_state(pdev);
if (!pci_device_is_present(pdev))
return -ENODEV;
@@ -7667,7 +7666,6 @@ static pci_ers_result_t igc_io_slot_reset(struct pci_dev *pdev)
} else {
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_enable_wake(pdev, PCI_D3cold, 0);

View File

@@ -12297,7 +12297,6 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
adapter->hw.hw_addr = adapter->io_addr;
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
pci_wake_from_d3(pdev, false);

View File

@@ -4366,7 +4366,6 @@ static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
return PCI_ERS_RESULT_RECOVERED;
}

View File

@@ -2095,7 +2095,6 @@ static pci_ers_result_t mlx5_pci_slot_reset(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
err = wait_vital(pdev);
if (err) {

View File

@@ -574,7 +574,6 @@ static pci_ers_result_t fbnic_err_slot_reset(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_save_state(pdev);
if (pci_enable_device_mem(pdev)) {
dev_err(&pdev->dev,

View File

@@ -3915,7 +3915,6 @@ static int lan743x_pm_resume(struct device *dev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_save_state(pdev);
/* Restore HW_CFG that was saved during pm suspend */
if (adapter->is_pci11x1x)

View File

@@ -3416,10 +3416,6 @@ static void myri10ge_watchdog(struct work_struct *work)
* nic was resumed from power saving mode.
*/
pci_restore_state(mgp->pdev);
/* save state again for accounting reasons */
pci_save_state(mgp->pdev);
} else {
/* if we get back -1's from our slot, perhaps somebody
* powered off our card. Don't try to reset it in

View File

@@ -3425,7 +3425,6 @@ static void s2io_reset(struct s2io_nic *sp)
/* Restore the PCI state saved during initialization. */
pci_restore_state(sp->pdev);
pci_save_state(sp->pdev);
pci_read_config_word(sp->pdev, 0x2, &val16);
if (check_pci_device_id(val16) != (u16)PCI_ANY_ID)
break;

View File

@@ -357,6 +357,9 @@ void pci_bus_add_device(struct pci_dev *dev)
pci_proc_attach_device(dev);
pci_bridge_d3_update(dev);
/* Save config space for error recoverability */
pci_save_state(dev);
/*
* If the PCI device is associated with a pwrctrl device with a
* power supply, create a device link between the PCI device and

View File

@@ -629,6 +629,8 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state)
struct pci_dev *pci_dev = to_pci_dev(dev);
struct pci_driver *drv = pci_dev->driver;
pci_dev->state_saved = false;
if (drv && drv->suspend) {
pci_power_t prev = pci_dev->current_state;
int error;
@@ -1036,6 +1038,8 @@ static int pci_pm_freeze(struct device *dev)
if (!pm) {
pci_pm_default_suspend(pci_dev);
if (!pm_runtime_suspended(dev))
pci_dev->state_saved = false;
return 0;
}
@@ -1129,8 +1133,6 @@ static int pci_pm_thaw(struct device *dev)
pci_pm_reenable_device(pci_dev);
}
pci_dev->state_saved = false;
return error;
}

View File

@@ -1855,9 +1855,6 @@ static void pci_restore_rebar_state(struct pci_dev *pdev)
*/
void pci_restore_state(struct pci_dev *dev)
{
if (!dev->state_saved)
return;
pci_restore_pcie_state(dev);
pci_restore_pasid_state(dev);
pci_restore_pri_state(dev);

View File

@@ -760,7 +760,6 @@ static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
device_for_each_child(&dev->dev, &off, pcie_port_device_iter);
pci_restore_state(dev);
pci_save_state(dev);
return PCI_ERS_RESULT_RECOVERED;
}

View File

@@ -2753,8 +2753,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
pci_reassigndev_resource_alignment(dev);
dev->state_saved = false;
pci_init_capabilities(dev);
/*

View File

@@ -1528,7 +1528,6 @@ bfad_pci_slot_reset(struct pci_dev *pdev)
goto out_disable_device;
}
pci_save_state(pdev);
pci_set_master(pdev);
rc = dma_set_mask_and_coherent(&bfad->pcidev->dev, DMA_BIT_MASK(64));

View File

@@ -1093,7 +1093,6 @@ csio_pci_slot_reset(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
/* Bring HW s/m to ready state.
* but don't resume IOs.

View File

@@ -7859,7 +7859,6 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
ENTER;
ioa_cfg->pdev->state_saved = true;
pci_restore_state(ioa_cfg->pdev);
if (ipr_set_pcix_cmd_reg(ioa_cfg)) {

View File

@@ -14434,12 +14434,6 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev)
pci_restore_state(pdev);
/*
* As the new kernel behavior of pci_restore_state() API call clears
* device saved_state flag, need to save the restored state again.
*/
pci_save_state(pdev);
if (pdev->is_busmaster)
pci_set_master(pdev);

View File

@@ -7886,11 +7886,6 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
pci_restore_state(pdev);
/* pci_restore_state() clears the saved_state flag of the device
* save restored state which resets saved_state flag
*/
pci_save_state(pdev);
if (ha->mem_only)
rc = pci_enable_device_mem(pdev);
else

View File

@@ -9796,11 +9796,6 @@ qla4xxx_pci_slot_reset(struct pci_dev *pdev)
*/
pci_restore_state(pdev);
/* pci_restore_state() clears the saved_state flag of the device
* save restored state which resets saved_state flag
*/
pci_save_state(pdev);
/* Initialize device or resume if in suspended state */
rc = pci_enable_device(pdev);
if (rc) {

View File

@@ -6178,7 +6178,6 @@ static pci_ers_result_t serial8250_io_slot_reset(struct pci_dev *dev)
return PCI_ERS_RESULT_DISCONNECT;
pci_restore_state(dev);
pci_save_state(dev);
return PCI_ERS_RESULT_RECOVERED;
}

View File

@@ -355,7 +355,6 @@ static void jsm_io_resume(struct pci_dev *pdev)
struct jsm_board *brd = pci_get_drvdata(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
jsm_uart_port_init(brd);
}