summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpica/acpi_cmbat.c
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2017-03-14 15:55:17 +0000
committerhselasky <hselasky@FreeBSD.org>2017-03-14 15:55:17 +0000
commit135156fe09131c6bd04f2002722f414b6081ab89 (patch)
tree5d1ac3049640e67312ca720d5a6df90c2f19df76 /sys/dev/acpica/acpi_cmbat.c
parent00d6cf0f54b827404cd040b20f76cb1314494902 (diff)
downloadFreeBSD-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.c34
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);
OpenPOWER on IntegriCloud