[PATCH RFC v2] Bluetooth: mt7925: trigger reset on WMT timeout
George Maraveyas <[email protected]>
| Newsgroups | org.kernel.feeds.b4-sent,org.infradead.lists.linux-arm-kernel,org.infradead.lists.linux-mediatek,org.kernel.vger.linux-bluetooth,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
The MT7925 Bluetooth USB function can enumerate successfully after a warm reboot while the WMT function-control command remains unresponsive. When that command times out, btmtk_usb_setup() currently returns -ETIMEDOUT without entering the existing MediaTek reset path. The existing USB reset and recovery machinery is therefore never reached. For MT7925, call btmtk_reset_sync() when the WMT function-control command times out. This enters the existing reset path in btusb_mtk_reset(), which performs the MediaTek subsystem reset and queues a USB device reset. Runtime tracing on the affected hardware showed the resulting path through usb_queue_reset_device(), usb_reset_device() and usb_reset_and_verify_device(). When reset and verification could not restore the device, the USB core escalated to a logical disconnect and re-enumeration. Recovery succeeded in three controlled Windows-to-Linux tests. Runtime tracing showed the existing USB reset path escalating to logical disconnect and re-enumeration. In two of those tests, tracing continued through the subsequent enumeration failures and directly captured usb_acpi_port_prr_reset(), after which the MT7925 re-enumerated and Bluetooth recovered. These tests were performed on top of Chia-Lin Kao's ACPI _PRR hub patch, which remains a prerequisite for this patch. A fourth Windows-to-Linux test was then performed with the diagnostic btusb blacklist removed and btusb binding normally during boot. The WMT timeout reproduced and Bluetooth recovered automatically without manual intervention. Signed-off-by: George Maraveyas <[email protected]> --- Dear Alan, Thank you for taking the time to look into my patch and for pointing me towards the existing reset path. I have now traced the failure on the affected MT7925 hardware and tested the individual parts separately. You were correct that a new USB re-enumeration helper is unnecessary. Once the MT7925 failure is made to enter the existing reset path, I can see: btmtk_reset_sync() -> btmtk_usb_subsys_reset() -> usb_queue_reset_device() -> usb_reset_device() -> usb_reset_and_verify_device() When reset and verification cannot restore the device, usb_reset_and_verify_device() eventually reaches: hub_port_logical_disconnect() and normal hub re-enumeration follows. I have therefore dropped the proposed USB helper from v1. The problem I found is earlier in the Bluetooth path. When MT7925 WMT FUNC_CTRL times out, btmtk_usb_setup() currently returns -ETIMEDOUT without entering the existing MediaTek reset machinery. The revised patch now consists only of the part of my original submission that makes this timeout enter the existing reset path: if (dev_id == 0x7925 && err == -ETIMEDOUT) btmtk_reset_sync(hdev); I tested this both with and without Chia-Lin Kao's _PRR hub patch. I want to stress that this v2 is based on and dependent on Kao's patch; that remains the configuration in which I have validated recovery. Kao's patch alone does not recover this failure because the WMT timeout never enters the reset path. With the WMT trigger but without Kao's patch, the reset/disconnect/re-enumeration sequence started, but the device did not recover in that test. With Kao's patch plus the WMT trigger, I reproduced and recovered the Windows-to-Linux failure in three controlled tests. Runtime tracing showed the existing reset path escalating through usb_queue_reset_device(), usb_reset_and_verify_device() and hub_port_logical_disconnect(). In two of those runs, tracing continued through the subsequent enumeration failures and directly captured: usb_acpi_port_prr_reset() <- hub_event.cold The MT7925 subsequently re-enumerated and Bluetooth recovered. I then removed the diagnostic btusb blacklist and repeated the test as a normal Windows-to-Linux restart, allowing btusb to bind automatically. The WMT command again timed out with -110 and the adapter recovered without any manual module loading or other intervention. One behavioural difference is recovery time. The original RFC, which requested logical disconnect/re-enumeration directly after the MT7925 subsystem reset timed out, recovered Bluetooth in about 71 seconds on average. Using the existing usb_queue_reset_device() path takes about 133 seconds to complete Bluetooth setup in the current tests, with successful USB re-enumeration at about 114-115 seconds. The traces account for most of that difference: usb_reset_and_verify_device() spends roughly 65 seconds attempting reset and verification before escalating to hub_port_logical_disconnect(). In practice this was long enough that, during the first test of the reduced patch, I almost concluded that recovery had failed and rebooted to start the test again before the device eventually returned. I do not think that recovery-time difference justifies retaining the new USB API, but it seemed worth mentioning because it is a noticeable behavioural difference between v1 and the reduced approach. Changes in v2: - Drop the proposed USB re-enumeration helper. - Drop the direct MT7925 re-enumeration handling which depended on it. - Reduce the series from two patches to one Bluetooth patch. - Retain only the part of the original Bluetooth patch that enters the existing reset path on an MT7925 WMT -ETIMEDOUT. - Keep Chia-Lin Kao's ACPI _PRR hub patch as a prerequisite. - Add the new runtime trace and recovery results. - Link to v1: https://patch.msgid.link/[email protected] Thanks again for the review. Kind regards, George --- drivers/bluetooth/btmtk.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index 66b346761..e8f02f1e3 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -1413,6 +1413,10 @@ int btmtk_usb_setup(struct hci_dev *hdev) err = btmtk_usb_hci_wmt_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err); + + if (dev_id == 0x7925 && err == -ETIMEDOUT) + btmtk_reset_sync(hdev); + return err; } --- base-commit: 28d012efb4327f9c75d5e042a7c91e9a542efa98 change-id: 20260818-mt7925-rfc-edd34ef031d9 prerequisite-message-id: <[email protected]> prerequisite-patch-id: 47a2729fbc473534f8ba52052b00723c54a26c17 Best regards, -- George Maraveyas <[email protected]>