PCI_EXP_SLTCTL_PWR_OFF);
 }
 
+static void pciehp_ignore_dpc_link_change(struct controller *ctrl,
+                                         struct pci_dev *pdev, int irq)
+{
+       /*
+        * Ignore link changes which occurred while waiting for DPC recovery.
+        * Could be several if DPC triggered multiple times consecutively.
+        */
+       synchronize_hardirq(irq);
+       atomic_and(~PCI_EXP_SLTSTA_DLLSC, &ctrl->pending_events);
+       if (pciehp_poll_mode)
+               pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
+                                          PCI_EXP_SLTSTA_DLLSC);
+       ctrl_info(ctrl, "Slot(%s): Link Down/Up ignored (recovered by DPC)\n",
+                 slot_name(ctrl));
+
+       /*
+        * If the link is unexpectedly down after successful recovery,
+        * the corresponding link change may have been ignored above.
+        * Synthesize it to ensure that it is acted on.
+        */
+       down_read(&ctrl->reset_lock);
+       if (!pciehp_check_link_active(ctrl))
+               pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC);
+       up_read(&ctrl->reset_lock);
+}
+
 static irqreturn_t pciehp_isr(int irq, void *dev_id)
 {
        struct controller *ctrl = (struct controller *)dev_id;
                                      PCI_EXP_SLTCTL_ATTN_IND_ON);
        }
 
+       /*
+        * Ignore Link Down/Up events caused by Downstream Port Containment
+        * if recovery from the error succeeded.
+        */
+       if ((events & PCI_EXP_SLTSTA_DLLSC) && pci_dpc_recovered(pdev) &&
+           ctrl->state == ON_STATE) {
+               events &= ~PCI_EXP_SLTSTA_DLLSC;
+               pciehp_ignore_dpc_link_change(ctrl, pdev, irq);
+       }
+
        /*
         * Disable requests have higher priority than Presence Detect Changed
         * or Data Link Layer State Changed events.
 
 
 /* pci_dev priv_flags */
 #define PCI_DEV_ADDED 0
+#define PCI_DPC_RECOVERED 1
+#define PCI_DPC_RECOVERING 2
 
 static inline void pci_dev_assign_added(struct pci_dev *dev, bool added)
 {
 void pci_dpc_init(struct pci_dev *pdev);
 void dpc_process_error(struct pci_dev *pdev);
 pci_ers_result_t dpc_reset_link(struct pci_dev *pdev);
+bool pci_dpc_recovered(struct pci_dev *pdev);
 #else
 static inline void pci_save_dpc_state(struct pci_dev *dev) {}
 static inline void pci_restore_dpc_state(struct pci_dev *dev) {}
 static inline void pci_dpc_init(struct pci_dev *pdev) {}
+static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
 #endif
 
 #ifdef CONFIG_PCIEPORTBUS
 
        pci_write_config_word(dev, dev->dpc_cap + PCI_EXP_DPC_CTL, *cap);
 }
 
+static DECLARE_WAIT_QUEUE_HEAD(dpc_completed_waitqueue);
+
+#ifdef CONFIG_HOTPLUG_PCI_PCIE
+static bool dpc_completed(struct pci_dev *pdev)
+{
+       u16 status;
+
+       pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS, &status);
+       if ((status != 0xffff) && (status & PCI_EXP_DPC_STATUS_TRIGGER))
+               return false;
+
+       if (test_bit(PCI_DPC_RECOVERING, &pdev->priv_flags))
+               return false;
+
+       return true;
+}
+
+/**
+ * pci_dpc_recovered - whether DPC triggered and has recovered successfully
+ * @pdev: PCI device
+ *
+ * Return true if DPC was triggered for @pdev and has recovered successfully.
+ * Wait for recovery if it hasn't completed yet.  Called from the PCIe hotplug
+ * driver to recognize and ignore Link Down/Up events caused by DPC.
+ */
+bool pci_dpc_recovered(struct pci_dev *pdev)
+{
+       struct pci_host_bridge *host;
+
+       if (!pdev->dpc_cap)
+               return false;
+
+       /*
+        * Synchronization between hotplug and DPC is not supported
+        * if DPC is owned by firmware and EDR is not enabled.
+        */
+       host = pci_find_host_bridge(pdev->bus);
+       if (!host->native_dpc && !IS_ENABLED(CONFIG_PCIE_EDR))
+               return false;
+
+       /*
+        * Need a timeout in case DPC never completes due to failure of
+        * dpc_wait_rp_inactive().  The spec doesn't mandate a time limit,
+        * but reports indicate that DPC completes within 4 seconds.
+        */
+       wait_event_timeout(dpc_completed_waitqueue, dpc_completed(pdev),
+                          msecs_to_jiffies(4000));
+
+       return test_and_clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
+}
+#endif /* CONFIG_HOTPLUG_PCI_PCIE */
+
 static int dpc_wait_rp_inactive(struct pci_dev *pdev)
 {
        unsigned long timeout = jiffies + HZ;
 
 pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
 {
+       pci_ers_result_t ret;
        u16 cap;
 
+       set_bit(PCI_DPC_RECOVERING, &pdev->priv_flags);
+
        /*
         * DPC disables the Link automatically in hardware, so it has
         * already been reset by the time we get here.
        if (!pcie_wait_for_link(pdev, false))
                pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n");
 
-       if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev))
-               return PCI_ERS_RESULT_DISCONNECT;
+       if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev)) {
+               clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
+               ret = PCI_ERS_RESULT_DISCONNECT;
+               goto out;
+       }
 
        pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
                              PCI_EXP_DPC_STATUS_TRIGGER);
 
        if (!pcie_wait_for_link(pdev, true)) {
                pci_info(pdev, "Data Link Layer Link Active not set in 1000 msec\n");
-               return PCI_ERS_RESULT_DISCONNECT;
+               clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
+               ret = PCI_ERS_RESULT_DISCONNECT;
+       } else {
+               set_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
+               ret = PCI_ERS_RESULT_RECOVERED;
        }
-
-       return PCI_ERS_RESULT_RECOVERED;
+out:
+       clear_bit(PCI_DPC_RECOVERING, &pdev->priv_flags);
+       wake_up_all(&dpc_completed_waitqueue);
+       return ret;
 }
 
 static void dpc_process_rp_pio_error(struct pci_dev *pdev)