From c5c5881979378a64ecf935ee2f1ebf2a3788ee1a Mon Sep 17 00:00:00 2001 From: hselasky Date: Tue, 14 Mar 2017 15:58:01 +0000 Subject: [PATCH] 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 @ git-svn-id: svn://svn.freebsd.org/base/stable/8@315266 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/acpica/acpi_cmbat.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/sys/dev/acpica/acpi_cmbat.c b/sys/dev/acpica/acpi_cmbat.c index 6c6525d3e..6d25b8c2a 100644 --- a/sys/dev/acpica/acpi_cmbat.c +++ b/sys/dev/acpica/acpi_cmbat.c @@ -163,6 +163,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); } @@ -435,7 +445,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"); @@ -445,18 +454,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); -- 2.44.0