Commit 8810a9c4 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/error'

  - Log only ACPI_NOTIFY_DISCONNECT_RECOVER events for EDR, not all ACPI
    SYSTEM-level events (Kuppuswamy Sathyanarayanan)

  - Rely only on _OSC (not _OSC + HEST FIRMWARE_FIRST) to negotiate AER
    Capability ownership (Alexandru Gagniuc)

  - Remove HEST/FIRMWARE_FIRST parsing that was previously used to help
    intuit AER Capability ownership (Kuppuswamy Sathyanarayanan)

  - Remove redundant pci_is_pcie() and dev->aer_cap checks (Kuppuswamy
    Sathyanarayanan)

  - Print IRQ number used by DPC (Yicong Yang)

* pci/error:
  PCI/DPC: Print IRQ number used by port
  PCI/AER: Use "aer" variable for capability offset
  PCI/AER: Remove redundant dev->aer_cap checks
  PCI/AER: Remove redundant pci_is_pcie() checks
  PCI/AER: Remove HEST/FIRMWARE_FIRST parsing for AER ownership
  PCI/AER: Use only _OSC to determine AER ownership
  PCI/EDR: Log only ACPI_NOTIFY_DISCONNECT_RECOVER events
parents 8ab064e9 9103aaf9
Loading
Loading
Loading
Loading
+2 −7
Original line number Diff line number Diff line
@@ -483,13 +483,8 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,
	if (IS_ENABLED(CONFIG_HOTPLUG_PCI_SHPC))
		control |= OSC_PCI_SHPC_NATIVE_HP_CONTROL;

	if (pci_aer_available()) {
		if (aer_acpi_firmware_first())
			dev_info(&device->dev,
				 "PCIe AER handled by firmware\n");
		else
	if (pci_aer_available())
		control |= OSC_PCI_EXPRESS_AER_CONTROL;
	}

	/*
	 * Per the Downstream Port Containment Related Enhancements ECN to
+96 −244
Original line number Diff line number Diff line
@@ -136,22 +136,18 @@ static const char * const ecrc_policy_str[] = {
 */
static int enable_ecrc_checking(struct pci_dev *dev)
{
	int pos;
	int aer = dev->aer_cap;
	u32 reg32;

	if (!pci_is_pcie(dev))
	if (!aer)
		return -ENODEV;

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

	pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
	pci_read_config_dword(dev, aer + PCI_ERR_CAP, &reg32);
	if (reg32 & PCI_ERR_CAP_ECRC_GENC)
		reg32 |= PCI_ERR_CAP_ECRC_GENE;
	if (reg32 & PCI_ERR_CAP_ECRC_CHKC)
		reg32 |= PCI_ERR_CAP_ECRC_CHKE;
	pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
	pci_write_config_dword(dev, aer + PCI_ERR_CAP, reg32);

	return 0;
}
@@ -164,19 +160,15 @@ static int enable_ecrc_checking(struct pci_dev *dev)
 */
static int disable_ecrc_checking(struct pci_dev *dev)
{
	int pos;
	int aer = dev->aer_cap;
	u32 reg32;

	if (!pci_is_pcie(dev))
	if (!aer)
		return -ENODEV;

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

	pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
	pci_read_config_dword(dev, aer + PCI_ERR_CAP, &reg32);
	reg32 &= ~(PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
	pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
	pci_write_config_dword(dev, aer + PCI_ERR_CAP, reg32);

	return 0;
}
@@ -217,142 +209,22 @@ void pcie_ecrc_get_policy(char *str)
}
#endif	/* CONFIG_PCIE_ECRC */

#ifdef CONFIG_ACPI_APEI
static inline int hest_match_pci(struct acpi_hest_aer_common *p,
				 struct pci_dev *pci)
{
	return   ACPI_HEST_SEGMENT(p->bus) == pci_domain_nr(pci->bus) &&
		 ACPI_HEST_BUS(p->bus)     == pci->bus->number &&
		 p->device                 == PCI_SLOT(pci->devfn) &&
		 p->function               == PCI_FUNC(pci->devfn);
}

static inline bool hest_match_type(struct acpi_hest_header *hest_hdr,
				struct pci_dev *dev)
{
	u16 hest_type = hest_hdr->type;
	u8 pcie_type = pci_pcie_type(dev);

