Re: [PATCH] Bluetooth: Properly disable remote wakeup for MT7922/MT7925 on Ryzen platform
From: Luiz Augusto von Dentz
Date: Tue Jun 30 2026 - 14:14:46 EST
Hi Rong,
On Mon, Jun 29, 2026 at 11:28 AM Rong Zhang <i@xxxxxxxx> wrote:
>
> It is reported that a remote wakeup could cause MT7922/MT7925's btusb
> interface completely unresponsive. Resetting the xHCI root hub doesn't
> help at all, and recovering from such a state needs a power cycle.
>
> All reports seen to be relevant to Ryzen-based laptops. These NICs are
> usually used as OEM components thanks to some sort of reference designs.
>
> Their popularity on other platforms is unclear. While there is still a
> chance that the quirk may exist on other platforms, be cautious and only
> apply the quirk on AMD platforms for the time being.
>
> Meanwhile, though device_set_wakeup_capable(false) is the correct fix
> for other NICs with fake remote wakeup capabilities, doing so for
> MT7922/MT7925 effectively prevents it from being used as wakeup
> sources as per userspace requests. Hence, return -EBUSY on runtime
> suspend to prevent the interface from being autosuspended while it's
> still opened, which has the same effect as
> device_set_wakeup_capable(false), since disabling remote wakeup simply
> causes the USB core to gate runtime autosuspend as well due to
> needs_remote_wakeup == 1. The interface can be safely autosuspended as
> long as remote wakeup is disabled, i.e., after closing the HCI device.
>
> Specifically, the interface may still take the advantage of remote
> wakeup in order to wake up the system from sleep if userspace has
> enabled it as a wakeup source.
>
> Fixes: e31d761628ad ("Bluetooth: btmtk: Disable remote wakeup for MT7922/MT7925")
> Signed-off-by: Rong Zhang <i@xxxxxxxx>
> ---
> drivers/bluetooth/btmtk.c | 10 ---------
> drivers/bluetooth/btusb.c | 57 +++++++++++++++++++++++++++++++++++++++++++----
> 2 files changed, 53 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
> index 02a96342e964..4614434dd57b 100644
> --- a/drivers/bluetooth/btmtk.c
> +++ b/drivers/bluetooth/btmtk.c
> @@ -1381,16 +1381,6 @@ int btmtk_usb_setup(struct hci_dev *hdev)
> break;
> case 0x7922:
> case 0x7925:
> - /*
> - * A remote wakeup could cause the device completely unresponsive, and
> - * recovering from such a state needs a power cycle.
> - *
> - * Since the remote wakeup capability is super broken, just disable it
> - * to get rid of the troubles. The device can still be autosuspended
> - * when the bluetooth interface is closed.
> - */
> - device_set_wakeup_capable(&btmtk_data->udev->dev, false);
> - fallthrough;
> case 0x7961:
> case 0x7902:
> case 0x6639:
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 08c0a99a62c5..023ae782f41a 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -6,6 +6,7 @@
> * Copyright (C) 2005-2008 Marcel Holtmann <marcel@xxxxxxxxxxxx>
> */
>
> +#include <linux/cpufeature.h>
> #include <linux/dmi.h>
> #include <linux/module.h>
> #include <linux/usb.h>
> @@ -957,6 +958,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_WAKEUP_BROKEN 18
>
> struct btusb_data {
> struct hci_dev *hdev;
> @@ -2936,10 +2938,20 @@ static int btusb_send_frame_mtk(struct hci_dev *hdev, struct sk_buff *skb)
> }
> }
>
> +static inline bool platform_is_ryzen(void)
> +{
> +#ifdef CONFIG_X86
> + return boot_cpu_has(X86_FEATURE_ZEN);
> +#else
> + return false;
> +#endif
> +}
> +
> static int btusb_mtk_setup(struct hci_dev *hdev)
> {
> struct btusb_data *data = hci_get_drvdata(hdev);
> struct btmtk_data *btmtk_data = hci_get_priv(hdev);
> + int err;
>
> /* MediaTek WMT vendor cmd requiring below USB resources to
> * complete the handshake.
> @@ -2956,7 +2968,29 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
> btusb_mtk_claim_iso_intf(data);
> }
>
> - return btmtk_usb_setup(hdev);
> + err = btmtk_usb_setup(hdev);
> + if (err)
> + return err;
> +
> + switch (btmtk_data->dev_id) {
> + case 0x7922:
> + case 0x7925:
> + /*
> + * All reports seen to be relevant to Ryzen-based laptops. These
> + * NICs are usually used as OEM components thanks to some sort
> + * of reference designs.
> + *
> + * Their popularity on other platforms is unclear. While there
> + * is still a chance that the quirk may exist on other
> + * platforms, be cautious and only apply the quirk on AMD
> + * platforms for the time being.
> + */
Is this going to be a reliable way to detect if wakeup is broken or
not? Since USB is a bus capable of hotplug, this check would block not
only internal/built-in controllers with the above IDs but also those
plugged via external ports if the CPU happens to be of the ZEN
familly.
> + if (platform_is_ryzen())
> + set_bit(BTUSB_WAKEUP_BROKEN, &data->flags);
> + break;
> + }
> +
> + return 0;
> }
>
> static int btusb_mtk_shutdown(struct hci_dev *hdev)
> @@ -4532,11 +4566,26 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
>
> BT_DBG("intf %p", intf);
>
> - /* Don't auto-suspend if there are connections or discovery in
> - * progress; external suspend calls shall never fail.
> + /*
> + * It is reported that remote wakeup events could sometimes cause some
> + * adapters completely unresponsive. Resetting the xHCI root hub doesn't
> + * help at all, and recovering from such a state needs a power cycle.
> + * Since disabling remote wakeup simply causes the USB core to gate
> + * runtime autosuspend as well due to needs_remote_wakeup == 1, let's do
> + * this ourselves to make our life easier. The interface can be safely
> + * autosuspended as long as remote wakeup is disabled, i.e., after
> + * closing the HCI device.
> + *
> + * Don't auto-suspend if there are connections or discovery in progress.
> + *
> + * External suspend calls shall never fail. Specifically, a device with
> + * broken remote wakeup may still take the advantage of remote wakeup in
> + * order to wake up the system from sleep if userspace has enabled it as
> + * a wakeup source.
> */
> if (PMSG_IS_AUTO(message) &&
> - (hci_conn_count(data->hdev) || hci_discovery_active(data->hdev)))
> + ((test_bit(BTUSB_WAKEUP_BROKEN, &data->flags) && data->intf->needs_remote_wakeup) ||
> + hci_conn_count(data->hdev) || hci_discovery_active(data->hdev)))
> return -EBUSY;
>
> if (data->suspend_count++)
>
> ---
> base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
> change-id: 230ba8c9-btmtk-ryzen-remote-wakeup-055a407682ef
>
> Thanks,
> Rong
>
--
Luiz Augusto von Dentz