Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 0/4] Bluetooth: Broadcom controllers of the Apple T2 Macs
@ 2026-11-04 15:15 Andre Eikmeyer
  2026-11-04 15:15 ` [PATCH 1/4] Bluetooth: btbcm: raise ACL priority on Apple Broadcom controllers Andre Eikmeyer
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Andre Eikmeyer @ 2026-11-04 15:15 UTC (permalink / raw)
  To: marcel, luiz.dentz
  Cc: linux-bluetooth, linux-kernel, sven, j, neal, asahi,
	linux-arm-kernel, 66ton99, josemiguelo.ochoa, aditya.garg,
	Andre Eikmeyer

Hello everyone,

This series is for the Broadcom Bluetooth controllers of the Apple T2
Macs, the BCM4364 over UART (hci_bcm) and the BCM4377 over PCIe
(hci_bcm4377).

  1    raise ACL priority on Apple Broadcom controllers
  2    clear vendor bits in LE advertising report types
  3    Revert "Bluetooth: hci_event: strip Broadcom vendor bits from
       legacy adv report type"
  4    set the strict duplicate filter quirk on Apple Broadcom controllers

Patch 2 and 3 belong together. Commit 88397423671f ("Bluetooth:
hci_event: strip Broadcom vendor bits from legacy adv report type") in
bluetooth-next masks the event type of legacy LE Advertising Reports for
every controller with manufacturer 15. The controllers known to set these
bits are the ones of the T2 Macs. Aditya Garg asked about this on the
list:

  https://lore.kernel.org/linux-bluetooth/F4853998-F2A8-4AFE-99EA-544657EAB0E8@linux.dev/

Masking the type to its low nibble goes back to a t2linux patch by Jose
Miguel Ochoa. Patch 2 clears the bits in the two drivers of these
controllers before the event reaches the core, and patch 3 reverts the
check in hci_event.c. Patch 2 comes first, so every commit in between
keeps the reports.

Patch 1 builds on a vendor command the Android Broadcom vendor library
uses, 0xfc57, to keep A2DP from dropping out while WLAN runs on 2.4 GHz.
Patch 4 sets the strict duplicate filter quirk in both drivers, so a
discovery reports changed advertisement data before its next cycle.

The KaiT2en community, about 280 members, runs these patches with its
kernels. Users reported them working on the MacBookPro15,1, 15,2, 15,3,
15,4, 16,1, 16,4, MacBookAir9,1 and iMac20,1, and nobody reported a
regression.

Andre Eikmeyer (4):
  Bluetooth: btbcm: raise ACL priority on Apple Broadcom controllers
  Bluetooth: btbcm: clear vendor bits in LE advertising report types
  Revert "Bluetooth: hci_event: strip Broadcom vendor bits from legacy
    adv report type"
  Bluetooth: set the strict duplicate filter quirk on Apple Broadcom
    controllers

 drivers/bluetooth/Kconfig       |   1 +
 drivers/bluetooth/btbcm.c       | 102 ++++++++++++++++++++++++++++++++
 drivers/bluetooth/btbcm.h       |  12 ++++
 drivers/bluetooth/hci_bcm.c     |  28 ++++++++-
 drivers/bluetooth/hci_bcm4377.c |   9 +++
 net/bluetooth/hci_event.c       |  11 ----
 6 files changed, 149 insertions(+), 14 deletions(-)


base-commit: 3f425f95ba3923d605f6a8b382e8fcdc59d479db

^ permalink raw reply	[flat|nested] 14+ messages in thread
* [PATCH v2 1/2] Bluetooth: btbcm: raise ACL priority on Apple Broadcom controllers
@ 2026-11-05  8:57 Andre Eikmeyer
  2026-11-05 17:38 ` Bluetooth: Broadcom controllers of the Apple T2 Macs bluez.test.bot
  0 siblings, 1 reply; 14+ messages in thread
From: Andre Eikmeyer @ 2026-11-05  8:57 UTC (permalink / raw)
  To: marcel, luiz.dentz
  Cc: linux-bluetooth, linux-kernel, sven, j, neal, asahi,
	linux-arm-kernel, Andre Eikmeyer, Yossef Osman, Aditya Garg

On the MacBookPro15,1 (BCM4364B0 over UART) A2DP audio drops out as
soon as WLAN runs on 2.4 GHz with traffic. The host keeps the eight ACL
buffers of the controller filled, but the controller holds single ACL
packets for 160-200 ms, so the sink runs dry.

Sending the Broadcom vendor command 0xfc57 (HCI_BRCM_SET_ACL_PRIORITY,
handle and priority, as used by the Android Broadcom vendor library) with
priority high for the audio link stops the dropouts. Setting it back to
normal brings them back right away. The BCM4377 of the MacBookAir9,1
accepts the command as well.

Raise the priority for every BR/EDR ACL link once its Connection Complete
event arrives. This covers audio as well as HID links. hci_bcm does this
on Apple machines only, hci_bcm4377 always, since it only runs on Apple
machines. The PCIe driver receives events in hard interrupt context, so
the command is queued from a work item.

