diff options
Diffstat (limited to 'drivers/pci/hotplug/pciehp_core.c')
| -rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 4042d87d539d..f59baa912970 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -20,6 +20,7 @@ #define pr_fmt(fmt) "pciehp: " fmt #define dev_fmt pr_fmt +#include <linux/bitfield.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -103,7 +104,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) struct pci_dev *pdev = ctrl->pcie->port; if (status) - status <<= PCI_EXP_SLTCTL_ATTN_IND_SHIFT; + status = FIELD_PREP(PCI_EXP_SLTCTL_AIC, status); else status = PCI_EXP_SLTCTL_ATTN_IND_OFF; @@ -292,9 +293,23 @@ static int pciehp_resume_noirq(struct pcie_device *dev) ctrl->cmd_busy = true; /* clear spurious events from rediscovery of inserted card */ - if (ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE) + if (ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE) { pcie_clear_hotplug_events(ctrl); + /* + * If hotplugged device was replaced with a different one + * during system sleep, mark the old device disconnected + * (to prevent its driver from accessing the new device) + * and synthesize a Presence Detect Changed event. + */ + if (pciehp_device_replaced(ctrl)) { + ctrl_dbg(ctrl, "device replaced during system sleep\n"); + pci_walk_bus(ctrl->pcie->port->subordinate, + pci_dev_set_disconnected, NULL); + pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC); + } + } + return 0; } #endif |
