summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lu <chris.lu@mediatek.com>2026-09-14 14:56:52 +0800
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2026-09-15 15:44:52 -0400
commita0e7cf793a2ae2f3bc7f37a639ab2dc2031dfd80 (patch)
tree47f46a4163f2e805c884dabfea8c0c2b1b5e3a4e
parenta766d91ca1047edf0e8b5ed83b01165ef1a4af23 (diff)
downloadlinux-next-a0e7cf793a2ae2f3bc7f37a639ab2dc2031dfd80.tar.gz
linux-next-a0e7cf793a2ae2f3bc7f37a639ab2dc2031dfd80.zip
Bluetooth: btmtk: Route firmware debug event to the diag channel
MediaTek controllers may emit a firmware debug event on the ACL channel using the reserved handle 0x0efd, which shows up in the ACL header as 0x2efd once the start fragment flag is included. Neither btmtk_usb_recv_acl() nor btmtksdio_recv_acl() recognizes it, so the packet is passed to the HCI core, which has no connection with that handle and complains: Bluetooth: hci0: ACL packet for unknown connection handle 3837 Handle it the same way as the existing firmware debug logging packets and forward it to the diagnostic channel instead. Confirmed with MTK internally that this event's wire format is fixed: firmware always sends it as a single ACL_START packet and never splits it into a continuation (ACL_CONT, which would show up as 0x1efd). Add a comment above the switch spelling that out for this and the other vendor-reserved handles already handled here (0xfc6f, 0x05ff, 0x05fe), so review tooling doesn't keep flagging the apparent lack of a matching continuation case. Verified on MT7922: under the condition that triggers this firmware debug event, it is now routed to the diag channel instead of reaching the host as an unknown ACL packet. Signed-off-by: Chris Lu <chris.lu@mediatek.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-rw-r--r--drivers/bluetooth/btmtk.c8
-rw-r--r--drivers/bluetooth/btmtksdio.c8
2 files changed, 16 insertions, 0 deletions
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 03b99826b52c..115a11fcb254 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -1060,6 +1060,13 @@ int btmtk_usb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb)
struct btmtk_data *data = hci_get_priv(hdev);
u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle);
+ /* The handles below are vendor-reserved values MTK firmware uses to
+ * tag out-of-band debug/dump data on the ACL channel rather than a
+ * real connection. Each is always sent as a single, complete
+ * ACL_START packet, so unlike genuine connection data they never
+ * arrive fragmented (e.g. 0x2efd is never followed by an ACL_CONT
+ * continuation, 0x1efd).
+ */
switch (handle) {
case 0xfc6f: /* Firmware dump from device */
/* When the firmware hangs, the device can no longer
@@ -1081,6 +1088,7 @@ int btmtk_usb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb)
fallthrough;
case 0x05ff: /* Firmware debug logging 1 */
case 0x05fe: /* Firmware debug logging 2 */
+ case 0x2efd: /* Firmware debug event */
return hci_recv_diag(hdev, skb);
}
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index 4d996d18652c..f7bdaebf660d 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -469,6 +469,13 @@ static int btmtksdio_recv_acl(struct hci_dev *hdev, struct sk_buff *skb)
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle);
+ /* The handles below are vendor-reserved values MTK firmware uses to
+ * tag out-of-band debug/dump data on the ACL channel rather than a
+ * real connection. Each is always sent as a single, complete
+ * ACL_START packet, so unlike genuine connection data they never
+ * arrive fragmented (e.g. 0x2efd is never followed by an ACL_CONT
+ * continuation, 0x1efd).
+ */
switch (handle) {
case 0xfc6f:
/* Firmware dump from device: when the firmware hangs, the
@@ -478,6 +485,7 @@ static int btmtksdio_recv_acl(struct hci_dev *hdev, struct sk_buff *skb)
fallthrough;
case 0x05ff:
case 0x05fe:
+ case 0x2efd: /* Firmware debug event */
/* Firmware debug logging */
return hci_recv_diag(hdev, skb);
}