Tested-by: Yossef Osman <Yossef.Osman@proton.me>
Tested-by: Aditya Garg <aditya.garg@linux.dev>
Signed-off-by: Andre Eikmeyer <dev@deq.rocks>
---
 drivers/bluetooth/Kconfig       |  1 +
 drivers/bluetooth/btbcm.c       | 71 +++++++++++++++++++++++++++++++++
 drivers/bluetooth/btbcm.h       |  7 ++++
 drivers/bluetooth/hci_bcm.c     | 18 ++++++++-
 drivers/bluetooth/hci_bcm4377.c |  3 ++
 5 files changed, 98 insertions(+), 2 deletions(-)

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index b18482b5677..3e2426abdff 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -318,6 +318,7 @@ config BT_HCIBCM4377
 	tristate "HCI BCM4377/4378/4387/4388 PCIe driver"
 	depends on PCI
 	select FW_LOADER
+	select BT_BCM
 	help
 	  Support for Broadcom BCM4377/4378/4387/4388 Bluetooth chipsets
 	  attached via PCIe. These are usually found in Apple machines.
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index 065536d4ec7..60114561593 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -210,6 +210,77 @@ int btbcm_write_pcm_int_params(struct hci_dev *hdev,
 }
 EXPORT_SYMBOL_GPL(btbcm_write_pcm_int_params);
 
