diff options
| author | Andriy Gapon <avg@FreeBSD.org> | 2019-01-28 09:45:28 +0000 |
|---|---|---|
| committer | Andriy Gapon <avg@FreeBSD.org> | 2019-01-28 09:45:28 +0000 |
| commit | 7a7a6d9241772089501af309cd4c7107611faa25 (patch) | |
| tree | 016c8468fbb43587b33780b6a13ebe72f42b4a4d /sys/dev/pci | |
| parent | 05eb2e665bbbd49d4ad475087a204ad7b5bb75e7 (diff) | |
Notes
Diffstat (limited to 'sys/dev/pci')
| -rw-r--r-- | sys/dev/pci/pci.c | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 7c6a1604c13a..ce1f6963555c 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -4457,6 +4457,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); @@ -4473,8 +4474,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); } @@ -4483,6 +4496,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); @@ -4494,6 +4508,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); } |
