]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Bluetooth: btusb: fix wakeup irq devres lifetime
authorJohan Hovold <johan@kernel.org>
Thu, 4 Jun 2026 06:37:39 +0000 (08:37 +0200)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 11 Jun 2026 18:24:40 +0000 (14:24 -0400)
The OOB wakeup interrupt is device managed but its lifetime is
incorrectly tied to the child HCI device rather than the USB interface
to which the driver is bound.

This should not cause any trouble currently as the interrupt will be
disabled when the HCI device is deregistered on disconnect (but this was
not always the case, see [1]), and there should be no further references
if probe fails before registering it. But it is still technically wrong
as the reference counted HCI device could in theory remain after a probe
failure.

Explicitly free the interrupt on disconnect so that it is guaranteed to
be disabled before freeing the (non-managed) driver data (including if
disconnected while suspended).

[1] 699fb50d9903 ("drivers: base: Free devm resources when unregistering
                   a device")

Fixes: fd913ef7ce61 ("Bluetooth: btusb: Add out-of-band wakeup support")
Cc: Rajat Jain <rajatja@google.com>
Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
drivers/bluetooth/btusb.c

index 966e017ac1dfe8bf70bb87e2e8e01710e6c87cee..843c649f80533bcc39a05817fba085dc226b65ab 100644 (file)
@@ -3843,8 +3843,7 @@ static int btusb_config_oob_wake(struct hci_dev *hdev)
        }
 
        irq_set_status_flags(irq, IRQ_NOAUTOEN);
-       ret = devm_request_irq(&hdev->dev, irq, btusb_oob_wake_handler,
-                              0, "OOB Wake-on-BT", data);
+       ret = request_irq(irq, btusb_oob_wake_handler, 0, "OOB Wake-on-BT", data);
        if (ret) {
                bt_dev_err(hdev, "%s: IRQ request failed", __func__);
                return ret;
@@ -3853,12 +3852,18 @@ static int btusb_config_oob_wake(struct hci_dev *hdev)
        ret = device_init_wakeup(dev, true);
        if (ret) {
                bt_dev_err(hdev, "%s: failed to init_wakeup", __func__);
-               return ret;
+               goto err_free_irq;
        }
 
        data->oob_wake_irq = irq;
        bt_dev_info(hdev, "OOB Wake-on-BT configured at IRQ %u", irq);
+
        return 0;
+
+err_free_irq:
+       free_irq(irq, data);
+
+       return ret;
 }
 #else
 static inline int btusb_config_oob_wake(struct hci_dev *hdev)
@@ -4457,8 +4462,10 @@ err_release_siblings:
 err_kill_tx_urbs:
        usb_kill_anchored_urbs(&data->tx_anchor);
 err_disable_wakeup:
-       if (data->oob_wake_irq)
+       if (data->oob_wake_irq) {
                device_init_wakeup(&data->udev->dev, false);
+               free_irq(data->oob_wake_irq, data);
+       }
 out_free_dev:
        if (data->reset_gpio)
                gpiod_put(data->reset_gpio);
@@ -4491,8 +4498,11 @@ static void btusb_disconnect(struct usb_interface *intf)
 
        hci_unregister_dev(hdev);
 
-       if (data->oob_wake_irq)
+       if (data->oob_wake_irq) {
                device_init_wakeup(&data->udev->dev, false);
+               free_irq(data->oob_wake_irq, data);
+       }
+
        if (data->reset_gpio)
                gpiod_put(data->reset_gpio);