	if ((hest_type == ACPI_HEST_TYPE_AER_ROOT_PORT &&
		pcie_type == PCI_EXP_TYPE_ROOT_PORT) ||
	    (hest_type == ACPI_HEST_TYPE_AER_ENDPOINT &&
		pcie_type == PCI_EXP_TYPE_ENDPOINT) ||
	    (hest_type == ACPI_HEST_TYPE_AER_BRIDGE &&
		(dev->class >> 16) == PCI_BASE_CLASS_BRIDGE))
		return true;
	return false;
}

struct aer_hest_parse_info {
	struct pci_dev *pci_dev;
	int firmware_first;
};

static int hest_source_is_pcie_aer(struct acpi_hest_header *hest_hdr)
{
	if (hest_hdr->type == ACPI_HEST_TYPE_AER_ROOT_PORT ||
	    hest_hdr->type == ACPI_HEST_TYPE_AER_ENDPOINT ||
	    hest_hdr->type == ACPI_HEST_TYPE_AER_BRIDGE)
		return 1;
	return 0;
}

static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data)
{
	struct aer_hest_parse_info *info = data;
	struct acpi_hest_aer_common *p;
	int ff;

	if (!hest_source_is_pcie_aer(hest_hdr))
		return 0;

	p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
	ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);

	/*
	 * If no specific device is supplied, determine whether
	 * FIRMWARE_FIRST is set for *any* PCIe device.
	 */
	if (!info->pci_dev) {
		info->firmware_first |= ff;
		return 0;
	}

	/* Otherwise, check the specific device */
	if (p->flags & ACPI_HEST_GLOBAL) {
		if (hest_match_type(hest_hdr, info->pci_dev))
			info->firmware_first = ff;
	} else
		if (hest_match_pci(p, info->pci_dev))
			info->firmware_first = ff;

	return 0;
}

static void aer_set_firmware_first(struct pci_dev *pci_dev)
{
	int rc;
	struct aer_hest_parse_info info = {
		.pci_dev	= pci_dev,
		.firmware_first	= 0,
	};

	rc = apei_hest_parse(aer_hest_parse, &info);

	if (rc)
		pci_dev->__aer_firmware_first = 0;
	else
		pci_dev->__aer_firmware_first = info.firmware_first;
	pci_dev->__aer_firmware_first_valid = 1;
}
#define	PCI_EXP_AER_FLAGS	(PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \
				 PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE)

int pcie_aer_get_firmware_first(struct pci_dev *dev)
int pcie_aer_is_native(struct pci_dev *dev)
{
	if (!pci_is_pcie(dev))
		return 0;
	struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);

	if (pcie_ports_native)
	if (!dev->aer_cap)
		return 0;

	if (!dev->__aer_firmware_first_valid)
		aer_set_firmware_first(dev);
	return dev->__aer_firmware_first;
}

static bool aer_firmware_first;

/**
 * aer_acpi_firmware_first - Check if APEI should control AER.
 */
bool aer_acpi_firmware_first(void)
{
	static bool parsed = false;
	struct aer_hest_parse_info info = {
		.pci_dev	= NULL,	/* Check all PCIe devices */
		.firmware_first	= 0,
	};

	if (pcie_ports_native)
		return false;

	if (!parsed) {
		apei_hest_parse(aer_hest_parse, &info);
		aer_firmware_first = info.firmware_first;
		parsed = true;
	}
	return aer_firmware_first;
	return pcie_ports_native || host->native_aer;
}
#endif

#define	PCI_EXP_AER_FLAGS	(PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \
				 PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE)

int pci_enable_pcie_error_reporting(struct pci_dev *dev)
{
	if (pcie_aer_get_firmware_first(dev))
		return -EIO;

	if (!dev->aer_cap)
	if (!pcie_aer_is_native(dev))
		return -EIO;

	return pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS);
@@ -361,7 +233,7 @@ EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);

int pci_disable_pcie_error_reporting(struct pci_dev *dev)
{
	if (pcie_aer_get_firmware_first(dev))
	if (!pcie_aer_is_native(dev))
		return -EIO;

	return pcie_capability_clear_word(dev, PCI_EXP_DEVCTL,
@@ -379,22 +251,18 @@ void pci_aer_clear_device_status(struct pci_dev *dev)

int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
{
	int pos;
	int aer = dev->aer_cap;
	u32 status, sev;

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

	if (pcie_aer_get_firmware_first(dev))
	if (!pcie_aer_is_native(dev))
		return -EIO;

	/* Clear status bits for ERR_NONFATAL errors only */
	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &sev);
	pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, &status);
	pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_SEVER, &sev);
	status &= ~sev;
	if (status)
		pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
		pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);

	return 0;
}
@@ -402,22 +270,18 @@ EXPORT_SYMBOL_GPL(pci_aer_clear_nonfatal_status);

