]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling
authorShuai Zhang <shuai.zhang@oss.qualcomm.com>
Fri, 10 Apr 2026 09:54:43 +0000 (17:54 +0800)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 13 Apr 2026 13:19:42 +0000 (09:19 -0400)
When a Bluetooth controller encounters a coredump, it triggers the
Subsystem Restart (SSR) mechanism. The controller first reports the
coredump data and, once the upload is complete, sends a hw_error
event. The host relies on this event to proceed with subsequent
recovery actions.

If the host has not finished processing the coredump data when the
hw_error event is received, it waits until either the processing is
complete or the 8-second timeout expires before handling the event.

The current implementation clears QCA_MEMDUMP_COLLECTION using
clear_bit(), which does not wake up waiters sleeping in
wait_on_bit_timeout(). As a result, the waiting thread may remain
blocked until the timeout expires even if the coredump collection
has already completed.

Fix this by clearing QCA_MEMDUMP_COLLECTION with
clear_and_wake_up_bit(), which also wakes up the waiting thread and
allows the hw_error handling to proceed immediately.

Test case:
- Trigger a controller coredump using:
    hcitool cmd 0x3f 0c 26
- Tested on QCA6390.
- Capture HCI logs using btmon.
- Verify that the delay between receiving the hw_error event and
  initiating the power-off sequence is reduced compared to the
  timeout-based behavior.

Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
drivers/bluetooth/hci_qca.c

index 4512ff7cd0c013710224c670f6c4dfd6da2c59e6..cd1834246b4793939c2f92af32ce7212f1f3d86a 100644 (file)
@@ -1108,7 +1108,7 @@ static void qca_controller_memdump(struct work_struct *work)
                                qca->qca_memdump = NULL;
                                qca->memdump_state = QCA_MEMDUMP_COLLECTED;
                                cancel_delayed_work(&qca->ctrl_memdump_timeout);
-                               clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
+                               clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
                                clear_bit(QCA_IBS_DISABLED, &qca->flags);
                                mutex_unlock(&qca->hci_memdump_lock);
                                return;
@@ -1186,7 +1186,7 @@ static void qca_controller_memdump(struct work_struct *work)
                        kfree(qca->qca_memdump);
                        qca->qca_memdump = NULL;
                        qca->memdump_state = QCA_MEMDUMP_COLLECTED;
-                       clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
+                       clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
                }
 
                mutex_unlock(&qca->hci_memdump_lock);