Commit 4ea40c38 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/edr'

  - Update error status after reset_link() so we don't report "recovery
    failed" when it in fact succeeded (Kuppuswamy Sathyanarayanan)

  - Move DPC data into struct pci_dev instead of allocating a separate
    struct dpc_dev (Bjorn Helgaas)

  - Remove AER/DPC service dependency to simplify error recovery
    (Kuppuswamy Sathyanarayanan)

  - Return error recovery status for future use by EDR, which needs to tell
    firmware whether recovery was successful (Kuppuswamy Sathyanarayanan)

  - Cache DPC capability info in core since it's needed by EDR as well as
    DPC driver (Kuppuswamy Sathyanarayanan)

  - Add pci_aer_raw_clear_status() to allow EDR recovery path to clear AER
    status even when OS doesn't own the AER capability (Kuppuswamy
    Sathyanarayanan)

  - Add Error Disconnect Recover (EDR) support, so firmware can use ACPI
    notification to tell the OS that devices have been disconnected, e.g.,
    via DPC, and that OS should attempt recovery (Kuppuswamy
    Sathyanarayanan)

  - Rename AER error status clearing interfaces to be more consistent
    (Kuppuswamy Sathyanarayanan)

* pci/edr:
  PCI/AER: Rationalize error status register clearing
  PCI/DPC: Add Error Disconnect Recover (EDR) support
  PCI/DPC: Expose dpc_process_error(), dpc_reset_link() for use by EDR
  PCI/AER: Add pci_aer_raw_clear_status() to unconditionally clear Error Status
  PCI/DPC: Cache DPC capabilities in pci_init_capabilities()
  PCI/ERR: Return status of pcie_do_recovery()
  PCI/ERR: Remove service dependency in pcie_do_recovery()
  PCI/DPC: Move DPC data into struct pci_dev
  PCI/ERR: Update error status after reset_link()
  PCI/ERR: Combine pci_channel_io_frozen cases
parents dd956a12 894020fd
Loading
Loading
Loading
Loading
+6 −17
Original line number Diff line number Diff line
@@ -156,12 +156,6 @@ default reset_link function, but different upstream ports might
have different specifications to reset pci express link, so all
upstream ports should provide their own reset_link functions.

In struct pcie_port_service_driver, a new pointer, reset_link, is
added.
::

	pci_ers_result_t (*reset_link) (struct pci_dev *dev);

Section 3.2.2.2 provides more detailed info on when to call
reset_link.

@@ -212,15 +206,10 @@ error_detected(dev, pci_channel_io_frozen) to all drivers within
a hierarchy in question. Then, performing link reset at upstream is
necessary. As different kinds of devices might use different approaches
to reset link, AER port service driver is required to provide the
function to reset link. Firstly, kernel looks for if the upstream
component has an aer driver. If it has, kernel uses the reset_link
callback of the aer driver. If the upstream component has no aer driver
and the port is downstream port, we will perform a hot reset as the
default by setting the Secondary Bus Reset bit of the Bridge Control
register associated with the downstream port. As for upstream ports,
they should provide their own aer service drivers with reset_link
function. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER and
reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes
function to reset link via callback parameter of pcie_do_recovery()
function. If reset_link is not NULL, recovery function will use it
to reset the link. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER
and reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes
to mmio_enabled.

helper functions
@@ -243,9 +232,9 @@ messages to root port when an error is detected.

::

  int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);`
  int pci_aer_clear_nonfatal_status(struct pci_dev *dev);`

pci_cleanup_aer_uncorrect_error_status cleanups the uncorrectable
pci_aer_clear_nonfatal_status clears non-fatal errors in the uncorrectable
error status register.

Frequent Asked Questions
+15 −0
Original line number Diff line number Diff line
@@ -131,6 +131,7 @@ static struct pci_osc_bit_struct pci_osc_support_bit[] = {
	{ OSC_PCI_CLOCK_PM_SUPPORT, "ClockPM" },
	{ OSC_PCI_SEGMENT_GROUPS_SUPPORT, "Segments" },
	{ OSC_PCI_MSI_SUPPORT, "MSI" },
	{ OSC_PCI_EDR_SUPPORT, "EDR" },
	{ OSC_PCI_HPX_TYPE_3_SUPPORT, "HPX-Type3" },
};

