summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoriwasaki <iwasaki@FreeBSD.org>2003-09-17 08:32:44 +0000
committeriwasaki <iwasaki@FreeBSD.org>2003-09-17 08:32:44 +0000
commit9fac14e51fbda70a693d9001fd1ab05d3560cc98 (patch)
treedf08b28e66ee6ccb78c1f44513d4a14348e26794
parentab6ce03a9b2691492b4e4996f2f14960556c42e8 (diff)
downloadFreeBSD-src-9fac14e51fbda70a693d9001fd1ab05d3560cc98.zip
FreeBSD-src-9fac14e51fbda70a693d9001fd1ab05d3560cc98.tar.gz
Add pci_resume() to reestablish interrupt routing after
suspend/resume. Especially after hibernation, interrupt routing went back to initial status on some machines.
-rw-r--r--sys/dev/acpica/acpi_pci.c2
-rw-r--r--sys/dev/pci/pci.c34
-rw-r--r--sys/dev/pci/pci_private.h1
3 files changed, 35 insertions, 2 deletions
diff --git a/sys/dev/acpica/acpi_pci.c b/sys/dev/acpica/acpi_pci.c
index b8bf11e..85b6b1c 100644
--- a/sys/dev/acpica/acpi_pci.c
+++ b/sys/dev/acpica/acpi_pci.c
@@ -79,7 +79,7 @@ static device_method_t acpi_pci_methods[] = {
DEVMETHOD(device_attach, acpi_pci_attach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
- DEVMETHOD(device_resume, bus_generic_resume),
+ DEVMETHOD(device_resume, pci_resume),
/* Bus interface */
DEVMETHOD(bus_print_child, pci_print_child),
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index a4e1a54..a7f320e 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -89,7 +89,7 @@ static device_method_t pci_methods[] = {
DEVMETHOD(device_attach, pci_attach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
- DEVMETHOD(device_resume, bus_generic_resume),
+ DEVMETHOD(device_resume, pci_resume),
/* Bus interface */
DEVMETHOD(bus_print_child, pci_print_child),
@@ -1509,3 +1509,35 @@ pci_modevent(module_t mod, int what, void *arg)
return (0);
}
+
+int
+pci_resume(device_t dev)
+{
+ int numdevs;
+ int i;
+ device_t *children;
+ device_t child;
+ struct pci_devinfo *dinfo;
+ pcicfgregs *cfg;
+
+ device_get_children(dev, &children, &numdevs);
+
+ for (i = 0; i < numdevs; i++) {
+ child = children[i];
+
+ dinfo = device_get_ivars(child);
+ cfg = &dinfo->cfg;
+ if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) {
+ cfg->intline = PCI_ASSIGN_INTERRUPT(dev, child);
+ if (PCI_INTERRUPT_VALID(cfg->intline)) {
+ pci_write_config(child, PCIR_INTLINE,
+ cfg->intline, 1);
+ }
+ }
+ }
+
+ free(children, M_TEMP);
+
+ return (bus_generic_resume(dev));
+}
+
diff --git a/sys/dev/pci/pci_private.h b/sys/dev/pci/pci_private.h
index 3123c61..816106d 100644
--- a/sys/dev/pci/pci_private.h
+++ b/sys/dev/pci/pci_private.h
@@ -73,4 +73,5 @@ int pci_child_location_str_method(device_t cbdev, device_t child,
int pci_child_pnpinfo_str_method(device_t cbdev, device_t child,
char *buf, size_t buflen);
int pci_assign_interrupt_method(device_t dev, device_t child);
+int pci_resume(device_t dev);
#endif /* _PCI_PRIVATE_H_ */
OpenPOWER on IntegriCloud