void pci_aer_clear_fatal_status(struct pci_dev *dev)
{
	int pos;
	int aer = dev->aer_cap;
	u32 status, sev;

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

	if (pcie_aer_get_firmware_first(dev))
	if (!pcie_aer_is_native(dev))
		return;

	/* Clear status bits for ERR_FATAL errors only */
	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &sev);
	pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, &status);
	pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_SEVER, &sev);
	status &= sev;
	if (status)
		pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
		pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
}

/**
@@ -431,35 +295,31 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
 */
int pci_aer_raw_clear_status(struct pci_dev *dev)
{
	int pos;
	int aer = dev->aer_cap;
	u32 status;
	int port_type;

	if (!pci_is_pcie(dev))
		return -ENODEV;

	pos = dev->aer_cap;
	if (!pos)
	if (!aer)
		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);
		pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status);
		pci_read_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, &status);
		pci_write_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, status);
	}

	pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status);
	pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, status);
	pci_read_config_dword(dev, aer + PCI_ERR_COR_STATUS, &status);
	pci_write_config_dword(dev, aer + PCI_ERR_COR_STATUS, status);

	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
	pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
	pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, &status);
	pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);

	return 0;
}

int pci_aer_clear_status(struct pci_dev *dev)
{
	if (pcie_aer_get_firmware_first(dev))
	if (!pcie_aer_is_native(dev))
		return -EIO;

	return pci_aer_raw_clear_status(dev);
@@ -467,12 +327,11 @@ int pci_aer_clear_status(struct pci_dev *dev)

void pci_save_aer_state(struct pci_dev *dev)
{
	int aer = dev->aer_cap;
	struct pci_cap_saved_state *save_state;
	u32 *cap;
	int pos;

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

	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_ERR);
@@ -480,22 +339,21 @@ void pci_save_aer_state(struct pci_dev *dev)
		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++);
	pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, cap++);
	pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_SEVER, cap++);
	pci_read_config_dword(dev, aer + PCI_ERR_COR_MASK, cap++);
	pci_read_config_dword(dev, aer + PCI_ERR_CAP, cap++);
	if (pcie_cap_has_rtctl(dev))
		pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, cap++);
		pci_read_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, cap++);
}

void pci_restore_aer_state(struct pci_dev *dev)
{
	int aer = dev->aer_cap;
	struct pci_cap_saved_state *save_state;
	u32 *cap;
	int pos;

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

	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_ERR);
@@ -503,12 +361,12 @@ void pci_restore_aer_state(struct pci_dev *dev)
		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++);
	pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, *cap++);
	pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_SEVER, *cap++);
	pci_write_config_dword(dev, aer + PCI_ERR_COR_MASK, *cap++);
	pci_write_config_dword(dev, aer + PCI_ERR_CAP, *cap++);
	if (pcie_cap_has_rtctl(dev))
		pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, *cap++);
		pci_write_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, *cap++);
}

void pci_aer_init(struct pci_dev *dev)
@@ -939,7 +797,7 @@ static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev)
 */
static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)
{
	int pos;
	int aer = dev->aer_cap;
	u32 status, mask;
	u16 reg16;

@@ -974,17 +832,16 @@ static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)
	if (!(reg16 & PCI_EXP_AER_FLAGS))
		return false;

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

	/* Check if error is recorded */
	if (e_info->severity == AER_CORRECTABLE) {
		pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status);
		pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &mask);
		pci_read_config_dword(dev, aer + PCI_ERR_COR_STATUS, &status);
		pci_read_config_dword(dev, aer + PCI_ERR_COR_MASK, &mask);
	} else {
		pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
		pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &mask);
		pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, &status);
		pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, &mask);
	}
	if (status & ~mask)
		return true;
