[PATCH v3 1/2] Bluetooth: btusb: mediatek: Fix leaked runtime PM reference in reset
Jiajia Liu
liujiajia at kylinos.cn
Thu Aug 20 23:26:05 PDT 2026
MT7925 on HP Pro Mini 260 sometimes timed out during reloading driver
and reset usb device. btusb_suspend is not called again after closing
bluetooth interface.
usbcore: registered new interface driver btusb
Bluetooth: hci0: HW/SW Version: 0x00000000, Build Time: 20260605184935
Bluetooth: hci0: Execution of wmt command timed out
Bluetooth: hci0: Failed to send wmt patch dwnld (-110)
Bluetooth: hci0: Failed to set up firmware (-110)
usb 3-10: reset high-speed USB device number 4 using xhci_hcd
Bluetooth: hci0: HW/SW Version: 0x00000000, Build Time: 20260605184935
Bluetooth: hci0: Device setup in 1856545 usecs
Bluetooth: hci0: AOSP extensions version v1.00
Bluetooth: hci0: AOSP quality report is supported
Bluetooth: MGMT ver 1.23
btusb_mtk_reset calls usb_autopm_get_interface to resume the device
before driving the hardware reset, but never calls the matching
usb_autopm_put_interface. Every hardware reset therefore leaks a PM
usage reference of the interface, preventing the device from being
runtime suspended again until it is unbound.
Add the BTUSB_RESET flag. It is set right after the PM reference
is acquired (unless the reset goes through a GPIO) and is cleared in
btusb_disconnect, which drops the reference as well. If the flag is
already set when a new reset is requested, the previously queued reset
has not finished yet, so drop the newly acquired reference and return.
Also clear BTMTK_HW_RESET_ACTIVE if usb_autopm_get_interface fails,
otherwise no further reset could ever be attempted.
Fixes: 25b6d7593a3a ("Bluetooth: btmtk: introduce btmtk reset work")
Assisted-by: Claude:qwen3.8-max
Signed-off-by: Jiajia Liu <liujiajia at kylinos.cn>
---
Changes in v3:
- rename BTUSB_USB_RESET_ACTIVE to BTUSB_RESET (Luiz)
- test_and_clear_bit BTUSB_RESET in btusb_disconnect (Luiz)
- handle multiple reset requests int btusb_mtk_reset (sashiko)
set BTUSB_RESET if no reset_gpio after usb_autopm_get_interface.
If the flag is already set, add log and drop newly acquired reference
and return.
- clear BTMTK_HW_RESET_ACTIVE if usb_autopm_get_interface fails and add
error log. (sashiko)
Changes in v2:
- Fix the race window (sashiko)
Add and set BTUSB_USB_RESET_ACTIVE flag before usb_queue_reset_device.
Release PM reference in btusb_disconnect if this flag is set.
Changes in v1:
- add usb_autopm_put_interface after usb_queue_reset_device
---
drivers/bluetooth/btusb.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 184e95c1625e..360cec460ce7 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -957,6 +957,7 @@ struct qca_dump_info {
#define BTUSB_USE_ALT3_FOR_WBS 15
#define BTUSB_ALT6_CONTINUOUS_TX 16
#define BTUSB_HW_SSR_ACTIVE 17
+#define BTUSB_RESET 18
struct btusb_data {
struct hci_dev *hdev;
@@ -2891,8 +2892,19 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
}
err = usb_autopm_get_interface(data->intf);
- if (err < 0)
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed usb_autopm_get_interface: %d", err);
+ clear_bit(BTMTK_HW_RESET_ACTIVE, &btmtk_data->flags);
return err;
+ }
+
+ if (!data->reset_gpio &&
+ test_and_set_bit(BTUSB_RESET, &data->flags)) {
+ bt_dev_err(hdev, "last usb reset failed? Not resetting again");
+ clear_bit(BTMTK_HW_RESET_ACTIVE, &btmtk_data->flags);
+ usb_autopm_put_interface_no_suspend(data->intf);
+ return -EBUSY;
+ }
/* Release MediaTek ISO data interface */
btusb_mtk_release_iso_intf(hdev);
@@ -4497,6 +4509,9 @@ static void btusb_disconnect(struct usb_interface *intf)
if (data->reset_gpio)
gpiod_put(data->reset_gpio);
+ if (test_and_clear_bit(BTUSB_RESET, &data->flags))
+ usb_autopm_put_interface_no_suspend(data->intf);
+
if (intf == data->intf) {
if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc);
--
2.55.0
More information about the Linux-mediatek
mailing list