]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI/EDR: Clear Device Status after EDR error recovery
authorKuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Wed, 15 Mar 2023 23:54:49 +0000 (16:54 -0700)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 7 Apr 2023 21:43:18 +0000 (16:43 -0500)
During EDR recovery, the OS must clear error status of the port that
triggered DPC even if firmware retains control of DPC and AER (see the
implementation note in the PCI Firmware spec r3.3, sec 4.6.12).

Prior to 068c29a248b6 ("PCI/ERR: Clear PCIe Device Status errors only if
OS owns AER"), the port Device Status was cleared in this path:

  edr_handle_event
    dpc_process_error(dev)                 # "dev" triggered DPC
    pcie_do_recovery(dev, dpc_reset_link)
      dpc_reset_link                       # exit DPC
      pcie_clear_device_status(dev)        # clear Device Status

After 068c29a248b6, pcie_do_recovery() no longer clears Device Status when
firmware controls AER, so the error bit remains set even after recovery.

Per the "Downstream Port Containment configuration control" bit in the
returned _OSC Control Field (sec 4.5.1), the OS is allowed to clear error
status until it evaluates _OST, so clear Device Status in
edr_handle_event() if the error recovery was successful.

[bhelgaas: commit log]
Fixes: 068c29a248b6 ("PCI/ERR: Clear PCIe Device Status errors only if OS owns AER")
Link: https://lore.kernel.org/r/20230315235449.1279209-1-sathyanarayanan.kuppuswamy@linux.intel.com
Reported-by: Tsaur Erwin <erwin.tsaur@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
drivers/pci/pcie/edr.c

index a6b9b479b97ad0c778820e366f814378d50e3177..87734e4c3c2047f40f8904a045c279da33ecfbd3 100644 (file)
@@ -193,6 +193,7 @@ send_ost:
         */
        if (estate == PCI_ERS_RESULT_RECOVERED) {
                pci_dbg(edev, "DPC port successfully recovered\n");
+               pcie_clear_device_status(edev);
                acpi_send_edr_status(pdev, edev, EDR_OST_SUCCESS);
        } else {
                pci_dbg(edev, "DPC port recovery failed\n");