summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2014-09-08 20:25:04 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2014-09-08 20:25:04 +0000
commit1ca7851bb42c55223415877acca530dec80257e1 (patch)
treea55fbd7fd285e79402bc9b0be7d37c735dd8eca4 /sys/dev
parent5697aaebdf992c29ef2b2f1e1f400ee0bdb23af9 (diff)
Clear the PME Status bit on PCI devices in response to Device Wake events.
Fixes the interrupt storm on the 2009 Mac mini with WOL enabled on its nfe(4) interface. ok mlarkin@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/acpi/acpi.c28
1 files changed, 27 insertions, 1 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c
index 9fdbfba3e98..3967d2c0ca9 100644
--- a/sys/dev/acpi/acpi.c
+++ b/sys/dev/acpi/acpi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi.c,v 1.267 2014/07/20 18:05:21 mlarkin Exp $ */
+/* $OpenBSD: acpi.c,v 1.268 2014/09/08 20:25:03 kettenis Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
@@ -74,6 +74,7 @@ int acpi_hasprocfvs;
void acpi_pci_match(struct device *, struct pci_attach_args *);
pcireg_t acpi_pci_min_powerstate(pci_chipset_tag_t, pcitag_t);
void acpi_pci_set_powerstate(pci_chipset_tag_t, pcitag_t, int, int);
+int acpi_pci_notify(struct aml_node *, int, void *);
int acpi_match(struct device *, void *, void *);
void acpi_attach(struct device *, struct device *, void *);
@@ -567,6 +568,8 @@ acpi_pci_match(struct device *dev, struct pci_attach_args *pa)
state = pci_get_powerstate(pa->pa_pc, pa->pa_tag);
acpi_pci_set_powerstate(pa->pa_pc, pa->pa_tag, state, 1);
acpi_pci_set_powerstate(pa->pa_pc, pa->pa_tag, state, 0);
+
+ aml_register_notify(pdev->node, NULL, acpi_pci_notify, pdev, 0);
}
}
@@ -662,6 +665,29 @@ acpi_pci_set_powerstate(pci_chipset_tag_t pc, pcitag_t tag, int state, int pre)
#endif /* NACPIPWRRES > 0 */
}
+int
+acpi_pci_notify(struct aml_node *node, int ntype, void *arg)
+{
+ struct acpi_pci *pdev = arg;
+ pci_chipset_tag_t pc = NULL;
+ pcitag_t tag;
+ pcireg_t reg;
+ int offset;
+
+ /* We're only interested in Device Wake notifications. */
+ if (ntype != 2)
+ return (0);
+
+ tag = pci_make_tag(pc, pdev->bus, pdev->dev, pdev->fun);
+ if (pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, 0)) {
+ /* Clear the PME Status bit if it is set. */
+ reg = pci_conf_read(pc, tag, offset + PCI_PMCSR);
+ pci_conf_write(pc, tag, offset + PCI_PMCSR, reg);
+ }
+
+ return (0);
+}
+
void
acpi_pciroots_attach(struct device *dev, void *aux, cfprint_t pr)
{