diff options
| author | riastradh <riastradh@NetBSD.org> | 2021-12-31 14:22:42 +0000 |
|---|---|---|
| committer | riastradh <riastradh@NetBSD.org> | 2021-12-31 14:22:42 +0000 |
| commit | 6b9e9fee75d787fae20994eae96731065aef4f27 (patch) | |
| tree | 3706a2516f41440b81e3959b1327b38c38174d62 /sys/dev | |
| parent | 77c274b4e6d87162073eebb0d6c7c5b9f807b7a6 (diff) | |
acpi(9): Fix memory ordering and completion bugs in notifiers.
1. Guarantee everything which happened before acpi_register_notify
has also happened before the notifier is actually called.
2. On acpi_deregister_notify, don't return until the notifier is
definitely not running any more on any CPU, using
AcpiOsWaitEventsComplete.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/acpi/acpi.c | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index 76bab345c5d..d018fdda109 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $NetBSD: acpi.c,v 1.294 2021/12/20 11:17:40 skrll Exp $ */ +/* $NetBSD: acpi.c,v 1.295 2021/12/31 14:22:42 riastradh Exp $ */ /*- * Copyright (c) 2003, 2007 The NetBSD Foundation, Inc. @@ -100,13 +100,14 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.294 2021/12/20 11:17:40 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.295 2021/12/31 14:22:42 riastradh Exp $"); #include "pci.h" #include "opt_acpi.h" #include "opt_pcifixup.h" #include <sys/param.h> +#include <sys/atomic.h> #include <sys/device.h> #include <sys/kernel.h> #include <sys/kmem.h> @@ -1146,6 +1147,7 @@ acpi_notify_handler(ACPI_HANDLE handle, uint32_t event, void *aux) { struct acpi_softc *sc = acpi_softc; struct acpi_devnode *ad; + ACPI_NOTIFY_HANDLER notify; KASSERT(sc != NULL); KASSERT(aux == NULL); @@ -1189,13 +1191,13 @@ acpi_notify_handler(ACPI_HANDLE handle, uint32_t event, void *aux) if (ad->ad_device == NULL) continue; - if (ad->ad_notify == NULL) + if ((notify = atomic_load_acquire(&ad->ad_notify)) == NULL) continue; if (ad->ad_handle != handle) continue; - (*ad->ad_notify)(ad->ad_handle, event, ad->ad_device); + (*notify)(ad->ad_handle, event, ad->ad_device); return; } @@ -1218,7 +1220,7 @@ acpi_register_notify(struct acpi_devnode *ad, ACPI_NOTIFY_HANDLER notify) if (ad == NULL || notify == NULL) goto fail; - ad->ad_notify = notify; + atomic_store_release(&ad->ad_notify, notify); return true; @@ -1233,7 +1235,10 @@ void acpi_deregister_notify(struct acpi_devnode *ad) { - ad->ad_notify = NULL; + atomic_store_relaxed(&ad->ad_notify, NULL); + + /* Wait for any in-flight calls to the notifier to complete. */ + AcpiOsWaitEventsComplete(); } /* |
