PCI/AER: Add pci_aer_raw_clear_status() to unconditionally clear Error Status
Per the SFI _OSC and DPC Updates ECN [1] implementation note flowchart, the OS seems to be expected to clear AER status even if it doesn't have ownership of the AER capability. Unlike the DPC capability, where a DPC ECN [2] specifies a window when the OS is allowed to access DPC registers even if it doesn't have ownership, there is no clear model for AER. Add pci_aer_raw_clear_status() to clear the AER error status registers unconditionally. This is intended for use only by the EDR path (see [2]). [1] System Firmware Intermediary (SFI) _OSC and DPC Updates ECN, Feb 24, 2020, affecting PCI Firmware Specification, Rev. 3.2 https://members.pcisig.com/wg/PCI-SIG/document/14076 [2] Downstream Port Containment Related Enhancements ECN, Jan 28, 2019, affecting PCI Firmware Specification, Rev. 3.2 https://members.pcisig.com/wg/PCI-SIG/document/12888 [bhelgaas: changelog] Link: https://lore.kernel.org/r/c19ad28f3633cce67448609e89a75635da0da07d.1585000084.git.sathyanarayanan.kuppuswamy@linux.intel.com Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
parent
2700561817
commit
20e15e673b
|
@ -654,12 +654,14 @@ void pci_aer_exit(struct pci_dev *dev);
|
|||
extern const struct attribute_group aer_stats_attr_group;
|
||||
void pci_aer_clear_fatal_status(struct pci_dev *dev);
|
||||
void pci_aer_clear_device_status(struct pci_dev *dev);
|
||||
int pci_aer_raw_clear_status(struct pci_dev *dev);
|
||||
#else
|
||||
static inline void pci_no_aer(void) { }
|
||||
static inline void pci_aer_init(struct pci_dev *d) { }
|
||||
static inline void pci_aer_exit(struct pci_dev *d) { }
|
||||
static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
|
||||
static inline void pci_aer_clear_device_status(struct pci_dev *dev) { }
|
||||
static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
|
|
@ -420,7 +420,16 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
|
|||
pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
|
||||
}
|
||||
|
||||
int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
|
||||
/**
|
||||
* pci_aer_raw_clear_status - Clear AER error registers.
|
||||
* @dev: the PCI device
|
||||
*
|
||||
* Clearing AER error status registers unconditionally, regardless of
|
||||
* whether they're owned by firmware or the OS.
|
||||
*
|
||||
* Returns 0 on success, or negative on failure.
|
||||
*/
|
||||
int pci_aer_raw_clear_status(struct pci_dev *dev)
|
||||
{
|
||||
int pos;
|
||||
u32 status;
|
||||
|
@ -433,9 +442,6 @@ int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
|
|||
if (!pos)
|
||||
return -EIO;
|
||||
|
||||
if (pcie_aer_get_firmware_first(dev))
|
||||
return -EIO;
|
||||
|
||||
port_type = pci_pcie_type(dev);
|
||||
if (port_type == PCI_EXP_TYPE_ROOT_PORT) {
|
||||
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status);
|
||||
|
@ -451,6 +457,14 @@ int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
|
||||
{
|
||||
if (pcie_aer_get_firmware_first(dev))
|
||||
return -EIO;
|
||||
|
||||
return pci_aer_raw_clear_status(dev);
|
||||
}
|
||||
|
||||
void pci_save_aer_state(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_cap_saved_state *save_state;
|
||||
|
|
Loading…
Reference in New Issue