diff options
author | hselasky <hselasky@FreeBSD.org> | 2017-03-14 15:55:17 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2017-03-14 15:55:17 +0000 |
commit | 135156fe09131c6bd04f2002722f414b6081ab89 (patch) | |
tree | 5d1ac3049640e67312ca720d5a6df90c2f19df76 /sys/dev/acpica/acpi_cmbat.c | |
parent | 00d6cf0f54b827404cd040b20f76cb1314494902 (diff) | |
download | FreeBSD-src-135156fe09131c6bd04f2002722f414b6081ab89.zip FreeBSD-src-135156fe09131c6bd04f2002722f414b6081ab89.tar.gz |
MFC r314328:
Fix startup race initialising ACPI CM battery structures on MacBookPro.
During acpi_cmbat_attach() the acpi_cmbat_init_battery() notification
handler is registered. It has been observed this notification handler
can be called instantly, before the attach routine has returned. In
the notification handler there is a call to device_is_attached() which
returns false. Because the softc is set we know an attach is in
progress and the fix is simply to wait and try again in this case.
Reviewed by: avg @
Diffstat (limited to 'sys/dev/acpica/acpi_cmbat.c')
-rw-r--r-- | sys/dev/acpica/acpi_cmbat.c | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/sys/dev/acpica/acpi_cmbat.c b/sys/dev/acpica/acpi_cmbat.c index be57a32..7dbfa03 100644 --- a/sys/dev/acpica/acpi_cmbat.c +++ b/sys/dev/acpica/acpi_cmbat.c @@ -164,6 +164,16 @@ acpi_cmbat_detach(device_t dev) handle = acpi_get_handle(dev); AcpiRemoveNotifyHandler(handle, ACPI_ALL_NOTIFY, acpi_cmbat_notify_handler); acpi_battery_remove(dev); + + /* + * Force any pending notification handler calls to complete by + * requesting cmbat serialisation while freeing and clearing the + * softc pointer: + */ + ACPI_SERIAL_BEGIN(cmbat); + device_set_softc(dev, NULL); + ACPI_SERIAL_END(cmbat); + return (0); } @@ -436,7 +446,6 @@ acpi_cmbat_init_battery(void *arg) device_t dev; dev = (device_t)arg; - sc = device_get_softc(dev); ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), "battery initialization start\n"); @@ -446,18 +455,33 @@ acpi_cmbat_init_battery(void *arg) * to wait a while. */ for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) { - /* batteries on DOCK can be ejected w/ DOCK during retrying */ - if (!device_is_attached(dev)) + /* + * Batteries on DOCK can be ejected w/ DOCK during retrying. + * + * If there is a valid softc pointer the device may be in + * attaching, attached or detaching state. If the state is + * different from attached retry getting the device state + * until it becomes stable. This solves a race if the ACPI + * notification handler is called during attach, because + * device_is_attached() doesn't return non-zero until after + * the attach code has been executed. + */ + ACPI_SERIAL_BEGIN(cmbat); + sc = device_get_softc(dev); + if (sc == NULL) { + ACPI_SERIAL_END(cmbat); return; + } - if (!acpi_BatteryIsPresent(dev)) + if (!acpi_BatteryIsPresent(dev) || !device_is_attached(dev)) { + ACPI_SERIAL_END(cmbat); continue; + } /* * Only query the battery if this is the first try or the specific * type of info is still invalid. */ - ACPI_SERIAL_BEGIN(cmbat); if (retry == 0 || !acpi_battery_bst_valid(&sc->bst)) { timespecclear(&sc->bst_lastupdated); acpi_cmbat_get_bst(dev); |