| From: Mika Westerberg <mika.westerberg@linux.intel.com> |
| Date: Wed, 23 May 2018 17:14:39 -0500 |
| Subject: PCI: pciehp: Clear Presence Detect and Data Link Layer Status Changed |
| on resume |
| |
| 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> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| drivers/pci/hotplug/pciehp.h | 2 +- |
| drivers/pci/hotplug/pciehp_core.c | 2 +- |
| drivers/pci/hotplug/pciehp_hpc.c | 13 ++++++++++++- |
| 3 files changed, 14 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/pci/hotplug/pciehp.h |
| +++ b/drivers/pci/hotplug/pciehp.h |
| @@ -143,7 +143,7 @@ struct controller *pcie_init(struct pcie |
| 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); |
| --- a/drivers/pci/hotplug/pciehp_core.c |
| +++ b/drivers/pci/hotplug/pciehp_core.c |
| @@ -332,7 +332,7 @@ static int pciehp_resume(struct pcie_dev |
| ctrl = get_service_data(dev); |
| |
| /* reinitialize the chipset's event detection logic */ |
| - pcie_enable_notification(ctrl); |
| + pcie_reenable_notification(ctrl); |
| |
| slot = ctrl->slot; |
| |
| --- a/drivers/pci/hotplug/pciehp_hpc.c |
| +++ b/drivers/pci/hotplug/pciehp_hpc.c |
| @@ -580,7 +580,7 @@ static irqreturn_t pcie_isr(int irq, voi |
| return IRQ_HANDLED; |
| } |
| |
| -void pcie_enable_notification(struct controller *ctrl) |
| +static void pcie_enable_notification(struct controller *ctrl) |
| { |
| u16 cmd, mask; |
| |
| @@ -618,6 +618,17 @@ void pcie_enable_notification(struct con |
| pcie_write_cmd(ctrl, cmd, mask); |
| } |
| |
| +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; |