* [PATCH 1/2] Bluetooth: btmtksdio: wait while Wi-Fi downloads the shared patch
2026-10-26 19:02 [PATCH 0/2] Bluetooth: btmtksdio: fix MT7663 setup next to the Wi-Fi function Ryan Brue
@ 2026-10-26 19:02 ` Ryan Brue
2026-10-26 22:02 ` Bluetooth: btmtksdio: fix MT7663 setup next to the Wi-Fi function bluez.test.bot
2026-10-26 19:02 ` [PATCH 2/2] Bluetooth: btmtksdio: retry enabling the function on MT7663/MT7668 Ryan Brue
1 sibling, 1 reply; 4+ messages in thread
From: Ryan Brue @ 2026-10-26 19:02 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Matthias Brugger,
AngeloGioacchino Del Regno, Sean Wang
Cc: linux-bluetooth, linux-kernel, linux-arm-kernel, linux-mediatek,
Ryan Brue
On MT7663 and MT7668 the Bluetooth and Wi-Fi SDIO functions share one
ROM patch, guarded by a semaphore in the firmware. The WMT semaphore
query answers 0 while the other function holds the semaphore and is
downloading the patch, 1 when the patch is ready, and 2 when it needs
downloading (MediaTek's own driver: PATCH_IS_DOWNLOAD_BY_OTHER,
PATCH_READY, PATCH_NEED_DOWNLOAD). btmtksdio treated 0 like 1, so when
it probed while mt7663s was downloading, it went on to enable the
Bluetooth function on a half-loaded patch. On an MT7663 module
(Amazon Fire TV Stick) that left the chip unresponsive until reset:
Bluetooth: hci0: Firmware already downloaded
Bluetooth: hci0: Execution of wmt command timed out
mt7663s mmc2:0001:1: Message 00000007 (seq 13) timeout
mt7663s mmc2:0001:1: Failed to start patch
Map 0 to BTMTK_WMT_PATCH_PROGRESS, and poll every 100 ms, for up to
5 s, while the other function is downloading, as MediaTek's driver
does.
Fixes: 9aebfd4a2200 ("Bluetooth: mediatek: add support for MediaTek MT7663S and MT7668S SDIO devices")
Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
---
drivers/bluetooth/btmtksdio.c | 35 +++++++++++++++++++++++++++++------
1 file changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index b9563df72983..bb311986271f 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -234,8 +234,16 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
switch (wmt_evt->whdr.op) {
case BTMTK_WMT_SEMAPHORE:
+ /*
+ * 0: the other function (Wi-Fi on MT7663/MT7668) holds the
+ * semaphore and is downloading the shared patch
+ * 1: the patch is ready
+ * 2: the patch needs downloading
+ */
if (wmt_evt->whdr.flag == 2)
status = BTMTK_WMT_PATCH_UNDONE;
+ else if (wmt_evt->whdr.flag == 0)
+ status = BTMTK_WMT_PATCH_PROGRESS;
else
status = BTMTK_WMT_PATCH_DONE;
break;
@@ -842,20 +850,35 @@ static int mt76xx_setup(struct hci_dev *hdev, const char *fwname)
struct btmtk_hci_wmt_params wmt_params;
struct btmtk_tci_sleep tci_sleep;
struct sk_buff *skb;
- int err, status;
+ int err, status, i;
u8 param = 0x1;
- /* Query whether the firmware is already download */
+ /*
+ * Query whether the firmware is already downloaded. While the Wi-Fi
+ * function downloads the shared patch, wait for it to finish.
+ */
wmt_params.op = BTMTK_WMT_SEMAPHORE;
wmt_params.flag = 1;
wmt_params.dlen = 0;
wmt_params.data = NULL;
wmt_params.status = &status;
- err = mtk_hci_wmt_sync(hdev, &wmt_params);
- if (err < 0) {
- bt_dev_err(hdev, "Failed to query firmware status (%d)", err);
- return err;
+ for (i = 0; i < 50; i++) {
+ err = mtk_hci_wmt_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to query firmware status (%d)",
+ err);
+ return err;
+ }
+
+ if (status != BTMTK_WMT_PATCH_PROGRESS)
+ break;
+ msleep(100);
+ }
+
+ if (status == BTMTK_WMT_PATCH_PROGRESS) {
+ bt_dev_err(hdev, "Patch download by the other function did not finish");
+ return -EBUSY;
}
if (status == BTMTK_WMT_PATCH_DONE) {
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH 2/2] Bluetooth: btmtksdio: retry enabling the function on MT7663/MT7668
2026-10-26 19:02 [PATCH 0/2] Bluetooth: btmtksdio: fix MT7663 setup next to the Wi-Fi function Ryan Brue
2026-10-26 19:02 ` [PATCH 1/2] Bluetooth: btmtksdio: wait while Wi-Fi downloads the shared patch Ryan Brue
@ 2026-10-26 19:02 ` Ryan Brue
1 sibling, 0 replies; 4+ messages in thread
From: Ryan Brue @ 2026-10-26 19:02 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Matthias Brugger,
AngeloGioacchino Del Regno, Sean Wang
Cc: linux-bluetooth, linux-kernel, linux-arm-kernel, linux-mediatek,
Ryan Brue
Right after the Wi-Fi function of an MT7663 combo chip starts its
firmware, the WMT function-enable request is refused (the reply's flag
byte is 2). btmtksdio ignored the reply, so the following low power
setup command then timed out and setup failed:
Bluetooth: hci0: command 0xfc7a tx timeout
Bluetooth: hci0: Failed to apply low power setting (-110)
Check the result and retry every 500 ms, up to ten times, as MediaTek's
own driver retries its power-on command. With mt7663s probing first, the
function now starts on the second attempt and setup completes.
Fixes: 9aebfd4a2200 ("Bluetooth: mediatek: add support for MediaTek MT7663S and MT7668S SDIO devices")
Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
---
drivers/bluetooth/btmtksdio.c | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index bb311986271f..239393a15e46 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -909,17 +909,33 @@ static int mt76xx_setup(struct hci_dev *hdev, const char *fwname)
goto ignore_func_on;
}
- /* Enable Bluetooth protocol */
+ /*
+ * Enable Bluetooth protocol. While the Wi-Fi function of a combo
+ * chip is still starting its firmware, the request is refused, so
+ * retry it.
+ */
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
wmt_params.flag = 0;
wmt_params.dlen = sizeof(param);
wmt_params.data = ¶m;
- wmt_params.status = NULL;
+ wmt_params.status = &status;
- err = mtk_hci_wmt_sync(hdev, &wmt_params);
- if (err < 0) {
- bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
- return err;
+ for (i = 0; i < 10; i++) {
+ err = mtk_hci_wmt_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)",
+ err);
+ return err;
+ }
+
+ if (status == BTMTK_WMT_ON_DONE)
+ break;
+ msleep(500);
+ }
+
+ if (status != BTMTK_WMT_ON_DONE) {
+ bt_dev_err(hdev, "Bluetooth function refused to start");
+ return -EIO;
}
set_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state);
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread