From 2d00975c841fa2e52921353392ce9780843bfee7 Mon Sep 17 00:00:00 2001 From: Chandrashekar Devegowda Date: Mon, 13 Apr 2026 09:50:40 +0530 Subject: [PATCH 01/49] Bluetooth: btintel_pcie: Support Product level reset When driver encounters a TOP exception, ACPI methods will be called for Product level reset since Wifi and BT share the same TOP. BT driver will first reprobe the wifi driver and then reprobe BT. Signed-off-by: Chandrashekar Devegowda Signed-off-by: Venkat Rao Bagalkote Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/Kconfig | 2 +- drivers/bluetooth/btintel.c | 10 +- drivers/bluetooth/btintel.h | 7 ++ drivers/bluetooth/btintel_pcie.c | 205 ++++++++++++++++++++++++++----- drivers/bluetooth/btintel_pcie.h | 7 ++ 5 files changed, 195 insertions(+), 36 deletions(-) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index c5d45cf91f88..fc1b37044a9b 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -502,7 +502,7 @@ config BT_NXPUART config BT_INTEL_PCIE tristate "Intel HCI PCIe driver" - depends on PCI + depends on PCI && ACPI select BT_INTEL select FW_LOADER help diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index dcaaa4ca02b9..5e9cac090bd8 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -67,9 +67,10 @@ static struct { u32 fw_build_num; } coredump_info; -static const guid_t btintel_guid_dsm = +const guid_t btintel_guid_dsm = GUID_INIT(0xaa10f4e0, 0x81ac, 0x4233, 0xab, 0xf6, 0x3b, 0x2a, 0xc5, 0x0e, 0x28, 0xd9); +EXPORT_SYMBOL_GPL(btintel_guid_dsm); int btintel_check_bdaddr(struct hci_dev *hdev) { @@ -2624,7 +2625,7 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver kfree_skb(skb); } -static int btintel_acpi_reset_method(struct hci_dev *hdev) +int btintel_acpi_reset_method(struct hci_dev *hdev) { int ret = 0; acpi_status status; @@ -2632,14 +2633,14 @@ static int btintel_acpi_reset_method(struct hci_dev *hdev) struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; status = acpi_evaluate_object(ACPI_HANDLE(GET_HCIDEV_DEV(hdev)), "_PRR", NULL, &buffer); - if (ACPI_FAILURE(status)) { + if (ACPI_FAILURE(status) || !buffer.pointer) { bt_dev_err(hdev, "Failed to run _PRR method"); ret = -ENODEV; return ret; } p = buffer.pointer; - if (p->package.count != 1 || p->type != ACPI_TYPE_PACKAGE) { + if (p->type != ACPI_TYPE_PACKAGE || p->package.count != 1) { bt_dev_err(hdev, "Invalid arguments"); ret = -EINVAL; goto exit_on_error; @@ -2663,6 +2664,7 @@ exit_on_error: kfree(buffer.pointer); return ret; } +EXPORT_SYMBOL_GPL(btintel_acpi_reset_method); static void btintel_set_dsm_reset_method(struct hci_dev *hdev, struct intel_version_tlv *ver_tlv) diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 0e9ca99aaaae..70d812ad36a2 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -79,6 +79,8 @@ struct intel_tlv { #define BTINTEL_HWID_SCP2 0x20 /* Scorpius Peak2 - Nova Lake */ #define BTINTEL_HWID_BZRIW 0x22 /* BlazarIW - Wildcat Lake */ +extern const guid_t btintel_guid_dsm; + struct intel_version_tlv { u32 cnvi_top; u32 cnvr_top; @@ -289,6 +291,7 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev, int btintel_shutdown_combined(struct hci_dev *hdev); void btintel_hw_error(struct hci_dev *hdev, u8 code); void btintel_print_fseq_info(struct hci_dev *hdev); +int btintel_acpi_reset_method(struct hci_dev *hdev); #else static inline int btintel_check_bdaddr(struct hci_dev *hdev) @@ -422,4 +425,8 @@ static inline void btintel_hw_error(struct hci_dev *hdev, u8 code) static inline void btintel_print_fseq_info(struct hci_dev *hdev) { } +static inline int btintel_acpi_reset_method(struct hci_dev *hdev) +{ + return -ENODEV; +} #endif diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 37e050763633..0a6e8481104e 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -102,6 +103,22 @@ enum { BTINTEL_PCIE_D3 }; +enum { + BTINTEL_PCIE_DSM_SET_RESET_TIMING = 1, + BTINTEL_PCIE_DSM_GET_RESET_TIMING = 2, + BTINTEL_PCIE_DSM_BT_PLDR_CONFIG = 3, + BTINTEL_PCIE_DSM_GET_RESET_TYPE = 4, + BTINTEL_PCIE_DSM_DYNAMIC_PLDR = 5, + BTINTEL_PCIE_DSM_GET_RESET_METHOD = 6, + BTINTEL_PCIE_DSM_SET_PLDR_DELAY = 7, +}; + +enum btintel_dsm_internal_product_reset_mode { + BTINTEL_PCIE_DSM_PLDR_MODE_EN_PROD_RESET = BIT(0), + BTINTEL_PCIE_DSM_PLDR_MODE_EN_WIFI_FLR = BIT(1), + BTINTEL_PCIE_DSM_PLDR_MODE_EN_BT_OFF_ON = BIT(2), +}; + /* Structure for dbgc fragment buffer * @buf_addr_lsb: LSB of the buffer's physical address * @buf_addr_msb: MSB of the buffer's physical address @@ -128,11 +145,6 @@ 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_recovery_list); static DEFINE_SPINLOCK(btintel_pcie_recovery_lock); @@ -2265,21 +2277,130 @@ static void btintel_pcie_inc_recovery_count(struct pci_dev *pdev, } static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data); +static void btintel_pcie_reset(struct hci_dev *hdev); -static void btintel_pcie_removal_work(struct work_struct *wk) +static int btintel_pcie_acpi_reset_method(struct btintel_pcie_data *data) { - struct btintel_pcie_removal *removal = - container_of(wk, struct btintel_pcie_removal, work); - struct pci_dev *pdev = removal->pdev; - struct btintel_pcie_data *data; + union acpi_object *obj, argv4; + acpi_handle handle; + int ret; + struct pldr_mode { + __le16 cmd_type; + __le16 cmd_payload; + } __packed; + + /* set 1 for _PRR mode + * Product Reset (PLDR Abort flow) + */ + static const struct pldr_mode mode = { + .cmd_type = cpu_to_le16(1), + .cmd_payload = cpu_to_le16(BTINTEL_PCIE_DSM_PLDR_MODE_EN_PROD_RESET | + BTINTEL_PCIE_DSM_PLDR_MODE_EN_WIFI_FLR), + }; + struct hci_dev *hdev = data->hdev; + + handle = ACPI_HANDLE(GET_HCIDEV_DEV(data->hdev)); + if (!handle) { + bt_dev_err(data->hdev, "No support for bluetooth device in ACPI firmware"); + return -EACCES; + } + + if (!acpi_has_method(handle, "_PRR")) { + bt_dev_err(data->hdev, "No support for _PRR ACPI method, cold boot"); + return -ENODEV; + } + + argv4.buffer.type = ACPI_TYPE_BUFFER; + argv4.buffer.length = sizeof(mode); + argv4.buffer.pointer = (void *)&mode; + + obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0, + BTINTEL_PCIE_DSM_DYNAMIC_PLDR, &argv4); + if (!obj) { + bt_dev_err(data->hdev, "Failed to call dsm to set reset method"); + return -EIO; + } + ACPI_FREE(obj); + + pci_dev_lock(data->pdev); + pci_save_state(data->pdev); + ret = btintel_acpi_reset_method(hdev); + if (ret) + bt_dev_err(data->hdev, "ACPI _PRR reset failed (%d), PLDR incomplete", + ret); + pci_restore_state(data->pdev); + pci_dev_unlock(data->pdev); + return ret; +} + +static void btintel_pcie_perform_pldr(struct btintel_pcie_data *data) +{ + struct pci_dev *pdev = data->pdev; + struct pci_dev *wifi = NULL; + struct pci_bus *bus; + int ret; + /* on integrated we have to look up by ID (same bus) */ + static const struct pci_device_id wifi_device_ids[] = { + #define WIFI_DEV(_id) { PCI_DEVICE(PCI_VENDOR_ID_INTEL, _id) } + WIFI_DEV(0xA840), /* LNL */ + WIFI_DEV(0xE440), /* PTL-P */ + WIFI_DEV(0xE340), /* PTL-H */ + WIFI_DEV(0xD340), /* NVL-H */ + WIFI_DEV(0x6E70), /* NVL-S */ + WIFI_DEV(0x4D40), /* WCL */ + {} + }; + struct pci_dev *tmp = NULL; + + bus = pdev->bus; + if (!bus) + return; + + list_for_each_entry(tmp, &bus->devices, bus_list) { + if (pci_match_id(wifi_device_ids, tmp)) { + wifi = pci_dev_get(tmp); + break; + } + } + + if (wifi) + device_release_driver(&wifi->dev); + + /* Wi-Fi is fully unbound before the reset and fully reprobed after + * the normal PCI probe path handles all state setup from scratch. + * BT needs pci_save_state()/pci_restore_state() because the BT driver + * is still partially attached when the _PRR runs (it hasn't been unbound yet). + * The PCI device needs to remain minimally functional so that + * device_reprobe(&pdev->dev) can work afterward + */ + ret = btintel_pcie_acpi_reset_method(data); + + if (wifi) { + if (device_reprobe(&wifi->dev)) + BT_ERR("WiFi reprobe failed for BDF:%s", pci_name(wifi)); + pci_dev_put(wifi); + } + + if (!ret) { + if (device_reprobe(&pdev->dev)) + BT_ERR("BT reprobe failed for BDF:%s", pci_name(pdev)); + } +} + +static void btintel_pcie_reset_work(struct work_struct *wk) +{ + struct btintel_pcie_data *data = + container_of(wk, struct btintel_pcie_data, reset_work); + struct pci_dev *pdev = data->pdev; int err; pci_lock_rescan_remove(); if (!pdev->bus) - goto error; + goto out; - data = pci_get_drvdata(pdev); + if (!data) + goto out; btintel_pcie_disable_interrupts(data); btintel_pcie_synchronize_irqs(data); @@ -2287,12 +2408,21 @@ static void btintel_pcie_removal_work(struct work_struct *wk) flush_work(&data->rx_work); bt_dev_dbg(data->hdev, "Release bluetooth interface"); + if (data->reset_type == BTINTEL_PCIE_IOSF_PRR_PLDR) { + /* This function holds pci_lock_rescan_remove(), which acquires + * pci_rescan_remove_lock. This mutex serializes against PCI device + * addition/removal (hotplug), so no device can be added to or + * removed from the bus list while this code runs. + */ + btintel_pcie_perform_pldr(data); + goto out; + } btintel_pcie_release_hdev(data); err = pci_reset_function(pdev); if (err) { BT_ERR("Failed resetting the pcie device (%d)", err); - goto error; + goto out; } btintel_pcie_enable_interrupts(data); @@ -2302,7 +2432,7 @@ static void btintel_pcie_removal_work(struct work_struct *wk) if (err) { BT_ERR("Failed to enable bluetooth hardware after reset (%d)", err); - goto error; + goto out; } btintel_pcie_reset_ia(data); @@ -2312,17 +2442,15 @@ static void btintel_pcie_removal_work(struct work_struct *wk) err = btintel_pcie_setup_hdev(data); if (err) { BT_ERR("Failed registering hdev (%d)", err); - goto error; + goto out; } -error: +out: 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); @@ -2333,14 +2461,8 @@ static void btintel_pcie_reset(struct hci_dev *hdev) if (test_and_set_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags)) return; - removal = kzalloc_obj(*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); + pci_dev_get(data->pdev); + schedule_work(&data->reset_work); } static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code) @@ -2350,15 +2472,19 @@ static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code) struct pci_dev *pdev = dev_data->pdev; time64_t retry_window; - if (code == 0x13) { - bt_dev_err(hdev, "Encountered top exception"); - return; - } + btintel_pcie_dump_debug_registers(hdev); data = btintel_pcie_get_recovery(pdev, &hdev->dev); if (!data) return; + if (code == 0x13) + dev_data->reset_type = BTINTEL_PCIE_IOSF_PRR_PLDR; + else + dev_data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR; + + bt_dev_err(hdev, "Encountered exception err:0x%x triggering: %s", code, + dev_data->reset_type == BTINTEL_PCIE_IOSF_PRR_PLDR ? "PLDR" : "FLR"); retry_window = ktime_get_boottime_seconds() - data->last_error; if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS && @@ -2511,10 +2637,14 @@ static int btintel_pcie_probe(struct pci_dev *pdev, skb_queue_head_init(&data->rx_skb_q); INIT_WORK(&data->rx_work, btintel_pcie_rx_work); + INIT_WORK(&data->reset_work, btintel_pcie_reset_work); data->boot_stage_cache = 0x00; data->img_resp_cache = 0x00; - + /* FLR can be invoked by echoing to debugfs path, so explicitly + * initialized + */ + data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR; err = btintel_pcie_config_pcie(pdev, data); if (err) goto exit_error; @@ -2562,6 +2692,18 @@ static void btintel_pcie_remove(struct pci_dev *pdev) struct btintel_pcie_data *data; data = pci_get_drvdata(pdev); + if (!data) { + BT_WARN("PCI driver data is NULL, aborting remove"); + return; + } + + /* Cancel pending reset work. Skip only when remove() is called from + * within the reset work itself (PLDR device_reprobe path) to avoid + * deadlock. current_work() returns the work_struct of the caller if + * we are in a workqueue context. + */ + if (current_work() != &data->reset_work) + cancel_work_sync(&data->reset_work); btintel_pcie_disable_interrupts(data); @@ -2712,6 +2854,7 @@ static int btintel_pcie_resume(struct device *dev) if (data->pm_sx_event == PM_EVENT_FREEZE || data->pm_sx_event == PM_EVENT_HIBERNATE) { set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags); + data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR; btintel_pcie_reset(data->hdev); return 0; } diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index 13efef499e4e..7fc8c46ed689 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -141,6 +141,11 @@ enum msix_mbox_int_causes { BTINTEL_PCIE_CSR_MBOX_STATUS_MBOX4 = BIT(3), /* cause MBOX4 */ }; +enum btintel_pcie_reset_type { + BTINTEL_PCIE_IOSF_PRR_FLR = 0, + BTINTEL_PCIE_IOSF_PRR_PLDR = 1, +}; + #define BTINTEL_PCIE_MSIX_NON_AUTO_CLEAR_CAUSE BIT(7) /* Minimum and Maximum number of MSI-X Vector @@ -497,6 +502,7 @@ struct btintel_pcie_data { struct workqueue_struct *workqueue; struct sk_buff_head rx_skb_q; struct work_struct rx_work; + struct work_struct reset_work; struct dma_pool *dma_pool; dma_addr_t dma_p_addr; @@ -508,6 +514,7 @@ struct btintel_pcie_data { struct txq txq; struct rxq rxq; u32 alive_intr_ctxt; + enum btintel_pcie_reset_type reset_type; struct btintel_pcie_dbgc dbgc; struct btintel_pcie_dump_header dmp_hdr; u8 pm_sx_event; From fd5dc066b43eb8ae63f713aef704385c686b16e3 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Tue, 7 Apr 2026 14:50:53 +0800 Subject: [PATCH 02/49] Bluetooth: btusb: MT7922: Add VID/PID 0e8d/223c Add VID 0e8d & PID 223c for MediaTek MT7922 USB Bluetooth chip. The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below. T: Bus=07 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0e8d ProdID=223c 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: Chris Lu Reviewed-by: Paul Menzel 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 830fefb342c6..54dc940af6a7 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -723,6 +723,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0e8d, 0x223c), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3584), .driver_info = BTUSB_MEDIATEK | From 69b2f05df3ee63e1273608cdb81a7d664e9de2b8 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Tue, 7 Apr 2026 14:51:10 +0800 Subject: [PATCH 03/49] Bluetooth: btusb: MT7925: Add VID/PID 0e8d/8c38 Add VID 0e8d & PID 8c38 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=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0e8d ProdID=8c38 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: Chris Lu 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 54dc940af6a7..7a59ed4fc42c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -775,6 +775,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe151), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0e8d, 0x8c38), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3602), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3603), .driver_info = BTUSB_MEDIATEK | From 47f4bf27eb5ab006b0022091c1ec1682acb7e800 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Thu, 16 Apr 2026 19:16:07 +0800 Subject: [PATCH 04/49] Bluetooth: btmtk: add event filter to filter specific event Add an event filter to filter event with specific opcode to prevent BT stack from receiving unexpected event. Event with opcode 0xfc5d is generated when MediaTek's Bluetooth enable firmware logs and is not expected to be sent to userspace. Signed-off-by: Chris Lu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btmtk.c | 23 +++++++++++++++++++++++ drivers/bluetooth/btmtk.h | 7 +++++++ drivers/bluetooth/btusb.c | 1 + 3 files changed, 31 insertions(+) diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index 8ff66b276af0..ea7a031000cd 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -1547,6 +1547,29 @@ int btmtk_usb_shutdown(struct hci_dev *hdev) return 0; } EXPORT_SYMBOL_GPL(btmtk_usb_shutdown); + +int btmtk_recv_event(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_event_hdr *hdr = (void *)skb->data; + struct hci_ev_cmd_complete *ec; + + if (hdr->evt == HCI_EV_CMD_COMPLETE && + skb->len >= HCI_EVENT_HDR_SIZE + sizeof(*ec)) { + u16 opcode; + + ec = (void *)(skb->data + HCI_EVENT_HDR_SIZE); + opcode = __le16_to_cpu(ec->opcode); + + /* Filter vendor opcode */ + if (opcode == 0xfc5d) { + kfree_skb(skb); + return 0; + } + } + + return hci_recv_frame(hdev, skb); +} +EXPORT_SYMBOL_GPL(btmtk_recv_event); #endif MODULE_AUTHOR("Sean Wang "); diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h index c564aedc0ce0..c83c24897c95 100644 --- a/drivers/bluetooth/btmtk.h +++ b/drivers/bluetooth/btmtk.h @@ -220,6 +220,8 @@ int btmtk_usb_suspend(struct hci_dev *hdev); int btmtk_usb_setup(struct hci_dev *hdev); int btmtk_usb_shutdown(struct hci_dev *hdev); + +int btmtk_recv_event(struct hci_dev *hdev, struct sk_buff *skb); #else static inline int btmtk_set_bdaddr(struct hci_dev *hdev, @@ -299,4 +301,9 @@ static inline int btmtk_usb_shutdown(struct hci_dev *hdev) { return -EOPNOTSUPP; } + +static inline int btmtk_recv_event(struct hci_dev *hdev, struct sk_buff *skb) +{ + return hci_recv_frame(hdev, skb); +} #endif diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 7a59ed4fc42c..525d70d9cf34 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -4252,6 +4252,7 @@ static int btusb_probe(struct usb_interface *intf, hci_set_quirk(hdev, HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN); hci_set_quirk(hdev, HCI_QUIRK_NON_PERSISTENT_SETUP); data->recv_acl = btmtk_usb_recv_acl; + data->recv_event = btmtk_recv_event; data->suspend = btmtk_usb_suspend; data->resume = btmtk_usb_resume; data->disconnect = btusb_mtk_disconnect; From 9707a015fe8f3ba8ec7c270f3b2b8efb38823d6b Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Sat, 11 Apr 2026 21:15:09 +0300 Subject: [PATCH 05/49] Bluetooth: 6lowpan: fix cyclic locking warning on netdev unregister 6lowpan.c has theoretically conflicting lock orderings, which lockdep complains about: a) rtnl_lock > hdev->workqueue from 6lowpan.c:delete_netdev -> rtnl_lock -> device_del -> put_device(parent) -> hci_release_dev -> destroy_workqueue b) hdev->workqueue > l2cap_conn->lock > chan->lock > rtnl_lock from hci_rx_work -> 6lowpan.c:chan_ready_cb -> lowpan_register_netdev, ifup -> rtnl_lock Actual deadlock appears not possible, as hci_rx_work is disabled and l2cap_conn flushed already on hdev unregister. Hence, do minimal thing to make lockdep happy by breaking chain a) by holding hdev refcount until after netdev put in 6lowpan.c. Fixes the lockdep complaint: WARNING: possible circular locking dependency detected. kworker/0:1/11 is trying to acquire lock: ffff8880023b3940 ((wq_completion)hci0#2){+.+.}-{0:0}, at: touch_wq_lockdep_map+0x8b/0x130 but task is already holding lock: ffffffff95e4f9c0 (rtnl_mutex){+.+.}-{4:4}, at: lowpan_unregister_netdev+0xd/0x30 Workqueue: events delete_netdev Signed-off-by: Pauli Virtanen Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/6lowpan.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 960a19b3e26d..cb1e329d66fd 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -760,13 +760,33 @@ static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan) return chan; } +static void unregister_dev(struct lowpan_btle_dev *dev) +{ + struct hci_dev *hdev = READ_ONCE(dev->hdev); + + /* If netdev holds last reference to hci_dev (its parent device), this + * leads to theoretical cyclic locking on lowpan_unregister_netdev: + * + * rtnl_lock -> put_device(parent) -> hci_release_dev -> + * destroy_workqueue -> hci_rx_work -> l2cap_recv_acldata -> + * chan_ready_cb -> ifup -> rtnl_lock + * + * However, hci_rx_work is disabled in hci_unregister_dev, so this + * should not occur. Make lockdep happy by postponing hdev release after + * netdev put. + */ + hci_dev_hold(hdev); + lowpan_unregister_netdev(dev->netdev); + hci_dev_put(hdev); +} + static void delete_netdev(struct work_struct *work) { struct lowpan_btle_dev *entry = container_of(work, struct lowpan_btle_dev, delete_netdev); - lowpan_unregister_netdev(entry->netdev); + unregister_dev(entry); /* The entry pointer is deleted by the netdev destructor. */ } @@ -1252,6 +1272,7 @@ static void disconnect_devices(void) break; new_dev->netdev = entry->netdev; + new_dev->hdev = entry->hdev; INIT_LIST_HEAD(&new_dev->list); list_add_rcu(&new_dev->list, &devices); @@ -1263,7 +1284,7 @@ static void disconnect_devices(void) ifdown(entry->netdev); BT_DBG("Unregistering netdev %s %p", entry->netdev->name, entry->netdev); - lowpan_unregister_netdev(entry->netdev); + unregister_dev(entry); kfree(entry); } } From ce21a5cf3d1fd92b84ea9ad2b7c7240aff2162d2 Mon Sep 17 00:00:00 2001 From: Hrvoje Nuic Date: Wed, 22 Apr 2026 23:26:47 +0200 Subject: [PATCH 06/49] Bluetooth: btusb: Add Mercusys MA530 for Realtek RTL8761BUV Add the USB ID for the Mercusys MA530 Bluetooth adapter. The device uses a Realtek RTL8761BUV controller and works with the existing Realtek setup path. The device reports vendor ID 0x2c4e and product ID 0x0115, and loads the rtl_bt/rtl8761bu_fw.bin firmware successfully with this quirk. Signed-off-by: Hrvoje Nuic 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 525d70d9cf34..dfafdb76d1de 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -818,6 +818,8 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK }, /* Additional Realtek 8761BUV Bluetooth devices */ + { USB_DEVICE(0x2c4e, 0x0115), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x2357, 0x0604), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK | From 480dcc68f2826a9768e6fc9e81f02078c1ed0e01 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Fri, 24 Apr 2026 20:09:28 +0800 Subject: [PATCH 07/49] Bluetooth: btusb: Add Realtek RTL8922AE VID/PID 0bda/d922 Add the vendor/product ID (0x0bda, 0xd922) to usb_device_id table for Realtek RTL8922AE. The device info from /sys/kernel/debug/usb/devices as below. T: Bus=10 Lev=01 Prnt=01 Port=00 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=0bda ProdID=d922 Rev= 0.00 S: Manufacturer=Realtek S: Product=Bluetooth Radio S: SerialNumber=00E04C885A01 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 Signed-off-by: Chen Zhang Reviewed-by: Paul Menzel 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 dfafdb76d1de..286041b94cf9 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -601,6 +601,8 @@ static const struct usb_device_id quirks_table[] = { /* Realtek 8922AE Bluetooth devices */ { USB_DEVICE(0x0bda, 0x8922), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0bda, 0xd922), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3617), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3616), .driver_info = BTUSB_REALTEK | From 5612ee230a33c450976c3bcaea174f1d816a2697 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Fri, 24 Apr 2026 20:25:22 +0800 Subject: [PATCH 08/49] Bluetooth: btusb: Add Realtek RTL8922AE VID/PID 0bda/d923 Add the vendor/product ID (0x0bda, 0xd923) to usb_device_id table for Realtek RTL8922AE. The device info from /sys/kernel/debug/usb/devices as below. T: Bus=10 Lev=01 Prnt=01 Port=00 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=0bda ProdID=d923 Rev= 0.00 S: Manufacturer=Realtek S: Product=Bluetooth Radio S: SerialNumber=00E04C885A01 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 Signed-off-by: Chen Zhang Reviewed-by: Paul Menzel 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 286041b94cf9..70abbabea0a7 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -603,6 +603,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0bda, 0xd922), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0bda, 0xd923), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3617), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3616), .driver_info = BTUSB_REALTEK | From 73e44a7d605ba7385476633996174f690c2e9a90 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 21 Apr 2026 16:09:16 -0700 Subject: [PATCH 09/49] Bluetooth: Remove unneeded crypto kconfig selections Remove several kconfig selections that are no longer needed: - CRYPTO_SKCIPHER and CRYPTO_ECB have been unneeded since commit a4770e1117f1 ("Bluetooth: Switch SMP to crypto_cipher_encrypt_one()") in 2016. - CRYPTO_SHA256 has been unneeded since commit e7b02296fb40 ("Bluetooth: Remove BT_HS") in 2024. Signed-off-by: Eric Biggers Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index ee6457d1a5ee..5a8bf9106710 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -9,12 +9,9 @@ menuconfig BT depends on RFKILL || !RFKILL select CRC16 select CRYPTO - select CRYPTO_SKCIPHER select CRYPTO_LIB_AES imply CRYPTO_AES select CRYPTO_CMAC - select CRYPTO_ECB - select CRYPTO_SHA256 select CRYPTO_ECDH help Bluetooth is low-cost, low-power, short-range wireless technology. From 48788c8de7c8cb36afcf8daa2be4b5160398af40 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 21 Apr 2026 16:09:17 -0700 Subject: [PATCH 10/49] Bluetooth: SMP: Use AES-CMAC library API Now that AES-CMAC has a library API, convert net/bluetooth/smp.c to use it instead of the "cmac(aes)" crypto_shash. Since the library API doesn't require dynamic memory allocation, we no longer need to pass a crypto_shash object down the call stack and can simply allocate the aes_cmac_key on the stack in smp_aes_cmac() (renamed from aes_cmac()). The result is simpler and faster code that no longer relies on the error-prone loading of algorithms by name. Note that the maximum stack usage actually decreases slightly, despite the expanded AES key being moved to the stack. This is because the old code called crypto_shash_tfm_digest(), which allocates 384 bytes on the stack for a maximally-sized hash descriptor for any algorithm. The new code instead declares a 288-byte aes_cmac_key, then calls aes_cmac() which declares a 32-byte aes_cmac_ctx. Since 288 + 32 < 384, the maximum stack usage decreases. I.e. the entire expanded AES key easily fits in the space that the generic crypto API was wasting before. I didn't add zeroization of the aes_cmac_key, since smp_aes_cmac() already copies the raw key to the stack without zeroizing it. Reviewed-by: Ard Biesheuvel Signed-off-by: Eric Biggers Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/Kconfig | 3 +- net/bluetooth/smp.c | 180 +++++++++++++++--------------------------- 2 files changed, 65 insertions(+), 118 deletions(-) diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 5a8bf9106710..d250e94e90eb 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -10,8 +10,7 @@ menuconfig BT select CRC16 select CRYPTO select CRYPTO_LIB_AES - imply CRYPTO_AES - select CRYPTO_CMAC + select CRYPTO_LIB_AES_CBC_MACS select CRYPTO_ECDH help Bluetooth is low-cost, low-power, short-range wireless technology. diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 98f1da4f5f55..1739c1989dbd 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -22,8 +22,8 @@ #include #include +#include #include -#include #include #include @@ -63,7 +63,7 @@ 0x3f : 0x07) #define KEY_DIST_MASK 0x07 -/* Maximum message length that can be passed to aes_cmac */ +/* Maximum message length that can be passed to smp_aes_cmac */ #define CMAC_MSG_MAX 80 enum { @@ -89,7 +89,6 @@ struct smp_dev { u8 local_rand[16]; bool debug_key; - struct crypto_shash *tfm_cmac; struct crypto_kpp *tfm_ecdh; }; @@ -127,7 +126,6 @@ struct smp_chan { u8 dhkey[32]; u8 mackey[16]; - struct crypto_shash *tfm_cmac; struct crypto_kpp *tfm_ecdh; }; @@ -166,20 +164,15 @@ static inline void swap_buf(const u8 *src, u8 *dst, size_t len) * AES-CMAC, f4, f5, f6, g2 and h6. */ -static int aes_cmac(struct crypto_shash *tfm, const u8 k[16], const u8 *m, - size_t len, u8 mac[16]) +static int smp_aes_cmac(const u8 k[16], const u8 *m, size_t len, u8 mac[16]) { uint8_t tmp[16], mac_msb[16], msg_msb[CMAC_MSG_MAX]; + struct aes_cmac_key key; int err; if (len > CMAC_MSG_MAX) return -EFBIG; - if (!tfm) { - BT_ERR("tfm %p", tfm); - return -EINVAL; - } - /* Swap key and message from LSB to MSB */ swap_buf(k, tmp, 16); swap_buf(m, msg_msb, len); @@ -187,17 +180,10 @@ static int aes_cmac(struct crypto_shash *tfm, const u8 k[16], const u8 *m, SMP_DBG("msg (len %zu) %*phN", len, (int) len, m); SMP_DBG("key %16phN", k); - err = crypto_shash_setkey(tfm, tmp, 16); - if (err) { - BT_ERR("cipher setkey failed: %d", err); + err = aes_cmac_preparekey(&key, tmp, 16); + if (WARN_ON_ONCE(err)) /* Should never happen, as 16 is valid keylen */ return err; - } - - err = crypto_shash_tfm_digest(tfm, msg_msb, len, mac_msb); - if (err) { - BT_ERR("Hash computation error %d", err); - return err; - } + aes_cmac(&key, msg_msb, len, mac_msb); swap_buf(mac_msb, mac, 16); @@ -206,8 +192,8 @@ static int aes_cmac(struct crypto_shash *tfm, const u8 k[16], const u8 *m, return 0; } -static int smp_f4(struct crypto_shash *tfm_cmac, const u8 u[32], - const u8 v[32], const u8 x[16], u8 z, u8 res[16]) +static int smp_f4(const u8 u[32], const u8 v[32], const u8 x[16], u8 z, + u8 res[16]) { u8 m[65]; int err; @@ -220,7 +206,7 @@ static int smp_f4(struct crypto_shash *tfm_cmac, const u8 u[32], memcpy(m + 1, v, 32); memcpy(m + 33, u, 32); - err = aes_cmac(tfm_cmac, x, m, sizeof(m), res); + err = smp_aes_cmac(x, m, sizeof(m), res); if (err) return err; @@ -229,9 +215,8 @@ static int smp_f4(struct crypto_shash *tfm_cmac, const u8 u[32], return err; } -static int smp_f5(struct crypto_shash *tfm_cmac, const u8 w[32], - const u8 n1[16], const u8 n2[16], const u8 a1[7], - const u8 a2[7], u8 mackey[16], u8 ltk[16]) +static int smp_f5(const u8 w[32], const u8 n1[16], const u8 n2[16], + const u8 a1[7], const u8 a2[7], u8 mackey[16], u8 ltk[16]) { /* The btle, salt and length "magic" values are as defined in * the SMP section of the Bluetooth core specification. In ASCII @@ -250,7 +235,7 @@ static int smp_f5(struct crypto_shash *tfm_cmac, const u8 w[32], SMP_DBG("n1 %16phN n2 %16phN", n1, n2); SMP_DBG("a1 %7phN a2 %7phN", a1, a2); - err = aes_cmac(tfm_cmac, salt, w, 32, t); + err = smp_aes_cmac(salt, w, 32, t); if (err) return err; @@ -265,7 +250,7 @@ static int smp_f5(struct crypto_shash *tfm_cmac, const u8 w[32], m[52] = 0; /* Counter */ - err = aes_cmac(tfm_cmac, t, m, sizeof(m), mackey); + err = smp_aes_cmac(t, m, sizeof(m), mackey); if (err) return err; @@ -273,7 +258,7 @@ static int smp_f5(struct crypto_shash *tfm_cmac, const u8 w[32], m[52] = 1; /* Counter */ - err = aes_cmac(tfm_cmac, t, m, sizeof(m), ltk); + err = smp_aes_cmac(t, m, sizeof(m), ltk); if (err) return err; @@ -282,10 +267,9 @@ static int smp_f5(struct crypto_shash *tfm_cmac, const u8 w[32], return 0; } -static int smp_f6(struct crypto_shash *tfm_cmac, const u8 w[16], - const u8 n1[16], const u8 n2[16], const u8 r[16], - const u8 io_cap[3], const u8 a1[7], const u8 a2[7], - u8 res[16]) +static int smp_f6(const u8 w[16], const u8 n1[16], const u8 n2[16], + const u8 r[16], const u8 io_cap[3], const u8 a1[7], + const u8 a2[7], u8 res[16]) { u8 m[65]; int err; @@ -301,7 +285,7 @@ static int smp_f6(struct crypto_shash *tfm_cmac, const u8 w[16], memcpy(m + 33, n2, 16); memcpy(m + 49, n1, 16); - err = aes_cmac(tfm_cmac, w, m, sizeof(m), res); + err = smp_aes_cmac(w, m, sizeof(m), res); if (err) return err; @@ -310,8 +294,8 @@ static int smp_f6(struct crypto_shash *tfm_cmac, const u8 w[16], return err; } -static int smp_g2(struct crypto_shash *tfm_cmac, const u8 u[32], const u8 v[32], - const u8 x[16], const u8 y[16], u32 *val) +static int smp_g2(const u8 u[32], const u8 v[32], const u8 x[16], + const u8 y[16], u32 *val) { u8 m[80], tmp[16]; int err; @@ -324,7 +308,7 @@ static int smp_g2(struct crypto_shash *tfm_cmac, const u8 u[32], const u8 v[32], memcpy(m + 16, v, 32); memcpy(m + 48, u, 32); - err = aes_cmac(tfm_cmac, x, m, sizeof(m), tmp); + err = smp_aes_cmac(x, m, sizeof(m), tmp); if (err) return err; @@ -336,14 +320,13 @@ static int smp_g2(struct crypto_shash *tfm_cmac, const u8 u[32], const u8 v[32], return 0; } -static int smp_h6(struct crypto_shash *tfm_cmac, const u8 w[16], - const u8 key_id[4], u8 res[16]) +static int smp_h6(const u8 w[16], const u8 key_id[4], u8 res[16]) { int err; SMP_DBG("w %16phN key_id %4phN", w, key_id); - err = aes_cmac(tfm_cmac, w, key_id, 4, res); + err = smp_aes_cmac(w, key_id, 4, res); if (err) return err; @@ -352,14 +335,13 @@ static int smp_h6(struct crypto_shash *tfm_cmac, const u8 w[16], return err; } -static int smp_h7(struct crypto_shash *tfm_cmac, const u8 w[16], - const u8 salt[16], u8 res[16]) +static int smp_h7(const u8 w[16], const u8 salt[16], u8 res[16]) { int err; SMP_DBG("w %16phN salt %16phN", w, salt); - err = aes_cmac(tfm_cmac, salt, w, 16, res); + err = smp_aes_cmac(salt, w, 16, res); if (err) return err; @@ -574,8 +556,7 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16]) get_random_bytes(smp->local_rand, 16); - err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->local_pk, - smp->local_rand, 0, hash); + err = smp_f4(smp->local_pk, smp->local_pk, smp->local_rand, 0, hash); if (err < 0) return err; @@ -757,7 +738,6 @@ static void smp_chan_destroy(struct l2cap_conn *conn) kfree_sensitive(smp->responder_csrk); kfree_sensitive(smp->link_key); - crypto_free_shash(smp->tfm_cmac); crypto_free_kpp(smp->tfm_ecdh); /* Ensure that we don't leave any debug key around if debug key @@ -1160,7 +1140,7 @@ static void sc_generate_link_key(struct smp_chan *smp) /* SALT = 0x000000000000000000000000746D7031 */ const u8 salt[16] = { 0x31, 0x70, 0x6d, 0x74 }; - if (smp_h7(smp->tfm_cmac, smp->tk, salt, smp->link_key)) { + if (smp_h7(smp->tk, salt, smp->link_key)) { kfree_sensitive(smp->link_key); smp->link_key = NULL; return; @@ -1169,14 +1149,14 @@ static void sc_generate_link_key(struct smp_chan *smp) /* From core spec. Spells out in ASCII as 'tmp1'. */ const u8 tmp1[4] = { 0x31, 0x70, 0x6d, 0x74 }; - if (smp_h6(smp->tfm_cmac, smp->tk, tmp1, smp->link_key)) { + if (smp_h6(smp->tk, tmp1, smp->link_key)) { kfree_sensitive(smp->link_key); smp->link_key = NULL; return; } } - if (smp_h6(smp->tfm_cmac, smp->link_key, lebr, smp->link_key)) { + if (smp_h6(smp->link_key, lebr, smp->link_key)) { kfree_sensitive(smp->link_key); smp->link_key = NULL; return; @@ -1218,17 +1198,17 @@ static void sc_generate_ltk(struct smp_chan *smp) /* SALT = 0x000000000000000000000000746D7032 */ const u8 salt[16] = { 0x32, 0x70, 0x6d, 0x74 }; - if (smp_h7(smp->tfm_cmac, key->val, salt, smp->tk)) + if (smp_h7(key->val, salt, smp->tk)) return; } else { /* From core spec. Spells out in ASCII as 'tmp2'. */ const u8 tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 }; - if (smp_h6(smp->tfm_cmac, key->val, tmp2, smp->tk)) + if (smp_h6(key->val, tmp2, smp->tk)) return; } - if (smp_h6(smp->tfm_cmac, smp->tk, brle, smp->tk)) + if (smp_h6(smp->tk, brle, smp->tk)) return; sc_add_ltk(smp); @@ -1389,16 +1369,10 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) if (!smp) return NULL; - smp->tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0); - if (IS_ERR(smp->tfm_cmac)) { - bt_dev_err(hcon->hdev, "Unable to create CMAC crypto context"); - goto zfree_smp; - } - smp->tfm_ecdh = crypto_alloc_kpp("ecdh-nist-p256", 0, 0); if (IS_ERR(smp->tfm_ecdh)) { bt_dev_err(hcon->hdev, "Unable to create ECDH crypto context"); - goto free_shash; + goto zfree_smp; } smp->conn = conn; @@ -1412,8 +1386,6 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) return smp; -free_shash: - crypto_free_shash(smp->tfm_cmac); zfree_smp: kfree_sensitive(smp); return NULL; @@ -1437,7 +1409,7 @@ static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16]) a[6] = hcon->init_addr_type; b[6] = hcon->resp_addr_type; - return smp_f5(smp->tfm_cmac, smp->dhkey, na, nb, a, b, mackey, ltk); + return smp_f5(smp->dhkey, na, nb, a, b, mackey, ltk); } static void sc_dhkey_check(struct smp_chan *smp) @@ -1470,8 +1442,8 @@ static void sc_dhkey_check(struct smp_chan *smp) if (smp->method == REQ_OOB) memcpy(r, smp->rr, 16); - smp_f6(smp->tfm_cmac, smp->mackey, smp->prnd, smp->rrnd, r, io_cap, - local_addr, remote_addr, check.e); + smp_f6(smp->mackey, smp->prnd, smp->rrnd, r, io_cap, local_addr, + remote_addr, check.e); smp_send_cmd(smp->conn, SMP_CMD_DHKEY_CHECK, sizeof(check), &check); } @@ -1488,7 +1460,7 @@ static u8 sc_passkey_send_confirm(struct smp_chan *smp) get_random_bytes(smp->prnd, sizeof(smp->prnd)); - if (smp_f4(smp->tfm_cmac, smp->local_pk, smp->remote_pk, smp->prnd, r, + if (smp_f4(smp->local_pk, smp->remote_pk, smp->prnd, r, cfm.confirm_val)) return SMP_UNSPECIFIED; @@ -1513,8 +1485,7 @@ static u8 sc_passkey_round(struct smp_chan *smp, u8 smp_op) r = ((hcon->passkey_notify >> smp->passkey_round) & 0x01); r |= 0x80; - if (smp_f4(smp->tfm_cmac, smp->remote_pk, smp->local_pk, - smp->rrnd, r, cfm)) + if (smp_f4(smp->remote_pk, smp->local_pk, smp->rrnd, r, cfm)) return SMP_UNSPECIFIED; if (crypto_memneq(smp->pcnf, cfm, 16)) @@ -2178,8 +2149,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) { u8 cfm[16]; - err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->local_pk, - smp->rrnd, 0, cfm); + err = smp_f4(smp->remote_pk, smp->local_pk, smp->rrnd, 0, cfm); if (err) return SMP_UNSPECIFIED; @@ -2205,7 +2175,7 @@ mackey_and_ltk: return 0; } - err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey); + err = smp_g2(pkax, pkbx, na, nb, &passkey); if (err) return SMP_UNSPECIFIED; @@ -2750,8 +2720,8 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(smp->remote_pk, key, 64); if (test_bit(SMP_FLAG_REMOTE_OOB, &smp->flags)) { - err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->remote_pk, - smp->rr, 0, cfm.confirm_val); + err = smp_f4(smp->remote_pk, smp->remote_pk, smp->rr, 0, + cfm.confirm_val); if (err) return SMP_UNSPECIFIED; @@ -2851,8 +2821,8 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb) if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) return 0; - err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->remote_pk, smp->prnd, - 0, cfm.confirm_val); + err = smp_f4(smp->local_pk, smp->remote_pk, smp->prnd, 0, + cfm.confirm_val); if (err) return SMP_UNSPECIFIED; @@ -2899,8 +2869,8 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb) else if (smp->method == REQ_OOB) memcpy(r, smp->lr, 16); - err = smp_f6(smp->tfm_cmac, smp->mackey, smp->rrnd, smp->prnd, r, - io_cap, remote_addr, local_addr, e); + err = smp_f6(smp->mackey, smp->rrnd, smp->prnd, r, io_cap, remote_addr, + local_addr, e); if (err) return SMP_UNSPECIFIED; @@ -3286,7 +3256,6 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) { struct l2cap_chan *chan; struct smp_dev *smp; - struct crypto_shash *tfm_cmac; struct crypto_kpp *tfm_ecdh; if (cid == L2CAP_CID_SMP_BREDR) { @@ -3298,30 +3267,20 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) if (!smp) return ERR_PTR(-ENOMEM); - tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0); - if (IS_ERR(tfm_cmac)) { - bt_dev_err(hdev, "Unable to create CMAC crypto context"); - kfree_sensitive(smp); - return ERR_CAST(tfm_cmac); - } - tfm_ecdh = crypto_alloc_kpp("ecdh-nist-p256", 0, 0); if (IS_ERR(tfm_ecdh)) { bt_dev_err(hdev, "Unable to create ECDH crypto context"); - crypto_free_shash(tfm_cmac); kfree_sensitive(smp); return ERR_CAST(tfm_ecdh); } smp->local_oob = false; - smp->tfm_cmac = tfm_cmac; smp->tfm_ecdh = tfm_ecdh; create_chan: chan = l2cap_chan_create(); if (!chan) { if (smp) { - crypto_free_shash(smp->tfm_cmac); crypto_free_kpp(smp->tfm_ecdh); kfree_sensitive(smp); } @@ -3368,7 +3327,6 @@ static void smp_del_chan(struct l2cap_chan *chan) smp = chan->data; if (smp) { chan->data = NULL; - crypto_free_shash(smp->tfm_cmac); crypto_free_kpp(smp->tfm_ecdh); kfree_sensitive(smp); } @@ -3565,7 +3523,7 @@ static int __init test_s1(void) return 0; } -static int __init test_f4(struct crypto_shash *tfm_cmac) +static int __init test_f4(void) { const u8 u[32] = { 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, @@ -3587,7 +3545,7 @@ static int __init test_f4(struct crypto_shash *tfm_cmac) u8 res[16]; int err; - err = smp_f4(tfm_cmac, u, v, x, z, res); + err = smp_f4(u, v, x, z, res); if (err) return err; @@ -3597,7 +3555,7 @@ static int __init test_f4(struct crypto_shash *tfm_cmac) return 0; } -static int __init test_f5(struct crypto_shash *tfm_cmac) +static int __init test_f5(void) { const u8 w[32] = { 0x98, 0xa6, 0xbf, 0x73, 0xf3, 0x34, 0x8d, 0x86, @@ -3621,7 +3579,7 @@ static int __init test_f5(struct crypto_shash *tfm_cmac) u8 mackey[16], ltk[16]; int err; - err = smp_f5(tfm_cmac, w, n1, n2, a1, a2, mackey, ltk); + err = smp_f5(w, n1, n2, a1, a2, mackey, ltk); if (err) return err; @@ -3634,7 +3592,7 @@ static int __init test_f5(struct crypto_shash *tfm_cmac) return 0; } -static int __init test_f6(struct crypto_shash *tfm_cmac) +static int __init test_f6(void) { const u8 w[16] = { 0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd, @@ -3657,7 +3615,7 @@ static int __init test_f6(struct crypto_shash *tfm_cmac) u8 res[16]; int err; - err = smp_f6(tfm_cmac, w, n1, n2, r, io_cap, a1, a2, res); + err = smp_f6(w, n1, n2, r, io_cap, a1, a2, res); if (err) return err; @@ -3667,7 +3625,7 @@ static int __init test_f6(struct crypto_shash *tfm_cmac) return 0; } -static int __init test_g2(struct crypto_shash *tfm_cmac) +static int __init test_g2(void) { const u8 u[32] = { 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, @@ -3689,7 +3647,7 @@ static int __init test_g2(struct crypto_shash *tfm_cmac) u32 val; int err; - err = smp_g2(tfm_cmac, u, v, x, y, &val); + err = smp_g2(u, v, x, y, &val); if (err) return err; @@ -3699,7 +3657,7 @@ static int __init test_g2(struct crypto_shash *tfm_cmac) return 0; } -static int __init test_h6(struct crypto_shash *tfm_cmac) +static int __init test_h6(void) { const u8 w[16] = { 0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34, @@ -3711,7 +3669,7 @@ static int __init test_h6(struct crypto_shash *tfm_cmac) u8 res[16]; int err; - err = smp_h6(tfm_cmac, w, key_id, res); + err = smp_h6(w, key_id, res); if (err) return err; @@ -3736,8 +3694,7 @@ static const struct file_operations test_smp_fops = { .llseek = default_llseek, }; -static int __init run_selftests(struct crypto_shash *tfm_cmac, - struct crypto_kpp *tfm_ecdh) +static int __init run_selftests(struct crypto_kpp *tfm_ecdh) { ktime_t calltime, delta, rettime; unsigned long long duration; @@ -3769,31 +3726,31 @@ static int __init run_selftests(struct crypto_shash *tfm_cmac, goto done; } - err = test_f4(tfm_cmac); + err = test_f4(); if (err) { BT_ERR("smp_f4 test failed"); goto done; } - err = test_f5(tfm_cmac); + err = test_f5(); if (err) { BT_ERR("smp_f5 test failed"); goto done; } - err = test_f6(tfm_cmac); + err = test_f6(); if (err) { BT_ERR("smp_f6 test failed"); goto done; } - err = test_g2(tfm_cmac); + err = test_g2(); if (err) { BT_ERR("smp_g2 test failed"); goto done; } - err = test_h6(tfm_cmac); + err = test_h6(); if (err) { BT_ERR("smp_h6 test failed"); goto done; @@ -3820,26 +3777,17 @@ done: int __init bt_selftest_smp(void) { - struct crypto_shash *tfm_cmac; struct crypto_kpp *tfm_ecdh; int err; - tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0); - if (IS_ERR(tfm_cmac)) { - BT_ERR("Unable to create CMAC crypto context"); - return PTR_ERR(tfm_cmac); - } - tfm_ecdh = crypto_alloc_kpp("ecdh-nist-p256", 0, 0); if (IS_ERR(tfm_ecdh)) { BT_ERR("Unable to create ECDH crypto context"); - crypto_free_shash(tfm_cmac); return PTR_ERR(tfm_ecdh); } - err = run_selftests(tfm_cmac, tfm_ecdh); + err = run_selftests(tfm_ecdh); - crypto_free_shash(tfm_cmac); crypto_free_kpp(tfm_ecdh); return err; From 5ead2063611ae56809b1b113ac44cef9547c81d7 Mon Sep 17 00:00:00 2001 From: Alexej Sidorenko Date: Wed, 29 Apr 2026 17:13:43 +0200 Subject: [PATCH 11/49] Bluetooth: btrtl: fix RTL8761B/BU broken LE extended scan RTL8761B and RTL8761BU devices report HCI version 5.1 but do not support the LE Extended Scan commands. This causes repeated failures with Opcode 0x2042 (LE Set Extended Scan Parameters) returning -EBUSY when BlueZ attempts extended scanning while a connection is active. Set HCI_QUIRK_BROKEN_EXT_SCAN for CHIP_ID_8761B to make BlueZ fall back to legacy LE scan commands which the firmware supports correctly. Tested with RTL8761BU (USB ID 0bda:a728) where the issue manifested as continuous 'Opcode 0x2042 failed: -16' errors in dmesg whenever a BLE connection was active. Signed-off-by: Alexej Sidorenko Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btrtl.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index 62f9d4df3a4f..49ecb18fea45 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -1342,6 +1342,19 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev) if (!btrtl_dev->ic_info) return; + switch (btrtl_dev->project_id) { + case CHIP_ID_8761B: + /* RTL8761B/BU reports HCI version 5.1 but does not support + * the LE Extended Scan commands (Opcode 0x2042), causing + * repeated -EBUSY failures when BlueZ attempts extended + * scanning while a connection is active. + */ + hci_set_quirk(hdev, HCI_QUIRK_BROKEN_EXT_SCAN); + break; + default: + break; + } + switch (btrtl_dev->ic_info->lmp_subver) { case RTL_ROM_LMP_8703B: /* 8723CS reports two pages for local ext features, From 794b5e7727de1ebaa07366ae346a139870874c2d Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Sat, 2 May 2026 20:31:21 -0700 Subject: [PATCH 12/49] bluetooth: remove all PCMCIA drivers PCMCIA is almost completely obsolete (the last computers supporting it natively were from ~2009), and the general consensus [1] seems to be that support for it should be gradually removed from the kernel. In 2023, an initial step of removing all the PCMCIA char drivers was taken in commit 9b12f050c76f ("char: pcmcia: remove all the drivers"), and that has not been reverted, so it seems logical to continue this process by removing more low-hanging fruit. These three Bluetooth drivers have had no meaningful changes since their status was discussed in 2022 [2], and are unlikely to have any remaining users. The latest functional change to any of them was a patch to bluecard_cs to fix LED blinking behavior in 2017. The other two drivers have not had any meaningful changes made since 2007. Remove them. Note that even with these drivers removed, it is still possible to use other PCMCIA Bluetooth cards that present themselves as a standard serial port via serial_cs and hciattach while the serial_cs driver is still present. [1] https://lore.kernel.org/all/c5b39544-a4fb-4796-a046-0b9be9853787@app.fastmail.com/ [2] https://lore.kernel.org/all/Y07d7rMvd5++85BJ@owl.dominikbrodowski.net/ Signed-off-by: Ethan Nelson-Moore Signed-off-by: Luiz Augusto von Dentz --- arch/arm/configs/pxa_defconfig | 3 - arch/arm/configs/spitz_defconfig | 3 - arch/loongarch/configs/loongson32_defconfig | 3 - arch/loongarch/configs/loongson64_defconfig | 3 - arch/mips/configs/mtx1_defconfig | 3 - arch/powerpc/configs/ppc6xx_defconfig | 3 - drivers/bluetooth/Kconfig | 40 - drivers/bluetooth/Makefile | 3 - drivers/bluetooth/bluecard_cs.c | 908 -------------------- drivers/bluetooth/bt3c_cs.c | 749 ---------------- drivers/bluetooth/dtl1_cs.c | 614 ------------- 11 files changed, 2332 deletions(-) delete mode 100644 drivers/bluetooth/bluecard_cs.c delete mode 100644 drivers/bluetooth/bt3c_cs.c delete mode 100644 drivers/bluetooth/dtl1_cs.c diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig index 83d1ed3a37f5..b86bb9bfbc99 100644 --- a/arch/arm/configs/pxa_defconfig +++ b/arch/arm/configs/pxa_defconfig @@ -77,9 +77,6 @@ CONFIG_BT_HCIUART_BCSP=y CONFIG_BT_HCIBCM203X=m CONFIG_BT_HCIBPA10X=m CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIDTL1=m -CONFIG_BT_HCIBT3C=m -CONFIG_BT_HCIBLUECARD=m CONFIG_BT_HCIBTUART=m CONFIG_BT_HCIVHCI=m CONFIG_BT_MRVL=m diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig index f116a01c3f5f..8f8a058294fb 100644 --- a/arch/arm/configs/spitz_defconfig +++ b/arch/arm/configs/spitz_defconfig @@ -62,9 +62,6 @@ CONFIG_BT_HCIUART_BCSP=y CONFIG_BT_HCIBCM203X=m CONFIG_BT_HCIBPA10X=m CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIDTL1=m -CONFIG_BT_HCIBT3C=m -CONFIG_BT_HCIBLUECARD=m CONFIG_BT_HCIBTUART=m CONFIG_BT_HCIVHCI=m CONFIG_PCCARD=y diff --git a/arch/loongarch/configs/loongson32_defconfig b/arch/loongarch/configs/loongson32_defconfig index d5ef396dffe3..f319c880127c 100644 --- a/arch/loongarch/configs/loongson32_defconfig +++ b/arch/loongarch/configs/loongson32_defconfig @@ -383,9 +383,6 @@ CONFIG_BT_HCIUART_AG6XX=y CONFIG_BT_HCIBCM203X=m CONFIG_BT_HCIBPA10X=m CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIDTL1=m -CONFIG_BT_HCIBT3C=m -CONFIG_BT_HCIBLUECARD=m CONFIG_BT_HCIVHCI=m CONFIG_BT_MRVL=m CONFIG_BT_ATH3K=m diff --git a/arch/loongarch/configs/loongson64_defconfig b/arch/loongarch/configs/loongson64_defconfig index cba4cdff5acd..ffa8ae26d713 100644 --- a/arch/loongarch/configs/loongson64_defconfig +++ b/arch/loongarch/configs/loongson64_defconfig @@ -399,9 +399,6 @@ CONFIG_BT_HCIUART_AG6XX=y CONFIG_BT_HCIBCM203X=m CONFIG_BT_HCIBPA10X=m CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIDTL1=m -CONFIG_BT_HCIBT3C=m -CONFIG_BT_HCIBLUECARD=m CONFIG_BT_HCIVHCI=m CONFIG_BT_MRVL=m CONFIG_BT_ATH3K=m diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index de82a55c9829..a1c374bd4785 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -184,9 +184,6 @@ CONFIG_BT_HCIUART_BCSP=y CONFIG_BT_HCIBCM203X=m CONFIG_BT_HCIBPA10X=m CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIDTL1=m -CONFIG_BT_HCIBT3C=m -CONFIG_BT_HCIBLUECARD=m CONFIG_BT_HCIVHCI=m CONFIG_CONNECTOR=m CONFIG_MTD=y diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 00a2e003ee9f..c9bdaed06d03 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -282,9 +282,6 @@ CONFIG_BT_HCIUART_BCSP=y CONFIG_BT_HCIBCM203X=m CONFIG_BT_HCIBPA10X=m CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIDTL1=m -CONFIG_BT_HCIBT3C=m -CONFIG_BT_HCIBLUECARD=m CONFIG_BT_HCIVHCI=m CONFIG_CFG80211=m CONFIG_MAC80211=m diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index fc1b37044a9b..4e8c24d757e9 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -337,46 +337,6 @@ config BT_HCIBFUSB Say Y here to compile support for HCI BFUSB devices into the kernel or say M to compile it as module (bfusb). -config BT_HCIDTL1 - tristate "HCI DTL1 (PC Card) driver" - depends on PCMCIA && HAS_IOPORT - help - Bluetooth HCI DTL1 (PC Card) driver. - This driver provides support for Bluetooth PCMCIA devices with - Nokia DTL1 interface: - Nokia Bluetooth Card - Socket Bluetooth CF Card - - Say Y here to compile support for HCI DTL1 devices into the - kernel or say M to compile it as module (dtl1_cs). - -config BT_HCIBT3C - tristate "HCI BT3C (PC Card) driver" - depends on PCMCIA && HAS_IOPORT - select FW_LOADER - help - Bluetooth HCI BT3C (PC Card) driver. - This driver provides support for Bluetooth PCMCIA devices with - 3Com BT3C interface: - 3Com Bluetooth Card (3CRWB6096) - HP Bluetooth Card - - Say Y here to compile support for HCI BT3C devices into the - kernel or say M to compile it as module (bt3c_cs). - -config BT_HCIBLUECARD - tristate "HCI BlueCard (PC Card) driver" - depends on PCMCIA && HAS_IOPORT - help - Bluetooth HCI BlueCard (PC Card) driver. - This driver provides support for Bluetooth PCMCIA devices with - Anycom BlueCard interface: - Anycom Bluetooth PC Card - Anycom Bluetooth CF Card - - Say Y here to compile support for HCI BlueCard devices into the - kernel or say M to compile it as module (bluecard_cs). - config BT_HCIVHCI tristate "HCI VHCI (Virtual HCI device) driver" select WANT_DEV_COREDUMP diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 81856512ddd0..bafc26250b63 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -9,9 +9,6 @@ obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o obj-$(CONFIG_BT_HCIBCM4377) += hci_bcm4377.o obj-$(CONFIG_BT_HCIBPA10X) += bpa10x.o obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o -obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o -obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o -obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c deleted file mode 100644 index 1e3a56e9b139..000000000000 --- a/drivers/bluetooth/bluecard_cs.c +++ /dev/null @@ -1,908 +0,0 @@ -/* - * - * Bluetooth driver for the Anycom BlueCard (LSE039/LSE041) - * - * Copyright (C) 2001-2002 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - * - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include - - - -/* ======================== Module parameters ======================== */ - - -MODULE_AUTHOR("Marcel Holtmann "); -MODULE_DESCRIPTION("Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)"); -MODULE_LICENSE("GPL"); - - - -/* ======================== Local structures ======================== */ - - -struct bluecard_info { - struct pcmcia_device *p_dev; - - struct hci_dev *hdev; - - spinlock_t lock; /* For serializing operations */ - struct timer_list timer; /* For LED control */ - - struct sk_buff_head txq; - unsigned long tx_state; - - unsigned long rx_state; - unsigned long rx_count; - struct sk_buff *rx_skb; - - unsigned char ctrl_reg; - unsigned long hw_state; /* Status of the hardware and LED control */ -}; - - -static int bluecard_config(struct pcmcia_device *link); -static void bluecard_release(struct pcmcia_device *link); - -static void bluecard_detach(struct pcmcia_device *p_dev); - - -/* Default baud rate: 57600, 115200, 230400 or 460800 */ -#define DEFAULT_BAUD_RATE 230400 - - -/* Hardware states */ -#define CARD_READY 1 -#define CARD_ACTIVITY 2 -#define CARD_HAS_PCCARD_ID 4 -#define CARD_HAS_POWER_LED 5 -#define CARD_HAS_ACTIVITY_LED 6 - -/* Transmit states */ -#define XMIT_SENDING 1 -#define XMIT_WAKEUP 2 -#define XMIT_BUFFER_NUMBER 5 /* unset = buffer one, set = buffer two */ -#define XMIT_BUF_ONE_READY 6 -#define XMIT_BUF_TWO_READY 7 -#define XMIT_SENDING_READY 8 - -/* Receiver states */ -#define RECV_WAIT_PACKET_TYPE 0 -#define RECV_WAIT_EVENT_HEADER 1 -#define RECV_WAIT_ACL_HEADER 2 -#define RECV_WAIT_SCO_HEADER 3 -#define RECV_WAIT_DATA 4 - -/* Special packet types */ -#define PKT_BAUD_RATE_57600 0x80 -#define PKT_BAUD_RATE_115200 0x81 -#define PKT_BAUD_RATE_230400 0x82 -#define PKT_BAUD_RATE_460800 0x83 - - -/* These are the register offsets */ -#define REG_COMMAND 0x20 -#define REG_INTERRUPT 0x21 -#define REG_CONTROL 0x22 -#define REG_RX_CONTROL 0x24 -#define REG_CARD_RESET 0x30 -#define REG_LED_CTRL 0x30 - -/* REG_COMMAND */ -#define REG_COMMAND_TX_BUF_ONE 0x01 -#define REG_COMMAND_TX_BUF_TWO 0x02 -#define REG_COMMAND_RX_BUF_ONE 0x04 -#define REG_COMMAND_RX_BUF_TWO 0x08 -#define REG_COMMAND_RX_WIN_ONE 0x00 -#define REG_COMMAND_RX_WIN_TWO 0x10 - -/* REG_CONTROL */ -#define REG_CONTROL_BAUD_RATE_57600 0x00 -#define REG_CONTROL_BAUD_RATE_115200 0x01 -#define REG_CONTROL_BAUD_RATE_230400 0x02 -#define REG_CONTROL_BAUD_RATE_460800 0x03 -#define REG_CONTROL_RTS 0x04 -#define REG_CONTROL_BT_ON 0x08 -#define REG_CONTROL_BT_RESET 0x10 -#define REG_CONTROL_BT_RES_PU 0x20 -#define REG_CONTROL_INTERRUPT 0x40 -#define REG_CONTROL_CARD_RESET 0x80 - -/* REG_RX_CONTROL */ -#define RTS_LEVEL_SHIFT_BITS 0x02 - - - -/* ======================== LED handling routines ======================== */ - - -static void bluecard_activity_led_timeout(struct timer_list *t) -{ - struct bluecard_info *info = timer_container_of(info, t, timer); - unsigned int iobase = info->p_dev->resource[0]->start; - - if (test_bit(CARD_ACTIVITY, &(info->hw_state))) { - /* leave LED in inactive state for HZ/10 for blink effect */ - clear_bit(CARD_ACTIVITY, &(info->hw_state)); - mod_timer(&(info->timer), jiffies + HZ / 10); - } - - /* Disable activity LED, enable power LED */ - outb(0x08 | 0x20, iobase + 0x30); -} - - -static void bluecard_enable_activity_led(struct bluecard_info *info) -{ - unsigned int iobase = info->p_dev->resource[0]->start; - - /* don't disturb running blink timer */ - if (timer_pending(&(info->timer))) - return; - - set_bit(CARD_ACTIVITY, &(info->hw_state)); - - if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { - /* Enable activity LED, keep power LED enabled */ - outb(0x18 | 0x60, iobase + 0x30); - } else { - /* Disable power LED */ - outb(0x00, iobase + 0x30); - } - - /* Stop the LED after HZ/10 */ - mod_timer(&(info->timer), jiffies + HZ / 10); -} - - - -/* ======================== Interrupt handling ======================== */ - - -static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len) -{ - int i, actual; - - actual = (len > 15) ? 15 : len; - - outb_p(actual, iobase + offset); - - for (i = 0; i < actual; i++) - outb_p(buf[i], iobase + offset + i + 1); - - return actual; -} - - -static void bluecard_write_wakeup(struct bluecard_info *info) -{ - if (!info) { - BT_ERR("Unknown device"); - return; - } - - if (!test_bit(XMIT_SENDING_READY, &(info->tx_state))) - return; - - if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { - set_bit(XMIT_WAKEUP, &(info->tx_state)); - return; - } - - do { - unsigned int iobase = info->p_dev->resource[0]->start; - unsigned int offset; - unsigned char command; - unsigned long ready_bit; - register struct sk_buff *skb; - int len; - - clear_bit(XMIT_WAKEUP, &(info->tx_state)); - - if (!pcmcia_dev_present(info->p_dev)) - return; - - if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) { - if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state))) - break; - offset = 0x10; - command = REG_COMMAND_TX_BUF_TWO; - ready_bit = XMIT_BUF_TWO_READY; - } else { - if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state))) - break; - offset = 0x00; - command = REG_COMMAND_TX_BUF_ONE; - ready_bit = XMIT_BUF_ONE_READY; - } - - skb = skb_dequeue(&(info->txq)); - if (!skb) - break; - - if (hci_skb_pkt_type(skb) & 0x80) { - /* Disable RTS */ - info->ctrl_reg |= REG_CONTROL_RTS; - outb(info->ctrl_reg, iobase + REG_CONTROL); - } - - /* Activate LED */ - bluecard_enable_activity_led(info); - - /* Send frame */ - len = bluecard_write(iobase, offset, skb->data, skb->len); - - /* Tell the FPGA to send the data */ - outb_p(command, iobase + REG_COMMAND); - - /* Mark the buffer as dirty */ - clear_bit(ready_bit, &(info->tx_state)); - - if (hci_skb_pkt_type(skb) & 0x80) { - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); - DEFINE_WAIT(wait); - - unsigned char baud_reg; - - switch (hci_skb_pkt_type(skb)) { - case PKT_BAUD_RATE_460800: - baud_reg = REG_CONTROL_BAUD_RATE_460800; - break; - case PKT_BAUD_RATE_230400: - baud_reg = REG_CONTROL_BAUD_RATE_230400; - break; - case PKT_BAUD_RATE_115200: - baud_reg = REG_CONTROL_BAUD_RATE_115200; - break; - case PKT_BAUD_RATE_57600: - default: - baud_reg = REG_CONTROL_BAUD_RATE_57600; - break; - } - - /* Wait until the command reaches the baseband */ - mdelay(100); - - /* Set baud on baseband */ - info->ctrl_reg &= ~0x03; - info->ctrl_reg |= baud_reg; - outb(info->ctrl_reg, iobase + REG_CONTROL); - - /* Enable RTS */ - info->ctrl_reg &= ~REG_CONTROL_RTS; - outb(info->ctrl_reg, iobase + REG_CONTROL); - - /* Wait before the next HCI packet can be send */ - mdelay(1000); - } - - if (len == skb->len) { - kfree_skb(skb); - } else { - skb_pull(skb, len); - skb_queue_head(&(info->txq), skb); - } - - info->hdev->stat.byte_tx += len; - - /* Change buffer */ - change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state)); - - } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); - - clear_bit(XMIT_SENDING, &(info->tx_state)); -} - - -static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size) -{ - int i, n, len; - - outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND); - - len = inb(iobase + offset); - n = 0; - i = 1; - - while (n < len) { - - if (i == 16) { - outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND); - i = 0; - } - - buf[n] = inb(iobase + offset + i); - - n++; - i++; - - } - - return len; -} - - -static void bluecard_receive(struct bluecard_info *info, - unsigned int offset) -{ - unsigned int iobase; - unsigned char buf[31]; - int i, len; - - if (!info) { - BT_ERR("Unknown device"); - return; - } - - iobase = info->p_dev->resource[0]->start; - - if (test_bit(XMIT_SENDING_READY, &(info->tx_state))) - bluecard_enable_activity_led(info); - - len = bluecard_read(iobase, offset, buf, sizeof(buf)); - - for (i = 0; i < len; i++) { - - /* Allocate packet */ - if (!info->rx_skb) { - info->rx_state = RECV_WAIT_PACKET_TYPE; - info->rx_count = 0; - info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); - if (!info->rx_skb) { - BT_ERR("Can't allocate mem for new packet"); - return; - } - } - - if (info->rx_state == RECV_WAIT_PACKET_TYPE) { - - hci_skb_pkt_type(info->rx_skb) = buf[i]; - - switch (hci_skb_pkt_type(info->rx_skb)) { - - case 0x00: - /* init packet */ - if (offset != 0x00) { - set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); - set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); - set_bit(XMIT_SENDING_READY, &(info->tx_state)); - bluecard_write_wakeup(info); - } - - kfree_skb(info->rx_skb); - info->rx_skb = NULL; - break; - - case HCI_EVENT_PKT: - info->rx_state = RECV_WAIT_EVENT_HEADER; - info->rx_count = HCI_EVENT_HDR_SIZE; - break; - - case HCI_ACLDATA_PKT: - info->rx_state = RECV_WAIT_ACL_HEADER; - info->rx_count = HCI_ACL_HDR_SIZE; - break; - - case HCI_SCODATA_PKT: - info->rx_state = RECV_WAIT_SCO_HEADER; - info->rx_count = HCI_SCO_HDR_SIZE; - break; - - default: - /* unknown packet */ - BT_ERR("Unknown HCI packet with type 0x%02x received", - hci_skb_pkt_type(info->rx_skb)); - info->hdev->stat.err_rx++; - - kfree_skb(info->rx_skb); - info->rx_skb = NULL; - break; - - } - - } else { - - skb_put_u8(info->rx_skb, buf[i]); - info->rx_count--; - - if (info->rx_count == 0) { - - int dlen; - struct hci_event_hdr *eh; - struct hci_acl_hdr *ah; - struct hci_sco_hdr *sh; - - switch (info->rx_state) { - - case RECV_WAIT_EVENT_HEADER: - eh = hci_event_hdr(info->rx_skb); - info->rx_state = RECV_WAIT_DATA; - info->rx_count = eh->plen; - break; - - case RECV_WAIT_ACL_HEADER: - ah = hci_acl_hdr(info->rx_skb); - dlen = __le16_to_cpu(ah->dlen); - info->rx_state = RECV_WAIT_DATA; - info->rx_count = dlen; - break; - - case RECV_WAIT_SCO_HEADER: - sh = hci_sco_hdr(info->rx_skb); - info->rx_state = RECV_WAIT_DATA; - info->rx_count = sh->dlen; - break; - - case RECV_WAIT_DATA: - hci_recv_frame(info->hdev, info->rx_skb); - info->rx_skb = NULL; - break; - - } - - } - - } - - - } - - info->hdev->stat.byte_rx += len; -} - - -static irqreturn_t bluecard_interrupt(int irq, void *dev_inst) -{ - struct bluecard_info *info = dev_inst; - unsigned int iobase; - unsigned char reg; - - if (!info || !info->hdev) - /* our irq handler is shared */ - return IRQ_NONE; - - if (!test_bit(CARD_READY, &(info->hw_state))) - return IRQ_HANDLED; - - iobase = info->p_dev->resource[0]->start; - - spin_lock(&(info->lock)); - - /* Disable interrupt */ - info->ctrl_reg &= ~REG_CONTROL_INTERRUPT; - outb(info->ctrl_reg, iobase + REG_CONTROL); - - reg = inb(iobase + REG_INTERRUPT); - - if ((reg != 0x00) && (reg != 0xff)) { - - if (reg & 0x04) { - bluecard_receive(info, 0x00); - outb(0x04, iobase + REG_INTERRUPT); - outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND); - } - - if (reg & 0x08) { - bluecard_receive(info, 0x10); - outb(0x08, iobase + REG_INTERRUPT); - outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND); - } - - if (reg & 0x01) { - set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); - outb(0x01, iobase + REG_INTERRUPT); - bluecard_write_wakeup(info); - } - - if (reg & 0x02) { - set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); - outb(0x02, iobase + REG_INTERRUPT); - bluecard_write_wakeup(info); - } - - } - - /* Enable interrupt */ - info->ctrl_reg |= REG_CONTROL_INTERRUPT; - outb(info->ctrl_reg, iobase + REG_CONTROL); - - spin_unlock(&(info->lock)); - - return IRQ_HANDLED; -} - - - -/* ======================== Device specific HCI commands ======================== */ - - -static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) -{ - struct bluecard_info *info = hci_get_drvdata(hdev); - struct sk_buff *skb; - - /* Ericsson baud rate command */ - unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 }; - - skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_KERNEL); - if (!skb) { - BT_ERR("Can't allocate mem for new packet"); - return -1; - } - - switch (baud) { - case 460800: - cmd[4] = 0x00; - hci_skb_pkt_type(skb) = PKT_BAUD_RATE_460800; - break; - case 230400: - cmd[4] = 0x01; - hci_skb_pkt_type(skb) = PKT_BAUD_RATE_230400; - break; - case 115200: - cmd[4] = 0x02; - hci_skb_pkt_type(skb) = PKT_BAUD_RATE_115200; - break; - case 57600: - default: - cmd[4] = 0x03; - hci_skb_pkt_type(skb) = PKT_BAUD_RATE_57600; - break; - } - - skb_put_data(skb, cmd, sizeof(cmd)); - - skb_queue_tail(&(info->txq), skb); - - bluecard_write_wakeup(info); - - return 0; -} - - - -/* ======================== HCI interface ======================== */ - - -static int bluecard_hci_flush(struct hci_dev *hdev) -{ - struct bluecard_info *info = hci_get_drvdata(hdev); - - /* Drop TX queue */ - skb_queue_purge(&(info->txq)); - - return 0; -} - - -static int bluecard_hci_open(struct hci_dev *hdev) -{ - struct bluecard_info *info = hci_get_drvdata(hdev); - unsigned int iobase = info->p_dev->resource[0]->start; - - if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) - bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); - - /* Enable power LED */ - outb(0x08 | 0x20, iobase + 0x30); - - return 0; -} - - -static int bluecard_hci_close(struct hci_dev *hdev) -{ - struct bluecard_info *info = hci_get_drvdata(hdev); - unsigned int iobase = info->p_dev->resource[0]->start; - - bluecard_hci_flush(hdev); - - /* Stop LED timer */ - timer_delete_sync(&(info->timer)); - - /* Disable power LED */ - outb(0x00, iobase + 0x30); - - return 0; -} - - -static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) -{ - struct bluecard_info *info = hci_get_drvdata(hdev); - - switch (hci_skb_pkt_type(skb)) { - case HCI_COMMAND_PKT: - hdev->stat.cmd_tx++; - break; - case HCI_ACLDATA_PKT: - hdev->stat.acl_tx++; - break; - case HCI_SCODATA_PKT: - hdev->stat.sco_tx++; - break; - } - - /* Prepend skb with frame type */ - memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); - skb_queue_tail(&(info->txq), skb); - - bluecard_write_wakeup(info); - - return 0; -} - - - -/* ======================== Card services HCI interaction ======================== */ - - -static int bluecard_open(struct bluecard_info *info) -{ - unsigned int iobase = info->p_dev->resource[0]->start; - struct hci_dev *hdev; - unsigned char id; - - spin_lock_init(&(info->lock)); - - timer_setup(&info->timer, bluecard_activity_led_timeout, 0); - - skb_queue_head_init(&(info->txq)); - - info->rx_state = RECV_WAIT_PACKET_TYPE; - info->rx_count = 0; - info->rx_skb = NULL; - - /* Initialize HCI device */ - hdev = hci_alloc_dev(); - if (!hdev) { - BT_ERR("Can't allocate HCI device"); - return -ENOMEM; - } - - info->hdev = hdev; - - hdev->bus = HCI_PCCARD; - hci_set_drvdata(hdev, info); - SET_HCIDEV_DEV(hdev, &info->p_dev->dev); - - hdev->open = bluecard_hci_open; - hdev->close = bluecard_hci_close; - hdev->flush = bluecard_hci_flush; - hdev->send = bluecard_hci_send_frame; - - id = inb(iobase + 0x30); - - if ((id & 0x0f) == 0x02) - set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)); - - if (id & 0x10) - set_bit(CARD_HAS_POWER_LED, &(info->hw_state)); - - if (id & 0x20) - set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state)); - - /* Reset card */ - info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET; - outb(info->ctrl_reg, iobase + REG_CONTROL); - - /* Turn FPGA off */ - outb(0x80, iobase + 0x30); - - /* Wait some time */ - msleep(10); - - /* Turn FPGA on */ - outb(0x00, iobase + 0x30); - - /* Activate card */ - info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU; - outb(info->ctrl_reg, iobase + REG_CONTROL); - - /* Enable interrupt */ - outb(0xff, iobase + REG_INTERRUPT); - info->ctrl_reg |= REG_CONTROL_INTERRUPT; - outb(info->ctrl_reg, iobase + REG_CONTROL); - - if ((id & 0x0f) == 0x03) { - /* Disable RTS */ - info->ctrl_reg |= REG_CONTROL_RTS; - outb(info->ctrl_reg, iobase + REG_CONTROL); - - /* Set baud rate */ - info->ctrl_reg |= 0x03; - outb(info->ctrl_reg, iobase + REG_CONTROL); - - /* Enable RTS */ - info->ctrl_reg &= ~REG_CONTROL_RTS; - outb(info->ctrl_reg, iobase + REG_CONTROL); - - set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); - set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); - set_bit(XMIT_SENDING_READY, &(info->tx_state)); - } - - /* Start the RX buffers */ - outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND); - outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND); - - /* Signal that the hardware is ready */ - set_bit(CARD_READY, &(info->hw_state)); - - /* Drop TX queue */ - skb_queue_purge(&(info->txq)); - - /* Control the point at which RTS is enabled */ - outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL); - - /* Timeout before it is safe to send the first HCI packet */ - msleep(1250); - - /* Register HCI device */ - if (hci_register_dev(hdev) < 0) { - BT_ERR("Can't register HCI device"); - info->hdev = NULL; - hci_free_dev(hdev); - return -ENODEV; - } - - return 0; -} - - -static int bluecard_close(struct bluecard_info *info) -{ - unsigned int iobase = info->p_dev->resource[0]->start; - struct hci_dev *hdev = info->hdev; - - if (!hdev) - return -ENODEV; - - bluecard_hci_close(hdev); - - clear_bit(CARD_READY, &(info->hw_state)); - - /* Reset card */ - info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET; - outb(info->ctrl_reg, iobase + REG_CONTROL); - - /* Turn FPGA off */ - outb(0x80, iobase + 0x30); - - hci_unregister_dev(hdev); - hci_free_dev(hdev); - - return 0; -} - -static int bluecard_probe(struct pcmcia_device *link) -{ - struct bluecard_info *info; - - /* Create new info device */ - info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->p_dev = link; - link->priv = info; - - link->config_flags |= CONF_ENABLE_IRQ; - - return bluecard_config(link); -} - - -static void bluecard_detach(struct pcmcia_device *link) -{ - bluecard_release(link); -} - - -static int bluecard_config(struct pcmcia_device *link) -{ - struct bluecard_info *info = link->priv; - int i, n; - - link->config_index = 0x20; - - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[0]->end = 64; - link->io_lines = 6; - - for (n = 0; n < 0x400; n += 0x40) { - link->resource[0]->start = n ^ 0x300; - i = pcmcia_request_io(link); - if (i == 0) - break; - } - - if (i != 0) - goto failed; - - i = pcmcia_request_irq(link, bluecard_interrupt); - if (i != 0) - goto failed; - - i = pcmcia_enable_device(link); - if (i != 0) - goto failed; - - if (bluecard_open(info) != 0) - goto failed; - - return 0; - -failed: - bluecard_release(link); - return -ENODEV; -} - - -static void bluecard_release(struct pcmcia_device *link) -{ - struct bluecard_info *info = link->priv; - - bluecard_close(info); - - timer_delete_sync(&(info->timer)); - - pcmcia_disable_device(link); -} - -static const struct pcmcia_device_id bluecard_ids[] = { - PCMCIA_DEVICE_PROD_ID12("BlueCard", "LSE041", 0xbaf16fbf, 0x657cc15e), - PCMCIA_DEVICE_PROD_ID12("BTCFCARD", "LSE139", 0xe3987764, 0x2524b59c), - PCMCIA_DEVICE_PROD_ID12("WSS", "LSE039", 0x0a0736ec, 0x24e6dfab), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, bluecard_ids); - -static struct pcmcia_driver bluecard_driver = { - .owner = THIS_MODULE, - .name = "bluecard_cs", - .probe = bluecard_probe, - .remove = bluecard_detach, - .id_table = bluecard_ids, -}; -module_pcmcia_driver(bluecard_driver); diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c deleted file mode 100644 index 54713833951a..000000000000 --- a/drivers/bluetooth/bt3c_cs.c +++ /dev/null @@ -1,749 +0,0 @@ -/* - * - * Driver for the 3Com Bluetooth PCMCIA card - * - * Copyright (C) 2001-2002 Marcel Holtmann - * Jose Orlando Pereira - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - * - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include - - - -/* ======================== Module parameters ======================== */ - - -MODULE_AUTHOR("Marcel Holtmann "); -MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("BT3CPCC.bin"); - - - -/* ======================== Local structures ======================== */ - - -struct bt3c_info { - struct pcmcia_device *p_dev; - - struct hci_dev *hdev; - - spinlock_t lock; /* For serializing operations */ - - struct sk_buff_head txq; - unsigned long tx_state; - - unsigned long rx_state; - unsigned long rx_count; - struct sk_buff *rx_skb; -}; - - -static int bt3c_config(struct pcmcia_device *link); -static void bt3c_release(struct pcmcia_device *link); - -static void bt3c_detach(struct pcmcia_device *p_dev); - - -/* Transmit states */ -#define XMIT_SENDING 1 -#define XMIT_WAKEUP 2 -#define XMIT_WAITING 8 - -/* Receiver states */ -#define RECV_WAIT_PACKET_TYPE 0 -#define RECV_WAIT_EVENT_HEADER 1 -#define RECV_WAIT_ACL_HEADER 2 -#define RECV_WAIT_SCO_HEADER 3 -#define RECV_WAIT_DATA 4 - - - -/* ======================== Special I/O functions ======================== */ - - -#define DATA_L 0 -#define DATA_H 1 -#define ADDR_L 2 -#define ADDR_H 3 -#define CONTROL 4 - - -static inline void bt3c_address(unsigned int iobase, unsigned short addr) -{ - outb(addr & 0xff, iobase + ADDR_L); - outb((addr >> 8) & 0xff, iobase + ADDR_H); -} - - -static inline void bt3c_put(unsigned int iobase, unsigned short value) -{ - outb(value & 0xff, iobase + DATA_L); - outb((value >> 8) & 0xff, iobase + DATA_H); -} - - -static inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value) -{ - bt3c_address(iobase, addr); - bt3c_put(iobase, value); -} - - -static inline unsigned short bt3c_get(unsigned int iobase) -{ - unsigned short value = inb(iobase + DATA_L); - - value |= inb(iobase + DATA_H) << 8; - - return value; -} - - -static inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr) -{ - bt3c_address(iobase, addr); - - return bt3c_get(iobase); -} - - - -/* ======================== Interrupt handling ======================== */ - - -static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) -{ - int actual = 0; - - bt3c_address(iobase, 0x7080); - - /* Fill FIFO with current frame */ - while (actual < len) { - /* Transmit next byte */ - bt3c_put(iobase, buf[actual]); - actual++; - } - - bt3c_io_write(iobase, 0x7005, actual); - - return actual; -} - - -static void bt3c_write_wakeup(struct bt3c_info *info) -{ - if (!info) { - BT_ERR("Unknown device"); - return; - } - - if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) - return; - - do { - unsigned int iobase = info->p_dev->resource[0]->start; - register struct sk_buff *skb; - int len; - - if (!pcmcia_dev_present(info->p_dev)) - break; - - skb = skb_dequeue(&(info->txq)); - if (!skb) { - clear_bit(XMIT_SENDING, &(info->tx_state)); - break; - } - - /* Send frame */ - len = bt3c_write(iobase, 256, skb->data, skb->len); - - if (len != skb->len) - BT_ERR("Very strange"); - - kfree_skb(skb); - - info->hdev->stat.byte_tx += len; - - } while (0); -} - - -static void bt3c_receive(struct bt3c_info *info) -{ - unsigned int iobase; - int size = 0, avail; - - if (!info) { - BT_ERR("Unknown device"); - return; - } - - iobase = info->p_dev->resource[0]->start; - - avail = bt3c_read(iobase, 0x7006); - - bt3c_address(iobase, 0x7480); - while (size < avail) { - size++; - info->hdev->stat.byte_rx++; - - /* Allocate packet */ - if (!info->rx_skb) { - info->rx_state = RECV_WAIT_PACKET_TYPE; - info->rx_count = 0; - info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); - if (!info->rx_skb) { - BT_ERR("Can't allocate mem for new packet"); - return; - } - } - - - if (info->rx_state == RECV_WAIT_PACKET_TYPE) { - - hci_skb_pkt_type(info->rx_skb) = inb(iobase + DATA_L); - inb(iobase + DATA_H); - - switch (hci_skb_pkt_type(info->rx_skb)) { - - case HCI_EVENT_PKT: - info->rx_state = RECV_WAIT_EVENT_HEADER; - info->rx_count = HCI_EVENT_HDR_SIZE; - break; - - case HCI_ACLDATA_PKT: - info->rx_state = RECV_WAIT_ACL_HEADER; - info->rx_count = HCI_ACL_HDR_SIZE; - break; - - case HCI_SCODATA_PKT: - info->rx_state = RECV_WAIT_SCO_HEADER; - info->rx_count = HCI_SCO_HDR_SIZE; - break; - - default: - /* Unknown packet */ - BT_ERR("Unknown HCI packet with type 0x%02x received", - hci_skb_pkt_type(info->rx_skb)); - info->hdev->stat.err_rx++; - - kfree_skb(info->rx_skb); - info->rx_skb = NULL; - break; - - } - - } else { - - __u8 x = inb(iobase + DATA_L); - - skb_put_u8(info->rx_skb, x); - inb(iobase + DATA_H); - info->rx_count--; - - if (info->rx_count == 0) { - - int dlen; - struct hci_event_hdr *eh; - struct hci_acl_hdr *ah; - struct hci_sco_hdr *sh; - - switch (info->rx_state) { - - case RECV_WAIT_EVENT_HEADER: - eh = hci_event_hdr(info->rx_skb); - info->rx_state = RECV_WAIT_DATA; - info->rx_count = eh->plen; - break; - - case RECV_WAIT_ACL_HEADER: - ah = hci_acl_hdr(info->rx_skb); - dlen = __le16_to_cpu(ah->dlen); - info->rx_state = RECV_WAIT_DATA; - info->rx_count = dlen; - break; - - case RECV_WAIT_SCO_HEADER: - sh = hci_sco_hdr(info->rx_skb); - info->rx_state = RECV_WAIT_DATA; - info->rx_count = sh->dlen; - break; - - case RECV_WAIT_DATA: - hci_recv_frame(info->hdev, info->rx_skb); - info->rx_skb = NULL; - break; - - } - - } - - } - - } - - bt3c_io_write(iobase, 0x7006, 0x0000); -} - - -static irqreturn_t bt3c_interrupt(int irq, void *dev_inst) -{ - struct bt3c_info *info = dev_inst; - unsigned int iobase; - int iir; - irqreturn_t r = IRQ_NONE; - - if (!info || !info->hdev) - /* our irq handler is shared */ - return IRQ_NONE; - - iobase = info->p_dev->resource[0]->start; - - spin_lock(&(info->lock)); - - iir = inb(iobase + CONTROL); - if (iir & 0x80) { - int stat = bt3c_read(iobase, 0x7001); - - if ((stat & 0xff) == 0x7f) { - BT_ERR("Very strange (stat=0x%04x)", stat); - } else if ((stat & 0xff) != 0xff) { - if (stat & 0x0020) { - int status = bt3c_read(iobase, 0x7002) & 0x10; - bt_dev_info(info->hdev, "Antenna %s", - status ? "out" : "in"); - } - if (stat & 0x0001) - bt3c_receive(info); - if (stat & 0x0002) { - clear_bit(XMIT_SENDING, &(info->tx_state)); - bt3c_write_wakeup(info); - } - - bt3c_io_write(iobase, 0x7001, 0x0000); - - outb(iir, iobase + CONTROL); - } - r = IRQ_HANDLED; - } - - spin_unlock(&(info->lock)); - - return r; -} - - - -/* ======================== HCI interface ======================== */ - - -static int bt3c_hci_flush(struct hci_dev *hdev) -{ - struct bt3c_info *info = hci_get_drvdata(hdev); - - /* Drop TX queue */ - skb_queue_purge(&(info->txq)); - - return 0; -} - - -static int bt3c_hci_open(struct hci_dev *hdev) -{ - return 0; -} - - -static int bt3c_hci_close(struct hci_dev *hdev) -{ - bt3c_hci_flush(hdev); - - return 0; -} - - -static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) -{ - struct bt3c_info *info = hci_get_drvdata(hdev); - unsigned long flags; - - switch (hci_skb_pkt_type(skb)) { - case HCI_COMMAND_PKT: - hdev->stat.cmd_tx++; - break; - case HCI_ACLDATA_PKT: - hdev->stat.acl_tx++; - break; - case HCI_SCODATA_PKT: - hdev->stat.sco_tx++; - break; - } - - /* Prepend skb with frame type */ - memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); - skb_queue_tail(&(info->txq), skb); - - spin_lock_irqsave(&(info->lock), flags); - - bt3c_write_wakeup(info); - - spin_unlock_irqrestore(&(info->lock), flags); - - return 0; -} - - - -/* ======================== Card services HCI interaction ======================== */ - - -static int bt3c_load_firmware(struct bt3c_info *info, - const unsigned char *firmware, - int count) -{ - char *ptr = (char *) firmware; - char b[9]; - unsigned int iobase, tmp, tn; - unsigned long size, addr, fcs; - int i, err = 0; - - iobase = info->p_dev->resource[0]->start; - - /* Reset */ - bt3c_io_write(iobase, 0x8040, 0x0404); - bt3c_io_write(iobase, 0x8040, 0x0400); - - udelay(1); - - bt3c_io_write(iobase, 0x8040, 0x0404); - - udelay(17); - - /* Load */ - while (count) { - if (ptr[0] != 'S') { - BT_ERR("Bad address in firmware"); - err = -EFAULT; - goto error; - } - - memset(b, 0, sizeof(b)); - memcpy(b, ptr + 2, 2); - if (kstrtoul(b, 16, &size) < 0) - return -EINVAL; - - memset(b, 0, sizeof(b)); - memcpy(b, ptr + 4, 8); - if (kstrtoul(b, 16, &addr) < 0) - return -EINVAL; - - memset(b, 0, sizeof(b)); - memcpy(b, ptr + (size * 2) + 2, 2); - if (kstrtoul(b, 16, &fcs) < 0) - return -EINVAL; - - memset(b, 0, sizeof(b)); - for (tmp = 0, i = 0; i < size; i++) { - memcpy(b, ptr + (i * 2) + 2, 2); - if (kstrtouint(b, 16, &tn)) - return -EINVAL; - tmp += tn; - } - - if (((tmp + fcs) & 0xff) != 0xff) { - BT_ERR("Checksum error in firmware"); - err = -EILSEQ; - goto error; - } - - if (ptr[1] == '3') { - bt3c_address(iobase, addr); - - memset(b, 0, sizeof(b)); - for (i = 0; i < (size - 4) / 2; i++) { - memcpy(b, ptr + (i * 4) + 12, 4); - if (kstrtouint(b, 16, &tmp)) - return -EINVAL; - bt3c_put(iobase, tmp); - } - } - - ptr += (size * 2) + 6; - count -= (size * 2) + 6; - } - - udelay(17); - - /* Boot */ - bt3c_address(iobase, 0x3000); - outb(inb(iobase + CONTROL) | 0x40, iobase + CONTROL); - -error: - udelay(17); - - /* Clear */ - bt3c_io_write(iobase, 0x7006, 0x0000); - bt3c_io_write(iobase, 0x7005, 0x0000); - bt3c_io_write(iobase, 0x7001, 0x0000); - - return err; -} - - -static int bt3c_open(struct bt3c_info *info) -{ - const struct firmware *firmware; - struct hci_dev *hdev; - int err; - - spin_lock_init(&(info->lock)); - - skb_queue_head_init(&(info->txq)); - - info->rx_state = RECV_WAIT_PACKET_TYPE; - info->rx_count = 0; - info->rx_skb = NULL; - - /* Initialize HCI device */ - hdev = hci_alloc_dev(); - if (!hdev) { - BT_ERR("Can't allocate HCI device"); - return -ENOMEM; - } - - info->hdev = hdev; - - hdev->bus = HCI_PCCARD; - hci_set_drvdata(hdev, info); - SET_HCIDEV_DEV(hdev, &info->p_dev->dev); - - hdev->open = bt3c_hci_open; - hdev->close = bt3c_hci_close; - hdev->flush = bt3c_hci_flush; - hdev->send = bt3c_hci_send_frame; - - /* Load firmware */ - err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev); - if (err < 0) { - BT_ERR("Firmware request failed"); - goto error; - } - - err = bt3c_load_firmware(info, firmware->data, firmware->size); - - release_firmware(firmware); - - if (err < 0) { - BT_ERR("Firmware loading failed"); - goto error; - } - - /* Timeout before it is safe to send the first HCI packet */ - msleep(1000); - - /* Register HCI device */ - err = hci_register_dev(hdev); - if (err < 0) { - BT_ERR("Can't register HCI device"); - goto error; - } - - return 0; - -error: - info->hdev = NULL; - hci_free_dev(hdev); - return err; -} - - -static int bt3c_close(struct bt3c_info *info) -{ - struct hci_dev *hdev = info->hdev; - - if (!hdev) - return -ENODEV; - - bt3c_hci_close(hdev); - - hci_unregister_dev(hdev); - hci_free_dev(hdev); - - return 0; -} - -static int bt3c_probe(struct pcmcia_device *link) -{ - struct bt3c_info *info; - - /* Create new info device */ - info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->p_dev = link; - link->priv = info; - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | - CONF_AUTO_SET_IO; - - return bt3c_config(link); -} - - -static void bt3c_detach(struct pcmcia_device *link) -{ - bt3c_release(link); -} - -static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data) -{ - int *try = priv_data; - - if (!try) - p_dev->io_lines = 16; - - if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0)) - return -EINVAL; - - p_dev->resource[0]->end = 8; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - - return pcmcia_request_io(p_dev); -} - -static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev, - void *priv_data) -{ - static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; - int j; - - if (p_dev->io_lines > 3) - return -ENODEV; - - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->resource[0]->end = 8; - - for (j = 0; j < 5; j++) { - p_dev->resource[0]->start = base[j]; - p_dev->io_lines = base[j] ? 16 : 3; - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -ENODEV; -} - -static int bt3c_config(struct pcmcia_device *link) -{ - struct bt3c_info *info = link->priv; - int i; - unsigned long try; - - /* First pass: look for a config entry that looks normal. - * Two tries: without IO aliases, then with aliases - */ - for (try = 0; try < 2; try++) - if (!pcmcia_loop_config(link, bt3c_check_config, (void *) try)) - goto found_port; - - /* Second pass: try to find an entry that isn't picky about - * its base address, then try to grab any standard serial port - * address, and finally try to get any free port. - */ - if (!pcmcia_loop_config(link, bt3c_check_config_notpicky, NULL)) - goto found_port; - - BT_ERR("No usable port range found"); - goto failed; - -found_port: - i = pcmcia_request_irq(link, &bt3c_interrupt); - if (i != 0) - goto failed; - - i = pcmcia_enable_device(link); - if (i != 0) - goto failed; - - if (bt3c_open(info) != 0) - goto failed; - - return 0; - -failed: - bt3c_release(link); - return -ENODEV; -} - - -static void bt3c_release(struct pcmcia_device *link) -{ - struct bt3c_info *info = link->priv; - - bt3c_close(info); - - pcmcia_disable_device(link); -} - - -static const struct pcmcia_device_id bt3c_ids[] = { - PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, bt3c_ids); - -static struct pcmcia_driver bt3c_driver = { - .owner = THIS_MODULE, - .name = "bt3c_cs", - .probe = bt3c_probe, - .remove = bt3c_detach, - .id_table = bt3c_ids, -}; -module_pcmcia_driver(bt3c_driver); diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c deleted file mode 100644 index 2adfe4fade76..000000000000 --- a/drivers/bluetooth/dtl1_cs.c +++ /dev/null @@ -1,614 +0,0 @@ -/* - * - * A driver for Nokia Connectivity Card DTL-1 devices - * - * Copyright (C) 2001-2002 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - * - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - - - -/* ======================== Module parameters ======================== */ - - -MODULE_AUTHOR("Marcel Holtmann "); -MODULE_DESCRIPTION("Bluetooth driver for Nokia Connectivity Card DTL-1"); -MODULE_LICENSE("GPL"); - - - -/* ======================== Local structures ======================== */ - - -struct dtl1_info { - struct pcmcia_device *p_dev; - - struct hci_dev *hdev; - - spinlock_t lock; /* For serializing operations */ - - unsigned long flowmask; /* HCI flow mask */ - int ri_latch; - - struct sk_buff_head txq; - unsigned long tx_state; - - unsigned long rx_state; - unsigned long rx_count; - struct sk_buff *rx_skb; -}; - - -static int dtl1_config(struct pcmcia_device *link); - - -/* Transmit states */ -#define XMIT_SENDING 1 -#define XMIT_WAKEUP 2 -#define XMIT_WAITING 8 - -/* Receiver States */ -#define RECV_WAIT_NSH 0 -#define RECV_WAIT_DATA 1 - - -struct nsh { - u8 type; - u8 zero; - u16 len; -} __packed; /* Nokia Specific Header */ - -#define NSHL 4 /* Nokia Specific Header Length */ - - - -/* ======================== Interrupt handling ======================== */ - - -static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) -{ - int actual = 0; - - /* Tx FIFO should be empty */ - if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) - return 0; - - /* Fill FIFO with current frame */ - while ((fifo_size-- > 0) && (actual < len)) { - /* Transmit next byte */ - outb(buf[actual], iobase + UART_TX); - actual++; - } - - return actual; -} - - -static void dtl1_write_wakeup(struct dtl1_info *info) -{ - if (!info) { - BT_ERR("Unknown device"); - return; - } - - if (test_bit(XMIT_WAITING, &(info->tx_state))) { - set_bit(XMIT_WAKEUP, &(info->tx_state)); - return; - } - - if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { - set_bit(XMIT_WAKEUP, &(info->tx_state)); - return; - } - - do { - unsigned int iobase = info->p_dev->resource[0]->start; - register struct sk_buff *skb; - int len; - - clear_bit(XMIT_WAKEUP, &(info->tx_state)); - - if (!pcmcia_dev_present(info->p_dev)) - return; - - skb = skb_dequeue(&(info->txq)); - if (!skb) - break; - - /* Send frame */ - len = dtl1_write(iobase, 32, skb->data, skb->len); - - if (len == skb->len) { - set_bit(XMIT_WAITING, &(info->tx_state)); - kfree_skb(skb); - } else { - skb_pull(skb, len); - skb_queue_head(&(info->txq), skb); - } - - info->hdev->stat.byte_tx += len; - - } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); - - clear_bit(XMIT_SENDING, &(info->tx_state)); -} - - -static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb) -{ - u8 flowmask = *(u8 *)skb->data; - int i; - - printk(KERN_INFO "Bluetooth: Nokia control data ="); - for (i = 0; i < skb->len; i++) - printk(" %02x", skb->data[i]); - - printk("\n"); - - /* transition to active state */ - if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) { - clear_bit(XMIT_WAITING, &(info->tx_state)); - dtl1_write_wakeup(info); - } - - info->flowmask = flowmask; - - kfree_skb(skb); -} - - -static void dtl1_receive(struct dtl1_info *info) -{ - unsigned int iobase; - struct nsh *nsh; - int boguscount = 0; - - if (!info) { - BT_ERR("Unknown device"); - return; - } - - iobase = info->p_dev->resource[0]->start; - - do { - info->hdev->stat.byte_rx++; - - /* Allocate packet */ - if (info->rx_skb == NULL) { - info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); - if (!info->rx_skb) { - BT_ERR("Can't allocate mem for new packet"); - info->rx_state = RECV_WAIT_NSH; - info->rx_count = NSHL; - return; - } - } - - skb_put_u8(info->rx_skb, inb(iobase + UART_RX)); - nsh = (struct nsh *)info->rx_skb->data; - - info->rx_count--; - - if (info->rx_count == 0) { - - switch (info->rx_state) { - case RECV_WAIT_NSH: - info->rx_state = RECV_WAIT_DATA; - info->rx_count = nsh->len + (nsh->len & 0x0001); - break; - case RECV_WAIT_DATA: - hci_skb_pkt_type(info->rx_skb) = nsh->type; - - /* remove PAD byte if it exists */ - if (nsh->len & 0x0001) { - info->rx_skb->tail--; - info->rx_skb->len--; - } - - /* remove NSH */ - skb_pull(info->rx_skb, NSHL); - - switch (hci_skb_pkt_type(info->rx_skb)) { - case 0x80: - /* control data for the Nokia Card */ - dtl1_control(info, info->rx_skb); - break; - case 0x82: - case 0x83: - case 0x84: - /* send frame to the HCI layer */ - hci_skb_pkt_type(info->rx_skb) &= 0x0f; - hci_recv_frame(info->hdev, info->rx_skb); - break; - default: - /* unknown packet */ - BT_ERR("Unknown HCI packet with type 0x%02x received", - hci_skb_pkt_type(info->rx_skb)); - kfree_skb(info->rx_skb); - break; - } - - info->rx_state = RECV_WAIT_NSH; - info->rx_count = NSHL; - info->rx_skb = NULL; - break; - } - - } - - /* Make sure we don't stay here too long */ - if (boguscount++ > 32) - break; - - } while (inb(iobase + UART_LSR) & UART_LSR_DR); -} - - -static irqreturn_t dtl1_interrupt(int irq, void *dev_inst) -{ - struct dtl1_info *info = dev_inst; - unsigned int iobase; - unsigned char msr; - int boguscount = 0; - int iir, lsr; - irqreturn_t r = IRQ_NONE; - - if (!info || !info->hdev) - /* our irq handler is shared */ - return IRQ_NONE; - - iobase = info->p_dev->resource[0]->start; - - spin_lock(&(info->lock)); - - iir = inb(iobase + UART_IIR) & UART_IIR_ID; - while (iir) { - - r = IRQ_HANDLED; - /* Clear interrupt */ - lsr = inb(iobase + UART_LSR); - - switch (iir) { - case UART_IIR_RLSI: - BT_ERR("RLSI"); - break; - case UART_IIR_RDI: - /* Receive interrupt */ - dtl1_receive(info); - break; - case UART_IIR_THRI: - if (lsr & UART_LSR_THRE) { - /* Transmitter ready for data */ - dtl1_write_wakeup(info); - } - break; - default: - BT_ERR("Unhandled IIR=%#x", iir); - break; - } - - /* Make sure we don't stay here too long */ - if (boguscount++ > 100) - break; - - iir = inb(iobase + UART_IIR) & UART_IIR_ID; - - } - - msr = inb(iobase + UART_MSR); - - if (info->ri_latch ^ (msr & UART_MSR_RI)) { - info->ri_latch = msr & UART_MSR_RI; - clear_bit(XMIT_WAITING, &(info->tx_state)); - dtl1_write_wakeup(info); - r = IRQ_HANDLED; - } - - spin_unlock(&(info->lock)); - - return r; -} - - - -/* ======================== HCI interface ======================== */ - - -static int dtl1_hci_open(struct hci_dev *hdev) -{ - return 0; -} - - -static int dtl1_hci_flush(struct hci_dev *hdev) -{ - struct dtl1_info *info = hci_get_drvdata(hdev); - - /* Drop TX queue */ - skb_queue_purge(&(info->txq)); - - return 0; -} - - -static int dtl1_hci_close(struct hci_dev *hdev) -{ - dtl1_hci_flush(hdev); - - return 0; -} - - -static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) -{ - struct dtl1_info *info = hci_get_drvdata(hdev); - struct sk_buff *s; - struct nsh nsh; - - switch (hci_skb_pkt_type(skb)) { - case HCI_COMMAND_PKT: - hdev->stat.cmd_tx++; - nsh.type = 0x81; - break; - case HCI_ACLDATA_PKT: - hdev->stat.acl_tx++; - nsh.type = 0x82; - break; - case HCI_SCODATA_PKT: - hdev->stat.sco_tx++; - nsh.type = 0x83; - break; - default: - return -EILSEQ; - } - - nsh.zero = 0; - nsh.len = skb->len; - - s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); - if (!s) - return -ENOMEM; - - skb_reserve(s, NSHL); - skb_copy_from_linear_data(skb, skb_put(s, skb->len), skb->len); - if (skb->len & 0x0001) - skb_put_u8(s, 0); /* PAD */ - - /* Prepend skb with Nokia frame header and queue */ - memcpy(skb_push(s, NSHL), &nsh, NSHL); - skb_queue_tail(&(info->txq), s); - - dtl1_write_wakeup(info); - - kfree_skb(skb); - - return 0; -} - - - -/* ======================== Card services HCI interaction ======================== */ - - -static int dtl1_open(struct dtl1_info *info) -{ - unsigned long flags; - unsigned int iobase = info->p_dev->resource[0]->start; - struct hci_dev *hdev; - - spin_lock_init(&(info->lock)); - - skb_queue_head_init(&(info->txq)); - - info->rx_state = RECV_WAIT_NSH; - info->rx_count = NSHL; - info->rx_skb = NULL; - - set_bit(XMIT_WAITING, &(info->tx_state)); - - /* Initialize HCI device */ - hdev = hci_alloc_dev(); - if (!hdev) { - BT_ERR("Can't allocate HCI device"); - return -ENOMEM; - } - - info->hdev = hdev; - - hdev->bus = HCI_PCCARD; - hci_set_drvdata(hdev, info); - SET_HCIDEV_DEV(hdev, &info->p_dev->dev); - - hdev->open = dtl1_hci_open; - hdev->close = dtl1_hci_close; - hdev->flush = dtl1_hci_flush; - hdev->send = dtl1_hci_send_frame; - - spin_lock_irqsave(&(info->lock), flags); - - /* Reset UART */ - outb(0, iobase + UART_MCR); - - /* Turn off interrupts */ - outb(0, iobase + UART_IER); - - /* Initialize UART */ - outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ - outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); - - info->ri_latch = inb(info->p_dev->resource[0]->start + UART_MSR) - & UART_MSR_RI; - - /* Turn on interrupts */ - outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); - - spin_unlock_irqrestore(&(info->lock), flags); - - /* Timeout before it is safe to send the first HCI packet */ - msleep(2000); - - /* Register HCI device */ - if (hci_register_dev(hdev) < 0) { - BT_ERR("Can't register HCI device"); - info->hdev = NULL; - hci_free_dev(hdev); - return -ENODEV; - } - - return 0; -} - - -static int dtl1_close(struct dtl1_info *info) -{ - unsigned long flags; - unsigned int iobase = info->p_dev->resource[0]->start; - struct hci_dev *hdev = info->hdev; - - if (!hdev) - return -ENODEV; - - dtl1_hci_close(hdev); - - spin_lock_irqsave(&(info->lock), flags); - - /* Reset UART */ - outb(0, iobase + UART_MCR); - - /* Turn off interrupts */ - outb(0, iobase + UART_IER); - - spin_unlock_irqrestore(&(info->lock), flags); - - hci_unregister_dev(hdev); - hci_free_dev(hdev); - - return 0; -} - -static int dtl1_probe(struct pcmcia_device *link) -{ - struct dtl1_info *info; - - /* Create new info device */ - info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->p_dev = link; - link->priv = info; - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - return dtl1_config(link); -} - - -static void dtl1_detach(struct pcmcia_device *link) -{ - struct dtl1_info *info = link->priv; - - dtl1_close(info); - pcmcia_disable_device(link); -} - -static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data) -{ - if ((p_dev->resource[1]->end) || (p_dev->resource[1]->end < 8)) - return -ENODEV; - - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - - return pcmcia_request_io(p_dev); -} - -static int dtl1_config(struct pcmcia_device *link) -{ - struct dtl1_info *info = link->priv; - int ret; - - /* Look for a generic full-sized window */ - link->resource[0]->end = 8; - ret = pcmcia_loop_config(link, dtl1_confcheck, NULL); - if (ret) - goto failed; - - ret = pcmcia_request_irq(link, dtl1_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - ret = dtl1_open(info); - if (ret) - goto failed; - - return 0; - -failed: - dtl1_detach(link); - return ret; -} - -static const struct pcmcia_device_id dtl1_ids[] = { - PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d), - PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82), - PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863), - PCMCIA_DEVICE_PROD_ID12("Socket", "CF+ Personal Network Card", 0xb38bcc2e, 0xe732bae3), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, dtl1_ids); - -static struct pcmcia_driver dtl1_driver = { - .owner = THIS_MODULE, - .name = "dtl1_cs", - .probe = dtl1_probe, - .remove = dtl1_detach, - .id_table = dtl1_ids, -}; -module_pcmcia_driver(dtl1_driver); From 79cf74d870603939183760888ea1cf0ff787d6b1 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 12 May 2026 04:12:16 -0700 Subject: [PATCH 13/49] Bluetooth: hci_sock: write the full optval for getsockopt In hci_sock_getsockopt_old(), HCI_DATA_DIR and HCI_TIME_STAMP both store their value into a local int and then call put_user(opt, optval). Because optval is the function parameter typed char __user *, put_user sizes the write from sizeof(*optval), so only the low byte of the int is copied to userspace. The matching setsockopt path reads sizeof(int) via copy_safe_from_sockptr, so userspace passes a 4-byte buffer in both directions but previously got back only one initialized byte on the read side. Not sending this through 'net' tree given this bug is mostly invisble, given opt is 0/1, and the last byte is being properly copied. With this change, the upcoming translation to .getsockopt_iter becomes mechanical. FWIW: This behavior appeared in commit 1da177e4c3f4 ("Linux-2.6.12-rc2"). Signed-off-by: Breno Leitao Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 0290dea081f6..1823c06ba894 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -2088,7 +2088,7 @@ static int hci_sock_getsockopt_old(struct socket *sock, int level, int optname, else opt = 0; - if (put_user(opt, optval)) + if (put_user(opt, (int __user *)optval)) err = -EFAULT; break; @@ -2098,7 +2098,7 @@ static int hci_sock_getsockopt_old(struct socket *sock, int level, int optname, else opt = 0; - if (put_user(opt, optval)) + if (put_user(opt, (int __user *)optval)) err = -EFAULT; break; From ad6cde306654504209f5602b00d6ceac681e29f2 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 12 May 2026 04:12:17 -0700 Subject: [PATCH 14/49] Bluetooth: hci_sock: convert to getsockopt_iter Convert HCI socket's getsockopt implementation to use the new getsockopt_iter callback with sockopt_t. Key changes: - Replace (char __user *optval, int __user *optlen) with sockopt_t *sopt - Use sopt->optlen for buffer length (input) - Use copy_to_iter() instead of put_user()/copy_to_user() - Add linux/uio.h for copy_to_iter() The sockopt_t parameter is named sopt rather than opt to avoid collision with the existing local int opt used by HCI_DATA_DIR and HCI_TIME_STAMP. Signed-off-by: Breno Leitao Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sock.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 1823c06ba894..61fec674a207 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -2063,7 +2064,7 @@ done: } static int hci_sock_getsockopt_old(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) + sockopt_t *sopt) { struct hci_ufilter uf; struct sock *sk = sock->sk; @@ -2071,8 +2072,7 @@ static int hci_sock_getsockopt_old(struct socket *sock, int level, int optname, BT_DBG("sk %p, opt %d", sk, optname); - if (get_user(len, optlen)) - return -EFAULT; + len = sopt->optlen; lock_sock(sk); @@ -2088,7 +2088,8 @@ static int hci_sock_getsockopt_old(struct socket *sock, int level, int optname, else opt = 0; - if (put_user(opt, (int __user *)optval)) + if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) != + sizeof(opt)) err = -EFAULT; break; @@ -2098,7 +2099,8 @@ static int hci_sock_getsockopt_old(struct socket *sock, int level, int optname, else opt = 0; - if (put_user(opt, (int __user *)optval)) + if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) != + sizeof(opt)) err = -EFAULT; break; @@ -2114,7 +2116,7 @@ static int hci_sock_getsockopt_old(struct socket *sock, int level, int optname, } len = min_t(unsigned int, len, sizeof(uf)); - if (copy_to_user(optval, &uf, len)) + if (copy_to_iter(&uf, len, &sopt->iter_out) != len) err = -EFAULT; break; @@ -2129,16 +2131,16 @@ done: } static int hci_sock_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) + sockopt_t *sopt) { struct sock *sk = sock->sk; int err = 0; + u16 mtu; BT_DBG("sk %p, opt %d", sk, optname); if (level == SOL_HCI) - return hci_sock_getsockopt_old(sock, level, optname, optval, - optlen); + return hci_sock_getsockopt_old(sock, level, optname, sopt); if (level != SOL_BLUETOOTH) return -ENOPROTOOPT; @@ -2148,7 +2150,9 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, switch (optname) { case BT_SNDMTU: case BT_RCVMTU: - if (put_user(hci_pi(sk)->mtu, (u16 __user *)optval)) + mtu = hci_pi(sk)->mtu; + if (copy_to_iter(&mtu, sizeof(mtu), &sopt->iter_out) != + sizeof(mtu)) err = -EFAULT; break; @@ -2185,7 +2189,7 @@ static const struct proto_ops hci_sock_ops = { .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = hci_sock_setsockopt, - .getsockopt = hci_sock_getsockopt, + .getsockopt_iter = hci_sock_getsockopt, .connect = sock_no_connect, .socketpair = sock_no_socketpair, .accept = sock_no_accept, From bafa5552d646959e320b6376df884844742395bd Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 12 May 2026 04:12:18 -0700 Subject: [PATCH 15/49] Bluetooth: ISO: convert to getsockopt_iter Convert ISO socket's getsockopt implementation to use the new getsockopt_iter callback with sockopt_t. Key changes: - Replace (char __user *optval, int __user *optlen) with sockopt_t *opt - Use opt->optlen for buffer length (input) and returned size (output) - Use copy_to_iter() instead of put_user()/copy_to_user() - Add linux/uio.h for copy_to_iter() Signed-off-by: Breno Leitao Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/iso.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 3abd8111dda8..793a481d7066 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -1882,18 +1883,17 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname, } static int iso_sock_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) + sockopt_t *opt) { struct sock *sk = sock->sk; - int len, err = 0; struct bt_iso_qos *qos; + int len, val, err = 0; u8 base_len; u8 *base; BT_DBG("sk %p", sk); - if (get_user(len, optlen)) - return -EFAULT; + len = opt->optlen; lock_sock(sk); @@ -1904,15 +1904,17 @@ static int iso_sock_getsockopt(struct socket *sock, int level, int optname, break; } - if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), - (u32 __user *)optval)) + val = test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + if (copy_to_iter(&val, sizeof(val), &opt->iter_out) != + sizeof(val)) err = -EFAULT; break; case BT_PKT_STATUS: - if (put_user(test_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags), - (int __user *)optval)) + val = test_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags); + if (copy_to_iter(&val, sizeof(val), &opt->iter_out) != + sizeof(val)) err = -EFAULT; break; @@ -1920,7 +1922,7 @@ static int iso_sock_getsockopt(struct socket *sock, int level, int optname, qos = iso_sock_get_qos(sk); len = min_t(unsigned int, len, sizeof(*qos)); - if (copy_to_user(optval, qos, len)) + if (copy_to_iter(qos, len, &opt->iter_out) != len) err = -EFAULT; break; @@ -1936,9 +1938,8 @@ static int iso_sock_getsockopt(struct socket *sock, int level, int optname, } len = min_t(unsigned int, len, base_len); - if (copy_to_user(optval, base, len)) - err = -EFAULT; - if (put_user(len, optlen)) + opt->optlen = len; + if (copy_to_iter(base, len, &opt->iter_out) != len) err = -EFAULT; break; @@ -2705,7 +2706,7 @@ static const struct proto_ops iso_sock_ops = { .socketpair = sock_no_socketpair, .shutdown = iso_sock_shutdown, .setsockopt = iso_sock_setsockopt, - .getsockopt = iso_sock_getsockopt + .getsockopt_iter = iso_sock_getsockopt }; static const struct net_proto_family iso_sock_family_ops = { From 69092990519b882127be93d5c412a737eb9f2578 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 12 May 2026 04:12:19 -0700 Subject: [PATCH 16/49] Bluetooth: RFCOMM: convert to getsockopt_iter Convert RFCOMM socket's getsockopt implementation to use the new getsockopt_iter callback with sockopt_t. Key changes: - Replace (char __user *optval, int __user *optlen) with sockopt_t *sopt - Use sopt->optlen for buffer length (input) - Use copy_to_iter() instead of put_user()/copy_to_user() - Add linux/uio.h for copy_to_iter() The sockopt_t parameter is named sopt rather than opt to avoid collision with the existing local u32 opt used by RFCOMM_LM. Signed-off-by: Breno Leitao Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/rfcomm/sock.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 805ed5d28ed6..ed31d5f4fc76 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -740,7 +741,8 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, return err; } -static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen) +static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, + sockopt_t *sopt) { struct sock *sk = sock->sk; struct sock *l2cap_sk; @@ -752,8 +754,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u BT_DBG("sk %p", sk); - if (get_user(len, optlen)) - return -EFAULT; + len = sopt->optlen; lock_sock(sk); @@ -782,7 +783,8 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u if (rfcomm_pi(sk)->role_switch) opt |= RFCOMM_LM_MASTER; - if (put_user(opt, (u32 __user *) optval)) + if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) != + sizeof(opt)) err = -EFAULT; break; @@ -802,7 +804,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u memcpy(cinfo.dev_class, conn->hcon->dev_class, 3); len = min(len, sizeof(cinfo)); - if (copy_to_user(optval, (char *) &cinfo, len)) + if (copy_to_iter(&cinfo, len, &sopt->iter_out) != len) err = -EFAULT; break; @@ -816,23 +818,24 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u return err; } -static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) +static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, + sockopt_t *sopt) { struct sock *sk = sock->sk; struct bt_security sec; int err = 0; size_t len; + u32 opt; BT_DBG("sk %p", sk); if (level == SOL_RFCOMM) - return rfcomm_sock_getsockopt_old(sock, optname, optval, optlen); + return rfcomm_sock_getsockopt_old(sock, optname, sopt); if (level != SOL_BLUETOOTH) return -ENOPROTOOPT; - if (get_user(len, optlen)) - return -EFAULT; + len = sopt->optlen; lock_sock(sk); @@ -847,7 +850,7 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c sec.key_size = 0; len = min(len, sizeof(sec)); - if (copy_to_user(optval, (char *) &sec, len)) + if (copy_to_iter(&sec, len, &sopt->iter_out) != len) err = -EFAULT; break; @@ -858,8 +861,9 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c break; } - if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), - (u32 __user *) optval)) + opt = test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) != + sizeof(opt)) err = -EFAULT; break; @@ -1039,7 +1043,7 @@ static const struct proto_ops rfcomm_sock_ops = { .recvmsg = rfcomm_sock_recvmsg, .shutdown = rfcomm_sock_shutdown, .setsockopt = rfcomm_sock_setsockopt, - .getsockopt = rfcomm_sock_getsockopt, + .getsockopt_iter = rfcomm_sock_getsockopt, .ioctl = rfcomm_sock_ioctl, .gettstamp = sock_gettstamp, .poll = bt_sock_poll, From bf01627cc04b70c04a6d68eda06f836fed3078bc Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 12 May 2026 04:12:20 -0700 Subject: [PATCH 17/49] Bluetooth: L2CAP: convert to getsockopt_iter Convert L2CAP socket's getsockopt implementation to use the new getsockopt_iter callback with sockopt_t. Key changes: - Replace (char __user *optval, int __user *optlen) with sockopt_t *sopt - Use sopt->optlen for buffer length (input) - Use copy_to_iter() instead of put_user()/copy_to_user() - Add linux/uio.h for copy_to_iter() The sockopt_t parameter is named sopt rather than opt to avoid collision with the existing local u32 opt used by L2CAP_LM. The same naming is reused for the new u32 helper in l2cap_sock_getsockopt(), with mtu and mval helpers covering the u16 and u8 cases. Signed-off-by: Breno Leitao Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/l2cap_sock.c | 61 +++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index c138aa4ae266..025329636353 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -438,7 +439,7 @@ static int l2cap_get_mode(struct l2cap_chan *chan) } static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, - char __user *optval, int __user *optlen) + sockopt_t *sopt) { struct sock *sk = sock->sk; struct l2cap_chan *chan = l2cap_pi(sk)->chan; @@ -450,8 +451,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, BT_DBG("sk %p", sk); - if (get_user(len, optlen)) - return -EFAULT; + len = sopt->optlen; lock_sock(sk); @@ -493,7 +493,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, BT_DBG("mode 0x%2.2x", chan->mode); len = min(len, sizeof(opts)); - if (copy_to_user(optval, (char *) &opts, len)) + if (copy_to_iter(&opts, len, &sopt->iter_out) != len) err = -EFAULT; break; @@ -525,7 +525,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) opt |= L2CAP_LM_RELIABLE; - if (put_user(opt, (u32 __user *) optval)) + if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) != + sizeof(opt)) err = -EFAULT; break; @@ -543,7 +544,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3); len = min(len, sizeof(cinfo)); - if (copy_to_user(optval, (char *) &cinfo, len)) + if (copy_to_iter(&cinfo, len, &sopt->iter_out) != len) err = -EFAULT; break; @@ -558,25 +559,26 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, } static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) + sockopt_t *sopt) { struct sock *sk = sock->sk; struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct bt_security sec; struct bt_power pwr; - u32 phys; int len, mode, err = 0; + u32 opt; + u16 mtu; + u8 mval; BT_DBG("sk %p", sk); if (level == SOL_L2CAP) - return l2cap_sock_getsockopt_old(sock, optname, optval, optlen); + return l2cap_sock_getsockopt_old(sock, optname, sopt); if (level != SOL_BLUETOOTH) return -ENOPROTOOPT; - if (get_user(len, optlen)) - return -EFAULT; + len = sopt->optlen; lock_sock(sk); @@ -600,7 +602,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, } len = min_t(unsigned int, len, sizeof(sec)); - if (copy_to_user(optval, (char *) &sec, len)) + if (copy_to_iter(&sec, len, &sopt->iter_out) != len) err = -EFAULT; break; @@ -611,15 +613,17 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, break; } - if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), - (u32 __user *) optval)) + opt = test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) != + sizeof(opt)) err = -EFAULT; break; case BT_FLUSHABLE: - if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags), - (u32 __user *) optval)) + opt = test_bit(FLAG_FLUSHABLE, &chan->flags); + if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) != + sizeof(opt)) err = -EFAULT; break; @@ -634,13 +638,15 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, pwr.force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags); len = min_t(unsigned int, len, sizeof(pwr)); - if (copy_to_user(optval, (char *) &pwr, len)) + if (copy_to_iter(&pwr, len, &sopt->iter_out) != len) err = -EFAULT; break; case BT_CHANNEL_POLICY: - if (put_user(chan->chan_policy, (u32 __user *) optval)) + opt = chan->chan_policy; + if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) != + sizeof(opt)) err = -EFAULT; break; @@ -655,7 +661,9 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, break; } - if (put_user(chan->omtu, (u16 __user *) optval)) + mtu = chan->omtu; + if (copy_to_iter(&mtu, sizeof(mtu), &sopt->iter_out) != + sizeof(mtu)) err = -EFAULT; break; @@ -665,7 +673,9 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, break; } - if (put_user(chan->imtu, (u16 __user *) optval)) + mtu = chan->imtu; + if (copy_to_iter(&mtu, sizeof(mtu), &sopt->iter_out) != + sizeof(mtu)) err = -EFAULT; break; @@ -675,9 +685,10 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, break; } - phys = hci_conn_get_phy(chan->conn->hcon); + opt = hci_conn_get_phy(chan->conn->hcon); - if (put_user(phys, (u32 __user *) optval)) + if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) != + sizeof(opt)) err = -EFAULT; break; @@ -698,7 +709,9 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, break; } - if (put_user(mode, (u8 __user *) optval)) + mval = mode; + if (copy_to_iter(&mval, sizeof(mval), &sopt->iter_out) != + sizeof(mval)) err = -EFAULT; break; @@ -2039,7 +2052,7 @@ static const struct proto_ops l2cap_sock_ops = { .socketpair = sock_no_socketpair, .shutdown = l2cap_sock_shutdown, .setsockopt = l2cap_sock_setsockopt, - .getsockopt = l2cap_sock_getsockopt + .getsockopt_iter = l2cap_sock_getsockopt }; static const struct net_proto_family l2cap_sock_family_ops = { From 255f8d39aa71240922f8264d9158b7f68c7528bc Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 12 May 2026 04:12:21 -0700 Subject: [PATCH 18/49] Bluetooth: SCO: convert to getsockopt_iter Convert SCO socket's getsockopt implementation to use the new getsockopt_iter callback with sockopt_t. Key changes: - Replace (char __user *optval, int __user *optlen) with sockopt_t *opt - Use opt->optlen for buffer length (input) and returned size (output) - Use copy_to_iter() instead of put_user()/copy_to_user() - Drop the open-coded ptr cursor in BT_CODEC; iter_out advances on every copy_to_iter() naturally - Add linux/uio.h for copy_to_iter() Signed-off-by: Breno Leitao Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/sco.c | 59 ++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 140869e5b2df..451ed32bee76 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -1089,7 +1090,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, } static int sco_sock_getsockopt_old(struct socket *sock, int optname, - char __user *optval, int __user *optlen) + sockopt_t *opt) { struct sock *sk = sock->sk; struct sco_options opts; @@ -1099,8 +1100,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, BT_DBG("sk %p", sk); - if (get_user(len, optlen)) - return -EFAULT; + len = opt->optlen; lock_sock(sk); @@ -1118,7 +1118,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, BT_DBG("mtu %u", opts.mtu); len = min(len, sizeof(opts)); - if (copy_to_user(optval, (char *)&opts, len)) + if (copy_to_iter(&opts, len, &opt->iter_out) != len) err = -EFAULT; break; @@ -1136,7 +1136,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3); len = min(len, sizeof(cinfo)); - if (copy_to_user(optval, (char *)&cinfo, len)) + if (copy_to_iter(&cinfo, len, &opt->iter_out) != len) err = -EFAULT; break; @@ -1151,15 +1151,15 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, } static int sco_sock_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) + sockopt_t *opt) { struct sock *sk = sock->sk; - int len, err = 0; + int len, val, err = 0; struct bt_voice voice; u32 phys; int buf_len; struct codec_list *c; - u8 num_codecs, i, __user *ptr; + u8 num_codecs, i; struct hci_dev *hdev; struct hci_codec_caps *caps; struct bt_codec codec; @@ -1167,10 +1167,9 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, BT_DBG("sk %p", sk); if (level == SOL_SCO) - return sco_sock_getsockopt_old(sock, optname, optval, optlen); + return sco_sock_getsockopt_old(sock, optname, opt); - if (get_user(len, optlen)) - return -EFAULT; + len = opt->optlen; lock_sock(sk); @@ -1182,8 +1181,9 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, break; } - if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), - (u32 __user *)optval)) + val = test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + if (copy_to_iter(&val, sizeof(val), &opt->iter_out) != + sizeof(val)) err = -EFAULT; break; @@ -1192,7 +1192,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, voice.setting = sco_pi(sk)->setting; len = min_t(unsigned int, len, sizeof(voice)); - if (copy_to_user(optval, (char *)&voice, len)) + if (copy_to_iter(&voice, len, &opt->iter_out) != len) err = -EFAULT; break; @@ -1205,13 +1205,15 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, phys = hci_conn_get_phy(sco_pi(sk)->conn->hcon); - if (put_user(phys, (u32 __user *) optval)) + if (copy_to_iter(&phys, sizeof(phys), &opt->iter_out) != + sizeof(phys)) err = -EFAULT; break; case BT_PKT_STATUS: - if (put_user(test_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags), - (int __user *)optval)) + val = test_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags); + if (copy_to_iter(&val, sizeof(val), &opt->iter_out) != + sizeof(val)) err = -EFAULT; break; @@ -1222,7 +1224,9 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, break; } - if (put_user(sco_pi(sk)->conn->mtu, (u32 __user *)optval)) + val = sco_pi(sk)->conn->mtu; + if (copy_to_iter(&val, sizeof(val), &opt->iter_out) != + sizeof(val)) err = -EFAULT; break; @@ -1269,13 +1273,12 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, hci_dev_put(hdev); return -ENOBUFS; } - ptr = optval; - if (put_user(num_codecs, ptr)) { + if (copy_to_iter(&num_codecs, sizeof(num_codecs), + &opt->iter_out) != sizeof(num_codecs)) { hci_dev_put(hdev); return -EFAULT; } - ptr += sizeof(num_codecs); /* Iterate all the codecs supported over SCO and populate * codec data @@ -1292,11 +1295,11 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, if (err < 0) break; codec.num_caps = c->num_caps; - if (copy_to_user(ptr, &codec, sizeof(codec))) { + if (copy_to_iter(&codec, sizeof(codec), &opt->iter_out) + != sizeof(codec)) { err = -EFAULT; break; } - ptr += sizeof(codec); /* find codec capabilities data length */ len = 0; @@ -1306,11 +1309,11 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, } /* copy codec capabilities data */ - if (len && copy_to_user(ptr, c->caps, len)) { + if (len && + copy_to_iter(c->caps, len, &opt->iter_out) != len) { err = -EFAULT; break; } - ptr += len; } hci_dev_unlock(hdev); @@ -1318,8 +1321,8 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, lock_sock(sk); - if (!err && put_user(buf_len, optlen)) - err = -EFAULT; + if (!err) + opt->optlen = buf_len; break; @@ -1594,7 +1597,7 @@ static const struct proto_ops sco_sock_ops = { .socketpair = sock_no_socketpair, .shutdown = sco_sock_shutdown, .setsockopt = sco_sock_setsockopt, - .getsockopt = sco_sock_getsockopt + .getsockopt_iter = sco_sock_getsockopt }; static const struct net_proto_family sco_sock_family_ops = { From a55ef87b61b26097373fe8cbd2ead36582a8df4f Mon Sep 17 00:00:00 2001 From: "luke-yj.chen" Date: Tue, 12 May 2026 14:03:18 +0800 Subject: [PATCH 19/49] Bluetooth: btusb: MT7925: Add VID/PID 13d3/3609 Add VID 13d3 & PID 3609 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=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3609 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: luke-yj.chen 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 70abbabea0a7..71f847c97157 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -789,6 +789,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3608), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3609), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3613), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3627), .driver_info = BTUSB_MEDIATEK | From 5269f7231c2b78774c39ae3a27ce2c497cd5aff4 Mon Sep 17 00:00:00 2001 From: Ravindra Date: Tue, 12 May 2026 14:04:44 +0530 Subject: [PATCH 20/49] Bluetooth: btusb: Add support for Intel Lizard Peak 2 (0x8087:0x0040) Device from /sys/kernel/debug/usb/devices: T: Bus=09 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=8087 ProdID=0040 Rev= 0.00 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= 64 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 Signed-off-by: Ravindra 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 71f847c97157..3523d86a4ba1 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -484,6 +484,7 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x8087, 0x0037), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x0038), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x0039), .driver_info = BTUSB_INTEL_COMBINED }, + { USB_DEVICE(0x8087, 0x0040), .driver_info = BTUSB_INTEL_COMBINED }, /* Lizard Peak 2 */ { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR }, { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED | BTUSB_INTEL_NO_WBS_SUPPORT | From ddb249341df3779c3c5cbe407b196f39921e1c53 Mon Sep 17 00:00:00 2001 From: Jiajia Liu Date: Wed, 20 May 2026 10:15:00 +0800 Subject: [PATCH 21/49] Bluetooth: btmtk: remove extra copy in cmd array init In btmtk_setup_firmware_79xx, the data length indicated by wmt_params.dlen in the cmd buffer is MTK_SEC_MAP_NEED_SEND_SIZE + 1. Except for the first byte, the remaining length is MTK_SEC_MAP_NEED_SEND_SIZE. memcpy copied one more byte to cmd + 1 than the remaining length. Align the length passed to memcpy to avoid exceeding current section map. Signed-off-by: Jiajia Liu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btmtk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index ea7a031000cd..53cba71cb07f 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -188,7 +188,7 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i + MTK_SEC_MAP_COMMON_SIZE, - MTK_SEC_MAP_NEED_SEND_SIZE + 1); + MTK_SEC_MAP_NEED_SEND_SIZE); wmt_params.op = BTMTK_WMT_PATCH_DWNLD; wmt_params.status = &status; From eb87bf6fcae6a2dc25d7f2c977d2cbca2113fb1e Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 26 May 2026 12:43:42 -0400 Subject: [PATCH 22/49] Bluetooth: hci_sync: Add support for HCI_LE_Set_Host_Feature [v2] This adds support for using HCI_LE_Set_Host_Feature [v2] instead of v1 if LL Extented Features is supported and the controller supports the command. Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci.h | 6 ++++++ net/bluetooth/hci_sync.c | 24 +++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 572b1c620c5d..5462f14ea0c6 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -2486,6 +2486,12 @@ struct hci_rp_le_cs_test { #define HCI_OP_LE_CS_TEST_END 0x2096 +#define HCI_OP_LE_SET_HOST_FEATURE_V2 0x2097 +struct hci_cp_le_set_host_feature_v2 { + __le16 bit_number; + __u8 bit_value; +} __packed; + /* ---- HCI Events ---- */ struct hci_ev_status { __u8 status; diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index df23245d6ccd..3be8c3581c6c 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -4588,11 +4588,33 @@ static int hci_set_le_support_sync(struct hci_dev *hdev) sizeof(cp), &cp, HCI_CMD_TIMEOUT); } +/* LE Set Host Feature V2 */ +static int hci_le_set_host_feature_v2_sync(struct hci_dev *hdev, u16 bit, + u8 value) +{ + struct hci_cp_le_set_host_feature_v2 cp; + + memset(&cp, 0, sizeof(cp)); + + /* Connected Isochronous Channels (Host Support) */ + cp.bit_number = cpu_to_le16(bit); + cp.bit_value = value; + + return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_HOST_FEATURE_V2, + sizeof(cp), &cp, HCI_CMD_TIMEOUT); +} + /* LE Set Host Feature */ -static int hci_le_set_host_feature_sync(struct hci_dev *hdev, u8 bit, u8 value) +static int hci_le_set_host_feature_sync(struct hci_dev *hdev, u16 bit, u8 value) { struct hci_cp_le_set_host_feature cp; + if (ll_ext_feature_capable(hdev) && hdev->commands[47] & BIT(4)) + return hci_le_set_host_feature_v2_sync(hdev, bit, value); + + if (bit > 255) + return 0; + memset(&cp, 0, sizeof(cp)); /* Connected Isochronous Channels (Host Support) */ From 88b4d528eda4ac71c2952b3458f2abbc80a91cd2 Mon Sep 17 00:00:00 2001 From: Zenm Chen Date: Tue, 26 May 2026 00:19:42 +0800 Subject: [PATCH 23/49] Bluetooth: btusb: Add USB ID 2c4e:0128 for Mercusys MA60XNB Add USB ID 2c4e:0128 for Mercusys MA60XNB, an RTL8851BU-based Wi-Fi + Bluetooth adapter. The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below: T: Bus=03 Lev=01 Prnt=01 Port=04 Cnt=01 Dev#= 3 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=2c4e ProdID=0128 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=rtw89_8851bu 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 # 6.6.x Signed-off-by: Zenm Chen 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 3523d86a4ba1..a13f10c7a981 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -532,6 +532,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x7392, 0xe611), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x2c4e, 0x0128), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, /* Realtek 8852AE Bluetooth devices */ { USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK | From 3ec629fee178d429f01ae843e4ea888de93012bf Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 1 Jun 2026 04:30:55 -0700 Subject: [PATCH 24/49] Bluetooth: hci_qca: fix NULL pointer dereference in qca_setup() for non-serdev device hu->serdev is NULL for hci_uart attached via non-serdev paths, but qca_setup() unconditionally calls serdev_device_get_drvdata(hu->serdev) and dereferences the result, causing a NULL pointer dereference. Fix by guarding the dereference with a NULL check, consistent with the rest of qca_setup(). Fixes: 22d893eec0d5 ("Bluetooth: hci_qca: Refactor HFP hardware offload capability handling") Signed-off-by: Zijun Hu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_qca.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 34500137df2c..cc7b34a61fa7 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1916,9 +1916,12 @@ static int qca_setup(struct hci_uart *hu) const char *rampatch_name = qca_get_rampatch_name(hu); int ret; struct qca_btsoc_version ver; - struct qca_serdev *qcadev = serdev_device_get_drvdata(hu->serdev); + struct qca_serdev *qcadev = NULL; const char *soc_name; + if (hu->serdev) + qcadev = serdev_device_get_drvdata(hu->serdev); + ret = qca_check_speeds(hu); if (ret) return ret; @@ -1980,7 +1983,7 @@ retry: case QCA_WCN6750: case QCA_WCN6855: case QCA_WCN7850: - if (qcadev->bdaddr_property_broken) + if (qcadev && qcadev->bdaddr_property_broken) hci_set_quirk(hdev, HCI_QUIRK_BDADDR_PROPERTY_BROKEN); hci_set_aosp_capable(hdev); @@ -2073,7 +2076,7 @@ out: else hu->hdev->set_bdaddr = qca_set_bdaddr; - if (qcadev->support_hfp_hw_offload) + if (qcadev && qcadev->support_hfp_hw_offload) qca_configure_hfp_offload(hdev); qca->fw_version = le16_to_cpu(ver.patch_ver); From 6b8cbcf08de0db62254d1981f83db0f94681ccd9 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 1 Jun 2026 04:30:56 -0700 Subject: [PATCH 25/49] Bluetooth: hci_qca: fix NULL pointer dereference in qca_dmp_hdr() for non-serdev device hu->serdev is NULL for hci_uart attached via non-serdev paths, but qca_dmp_hdr() unconditionally dereferences hu->serdev->dev.driver->name, causing a NULL pointer dereference. Fix by guarding the dereference with a NULL check and falling back to "hci_ldisc_qca" for the non-serdev case. Fixes: 06d3fdfcdf5c ("Bluetooth: hci_qca: Add qcom devcoredump support") Signed-off-by: Zijun Hu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_qca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index cc7b34a61fa7..244447195619 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1028,7 +1028,7 @@ static void qca_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb) skb_put_data(skb, buf, strlen(buf)); snprintf(buf, sizeof(buf), "Driver: %s\n", - hu->serdev->dev.driver->name); + hu->serdev ? hu->serdev->dev.driver->name : "hci_ldisc_qca"); skb_put_data(skb, buf, strlen(buf)); } From bc597f0cc44f0b173c50ee986a047219cd559ee9 Mon Sep 17 00:00:00 2001 From: Nils Helmig Date: Sat, 30 May 2026 14:39:34 +0200 Subject: [PATCH 26/49] Bluetooth: btusb: Add TP-Link UB600 for Realtek 8761BUV Add the vendor/product ID (0x37ad, 0x0600) to usb_device_id table for Realtek 8761BUV. The device info from /sys/kernel/debug/usb/devices as below. T: Bus=03 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=37ad ProdID=0600 Rev= 2.00 S: Manufacturer= S: Product=TP-Link Bluetooth USB Adapter S: SerialNumber=ACA7F14FD2A5 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: Nils Helmig Reviewed-by: Paul Menzel 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 a13f10c7a981..3aef21d4ccd3 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -845,6 +845,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x2b89, 0x6275), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x37ad, 0x0600), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, /* Additional Realtek 8821AE Bluetooth devices */ { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, From e31d761628ad7e96490fc78105ed0a064ec1c1d9 Mon Sep 17 00:00:00 2001 From: Rong Zhang Date: Wed, 3 Jun 2026 02:38:10 +0800 Subject: [PATCH 27/49] Bluetooth: btmtk: Disable remote wakeup for MT7922/MT7925 These NICs are often reported to lose their Bluetooth interfaces, i.e, their USB interfaces suddenly become completely unresponsive, causing the USB core to reset them, only to find that they are no longer accessible. A power cycle is required to make the Bluetooth interfaces recover. After some investigations, I found that their USB autosuspend remote wakeup capabilities are so broken that they are precisely the culprit behind the issue: [27452.608056] hub 3-0:1.0: state 7 ports 5 chg 0000 evt 0020 [27452.702018] usb 3-5: usb wakeup-resume [27452.716038] usb 3-5: Waited 0ms for CONNECT [27452.716642] usb 3-5: finish resume /* usbmon showed that the device was completely unresponsive to any URBs after the remote wakeup */ [27457.836030] usb 3-5: retry with reset-resume [27457.956046] usb 3-5: reset high-speed USB device number 4 using xhci_hcd [27463.332047] usb 3-5: device descriptor read/64, error -110 [27478.948117] usb 3-5: device descriptor read/64, error -110 [27479.172430] usb 3-5: reset high-speed USB device number 4 using xhci_hcd [27484.332035] usb 3-5: device descriptor read/64, error -110 [27499.940039] usb 3-5: device descriptor read/64, error -110 [27500.164060] usb 3-5: reset high-speed USB device number 4 using xhci_hcd [27505.196142] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command [27510.576045] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command [27510.784038] usb 3-5: device not accepting address 4, error -62 [27510.912215] usb 3-5: reset high-speed USB device number 4 using xhci_hcd [27515.948307] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command [27521.324380] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command [27521.525107] usb 3-5: device not accepting address 4, error -62 [27521.525928] usb usb3-port5: logical disconnect [27521.525996] usb 3-5: gone after usb resume? status -19 [27521.526230] usb 3-5: can't resume, status -19 [27521.526434] usb usb3-port5: logical disconnect [27521.526469] usb usb3-port5: resume, status -19 [27521.526493] usb usb3-port5: status 0503, change 0004, 480 Mb/s [27521.526528] usb 3-5: USB disconnect, device number 4 [27521.526736] usb 3-5: unregistering device [27521.804029] usb 3-5: new high-speed USB device number 5 using xhci_hcd [27527.076067] usb 3-5: device descriptor read/64, error -110 [27542.692027] usb 3-5: device descriptor read/64, error -110 [27542.916047] usb 3-5: new high-speed USB device number 6 using xhci_hcd [27548.068043] usb 3-5: device descriptor read/64, error -110 [27563.684073] usb 3-5: device descriptor read/64, error -110 [27563.792133] usb usb3-port5: attempt power cycle [27563.924381] hub 3-0:1.0: port_wait_reset: err = -11 [27563.925213] usb usb3-port5: not enabled, trying reset again... [27564.184398] usb 3-5: new high-speed USB device number 7 using xhci_hcd [27569.196322] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command [27574.572040] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command [27574.776053] usb 3-5: device not accepting address 7, error -62 [27574.900165] usb 3-5: new high-speed USB device number 8 using xhci_hcd [27579.948039] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command [27585.324331] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command [27585.528040] usb 3-5: device not accepting address 8, error -62 [27585.528389] usb usb3-port5: unable to enumerate USB device [27585.528424] hub 3-0:1.0: state 7 ports 5 chg 0000 evt 0020 To reproduce the issue, these conditions must be met: - a noisy radio environment (cafe or office) to cause frequent remote wakeup events - no Bluetooth device is connected, so autosuspend is not prohibited - the Bluetooth interface is opened, so remote wakeup is enabled when the device runs into autosuspend Then I can reproduce the issue within sereval hours each time. Increasing TRSMRCY or setting USB_QUIRK_RESET doesn't help at all. Since the remote wakeup capability is super broken, just disable it to get rid of the troubles. The device can still be autosuspended when the bluetooth interface is closed, which won't break the device as remote wakeup is unneeded in this case. Link: https://bbs.archlinux.org/viewtopic.php?id=308169 Link: https://bbs.bee-link.com/d/7694-gtr9-pro-ai-max-395-usb-issues Signed-off-by: Rong Zhang Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btmtk.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index 53cba71cb07f..d7aa5aded649 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -1379,6 +1379,16 @@ int btmtk_usb_setup(struct hci_dev *hdev) break; case 0x7922: case 0x7925: + /* + * A remote wakeup could cause the device completely unresponsive, and + * recovering from such a state needs a power cycle. + * + * Since the remote wakeup capability is super broken, just disable it + * to get rid of the troubles. The device can still be autosuspended + * when the bluetooth interface is closed. + */ + device_set_wakeup_capable(&btmtk_data->udev->dev, false); + fallthrough; case 0x7961: case 0x7902: case 0x6639: From ea77debfe443f505a4edbb7f21340a583a8a143f Mon Sep 17 00:00:00 2001 From: Cris Date: Wed, 3 Jun 2026 11:58:18 +0800 Subject: [PATCH 28/49] Bluetooth: btusb: Add support for TP-Link TL-UB250 Add USB ID 2357:0607 for TP-Link TL-UB250. This is a Realtek RTL8761BUV based Bluetooth adapter. Without this entry the device is picked up by the generic Bluetooth USB class match and exposes hci0, but the Realtek setup path is not used and rtl8761bu firmware/config are not loaded. The controller reports Realtek Semiconductor Corporation as the manufacturer and LMP subversion 0x8761. With this entry added, btusb loads rtl_bt/rtl8761bu_fw.bin and rtl_bt/rtl8761bu_config.bin successfully. Relevant part of /sys/kernel/debug/usb/devices: T: Bus=01 Lev=02 Prnt=06 Port=00 Cnt=01 Dev#= 9 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=2357 ProdID=0607 Rev= 2.00 S: Product=TP-Link TL-UB250 Adapter 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 I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Use the same flags as the existing TP-Link 2357:0604 entry. Reviewed-by: Paul Menzel Signed-off-by: Cris 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 3aef21d4ccd3..3cbb3c22e20f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -831,6 +831,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x2357, 0x0604), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x2357, 0x0607), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x2550, 0x8761), .driver_info = BTUSB_REALTEK | From 6f5fb689fdf80bdd143f22a502f9eb1f3c85e286 Mon Sep 17 00:00:00 2001 From: Weiming Shi Date: Wed, 3 Jun 2026 01:06:21 +0800 Subject: [PATCH 29/49] Bluetooth: eir: Fix stack OOB write when prepending the Flags AD eir_create_adv_data() builds the advertising data into a fixed-size buffer ("size", 31 for the legacy path). It may prepend a 3-byte "Flags" AD structure (LE_AD_NO_BREDR on an LE-only controller) and then copies the per-instance data without checking that it still fits: memcpy(ptr, adv->adv_data, adv->adv_data_len); tlv_data_max_len() only reserves those 3 bytes when the user-supplied flags carry a managed-flags bit, so an instance added with flags == 0 is accepted with adv_data_len up to the full buffer. At advertise time the flags are still prepended, and the memcpy() writes 3 + adv_data_len bytes into the size-byte buffer: BUG: KASAN: stack-out-of-bounds in eir_create_adv_data (net/bluetooth/eir.c:301) Write of size 31 at addr ffff88800a547bdc by task kworker/u9:0/65 Workqueue: hci0 hci_cmd_sync_work __asan_memcpy (mm/kasan/shadow.c:106) eir_create_adv_data (net/bluetooth/eir.c:301) hci_update_adv_data_sync (net/bluetooth/hci_sync.c:1310) hci_schedule_adv_instance_sync (net/bluetooth/hci_sync.c:1817) hci_cmd_sync_work (net/bluetooth/hci_sync.c:332) This frame has 1 object: [32, 64) 'cp' The "Flags" structure is added by the kernel, not requested by userspace, so only prepend it when it fits together with the instance advertising data; when there is no room for both, drop the flags rather than the user-provided data. Reachable by a local user with CAP_NET_ADMIN owning an LE-only controller on the legacy advertising path. Fixes: b44133ff03be ("Bluetooth: Support the "discoverable" adv flag") Reported-by: Xiang Mei Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Weiming Shi Reported-by: Xiang Mei Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/eir.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/eir.c b/net/bluetooth/eir.c index 3f72111ba651..1de5f9df6eec 100644 --- a/net/bluetooth/eir.c +++ b/net/bluetooth/eir.c @@ -283,10 +283,12 @@ u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size) if (!flags) flags |= mgmt_get_adv_discov_flags(hdev); - /* If flags would still be empty, then there is no need to - * include the "Flags" AD field". + /* Only add the "Flags" if it fits together with the instance + * advertising data; drop it rather than overflow the buffer. */ - if (flags && (ad_len + eir_precalc_len(1) <= size)) { + if (flags && + (ad_len + eir_precalc_len(1) + + (adv ? adv->adv_data_len : 0) <= size)) { ptr[0] = 0x02; ptr[1] = EIR_FLAGS; ptr[2] = flags; From 96d006ae6445679436b945593950fd465eba7e76 Mon Sep 17 00:00:00 2001 From: Jiajia Liu Date: Tue, 2 Jun 2026 15:00:32 +0800 Subject: [PATCH 30/49] Bluetooth: hci_event: fix simultaneous discovery stuck in FINDING When hci_inquiry_complete_evt is called between le_scan_disable and le_set_scan_enable_complete and no remote name needs to be resolved, the interleaved discovery with SIMULTANEOUS quirk gets stuck in DISCOVERY_FINDING. le_set_scan_enable_complete does not check inquiry state. No one sets DISCOVERY_STOPPED in this process. Add state check in le_set_scan_enable_complete and change state if the state is DISCOVERY_FINDING. Tested with AX201 (8087:0026) in Dell Vostro 13. Discovering disabled MGMT Event below is reported when running into the above condition. @ MGMT Command: Start Discovery (0x0023) {0x0001} [hci0] 10885.970873 Address type: 0x07 BR/EDR LE Public LE Random ... < HCI Command: LE Set Extended Scan Enable #38205 [hci0] 10886.131438 Extended scan: Enabled (0x01) Filter duplicates: Enabled (0x01) Duration: 0 msec (0x0000) Period: 0.00 sec (0x0000) > HCI Event: Command Complete (0x0e) plen 4 #38206 [hci0] 10886.133295 LE Set Extended Scan Enable (0x08|0x0042) ncmd 2 Status: Success (0x00) @ MGMT Event: Discovering (0x0013) plen 2 {0x0001} [hci0] 10886.133414 Address type: 0x07 BR/EDR LE Public LE Random Discovery: Enabled (0x01) < HCI Command: Inquiry (0x01|0x0001) plen 5 #38207 [hci0] 10886.133528 Access code: 0x9e8b33 (General Inquiry) Length: 10.24s (0x08) Num responses: 0 > HCI Event: Command Status (0x0f) plen 4 #38208 [hci0] 10886.141333 Inquiry (0x01|0x0001) ncmd 2 Status: Success (0x00) ... < HCI Command: LE Set Extended Scan Enable #38242 [hci0] 10896.381802 Extended scan: Disabled (0x00) Filter duplicates: Disabled (0x00) Duration: 0 msec (0x0000) Period: 0.00 sec (0x0000) > HCI Event: Inquiry Complete (0x01) plen 1 #38243 [hci0] 10896.383419 Status: Success (0x00) > HCI Event: Command Complete (0x0e) plen 4 #38244 [hci0] 10896.394378 LE Set Extended Scan Enable (0x08|0x0042) ncmd 2 Status: Success (0x00) @ MGMT Event: Device Found (0x0012) plen 22 {0x0001} [hci0] 10896.394497 LE Address: 88:12:AC:92:43:69 RSSI: -101 dBm (0x9b) Flags: 0x00000004 Not Connectable Data length: 8 Company: Xiaomi Inc. (911) Data[0]: 16-bit Service UUIDs (complete): 1 entry Xiaomi Inc. (0xfdaa) @ MGMT Event: Discovering (0x0013) plen 2 {0x0001} [hci0] 10896.394506 Address type: 0x07 BR/EDR LE Public LE Random Discovery: Disabled (0x00) Fixes: 8ffde2a73f2c ("Bluetooth: Convert le_scan_disable timeout to hci_sync") Signed-off-by: Jiajia Liu Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_event.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index eea2f810aafa..1cd5f97daafe 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1769,6 +1769,13 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable) hci_dev_clear_flag(hdev, HCI_LE_SCAN); + if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED && + hci_test_quirk(hdev, HCI_QUIRK_SIMULTANEOUS_DISCOVERY) && + !test_bit(HCI_INQUIRY, &hdev->flags) && + hdev->discovery.state == DISCOVERY_FINDING) { + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + } + /* The HCI_LE_SCAN_INTERRUPTED flag indicates that we * interrupted scanning due to a connect request. Mark * therefore discovery as stopped. From 5edcc018fa6e80b2c478454a4a8229c23d67c181 Mon Sep 17 00:00:00 2001 From: Jordan Walters Date: Wed, 3 Jun 2026 04:50:47 -0400 Subject: [PATCH 31/49] Bluetooth: hci_core: Fix UAF in hci_unregister_dev() hci_unregister_dev() does not disable cmd_timer and ncmd_timer before the hci_dev structure is freed. If a timeout fires during device teardown, the callback dereferences freed memory (including the hdev->reset function pointer), leading to a use-after-free. Add disable_delayed_work_sync() calls alongside the existing disable_work_sync() calls to ensure both timers are fully quiesced before teardown proceeds. Fixes: 0d151a103775 ("Bluetooth: hci_core: cancel all works upon hci_unregister_dev()") Signed-off-by: Jordan Walters Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 28d7929dc593..1cbc666527c5 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2671,6 +2671,8 @@ void hci_unregister_dev(struct hci_dev *hdev) disable_work_sync(&hdev->tx_work); disable_work_sync(&hdev->power_on); disable_work_sync(&hdev->error_reset); + disable_delayed_work_sync(&hdev->cmd_timer); + disable_delayed_work_sync(&hdev->ncmd_timer); hci_cmd_sync_clear(hdev); From f396f4005180928cd9e15e352a6512865d3bc908 Mon Sep 17 00:00:00 2001 From: Zhao Dongdong Date: Thu, 4 Jun 2026 19:46:40 +0800 Subject: [PATCH 32/49] Bluetooth: btmtk: fix URB leak in alloc_mtk_intr_urb error path When btmtk_isopkt_pad() fails, the previously allocated URB is not freed, leaking the urb structure. Add usb_free_urb() before returning the error. Fixes: ceac1cb0259d ("Bluetooth: btusb: mediatek: add ISO data transmission functions") Signed-off-by: Zhao Dongdong Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btmtk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index d7aa5aded649..02a96342e964 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -1074,8 +1074,10 @@ struct urb *alloc_mtk_intr_urb(struct hci_dev *hdev, struct sk_buff *skb, if (!urb) return ERR_PTR(-ENOMEM); - if (btmtk_isopkt_pad(hdev, skb)) + if (btmtk_isopkt_pad(hdev, skb)) { + usb_free_urb(urb); return ERR_PTR(-EINVAL); + } pipe = usb_sndintpipe(btmtk_data->udev, btmtk_data->isopkt_tx_ep->bEndpointAddress); From eedc6867ebad73edbfaf9a0a65fbef7115cc4753 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 4 Jun 2026 08:37:36 +0200 Subject: [PATCH 33/49] Bluetooth: btusb: fix use-after-free on registration failure Make sure to release the sibling interfaces in case controller registration fails to avoid use-after-free and double-free when they are eventually disconnected. This issue was reported by Sashiko while reviewing a fix for a wakeup source leak in the btusb probe errors paths. Link: https://sashiko.dev/#/patchset/20260402092704.2346710-1-johan%40kernel.org Fixes: 9bfa35fe422c ("[Bluetooth] Add SCO support to btusb driver") Fixes: 9d08f50401ac ("Bluetooth: btusb: Add support for Broadcom LM_DIAG interface") Cc: stable@vger.kernel.org # 2.6.27 Reviewed-by: Paul Menzel Signed-off-by: Johan Hovold Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 3cbb3c22e20f..c181e1a3eb3e 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -4427,7 +4427,7 @@ static int btusb_probe(struct usb_interface *intf, err = hci_register_dev(hdev); if (err < 0) - goto out_free_dev; + goto err_release_siblings; usb_set_intfdata(intf, data); @@ -4436,6 +4436,15 @@ static int btusb_probe(struct usb_interface *intf, return 0; +err_release_siblings: + if (data->diag) { + usb_set_intfdata(data->diag, NULL); + usb_driver_release_interface(&btusb_driver, data->diag); + } + if (data->isoc) { + usb_set_intfdata(data->isoc, NULL); + usb_driver_release_interface(&btusb_driver, data->isoc); + } out_free_dev: if (data->reset_gpio) gpiod_put(data->reset_gpio); From c5b600a3c05b1a7a110d558df935a8fc8a471c79 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 4 Jun 2026 08:37:37 +0200 Subject: [PATCH 34/49] Bluetooth: btusb: fix use-after-free on marvell probe failure Make sure to stop any TX URBs submitted during Marvell OOB wakeup configuration on later probe failures to avoid use-after-free in the completion callback. This issue was reported by Sashiko while reviewing a fix for a wakeup source leak in the btusb probe errors paths. Link: https://sashiko.dev/#/patchset/20260402092704.2346710-1-johan%40kernel.org Fixes: a4ccc9e33d2f ("Bluetooth: btusb: Configure Marvell to use one of the pins for oob wakeup") Cc: stable@vger.kernel.org # 4.11 Cc: Rajat Jain Signed-off-by: Johan Hovold Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c181e1a3eb3e..669fb3ebde4c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -4237,7 +4237,7 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_INTEL_COMBINED) { err = btintel_configure_setup(hdev, btusb_driver.name); if (err) - goto out_free_dev; + goto err_kill_tx_urbs; /* Transport specific configuration */ hdev->send = btusb_send_frame_intel; @@ -4401,7 +4401,7 @@ static int btusb_probe(struct usb_interface *intf, err = usb_set_interface(data->udev, 0, 0); if (err < 0) { BT_ERR("failed to set interface 0, alt 0 %d", err); - goto out_free_dev; + goto err_kill_tx_urbs; } } @@ -4409,7 +4409,7 @@ static int btusb_probe(struct usb_interface *intf, err = usb_driver_claim_interface(&btusb_driver, data->isoc, data); if (err < 0) - goto out_free_dev; + goto err_kill_tx_urbs; } if (IS_ENABLED(CONFIG_BT_HCIBTUSB_BCM) && data->diag) { @@ -4445,6 +4445,8 @@ err_release_siblings: usb_set_intfdata(data->isoc, NULL); usb_driver_release_interface(&btusb_driver, data->isoc); } +err_kill_tx_urbs: + usb_kill_anchored_urbs(&data->tx_anchor); out_free_dev: if (data->reset_gpio) gpiod_put(data->reset_gpio); From 3d93e1bb0fb881fe3ef961d1120556658e9cac4d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 4 Jun 2026 08:37:38 +0200 Subject: [PATCH 35/49] Bluetooth: btusb: fix wakeup source leak on probe failure Make sure to disable wakeup on probe failure to avoid leaking the wakeup source. Fixes: fd913ef7ce61 ("Bluetooth: btusb: Add out-of-band wakeup support") Cc: stable@vger.kernel.org # 4.11 Cc: Rajat Jain Signed-off-by: Johan Hovold Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 669fb3ebde4c..966e017ac1df 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -3013,6 +3013,11 @@ static int marvell_config_oob_wake(struct hci_dev *hdev) return 0; } +#else +static inline int marvell_config_oob_wake(struct hci_dev *hdev) +{ + return 0; +} #endif static int btusb_set_bdaddr_marvell(struct hci_dev *hdev, @@ -3855,6 +3860,11 @@ static int btusb_config_oob_wake(struct hci_dev *hdev) bt_dev_info(hdev, "OOB Wake-on-BT configured at IRQ %u", irq); return 0; } +#else +static inline int btusb_config_oob_wake(struct hci_dev *hdev) +{ + return 0; +} #endif static void btusb_check_needs_reset_resume(struct usb_interface *intf) @@ -4191,7 +4201,6 @@ static int btusb_probe(struct usb_interface *intf, hdev->wakeup = btusb_wakeup; hdev->hci_drv = &btusb_hci_drv; -#ifdef CONFIG_PM err = btusb_config_oob_wake(hdev); if (err) goto out_free_dev; @@ -4200,9 +4209,9 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL && data->oob_wake_irq) { err = marvell_config_oob_wake(hdev); if (err) - goto out_free_dev; + goto err_disable_wakeup; } -#endif + if (id->driver_info & BTUSB_CW6622) hci_set_quirk(hdev, HCI_QUIRK_BROKEN_STORED_LINK_KEY); @@ -4447,6 +4456,9 @@ err_release_siblings: } err_kill_tx_urbs: usb_kill_anchored_urbs(&data->tx_anchor); +err_disable_wakeup: + if (data->oob_wake_irq) + device_init_wakeup(&data->udev->dev, false); out_free_dev: if (data->reset_gpio) gpiod_put(data->reset_gpio); From cfb192390bb8e8674b78d750e31fc49a5586596d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 4 Jun 2026 08:37:39 +0200 Subject: [PATCH 36/49] Bluetooth: btusb: fix wakeup irq devres lifetime The OOB wakeup interrupt is device managed but its lifetime is incorrectly tied to the child HCI device rather than the USB interface to which the driver is bound. This should not cause any trouble currently as the interrupt will be disabled when the HCI device is deregistered on disconnect (but this was not always the case, see [1]), and there should be no further references if probe fails before registering it. But it is still technically wrong as the reference counted HCI device could in theory remain after a probe failure. Explicitly free the interrupt on disconnect so that it is guaranteed to be disabled before freeing the (non-managed) driver data (including if disconnected while suspended). [1] 699fb50d9903 ("drivers: base: Free devm resources when unregistering a device") Fixes: fd913ef7ce61 ("Bluetooth: btusb: Add out-of-band wakeup support") Cc: Rajat Jain Signed-off-by: Johan Hovold Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 966e017ac1df..843c649f8053 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -3843,8 +3843,7 @@ static int btusb_config_oob_wake(struct hci_dev *hdev) } irq_set_status_flags(irq, IRQ_NOAUTOEN); - ret = devm_request_irq(&hdev->dev, irq, btusb_oob_wake_handler, - 0, "OOB Wake-on-BT", data); + ret = request_irq(irq, btusb_oob_wake_handler, 0, "OOB Wake-on-BT", data); if (ret) { bt_dev_err(hdev, "%s: IRQ request failed", __func__); return ret; @@ -3853,12 +3852,18 @@ static int btusb_config_oob_wake(struct hci_dev *hdev) ret = device_init_wakeup(dev, true); if (ret) { bt_dev_err(hdev, "%s: failed to init_wakeup", __func__); - return ret; + goto err_free_irq; } data->oob_wake_irq = irq; bt_dev_info(hdev, "OOB Wake-on-BT configured at IRQ %u", irq); + return 0; + +err_free_irq: + free_irq(irq, data); + + return ret; } #else static inline int btusb_config_oob_wake(struct hci_dev *hdev) @@ -4457,8 +4462,10 @@ err_release_siblings: err_kill_tx_urbs: usb_kill_anchored_urbs(&data->tx_anchor); err_disable_wakeup: - if (data->oob_wake_irq) + if (data->oob_wake_irq) { device_init_wakeup(&data->udev->dev, false); + free_irq(data->oob_wake_irq, data); + } out_free_dev: if (data->reset_gpio) gpiod_put(data->reset_gpio); @@ -4491,8 +4498,11 @@ static void btusb_disconnect(struct usb_interface *intf) hci_unregister_dev(hdev); - if (data->oob_wake_irq) + if (data->oob_wake_irq) { device_init_wakeup(&data->udev->dev, false); + free_irq(data->oob_wake_irq, data); + } + if (data->reset_gpio) gpiod_put(data->reset_gpio); From 43ea69d0ef06975837e7d7270b64f4b500113837 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 4 Jun 2026 08:37:40 +0200 Subject: [PATCH 37/49] Bluetooth: btusb: clean up probe error handling Clean up probe error handling by using dedicated error labels with an "err" prefix. Note that the endpoint lookup helper returns -ENXIO when endpoints are missing which is functionally equivalent to returning -ENODEV. Signed-off-by: Johan Hovold Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 843c649f8053..08c0a99a62c5 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -4119,10 +4119,8 @@ static int btusb_probe(struct usb_interface *intf, err = usb_find_common_endpoints(intf->cur_altsetting, &data->bulk_rx_ep, &data->bulk_tx_ep, &data->intr_ep, NULL); - if (err) { - kfree(data); - return -ENODEV; - } + if (err) + goto err_free_data; if (id->driver_info & BTUSB_AMP) { data->cmdreq_type = USB_TYPE_CLASS | 0x01; @@ -4178,8 +4176,8 @@ static int btusb_probe(struct usb_interface *intf, hdev = hci_alloc_dev_priv(priv_size); if (!hdev) { - kfree(data); - return -ENOMEM; + err = -ENOMEM; + goto err_free_data; } hdev->bus = HCI_USB; @@ -4193,7 +4191,7 @@ static int btusb_probe(struct usb_interface *intf, GPIOD_OUT_LOW); if (IS_ERR(reset_gpio)) { err = PTR_ERR(reset_gpio); - goto out_free_dev; + goto err_free_hdev; } else if (reset_gpio) { data->reset_gpio = reset_gpio; } @@ -4208,7 +4206,7 @@ static int btusb_probe(struct usb_interface *intf, err = btusb_config_oob_wake(hdev); if (err) - goto out_free_dev; + goto err_put_reset; /* Marvell devices may need a specific chip configuration */ if (id->driver_info & BTUSB_MARVELL && data->oob_wake_irq) { @@ -4466,11 +4464,14 @@ err_disable_wakeup: device_init_wakeup(&data->udev->dev, false); free_irq(data->oob_wake_irq, data); } -out_free_dev: +err_put_reset: if (data->reset_gpio) gpiod_put(data->reset_gpio); +err_free_hdev: hci_free_dev(hdev); +err_free_data: kfree(data); + return err; } From 93f5d7057da83e951e1e49de7c8a80ccd44d8d82 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Mon, 1 Jun 2026 23:21:30 +0300 Subject: [PATCH 38/49] Bluetooth: hci_h5: reset hci_uart::priv in the close() method Unlike the other HCI UART drivers, the 3-wire UART driver doesn't reset hci_uart::priv in its close() method -- this shouldn't pose a problem as all the methods in *struct* hci_uart_proto should only be called after the open() method that sets up hci_uart::priv properly. However, it seems wise to be more consistent and provide for the *struct* hci_uart_proto methods the same state that exists before the first open() method call (so that they rather crash than dereference a stale hci_uart::priv pointer)... Found by Linux Verification Center (linuxtesting.org) with the Svace static analysis tool. Signed-off-by: Sergey Shtylyov Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_h5.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index d35383718212..c6d9f70ad3bb 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -273,6 +273,7 @@ static int h5_close(struct hci_uart *hu) if (!hu->serdev) kfree(h5); + hu->priv = NULL; return 0; } From 975a70ff0aec8a2be0d633113f781b301db4a816 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Wed, 3 Jun 2026 21:24:15 +0530 Subject: [PATCH 39/49] Bluetooth: btintel_pcie: Add support for smart trigger dump Based on the debug configuration, firmware can raise MSI-X interrupt with firmware trigger cause bit set on specific events like Disconnection, Connection Timeout, Page Timeout etc. Upon receiving an MSI-X interrupt with the firmware trigger cause bit set, the driver performs the following actions: 1. Reads Device Memory: Retrieves data from the device memory, constructs an HCI diagnostic event, and sends it to the monitor. This event includes details about the trigger, such as connection timeout or page timeout. 2. Dumps Device Coredump: Generates a coredump containing firmware traces for further analysis. The coredump can be retrieved using: $ cat /sys/class/devcoredump/devcd*/data > /tmp/btintel_coredump.bin HCI traces: = Vendor Diagnostic (len 12) a5 a5 a5 a5 01 03 00 23 00 01 00 00 Signed-off-by: Kiran K Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel.h | 1 + drivers/bluetooth/btintel_pcie.c | 164 +++++++++++++++++++++++++++++++ drivers/bluetooth/btintel_pcie.h | 10 +- 3 files changed, 174 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 70d812ad36a2..7cce1bdebae0 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -53,6 +53,7 @@ struct intel_tlv { } __packed; #define BTINTEL_HCI_OP_RESET 0xfc01 +#define BTINTEL_HCI_OP_DEBUG 0xfcd9 #define BTINTEL_CNVI_BLAZARI 0x900 /* BlazarI - Lunar Lake */ #define BTINTEL_CNVI_BLAZARIW 0x901 /* BlazarIW - Wildcat Lake */ diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 0a6e8481104e..d2b0875cfa08 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -145,6 +145,22 @@ struct btintel_pcie_dbgc_ctxt { struct btintel_pcie_dbgc_ctxt_buf bufs[BTINTEL_PCIE_DBGC_BUFFER_COUNT]; }; +struct btintel_pcie_trigger_evt { + u8 type; + u8 len; + __le32 addr; + __le32 size; +} __packed; + +struct btintel_pcie_fwtrigger_evt { + __le32 reserved; + u8 type; /* Debug Trigger event */ + __le16 len; + u8 event_type; + __le16 event_id; + __le16 reserved2; +} __packed; + static LIST_HEAD(btintel_pcie_recovery_list); static DEFINE_SPINLOCK(btintel_pcie_recovery_lock); @@ -696,6 +712,11 @@ static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data) sizeof(*tlv) + strlen(vendor) + sizeof(*tlv) + strlen(driver); + if (data->dmp_hdr.event_type && data->dmp_hdr.event_id) { + data_len += sizeof(*tlv) + sizeof(data->dmp_hdr.event_type); + data_len += sizeof(*tlv) + sizeof(data->dmp_hdr.event_id); + } + /* * sizeof(u32) - signature * sizeof(data_len) - to store tlv data size @@ -743,6 +764,17 @@ static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data) p = btintel_pcie_copy_tlv(p, BTINTEL_CNVI_TOP, &data->dmp_hdr.cnvi_top, sizeof(data->dmp_hdr.cnvi_top)); + if (data->dmp_hdr.event_type && data->dmp_hdr.event_id) { + p = btintel_pcie_copy_tlv(p, BTINTEL_EVENT_TYPE, + &data->dmp_hdr.event_type, + sizeof(data->dmp_hdr.event_type)); + p = btintel_pcie_copy_tlv(p, BTINTEL_EVENT_ID, + &data->dmp_hdr.event_id, + sizeof(data->dmp_hdr.event_id)); + data->dmp_hdr.event_type = 0; + data->dmp_hdr.event_id = 0; + } + memcpy(p, dbgc->bufs[0].data, dbgc->count * BTINTEL_PCIE_DBGC_BUFFER_SIZE); dev_coredumpv(&hdev->dev, pdata, dump_size, GFP_KERNEL); return 0; @@ -1330,6 +1362,73 @@ exit_on_error: kfree(buf); } +static int btintel_pcie_dump_fwtrigger_event(struct btintel_pcie_data *data) +{ + struct btintel_pcie_fwtrigger_evt *evt; + struct sk_buff *skb; + unsigned int len; + int err; + u8 *buf; + + if (!data->debug_evt_size || !data->debug_evt_addr) + return -EINVAL; + + len = data->debug_evt_size; + + len = ALIGN_DOWN(len, 4); + + if (len < sizeof(*evt) || len > HCI_MAX_EVENT_SIZE) { + bt_dev_err(data->hdev, "Invalid FW trigger data size (%u bytes)", len); + return -EINVAL; + } + + buf = kzalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + btintel_pcie_mac_init(data); + + err = btintel_pcie_read_device_mem(data, buf, data->debug_evt_addr, + len); + if (err) + goto exit_on_error; + + evt = (void *)buf; + data->dmp_hdr.event_type = evt->event_type; + data->dmp_hdr.event_id = le16_to_cpu(evt->event_id); + + bt_dev_dbg(data->hdev, "event type: 0x%2.2x event id: 0x%4.4x len: %u", + data->dmp_hdr.event_type, data->dmp_hdr.event_id, len); + + skb = bt_skb_alloc(len, GFP_KERNEL); + if (!skb) { + err = -ENOMEM; + goto exit_on_error; + } + skb_put_data(skb, buf, len); + + hci_recv_diag(data->hdev, skb); + err = 0; + +exit_on_error: + kfree(buf); + return err; +} + +static void btintel_pcie_msix_fw_trigger_handler(struct btintel_pcie_data *data) +{ + bt_dev_dbg(data->hdev, "Received firmware smart trigger cause"); + + if (test_and_set_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags)) + return; + + /* Trigger device core dump when there is FW assert */ + if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) + data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT; + + queue_work(data->workqueue, &data->rx_work); +} + static void btintel_pcie_msix_hw_exp_handler(struct btintel_pcie_data *data) { bt_dev_err(data->hdev, "Received hw exception interrupt"); @@ -1352,6 +1451,14 @@ static void btintel_pcie_rx_work(struct work_struct *work) struct btintel_pcie_data *data = container_of(work, struct btintel_pcie_data, rx_work); struct sk_buff *skb; + int err; + + if (test_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags)) { + err = btintel_pcie_dump_fwtrigger_event(data); + if (err) + bt_dev_warn(data->hdev, "failed to log fwtrigger event"); + clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags); + } if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) { btintel_pcie_dump_traces(data->hdev); @@ -1509,6 +1616,9 @@ static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id) btintel_pcie_msix_tx_handle(data); } + if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_FWTRIG) + btintel_pcie_msix_fw_trigger_handler(data); + /* This interrupt is triggered by the firmware after updating * boot_stage register and image_response register */ @@ -1583,6 +1693,7 @@ static struct btintel_pcie_causes_list causes_list[] = { { BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1, BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK, 0x01 }, { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x20 }, { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HWEXP, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x23 }, + { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_FWTRIG, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x25 }, }; /* This function configures the interrupt masks for both HW_INT_CAUSES and @@ -2069,6 +2180,55 @@ static void btintel_pcie_synchronize_irqs(struct btintel_pcie_data *data) synchronize_irq(data->msix_entries[i].vector); } +static int btintel_pcie_get_debug_info_addr(struct hci_dev *hdev) +{ + struct btintel_pcie_data *data = hci_get_drvdata(hdev); + struct btintel_pcie_trigger_evt *evt; + u8 param[1] = {0x10}; + struct sk_buff *skb; + int err = 0; + + skb = __hci_cmd_sync(hdev, BTINTEL_HCI_OP_DEBUG, 1, param, + HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Reading Intel read debug info address command failed (%ld)", + PTR_ERR(skb)); + /* Not all Intel products supports this command */ + if (PTR_ERR(skb) == -EOPNOTSUPP) + return 0; + return PTR_ERR(skb); + } + + if (skb->len < (1 + sizeof(*evt))) { + bt_dev_err(hdev, "Debug info response too short (%u bytes)", skb->len); + err = -EIO; + goto exit_error; + } + + /* Check the status */ + if (skb->data[0]) { + bt_dev_err(hdev, "Reading Intel read debug info command failed (0x%2.2x)", + skb->data[0]); + err = -EIO; + goto exit_error; + } + + /* Consume Command Complete Status field */ + skb_pull(skb, 1); + + evt = (void *)skb->data; + + data->debug_evt_addr = le32_to_cpu(evt->addr); + data->debug_evt_size = le32_to_cpu(evt->size); + + bt_dev_dbg(hdev, "config type: %u config len: %u debug event addr: 0x%8.8x size: 0x%8.8x", + evt->type, evt->len, data->debug_evt_addr, + data->debug_evt_size); +exit_error: + kfree_skb(skb); + return err; +} + static int btintel_pcie_setup_internal(struct hci_dev *hdev) { struct btintel_pcie_data *data = hci_get_drvdata(hdev); @@ -2168,6 +2328,10 @@ static int btintel_pcie_setup_internal(struct hci_dev *hdev) if (ver_tlv.img_type == 0x02 || ver_tlv.img_type == 0x03) data->dmp_hdr.fw_git_sha1 = ver_tlv.git_sha1; + err = btintel_pcie_get_debug_info_addr(hdev); + if (err) + goto exit_error; + btintel_print_fseq_info(hdev); exit_error: kfree_skb(skb); diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index 7fc8c46ed689..cae84b00a700 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -98,6 +98,7 @@ enum msix_hw_int_causes { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0 = BIT(0), /* cause 32 */ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP1 = BIT(1), /* cause 33 */ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HWEXP = BIT(3), /* cause 35 */ + BTINTEL_PCIE_MSIX_HW_INT_CAUSES_FWTRIG = BIT(5), /* cause 37 */ }; /* PCIe device states @@ -115,6 +116,7 @@ enum { BTINTEL_PCIE_CORE_HALTED, BTINTEL_PCIE_HWEXP_INPROGRESS, BTINTEL_PCIE_COREDUMP_INPROGRESS, + BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, BTINTEL_PCIE_RECOVERY_IN_PROGRESS, BTINTEL_PCIE_SETUP_DONE }; @@ -130,7 +132,9 @@ enum btintel_pcie_tlv_type { BTINTEL_DUMP_TIME, BTINTEL_FW_BUILD, BTINTEL_VENDOR, - BTINTEL_DRIVER + BTINTEL_DRIVER, + BTINTEL_EVENT_TYPE, + BTINTEL_EVENT_ID }; /* causes for the MBOX interrupts */ @@ -430,6 +434,8 @@ struct btintel_pcie_dump_header { u32 wrap_ctr; u16 trigger_reason; int state; + u8 event_type; + u16 event_id; }; /* struct btintel_pcie_data @@ -518,6 +524,8 @@ struct btintel_pcie_data { struct btintel_pcie_dbgc dbgc; struct btintel_pcie_dump_header dmp_hdr; u8 pm_sx_event; + u32 debug_evt_addr; + u32 debug_evt_size; }; static inline u32 btintel_pcie_rd_reg32(struct btintel_pcie_data *data, From bea06c7c1b83bcd0519b91141999369eae6925bd Mon Sep 17 00:00:00 2001 From: Tim Bird Date: Thu, 4 Jun 2026 11:06:33 -0600 Subject: [PATCH 40/49] Bluetooth: Add SPDX id lines to some source files Many bluetooth source files are missing SPDX-License-Identifier lines. Add appropriate IDs to these files, and remove other license lines from the headers. Leave the warranty disclaimer in files where the license ID is GPL-2.0 but the wording of the disclaimer is slightly different from that of the GPL v2 disclaimer. It is not different enough to cause licensing conflicts, but is kept to honor the original contributors' legal intent. Signed-off-by: Tim Bird Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btrsi.c | 12 +----------- include/net/bluetooth/bluetooth.h | 5 +---- include/net/bluetooth/hci.h | 5 +---- include/net/bluetooth/hci_core.h | 5 +---- include/net/bluetooth/hci_mon.h | 5 +---- include/net/bluetooth/hci_sock.h | 5 +---- include/net/bluetooth/l2cap.h | 5 +---- include/net/bluetooth/mgmt.h | 5 +---- include/net/bluetooth/rfcomm.h | 5 +---- include/net/bluetooth/sco.h | 5 +---- net/bluetooth/af_bluetooth.c | 5 +---- net/bluetooth/bnep/core.c | 5 +---- net/bluetooth/bnep/netdev.c | 5 +---- net/bluetooth/bnep/sock.c | 5 +---- net/bluetooth/ecdh_helper.c | 5 +---- net/bluetooth/ecdh_helper.h | 5 +---- net/bluetooth/hci_conn.c | 5 +---- net/bluetooth/hci_core.c | 5 +---- net/bluetooth/hci_debugfs.c | 5 +---- net/bluetooth/hci_debugfs.h | 5 +---- net/bluetooth/hci_event.c | 5 +---- net/bluetooth/hci_sock.c | 5 +---- net/bluetooth/hidp/core.c | 5 +---- net/bluetooth/hidp/hidp.h | 5 +---- net/bluetooth/hidp/sock.c | 5 +---- net/bluetooth/l2cap_core.c | 5 +---- net/bluetooth/l2cap_sock.c | 5 +---- net/bluetooth/lib.c | 5 +---- net/bluetooth/mgmt.c | 5 +---- net/bluetooth/mgmt_util.c | 5 +---- net/bluetooth/mgmt_util.h | 5 +---- net/bluetooth/rfcomm/core.c | 5 +---- net/bluetooth/rfcomm/sock.c | 5 +---- net/bluetooth/rfcomm/tty.c | 5 +---- net/bluetooth/sco.c | 5 +---- net/bluetooth/selftest.c | 5 +---- net/bluetooth/selftest.h | 5 +---- net/bluetooth/smp.c | 5 +---- net/bluetooth/smp.h | 5 +---- 39 files changed, 39 insertions(+), 163 deletions(-) diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c index c68dd2fba01c..59ad0b9b14c3 100644 --- a/drivers/bluetooth/btrsi.c +++ b/drivers/bluetooth/btrsi.c @@ -1,17 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2017 Redpine Signals Inc. * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 3faea66b1979..b624da5026f5 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated @@ -5,10 +6,6 @@ Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 5462f14ea0c6..38186a245f14 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated @@ -5,10 +6,6 @@ Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index aa600fbf9a53..7e15da47fe3a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* BlueZ - Bluetooth protocol stack for Linux Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved. @@ -5,10 +6,6 @@ Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/include/net/bluetooth/hci_mon.h b/include/net/bluetooth/hci_mon.h index bbd752494ef9..4b2a0af4ed58 100644 --- a/include/net/bluetooth/hci_mon.h +++ b/include/net/bluetooth/hci_mon.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2011-2012 Intel Corporation - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/include/net/bluetooth/hci_sock.h b/include/net/bluetooth/hci_sock.h index 13e8cd4414a1..16f150b861be 100644 --- a/include/net/bluetooth/hci_sock.h +++ b/include/net/bluetooth/hci_sock.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index e0a1f2293679..790935950a0c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated @@ -6,10 +7,6 @@ Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 8234915854b6..08daed7a96d5 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2010 Nokia Corporation Copyright (C) 2011-2012 Intel Corporation - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index c05882476900..feb6b3ae5e69 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* RFCOMM implementation for Linux Bluetooth stack (BlueZ) Copyright (C) 2002 Maxim Krasnyansky Copyright (C) 2002 Marcel Holtmann - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index f40ddb4264fc..214409527b35 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 1a6aa3f8d4d6..bcbc11c9cb15 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 5c5f53ff30e8..add9a8f7535d 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* BNEP implementation for Linux Bluetooth stack (BlueZ). Copyright (C) 2001-2002 Inventel Systemes @@ -7,10 +8,6 @@ Copyright (C) 2002 Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index cc1cff63194f..ee1e39a3daff 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* BNEP implementation for Linux Bluetooth stack (BlueZ). Copyright (C) 2001-2002 Inventel Systemes @@ -7,10 +8,6 @@ Copyright (C) 2002 Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 00d47bcf4d7d..f3fe818d0e4c 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* BNEP implementation for Linux Bluetooth stack (BlueZ). Copyright (C) 2001-2002 Inventel Systemes @@ -6,10 +7,6 @@ Copyright (C) 2002 Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/ecdh_helper.c b/net/bluetooth/ecdh_helper.c index 0efc93fdae8a..1938e5559d88 100644 --- a/net/bluetooth/ecdh_helper.c +++ b/net/bluetooth/ecdh_helper.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ECDH helper functions - KPP wrappings * * Copyright (C) 2017 Intel Corporation * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/ecdh_helper.h b/net/bluetooth/ecdh_helper.h index 830723971cf8..9d787d3c8797 100644 --- a/net/bluetooth/ecdh_helper.h +++ b/net/bluetooth/ecdh_helper.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * ECDH helper functions - KPP wrappings * * Copyright (C) 2017 Intel Corporation * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 54eabaa46960..c335372e4062 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved. @@ -5,10 +6,6 @@ Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1cbc666527c5..5ba9fe8261ec 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated @@ -5,10 +6,6 @@ Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c index 99e2e9fc70e8..0635e4641db4 100644 --- a/net/bluetooth/hci_debugfs.c +++ b/net/bluetooth/hci_debugfs.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2014 Intel Corporation - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/hci_debugfs.h b/net/bluetooth/hci_debugfs.h index 9a8a7c93bb12..92365cbc922a 100644 --- a/net/bluetooth/hci_debugfs.h +++ b/net/bluetooth/hci_debugfs.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2014 Intel Corporation - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1cd5f97daafe..b6d963ce26d0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved. @@ -5,10 +6,6 @@ Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 61fec674a207..070ca388f9ac 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 70344bd3248a..0e24c5e2955e 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* HIDP implementation for Linux Bluetooth stack (BlueZ). Copyright (C) 2003-2004 Marcel Holtmann Copyright (C) 2013 David Herrmann - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index 6ef88d0a1919..959b745bb770 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* HIDP implementation for Linux Bluetooth stack (BlueZ). Copyright (C) 2003-2004 Marcel Holtmann - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index c93aaeb3a3fa..b75bea3cf422 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* HIDP implementation for Linux Bluetooth stack (BlueZ). Copyright (C) 2003-2004 Marcel Holtmann - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c4ccfbda9d78..863fc4b8a55e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated @@ -8,10 +9,6 @@ Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 025329636353..4853f1b33449 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated @@ -7,10 +8,6 @@ Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c index 305044a84478..cea21a4c49a0 100644 --- a/net/bluetooth/lib.c +++ b/net/bluetooth/lib.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f4aa814a0397..d23ca1dd0893 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2010 Nokia Corporation Copyright (C) 2011-2012 Intel Corporation - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/mgmt_util.c b/net/bluetooth/mgmt_util.c index 4f19654d41a9..6ea107c0e054 100644 --- a/net/bluetooth/mgmt_util.c +++ b/net/bluetooth/mgmt_util.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2015 Intel Corporation - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/mgmt_util.h b/net/bluetooth/mgmt_util.h index bcba8c9d8952..20810cf06e81 100644 --- a/net/bluetooth/mgmt_util.h +++ b/net/bluetooth/mgmt_util.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2015 Intel Coropration - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 364b9381c2dc..ebeae17b71d1 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* RFCOMM implementation for Linux Bluetooth stack (BlueZ). Copyright (C) 2002 Maxim Krasnyansky Copyright (C) 2002 Marcel Holtmann - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index ed31d5f4fc76..feb302a491fa 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* RFCOMM implementation for Linux Bluetooth stack (BlueZ). Copyright (C) 2002 Maxim Krasnyansky Copyright (C) 2002 Marcel Holtmann - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 91bf5274262e..4b9a699ec59b 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* RFCOMM implementation for Linux Bluetooth stack (BlueZ). Copyright (C) 2002 Maxim Krasnyansky Copyright (C) 2002 Marcel Holtmann - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 451ed32bee76..fcc597be5bbd 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated Written 2000,2001 by Maxim Krasnyansky - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/selftest.c b/net/bluetooth/selftest.c index f49604d44b87..ae5b44bb9d3d 100644 --- a/net/bluetooth/selftest.c +++ b/net/bluetooth/selftest.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2014 Intel Corporation - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/selftest.h b/net/bluetooth/selftest.h index 2aa0a346a913..34d684ee84fd 100644 --- a/net/bluetooth/selftest.h +++ b/net/bluetooth/selftest.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2014 Intel Corporation - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1739c1989dbd..031d3022cb1e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index c5da53dfab04..eac27bd541bb 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. From 4d62d88e7ae6dcecd9a8c70a045a6c6c64bf3b52 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Sat, 6 Jun 2026 06:06:37 +0530 Subject: [PATCH 41/49] Bluetooth: btintel_pcie: Add 50 ms delay before MAC init on BlazarIW On BlazarIW, fast restart cycles fail because the D0 entry to MAC init does not complete in time. As a result, MAC initialization does not proceed and the controller fails to transition past the ROM boot stage. Add a 50 ms delay (worst case as per HW analysis) before doing MAC init in btintel_pcie_enable_bt() so the shared hardware reset flow has time to complete. The delay is gated on the BlazarIW PCI device id 0x4D76 so other Intel BT PCIe controllers are unaffected. Signed-off-by: Kiran K Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index d2b0875cfa08..2084159f2ced 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -799,6 +799,11 @@ static void btintel_pcie_dump_traces(struct hci_dev *hdev) bt_dev_err(hdev, "Failed to dump traces: (%d)", ret); } +static bool btintel_pcie_is_blazariw(struct pci_dev *pdev) +{ + return pdev->device == 0x4D76; +} + /* This function enables BT function by setting BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT bit in * BTINTEL_PCIE_CSR_FUNC_CTRL_REG register and wait for MSI-X with * BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0. @@ -818,6 +823,14 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data) btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_CI_ADDR_MSB_REG, (u64)data->ci_p_addr >> 32); + /* On BlazarIW, the D0 entry to MAC init does not complete in + * time. Wait 50 ms (worst case as per HW analysis) for the + * shared hardware reset flow to complete before proceeding with + * MAC init. + */ + if (btintel_pcie_is_blazariw(data->pdev)) + msleep(50); + /* Reset the cached value of boot stage. it is updated by the MSI-X * gp0 interrupt handler. */ From e43b33bf8d671c50a45fe5f487819927595bbd50 Mon Sep 17 00:00:00 2001 From: Sai Teja Aluvala Date: Sun, 7 Jun 2026 11:51:17 +0530 Subject: [PATCH 42/49] Bluetooth: btintel_pcie: Load IOSF debug regs by controller variant Load the IOSF DBGC base address based on the controller hardware variant when reading DRAM buffers during a trace dump. Scorpius Peak family controllers (SCP/SCP2/SCP2F) use a different DBGC base address (0xf0d5d500) than Blazar family controllers (BZRI/BZRIW, 0xf3800300). Fixes: 07e6bddb54b4 ("Bluetooth: btintel_pcie: Add support for device coredump") Signed-off-by: Sai Teja Aluvala Signed-off-by: Kiran K Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel.h | 1 + drivers/bluetooth/btintel_pcie.c | 30 ++++++++++++++++++++++++------ drivers/bluetooth/btintel_pcie.h | 4 ++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 7cce1bdebae0..37d93abdd5a3 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -78,6 +78,7 @@ struct intel_tlv { #define BTINTEL_HWID_BZRU 0x1d /* BlazarU - Meteor Lake */ #define BTINTEL_HWID_SCP 0x1f /* Scorpius Peak - Panther Lake */ #define BTINTEL_HWID_SCP2 0x20 /* Scorpius Peak2 - Nova Lake */ +#define BTINTEL_HWID_SCP2F 0x21 /* Scorpius Peak2-F - Nova Lake */ #define BTINTEL_HWID_BZRIW 0x22 /* BlazarIW - Wildcat Lake */ extern const guid_t btintel_guid_dsm; diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 2084159f2ced..93473ba05d83 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -654,9 +654,10 @@ static void *btintel_pcie_copy_tlv(void *dest, enum btintel_pcie_tlv_type type, static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data) { u32 offset, prev_size, wr_ptr_status, dump_size, data_len; + u32 status_reg, wrap_reg; struct btintel_pcie_dbgc *dbgc = &data->dbgc; struct hci_dev *hdev = data->hdev; - u8 *pdata, *p, buf_idx; + u8 *pdata, *p, buf_idx, hw_variant; struct intel_tlv *tlv; struct timespec64 now; struct tm tm_now; @@ -669,7 +670,28 @@ static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data) return -EOPNOTSUPP; - wr_ptr_status = btintel_pcie_rd_dev_mem(data, BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS); + hw_variant = INTEL_HW_VARIANT(data->cnvi); + switch (hw_variant) { + case BTINTEL_HWID_BZRI: + case BTINTEL_HWID_BZRIW: + status_reg = BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS; + wrap_reg = BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND; + break; + case BTINTEL_HWID_SCP: + case BTINTEL_HWID_SCP2: + case BTINTEL_HWID_SCP2F: + status_reg = BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS_SCP; + wrap_reg = BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND_SCP; + break; + default: + bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%2.2x)", + hw_variant); + return -EINVAL; + } + + wr_ptr_status = btintel_pcie_rd_dev_mem(data, status_reg); + data->dmp_hdr.wrap_ctr = btintel_pcie_rd_dev_mem(data, wrap_reg); + offset = wr_ptr_status & BTINTEL_PCIE_DBG_OFFSET_BIT_MASK; buf_idx = BTINTEL_PCIE_DBGC_DBG_BUF_IDX(wr_ptr_status); @@ -751,10 +773,6 @@ static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data) sizeof(data->dmp_hdr.write_ptr)); p = btintel_pcie_copy_tlv(p, BTINTEL_WRAP_CTR, &data->dmp_hdr.wrap_ctr, sizeof(data->dmp_hdr.wrap_ctr)); - - data->dmp_hdr.wrap_ctr = btintel_pcie_rd_dev_mem(data, - BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND); - p = btintel_pcie_copy_tlv(p, BTINTEL_TRIGGER_REASON, &data->dmp_hdr.trigger_reason, sizeof(data->dmp_hdr.trigger_reason)); p = btintel_pcie_copy_tlv(p, BTINTEL_FW_SHA, &data->dmp_hdr.fw_git_sha1, diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index cae84b00a700..e4a8fa479188 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -68,6 +68,10 @@ #define BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS (BTINTEL_PCIE_DBGC_BASE_ADDR + 0x1C) #define BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND (BTINTEL_PCIE_DBGC_BASE_ADDR + 0x2C) +#define BTINTEL_PCIE_DBGC_BASE_ADDR_SCP (0xf0d5d500) +#define BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS_SCP (BTINTEL_PCIE_DBGC_BASE_ADDR_SCP + 0x1C) +#define BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND_SCP (BTINTEL_PCIE_DBGC_BASE_ADDR_SCP + 0x2C) + #define BTINTEL_PCIE_DBG_IDX_BIT_MASK 0x0F #define BTINTEL_PCIE_DBGC_DBG_BUF_IDX(data) (((data) >> 24) & BTINTEL_PCIE_DBG_IDX_BIT_MASK) #define BTINTEL_PCIE_DBG_OFFSET_BIT_MASK 0xFFFFFF From b66774b48dd98f07254951f74ea6f513efe7ff8b Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 5 Jun 2026 16:23:35 +0200 Subject: [PATCH 43/49] Bluetooth: L2CAP: Fix UAF in channel timeout by holding conn ref l2cap_chan_timeout() runs asynchronously and accesses chan->conn. If the connection is torn down while the timer is running or pending, chan->conn can be freed, leading to a use-after-free when the timer worker attempts to lock conn->lock: | BUG: KASAN: slab-use-after-free in instrument_atomic_read_write include/linux/instrumented.h:112 [inline] | BUG: KASAN: slab-use-after-free in atomic_long_try_cmpxchg_acquire include/linux/atomic/atomic-instrumented.h:4456 [inline] | BUG: KASAN: slab-use-after-free in __mutex_trylock_fast kernel/locking/mutex.c:161 [inline] | BUG: KASAN: slab-use-after-free in mutex_lock+0x4f/0xa0 kernel/locking/mutex.c:318 | Write of size 8 at addr ffff8881298d9550 by task kworker/2:1/83 | | CPU: 2 UID: 0 PID: 83 Comm: kworker/2:1 Not tainted 7.1.0-rc6-next-20260601-dirty #6 PREEMPT(full) | Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 | Workqueue: events l2cap_chan_timeout | Call Trace: | | instrument_atomic_read_write include/linux/instrumented.h:112 [inline] | atomic_long_try_cmpxchg_acquire include/linux/atomic/atomic-instrumented.h:4456 [inline] | __mutex_trylock_fast kernel/locking/mutex.c:161 [inline] | mutex_lock+0x4f/0xa0 kernel/locking/mutex.c:318 | l2cap_chan_timeout+0x5d/0x1b0 net/bluetooth/l2cap_core.c:422 | process_one_work kernel/workqueue.c:3326 [inline] | process_scheduled_works+0x7c8/0xfb0 kernel/workqueue.c:3409 | worker_thread+0x8a9/0xcf0 kernel/workqueue.c:3490 | kthread+0x346/0x430 kernel/kthread.c:436 | ret_from_fork+0x1a3/0x470 arch/x86/kernel/process.c:158 | ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 | | | Allocated by task 320: | l2cap_conn_add+0xa7/0x820 net/bluetooth/l2cap_core.c:7075 | l2cap_connect_cfm+0xdb/0xd70 net/bluetooth/l2cap_core.c:7452 | hci_connect_cfm include/net/bluetooth/hci_core.h:2139 [inline] | hci_remote_features_evt+0x52f/0x9f0 net/bluetooth/hci_event.c:3760 | hci_event_func net/bluetooth/hci_event.c:7796 [inline] | hci_event_packet+0x561/0xa70 net/bluetooth/hci_event.c:7847 | hci_rx_work+0x370/0x890 net/bluetooth/hci_core.c:4040 | process_one_work kernel/workqueue.c:3326 [inline] | process_scheduled_works+0x7c8/0xfb0 kernel/workqueue.c:3409 | worker_thread+0x8a9/0xcf0 kernel/workqueue.c:3490 | kthread+0x346/0x430 kernel/kthread.c:436 | ret_from_fork+0x1a3/0x470 arch/x86/kernel/process.c:158 | ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 | | Freed by task 322: | hci_disconn_cfm include/net/bluetooth/hci_core.h:2154 [inline] | hci_conn_hash_flush+0x101/0x1f0 net/bluetooth/hci_conn.c:2736 | hci_dev_close_sync+0x889/0xde0 net/bluetooth/hci_sync.c:5405 | hci_dev_do_close net/bluetooth/hci_core.c:502 [inline] | hci_unregister_dev+0x1f7/0x370 net/bluetooth/hci_core.c:2679 | vhci_release+0x12a/0x180 drivers/bluetooth/hci_vhci.c:690 | __fput+0x369/0x890 fs/file_table.c:510 | task_work_run+0x160/0x1d0 kernel/task_work.c:233 | get_signal+0xf5b/0x1120 kernel/signal.c:2810 | arch_do_signal_or_restart+0x4d/0x600 arch/x86/kernel/signal.c:337 | __exit_to_user_mode_loop kernel/entry/common.c:64 [inline] | exit_to_user_mode_loop+0x85/0x510 kernel/entry/common.c:98 | do_syscall_64+0x263/0x3d0 arch/x86/entry/syscall_64.c:100 | entry_SYSCALL_64_after_hwframe+0x77/0x7f | | The buggy address belongs to the object at ffff8881298d9400 | which belongs to the cache kmalloc-512 of size 512 | The buggy address is located 336 bytes inside of | freed 512-byte region [ffff8881298d9400, ffff8881298d9600) Fix it by having chan->conn hold a reference to l2cap_conn (via l2cap_conn_get) when the channel is added to the connection, and releasing it in the channel destructor. This ensures the l2cap_conn remains alive as long as the channel exists. A new FLAG_DEL channel flag is introduced to indicate that the channel has been deleted from its connection. l2cap_chan_del() atomically sets this flag using test_and_set_bit() instead of setting chan->conn to NULL. All asynchronous workers (l2cap_chan_timeout, l2cap_ack_timeout, l2cap_monitor_timeout, l2cap_retrans_timeout) and l2cap_chan_send() check FLAG_DEL to determine whether the channel has been torn down, rather than testing chan->conn for NULL. Fixes: 8c8e620467a7 ("Bluetooth: L2CAP: use chan timer to close channels in cleanup_listen()") Cc: Cc: Siwei Zhang Cc: Luiz Augusto von Dentz Assisted-by: Gemini:gemini-3.1-pro-preview Reported-by: https://sashiko.dev/#/patchset/20260521021249.3258069-1-oss%40fourdim.xyz Signed-off-by: Marco Elver Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 34 ++++++++++++++++++++-------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 790935950a0c..1640cc9bf83a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -745,6 +745,7 @@ enum { FLAG_ECRED_CONN_REQ_SENT, FLAG_PENDING_SECURITY, FLAG_HOLD_HCI_CONN, + FLAG_DEL, }; /* Lock nesting levels for L2CAP channels. We need these because lockdep diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 863fc4b8a55e..a97d492473e2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -408,7 +408,7 @@ static void l2cap_chan_timeout(struct work_struct *work) BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); - if (!conn) { + if (test_bit(FLAG_DEL, &chan->flags)) { l2cap_chan_put(chan); return; } @@ -419,6 +419,9 @@ static void l2cap_chan_timeout(struct work_struct *work) */ l2cap_chan_lock(chan); + if (test_bit(FLAG_DEL, &chan->flags)) + goto unlock; + if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) reason = ECONNREFUSED; else if (chan->state == BT_CONNECT && @@ -431,10 +434,10 @@ static void l2cap_chan_timeout(struct work_struct *work) chan->ops->close(chan); +unlock: l2cap_chan_unlock(chan); - l2cap_chan_put(chan); - mutex_unlock(&conn->lock); + l2cap_chan_put(chan); } struct l2cap_chan *l2cap_chan_create(void) @@ -487,6 +490,9 @@ static void l2cap_chan_destroy(struct kref *kref) list_del(&chan->global_l); write_unlock(&chan_list_lock); + if (chan->conn) + l2cap_conn_put(chan->conn); + kfree(chan); } @@ -590,7 +596,7 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; - chan->conn = conn; + chan->conn = l2cap_conn_get(conn); switch (chan->chan_type) { case L2CAP_CHAN_CONN_ORIENTED: @@ -645,30 +651,26 @@ void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) void l2cap_chan_del(struct l2cap_chan *chan, int err) { - struct l2cap_conn *conn = chan->conn; - __clear_chan_timer(chan); - BT_DBG("chan %p, conn %p, err %d, state %s", chan, conn, err, + BT_DBG("chan %p, err %d, state %s", chan, err, state_to_string(chan->state)); chan->ops->teardown(chan, err); - if (conn) { + if (!test_and_set_bit(FLAG_DEL, &chan->flags)) { /* Delete from channel list */ list_del(&chan->list); l2cap_chan_put(chan); - chan->conn = NULL; - /* Reference was only held for non-fixed channels or * fixed channels that explicitly requested it using the * FLAG_HOLD_HCI_CONN flag. */ if (chan->chan_type != L2CAP_CHAN_FIXED || test_bit(FLAG_HOLD_HCI_CONN, &chan->flags)) - hci_conn_drop(conn->hcon); + hci_conn_drop(chan->conn->hcon); } if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state)) @@ -1900,7 +1902,7 @@ static void l2cap_monitor_timeout(struct work_struct *work) l2cap_chan_lock(chan); - if (!chan->conn) { + if (test_bit(FLAG_DEL, &chan->flags)) { l2cap_chan_unlock(chan); l2cap_chan_put(chan); return; @@ -1921,7 +1923,7 @@ static void l2cap_retrans_timeout(struct work_struct *work) l2cap_chan_lock(chan); - if (!chan->conn) { + if (test_bit(FLAG_DEL, &chan->flags)) { l2cap_chan_unlock(chan); l2cap_chan_put(chan); return; @@ -2562,7 +2564,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, int err; struct sk_buff_head seg_queue; - if (!chan->conn) + if (test_bit(FLAG_DEL, &chan->flags)) return -ENOTCONN; /* Connectionless channel */ @@ -3157,12 +3159,16 @@ static void l2cap_ack_timeout(struct work_struct *work) l2cap_chan_lock(chan); + if (test_bit(FLAG_DEL, &chan->flags)) + goto unlock; + frames_to_ack = __seq_offset(chan, chan->buffer_seq, chan->last_acked_seq); if (frames_to_ack) l2cap_send_rr_or_rnr(chan, 0); +unlock: l2cap_chan_unlock(chan); l2cap_chan_put(chan); } From c38fbcdc407925c7088f7e5f11c1fff73d2d35a2 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Mon, 8 Jun 2026 23:56:28 +0000 Subject: [PATCH 44/49] Bluetooth: hci: validate codec capability element length Read Local Codec Capabilities returns a sequence of capability elements. Each element starts with a one-byte length followed by that many payload bytes. hci_read_codec_capabilities() checks that the skb contains the length byte, but then validates only caps->len against the remaining skb length. A malformed controller response with one remaining byte and caps->len set to one passes that check even though the element needs two bytes. The parser then records a two-byte capability and copies one byte beyond the advertised response payload into the codec list. Validate the full element size, including the length byte, before adding it to the accumulated capability length. This preserves all well-formed capability elements and drops only truncated controller responses. Fixes: 8961987f3f5f ("Bluetooth: Enumerate local supported codec and cache details") Assisted-by: Codex:gpt-5.5-cyber-preview Signed-off-by: Samuel Moelius Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c index 3cc135bb1d30..5bc5003c387c 100644 --- a/net/bluetooth/hci_codec.c +++ b/net/bluetooth/hci_codec.c @@ -100,7 +100,7 @@ static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 transport, caps = (void *)skb->data; if (skb->len < sizeof(*caps)) goto error; - if (skb->len < caps->len) + if (skb->len < sizeof(caps->len) + caps->len) goto error; len += sizeof(caps->len) + caps->len; skb_pull(skb, sizeof(caps->len) + caps->len); From a40a5f922546b3bd7c094d882b29177db4f2abe0 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Mon, 8 Jun 2026 23:57:05 +0000 Subject: [PATCH 45/49] Bluetooth: L2CAP: validate connectionless PSM length Connectionless L2CAP frames carry a two-byte PSM at the start of the payload. l2cap_recv_frame() currently reads that PSM unconditionally after validating only the outer L2CAP length. A malformed connectionless frame with a zero- or one-byte payload can therefore make the parser read beyond the advertised skb payload and use tailroom bytes as part of the PSM. A VHCI-backed QEMU reproducer injected a one-byte connectionless payload and reached the unchecked read. Reject connectionless frames that cannot contain the PSM before reading or pulling it. This preserves all valid connectionless frames while dropping only structurally incomplete packets. Assisted-by: Codex:gpt-5.5-cyber-preview Signed-off-by: Samuel Moelius Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/l2cap_core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a97d492473e2..62133eef9d2f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7029,6 +7029,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) break; case L2CAP_CID_CONN_LESS: + if (skb->len < L2CAP_PSMLEN_SIZE) { + kfree_skb(skb); + break; + } + psm = get_unaligned((__le16 *) skb->data); skb_pull(skb, L2CAP_PSMLEN_SIZE); l2cap_conless_channel(conn, psm, skb); From 88c2404a3c59c3126453919388dbd5ed98ed01bd Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Mon, 8 Jun 2026 23:58:23 +0000 Subject: [PATCH 46/49] Bluetooth: vhci: validate devcoredump state before side effects The VHCI force_devcoredump debugfs hook accepts a small test record from userspace. It validates the requested terminal state only after registering, initializing and appending a Bluetooth devcoredump. As a result, an invalid state returns -EINVAL but still leaves queued devcoredump work behind. With a non-zero timeout field, the rejected write can still emit a devcoredump after the timeout expires. Reject unsupported states before allocating the skb or changing the HCI devcoredump state machine. Fixes: ab4e4380d4e1 ("Bluetooth: Add vhci devcoredump support") Assisted-by: Codex:gpt-5.5-cyber-preview Signed-off-by: Samuel Moelius Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_vhci.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 2762eacf7f20..eddb32b30539 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -337,7 +337,17 @@ static ssize_t force_devcd_write(struct file *file, const char __user *user_buf, if (copy_from_user(&dump_data, user_buf, count)) return -EFAULT; + switch (dump_data.state) { + case HCI_DEVCOREDUMP_DONE: + case HCI_DEVCOREDUMP_ABORT: + case HCI_DEVCOREDUMP_TIMEOUT: + break; + default: + return -EINVAL; + } + data_size = count - offsetof(struct devcoredump_test_data, data); + skb = alloc_skb(data_size, GFP_ATOMIC); if (!skb) return -ENOMEM; From bdea21b3be4350592965bec213837e7b4f9fe75f Mon Sep 17 00:00:00 2001 From: Xiuzhuo Shang Date: Wed, 10 Jun 2026 14:42:32 +0800 Subject: [PATCH 47/49] Bluetooth: qca: Add BT FW build version to kernel log Firmware version is critical for bug triage. Users reporting issues typically share dmesg output rather than debugfs contents, requiring extra communication rounds to collect this information. Log the FW build version directly to the kernel log so it is immediately available in bug reports. Acked-by: Bartosz Golaszewski Signed-off-by: Xiuzhuo Shang Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btqca.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index dda76365726f..04ebe290bc78 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -143,6 +143,8 @@ static int qca_read_fw_build_info(struct hci_dev *hdev) hci_set_fw_info(hdev, "%s", build_label); + bt_dev_info(hdev, "QCA FW build version: %s", build_label); + kfree(build_label); out: kfree_skb(skb); From a257407e2bbbb099ed427719a50563f67fa366d8 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 9 Jun 2026 21:10:06 +0900 Subject: [PATCH 48/49] Bluetooth: btmtksdio: fix infinite loop in btmtksdio_txrx_work() Every once in a while we see a hung btmtksdio_flush() task: INFO: task kworker/u17:0:189 blocked for more than 122 seconds. __cancel_work_timer+0x3f4/0x460 cancel_work_sync+0x1c/0x2c btmtksdio_flush+0x2c/0x40 hci_dev_open_sync+0x10c4/0x2190 [..] It all boils down to incorrect time_is_before_jiffies() usage in btmtksdio_txrx_work(). The btmtksdio_txrx_work() loop is expected to be terminated if running for longer than 5*HZ. However the timeout check is twisted: time_is_before_jiffies(old_jiffies + 5*HZ) evaluates to true when old_jiffies + 5*HZ is in the past i.e. when a timeout has occurred. Using OR with time_is_before_jiffies(txrx_timeout) means that: - before the 5-second timeout: the condition is `int_status || false`, so it loops as long as there are pending interrupts. - after the 5-second timeout: the condition becomes `int_status || true`, which is always true. When the loop becomes infinite btmtksdio_txrx_work() loop never terminates and never releases the SDIO host. Fix loop termination condition to actually enforce a 5*HZ timeout. Fixes: 26270bc189ea4 ("Bluetooth: btmtksdio: move interrupt service to work") Cc: stable@vger.kernel.org Signed-off-by: Sergey Senozhatsky Reviewed-by: Sean Wang Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btmtksdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 5b0fab7b89b5..c6f80c419e90 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -620,7 +620,7 @@ static void btmtksdio_txrx_work(struct work_struct *work) if (btmtksdio_rx_packet(bdev, rx_size) < 0) bdev->hdev->stat.err_rx++; } - } while (int_status || time_is_before_jiffies(txrx_timeout)); + } while (int_status && time_is_after_jiffies(txrx_timeout)); /* Enable interrupt */ if (bdev->func->irq_handler) From f70f7f2512c6b9113dc78f6a25361166afd1412e Mon Sep 17 00:00:00 2001 From: Ravindra Date: Wed, 10 Jun 2026 21:55:44 +0530 Subject: [PATCH 49/49] Bluetooth: btintel_pcie: Separate coredump work from RX work Sharing a single workqueue between coredump processing and RX delays evacuation of RX events while a coredump is in progress. The firmware's RX buffers can overflow during that window, leading to dropped events. The issue was observed in HID use cases where HID reports arrive in bursts and quickly fill the RX path while a coredump is being collected. Move coredump processing to a dedicated ordered coredump_workqueue with its own coredump_work, so coredumps run independently of RX. All four coredump trigger sources (FW assert, HW exception, user sysfs trigger, and resume-error detection) are switched to this new workqueue. Ordering serialises concurrent triggers without blocking RX. Signed-off-by: Ravindra Signed-off-by: Kiran K Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 102 +++++++++++++++++++++++++------ drivers/bluetooth/btintel_pcie.h | 5 ++ 2 files changed, 87 insertions(+), 20 deletions(-) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 93473ba05d83..9e39327dc1fe 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -1457,7 +1457,7 @@ static void btintel_pcie_msix_fw_trigger_handler(struct btintel_pcie_data *data) if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT; - queue_work(data->workqueue, &data->rx_work); + queue_work(data->coredump_workqueue, &data->coredump_work); } static void btintel_pcie_msix_hw_exp_handler(struct btintel_pcie_data *data) @@ -1474,16 +1474,21 @@ static void btintel_pcie_msix_hw_exp_handler(struct btintel_pcie_data *data) if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT; - queue_work(data->workqueue, &data->rx_work); + queue_work(data->coredump_workqueue, &data->coredump_work); } -static void btintel_pcie_rx_work(struct work_struct *work) +static void btintel_pcie_coredump_worker(struct work_struct *work) { struct btintel_pcie_data *data = container_of(work, - struct btintel_pcie_data, rx_work); - struct sk_buff *skb; + struct btintel_pcie_data, coredump_work); int err; + /* hdev is NULL until setup_hdev() succeeds, and is cleared on + * teardown after disable_work_sync() drains us; bail in that case. + */ + if (!data->hdev) + return; + if (test_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags)) { err = btintel_pcie_dump_fwtrigger_event(data); if (err) @@ -1507,6 +1512,13 @@ static void btintel_pcie_rx_work(struct work_struct *work) btintel_pcie_read_hwexp(data); clear_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags); } +} + +static void btintel_pcie_rx_work(struct work_struct *work) +{ + struct btintel_pcie_data *data = container_of(work, + struct btintel_pcie_data, rx_work); + struct sk_buff *skb; /* Process the sk_buf in queue and send to the HCI layer */ while ((skb = skb_dequeue(&data->rx_skb_q))) { @@ -2181,9 +2193,11 @@ exit_error: static void btintel_pcie_release_hdev(struct btintel_pcie_data *data) { - struct hci_dev *hdev; + struct hci_dev *hdev = data->hdev; + + if (!hdev) + return; - hdev = data->hdev; hci_unregister_dev(hdev); hci_free_dev(hdev); data->hdev = NULL; @@ -2601,6 +2615,10 @@ static void btintel_pcie_reset_work(struct work_struct *wk) btintel_pcie_synchronize_irqs(data); flush_work(&data->rx_work); + /* Drain any in-flight coredump and block new ones across reset. + * Safe from self-deadlock: coredump_work runs on a separate wq. + */ + disable_work_sync(&data->coredump_work); bt_dev_dbg(data->hdev, "Release bluetooth interface"); if (data->reset_type == BTINTEL_PCIE_IOSF_PRR_PLDR) { @@ -2608,16 +2626,27 @@ static void btintel_pcie_reset_work(struct work_struct *wk) * pci_rescan_remove_lock. This mutex serializes against PCI device * addition/removal (hotplug), so no device can be added to or * removed from the bus list while this code runs. + * + * device_reprobe() inside btintel_pcie_perform_pldr() destroys + * 'data' via .remove(); a fresh probe re-INIT_WORKs the + * coredump_work with disable count 0, so we must not call + * enable_work() on this path. */ btintel_pcie_perform_pldr(data); goto out; } btintel_pcie_release_hdev(data); - err = pci_reset_function(pdev); + /* Use pci_try_reset_function() rather than pci_reset_function() to + * avoid an ABBA deadlock against btintel_pcie_remove(): the PCI core + * calls .remove() with device_lock held, and remove() then waits for + * this work via cancel_work_sync(); pci_reset_function() would in + * turn try to acquire the same device_lock, deadlocking both paths. + */ + err = pci_try_reset_function(pdev); if (err) { BT_ERR("Failed resetting the pcie device (%d)", err); - goto out; + goto out_enable; } btintel_pcie_enable_interrupts(data); @@ -2627,7 +2656,7 @@ static void btintel_pcie_reset_work(struct work_struct *wk) if (err) { BT_ERR("Failed to enable bluetooth hardware after reset (%d)", err); - goto out; + goto out_enable; } btintel_pcie_reset_ia(data); @@ -2637,8 +2666,15 @@ static void btintel_pcie_reset_work(struct work_struct *wk) err = btintel_pcie_setup_hdev(data); if (err) { BT_ERR("Failed registering hdev (%d)", err); - goto out; + goto out_enable; } + +out_enable: + /* Balance disable_work_sync() above on every exit. Leaving the + * counter incremented on a failed reset would permanently disable + * coredump_work even after a later successful reset. + */ + enable_work(&data->coredump_work); out: pci_dev_put(pdev); pci_unlock_rescan_remove(); @@ -2772,7 +2808,6 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) hdev->bus = HCI_PCI; hci_set_drvdata(hdev, data); - data->hdev = hdev; SET_HCIDEV_DEV(hdev, &data->pdev->dev); hdev->manufacturer = 2; @@ -2791,15 +2826,17 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) err = hci_register_dev(hdev); if (err < 0) { BT_ERR("Failed to register to hdev (%d)", err); - goto exit_error; + hci_free_dev(hdev); + return err; } + /* Publish hdev only after successful registration; the coredump + * worker bails on !data->hdev, so it never observes a half-set-up + * device. + */ + data->hdev = hdev; data->dmp_hdr.driver_name = KBUILD_MODNAME; return 0; - -exit_error: - hci_free_dev(hdev); - return err; } static int btintel_pcie_probe(struct pci_dev *pdev, @@ -2830,9 +2867,16 @@ static int btintel_pcie_probe(struct pci_dev *pdev, if (!data->workqueue) return -ENOMEM; + data->coredump_workqueue = alloc_ordered_workqueue(KBUILD_MODNAME "_cd", 0); + if (!data->coredump_workqueue) { + destroy_workqueue(data->workqueue); + return -ENOMEM; + } + skb_queue_head_init(&data->rx_skb_q); INIT_WORK(&data->rx_work, btintel_pcie_rx_work); INIT_WORK(&data->reset_work, btintel_pcie_reset_work); + INIT_WORK(&data->coredump_work, btintel_pcie_coredump_worker); data->boot_stage_cache = 0x00; data->img_resp_cache = 0x00; @@ -2875,6 +2919,8 @@ exit_error: /* reset device before exit */ btintel_pcie_reset_bt(data); + destroy_workqueue(data->coredump_workqueue); + pci_clear_master(pdev); pci_set_drvdata(pdev, NULL); @@ -2892,13 +2938,20 @@ static void btintel_pcie_remove(struct pci_dev *pdev) return; } + /* Permanently block coredump triggers and drain the worker before + * tearing down. Must run before cancel_work_sync(&reset_work) so + * the disable counter stays >= 1 even after reset_work()'s + * balanced enable_work() (counter 2 -> 1, never reaching 0). + */ + disable_work_sync(&data->coredump_work); + /* Cancel pending reset work. Skip only when remove() is called from * within the reset work itself (PLDR device_reprobe path) to avoid * deadlock. current_work() returns the work_struct of the caller if * we are in a workqueue context. */ if (current_work() != &data->reset_work) - cancel_work_sync(&data->reset_work); + disable_work_sync(&data->reset_work); btintel_pcie_disable_interrupts(data); @@ -2918,6 +2971,7 @@ static void btintel_pcie_remove(struct pci_dev *pdev) btintel_pcie_release_hdev(data); + destroy_workqueue(data->coredump_workqueue); destroy_workqueue(data->workqueue); btintel_pcie_free(data); @@ -2933,11 +2987,19 @@ static void btintel_pcie_coredump(struct device *dev) struct pci_dev *pdev = to_pci_dev(dev); struct btintel_pcie_data *data = pci_get_drvdata(pdev); + if (!data) + return; + if (test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) return; data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER; - queue_work(data->workqueue, &data->rx_work); + /* queue_work() returns false if the work is disabled (reset or + * remove in progress); clear the in-progress bit so a later + * trigger can succeed once the work is re-enabled. + */ + if (!queue_work(data->coredump_workqueue, &data->coredump_work)) + clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags); } #endif @@ -3078,7 +3140,7 @@ static int btintel_pcie_resume(struct device *dev) &data->flags)) { data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT; - queue_work(data->workqueue, &data->rx_work); + queue_work(data->coredump_workqueue, &data->coredump_work); } set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags); btintel_pcie_reset(data->hdev); diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index e4a8fa479188..7caee093e316 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -466,6 +466,8 @@ struct btintel_pcie_dump_header { * @workqueue: workqueue for RX work * @rx_skb_q: SKB queue for RX packet * @rx_work: RX work struct to process the RX packet in @rx_skb_q + * @coredump_workqueue: dedicated workqueue for coredump collection + * @coredump_work: work struct for coredump trace collection * @dma_pool: DMA pool for descriptors, index array and ci * @dma_p_addr: DMA address for pool * @dma_v_addr: address of pool @@ -514,6 +516,9 @@ struct btintel_pcie_data { struct work_struct rx_work; struct work_struct reset_work; + struct workqueue_struct *coredump_workqueue; + struct work_struct coredump_work; + struct dma_pool *dma_pool; dma_addr_t dma_p_addr; void *dma_v_addr;