@@ -1055,16 +912,15 @@ static bool find_source_device(struct pci_dev *parent,
 */
static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info)
{
	int pos;
	int aer = dev->aer_cap;

	if (info->severity == AER_CORRECTABLE) {
		/*
		 * Correctable error does not need software intervention.
		 * No need to go through error recovery process.
		 */
		pos = dev->aer_cap;
		if (pos)
			pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
		if (aer)
			pci_write_config_dword(dev, aer + PCI_ERR_COR_STATUS,
					info->status);
		pci_aer_clear_device_status(dev);
	} else if (info->severity == AER_NONFATAL)
@@ -1155,22 +1011,21 @@ EXPORT_SYMBOL_GPL(aer_recover_queue);
 */
int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
{
	int pos, temp;
	int aer = dev->aer_cap;
	int temp;

	/* Must reset in this function */
	info->status = 0;
	info->tlp_header_valid = 0;

	pos = dev->aer_cap;

	/* The device might not support AER */
	if (!pos)
	if (!aer)
		return 0;

	if (info->severity == AER_CORRECTABLE) {
		pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS,
		pci_read_config_dword(dev, aer + PCI_ERR_COR_STATUS,
			&info->status);
		pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK,
		pci_read_config_dword(dev, aer + PCI_ERR_COR_MASK,
			&info->mask);
		if (!(info->status & ~info->mask))
			return 0;
@@ -1179,27 +1034,27 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
		   info->severity == AER_NONFATAL) {

		/* Link is still healthy for IO reads */
		pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
		pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS,
			&info->status);
		pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK,
		pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK,
			&info->mask);
		if (!(info->status & ~info->mask))
			return 0;

		/* Get First Error Pointer */
		pci_read_config_dword(dev, pos + PCI_ERR_CAP, &temp);
		pci_read_config_dword(dev, aer + PCI_ERR_CAP, &temp);
		info->first_error = PCI_ERR_CAP_FEP(temp);

		if (info->status & AER_LOG_TLP_MASKS) {
			info->tlp_header_valid = 1;
			pci_read_config_dword(dev,
				pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0);
				aer + PCI_ERR_HEADER_LOG, &info->tlp.dw0);
			pci_read_config_dword(dev,
				pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1);
				aer + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1);
			pci_read_config_dword(dev,
				pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2);
				aer + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2);
			pci_read_config_dword(dev,
				pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3);
				aer + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3);
		}
	}

@@ -1305,15 +1160,15 @@ static irqreturn_t aer_irq(int irq, void *context)
	struct pcie_device *pdev = (struct pcie_device *)context;
	struct aer_rpc *rpc = get_service_data(pdev);
	struct pci_dev *rp = rpc->rpd;
	int aer = rp->aer_cap;
	struct aer_err_source e_src = {};
	int pos = rp->aer_cap;

	pci_read_config_dword(rp, pos + PCI_ERR_ROOT_STATUS, &e_src.status);
	pci_read_config_dword(rp, aer + PCI_ERR_ROOT_STATUS, &e_src.status);
	if (!(e_src.status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV)))
		return IRQ_NONE;

	pci_read_config_dword(rp, pos + PCI_ERR_ROOT_ERR_SRC, &e_src.id);
	pci_write_config_dword(rp, pos + PCI_ERR_ROOT_STATUS, e_src.status);
	pci_read_config_dword(rp, aer + PCI_ERR_ROOT_ERR_SRC, &e_src.id);
	pci_write_config_dword(rp, aer + PCI_ERR_ROOT_STATUS, e_src.status);

	if (!kfifo_put(&rpc->aer_fifo, e_src))
		return IRQ_HANDLED;
@@ -1365,7 +1220,7 @@ static void set_downstream_devices_error_reporting(struct pci_dev *dev,
static void aer_enable_rootport(struct aer_rpc *rpc)
{
	struct pci_dev *pdev = rpc->rpd;
	int aer_pos;
	int aer = pdev->aer_cap;
	u16 reg16;
	u32 reg32;

@@ -1377,14 +1232,13 @@ static void aer_enable_rootport(struct aer_rpc *rpc)
	pcie_capability_clear_word(pdev, PCI_EXP_RTCTL,
				   SYSTEM_ERROR_INTR_ON_MESG_MASK);

	aer_pos = pdev->aer_cap;
	/* Clear error status */
	pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
	pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
	pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32);
	pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);
	pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
	pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
	pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, &reg32);
	pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, reg32);
	pci_read_config_dword(pdev, aer + PCI_ERR_COR_STATUS, &reg32);
	pci_write_config_dword(pdev, aer + PCI_ERR_COR_STATUS, reg32);
	pci_read_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, &reg32);
	pci_write_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, reg32);

	/*
	 * Enable error reporting for the root port device and downstream port
@@ -1393,9 +1247,9 @@ static void aer_enable_rootport(struct aer_rpc *rpc)
	set_downstream_devices_error_reporting(pdev, true);

	/* Enable Root Port's interrupt in response to error messages */
	pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, &reg32);
	pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, &reg32);
	reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
	pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, reg32);
	pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32);
}

