[PATCH] Bluetooth: Properly disable remote wakeup for MT7922/MT7925 on Ryzen platform

Luiz Augusto von Dentz luiz.dentz at gmail.com
Tue Jun 30 11:13:39 PDT 2026


Hi Rong,

On Mon, Jun 29, 2026 at 11:28 AM Rong Zhang <i at rong.moe> 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 at rong.moe>
> ---
>  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 at holtmann.org>
>   */
>
> +#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



More information about the Linux-mediatek mailing list