]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
PCI: pciehp: Clear Presence Detect and Data Link Layer Status Changed on resume
authorMika Westerberg <mika.westerberg@linux.intel.com>
Wed, 23 May 2018 22:14:39 +0000 (17:14 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 Jul 2018 09:21:30 +0000 (11:21 +0200)
commit 13c65840feab8109194f9490c9870587173cb29d upstream.

After a suspend/resume cycle the Presence Detect or Data Link Layer Status
Changed bits might be set.  If we don't clear them those events will not
fire anymore and nothing happens for instance when a device is now
hot-unplugged.

Fix this by clearing those bits in a newly introduced function
pcie_reenable_notification().  This should be fine because immediately
after, we check if the adapter is still present by reading directly from
the status register.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_hpc.c

index 62d6fe6c37145c5c35c62a4746093f486edd3457..cbe58480b4745c86f6559f1374f6d404d5a4bfe2 100644 (file)
@@ -134,7 +134,7 @@ struct controller *pcie_init(struct pcie_device *dev);
 int pcie_init_notification(struct controller *ctrl);
 int pciehp_enable_slot(struct slot *p_slot);
 int pciehp_disable_slot(struct slot *p_slot);
-void pcie_enable_notification(struct controller *ctrl);
+void pcie_reenable_notification(struct controller *ctrl);
 int pciehp_power_on_slot(struct slot *slot);
 void pciehp_power_off_slot(struct slot *slot);
 void pciehp_get_power_status(struct slot *slot, u8 *status);
index 612b21a14df5931254d6b76059b45090a4a2fe12..8f6ded43760a7b193eadf36fd60734b501aa7e38 100644 (file)
@@ -295,7 +295,7 @@ static int pciehp_resume(struct pcie_device *dev)
        ctrl = get_service_data(dev);
 
        /* reinitialize the chipset's event detection logic */
-       pcie_enable_notification(ctrl);
+       pcie_reenable_notification(ctrl);
 
        slot = ctrl->slot;
 
index 5c24e938042fd6bccb4e207d58dcb988d7c62611..63c6c7fce3ebb35fb37e9863b51b09aab49507f0 100644 (file)
@@ -628,7 +628,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-void pcie_enable_notification(struct controller *ctrl)
+static void pcie_enable_notification(struct controller *ctrl)
 {
        u16 cmd, mask;
 
@@ -666,6 +666,17 @@ void pcie_enable_notification(struct controller *ctrl)
                 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd);
 }
 
+void pcie_reenable_notification(struct controller *ctrl)
+{
+       /*
+        * Clear both Presence and Data Link Layer Changed to make sure
+        * those events still fire after we have re-enabled them.
+        */
+       pcie_capability_write_word(ctrl->pcie->port, PCI_EXP_SLTSTA,
+                                  PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
+       pcie_enable_notification(ctrl);
+}
+
 static void pcie_disable_notification(struct controller *ctrl)
 {
        u16 mask;