Skip to content

Commit eb34da6

Browse files
westeribjorn-helgaas
authored andcommitted
PCI: pciehp: Disable hotplug interrupt during suspend
When PCIe hotplug port is transitioned into D3hot, the link to the downstream component will go down. If hotplug interrupt generation is enabled when that happens, it will trigger immediately, waking up the system and bringing the link back up. To prevent this, disable hotplug interrupt generation when system suspend is entered. This does not prevent wakeup from low power states according to PCIe 4.0 spec section 6.7.3.4: Software enables a hot-plug event to generate a wakeup event by enabling software notification of the event as described in Section 6.7.3.1. Note that in order for software to disable interrupt generation while keeping wakeup generation enabled, the Hot-Plug Interrupt Enable bit must be cleared. So as long as we have set the slot event mask accordingly, wakeup should work even if slot interrupt is disabled. The port should trigger wake and then send PME to the root port when the PCIe hierarchy is brought back up. Limit this to systems using native PME mechanism to make sure older Apple systems depending on commit e3354628c376 ("PCI: pciehp: Support interrupts sent from D3hot") still continue working. 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>
1 parent 6299cf9 commit eb34da6

File tree

3 files changed

+30
-0
lines changed

3 files changed

+30
-0
lines changed

drivers/pci/hotplug/pciehp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ struct controller *pcie_init(struct pcie_device *dev);
176176
int pcie_init_notification(struct controller *ctrl);
177177
void pcie_shutdown_notification(struct controller *ctrl);
178178
void pcie_clear_hotplug_events(struct controller *ctrl);
179+
void pcie_enable_interrupt(struct controller *ctrl);
180+
void pcie_disable_interrupt(struct controller *ctrl);
179181
int pciehp_power_on_slot(struct controller *ctrl);
180182
void pciehp_power_off_slot(struct controller *ctrl);
181183
void pciehp_get_power_status(struct controller *ctrl, u8 *status);

drivers/pci/hotplug/pciehp_core.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,23 @@ static void pciehp_remove(struct pcie_device *dev)
242242
}
243243

244244
#ifdef CONFIG_PM
245+
static bool pme_is_native(struct pcie_device *dev)
246+
{
247+
const struct pci_host_bridge *host;
248+
249+
host = pci_find_host_bridge(dev->port->bus);
250+
return pcie_ports_native || host->native_pme;
251+
}
252+
245253
static int pciehp_suspend(struct pcie_device *dev)
246254
{
255+
/*
256+
* Disable hotplug interrupt so that it does not trigger
257+
* immediately when the downstream link goes down.
258+
*/
259+
if (pme_is_native(dev))
260+
pcie_disable_interrupt(get_service_data(dev));
261+
247262
return 0;
248263
}
249264

@@ -266,6 +281,9 @@ static int pciehp_resume(struct pcie_device *dev)
266281
{
267282
struct controller *ctrl = get_service_data(dev);
268283

284+
if (pme_is_native(dev))
285+
pcie_enable_interrupt(ctrl);
286+
269287
pciehp_check_presence(ctrl);
270288

271289
return 0;

drivers/pci/hotplug/pciehp_hpc.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,16 @@ void pcie_clear_hotplug_events(struct controller *ctrl)
732732
PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
733733
}
734734

735+
void pcie_enable_interrupt(struct controller *ctrl)
736+
{
737+
pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_HPIE, PCI_EXP_SLTCTL_HPIE);
738+
}
739+
740+
void pcie_disable_interrupt(struct controller *ctrl)
741+
{
742+
pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_HPIE);
743+
}
744+
735745
/*
736746
* pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
737747
* bus reset of the bridge, but at the same time we want to ensure that it is

0 commit comments

Comments
 (0)