[PATCH 1/2] Bluetooth: btmtksdio: wait while Wi-Fi downloads the shared patch

Ryan Brue ryanbrue.dev at gmail.com
Mon Oct 26 12:02:13 PDT 2026


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 at 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




More information about the Linux-mediatek mailing list