+#define BCM_SET_ACL_PRIORITY	0xfc57
+#define BCM_ACL_PRIORITY_HIGH	0x01
+
+struct bcm_set_acl_priority {
+	__le16	handle;
+	u8	priority;
+} __packed;
+
+struct btbcm_acl_priority_work {
+	struct work_struct	work;
+	struct hci_dev		*hdev;
+	u16			handle;
+};
+
+static int btbcm_set_acl_priority_sync(struct hci_dev *hdev, void *data)
+{
+	struct bcm_set_acl_priority cp;
+	int err;
+
+	cp.handle = cpu_to_le16(PTR_UINT(data));
+	cp.priority = BCM_ACL_PRIORITY_HIGH;
+
+	err = __hci_cmd_sync_status(hdev, BCM_SET_ACL_PRIORITY, sizeof(cp),
+				    &cp, HCI_CMD_TIMEOUT);
+	if (err)
+		bt_dev_warn(hdev, "BCM: setting ACL priority for handle 0x%4.4x failed (%d)",
+			    le16_to_cpu(cp.handle), err);
+	return err;
+}
+
+static void btbcm_acl_priority_work(struct work_struct *work)
+{
+	struct btbcm_acl_priority_work *w =
+		container_of(work, struct btbcm_acl_priority_work, work);
+
+	hci_cmd_sync_queue(w->hdev, btbcm_set_acl_priority_sync,
+			   UINT_PTR(w->handle), NULL);
+	hci_dev_put(w->hdev);
+	kfree(w);
+}
+
+/* Give every BR/EDR ACL link high priority in the controller as soon as it
+ * is connected. Without it the BCM4364 coexistence arbitration lets 2.4 GHz
+ * WLAN traffic delay ACL packets by up to 200 ms, which drops A2DP audio.
+ */
+void btbcm_set_acl_priority_on_connect(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_event_hdr *hdr = (void *)skb->data;
+	struct hci_ev_conn_complete *ev;
+	struct btbcm_acl_priority_work *w;
+
+	if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT ||
+	    skb->len < sizeof(*hdr) + sizeof(*ev) ||
+	    hdr->evt != HCI_EV_CONN_COMPLETE)
+		return;
+
+	ev = (void *)(skb->data + sizeof(*hdr));
+	if (ev->status || ev->link_type != ACL_LINK)
+		return;
+
+	w = kzalloc_obj(*w, GFP_ATOMIC);
+	if (!w)
+		return;
+
+	INIT_WORK(&w->work, btbcm_acl_priority_work);
+	w->hdev = hci_dev_hold(hdev);
+	w->handle = __le16_to_cpu(ev->handle);
+	queue_work(system_dfl_wq, &w->work);
+}
+EXPORT_SYMBOL_GPL(btbcm_set_acl_priority_on_connect);
+
 int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw)
 {
 	const struct hci_command_hdr *cmd;
diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h
index b4cb24231a2..a4d47b242e9 100644
--- a/drivers/bluetooth/btbcm.h
+++ b/drivers/bluetooth/btbcm.h
@@ -59,6 +59,8 @@ int btbcm_read_pcm_int_params(struct hci_dev *hdev,
 int btbcm_write_pcm_int_params(struct hci_dev *hdev,
 			       const struct bcm_set_pcm_int_params *params);
 
+void btbcm_set_acl_priority_on_connect(struct hci_dev *hdev, struct sk_buff *skb);
+
 int btbcm_setup_patchram(struct hci_dev *hdev);
 int btbcm_setup_apple(struct hci_dev *hdev);
 
@@ -94,6 +96,11 @@ static inline int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw
 	return -EOPNOTSUPP;
 }
 
+static inline void btbcm_set_acl_priority_on_connect(struct hci_dev *hdev,
+						     struct sk_buff *skb)
+{
+}
+
 static inline int btbcm_setup_patchram(struct hci_dev *hdev)
 {
 	return 0;
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index e70b9f3fd96..cf4f1455cf9 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -147,6 +147,7 @@ struct bcm_device {
 	bool			drive_rts_on_open;
 	bool			no_uart_clock_set;
 	bool			use_autobaud_mode;
+	bool			acl_priority;
 	u8			pcm_int_params[5];
 	u32			max_autobaud_speed;
 };
@@ -680,10 +681,21 @@ static int bcm_setup(struct hci_uart *hu)
 	.lsize = 0, \
 	.maxlen = BCM_TYPE52_SIZE
 
+static int bcm_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_uart *hu = hci_get_drvdata(hdev);
+	struct bcm_data *bcm = hu->priv;
+
+	if (bcm->dev && bcm->dev->acl_priority)
+		btbcm_set_acl_priority_on_connect(hdev, skb);
+
+	return hci_recv_frame(hdev, skb);
+}
+
 static const struct h4_recv_pkt bcm_recv_pkts[] = {
 	{ H4_RECV_ACL,      .recv = hci_recv_frame },
 	{ H4_RECV_SCO,      .recv = hci_recv_frame },
-	{ H4_RECV_EVENT,    .recv = hci_recv_frame },
+	{ H4_RECV_EVENT,    .recv = bcm_recv_event },
 	{ H4_RECV_ISO,      .recv = hci_recv_frame },
 	{ BCM_RECV_LM_DIAG, .recv = hci_recv_diag  },
 	{ BCM_RECV_NULL,    .recv = hci_recv_diag  },
@@ -1086,8 +1098,10 @@ static int bcm_get_resources(struct bcm_device *dev)
 
 	dev->name = dev_name(dev->dev);
 
-	if (x86_apple_machine && !bcm_apple_get_resources(dev))
+	if (x86_apple_machine && !bcm_apple_get_resources(dev)) {
+		dev->acl_priority = true;
 		return 0;
+	}
 
 	dev->txco_clk = bcm_get_txco(dev->dev);
 	if (IS_ERR(dev->txco_clk))
diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c
index 66d49b47154..30fcadfae3f 100644
--- a/drivers/bluetooth/hci_bcm4377.c
+++ b/drivers/bluetooth/hci_bcm4377.c
@@ -22,6 +22,8 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
+#include "btbcm.h"
+
 enum bcm4377_chip {
 	BCM4377 = 0,
 	BCM4378,
@@ -689,6 +691,7 @@ static void bcm4377_handle_event(struct bcm4377_data *bcm4377,
 
 	memcpy(skb_put(skb, len), payload, len);
 	hci_skb_pkt_type(skb) = type;
+	btbcm_set_acl_priority_on_connect(bcm4377->hdev, skb);
 	hci_recv_frame(bcm4377->hdev, skb);
 
 out:

base-commit: 3f425f95ba3923d605f6a8b382e8fcdc59d479db

^ permalink raw reply related	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2026-11-05 17:38 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-04 15:15 [PATCH 0/4] Bluetooth: Broadcom controllers of the Apple T2 Macs Andre Eikmeyer
2026-11-04 15:15 ` [PATCH 1/4] Bluetooth: btbcm: raise ACL priority on Apple Broadcom controllers Andre Eikmeyer
2026-11-04 16:46   ` Bluetooth: Broadcom controllers of the Apple T2 Macs bluez.test.bot
2026-11-05  5:22   ` [PATCH 1/4] Bluetooth: btbcm: raise ACL priority on Apple Broadcom controllers kernel test robot
2026-11-04 15:15 ` [PATCH 2/4] Bluetooth: btbcm: clear vendor bits in LE advertising report types Andre Eikmeyer
2026-11-04 15:24   ` Luiz Augusto von Dentz
2026-11-04 15:34     ` Aditya Garg
2026-11-04 15:46     ` André Eikmeyer
2026-11-04 16:29       ` Luiz Augusto von Dentz
2026-11-04 16:47         ` André Eikmeyer
2026-11-05  9:10   ` kernel test robot
2026-11-04 15:16 ` [PATCH 3/4] Revert "Bluetooth: hci_event: strip Broadcom vendor bits from legacy adv report type" Andre Eikmeyer
2026-11-04 15:16 ` [PATCH 4/4] Bluetooth: set the strict duplicate filter quirk on Apple Broadcom controllers Andre Eikmeyer
  -- strict thread matches above, loose matches on Subject: below --
2026-11-05  8:57 [PATCH v2 1/2] Bluetooth: btbcm: raise ACL priority " Andre Eikmeyer
2026-11-05 17:38 ` Bluetooth: Broadcom controllers of the Apple T2 Macs bluez.test.bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox