Commit 13c65840 authored by Mika Westerberg's avatar Mika Westerberg Committed by Bjorn Helgaas

PCI: pciehp: Clear Presence Detect and Data Link Layer Status Changed on resume

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: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: stable@vger.kernel.org
parent 5d9c6b8a
...@@ -121,7 +121,7 @@ struct controller *pcie_init(struct pcie_device *dev); ...@@ -121,7 +121,7 @@ struct controller *pcie_init(struct pcie_device *dev);
int pcie_init_notification(struct controller *ctrl); int pcie_init_notification(struct controller *ctrl);
int pciehp_enable_slot(struct slot *p_slot); int pciehp_enable_slot(struct slot *p_slot);
int pciehp_disable_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); int pciehp_power_on_slot(struct slot *slot);
void pciehp_power_off_slot(struct slot *slot); void pciehp_power_off_slot(struct slot *slot);
void pciehp_get_power_status(struct slot *slot, u8 *status); void pciehp_get_power_status(struct slot *slot, u8 *status);
......
...@@ -283,7 +283,7 @@ static int pciehp_resume(struct pcie_device *dev) ...@@ -283,7 +283,7 @@ static int pciehp_resume(struct pcie_device *dev)
ctrl = get_service_data(dev); ctrl = get_service_data(dev);
/* reinitialize the chipset's event detection logic */ /* reinitialize the chipset's event detection logic */
pcie_enable_notification(ctrl); pcie_reenable_notification(ctrl);
slot = ctrl->slot; slot = ctrl->slot;
......
...@@ -667,7 +667,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) ...@@ -667,7 +667,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
return handled; return handled;
} }
void pcie_enable_notification(struct controller *ctrl) static void pcie_enable_notification(struct controller *ctrl)
{ {
u16 cmd, mask; u16 cmd, mask;
...@@ -705,6 +705,17 @@ void pcie_enable_notification(struct controller *ctrl) ...@@ -705,6 +705,17 @@ void pcie_enable_notification(struct controller *ctrl)
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd); 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) static void pcie_disable_notification(struct controller *ctrl)
{ {
u16 mask; u16 mask;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment