From d9da920233ec85af8b9c87154f2721a7dc4623f5 Mon Sep 17 00:00:00 2001 From: Zenm Chen Date: Wed, 21 May 2025 09:30:20 +0800 Subject: [PATCH 01/42] Bluetooth: btusb: Add USB ID 3625:010b for TP-LINK Archer TX10UB Nano Add USB ID 3625:010b for TP-LINK Archer TX10UB Nano which is based on a Realtek RTL8851BU chip. The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below: T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 9 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=3625 ProdID=010b Rev= 0.00 S: Manufacturer=Realtek S: Product=802.11ax WLAN Adapter S: SerialNumber=00e04c000001 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=500mA A: FirstIf#= 0 IfCount= 2 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 8 Cls=ff(vend.) Sub=ff Prot=ff Driver=rtl8851bu E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=07(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=09(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=0a(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=0b(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=0c(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms Cc: stable@vger.kernel.org Signed-off-by: Zenm Chen Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index f9eeec0aed57..ee85fa648c1a 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -516,6 +516,10 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x0bda, 0xb850), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3600), .driver_info = BTUSB_REALTEK }, + /* Realtek 8851BU Bluetooth devices */ + { USB_DEVICE(0x3625, 0x010b), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, + /* Realtek 8852AE Bluetooth devices */ { USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, From 65b0dca6f9f2c912a77a6ad6cf56f60a895a496b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 29 May 2025 18:23:32 +0200 Subject: [PATCH 02/42] Bluetooth: btusb: Add support for variant of RTL8851BE (USB ID 13d3:3601) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Teach the btusb driver to recognize another variant of the RTL8851BE bluetooth radio. /sys/kernel/debug/usb/devices reports for that device: T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3601 Rev= 0.00 S: Manufacturer=Realtek S: Product=Bluetooth Radio S: SerialNumber=00e04c000001 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms Reported-by: shdeb Link: https://bugs.debian.org/1106386 Signed-off-by: Uwe Kleine-König Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ee85fa648c1a..0eb2de670d8d 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -515,6 +515,7 @@ static const struct usb_device_id quirks_table[] = { /* Realtek 8851BE Bluetooth devices */ { USB_DEVICE(0x0bda, 0xb850), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3600), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3601), .driver_info = BTUSB_REALTEK }, /* Realtek 8851BU Bluetooth devices */ { USB_DEVICE(0x3625, 0x010b), .driver_info = BTUSB_REALTEK | From 256ab9520d15c772e39620cc0ef6310091406c67 Mon Sep 17 00:00:00 2001 From: Chandrashekar Devegowda Date: Tue, 10 Jun 2025 19:30:38 +0530 Subject: [PATCH 03/42] Bluetooth: btintel_pcie: Support Function level reset The driver supports Function Level Reset (FLR) to recover the controller upon hardware exceptions or hci command timeouts. FLR is triggered only when no prior reset has occurred within the retry window, with a maximum of one FLR allowed within this window. This patch is tested by, echo 1 > /sys/class/bluetooth/hciX/reset Signed-off-by: Chandrashekar Devegowda Signed-off-by: Kiran K Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 226 ++++++++++++++++++++++++++++++- drivers/bluetooth/btintel_pcie.h | 4 +- 2 files changed, 227 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index f4e3fb54fe76..628b3ea7f6f6 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -41,6 +41,13 @@ static const struct pci_device_id btintel_pcie_table[] = { }; MODULE_DEVICE_TABLE(pci, btintel_pcie_table); +struct btintel_pcie_dev_restart_data { + struct list_head list; + u8 restart_count; + time64_t last_error; + char name[]; +}; + /* Intel PCIe uses 4 bytes of HCI type instead of 1 byte BT SIG HCI type */ #define BTINTEL_PCIE_HCI_TYPE_LEN 4 #define BTINTEL_PCIE_HCI_CMD_PKT 0x00000001 @@ -62,6 +69,9 @@ MODULE_DEVICE_TABLE(pci, btintel_pcie_table); #define BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER 0x17A2 #define BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT 0x1E61 +#define BTINTEL_PCIE_RESET_WINDOW_SECS 5 +#define BTINTEL_PCIE_FLR_MAX_RETRY 1 + /* Alive interrupt context */ enum { BTINTEL_PCIE_ROM, @@ -99,6 +109,14 @@ struct btintel_pcie_dbgc_ctxt { struct btintel_pcie_dbgc_ctxt_buf bufs[BTINTEL_PCIE_DBGC_BUFFER_COUNT]; }; +struct btintel_pcie_removal { + struct pci_dev *pdev; + struct work_struct work; +}; + +static LIST_HEAD(btintel_pcie_restart_data_list); +static DEFINE_SPINLOCK(btintel_pcie_restart_data_lock); + /* This function initializes the memory for DBGC buffers and formats the * DBGC fragment which consists header info and DBGC buffer's LSB, MSB and * size as the payload @@ -1932,6 +1950,9 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, u32 type; u32 old_ctxt; + if (test_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags)) + return -ENODEV; + /* Due to the fw limitation, the type header of the packet should be * 4 bytes unlike 1 byte for UART. In UART, the firmware can read * the first byte to get the packet type and redirect the rest of data @@ -2192,9 +2213,196 @@ static int btintel_pcie_setup(struct hci_dev *hdev) } btintel_pcie_start_rx(data); } + + if (!err) + set_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags); return err; } +static struct btintel_pcie_dev_restart_data *btintel_pcie_get_restart_data(struct pci_dev *pdev, + struct device *dev) +{ + struct btintel_pcie_dev_restart_data *tmp, *data = NULL; + const char *name = pci_name(pdev); + struct hci_dev *hdev = to_hci_dev(dev); + + spin_lock(&btintel_pcie_restart_data_lock); + list_for_each_entry(tmp, &btintel_pcie_restart_data_list, list) { + if (strcmp(tmp->name, name)) + continue; + data = tmp; + break; + } + spin_unlock(&btintel_pcie_restart_data_lock); + + if (data) { + bt_dev_dbg(hdev, "Found restart data for BDF: %s", data->name); + return data; + } + + data = kzalloc(struct_size(data, name, strlen(name) + 1), GFP_ATOMIC); + if (!data) + return NULL; + + strscpy_pad(data->name, name, strlen(name) + 1); + spin_lock(&btintel_pcie_restart_data_lock); + list_add_tail(&data->list, &btintel_pcie_restart_data_list); + spin_unlock(&btintel_pcie_restart_data_lock); + + return data; +} + +static void btintel_pcie_free_restart_list(void) +{ + struct btintel_pcie_dev_restart_data *tmp; + + while ((tmp = list_first_entry_or_null(&btintel_pcie_restart_data_list, + typeof(*tmp), list))) { + list_del(&tmp->list); + kfree(tmp); + } +} + +static void btintel_pcie_inc_restart_count(struct pci_dev *pdev, + struct device *dev) +{ + struct btintel_pcie_dev_restart_data *data; + struct hci_dev *hdev = to_hci_dev(dev); + time64_t retry_window; + + data = btintel_pcie_get_restart_data(pdev, dev); + if (!data) + return; + + retry_window = ktime_get_boottime_seconds() - data->last_error; + if (data->restart_count == 0) { + data->last_error = ktime_get_boottime_seconds(); + data->restart_count++; + bt_dev_dbg(hdev, "First iteration initialise. last_error: %lld seconds restart_count: %d", + data->last_error, data->restart_count); + } else if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS && + data->restart_count <= BTINTEL_PCIE_FLR_MAX_RETRY) { + data->restart_count++; + bt_dev_dbg(hdev, "Flr triggered within the max retry time so increment the restart_count: %d", + data->restart_count); + } else if (retry_window > BTINTEL_PCIE_RESET_WINDOW_SECS) { + data->last_error = 0; + data->restart_count = 0; + bt_dev_dbg(hdev, "Flr triggered out of the retry window, so reset counters"); + } +} + +static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data); + +static void btintel_pcie_removal_work(struct work_struct *wk) +{ + struct btintel_pcie_removal *removal = + container_of(wk, struct btintel_pcie_removal, work); + struct pci_dev *pdev = removal->pdev; + struct btintel_pcie_data *data; + int err; + + pci_lock_rescan_remove(); + + if (!pdev->bus) + goto error; + + data = pci_get_drvdata(pdev); + + btintel_pcie_disable_interrupts(data); + btintel_pcie_synchronize_irqs(data); + + flush_work(&data->rx_work); + flush_work(&data->hdev->dump.dump_rx); + + bt_dev_dbg(data->hdev, "Release bluetooth interface"); + btintel_pcie_release_hdev(data); + + err = pci_reset_function(pdev); + if (err) { + BT_ERR("Failed resetting the pcie device (%d)", err); + goto error; + } + + btintel_pcie_enable_interrupts(data); + btintel_pcie_config_msix(data); + + err = btintel_pcie_enable_bt(data); + if (err) { + BT_ERR("Failed to enable bluetooth hardware after reset (%d)", + err); + goto error; + } + + btintel_pcie_reset_ia(data); + btintel_pcie_start_rx(data); + data->flags = 0; + + err = btintel_pcie_setup_hdev(data); + if (err) { + BT_ERR("Failed registering hdev (%d)", err); + goto error; + } +error: + pci_dev_put(pdev); + pci_unlock_rescan_remove(); + kfree(removal); +} + +static void btintel_pcie_reset(struct hci_dev *hdev) +{ + struct btintel_pcie_removal *removal; + struct btintel_pcie_data *data; + + data = hci_get_drvdata(hdev); + + if (!test_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags)) + return; + + if (test_and_set_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags)) + return; + + removal = kzalloc(sizeof(*removal), GFP_ATOMIC); + if (!removal) + return; + + removal->pdev = data->pdev; + INIT_WORK(&removal->work, btintel_pcie_removal_work); + pci_dev_get(removal->pdev); + schedule_work(&removal->work); +} + +static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code) +{ + struct btintel_pcie_dev_restart_data *data; + struct btintel_pcie_data *dev_data = hci_get_drvdata(hdev); + struct pci_dev *pdev = dev_data->pdev; + time64_t retry_window; + + if (code == 0x13) { + bt_dev_err(hdev, "Encountered top exception"); + return; + } + + data = btintel_pcie_get_restart_data(pdev, &hdev->dev); + if (!data) + return; + + retry_window = ktime_get_boottime_seconds() - data->last_error; + + if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS && + data->restart_count >= BTINTEL_PCIE_FLR_MAX_RETRY) { + bt_dev_err(hdev, "Exhausted maximum: %d recovery attempts: %d", + BTINTEL_PCIE_FLR_MAX_RETRY, data->restart_count); + bt_dev_dbg(hdev, "Boot time: %lld seconds first_flr at: %lld seconds restart_count: %d", + ktime_get_boottime_seconds(), data->last_error, + data->restart_count); + return; + } + btintel_pcie_inc_restart_count(pdev, &hdev->dev); + btintel_pcie_reset(hdev); +} + static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) { int err; @@ -2216,9 +2424,10 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) hdev->send = btintel_pcie_send_frame; hdev->setup = btintel_pcie_setup; hdev->shutdown = btintel_shutdown_combined; - hdev->hw_error = btintel_hw_error; + hdev->hw_error = btintel_pcie_hw_error; hdev->set_diag = btintel_set_diag; hdev->set_bdaddr = btintel_set_bdaddr; + hdev->reset = btintel_pcie_reset; err = hci_register_dev(hdev); if (err < 0) { @@ -2366,7 +2575,20 @@ static struct pci_driver btintel_pcie_driver = { .driver.coredump = btintel_pcie_coredump #endif }; -module_pci_driver(btintel_pcie_driver); + +static int __init btintel_pcie_init(void) +{ + return pci_register_driver(&btintel_pcie_driver); +} + +static void __exit btintel_pcie_exit(void) +{ + pci_unregister_driver(&btintel_pcie_driver); + btintel_pcie_free_restart_list(); +} + +module_init(btintel_pcie_init); +module_exit(btintel_pcie_exit); MODULE_AUTHOR("Tedd Ho-Jeong An "); MODULE_DESCRIPTION("Intel Bluetooth PCIe transport driver ver " VERSION); diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index 7dad4523236c..0fa876c5b954 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -117,7 +117,9 @@ enum { enum { BTINTEL_PCIE_CORE_HALTED, BTINTEL_PCIE_HWEXP_INPROGRESS, - BTINTEL_PCIE_COREDUMP_INPROGRESS + BTINTEL_PCIE_COREDUMP_INPROGRESS, + BTINTEL_PCIE_RECOVERY_IN_PROGRESS, + BTINTEL_PCIE_SETUP_DONE }; enum btintel_pcie_tlv_type { From 171fccce45e34b1552254c9b38454ec8b46886f1 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 10 Jun 2025 15:46:23 -0400 Subject: [PATCH 04/42] Bluetooth: btintel_pcie: Reword restart to recovery This rewords the term restart with recovery since the intend is for hardware recovery not a regular restart, also remove some debug logs which might just clutter the output informing the recovery counter which isn't really useful for regular users. Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 71 +++++++++++++++----------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 628b3ea7f6f6..565d04e0afc6 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -41,9 +41,9 @@ static const struct pci_device_id btintel_pcie_table[] = { }; MODULE_DEVICE_TABLE(pci, btintel_pcie_table); -struct btintel_pcie_dev_restart_data { +struct btintel_pcie_dev_recovery { struct list_head list; - u8 restart_count; + u8 count; time64_t last_error; char name[]; }; @@ -114,8 +114,8 @@ struct btintel_pcie_removal { struct work_struct work; }; -static LIST_HEAD(btintel_pcie_restart_data_list); -static DEFINE_SPINLOCK(btintel_pcie_restart_data_lock); +static LIST_HEAD(btintel_pcie_recovery_list); +static DEFINE_SPINLOCK(btintel_pcie_recovery_lock); /* This function initializes the memory for DBGC buffers and formats the * DBGC fragment which consists header info and DBGC buffer's LSB, MSB and @@ -2219,21 +2219,21 @@ static int btintel_pcie_setup(struct hci_dev *hdev) return err; } -static struct btintel_pcie_dev_restart_data *btintel_pcie_get_restart_data(struct pci_dev *pdev, - struct device *dev) +static struct btintel_pcie_dev_recovery * +btintel_pcie_get_recovery(struct pci_dev *pdev, struct device *dev) { - struct btintel_pcie_dev_restart_data *tmp, *data = NULL; + struct btintel_pcie_dev_recovery *tmp, *data = NULL; const char *name = pci_name(pdev); struct hci_dev *hdev = to_hci_dev(dev); - spin_lock(&btintel_pcie_restart_data_lock); - list_for_each_entry(tmp, &btintel_pcie_restart_data_list, list) { + spin_lock(&btintel_pcie_recovery_lock); + list_for_each_entry(tmp, &btintel_pcie_recovery_list, list) { if (strcmp(tmp->name, name)) continue; data = tmp; break; } - spin_unlock(&btintel_pcie_restart_data_lock); + spin_unlock(&btintel_pcie_recovery_lock); if (data) { bt_dev_dbg(hdev, "Found restart data for BDF: %s", data->name); @@ -2245,50 +2245,44 @@ static struct btintel_pcie_dev_restart_data *btintel_pcie_get_restart_data(struc return NULL; strscpy_pad(data->name, name, strlen(name) + 1); - spin_lock(&btintel_pcie_restart_data_lock); - list_add_tail(&data->list, &btintel_pcie_restart_data_list); - spin_unlock(&btintel_pcie_restart_data_lock); + spin_lock(&btintel_pcie_recovery_lock); + list_add_tail(&data->list, &btintel_pcie_recovery_list); + spin_unlock(&btintel_pcie_recovery_lock); return data; } static void btintel_pcie_free_restart_list(void) { - struct btintel_pcie_dev_restart_data *tmp; + struct btintel_pcie_dev_recovery *tmp; - while ((tmp = list_first_entry_or_null(&btintel_pcie_restart_data_list, + while ((tmp = list_first_entry_or_null(&btintel_pcie_recovery_list, typeof(*tmp), list))) { list_del(&tmp->list); kfree(tmp); } } -static void btintel_pcie_inc_restart_count(struct pci_dev *pdev, - struct device *dev) +static void btintel_pcie_inc_recovery_count(struct pci_dev *pdev, + struct device *dev) { - struct btintel_pcie_dev_restart_data *data; - struct hci_dev *hdev = to_hci_dev(dev); + struct btintel_pcie_dev_recovery *data; time64_t retry_window; - data = btintel_pcie_get_restart_data(pdev, dev); + data = btintel_pcie_get_recovery(pdev, dev); if (!data) return; retry_window = ktime_get_boottime_seconds() - data->last_error; - if (data->restart_count == 0) { + if (data->count == 0) { data->last_error = ktime_get_boottime_seconds(); - data->restart_count++; - bt_dev_dbg(hdev, "First iteration initialise. last_error: %lld seconds restart_count: %d", - data->last_error, data->restart_count); + data->count++; } else if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS && - data->restart_count <= BTINTEL_PCIE_FLR_MAX_RETRY) { - data->restart_count++; - bt_dev_dbg(hdev, "Flr triggered within the max retry time so increment the restart_count: %d", - data->restart_count); + data->count <= BTINTEL_PCIE_FLR_MAX_RETRY) { + data->count++; } else if (retry_window > BTINTEL_PCIE_RESET_WINDOW_SECS) { data->last_error = 0; - data->restart_count = 0; - bt_dev_dbg(hdev, "Flr triggered out of the retry window, so reset counters"); + data->count = 0; } } @@ -2374,7 +2368,7 @@ static void btintel_pcie_reset(struct hci_dev *hdev) static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code) { - struct btintel_pcie_dev_restart_data *data; + struct btintel_pcie_dev_recovery *data; struct btintel_pcie_data *dev_data = hci_get_drvdata(hdev); struct pci_dev *pdev = dev_data->pdev; time64_t retry_window; @@ -2384,22 +2378,23 @@ static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code) return; } - data = btintel_pcie_get_restart_data(pdev, &hdev->dev); + data = btintel_pcie_get_recovery(pdev, &hdev->dev); if (!data) return; retry_window = ktime_get_boottime_seconds() - data->last_error; if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS && - data->restart_count >= BTINTEL_PCIE_FLR_MAX_RETRY) { + data->count >= BTINTEL_PCIE_FLR_MAX_RETRY) { bt_dev_err(hdev, "Exhausted maximum: %d recovery attempts: %d", - BTINTEL_PCIE_FLR_MAX_RETRY, data->restart_count); - bt_dev_dbg(hdev, "Boot time: %lld seconds first_flr at: %lld seconds restart_count: %d", - ktime_get_boottime_seconds(), data->last_error, - data->restart_count); + BTINTEL_PCIE_FLR_MAX_RETRY, data->count); + bt_dev_dbg(hdev, "Boot time: %lld seconds", + ktime_get_boottime_seconds()); + bt_dev_dbg(hdev, "last error at: %lld seconds", + data->last_error); return; } - btintel_pcie_inc_restart_count(pdev, &hdev->dev); + btintel_pcie_inc_recovery_count(pdev, &hdev->dev); btintel_pcie_reset(hdev); } From 7ed1d46c6bc2848469f8b0cefc43eef2c5d23536 Mon Sep 17 00:00:00 2001 From: Haochen Tong Date: Fri, 6 Jun 2025 23:33:03 +0800 Subject: [PATCH 05/42] Bluetooth: btusb: Add a new VID/PID 2c7c/7009 for MT7925 Adds a new entry with VID 2c7c and PID 7009 for MediaTek MT7925 Bluetooth chip. The device information from /sys/kernel/debug/usb/devices is provided below. T: Bus=03 Lev=01 Prnt=01 Port=04 Cnt=02 Dev#= 3 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=2c7c ProdID=7009 Rev= 1.00 S: Manufacturer=MediaTek Inc. S: Product=Wireless_Device S: SerialNumber=000000000 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us Signed-off-by: Haochen Tong Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 0eb2de670d8d..b04a4ad64e3b 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -730,6 +730,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3630), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x2c7c, 0x7009), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, /* Additional Realtek 8723AE Bluetooth devices */ { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK }, From 70c672f933337fc1de2df8628567ee0a8146562b Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Fri, 20 Jun 2025 15:03:45 +0800 Subject: [PATCH 06/42] Bluetooth: Remove hci_conn_hash_lookup_state() Since commit 4aa42119d971 ("Bluetooth: Remove pending ACL connection attempts") this function is unused. Signed-off-by: Yue Haibing Reviewed-by: Simon Horman Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f79f59e67114..69f491399dac 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1420,26 +1420,6 @@ hci_conn_hash_lookup_pa_sync_handle(struct hci_dev *hdev, __u16 sync_handle) return NULL; } -static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, - __u8 type, __u16 state) -{ - struct hci_conn_hash *h = &hdev->conn_hash; - struct hci_conn *c; - - rcu_read_lock(); - - list_for_each_entry_rcu(c, &h->list, list) { - if (c->type == type && c->state == state) { - rcu_read_unlock(); - return c; - } - } - - rcu_read_unlock(); - - return NULL; -} - typedef void (*hci_conn_func_t)(struct hci_conn *conn, void *data); static inline void hci_conn_hash_list_state(struct hci_dev *hdev, hci_conn_func_t func, __u8 type, From 6053b532d345b551a5d4b87fb721a0bc51393858 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Sat, 21 Jun 2025 12:16:31 +0530 Subject: [PATCH 07/42] Bluetooth: btintel_pcie: Add support for device 0x4d76 lspci -v -k -d 8086:4d76 00:14.7 Bluetooth: Intel Corporation Device 4d76 Subsystem: Intel Corporation Device 0011 Flags: fast devsel, IRQ 255, IOMMU group 12 Memory at 13013328000 (64-bit, non-prefetchable) [disabled] [size=16K] Capabilities: [c8] Power Management version 3 Capabilities: [d0] MSI: Enable- Count=1/1 Maskable- 64bit+ Capabilities: [40] Express Root Complex Integrated Endpoint, MSI 00 Capabilities: [80] MSI-X: Enable- Count=32 Masked- Capabilities: [100] Latency Tolerance Reporting Kernel driver in use: btintel_pcie Kernel modules: btintel_pcie Signed-off-by: Kiran K Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 565d04e0afc6..ce59a98f1b6a 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -35,6 +35,7 @@ /* Intel Bluetooth PCIe device id table */ static const struct pci_device_id btintel_pcie_table[] = { + { BTINTEL_PCI_DEVICE(0x4D76, PCI_ANY_ID) }, { BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) }, { BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) }, { 0 } From b47c97f2ed9434ccff4efb0b08e3cc0a6c4e08c8 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 23 Jun 2025 19:23:48 +0800 Subject: [PATCH 08/42] Bluetooth: hci_qca: Enable ISO data packet RX Enable ISO data packet RX for LE audio. Signed-off-by: Zijun Hu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_qca.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 33c43503714b..4cff4d9be313 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1264,6 +1264,7 @@ static const struct h4_recv_pkt qca_recv_pkts[] = { { H4_RECV_ACL, .recv = qca_recv_acl_data }, { H4_RECV_SCO, .recv = hci_recv_frame }, { H4_RECV_EVENT, .recv = qca_recv_event }, + { H4_RECV_ISO, .recv = hci_recv_frame }, { QCA_IBS_WAKE_IND_EVENT, .recv = qca_ibs_wake_ind }, { QCA_IBS_WAKE_ACK_EVENT, .recv = qca_ibs_wake_ack }, { QCA_IBS_SLEEP_IND_EVENT, .recv = qca_ibs_sleep_ind }, From 4d7936e8a5b1fa803f4a631d2da4a80fa4f0f37f Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 23 Jun 2025 20:31:16 +0800 Subject: [PATCH 09/42] Bluetooth: hci_sock: Reset cookie to zero in hci_sock_free_cookie() Reset cookie value to 0 instead of 0xffffffff in hci_sock_free_cookie() since: 0 : means cookie has not been assigned yet 0xffffffff: means cookie assignment failure Also fix generating cookie failure with usage shown below: hci_sock_gen_cookie(sk) // generate cookie hci_sock_free_cookie(sk) // free cookie hci_sock_gen_cookie(sk) // Can't generate cookie any more Signed-off-by: Zijun Hu Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 428ee5c7de7e..fc866759910d 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -118,7 +118,7 @@ static void hci_sock_free_cookie(struct sock *sk) int id = hci_pi(sk)->cookie; if (id) { - hci_pi(sk)->cookie = 0xffffffff; + hci_pi(sk)->cookie = 0; ida_free(&sock_cookie_ida, id); } } From da0186f19a7433d3d5607b0f61e9a3de17d1f721 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 23 Jun 2025 20:31:17 +0800 Subject: [PATCH 10/42] Bluetooth: hci_sync: Use bt_dev_err() to log error message in hci_update_event_filter_sync() Use bt_dev_err() instead of bt_dev_dbg() to log error message in hci_update_event_filter_sync(). Signed-off-by: Zijun Hu Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 7938c004071c..956aea977f2a 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -6116,7 +6116,7 @@ static int hci_update_event_filter_sync(struct hci_dev *hdev) &b->bdaddr, HCI_CONN_SETUP_AUTO_ON); if (err) - bt_dev_dbg(hdev, "Failed to set event filter for %pMR", + bt_dev_err(hdev, "Failed to set event filter for %pMR", &b->bdaddr); else scan = SCAN_PAGE; From 88d6ba89d86404073dc3cb711203c02b0754b166 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 23 Jun 2025 20:31:18 +0800 Subject: [PATCH 11/42] Bluetooth: hci_core: Eliminate an unnecessary goto label in hci_find_irk_by_addr() Eliminate an unnecessary goto label by using break instead of goto to exit the loop in hci_find_irk_by_addr(). Signed-off-by: Zijun Hu Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 441cb1700f99..f2fbe9c8e1be 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1256,12 +1256,10 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, if (addr_type == irk->addr_type && bacmp(bdaddr, &irk->bdaddr) == 0) { irk_to_return = irk; - goto done; + break; } } -done: - if (irk_to_return && hci_is_blocked_key(hdev, HCI_BLOCKED_KEY_TYPE_IRK, irk_to_return->val)) { bt_dev_warn_ratelimited(hdev, "Identity key blocked for %pMR", From e44328c99be4fb2f6bcd6da42a9b9fa52c14bb05 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 23 Jun 2025 20:31:19 +0800 Subject: [PATCH 12/42] Bluetooth: hci_event: Correct comment about HCI_EV_EXTENDED_INQUIRY_RESULT HCI_EV_EXTENDED_INQUIRY_RESULT's comment wrongly uses 0x2d as its event code. Use right 0x2f instead. Signed-off-by: Zijun Hu Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index cf4b30ac9e0e..f668bde007d4 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -7399,7 +7399,7 @@ static const struct hci_ev { /* [0x2c = HCI_EV_SYNC_CONN_COMPLETE] */ HCI_EV(HCI_EV_SYNC_CONN_COMPLETE, hci_sync_conn_complete_evt, sizeof(struct hci_ev_sync_conn_complete)), - /* [0x2d = HCI_EV_EXTENDED_INQUIRY_RESULT] */ + /* [0x2f = HCI_EV_EXTENDED_INQUIRY_RESULT] */ HCI_EV_VL(HCI_EV_EXTENDED_INQUIRY_RESULT, hci_extended_inquiry_result_evt, sizeof(struct hci_ev_ext_inquiry_result), HCI_MAX_EVENT_SIZE), From 4112e29a33d98afe107e62d94c884514ffbcb21b Mon Sep 17 00:00:00 2001 From: Neeraj Sanjay Kale Date: Mon, 23 Jun 2025 14:43:21 +0530 Subject: [PATCH 13/42] dt-bindings: net: bluetooth: nxp: Add support for 4M baudrate Add support for 4000000 as secondary baudrate for NXP chipsets supporting max baudrate as 4M, and are close to the host processor on same PCB. This mainly helps with faster FW download. Signed-off-by: Neeraj Sanjay Kale Reviewed-by: Krzysztof Kozlowski Signed-off-by: Luiz Augusto von Dentz --- .../devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml index 3ab60c70286f..bb9ab5dd3b4a 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml @@ -34,6 +34,13 @@ properties: This property depends on the module vendor's configuration. + max-speed: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 3000000 + - 4000000 + default: 3000000 + firmware-name: maxItems: 1 @@ -78,6 +85,7 @@ examples: bluetooth { compatible = "nxp,88w8987-bt"; fw-init-baudrate = <3000000>; + max-speed = <4000000>; firmware-name = "uartuart8987_bt_v0.bin"; device-wakeup-gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; nxp,wakein-pin = /bits/ 8 <18>; From 45b54f007dc36f14e90a4b8a207964a672d1d151 Mon Sep 17 00:00:00 2001 From: Neeraj Sanjay Kale Date: Mon, 23 Jun 2025 14:43:22 +0530 Subject: [PATCH 14/42] Bluetooth: btnxpuart: Add support for 4M baudrate This adds support for 4000000 as secondary baudrate. This value is selected from device tree property "max-speed" which is then used to download FW chunks, and as operational baudrate after HCI initialization is done. Earlier, the secondary baudrate was fixed to 3000000 in driver, but now with "max-speed" property, this secondary baudrate can be set to 4000000. The secondary baudrate is set by the driver by sending a vendor command (3F 09) to the firmware, with secondary baudrate parameter, in nxp_post_init(). Any other value set for max-speed other than 3000000 or 4000000 will default to 3000000, which is supported by all legacy and new NXP chipsets. This feature is applicable for all new V3 bootloader chips and w8987 V1 bootloader chip. This property does not apply for w8997 compatible device, since it downloads a helper.bin FW file that sets secondary baudrate as 3000000 only. The switch to 4000000 baudrate is validated using a Saleae Logic Analyzer and imx8m-mini with AW693 M.2 module. Signed-off-by: Neeraj Sanjay Kale Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btnxpuart.c | 36 ++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 24f9b52605a1..7c6592bf773c 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -73,7 +73,8 @@ #define FW_AUTH_ENC 0xc0 #define HCI_NXP_PRI_BAUDRATE 115200 -#define HCI_NXP_SEC_BAUDRATE 3000000 +#define HCI_NXP_SEC_BAUDRATE_3M 3000000 +#define HCI_NXP_SEC_BAUDRATE_4M 4000000 #define MAX_FW_FILE_NAME_LEN 50 @@ -201,6 +202,7 @@ struct btnxpuart_dev { u32 new_baudrate; u32 current_baudrate; u32 fw_init_baudrate; + u32 secondary_baudrate; enum bootloader_param_change timeout_changed; enum bootloader_param_change baudrate_changed; bool helper_downloaded; @@ -802,7 +804,10 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len) nxpdev->fw_v3_offset_correction += req_len; } else if (req_len == sizeof(uart_config)) { uart_config.clkdiv.address = __cpu_to_le32(clkdivaddr); - uart_config.clkdiv.value = __cpu_to_le32(0x00c00000); + if (nxpdev->new_baudrate == HCI_NXP_SEC_BAUDRATE_4M) + uart_config.clkdiv.value = __cpu_to_le32(0x01000000); + else + uart_config.clkdiv.value = __cpu_to_le32(0x00c00000); uart_config.uartdiv.address = __cpu_to_le32(uartdivaddr); uart_config.uartdiv.value = __cpu_to_le32(1); uart_config.mcr.address = __cpu_to_le32(uartmcraddr); @@ -966,12 +971,13 @@ static int nxp_recv_fw_req_v1(struct hci_dev *hdev, struct sk_buff *skb) goto free_skb; } if (nxpdev->baudrate_changed != changed) { + nxpdev->new_baudrate = nxpdev->secondary_baudrate; if (nxp_fw_change_baudrate(hdev, len)) { nxpdev->baudrate_changed = changed; serdev_device_set_baudrate(nxpdev->serdev, - HCI_NXP_SEC_BAUDRATE); + nxpdev->secondary_baudrate); serdev_device_set_flow_control(nxpdev->serdev, true); - nxpdev->current_baudrate = HCI_NXP_SEC_BAUDRATE; + nxpdev->current_baudrate = nxpdev->secondary_baudrate; } goto free_skb; } @@ -992,7 +998,7 @@ static int nxp_recv_fw_req_v1(struct hci_dev *hdev, struct sk_buff *skb) nxpdev->helper_downloaded = true; serdev_device_wait_until_sent(nxpdev->serdev, 0); serdev_device_set_baudrate(nxpdev->serdev, - HCI_NXP_SEC_BAUDRATE); + HCI_NXP_SEC_BAUDRATE_3M); serdev_device_set_flow_control(nxpdev->serdev, true); } else { clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); @@ -1216,12 +1222,13 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb) } if (nxpdev->baudrate_changed != changed) { + nxpdev->new_baudrate = nxpdev->secondary_baudrate; if (nxp_fw_change_baudrate(hdev, len)) { nxpdev->baudrate_changed = cmd_sent; serdev_device_set_baudrate(nxpdev->serdev, - HCI_NXP_SEC_BAUDRATE); + nxpdev->secondary_baudrate); serdev_device_set_flow_control(nxpdev->serdev, true); - nxpdev->current_baudrate = HCI_NXP_SEC_BAUDRATE; + nxpdev->current_baudrate = nxpdev->secondary_baudrate; } goto free_skb; } @@ -1447,8 +1454,8 @@ static int nxp_post_init(struct hci_dev *hdev) struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); struct ps_data *psdata = &nxpdev->psdata; - if (nxpdev->current_baudrate != HCI_NXP_SEC_BAUDRATE) { - nxpdev->new_baudrate = HCI_NXP_SEC_BAUDRATE; + if (nxpdev->current_baudrate != nxpdev->secondary_baudrate) { + nxpdev->new_baudrate = nxpdev->secondary_baudrate; nxp_set_baudrate_cmd(hdev, NULL); } if (psdata->cur_h2c_wakeupmode != psdata->h2c_wakeupmode) @@ -1773,6 +1780,17 @@ static int nxp_serdev_probe(struct serdev_device *serdev) if (!nxpdev->fw_init_baudrate) nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE; + device_property_read_u32(&nxpdev->serdev->dev, "max-speed", + &nxpdev->secondary_baudrate); + if (!nxpdev->secondary_baudrate || + (nxpdev->secondary_baudrate != HCI_NXP_SEC_BAUDRATE_3M && + nxpdev->secondary_baudrate != HCI_NXP_SEC_BAUDRATE_4M)) { + if (nxpdev->secondary_baudrate) + dev_err(&serdev->dev, + "Invalid max-speed. Using default 3000000."); + nxpdev->secondary_baudrate = HCI_NXP_SEC_BAUDRATE_3M; + } + set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); crc8_populate_msb(crc8_table, POLYNOMIAL8); From b2a5f2e1c127cb431df22e114998ff72eb4578c8 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Tue, 1 Jul 2025 15:56:22 +0800 Subject: [PATCH 15/42] Bluetooth: hci_event: Add support for handling LE BIG Sync Lost event When the BIS source stops, the controller sends an LE BIG Sync Lost event (subevent 0x1E). Currently, this event is not handled, causing the BIS stream to remain active in BlueZ and preventing recovery. Signed-off-by: Yang Li Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci.h | 6 +++++ include/net/bluetooth/hci_core.h | 5 ++-- net/bluetooth/hci_conn.c | 3 ++- net/bluetooth/hci_event.c | 39 +++++++++++++++++++++++++++++++- 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index c79901f2dc2a..6213012610d7 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -2851,6 +2851,12 @@ struct hci_evt_le_big_sync_estabilished { __le16 bis[]; } __packed; +#define HCI_EVT_LE_BIG_SYNC_LOST 0x1e +struct hci_evt_le_big_sync_lost { + __u8 handle; + __u8 reason; +} __packed; + #define HCI_EVT_LE_BIG_INFO_ADV_REPORT 0x22 struct hci_evt_le_big_info_adv_report { __le16 sync_handle; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 69f491399dac..1ef9279cfd6f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1346,7 +1346,8 @@ hci_conn_hash_lookup_big_sync_pend(struct hci_dev *hdev, } static inline struct hci_conn * -hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state) +hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state, + __u8 role) { struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn *c; @@ -1354,7 +1355,7 @@ hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state) rcu_read_lock(); list_for_each_entry_rcu(c, &h->list, list) { - if (c->type != BIS_LINK || c->state != state) + if (c->type != BIS_LINK || c->state != state || c->role != role) continue; if (handle == c->iso_qos.bcast.big) { diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 4f379184df5b..f5cd935490ad 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -2146,7 +2146,8 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, struct hci_link *link; /* Look for any BIS that is open for rebinding */ - conn = hci_conn_hash_lookup_big_state(hdev, qos->bcast.big, BT_OPEN); + conn = hci_conn_hash_lookup_big_state(hdev, qos->bcast.big, BT_OPEN, + HCI_ROLE_MASTER); if (conn) { memcpy(qos, &conn->iso_qos, sizeof(*qos)); conn->state = BT_CONNECTED; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f668bde007d4..fca58984ee4e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -6876,7 +6876,8 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, /* Connect all BISes that are bound to the BIG */ while ((conn = hci_conn_hash_lookup_big_state(hdev, ev->handle, - BT_BOUND))) { + BT_BOUND, + HCI_ROLE_MASTER))) { if (ev->status) { hci_connect_cfm(conn, ev->status); hci_conn_del(conn); @@ -6992,6 +6993,37 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, hci_dev_unlock(hdev); } +static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data, + struct sk_buff *skb) +{ + struct hci_evt_le_big_sync_lost *ev = data; + struct hci_conn *bis, *conn; + + bt_dev_dbg(hdev, "big handle 0x%2.2x", ev->handle); + + hci_dev_lock(hdev); + + /* Delete the pa sync connection */ + bis = hci_conn_hash_lookup_pa_sync_big_handle(hdev, ev->handle); + if (bis) { + conn = hci_conn_hash_lookup_pa_sync_handle(hdev, + bis->sync_handle); + if (conn) + hci_conn_del(conn); + } + + /* Delete each bis connection */ + while ((bis = hci_conn_hash_lookup_big_state(hdev, ev->handle, + BT_CONNECTED, + HCI_ROLE_SLAVE))) { + clear_bit(HCI_CONN_BIG_SYNC, &bis->flags); + hci_disconn_cfm(bis, ev->reason); + hci_conn_del(bis); + } + + hci_dev_unlock(hdev); +} + static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb) { @@ -7115,6 +7147,11 @@ static const struct hci_le_ev { hci_le_big_sync_established_evt, sizeof(struct hci_evt_le_big_sync_estabilished), HCI_MAX_EVENT_SIZE), + /* [0x1e = HCI_EVT_LE_BIG_SYNC_LOST] */ + HCI_LE_EV_VL(HCI_EVT_LE_BIG_SYNC_LOST, + hci_le_big_sync_lost_evt, + sizeof(struct hci_evt_le_big_sync_lost), + HCI_MAX_EVENT_SIZE), /* [0x22 = HCI_EVT_LE_BIG_INFO_ADV_REPORT] */ HCI_LE_EV_VL(HCI_EVT_LE_BIG_INFO_ADV_REPORT, hci_le_big_info_adv_report_evt, From be31d11ec9144f7f8f7fcbf84ba6971b664683f3 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Tue, 1 Jul 2025 16:47:26 +0800 Subject: [PATCH 16/42] Bluetooth: Fix spelling mistakes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct the misspelling of “estabilished” in the code. Signed-off-by: Yang Li Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci.h | 2 +- net/bluetooth/hci_event.c | 16 ++++++++-------- net/bluetooth/iso.c | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6213012610d7..94f365b75166 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -2837,7 +2837,7 @@ struct hci_evt_le_create_big_complete { } __packed; #define HCI_EVT_LE_BIG_SYNC_ESTABLISHED 0x1d -struct hci_evt_le_big_sync_estabilished { +struct hci_evt_le_big_sync_established { __u8 status; __u8 handle; __u8 latency[3]; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fca58984ee4e..d44463e65194 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -6350,8 +6350,8 @@ static int hci_le_pa_term_sync(struct hci_dev *hdev, __le16 handle) return hci_send_cmd(hdev, HCI_OP_LE_PA_TERM_SYNC, sizeof(cp), &cp); } -static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data, - struct sk_buff *skb) +static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data, + struct sk_buff *skb) { struct hci_ev_le_pa_sync_established *ev = data; int mask = hdev->link_mode; @@ -6681,8 +6681,8 @@ static void hci_le_phy_update_evt(struct hci_dev *hdev, void *data, hci_dev_unlock(hdev); } -static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data, - struct sk_buff *skb) +static void hci_le_cis_established_evt(struct hci_dev *hdev, void *data, + struct sk_buff *skb) { struct hci_evt_le_cis_established *ev = data; struct hci_conn *conn; @@ -6910,7 +6910,7 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb) { - struct hci_evt_le_big_sync_estabilished *ev = data; + struct hci_evt_le_big_sync_established *ev = data; struct hci_conn *bis, *conn; int i; @@ -7121,7 +7121,7 @@ static const struct hci_le_ev { HCI_MAX_EVENT_SIZE), /* [0x0e = HCI_EV_LE_PA_SYNC_ESTABLISHED] */ HCI_LE_EV(HCI_EV_LE_PA_SYNC_ESTABLISHED, - hci_le_pa_sync_estabilished_evt, + hci_le_pa_sync_established_evt, sizeof(struct hci_ev_le_pa_sync_established)), /* [0x0f = HCI_EV_LE_PER_ADV_REPORT] */ HCI_LE_EV_VL(HCI_EV_LE_PER_ADV_REPORT, @@ -7132,7 +7132,7 @@ static const struct hci_le_ev { HCI_LE_EV(HCI_EV_LE_EXT_ADV_SET_TERM, hci_le_ext_adv_term_evt, sizeof(struct hci_evt_le_ext_adv_set_term)), /* [0x19 = HCI_EVT_LE_CIS_ESTABLISHED] */ - HCI_LE_EV(HCI_EVT_LE_CIS_ESTABLISHED, hci_le_cis_estabilished_evt, + HCI_LE_EV(HCI_EVT_LE_CIS_ESTABLISHED, hci_le_cis_established_evt, sizeof(struct hci_evt_le_cis_established)), /* [0x1a = HCI_EVT_LE_CIS_REQ] */ HCI_LE_EV(HCI_EVT_LE_CIS_REQ, hci_le_cis_req_evt, @@ -7145,7 +7145,7 @@ static const struct hci_le_ev { /* [0x1d = HCI_EV_LE_BIG_SYNC_ESTABLISHED] */ HCI_LE_EV_VL(HCI_EVT_LE_BIG_SYNC_ESTABLISHED, hci_le_big_sync_established_evt, - sizeof(struct hci_evt_le_big_sync_estabilished), + sizeof(struct hci_evt_le_big_sync_established), HCI_MAX_EVENT_SIZE), /* [0x1e = HCI_EVT_LE_BIG_SYNC_LOST] */ HCI_LE_EV_VL(HCI_EVT_LE_BIG_SYNC_LOST, diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 34e89bb5f384..5e752950e266 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -1891,7 +1891,7 @@ static void iso_sock_ready(struct sock *sk) static bool iso_match_big(struct sock *sk, void *data) { - struct hci_evt_le_big_sync_estabilished *ev = data; + struct hci_evt_le_big_sync_established *ev = data; return ev->handle == iso_pi(sk)->qos.bcast.big; } @@ -1912,7 +1912,7 @@ static void iso_conn_ready(struct iso_conn *conn) { struct sock *parent = NULL; struct sock *sk = conn->sk; - struct hci_ev_le_big_sync_estabilished *ev = NULL; + struct hci_ev_le_big_sync_established *ev = NULL; struct hci_ev_le_pa_sync_established *ev2 = NULL; struct hci_ev_le_per_adv_report *ev3 = NULL; struct hci_conn *hcon; @@ -2023,7 +2023,7 @@ static void iso_conn_ready(struct iso_conn *conn) hci_conn_hold(hcon); iso_chan_add(conn, sk, parent); - if ((ev && ((struct hci_evt_le_big_sync_estabilished *)ev)->status) || + if ((ev && ((struct hci_evt_le_big_sync_established *)ev)->status) || (ev2 && ev2->status)) { /* Trigger error signal on child socket */ sk->sk_err = ECONNREFUSED; @@ -2082,7 +2082,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) * proceed to establishing a BIG sync: * * 1. HCI_EV_LE_PA_SYNC_ESTABLISHED: The socket may specify a specific - * SID to listen to and once sync is estabilished its handle needs to + * SID to listen to and once sync is established its handle needs to * be stored in iso_pi(sk)->sync_handle so it can be matched once * receiving the BIG Info. * 2. HCI_EVT_LE_BIG_INFO_ADV_REPORT: When connect_ind is triggered by a From 18afbdcd1250cafee0012dc45832d439f96b85e6 Mon Sep 17 00:00:00 2001 From: Catalin Popescu Date: Wed, 2 Jul 2025 13:41:04 +0200 Subject: [PATCH 17/42] dt-bindings: net: bluetooth: nxp: add support for supply and reset Add support for chip power supply and chip reset/powerdown. Signed-off-by: Catalin Popescu Acked-by: Conor Dooley Signed-off-by: Luiz Augusto von Dentz --- .../bindings/net/bluetooth/nxp,88w8987-bt.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml index bb9ab5dd3b4a..857c6234ba9b 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml @@ -72,6 +72,14 @@ properties: description: The GPIO number of the NXP chipset used for BT_WAKE_OUT. + vcc-supply: + description: + phandle of the regulator that provides the supply voltage. + + reset-gpios: + description: + Chip powerdown/reset signal (PDn). + required: - compatible @@ -90,6 +98,8 @@ examples: device-wakeup-gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; nxp,wakein-pin = /bits/ 8 <18>; nxp,wakeout-pin = /bits/ 8 <19>; + vcc-supply = <&nxp_iw612_supply>; + reset-gpios = <&gpioctrl 2 GPIO_ACTIVE_LOW>; local-bd-address = [66 55 44 33 22 11]; interrupt-parent = <&gpio>; interrupts = <8 IRQ_TYPE_EDGE_FALLING>; From 636c803f926ba0b20ad04be6a98592f4df7a7fd5 Mon Sep 17 00:00:00 2001 From: Catalin Popescu Date: Wed, 2 Jul 2025 13:41:05 +0200 Subject: [PATCH 18/42] Bluetooth: btnxpuart: implement powerup sequence NXP bluetooth chip shares power supply and reset gpio with a WLAN chip. Add support for power supply and reset and enforce powerup sequence: - apply power supply - deassert reset/powerdown Signed-off-by: Catalin Popescu Reviewed-by: Neeraj Sanjay Kale Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btnxpuart.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 7c6592bf773c..52e5cc3eb451 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -209,6 +211,7 @@ struct btnxpuart_dev { struct ps_data psdata; struct btnxpuart_data *nxp_data; + struct reset_control *pdn; }; #define NXP_V1_FW_REQ_PKT 0xa5 @@ -1757,6 +1760,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev) struct hci_dev *hdev; struct btnxpuart_dev *nxpdev; bdaddr_t ba = {0}; + int err; nxpdev = devm_kzalloc(&serdev->dev, sizeof(*nxpdev), GFP_KERNEL); if (!nxpdev) @@ -1795,6 +1799,16 @@ static int nxp_serdev_probe(struct serdev_device *serdev) crc8_populate_msb(crc8_table, POLYNOMIAL8); + nxpdev->pdn = devm_reset_control_get_optional_shared(&serdev->dev, NULL); + if (IS_ERR(nxpdev->pdn)) + return PTR_ERR(nxpdev->pdn); + + err = devm_regulator_get_enable(&serdev->dev, "vcc"); + if (err) { + dev_err(&serdev->dev, "Failed to enable vcc regulator\n"); + return err; + } + /* Initialize and register HCI device */ hdev = hci_alloc_dev(); if (!hdev) { @@ -1802,6 +1816,8 @@ static int nxp_serdev_probe(struct serdev_device *serdev) return -ENOMEM; } + reset_control_deassert(nxpdev->pdn); + nxpdev->hdev = hdev; hdev->bus = HCI_UART; @@ -1840,6 +1856,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev) return 0; probe_fail: + reset_control_assert(nxpdev->pdn); hci_free_dev(hdev); return -ENODEV; } @@ -1867,6 +1884,7 @@ static void nxp_serdev_remove(struct serdev_device *serdev) ps_cleanup(nxpdev); hci_unregister_dev(hdev); + reset_control_assert(nxpdev->pdn); hci_free_dev(hdev); } From b505902c66a282dcb01bcdc015aa1fdfaaa075db Mon Sep 17 00:00:00 2001 From: Zhongqiu Han Date: Sat, 5 Jul 2025 18:52:46 +0800 Subject: [PATCH 19/42] Bluetooth: btusb: Fix potential NULL dereference on kmalloc failure Avoid potential NULL pointer dereference by checking the return value of kmalloc and handling allocation failure properly. Fixes: 7d70989fcea7 ("Bluetooth: btusb: Add HCI Drv commands for configuring altsetting") Signed-off-by: Zhongqiu Han Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b04a4ad64e3b..8023a2eb4681 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -3809,6 +3809,8 @@ static int btusb_hci_drv_supported_altsettings(struct hci_dev *hdev, void *data, /* There are at most 7 alt (0 - 6) */ rp = kmalloc(sizeof(*rp) + 7, GFP_KERNEL); + if (!rp) + return -ENOMEM; rp->num = 0; if (!drvdata->isoc) From 385d358a0e12f50231b1d5eca819c551d4b84d41 Mon Sep 17 00:00:00 2001 From: Hao Li Date: Thu, 10 Jul 2025 16:05:48 +0800 Subject: [PATCH 20/42] Bluetooth: btusb: Add RTL8852BE device 0x13d3:0x3618 The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below: T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3618 Rev= 0.00 S: Manufacturer=Realtek S: Product=Bluetooth Radio S: SerialNumber=00e04c000001 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Hao Li Signed-off-by: WangYuli Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 8023a2eb4681..70c361dee225 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -570,6 +570,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3591), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3618), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe123), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe125), .driver_info = BTUSB_REALTEK | From 942873c8137fe0015ab37f62f159d88079859c5e Mon Sep 17 00:00:00 2001 From: En-Wei Wu Date: Wed, 9 Jul 2025 14:36:06 +0800 Subject: [PATCH 21/42] Bluetooth: btusb: Add new VID/PID 0489/e14e for MT7925 Add VID 0489 & PID e14e for MediaTek MT7925 USB Bluetooth chip. The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below. T: Bus=01 Lev=01 Prnt=01 Port=03 Cnt=03 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0489 ProdID=e14e Rev= 1.00 S: Manufacturer=MediaTek Inc. S: Product=Wireless_Device S: SerialNumber=000000000 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms I: If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us I:* If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us Signed-off-by: En-Wei Wu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 70c361dee225..128596ecc888 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -712,6 +712,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe139), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe14e), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe14f), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe150), .driver_info = BTUSB_MEDIATEK | From 9918b837fac203c7139499ba162d779572b476ab Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 3 Jul 2025 19:16:55 +0200 Subject: [PATCH 22/42] Bluetooth: btintel: Fix typo in comment Found by codespell. Signed-off-by: Bastien Nocera Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 06016ac3965c..d02d5791e0da 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -555,7 +555,7 @@ int btintel_parse_version_tlv(struct hci_dev *hdev, /* Consume Command Complete Status field */ skb_pull(skb, 1); - /* Event parameters contatin multiple TLVs. Read each of them + /* Event parameters contain multiple TLVs. Read each of them * and only keep the required data. Also, it use existing legacy * version field like hw_platform, hw_variant, and fw_variant * to keep the existing setup flow From b32cb99d9d846bc7d9bdc6d5964ca8f512528359 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 3 Jul 2025 19:16:56 +0200 Subject: [PATCH 23/42] Bluetooth: btmtk: Fix typo in log string Found by codespell. Signed-off-by: Bastien Nocera Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btmtkuart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index 51400a891f6e..76995cfcd534 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -316,7 +316,7 @@ mtk_stp_split(struct btmtkuart_dev *bdev, const unsigned char *data, int count, /* Resync STP when unexpected data is being read */ if (shdr->prefix != 0x80 || bdev->stp_dlen > 2048) { - bt_dev_err(bdev->hdev, "stp format unexpect (%d, %d)", + bt_dev_err(bdev->hdev, "stp format unexpected (%d, %d)", shdr->prefix, bdev->stp_dlen); bdev->stp_cursor = 2; bdev->stp_dlen = 0; From 887f83d4f2fac7c2029f345eac649aff7679db47 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 3 Jul 2025 19:16:57 +0200 Subject: [PATCH 24/42] Bluetooth: btrtl: Fix typo in comment Found by codespell. Signed-off-by: Bastien Nocera Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btrtl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index 4d182cf6e037..6abd962502e3 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -693,7 +693,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, /* Loop from the end of the firmware parsing instructions, until * we find an instruction that identifies the "project ID" for the - * hardware supported by this firwmare file. + * hardware supported by this firmware file. * Once we have that, we double-check that project_id is suitable * for the hardware we are working with. */ From 0e77524dbc09e3d9f1cfa7d4a15b988466f89b1f Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 3 Jul 2025 19:16:58 +0200 Subject: [PATCH 25/42] Bluetooth: hci_bcm4377: Fix typo in comment Found by codespell. Signed-off-by: Bastien Nocera Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_bcm4377.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c index 8a9aa33776b0..45e6d84224ee 100644 --- a/drivers/bluetooth/hci_bcm4377.c +++ b/drivers/bluetooth/hci_bcm4377.c @@ -420,7 +420,7 @@ struct bcm4377_ring_state { * payloads_dma:DMA address for payload buffer * events: pointer to array of completions if waiting is allowed * msgids: bitmap to keep track of used message ids - * lock: Spinlock to protect access to ring structurs used in the irq handler + * lock: Spinlock to protect access to ring structures used in the irq handler */ struct bcm4377_transfer_ring { enum bcm4377_transfer_ring_id ring_id; From 8074811359141e2f67eff9bce41a3e2ecae4ace9 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 3 Jul 2025 19:16:59 +0200 Subject: [PATCH 26/42] Bluetooth: aosp: Fix typo in comment Found by codespell. Signed-off-by: Bastien Nocera Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/aosp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/aosp.c b/net/bluetooth/aosp.c index 1d67836e95e1..59025771af53 100644 --- a/net/bluetooth/aosp.c +++ b/net/bluetooth/aosp.c @@ -70,7 +70,7 @@ void aosp_do_open(struct hci_dev *hdev) rp = (struct aosp_rp_le_get_vendor_capa *)skb->data; version_supported = le16_to_cpu(rp->version_supported); - /* AOSP displays the verion number like v0.98, v1.00, etc. */ + /* AOSP displays the version number like v0.98, v1.00, etc. */ bt_dev_info(hdev, "AOSP extensions version v%u.%02u", version_supported >> 8, version_supported & 0xff); From e6555fffd5189be7f1a3d936915660ee63c503da Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 3 Jul 2025 19:17:00 +0200 Subject: [PATCH 27/42] Bluetooth: RFCOMM: Fix typos in comments Found by codespell. Signed-off-by: Bastien Nocera Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/rfcomm/core.c | 3 ++- net/bluetooth/rfcomm/tty.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 3b8f39618d65..96250807b32b 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1962,7 +1962,8 @@ static void rfcomm_accept_connection(struct rfcomm_session *s) int err; /* Fast check for a new connection. - * Avoids unnesesary socket allocations. */ + * Avoids unnecessary socket allocations. + */ if (list_empty(&bt_sk(sock->sk)->accept_q)) return; diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 21a5b5535ebc..58d1707f7daf 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -980,7 +980,7 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty, baud = RFCOMM_RPN_BR_230400; break; default: - /* 9600 is standard accordinag to the RFCOMM specification */ + /* 9600 is standard according to the RFCOMM specification */ baud = RFCOMM_RPN_BR_9600; break; From 0e492dbaccda2807eae56274bc90839f41b332fd Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 3 Jul 2025 19:17:01 +0200 Subject: [PATCH 28/42] Bluetooth: Fix typos in comments Found by codespell. Signed-off-by: Bastien Nocera Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/hci_event.c | 4 ++-- net/bluetooth/hci_sync.c | 2 +- net/bluetooth/lib.c | 2 +- net/bluetooth/smp.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index f5cd935490ad..b2e09e7f70e1 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -814,7 +814,7 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *c * * Detects if there any BIS left connected in a BIG * broadcaster: Remove advertising instance and terminate BIG. - * broadcaster receiver: Teminate BIG sync and terminate PA sync. + * broadcaster receiver: Terminate BIG sync and terminate PA sync. */ static void bis_cleanup(struct hci_conn *conn) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d44463e65194..c0eb03e5cbf8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -5717,7 +5717,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, conn->state = BT_CONFIG; /* Store current advertising instance as connection advertising instance - * when sotfware rotation is in use so it can be re-enabled when + * when software rotation is in use so it can be re-enabled when * disconnected. */ if (!ext_adv_capable(hdev)) @@ -7075,7 +7075,7 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data, /* Entries in this table shall have their position according to the subevent * opcode they handle so the use of the macros above is recommend since it does * attempt to initialize at its proper index using Designated Initializers that - * way events without a callback function can be ommited. + * way events without a callback function can be omitted. */ static const struct hci_le_ev { void (*func)(struct hci_dev *hdev, void *data, struct sk_buff *skb); diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 956aea977f2a..e9df6502e58e 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -5677,7 +5677,7 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason) } /* Cleanup hci_conn object if it cannot be cancelled as it - * likelly means the controller and host stack are out of sync + * likely means the controller and host stack are out of sync * or in case of LE it was still scanning so it can be cleanup * safely. */ diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c index 43aa01fd07b9..305044a84478 100644 --- a/net/bluetooth/lib.c +++ b/net/bluetooth/lib.c @@ -54,7 +54,7 @@ EXPORT_SYMBOL(baswap); * bt_to_errno() - Bluetooth error codes to standard errno * @code: Bluetooth error code to be converted * - * This function takes a Bluetooth error code as input and convets + * This function takes a Bluetooth error code as input and converts * it to an equivalent Unix/standard errno value. * * Return: diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 8115d42fc15b..45512b2ba951 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -3189,7 +3189,7 @@ static void smp_ready_cb(struct l2cap_chan *chan) /* No need to call l2cap_chan_hold() here since we already own * the reference taken in smp_new_conn_cb(). This is just the * first time that we tie it to a specific pointer. The code in - * l2cap_core.c ensures that there's no risk this function wont + * l2cap_core.c ensures that there's no risk this function won't * get called if smp_new_conn_cb was previously called. */ conn->smp = chan; From 15843c7fdba65568704245fd3ea2aa3aa2d50825 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Fri, 11 Jul 2025 15:37:25 +0530 Subject: [PATCH 29/42] Bluetooth: btintel: Define a macro for Intel Reset vendor command Use macro for Intel Reset command (0xfc01) instead of hard coded value. Signed-off-by: Kiran K Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel.c | 4 ++-- drivers/bluetooth/btintel.h | 2 ++ drivers/bluetooth/btintel_pcie.c | 12 ++++++------ drivers/bluetooth/btusb.c | 8 ++++---- drivers/bluetooth/hci_intel.c | 10 +++++----- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index d02d5791e0da..be69d21c9aa7 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -889,7 +889,7 @@ int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param) params.boot_param = cpu_to_le32(boot_param); - skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params), ¶ms, + skb = __hci_cmd_sync(hdev, BTINTEL_HCI_OP_RESET, sizeof(params), ¶ms, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "Failed to send Intel Reset command"); @@ -1287,7 +1287,7 @@ static void btintel_reset_to_bootloader(struct hci_dev *hdev) params.boot_option = 0x00; params.boot_param = cpu_to_le32(0x00000000); - skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params), + skb = __hci_cmd_sync(hdev, BTINTEL_HCI_OP_RESET, sizeof(params), ¶ms, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "FW download error recovery failed (%ld)", diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 1d12c4113c66..431998049e68 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -52,6 +52,8 @@ struct intel_tlv { u8 val[]; } __packed; +#define BTINTEL_HCI_OP_RESET 0xfc01 + #define BTINTEL_CNVI_BLAZARI 0x900 #define BTINTEL_CNVI_BLAZARIW 0x901 #define BTINTEL_CNVI_GAP 0x910 diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index ce59a98f1b6a..60528bdc4316 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -1977,12 +1977,12 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, struct hci_command_hdr *cmd = (void *)skb->data; __u16 opcode = le16_to_cpu(cmd->opcode); - /* When the 0xfc01 command is issued to boot into - * the operational firmware, it will actually not - * send a command complete event. To keep the flow + /* When the BTINTEL_HCI_OP_RESET command is issued to + * boot into the operational firmware, it will actually + * not send a command complete event. To keep the flow * control working inject that event here. */ - if (opcode == 0xfc01) + if (opcode == BTINTEL_HCI_OP_RESET) btintel_pcie_inject_cmd_complete(hdev, opcode); } /* Firmware raises alive interrupt on HCI_OP_RESET */ @@ -2017,10 +2017,10 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, } if (type == BTINTEL_PCIE_HCI_CMD_PKT && - (opcode == HCI_OP_RESET || opcode == 0xfc01)) { + (opcode == HCI_OP_RESET || opcode == BTINTEL_HCI_OP_RESET)) { old_ctxt = data->alive_intr_ctxt; data->alive_intr_ctxt = - (opcode == 0xfc01 ? BTINTEL_PCIE_INTEL_HCI_RESET1 : + (opcode == BTINTEL_HCI_OP_RESET ? BTINTEL_PCIE_INTEL_HCI_RESET1 : BTINTEL_PCIE_HCI_RESET); bt_dev_dbg(data->hdev, "sent cmd: 0x%4.4x alive context changed: %s -> %s", opcode, btintel_pcie_alivectxt_state2str(old_ctxt), diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 128596ecc888..2dd665bc5703 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2605,12 +2605,12 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) else urb = alloc_ctrl_urb(hdev, skb); - /* When the 0xfc01 command is issued to boot into - * the operational firmware, it will actually not - * send a command complete event. To keep the flow + /* When the BTINTEL_HCI_OP_RESET command is issued to + * boot into the operational firmware, it will actually + * not send a command complete event. To keep the flow * control working inject that event here. */ - if (opcode == 0xfc01) + if (opcode == BTINTEL_HCI_OP_RESET) inject_cmd_complete(hdev, opcode); } else { urb = alloc_ctrl_urb(hdev, skb); diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index d22fbb7f9fc5..9b353c3d6442 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -1029,12 +1029,12 @@ static struct sk_buff *intel_dequeue(struct hci_uart *hu) struct hci_command_hdr *cmd = (void *)skb->data; __u16 opcode = le16_to_cpu(cmd->opcode); - /* When the 0xfc01 command is issued to boot into - * the operational firmware, it will actually not - * send a command complete event. To keep the flow - * control working inject that event here. + /* When the BTINTEL_HCI_OP_RESET command is issued to boot into + * the operational firmware, it will actually not send a command + * complete event. To keep the flow control working inject that + * event here. */ - if (opcode == 0xfc01) + if (opcode == BTINTEL_HCI_OP_RESET) inject_cmd_complete(hu->hdev, opcode); } From 7565bc56598c3d135318f1bd76a0178dd3ea918f Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Mon, 14 Jul 2025 19:40:37 +0300 Subject: [PATCH 30/42] Bluetooth: ISO: add socket option to report packet seqnum via CMSG User applications need a way to track which ISO interval a given SDU belongs to, to properly detect packet loss. All controllers do not set timestamps, and it's not guaranteed user application receives all packet reports (small socket buffer, or controller doesn't send all reports like Intel AX210 is doing). Add socket option BT_PKT_SEQNUM that enables reporting of received packet ISO sequence number in BT_SCM_PKT_SEQNUM CMSG. Use BT_PKT_SEQNUM == 22 for the socket option, as 21 was used earlier for a removed experimental feature that never got into mainline. Signed-off-by: Pauli Virtanen Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/bluetooth.h | 11 ++++++++++- net/bluetooth/af_bluetooth.c | 7 +++++++ net/bluetooth/iso.c | 21 ++++++++++++++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 114299bd8b98..ada5b56a4413 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -244,6 +244,12 @@ struct bt_codecs { #define BT_ISO_BASE 20 +/* Socket option value 21 reserved */ + +#define BT_PKT_SEQNUM 22 + +#define BT_SCM_PKT_SEQNUM 0x05 + __printf(1, 2) void bt_info(const char *fmt, ...); __printf(1, 2) @@ -391,7 +397,8 @@ struct bt_sock { enum { BT_SK_DEFER_SETUP, BT_SK_SUSPEND, - BT_SK_PKT_STATUS + BT_SK_PKT_STATUS, + BT_SK_PKT_SEQNUM, }; struct bt_sock_list { @@ -475,6 +482,7 @@ struct bt_skb_cb { u8 pkt_type; u8 force_active; u16 expect; + u16 pkt_seqnum; u8 incoming:1; u8 pkt_status:2; union { @@ -488,6 +496,7 @@ struct bt_skb_cb { #define hci_skb_pkt_type(skb) bt_cb((skb))->pkt_type #define hci_skb_pkt_status(skb) bt_cb((skb))->pkt_status +#define hci_skb_pkt_seqnum(skb) bt_cb((skb))->pkt_seqnum #define hci_skb_expect(skb) bt_cb((skb))->expect #define hci_skb_opcode(skb) bt_cb((skb))->hci.opcode #define hci_skb_event(skb) bt_cb((skb))->hci.req_event diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index ee9bf84c88a7..2b94e2077203 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -364,6 +364,13 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, put_cmsg(msg, SOL_BLUETOOTH, BT_SCM_PKT_STATUS, sizeof(pkt_status), &pkt_status); } + + if (test_bit(BT_SK_PKT_SEQNUM, &bt_sk(sk)->flags)) { + u16 pkt_seqnum = hci_skb_pkt_seqnum(skb); + + put_cmsg(msg, SOL_BLUETOOTH, BT_SCM_PKT_SEQNUM, + sizeof(pkt_seqnum), &pkt_seqnum); + } } skb_free_datagram(sk, skb); diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 5e752950e266..2f229f2077e8 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -1687,6 +1687,17 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname, clear_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags); break; + case BT_PKT_SEQNUM: + err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + + if (opt) + set_bit(BT_SK_PKT_SEQNUM, &bt_sk(sk)->flags); + else + clear_bit(BT_SK_PKT_SEQNUM, &bt_sk(sk)->flags); + break; + case BT_ISO_QOS: if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECT2 && @@ -2278,7 +2289,7 @@ static void iso_disconn_cfm(struct hci_conn *hcon, __u8 reason) void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) { struct iso_conn *conn = hcon->iso_data; - __u16 pb, ts, len; + __u16 pb, ts, len, sn; if (!conn) goto drop; @@ -2308,6 +2319,7 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) goto drop; } + sn = __le16_to_cpu(hdr->sn); len = __le16_to_cpu(hdr->slen); } else { struct hci_iso_data_hdr *hdr; @@ -2318,18 +2330,20 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) goto drop; } + sn = __le16_to_cpu(hdr->sn); len = __le16_to_cpu(hdr->slen); } flags = hci_iso_data_flags(len); len = hci_iso_data_len(len); - BT_DBG("Start: total len %d, frag len %d flags 0x%4.4x", len, - skb->len, flags); + BT_DBG("Start: total len %d, frag len %d flags 0x%4.4x sn %d", + len, skb->len, flags, sn); if (len == skb->len) { /* Complete frame received */ hci_skb_pkt_status(skb) = flags & 0x03; + hci_skb_pkt_seqnum(skb) = sn; iso_recv_frame(conn, skb); return; } @@ -2352,6 +2366,7 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) goto drop; hci_skb_pkt_status(conn->rx_skb) = flags & 0x03; + hci_skb_pkt_seqnum(conn->rx_skb) = sn; skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), skb->len); conn->rx_len = len - skb->len; From ef568ae04ead4d132481550fde36fcdd29a31b3b Mon Sep 17 00:00:00 2001 From: Yang Li Date: Mon, 7 Jul 2025 10:38:17 +0800 Subject: [PATCH 31/42] Bluetooth: ISO: Support SCM_TIMESTAMPING for ISO TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User-space applications (e.g. PipeWire) depend on ISO-formatted timestamps for precise audio sync. The ISO ts is based on the controller’s clock domain, so hardware timestamping (hwtimestamp) must be used. Ref: Documentation/networking/timestamping.rst, section 3.1 Hardware Timestamping. Signed-off-by: Yang Li Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/iso.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 2f229f2077e8..2f45e46a9b6a 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -2289,6 +2289,7 @@ static void iso_disconn_cfm(struct hci_conn *hcon, __u8 reason) void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) { struct iso_conn *conn = hcon->iso_data; + struct skb_shared_hwtstamps *hwts; __u16 pb, ts, len, sn; if (!conn) @@ -2312,13 +2313,16 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) if (ts) { struct hci_iso_ts_data_hdr *hdr; - /* TODO: add timestamp to the packet? */ hdr = skb_pull_data(skb, HCI_ISO_TS_DATA_HDR_SIZE); if (!hdr) { BT_ERR("Frame is too short (len %d)", skb->len); goto drop; } + /* Record the timestamp to skb */ + hwts = skb_hwtstamps(skb); + hwts->hwtstamp = us_to_ktime(le32_to_cpu(hdr->ts)); + sn = __le16_to_cpu(hdr->sn); len = __le16_to_cpu(hdr->slen); } else { @@ -2370,6 +2374,13 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), skb->len); conn->rx_len = len - skb->len; + + /* Copy hw timestamp from skb to rx_skb if present */ + if (ts) { + hwts = skb_hwtstamps(conn->rx_skb); + hwts->hwtstamp = skb_hwtstamps(skb)->hwtstamp; + } + break; case ISO_CONT: From 634fd53a63be4798da356dbc7251046b713d992a Mon Sep 17 00:00:00 2001 From: Neeraj Sanjay Kale Date: Mon, 14 Jul 2025 13:00:15 +0530 Subject: [PATCH 32/42] Bluetooth: btnxpuart: Correct the Independent Reset handling after FW dump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds proper handling for the independent reset command sent by the driver after FW dump is complete. In normal scenario, the independent reset vendor command gives a success response before jumping to bootcode. However, when FW goes in a bad state, and sends out FW dump packets, the independent reset command does not get any response from the controller. [ 159.807732] Bluetooth: hci0: ==== Start FW dump === [ 180.759060] Bluetooth: hci0: ==== FW dump complete === [ 182.779208] Bluetooth: hci0: command 0xfcfc tx timeout [ 183.364974] Bluetooth: hci0: ChipID: 7601, Version: 0 [ 183.368490] Bluetooth: hci0: Request Firmware: nxp/uartspi_n61x_v1.bin.se [ 184.679977] Bluetooth: hci0: FW Download Complete: 417064 bytes [ 187.963102] Bluetooth: hci0: Opcode 0x0c03 failed: -110 As a fix for such scenario, the independent reset vendor command is sent using the __hci_cmd_send() API, which does not expect any response for vendor commands. __hci_cmd_send is non blocking, so before the tx_work is scheduled, it sometimes gets canceled and 3F|FC command is never sent. Adding a small delay after __hci_cmd_send allows the command to be sent to the controller. Signed-off-by: Neeraj Sanjay Kale Tested-by: Jean-Yves Salaün Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btnxpuart.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 52e5cc3eb451..a2a0a3937d17 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -370,17 +370,26 @@ static u8 crc8_table[CRC8_TABLE_SIZE]; static struct sk_buff *nxp_drv_send_cmd(struct hci_dev *hdev, u16 opcode, u32 plen, - void *param) + void *param, + bool resp) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); struct ps_data *psdata = &nxpdev->psdata; - struct sk_buff *skb; + struct sk_buff *skb = NULL; /* set flag to prevent nxp_enqueue from parsing values from this command and * calling hci_cmd_sync_queue() again. */ psdata->driver_sent_cmd = true; - skb = __hci_cmd_sync(hdev, opcode, plen, param, HCI_CMD_TIMEOUT); + if (resp) { + skb = __hci_cmd_sync(hdev, opcode, plen, param, HCI_CMD_TIMEOUT); + } else { + __hci_cmd_send(hdev, opcode, plen, param); + /* Allow command to be sent before tx_work is cancelled + * by btnxpuart_flush() + */ + msleep(20); + } psdata->driver_sent_cmd = false; return skb; @@ -600,7 +609,8 @@ static int send_ps_cmd(struct hci_dev *hdev, void *data) pcmd.ps_cmd = BT_PS_DISABLE; pcmd.c2h_ps_interval = __cpu_to_le16(psdata->c2h_ps_interval); - skb = nxp_drv_send_cmd(hdev, HCI_NXP_AUTO_SLEEP_MODE, sizeof(pcmd), &pcmd); + skb = nxp_drv_send_cmd(hdev, HCI_NXP_AUTO_SLEEP_MODE, sizeof(pcmd), + &pcmd, true); if (IS_ERR(skb)) { bt_dev_err(hdev, "Setting Power Save mode failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); @@ -649,7 +659,8 @@ static int send_wakeup_method_cmd(struct hci_dev *hdev, void *data) break; } - skb = nxp_drv_send_cmd(hdev, HCI_NXP_WAKEUP_METHOD, sizeof(pcmd), &pcmd); + skb = nxp_drv_send_cmd(hdev, HCI_NXP_WAKEUP_METHOD, sizeof(pcmd), + &pcmd, true); if (IS_ERR(skb)) { bt_dev_err(hdev, "Setting wake-up method failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); @@ -1275,7 +1286,8 @@ static int nxp_set_baudrate_cmd(struct hci_dev *hdev, void *data) if (!psdata) return 0; - skb = nxp_drv_send_cmd(hdev, HCI_NXP_SET_OPER_SPEED, 4, (u8 *)&new_baudrate); + skb = nxp_drv_send_cmd(hdev, HCI_NXP_SET_OPER_SPEED, 4, + (u8 *)&new_baudrate, true); if (IS_ERR(skb)) { bt_dev_err(hdev, "Setting baudrate failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); @@ -1333,7 +1345,7 @@ static void nxp_coredump(struct hci_dev *hdev) struct sk_buff *skb; u8 pcmd = 2; - skb = nxp_drv_send_cmd(hdev, HCI_NXP_TRIGGER_DUMP, 1, &pcmd); + skb = nxp_drv_send_cmd(hdev, HCI_NXP_TRIGGER_DUMP, 1, &pcmd, true); if (IS_ERR(skb)) bt_dev_err(hdev, "Failed to trigger FW Dump. (%ld)", PTR_ERR(skb)); else @@ -1375,7 +1387,6 @@ static int nxp_process_fw_dump(struct hci_dev *hdev, struct sk_buff *skb) if (buf_len == 0) { bt_dev_warn(hdev, "==== FW dump complete ==="); - clear_bit(BTNXPUART_FW_DUMP_IN_PROGRESS, &nxpdev->tx_state); hci_devcd_complete(hdev); nxp_set_ind_reset(hdev, NULL); } @@ -1489,7 +1500,13 @@ static int nxp_shutdown(struct hci_dev *hdev) u8 pcmd = 0; if (ind_reset_in_progress(nxpdev)) { - skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd); + if (test_and_clear_bit(BTNXPUART_FW_DUMP_IN_PROGRESS, + &nxpdev->tx_state)) + skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, + &pcmd, false); + else + skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, + &pcmd, true); serdev_device_set_flow_control(nxpdev->serdev, false); set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); /* HCI_NXP_IND_RESET command may not returns any response */ From 085ee7cf937ce1f524cc6e68e81f109ddb1682c7 Mon Sep 17 00:00:00 2001 From: Neeraj Sanjay Kale Date: Mon, 14 Jul 2025 13:00:16 +0530 Subject: [PATCH 33/42] Bluetooth: btnxpuart: Add uevents for FW dump and FW download complete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds uevents which will be generated whenever FW dump is triggered, FW dump is complete and FW (re)download is done. This feature is needed for IW612 chipset, which is a tri-radio chipset, where WLAN runs on CPU1 and BT and Zigbee runs on CPU2. Currently, whenever BT FW crashes, and FW dump is in progress, there is no way for 15.4 application to know that CPU2 is in bad state, and when it will be recovered. With the help of these uevents and udev rules, the 15.4 app, or any userspace application can be alerted whenever CPU2 goes in bad state and recoveres after BTNXPUART reloads the firmware. [ 334.255154] Bluetooth: hci0: ==== Start FW dump === [ 334.261003] Bluetooth: hci0: ==== Send uevent: BTNXPUART_DEV=serial0-0:BTNXPUART_STATE=FW_DUMP_ACTIVE === [ 351.486048] Bluetooth: hci0: ==== FW dump complete === [ 351.491356] Bluetooth: hci0: ==== Send uevent: BTNXPUART_DEV=serial0-0:BTNXPUART_STATE=FW_DUMP_DONE === [ 352.028974] Bluetooth: hci0: ChipID: 7601, Version: 0 [ 352.034490] Bluetooth: hci0: Request Firmware: nxp/uartspi_n61x_v1.bin.se [ 353.979977] Bluetooth: hci0: FW Download Complete: 417064 bytes [ 355.197222] Bluetooth: hci0: ==== Send uevent: BTNXPUART_DEV=serial0-0:BTNXPUART_STATE=FW_READY === Tested this change by creating a simple udev rule to store the BTNXPUART_STATE value in a ~//state file, and running 15.4 traffic. The 15.4 packets were sent over SPI only when BTNXPUART_STATE was FW_READY. Signed-off-by: Neeraj Sanjay Kale Tested-by: Jean-Yves Salaün Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btnxpuart.c | 42 ++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index a2a0a3937d17..73a4a325c867 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -1440,6 +1440,10 @@ static int nxp_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) static int nxp_setup(struct hci_dev *hdev) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); + struct serdev_device *serdev = nxpdev->serdev; + char device_string[30]; + char event_string[50]; + char *envp[] = {device_string, event_string, NULL}; int err = 0; if (nxp_check_boot_sign(nxpdev)) { @@ -1452,6 +1456,12 @@ static int nxp_setup(struct hci_dev *hdev) clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); } + snprintf(device_string, 30, "BTNXPUART_DEV=%s", dev_name(&serdev->dev)); + snprintf(event_string, 50, "BTNXPUART_STATE=FW_READY"); + bt_dev_dbg(hdev, "==== Send uevent: %s:%s ===", device_string, + event_string); + kobject_uevent_env(&serdev->dev.kobj, KOBJ_CHANGE, envp); + serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate); nxpdev->current_baudrate = nxpdev->fw_init_baudrate; @@ -1772,6 +1782,35 @@ static const struct serdev_device_ops btnxpuart_client_ops = { .write_wakeup = btnxpuart_write_wakeup, }; +static void nxp_coredump_notify(struct hci_dev *hdev, int state) +{ + struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); + struct serdev_device *serdev = nxpdev->serdev; + char device_string[30]; + char event_string[50]; + char *envp[] = {device_string, event_string, NULL}; + + snprintf(device_string, 30, "BTNXPUART_DEV=%s", dev_name(&serdev->dev)); + switch (state) { + case HCI_DEVCOREDUMP_ACTIVE: + snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_ACTIVE"); + break; + case HCI_DEVCOREDUMP_DONE: + snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_DONE"); + break; + case HCI_DEVCOREDUMP_TIMEOUT: + snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_TIMEOUT"); + break; + default: + snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_STATE_%d", + state); + break; + } + bt_dev_dbg(hdev, "==== Send uevent: %s:%s ===", device_string, + event_string); + kobject_uevent_env(&serdev->dev.kobj, KOBJ_CHANGE, envp); +} + static int nxp_serdev_probe(struct serdev_device *serdev) { struct hci_dev *hdev; @@ -1868,7 +1907,8 @@ static int nxp_serdev_probe(struct serdev_device *serdev) if (ps_setup(hdev)) goto probe_fail; - hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr, NULL); + hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr, + nxp_coredump_notify); return 0; From a3f9f6dd047af711341a2367a8b08a3ade31438d Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Tue, 15 Jul 2025 20:40:14 +0800 Subject: [PATCH 34/42] Bluetooth: btusb: QCA: Support downloading custom-made firmwares There are custom-made firmwares based on board ID for a given QCA BT chip sometimes, and they are different with existing firmwares and put in a separate subdirectory to avoid conflict, for example: QCA2066, as a variant of WCN6855, has firmwares under 'qca/QCA2066/' of linux-firmware repository. Support downloading custom-made firmwares based on a table newly added. Signed-off-by: Zijun Hu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 54 +++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 2dd665bc5703..6b3499b8a717 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -3190,6 +3190,12 @@ struct qca_device_info { u8 ver_offset; /* offset of version structure in rampatch */ }; +struct qca_custom_firmware { + u32 rom_version; + u16 board_id; + const char *subdirectory; +}; + static const struct qca_device_info qca_devices_table[] = { { 0x00000100, 20, 4, 8 }, /* Rome 1.0 */ { 0x00000101, 20, 4, 8 }, /* Rome 1.1 */ @@ -3203,6 +3209,11 @@ static const struct qca_device_info qca_devices_table[] = { { 0x00190200, 40, 4, 16 }, /* WCN785x 2.0 */ }; +static const struct qca_custom_firmware qca_custom_btfws[] = { + { 0x00130201, 0x030A, "QCA2066" }, + { }, +}; + static u16 qca_extract_board_id(const struct qca_version *ver) { u16 flag = le16_to_cpu(ver->flag); @@ -3229,6 +3240,26 @@ static u16 qca_extract_board_id(const struct qca_version *ver) return board_id; } +static const char *qca_get_fw_subdirectory(const struct qca_version *ver) +{ + const struct qca_custom_firmware *ptr; + u32 rom_ver; + u16 board_id; + + rom_ver = le32_to_cpu(ver->rom_version); + board_id = qca_extract_board_id(ver); + if (!board_id) + return NULL; + + for (ptr = qca_custom_btfws; ptr->rom_version; ptr++) { + if (ptr->rom_version == rom_ver && + ptr->board_id == board_id) + return ptr->subdirectory; + } + + return NULL; +} + static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request, void *data, u16 size) { @@ -3333,15 +3364,22 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev, { struct qca_rampatch_version *rver; const struct firmware *fw; + const char *fw_subdir; u32 ver_rom, ver_patch, rver_rom; u16 rver_rom_low, rver_rom_high, rver_patch; - char fwname[64]; + char fwname[80]; int err; ver_rom = le32_to_cpu(ver->rom_version); ver_patch = le32_to_cpu(ver->patch_version); - snprintf(fwname, sizeof(fwname), "qca/rampatch_usb_%08x.bin", ver_rom); + fw_subdir = qca_get_fw_subdirectory(ver); + if (fw_subdir) + snprintf(fwname, sizeof(fwname), "qca/%s/rampatch_usb_%08x.bin", + fw_subdir, ver_rom); + else + snprintf(fwname, sizeof(fwname), "qca/rampatch_usb_%08x.bin", + ver_rom); err = request_firmware(&fw, fwname, &hdev->dev); if (err) { @@ -3385,10 +3423,11 @@ static void btusb_generate_qca_nvm_name(char *fwname, size_t max_size, const struct qca_version *ver) { u32 rom_version = le32_to_cpu(ver->rom_version); - const char *variant; + const char *variant, *fw_subdir; int len; u16 board_id; + fw_subdir = qca_get_fw_subdirectory(ver); board_id = qca_extract_board_id(ver); switch (le32_to_cpu(ver->ram_version)) { @@ -3401,7 +3440,12 @@ static void btusb_generate_qca_nvm_name(char *fwname, size_t max_size, break; } - len = snprintf(fwname, max_size, "qca/nvm_usb_%08x", rom_version); + if (fw_subdir) + len = snprintf(fwname, max_size, "qca/%s/nvm_usb_%08x", + fw_subdir, rom_version); + else + len = snprintf(fwname, max_size, "qca/nvm_usb_%08x", + rom_version); if (variant) len += snprintf(fwname + len, max_size - len, "%s", variant); if (board_id) @@ -3414,7 +3458,7 @@ static int btusb_setup_qca_load_nvm(struct hci_dev *hdev, const struct qca_device_info *info) { const struct firmware *fw; - char fwname[64]; + char fwname[80]; int err; btusb_generate_qca_nvm_name(fwname, sizeof(fwname), ver); From 986cb42191b6125dfccbc7ac2ea5ae5f3661eb3b Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Tue, 15 Jul 2025 07:27:07 -0700 Subject: [PATCH 35/42] Bluetooth: btusb: Sort WCN6855 device IDs by VID and PID Sort WCN6855 device IDs to more easily manage them. Signed-off-by: Zijun Hu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 76 +++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 6b3499b8a717..f52a4f63a428 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -298,44 +298,6 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, /* QCA WCN6855 chipset */ - { USB_DEVICE(0x0cf3, 0xe600), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0cc), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0d6), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0e3), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9309), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9409), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0d0), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9108), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9109), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9208), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9209), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9308), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9408), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9508), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9509), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9608), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9609), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9f09), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x04ca, 0x3022), .driver_info = BTUSB_QCA_WCN6855 | - BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe0c7), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe0c9), .driver_info = BTUSB_QCA_WCN6855 | @@ -344,18 +306,28 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe0cb), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe0cc), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe0ce), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe0d0), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe0d6), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe0de), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe0df), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe0e1), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe0e3), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe0ea), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe0ec), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x3022), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x04ca, 0x3023), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x04ca, 0x3024), .driver_info = BTUSB_QCA_WCN6855 | @@ -368,6 +340,34 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x04ca, 0x3a27), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0cf3, 0xe600), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9108), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9109), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9208), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9209), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9308), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9309), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9408), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9409), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9508), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9509), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9608), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9609), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x10ab, 0x9f09), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, /* QCA WCN785x chipset */ { USB_DEVICE(0x0cf3, 0xe700), .driver_info = BTUSB_QCA_WCN6855 | From c20284f73417581a6097401a4a93843ed670f23b Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Tue, 15 Jul 2025 07:27:08 -0700 Subject: [PATCH 36/42] Bluetooth: btusb: Add one more ID 0x28de:0x1401 for Qualcomm WCN6855 Add one more part with ID (0x28de, 0x1401) to usb_device_id table for Qualcomm WCN6855, and its device info from /sys/kernel/debug/usb/devices is shown below: T: Bus=03 Lev=01 Prnt=01 Port=09 Cnt=03 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=28de ProdID=1401 Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms I: If#= 1 Alt= 7 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 65 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 65 Ivl=1ms Signed-off-by: Zijun Hu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index f52a4f63a428..8085fabadde8 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -368,6 +368,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x10ab, 0x9f09), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x28de, 0x1401), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, /* QCA WCN785x chipset */ { USB_DEVICE(0x0cf3, 0xe700), .driver_info = BTUSB_QCA_WCN6855 | From 2935e556850e9c94d7a00adf14d3cd7fe406ac03 Mon Sep 17 00:00:00 2001 From: Arseniy Krasnov Date: Wed, 16 Jul 2025 22:23:58 +0300 Subject: [PATCH 37/42] Bluetooth: hci_sync: fix double free in 'hci_discovery_filter_clear()' Function 'hci_discovery_filter_clear()' frees 'uuids' array and then sets it to NULL. There is a tiny chance of the following race: 'hci_cmd_sync_work()' 'update_passive_scan_sync()' 'hci_update_passive_scan_sync()' 'hci_discovery_filter_clear()' kfree(uuids); <-------------------------preempted--------------------------------> 'start_service_discovery()' 'hci_discovery_filter_clear()' kfree(uuids); // DOUBLE FREE <-------------------------preempted--------------------------------> uuids = NULL; To fix it let's add locking around 'kfree()' call and NULL pointer assignment. Otherwise the following backtrace fires: [ ] ------------[ cut here ]------------ [ ] kernel BUG at mm/slub.c:547! [ ] Internal error: Oops - BUG: 00000000f2000800 [#1] PREEMPT SMP [ ] CPU: 3 UID: 0 PID: 246 Comm: bluetoothd Tainted: G O 6.12.19-kernel #1 [ ] Tainted: [O]=OOT_MODULE [ ] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ ] pc : __slab_free+0xf8/0x348 [ ] lr : __slab_free+0x48/0x348 ... [ ] Call trace: [ ] __slab_free+0xf8/0x348 [ ] kfree+0x164/0x27c [ ] start_service_discovery+0x1d0/0x2c0 [ ] hci_sock_sendmsg+0x518/0x924 [ ] __sock_sendmsg+0x54/0x60 [ ] sock_write_iter+0x98/0xf8 [ ] do_iter_readv_writev+0xe4/0x1c8 [ ] vfs_writev+0x128/0x2b0 [ ] do_writev+0xfc/0x118 [ ] __arm64_sys_writev+0x20/0x2c [ ] invoke_syscall+0x68/0xf0 [ ] el0_svc_common.constprop.0+0x40/0xe0 [ ] do_el0_svc+0x1c/0x28 [ ] el0_svc+0x30/0xd0 [ ] el0t_64_sync_handler+0x100/0x12c [ ] el0t_64_sync+0x194/0x198 [ ] Code: 8b0002e6 eb17031f 54fffbe1 d503201f (d4210000) [ ] ---[ end trace 0000000000000000 ]--- Fixes: ad383c2c65a5 ("Bluetooth: hci_sync: Enable advertising when LL privacy is enabled") Signed-off-by: Arseniy Krasnov Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 1ef9279cfd6f..3728495f0819 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -94,6 +95,7 @@ struct discovery_state { u16 uuid_count; u8 (*uuids)[16]; unsigned long name_resolve_timeout; + spinlock_t lock; }; #define SUSPEND_NOTIFIER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ @@ -889,6 +891,7 @@ static inline void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, static inline void discovery_init(struct hci_dev *hdev) { + spin_lock_init(&hdev->discovery.lock); hdev->discovery.state = DISCOVERY_STOPPED; INIT_LIST_HEAD(&hdev->discovery.all); INIT_LIST_HEAD(&hdev->discovery.unknown); @@ -903,8 +906,11 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev) hdev->discovery.report_invalid_rssi = true; hdev->discovery.rssi = HCI_RSSI_INVALID; hdev->discovery.uuid_count = 0; + + spin_lock(&hdev->discovery.lock); kfree(hdev->discovery.uuids); hdev->discovery.uuids = NULL; + spin_unlock(&hdev->discovery.lock); } bool hci_discovery_active(struct hci_dev *hdev); From 7af4d7b53502286c6cf946d397ab183e76d14820 Mon Sep 17 00:00:00 2001 From: Ivan Pravdin Date: Thu, 17 Jul 2025 11:10:52 -0400 Subject: [PATCH 38/42] Bluetooth: hci_devcd_dump: fix out-of-bounds via dev_coredumpv Currently both dev_coredumpv and skb_put_data in hci_devcd_dump use hdev->dump.head. However, dev_coredumpv can free the buffer. From dev_coredumpm_timeout documentation, which is used by dev_coredumpv: > Creates a new device coredump for the given device. If a previous one hasn't > been read yet, the new coredump is discarded. The data lifetime is determined > by the device coredump framework and when it is no longer needed the @free > function will be called to free the data. If the data has not been read by the userspace yet, dev_coredumpv will discard new buffer, freeing hdev->dump.head. This leads to vmalloc-out-of-bounds error when skb_put_data tries to access hdev->dump.head. A crash report from syzbot illustrates this: ================================================================== BUG: KASAN: vmalloc-out-of-bounds in skb_put_data include/linux/skbuff.h:2752 [inline] BUG: KASAN: vmalloc-out-of-bounds in hci_devcd_dump+0x142/0x240 net/bluetooth/coredump.c:258 Read of size 140 at addr ffffc90004ed5000 by task kworker/u9:2/5844 CPU: 1 UID: 0 PID: 5844 Comm: kworker/u9:2 Not tainted 6.14.0-syzkaller-10892-g4e82c87058f4 #0 PREEMPT(full) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2025 Workqueue: hci0 hci_devcd_timeout Call Trace: __dump_stack lib/dump_stack.c:94 [inline] dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:408 [inline] print_report+0xc3/0x670 mm/kasan/report.c:521 kasan_report+0xe0/0x110 mm/kasan/report.c:634 check_region_inline mm/kasan/generic.c:183 [inline] kasan_check_range+0xef/0x1a0 mm/kasan/generic.c:189 __asan_memcpy+0x23/0x60 mm/kasan/shadow.c:105 skb_put_data include/linux/skbuff.h:2752 [inline] hci_devcd_dump+0x142/0x240 net/bluetooth/coredump.c:258 hci_devcd_timeout+0xb5/0x2e0 net/bluetooth/coredump.c:413 process_one_work+0x9cc/0x1b70 kernel/workqueue.c:3238 process_scheduled_works kernel/workqueue.c:3319 [inline] worker_thread+0x6c8/0xf10 kernel/workqueue.c:3400 kthread+0x3c2/0x780 kernel/kthread.c:464 ret_from_fork+0x45/0x80 arch/x86/kernel/process.c:153 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 The buggy address ffffc90004ed5000 belongs to a vmalloc virtual mapping Memory state around the buggy address: ffffc90004ed4f00: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 ffffc90004ed4f80: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 >ffffc90004ed5000: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 ^ ffffc90004ed5080: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 ffffc90004ed5100: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 ================================================================== To avoid this issue, reorder dev_coredumpv to be called after skb_put_data that does not free the data. Reported-by: syzbot+ac3c79181f6aecc5120c@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=ac3c79181f6aecc5120c Fixes: b257e02ecc46 ("HCI: coredump: Log devcd dumps into the monitor") Tested-by: syzbot+ac3c79181f6aecc5120c@syzkaller.appspotmail.com Signed-off-by: Ivan Pravdin Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/coredump.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/coredump.c b/net/bluetooth/coredump.c index 819eacb38762..720cb79adf96 100644 --- a/net/bluetooth/coredump.c +++ b/net/bluetooth/coredump.c @@ -249,15 +249,15 @@ static void hci_devcd_dump(struct hci_dev *hdev) size = hdev->dump.tail - hdev->dump.head; - /* Emit a devcoredump with the available data */ - dev_coredumpv(&hdev->dev, hdev->dump.head, size, GFP_KERNEL); - /* Send a copy to monitor as a diagnostic packet */ skb = bt_skb_alloc(size, GFP_ATOMIC); if (skb) { skb_put_data(skb, hdev->dump.head, size); hci_recv_diag(hdev, skb); } + + /* Emit a devcoredump with the available data */ + dev_coredumpv(&hdev->dev, hdev->dump.head, size, GFP_KERNEL); } static void hci_devcd_handle_pkt_complete(struct hci_dev *hdev, From 69b3d3acf3dba21e2abad863c80c7114eb110b3d Mon Sep 17 00:00:00 2001 From: Kiran K Date: Mon, 21 Jul 2025 15:14:36 +0530 Subject: [PATCH 39/42] Bluetooth: btintel_pcie: Make driver wait for alive interrupt The firmware raises an alive interrupt upon receiving the HCI_RESET or BTINTEL_HCI_OP_RESET (Intel reset - 0xfc01) command. This change fixes the driver to properly wait for the alive interrupt to avoid driver sending commands to firmware before it is ready to process. For details on the handshake between the driver and firmware, refer to commit 05c200c8f029 ("Bluetooth: btintel_pcie: Add handshake between driver and firmware"). As the driver needs to handle two interrupts for HCI_OP_RESET and BTINTEL_HCI_OP_RESET, the firmware ensures that the TX completion interrupt is always followed by the alive interrupt. Fixes: 05c200c8f029 ("Bluetooth: btintel_pcie: Add handshake between driver and firmware") Signed-off-by: Sai Teja Aluvala Signed-off-by: Kiran K Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 60528bdc4316..a17c438784ae 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -947,11 +947,13 @@ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data) case BTINTEL_PCIE_INTEL_HCI_RESET1: if (btintel_pcie_in_op(data)) { submit_rx = true; + signal_waitq = true; break; } if (btintel_pcie_in_iml(data)) { submit_rx = true; + signal_waitq = true; data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL; break; } @@ -1985,8 +1987,11 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, if (opcode == BTINTEL_HCI_OP_RESET) btintel_pcie_inject_cmd_complete(hdev, opcode); } - /* Firmware raises alive interrupt on HCI_OP_RESET */ - if (opcode == HCI_OP_RESET) + + /* Firmware raises alive interrupt on HCI_OP_RESET or + * BTINTEL_HCI_OP_RESET + */ + if (opcode == HCI_OP_RESET || opcode == BTINTEL_HCI_OP_RESET) data->gp0_received = false; hdev->stat.cmd_tx++; @@ -2025,17 +2030,16 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, bt_dev_dbg(data->hdev, "sent cmd: 0x%4.4x alive context changed: %s -> %s", opcode, btintel_pcie_alivectxt_state2str(old_ctxt), btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); - if (opcode == HCI_OP_RESET) { - ret = wait_event_timeout(data->gp0_wait_q, - data->gp0_received, - msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS)); - if (!ret) { - hdev->stat.err_tx++; - bt_dev_err(hdev, "No alive interrupt received for %s", - btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); - ret = -ETIME; - goto exit_error; - } + ret = wait_event_timeout(data->gp0_wait_q, + data->gp0_received, + msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS)); + if (!ret) { + hdev->stat.err_tx++; + bt_dev_err(hdev, "Timeout on alive interrupt (%u ms). Alive context: %s", + BTINTEL_DEFAULT_INTR_TIMEOUT_MS, + btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); + ret = -ETIME; + goto exit_error; } } hdev->stat.byte_tx += skb->len; From 54713670372e17903bff948f5d0859da02106f09 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Mon, 21 Jul 2025 15:14:37 +0530 Subject: [PATCH 40/42] Bluetooth: btintel_pcie: Fix Alive Context State Handling The firmware raises an alive interrupt upon sending the HCI_RESET or BTINTEL_HCI_OP_RESET command. As part of handling the reset command, firmware initializes the hardware and data path and raises the alive interrupt. Upon receiving the alive interrupt, the driver must enable the data path and grant RX buffers to the firmware before sending any commands. The alive context maintained in the driver must be updated before sending BTINTEL_HCI_OP_RESET or HCI_OP_RESET to prevent a potential race condition where the context is also updated in the threaded IRQ. The issue was observed in a stress reboot usecase (1/25) using "sudo reboot" command where the firmware download was failing as the driver was not granting RX buffer to firmware due to race condition. Bluetooth: hci0: API lock is disabled Bluetooth: hci0: Debug lock is disabled Bluetooth: hci0: Minimum firmware build 1 week 10 2014 Bluetooth: hci0: Bootloader timestamp 2023.43 buildtype 1 build 11631 Bluetooth: hci0: Found device firmware: intel/ibt-00a0-00a1-iml.sfi Bluetooth: hci0: Boot Address: 0xb0301000 Bluetooth: hci0: Firmware Version: 167-12.25 Bluetooth: hci0: Waiting for firmware download to complete Bluetooth: hci0: Firmware loaded in 99902 usecs Bluetooth: hci0: Alive context: fw_dl old_boot_stage: 0xa0db0003 new_boot_stage: 0xa0db0003 Bluetooth: hci0: sent cmd: 0xfc01 alive context changed: fw_dl -> intel_reset1 Bluetooth: hci0: Waiting for device to boot Bluetooth: hci0: Device boot timeout Bluetooth: hci0: Firmware download retry count: 1 Fixes: 05c200c8f029 ("Bluetooth: btintel_pcie: Add handshake between driver and firmware") Signed-off-by: Kiran K Signed-off-by: Sai Teja Aluvala Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 117 ++++++++++++++++--------------- 1 file changed, 62 insertions(+), 55 deletions(-) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index a17c438784ae..6e7bbbd35279 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -118,6 +118,28 @@ struct btintel_pcie_removal { static LIST_HEAD(btintel_pcie_recovery_list); static DEFINE_SPINLOCK(btintel_pcie_recovery_lock); +static inline char *btintel_pcie_alivectxt_state2str(u32 alive_intr_ctxt) +{ + switch (alive_intr_ctxt) { + case BTINTEL_PCIE_ROM: + return "rom"; + case BTINTEL_PCIE_FW_DL: + return "fw_dl"; + case BTINTEL_PCIE_D0: + return "d0"; + case BTINTEL_PCIE_D3: + return "d3"; + case BTINTEL_PCIE_HCI_RESET: + return "hci_reset"; + case BTINTEL_PCIE_INTEL_HCI_RESET1: + return "intel_reset1"; + case BTINTEL_PCIE_INTEL_HCI_RESET2: + return "intel_reset2"; + default: + return "unknown"; + } +} + /* This function initializes the memory for DBGC buffers and formats the * DBGC fragment which consists header info and DBGC buffer's LSB, MSB and * size as the payload @@ -318,10 +340,14 @@ static inline void btintel_pcie_dump_debug_registers(struct hci_dev *hdev) } static int btintel_pcie_send_sync(struct btintel_pcie_data *data, - struct sk_buff *skb) + struct sk_buff *skb, u32 pkt_type, u16 opcode) { int ret; u16 tfd_index; + u32 old_ctxt; + bool wait_on_alive = false; + struct hci_dev *hdev = data->hdev; + struct txq *txq = &data->txq; tfd_index = data->ia.tr_hia[BTINTEL_PCIE_TXQ_NUM]; @@ -329,6 +355,26 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data, if (tfd_index > txq->count) return -ERANGE; + /* Firmware raises alive interrupt on HCI_OP_RESET or + * BTINTEL_HCI_OP_RESET + */ + wait_on_alive = (pkt_type == BTINTEL_PCIE_HCI_CMD_PKT && + (opcode == BTINTEL_HCI_OP_RESET || opcode == HCI_OP_RESET)); + + if (wait_on_alive) { + data->gp0_received = false; + old_ctxt = data->alive_intr_ctxt; + data->alive_intr_ctxt = + (opcode == BTINTEL_HCI_OP_RESET ? BTINTEL_PCIE_INTEL_HCI_RESET1 : + BTINTEL_PCIE_HCI_RESET); + bt_dev_dbg(data->hdev, "sending cmd: 0x%4.4x alive context changed: %s -> %s", + opcode, btintel_pcie_alivectxt_state2str(old_ctxt), + btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); + } + + memcpy(skb_push(skb, BTINTEL_PCIE_HCI_TYPE_LEN), &pkt_type, + BTINTEL_PCIE_HCI_TYPE_LEN); + /* Prepare for TX. It updates the TFD with the length of data and * address of the DMA buffer, and copy the data to the DMA buffer */ @@ -347,11 +393,24 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data, ret = wait_event_timeout(data->tx_wait_q, data->tx_wait_done, msecs_to_jiffies(BTINTEL_PCIE_TX_WAIT_TIMEOUT_MS)); if (!ret) { - bt_dev_err(data->hdev, "tx completion timeout"); + bt_dev_err(data->hdev, "Timeout (%u ms) on tx completion", + BTINTEL_PCIE_TX_WAIT_TIMEOUT_MS); btintel_pcie_dump_debug_registers(data->hdev); return -ETIME; } + if (wait_on_alive) { + ret = wait_event_timeout(data->gp0_wait_q, + data->gp0_received, + msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS)); + if (!ret) { + hdev->stat.err_tx++; + bt_dev_err(hdev, "Timeout (%u ms) on alive interrupt, alive context: %s", + BTINTEL_DEFAULT_INTR_TIMEOUT_MS, + btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); + return -ETIME; + } + } return 0; } @@ -830,28 +889,6 @@ static void btintel_pcie_wr_sleep_cntrl(struct btintel_pcie_data *data, btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG, dxstate); } -static inline char *btintel_pcie_alivectxt_state2str(u32 alive_intr_ctxt) -{ - switch (alive_intr_ctxt) { - case BTINTEL_PCIE_ROM: - return "rom"; - case BTINTEL_PCIE_FW_DL: - return "fw_dl"; - case BTINTEL_PCIE_D0: - return "d0"; - case BTINTEL_PCIE_D3: - return "d3"; - case BTINTEL_PCIE_HCI_RESET: - return "hci_reset"; - case BTINTEL_PCIE_INTEL_HCI_RESET1: - return "intel_reset1"; - case BTINTEL_PCIE_INTEL_HCI_RESET2: - return "intel_reset2"; - default: - return "unknown"; - } -} - static int btintel_pcie_read_device_mem(struct btintel_pcie_data *data, void *buf, u32 dev_addr, int len) { @@ -1951,7 +1988,6 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, __u16 opcode = ~0; int ret; u32 type; - u32 old_ctxt; if (test_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags)) return -ENODEV; @@ -1988,12 +2024,6 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, btintel_pcie_inject_cmd_complete(hdev, opcode); } - /* Firmware raises alive interrupt on HCI_OP_RESET or - * BTINTEL_HCI_OP_RESET - */ - if (opcode == HCI_OP_RESET || opcode == BTINTEL_HCI_OP_RESET) - data->gp0_received = false; - hdev->stat.cmd_tx++; break; case HCI_ACLDATA_PKT: @@ -2011,37 +2041,14 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, bt_dev_err(hdev, "Unknown HCI packet type"); return -EILSEQ; } - memcpy(skb_push(skb, BTINTEL_PCIE_HCI_TYPE_LEN), &type, - BTINTEL_PCIE_HCI_TYPE_LEN); - ret = btintel_pcie_send_sync(data, skb); + ret = btintel_pcie_send_sync(data, skb, type, opcode); if (ret) { hdev->stat.err_tx++; bt_dev_err(hdev, "Failed to send frame (%d)", ret); goto exit_error; } - if (type == BTINTEL_PCIE_HCI_CMD_PKT && - (opcode == HCI_OP_RESET || opcode == BTINTEL_HCI_OP_RESET)) { - old_ctxt = data->alive_intr_ctxt; - data->alive_intr_ctxt = - (opcode == BTINTEL_HCI_OP_RESET ? BTINTEL_PCIE_INTEL_HCI_RESET1 : - BTINTEL_PCIE_HCI_RESET); - bt_dev_dbg(data->hdev, "sent cmd: 0x%4.4x alive context changed: %s -> %s", - opcode, btintel_pcie_alivectxt_state2str(old_ctxt), - btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); - ret = wait_event_timeout(data->gp0_wait_q, - data->gp0_received, - msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS)); - if (!ret) { - hdev->stat.err_tx++; - bt_dev_err(hdev, "Timeout on alive interrupt (%u ms). Alive context: %s", - BTINTEL_DEFAULT_INTR_TIMEOUT_MS, - btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); - ret = -ETIME; - goto exit_error; - } - } hdev->stat.byte_tx += skb->len; kfree_skb(skb); From 0cadf8534f2a727bc3a01e8c583b085d25963ee0 Mon Sep 17 00:00:00 2001 From: Chris Down Date: Mon, 21 Jul 2025 16:30:23 +0100 Subject: [PATCH 41/42] Bluetooth: hci_event: Mask data status from LE ext adv reports The Event_Type field in an LE Extended Advertising Report uses bits 5 and 6 for data status (e.g. truncation or fragmentation), not the PDU type itself. The ext_evt_type_to_legacy() function fails to mask these status bits before evaluation. This causes valid advertisements with status bits set (e.g. a truncated non-connectable advertisement, which ends up showing as PDU type 0x40) to be misclassified as unknown and subsequently dropped. This is okay for most checks which use bitwise AND on the relevant event type bits, but it doesn't work for non-connectable types, which are checked with '== LE_EXT_ADV_NON_CONN_IND' (that is, zero). In terms of behaviour, first the device sends a truncated report: > HCI Event: LE Meta Event (0x3e) plen 26 LE Extended Advertising Report (0x0d) Entry 0 Event type: 0x0040 Data status: Incomplete, data truncated, no more to come Address type: Random (0x01) Address: 1D:12:46:FA:F8:6E (Non-Resolvable) SID: 0x03 RSSI: -98 dBm (0x9e) Data length: 0x00 Then, a few seconds later, it sends the subsequent complete report: > HCI Event: LE Meta Event (0x3e) plen 122 LE Extended Advertising Report (0x0d) Entry 0 Event type: 0x0000 Data status: Complete Address type: Random (0x01) Address: 1D:12:46:FA:F8:6E (Non-Resolvable) SID: 0x03 RSSI: -97 dBm (0x9f) Data length: 0x60 Service Data: Google (0xfef3) Data[92]: ... These devices often send multiple truncated reports per second. This patch introduces a PDU type mask to ensure only the relevant bits are evaluated, allowing for the correct translation of all valid extended advertising packets. Fixes: b2cc9761f144 ("Bluetooth: Handle extended ADV PDU types") Signed-off-by: Chris Down Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_event.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 94f365b75166..e90a7b753926 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -2634,6 +2634,7 @@ struct hci_ev_le_conn_complete { #define LE_EXT_ADV_DIRECT_IND 0x0004 #define LE_EXT_ADV_SCAN_RSP 0x0008 #define LE_EXT_ADV_LEGACY_PDU 0x0010 +#define LE_EXT_ADV_DATA_STATUS_MASK 0x0060 #define LE_EXT_ADV_EVT_TYPE_MASK 0x007f #define ADDR_LE_DEV_PUBLIC 0x00 diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c0eb03e5cbf8..b7b473473b70 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -6239,6 +6239,11 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, void *data, static u8 ext_evt_type_to_legacy(struct hci_dev *hdev, u16 evt_type) { + u16 pdu_type = evt_type & ~LE_EXT_ADV_DATA_STATUS_MASK; + + if (!pdu_type) + return LE_ADV_NONCONN_IND; + if (evt_type & LE_EXT_ADV_LEGACY_PDU) { switch (evt_type) { case LE_LEGACY_ADV_IND: @@ -6270,8 +6275,7 @@ static u8 ext_evt_type_to_legacy(struct hci_dev *hdev, u16 evt_type) if (evt_type & LE_EXT_ADV_SCAN_IND) return LE_ADV_SCAN_IND; - if (evt_type == LE_EXT_ADV_NON_CONN_IND || - evt_type & LE_EXT_ADV_DIRECT_IND) + if (evt_type & LE_EXT_ADV_DIRECT_IND) return LE_ADV_NONCONN_IND; invalid: From a7bcffc673de219af2698fbb90627016233de67b Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 10 Jul 2025 18:52:47 +0800 Subject: [PATCH 42/42] Bluetooth: Add PA_LINK to distinguish BIG sync and PA sync connections Currently, BIS_LINK is used for both BIG sync and PA sync connections, which makes it impossible to distinguish them when searching for a PA sync connection. Adding PA_LINK will make the distinction clearer and simplify future extensions for PA-related features. Signed-off-by: Yang Li Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 10 +++++++--- net/bluetooth/hci_conn.c | 14 +++++++++----- net/bluetooth/hci_core.c | 27 +++++++++++++++------------ net/bluetooth/hci_event.c | 7 ++++--- net/bluetooth/hci_sync.c | 10 +++++----- net/bluetooth/iso.c | 6 ++++-- net/bluetooth/mgmt.c | 1 + 8 files changed, 46 insertions(+), 30 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index e90a7b753926..df1847b74e55 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -562,6 +562,7 @@ enum { #define LE_LINK 0x80 #define CIS_LINK 0x82 #define BIS_LINK 0x83 +#define PA_LINK 0x84 #define INVALID_LINK 0xff /* LMP features */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3728495f0819..4dc11c66f7b8 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1015,6 +1015,7 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) break; case CIS_LINK: case BIS_LINK: + case PA_LINK: h->iso_num++; break; } @@ -1042,6 +1043,7 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) break; case CIS_LINK: case BIS_LINK: + case PA_LINK: h->iso_num--; break; } @@ -1060,6 +1062,7 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type) return h->sco_num; case CIS_LINK: case BIS_LINK: + case PA_LINK: return h->iso_num; default: return 0; @@ -1142,7 +1145,7 @@ hci_conn_hash_lookup_create_pa_sync(struct hci_dev *hdev) rcu_read_lock(); list_for_each_entry_rcu(c, &h->list, list) { - if (c->type != BIS_LINK) + if (c->type != PA_LINK) continue; if (!test_bit(HCI_CONN_CREATE_PA_SYNC, &c->flags)) @@ -1337,7 +1340,7 @@ hci_conn_hash_lookup_big_sync_pend(struct hci_dev *hdev, rcu_read_lock(); list_for_each_entry_rcu(c, &h->list, list) { - if (c->type != BIS_LINK) + if (c->type != PA_LINK) continue; if (handle == c->iso_qos.bcast.big && num_bis == c->num_bis) { @@ -1407,7 +1410,7 @@ hci_conn_hash_lookup_pa_sync_handle(struct hci_dev *hdev, __u16 sync_handle) rcu_read_lock(); list_for_each_entry_rcu(c, &h->list, list) { - if (c->type != BIS_LINK) + if (c->type != PA_LINK) continue; /* Ignore the listen hcon, we are looking @@ -2006,6 +2009,7 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, case CIS_LINK: case BIS_LINK: + case PA_LINK: return iso_connect_ind(hdev, bdaddr, flags); default: diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b2e09e7f70e1..7d1e79f69cd1 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -785,7 +785,7 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *c d->sync_handle = conn->sync_handle; if (test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) { - hci_conn_hash_list_flag(hdev, find_bis, BIS_LINK, + hci_conn_hash_list_flag(hdev, find_bis, PA_LINK, HCI_CONN_PA_SYNC, d); if (!d->count) @@ -914,6 +914,7 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t break; case CIS_LINK: case BIS_LINK: + case PA_LINK: if (hdev->iso_mtu) /* Dedicated ISO Buffer exists */ break; @@ -979,6 +980,7 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t break; case CIS_LINK: case BIS_LINK: + case PA_LINK: /* conn->src should reflect the local identity address */ hci_copy_identity_address(hdev, &conn->src, &conn->src_type); @@ -1033,7 +1035,6 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t } hci_conn_init_sysfs(conn); - return conn; } @@ -1077,6 +1078,7 @@ static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason) break; case CIS_LINK: case BIS_LINK: + case PA_LINK: if ((conn->state != BT_CONNECTED && !test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) || test_bit(HCI_CONN_BIG_CREATED, &conn->flags)) @@ -1152,7 +1154,8 @@ void hci_conn_del(struct hci_conn *conn) } else { /* Unacked ISO frames */ if (conn->type == CIS_LINK || - conn->type == BIS_LINK) { + conn->type == BIS_LINK || + conn->type == PA_LINK) { if (hdev->iso_pkts) hdev->iso_cnt += conn->sent; else if (hdev->le_pkts) @@ -2081,7 +2084,7 @@ struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, bt_dev_dbg(hdev, "dst %pMR type %d sid %d", dst, dst_type, sid); - conn = hci_conn_add_unset(hdev, BIS_LINK, dst, HCI_ROLE_SLAVE); + conn = hci_conn_add_unset(hdev, PA_LINK, dst, HCI_ROLE_SLAVE); if (IS_ERR(conn)) return conn; @@ -2246,7 +2249,7 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, * the start periodic advertising and create BIG commands have * been queued */ - hci_conn_hash_list_state(hdev, bis_mark_per_adv, BIS_LINK, + hci_conn_hash_list_state(hdev, bis_mark_per_adv, PA_LINK, BT_BOUND, &data); /* Queue start periodic advertising and create BIG */ @@ -2980,6 +2983,7 @@ void hci_conn_tx_queue(struct hci_conn *conn, struct sk_buff *skb) switch (conn->type) { case CIS_LINK: case BIS_LINK: + case PA_LINK: case ACL_LINK: case LE_LINK: break; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f2fbe9c8e1be..55e0722fd066 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2936,12 +2936,14 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb) case HCI_ACLDATA_PKT: /* Detect if ISO packet has been sent as ACL */ if (hci_conn_num(hdev, CIS_LINK) || - hci_conn_num(hdev, BIS_LINK)) { + hci_conn_num(hdev, BIS_LINK) || + hci_conn_num(hdev, PA_LINK)) { __u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle); __u8 type; type = hci_conn_lookup_type(hdev, hci_handle(handle)); - if (type == CIS_LINK || type == BIS_LINK) + if (type == CIS_LINK || type == BIS_LINK || + type == PA_LINK) hci_skb_pkt_type(skb) = HCI_ISODATA_PKT; } break; @@ -3396,6 +3398,7 @@ static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote) break; case CIS_LINK: case BIS_LINK: + case PA_LINK: cnt = hdev->iso_mtu ? hdev->iso_cnt : hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt; break; @@ -3409,7 +3412,7 @@ static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote) } static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, - __u8 type2, int *quote) + int *quote) { struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn *conn = NULL, *c; @@ -3421,7 +3424,7 @@ static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, rcu_read_lock(); list_for_each_entry_rcu(c, &h->list, list) { - if ((c->type != type && c->type != type2) || + if (c->type != type || skb_queue_empty(&c->data_q)) continue; @@ -3625,7 +3628,7 @@ static void hci_sched_sco(struct hci_dev *hdev, __u8 type) else cnt = &hdev->sco_cnt; - while (*cnt && (conn = hci_low_sent(hdev, type, type, "e))) { + while (*cnt && (conn = hci_low_sent(hdev, type, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); hci_send_conn_frame(hdev, conn, skb); @@ -3744,8 +3747,8 @@ static void hci_sched_le(struct hci_dev *hdev) hci_prio_recalculate(hdev, LE_LINK); } -/* Schedule CIS */ -static void hci_sched_iso(struct hci_dev *hdev) +/* Schedule iso */ +static void hci_sched_iso(struct hci_dev *hdev, __u8 type) { struct hci_conn *conn; struct sk_buff *skb; @@ -3753,14 +3756,12 @@ static void hci_sched_iso(struct hci_dev *hdev) BT_DBG("%s", hdev->name); - if (!hci_conn_num(hdev, CIS_LINK) && - !hci_conn_num(hdev, BIS_LINK)) + if (!hci_conn_num(hdev, type)) return; cnt = hdev->iso_pkts ? &hdev->iso_cnt : hdev->le_pkts ? &hdev->le_cnt : &hdev->acl_cnt; - while (*cnt && (conn = hci_low_sent(hdev, CIS_LINK, BIS_LINK, - "e))) { + while (*cnt && (conn = hci_low_sent(hdev, type, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); hci_send_conn_frame(hdev, conn, skb); @@ -3785,7 +3786,9 @@ static void hci_tx_work(struct work_struct *work) /* Schedule queues and send stuff to HCI driver */ hci_sched_sco(hdev, SCO_LINK); hci_sched_sco(hdev, ESCO_LINK); - hci_sched_iso(hdev); + hci_sched_iso(hdev, CIS_LINK); + hci_sched_iso(hdev, BIS_LINK); + hci_sched_iso(hdev, PA_LINK); hci_sched_acl(hdev); hci_sched_le(hdev); } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b7b473473b70..8aa5039b975a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4432,6 +4432,7 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data, case CIS_LINK: case BIS_LINK: + case PA_LINK: if (hdev->iso_pkts) { hdev->iso_cnt += count; if (hdev->iso_cnt > hdev->iso_pkts) @@ -6381,7 +6382,7 @@ static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data, conn->sync_handle = le16_to_cpu(ev->handle); conn->sid = HCI_SID_INVALID; - mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, BIS_LINK, + mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, PA_LINK, &flags); if (!(mask & HCI_LM_ACCEPT)) { hci_le_pa_term_sync(hdev, ev->handle); @@ -6392,7 +6393,7 @@ static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data, goto unlock; /* Add connection to indicate PA sync event */ - pa_sync = hci_conn_add_unset(hdev, BIS_LINK, BDADDR_ANY, + pa_sync = hci_conn_add_unset(hdev, PA_LINK, BDADDR_ANY, HCI_ROLE_SLAVE); if (IS_ERR(pa_sync)) @@ -6423,7 +6424,7 @@ static void hci_le_per_adv_report_evt(struct hci_dev *hdev, void *data, hci_dev_lock(hdev); - mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, BIS_LINK, &flags); + mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, PA_LINK, &flags); if (!(mask & HCI_LM_ACCEPT)) goto unlock; diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index e9df6502e58e..2b4f21fbf9c1 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -2929,7 +2929,7 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type, if (sent) { struct hci_conn *conn; - conn = hci_conn_hash_lookup_ba(hdev, BIS_LINK, + conn = hci_conn_hash_lookup_ba(hdev, PA_LINK, &sent->bdaddr); if (conn) { struct bt_iso_qos *qos = &conn->iso_qos; @@ -5493,7 +5493,7 @@ static int hci_disconnect_sync(struct hci_dev *hdev, struct hci_conn *conn, { struct hci_cp_disconnect cp; - if (conn->type == BIS_LINK) { + if (conn->type == BIS_LINK || conn->type == PA_LINK) { /* This is a BIS connection, hci_conn_del will * do the necessary cleanup. */ @@ -5562,7 +5562,7 @@ static int hci_connect_cancel_sync(struct hci_dev *hdev, struct hci_conn *conn, return HCI_ERROR_LOCAL_HOST_TERM; } - if (conn->type == BIS_LINK) { + if (conn->type == BIS_LINK || conn->type == PA_LINK) { /* There is no way to cancel a BIS without terminating the BIG * which is done later on connection cleanup. */ @@ -5627,7 +5627,7 @@ static int hci_reject_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, if (conn->type == CIS_LINK) return hci_le_reject_cis_sync(hdev, conn, reason); - if (conn->type == BIS_LINK) + if (conn->type == BIS_LINK || conn->type == PA_LINK) return -EINVAL; if (conn->type == SCO_LINK || conn->type == ESCO_LINK) @@ -6994,7 +6994,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err) goto unlock; /* Add connection to indicate PA sync error */ - pa_sync = hci_conn_add_unset(hdev, BIS_LINK, BDADDR_ANY, + pa_sync = hci_conn_add_unset(hdev, PA_LINK, BDADDR_ANY, HCI_ROLE_SLAVE); if (IS_ERR(pa_sync)) diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 2f45e46a9b6a..7bd3aa0a6db9 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -2237,7 +2237,8 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) static void iso_connect_cfm(struct hci_conn *hcon, __u8 status) { - if (hcon->type != CIS_LINK && hcon->type != BIS_LINK) { + if (hcon->type != CIS_LINK && hcon->type != BIS_LINK && + hcon->type != PA_LINK) { if (hcon->type != LE_LINK) return; @@ -2278,7 +2279,8 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status) static void iso_disconn_cfm(struct hci_conn *hcon, __u8 reason) { - if (hcon->type != CIS_LINK && hcon->type != BIS_LINK) + if (hcon->type != CIS_LINK && hcon->type != BIS_LINK && + hcon->type != PA_LINK) return; BT_DBG("hcon %p reason %d", hcon, reason); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 63dba0503653..1ce682038b51 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3237,6 +3237,7 @@ static u8 link_to_bdaddr(u8 link_type, u8 addr_type) switch (link_type) { case CIS_LINK: case BIS_LINK: + case PA_LINK: case LE_LINK: switch (addr_type) { case ADDR_LE_DEV_PUBLIC: