Commit c2a3d213 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/aer'

  - Restore AER capability after resume (Mayurkumar Patel)

  - Add PoisonTLPBlocked AER counter (Rajat Jain)

  - Use for_each_set_bit() to simplify AER code (Andy Shevchenko)

  - Fix AER kernel-doc (Andy Shevchenko)

  - Add "pcie_ports=dpc-native" parameter to allow native use of DPC even
    if platform didn't grant control over AER (Olof Johansson)

* pci/aer:
  PCI/DPC: Add "pcie_ports=dpc-native" to allow DPC without AER control
  PCI/AER: Fix kernel-doc warnings
  PCI/AER: Use for_each_set_bit() to simplify code
  PCI/AER: Add PoisonTLPBlocked to Uncorrectable error counters
  PCI/AER: Save AER Capability for suspend/resume
parents 7d194c21 35a0b237
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -3540,6 +3540,8 @@
			even if the platform doesn't give the OS permission to
			use them.  This may cause conflicts if the platform
			also tries to use these services.
		dpc-native	Use native PCIe service for DPC only.  May
				cause conflicts if firmware uses AER or DPC.
		compat	Disable native PCIe services (PME, AER, DPC, PCIe
			hotplug).

+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
@@ -1359,6 +1359,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);
@@ -1472,6 +1473,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 */

+73 −15
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#define pr_fmt(fmt) "AER: " fmt
#define dev_fmt pr_fmt

#include <linux/bitops.h>
#include <linux/cper.h>
#include <linux/pci.h>
#include <linux/pci-acpi.h>
@@ -36,7 +37,7 @@
#define AER_ERROR_SOURCES_MAX		128

#define AER_MAX_TYPEOF_COR_ERRS		16	/* as per PCI_ERR_COR_STATUS */
#define AER_MAX_TYPEOF_UNCOR_ERRS	26	/* as per PCI_ERR_UNCOR_STATUS*/
#define AER_MAX_TYPEOF_UNCOR_ERRS	27	/* as per PCI_ERR_UNCOR_STATUS*/

struct aer_err_source {
	unsigned int status;
@@ -201,6 +202,7 @@ void pcie_set_ecrc_checking(struct pci_dev *dev)

/**
 * pcie_ecrc_get_policy - parse kernel command-line ecrc option
 * @str: ECRC policy from kernel command line to use
 */
void pcie_ecrc_get_policy(char *str)
{
@@ -448,13 +450,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);
}

@@ -560,6 +620,7 @@ static const char *aer_uncorrectable_error_string[AER_MAX_TYPEOF_UNCOR_ERRS] = {
	"BlockedTLP",			/* Bit Position 23	*/
	"AtomicOpBlocked",		/* Bit Position 24	*/
	"TLPBlockedErr",		/* Bit Position 25	*/
	"PoisonTLPBlocked",		/* Bit Position 26	*/
};

static const char *aer_agent_string[] = {
@@ -657,7 +718,8 @@ const struct attribute_group aer_stats_attr_group = {
static void pci_dev_aer_stats_incr(struct pci_dev *pdev,
				   struct aer_err_info *info)
{
	int status, i, max = -1;
	unsigned long status = info->status & ~info->mask;
	int i, max = -1;
	u64 *counter = NULL;
	struct aer_stats *aer_stats = pdev->aer_stats;

@@ -682,9 +744,7 @@ static void pci_dev_aer_stats_incr(struct pci_dev *pdev,
		break;
	}

	status = (info->status & ~info->mask);
	for (i = 0; i < max; i++)
		if (status & (1 << i))
	for_each_set_bit(i, &status, max)
		counter[i]++;
}

@@ -717,14 +777,11 @@ static void __print_tlp_header(struct pci_dev *dev,
static void __aer_print_error(struct pci_dev *dev,
			      struct aer_err_info *info)
{
	int i, status;
	unsigned long status = info->status & ~info->mask;
	const char *errmsg = NULL;
	status = (info->status & ~info->mask);

	for (i = 0; i < 32; i++) {
		if (!(status & (1 << i)))
			continue;
	int i;

	for_each_set_bit(i, &status, 32) {
		if (info->severity == AER_CORRECTABLE)
			errmsg = i < ARRAY_SIZE(aer_correctable_error_string) ?
				aer_correctable_error_string[i] : NULL;
@@ -1204,7 +1261,8 @@ static void aer_isr_one_error(struct aer_rpc *rpc,

/**
 * aer_isr - consume errors detected by root port
 * @work: definition of this work item
 * @irq: IRQ assigned to Root Port
 * @context: pointer to Root Port data structure
 *
 * Invoked, as DPC, when root port records new detected error
 */
Loading