summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/pci/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/dev/pci/pci.c')
-rw-r--r--freebsd/sys/dev/pci/pci.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/freebsd/sys/dev/pci/pci.c b/freebsd/sys/dev/pci/pci.c
index 512e8636..09d1ee42 100644
--- a/freebsd/sys/dev/pci/pci.c
+++ b/freebsd/sys/dev/pci/pci.c
@@ -4467,6 +4467,7 @@ int
pci_suspend_child(device_t dev, device_t child)
{
struct pci_devinfo *dinfo;
+ struct resource_list_entry *rle;
int error;
dinfo = device_get_ivars(child);
@@ -4483,8 +4484,20 @@ pci_suspend_child(device_t dev, device_t child)
if (error)
return (error);
- if (pci_do_power_suspend)
+ if (pci_do_power_suspend) {
+ /*
+ * Make sure this device's interrupt handler is not invoked
+ * in the case the device uses a shared interrupt that can
+ * be raised by some other device.
+ * This is applicable only to regular (legacy) PCI interrupts
+ * as MSI/MSI-X interrupts are never shared.
+ */
+ rle = resource_list_find(&dinfo->resources,
+ SYS_RES_IRQ, 0);
+ if (rle != NULL && rle->res != NULL)
+ (void)bus_suspend_intr(child, rle->res);
pci_set_power_child(dev, child, PCI_POWERSTATE_D3);
+ }
return (0);
}
@@ -4493,6 +4506,7 @@ int
pci_resume_child(device_t dev, device_t child)
{
struct pci_devinfo *dinfo;
+ struct resource_list_entry *rle;
if (pci_do_power_resume)
pci_set_power_child(dev, child, PCI_POWERSTATE_D0);
@@ -4504,6 +4518,16 @@ pci_resume_child(device_t dev, device_t child)
bus_generic_resume_child(dev, child);
+ /*
+ * Allow interrupts only after fully resuming the driver and hardware.
+ */
+ if (pci_do_power_suspend) {
+ /* See pci_suspend_child for details. */
+ rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 0);
+ if (rle != NULL && rle->res != NULL)
+ (void)bus_resume_intr(child, rle->res);
+ }
+
return (0);
}