@@ -141,6 +142,7 @@ static struct pci_osc_bit_struct pci_osc_control_bit[] = {
	{ OSC_PCI_EXPRESS_AER_CONTROL, "AER" },
	{ OSC_PCI_EXPRESS_CAPABILITY_CONTROL, "PCIeCapability" },
	{ OSC_PCI_EXPRESS_LTR_CONTROL, "LTR" },
	{ OSC_PCI_EXPRESS_DPC_CONTROL, "DPC" },
};

static void decode_osc_bits(struct acpi_pci_root *root, char *msg, u32 word,
@@ -440,6 +442,8 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,
		support |= OSC_PCI_ASPM_SUPPORT | OSC_PCI_CLOCK_PM_SUPPORT;
	if (pci_msi_enabled())
		support |= OSC_PCI_MSI_SUPPORT;
	if (IS_ENABLED(CONFIG_PCIE_EDR))
		support |= OSC_PCI_EDR_SUPPORT;

	decode_osc_support(root, "OS supports", support);
	status = acpi_pci_osc_support(root, support);
@@ -487,6 +491,15 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,
			control |= OSC_PCI_EXPRESS_AER_CONTROL;
	}

	/*
	 * Per the Downstream Port Containment Related Enhancements ECN to
	 * the PCI Firmware Spec, r3.2, sec 4.5.1, table 4-5,
	 * OSC_PCI_EXPRESS_DPC_CONTROL indicates the OS supports both DPC
	 * and EDR.
	 */
	if (IS_ENABLED(CONFIG_PCIE_DPC) && IS_ENABLED(CONFIG_PCIE_EDR))
		control |= OSC_PCI_EXPRESS_DPC_CONTROL;

	requested = control;
	status = acpi_pci_osc_control_set(handle, &control,
					  OSC_PCI_EXPRESS_CAPABILITY_CONTROL);
@@ -916,6 +929,8 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
		host_bridge->native_pme = 0;
	if (!(root->osc_control_set & OSC_PCI_EXPRESS_LTR_CONTROL))
		host_bridge->native_ltr = 0;
	if (!(root->osc_control_set & OSC_PCI_EXPRESS_DPC_CONTROL))
		host_bridge->native_dpc = 0;

	/*
	 * Evaluate the "PCI Boot Configuration" _DSM Function.  If it
+2 −2
Original line number Diff line number Diff line
@@ -3495,10 +3495,10 @@ static pci_ers_result_t ice_pci_err_slot_reset(struct pci_dev *pdev)
			result = PCI_ERS_RESULT_DISCONNECT;
	}

	err = pci_cleanup_aer_uncorrect_error_status(pdev);
	err = pci_aer_clear_nonfatal_status(pdev);
	if (err)
		dev_dbg(&pdev->dev,
			"pci_cleanup_aer_uncorrect_error_status failed, error %d\n",
			"pci_aer_clear_nonfatal_status() failed, error %d\n",
			err);
		/* non-fatal, continue */

+2 −2
Original line number Diff line number Diff line
@@ -2674,8 +2674,8 @@ static int idt_init_pci(struct idt_ntb_dev *ndev)
	ret = pci_enable_pcie_error_reporting(pdev);
	if (ret != 0)
		dev_warn(&pdev->dev, "PCIe AER capability disabled\n");
	else /* Cleanup uncorrectable error status before getting to init */
		pci_cleanup_aer_uncorrect_error_status(pdev);
	else /* Cleanup nonfatal error status before getting to init */
		pci_aer_clear_nonfatal_status(pdev);

	/* First enable the PCI device */
	ret = pcim_enable_device(pdev);
+2 −0
Original line number Diff line number Diff line
@@ -1241,6 +1241,7 @@ static void pci_acpi_setup(struct device *dev)

	pci_acpi_optimize_delay(pci_dev, adev->handle);
	pci_acpi_set_untrusted(pci_dev);
	pci_acpi_add_edr_notifier(pci_dev);

	pci_acpi_add_pm_notifier(adev, pci_dev);
	if (!adev->wakeup.flags.valid)
@@ -1268,6 +1269,7 @@ static void pci_acpi_cleanup(struct device *dev)
	if (!adev)
		return;

	pci_acpi_remove_edr_notifier(pci_dev);
	pci_acpi_remove_pm_notifier(adev);
	if (adev->wakeup.flags.valid) {
		acpi_device_power_remove_dependent(adev, dev);
Loading