Commit af65d1ad authored by Patel, Mayurkumar's avatar Patel, Mayurkumar Committed by Bjorn Helgaas
Browse files

PCI/AER: Save AER Capability for suspend/resume

Previously we did not save and restore the AER configuration on
suspend/resume, so the configuration may be lost after resume.

Save the AER configuration during suspend and restore it during resume.

[bhelgaas: commit log]
Link: https://lore.kernel.org/r/92EBB4272BF81E4089A7126EC1E7B28492C3B007@IRSMSX101.ger.corp.intel.com


Signed-off-by: default avatarMayurkumar Patel <mayurkumar.patel@intel.com>
Signed-off-by: default avatarKuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
parent 54ecb8f7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -355,7 +355,7 @@ static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev)
	       pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT;
}

static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev)
bool pcie_cap_has_rtctl(const struct pci_dev *dev)
{
	int type = pci_pcie_type(dev);

+2 −0
Original line number Diff line number Diff line
@@ -1361,6 +1361,7 @@ int pci_save_state(struct pci_dev *dev)

	pci_save_ltr_state(dev);
	pci_save_dpc_state(dev);
	pci_save_aer_state(dev);
	return pci_save_vc_state(dev);
}
EXPORT_SYMBOL(pci_save_state);
@@ -1474,6 +1475,7 @@ void pci_restore_state(struct pci_dev *dev)
	pci_restore_dpc_state(dev);

	pci_cleanup_aer_error_status_regs(dev);
	pci_restore_aer_state(dev);

	pci_restore_config_space(dev);

+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ extern const unsigned char pcie_link_speed[];
extern bool pci_early_dump;

bool pcie_cap_has_lnkctl(const struct pci_dev *dev);
bool pcie_cap_has_rtctl(const struct pci_dev *dev);

/* Functions internal to the PCI core code */

+60 −2
Original line number Diff line number Diff line
@@ -448,13 +448,71 @@ int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
	return 0;
}

void pci_save_aer_state(struct pci_dev *dev)
{
	struct pci_cap_saved_state *save_state;
	u32 *cap;
	int pos;

	pos = dev->aer_cap;
	if (!pos)
		return;

	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_ERR);
	if (!save_state)
		return;

	cap = &save_state->cap.data[0];
	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, cap++);
	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, cap++);
	pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, cap++);
	pci_read_config_dword(dev, pos + PCI_ERR_CAP, cap++);
	if (pcie_cap_has_rtctl(dev))
		pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, cap++);
}

void pci_restore_aer_state(struct pci_dev *dev)
{
	struct pci_cap_saved_state *save_state;
	u32 *cap;
	int pos;

	pos = dev->aer_cap;
	if (!pos)
		return;

	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_ERR);
	if (!save_state)
		return;

	cap = &save_state->cap.data[0];
	pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, *cap++);
	pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, *cap++);
	pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, *cap++);
	pci_write_config_dword(dev, pos + PCI_ERR_CAP, *cap++);
	if (pcie_cap_has_rtctl(dev))
		pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, *cap++);
}

void pci_aer_init(struct pci_dev *dev)
{
	int n;

	dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
	if (!dev->aer_cap)
		return;

	if (dev->aer_cap)
	dev->aer_stats = kzalloc(sizeof(struct aer_stats), GFP_KERNEL);

	/*
	 * We save/restore PCI_ERR_UNCOR_MASK, PCI_ERR_UNCOR_SEVER,
	 * PCI_ERR_COR_MASK, and PCI_ERR_CAP.  Root and Root Complex Event
	 * Collectors also implement PCI_ERR_ROOT_COMMAND (PCIe r5.0, sec
	 * 7.8.4).
	 */
	n = pcie_cap_has_rtctl(dev) ? 5 : 4;
	pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_ERR, sizeof(u32) * n);

	pci_cleanup_aer_error_status_regs(dev);
}

+4 −0
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev);
int pci_disable_pcie_error_reporting(struct pci_dev *dev);
int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
int pci_cleanup_aer_error_status_regs(struct pci_dev *dev);
void pci_save_aer_state(struct pci_dev *dev);
void pci_restore_aer_state(struct pci_dev *dev);
#else
static inline int pci_enable_pcie_error_reporting(struct pci_dev *dev)
{
@@ -63,6 +65,8 @@ static inline int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
{
	return -EINVAL;
}
static inline void pci_save_aer_state(struct pci_dev *dev) {}
static inline void pci_restore_aer_state(struct pci_dev *dev) {}
#endif

void cper_print_aer(struct pci_dev *dev, int aer_severity,