/**
@@ -1407,8 +1261,8 @@ static void aer_enable_rootport(struct aer_rpc *rpc)
static void aer_disable_rootport(struct aer_rpc *rpc)
{
	struct pci_dev *pdev = rpc->rpd;
	int aer = pdev->aer_cap;
	u32 reg32;
	int pos;

	/*
	 * Disable error reporting for the root port device and downstream port
@@ -1416,15 +1270,14 @@ static void aer_disable_rootport(struct aer_rpc *rpc)
	 */
	set_downstream_devices_error_reporting(pdev, false);

	pos = pdev->aer_cap;
	/* Disable Root's interrupt in response to error messages */
	pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
	pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, &reg32);
	reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
	pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, reg32);
	pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32);

	/* Clear Root's error status reg */
	pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32);
	pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);
	pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, &reg32);
	pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, reg32);
}

/**
@@ -1481,28 +1334,27 @@ static int aer_probe(struct pcie_device *dev)
 */
static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
{
	int aer = dev->aer_cap;
	u32 reg32;
	int pos;
	int rc;

	pos = dev->aer_cap;

	/* Disable Root's interrupt in response to error messages */
	pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
	pci_read_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, &reg32);
	reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
	pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
	pci_write_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, reg32);

	rc = pci_bus_error_reset(dev);
	pci_info(dev, "Root Port link has been reset\n");

	/* Clear Root Error Status */
	pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
	pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32);
	pci_read_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, &reg32);
	pci_write_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, reg32);

	/* Enable Root Port's interrupt in response to error messages */
	pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
	pci_read_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, &reg32);
	reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
	pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
	pci_write_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, reg32);

	return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
}
@@ -1523,7 +1375,7 @@ static struct pcie_port_service_driver aerdriver = {
 */
int __init pcie_aer_init(void)
{
	if (!pci_aer_available() || aer_acpi_firmware_first())
	if (!pci_aer_available())
		return -ENXIO;
	return pcie_port_service_register(&aerdriver);
}
+2 −1
Original line number Diff line number Diff line
@@ -284,7 +284,7 @@ static int dpc_probe(struct pcie_device *dev)
	int status;
	u16 ctl, cap;

	if (pcie_aer_get_firmware_first(pdev) && !pcie_ports_dpc_native)
	if (!pcie_aer_is_native(pdev) && !pcie_ports_dpc_native)
		return -ENOTSUPP;

	status = devm_request_threaded_irq(device, dev->irq, dpc_irq,
@@ -301,6 +301,7 @@ static int dpc_probe(struct pcie_device *dev)

	ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN;
	pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, ctl);
	pci_info(pdev, "enabled with IRQ %d\n", dev->irq);

	pci_info(pdev, "error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n",
		 cap & PCI_EXP_DPC_IRQ, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT),
+2 −2
Original line number Diff line number Diff line
@@ -148,11 +148,11 @@ static void edr_handle_event(acpi_handle handle, u32 event, void *data)
	pci_ers_result_t estate = PCI_ERS_RESULT_DISCONNECT;
	u16 status;

	pci_info(pdev, "ACPI event %#x received\n", event);

	if (event != ACPI_NOTIFY_DISCONNECT_RECOVER)
		return;

	pci_info(pdev, "EDR event received\n");

	/* Locate the port which issued EDR event */
	edev = acpi_dpc_port_get(pdev);
	if (!edev) {
+2 −11
Original line number Diff line number Diff line
@@ -29,8 +29,10 @@ extern bool pcie_ports_dpc_native;

#ifdef CONFIG_PCIEAER
int pcie_aer_init(void);
int pcie_aer_is_native(struct pci_dev *dev);
#else
static inline int pcie_aer_init(void) { return 0; }
static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
#endif

#ifdef CONFIG_HOTPLUG_PCI_PCIE
@@ -147,16 +149,5 @@ static inline bool pcie_pme_no_msi(void) { return false; }
static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {}
#endif /* !CONFIG_PCIE_PME */

#ifdef CONFIG_ACPI_APEI
int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
#else
static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
{
	if (pci_dev->__aer_firmware_first_valid)
		return pci_dev->__aer_firmware_first;
	return 0;
}
#endif

struct device *pcie_port_find_device(struct pci_dev *dev, u32 service);
#endif /* _PORTDRV_H_ */
Loading