struct controller *ctrl = (struct controller *)dev_id;
        struct pci_dev *pdev = ctrl_dev(ctrl);
        struct device *parent = pdev->dev.parent;
-       u16 status, events;
+       u16 status, events = 0;
 
        /*
         * Interrupts only occur in D3hot or shallower and only if enabled
                }
        }
 
+read_status:
        pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &status);
        if (status == (u16) ~0) {
                ctrl_info(ctrl, "%s: no response from device\n", __func__);
         * Slot Status contains plain status bits as well as event
         * notification bits; right now we only want the event bits.
         */
-       events = status & (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
-                          PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_CC |
-                          PCI_EXP_SLTSTA_DLLSC);
+       status &= PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
+                 PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_CC |
+                 PCI_EXP_SLTSTA_DLLSC;
 
        /*
         * If we've already reported a power fault, don't report it again
         * until we've done something to handle it.
         */
        if (ctrl->power_fault_detected)
-               events &= ~PCI_EXP_SLTSTA_PFD;
+               status &= ~PCI_EXP_SLTSTA_PFD;
 
+       events |= status;
        if (!events) {
                if (parent)
                        pm_runtime_put(parent);
                return IRQ_NONE;
        }
 
-       pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, events);
+       if (status) {
+               pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, events);
+
+               /*
+                * In MSI mode, all event bits must be zero before the port
+                * will send a new interrupt (PCIe Base Spec r5.0 sec 6.7.3.4).
+                * So re-read the Slot Status register in case a bit was set
+                * between read and write.
+                */
+               if (pci_dev_msi_enabled(pdev) && !pciehp_poll_mode)
+                       goto read_status;
+       }
+
        ctrl_dbg(ctrl, "pending interrupts %#06x from Slot Status\n", events);
        if (parent)
                pm_runtime_put(parent);