diff options
Diffstat (limited to 'drivers/bluetooth')
| -rw-r--r-- | drivers/bluetooth/btmtk.c | 11 | ||||
| -rw-r--r-- | drivers/bluetooth/btmtksdio.c | 33 | ||||
| -rw-r--r-- | drivers/bluetooth/btnxpuart.c | 39 | ||||
| -rw-r--r-- | drivers/bluetooth/btrtl.c | 13 | ||||
| -rw-r--r-- | drivers/bluetooth/btusb.c | 8 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_bcm.c | 1 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_bcm4377.c | 1 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_h5.c | 4 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_intel.c | 1 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 2 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_serdev.c | 2 |
11 files changed, 83 insertions, 32 deletions
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index 66b346761043..c0ed51567ed4 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -860,6 +860,7 @@ static u32 btmtk_usb_reset_done(struct hci_dev *hdev) int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id) { + int reset_err = 0; u32 val; int err; @@ -958,8 +959,10 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id) err = readx_poll_timeout(btmtk_usb_reset_done, hdev, val, val & MTK_BT_RST_DONE, 20000, 1000000); - if (err < 0) + if (err < 0) { bt_dev_err(hdev, "Reset timeout"); + reset_err = err; + } if (dev_id == 0x7922) { err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT, 0x000000FF); @@ -968,10 +971,12 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id) } err = btmtk_usb_id_get(hdev, 0x70010200, &val); - if (err || (!val && dev_id != 0x6639)) + if (err || (!val && dev_id != 0x6639)) { bt_dev_err(hdev, "Can't get device id, subsys reset fail."); + return err ? err : -ENODEV; + } - return err; + return reset_err; } EXPORT_SYMBOL_GPL(btmtk_usb_subsys_reset); diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 4e1012e90979..94aa60d9cc20 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -272,12 +272,24 @@ static int btmtksdio_tx_packet(struct btmtksdio_dev *bdev, struct sk_buff *skb) { struct mtkbtsdio_hdr *sdio_hdr; + unsigned int len, pad_len; int err; - /* Make sure that there are enough rooms for SDIO header */ - if (unlikely(skb_headroom(skb) < sizeof(*sdio_hdr))) { - err = pskb_expand_head(skb, sizeof(*sdio_hdr), 0, - GFP_ATOMIC); + /* Make sure that the data buffer is not shared with anyone else and + * that there is enough room for the SDIO header + */ + err = skb_cow_head(skb, sizeof(*sdio_hdr)); + if (err < 0) + return err; + + /* The transfer is rounded up to the SDIO block size, so the buffer + * has to provide tailroom for the padding as well + */ + len = skb->len + sizeof(*sdio_hdr); + pad_len = round_up(len, MTK_SDIO_BLOCK_SIZE) - len; + + if (unlikely(skb_tailroom(skb) < pad_len)) { + err = pskb_expand_head(skb, 0, pad_len, GFP_ATOMIC); if (err < 0) return err; } @@ -290,19 +302,22 @@ static int btmtksdio_tx_packet(struct btmtksdio_dev *bdev, sdio_hdr->reserved = cpu_to_le16(0); sdio_hdr->bt_type = hci_skb_pkt_type(skb); + /* Zero the padding so that no uninitialised memory is sent out */ + skb_put_zero(skb, pad_len); + clear_bit(BTMTKSDIO_HW_TX_READY, &bdev->tx_state); - err = sdio_writesb(bdev->func, MTK_REG_CTDR, skb->data, - round_up(skb->len, MTK_SDIO_BLOCK_SIZE)); + err = sdio_writesb(bdev->func, MTK_REG_CTDR, skb->data, skb->len); if (err < 0) - goto err_skb_pull; + goto err_skb_restore; - bdev->hdev->stat.byte_tx += skb->len; + bdev->hdev->stat.byte_tx += len; kfree_skb(skb); return 0; -err_skb_pull: +err_skb_restore: + skb_trim(skb, len); skb_pull(skb, sizeof(*sdio_hdr)); return err; diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 9afe3f73c22b..25e7b41b349f 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -1359,12 +1359,21 @@ static int nxp_process_fw_dump(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_acl_hdr *acl_hdr = (struct hci_acl_hdr *)skb_pull_data(skb, sizeof(*acl_hdr)); - struct nxp_fw_dump_hdr *fw_dump_hdr = (struct nxp_fw_dump_hdr *)skb->data; + struct nxp_fw_dump_hdr *fw_dump_hdr; struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); - __u16 seq_num = __le16_to_cpu(fw_dump_hdr->seq_num); - __u16 buf_len = __le16_to_cpu(fw_dump_hdr->buf_len); + __u16 seq_num; + __u16 buf_len; int err; + fw_dump_hdr = skb_pull_data(skb, sizeof(*fw_dump_hdr)); + if (!fw_dump_hdr) { + bt_dev_warn(hdev, "FW dump: invalid or corrupt fw dump chunk"); + goto free_skb; + } + + seq_num = __le16_to_cpu(fw_dump_hdr->seq_num); + buf_len = __le16_to_cpu(fw_dump_hdr->buf_len); + if (seq_num == 0x0001) { if (test_and_set_bit(BTNXPUART_FW_DUMP_IN_PROGRESS, &nxpdev->tx_state)) { bt_dev_err(hdev, "FW dump already in progress"); @@ -1809,6 +1818,28 @@ static void nxp_coredump_notify(struct hci_dev *hdev, int state) kobject_uevent_env(&serdev->dev.kobj, KOBJ_CHANGE, envp); } +/* + * Check if the remote M.2 connector device linked via OF graph is present + * and available. This is used to determine whether the pwrseq path should + * be taken. When the remote connector node is disabled (e.g., by a DT + * overlay switching from PCIe WiFi to SDIO WiFi), the pwrseq path is + * skipped, allowing the BT driver to use a direct bluetooth child node + * instead. + */ +static bool nxp_m2_connector_is_available(struct device *dev) +{ + struct device_node *ep __free(device_node) = + of_graph_get_next_endpoint(dev_of_node(dev), NULL); + + if (!ep) + return false; + + struct device_node *remote __free(device_node) = + of_graph_get_remote_port_parent(ep); + + return remote && of_device_is_available(remote); +} + static int nxp_serdev_probe(struct serdev_device *serdev) { struct hci_dev *hdev; @@ -1863,7 +1894,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev) return err; } - if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) { + if (nxp_m2_connector_is_available(&serdev->ctrl->dev)) { struct pwrseq_desc *pwrseq; pwrseq = pwrseq_get(&serdev->ctrl->dev, "uart"); diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index 7f54d2d2d13a..03fa9409e3ee 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -1343,19 +1343,6 @@ 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, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index be82bbbc1b5c..d70a3e7a13f5 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -67,6 +67,7 @@ static struct usb_driver btusb_driver; #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) #define BTUSB_ACTIONS_SEMI BIT(27) #define BTUSB_BARROT BIT(28) +#define BTUSB_BROKEN_EXT_SCAN BIT(29) static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -617,6 +618,10 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x0489, 0xe130), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + /* Realtek 8761BU Bluetooth devices */ + { USB_DEVICE(0x0bda, 0xa728), .driver_info = BTUSB_REALTEK | + BTUSB_BROKEN_EXT_SCAN }, + /* Realtek Bluetooth devices */ { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01), .driver_info = BTUSB_REALTEK }, @@ -4401,6 +4406,9 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_INVALID_LE_STATES) hci_set_quirk(hdev, HCI_QUIRK_BROKEN_LE_STATES); + if (id->driver_info & BTUSB_BROKEN_EXT_SCAN) + hci_set_quirk(hdev, HCI_QUIRK_BROKEN_EXT_SCAN); + if (id->driver_info & BTUSB_DIGIANSWER) { data->cmdreq_type = USB_TYPE_VENDOR; hci_set_quirk(hdev, HCI_QUIRK_RESET_ON_CLOSE); diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 01da3fecb536..9a103db7e355 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -547,6 +547,7 @@ static int bcm_close(struct hci_uart *hu) if (IS_ENABLED(CONFIG_PM) && bdev->irq_acquired) { devm_free_irq(bdev->dev, bdev->irq, bdev); device_init_wakeup(bdev->dev, false); + pm_runtime_dont_use_autosuspend(bdev->dev); pm_runtime_disable(bdev->dev); } diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c index 925d0a635945..66d49b471544 100644 --- a/drivers/bluetooth/hci_bcm4377.c +++ b/drivers/bluetooth/hci_bcm4377.c @@ -2490,6 +2490,7 @@ static const struct bcm4377_hw bcm4377_hw_variants[] = { .has_bar0_core2_window2 = true, .broken_mws_transport_config = true, .broken_le_coded = true, + .broken_le_ext_adv_report_phy = true, .send_calibration = bcm4378_send_calibration, .send_ptb = bcm4378_send_ptb, }, diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 60b90f1e11fc..b1999e14aade 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -1023,8 +1023,10 @@ static void h5_btrtl_open(struct h5 *h5) static void h5_btrtl_close(struct h5 *h5) { - if (!test_bit(H5_WAKEUP_DISABLE, &h5->flags)) + if (!test_bit(H5_WAKEUP_DISABLE, &h5->flags)) { + pm_runtime_dont_use_autosuspend(&h5->hu->serdev->dev); pm_runtime_disable(&h5->hu->serdev->dev); + } gpiod_set_value_cansleep(h5->device_wake_gpio, 0); gpiod_set_value_cansleep(h5->enable_gpio, 0); diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index ecf597f3e201..d10ce7a0ba3e 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -345,6 +345,7 @@ static int intel_set_power(struct hci_uart *hu, bool powered) devm_free_irq(&idev->pdev->dev, idev->irq, idev); device_wakeup_disable(&idev->pdev->dev); + pm_runtime_dont_use_autosuspend(&idev->pdev->dev); pm_runtime_disable(&idev->pdev->dev); } } diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 58f5504a336e..697e32122cc8 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -457,7 +457,7 @@ static int hci_uart_setup(struct hci_dev *hdev) if (IS_ERR(skb)) { BT_ERR("%s: Reading local version information failed (%ld)", hdev->name, PTR_ERR(skb)); - return 0; + return PTR_ERR(skb); } if (skb->len != sizeof(*ver)) { diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index 593d9cefbbf9..d2eaf2f12aa2 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -221,7 +221,7 @@ static int hci_uart_setup(struct hci_dev *hdev) if (IS_ERR(skb)) { bt_dev_err(hdev, "Reading local version info failed (%ld)", PTR_ERR(skb)); - return 0; + return PTR_ERR(skb); } if (skb->len != sizeof(*ver)) |
