summaryrefslogtreecommitdiff
path: root/drivers/bluetooth
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r--drivers/bluetooth/btmtk.c11
-rw-r--r--drivers/bluetooth/btmtksdio.c33
-rw-r--r--drivers/bluetooth/btnxpuart.c39
-rw-r--r--drivers/bluetooth/btrtl.c13
-rw-r--r--drivers/bluetooth/btusb.c8
-rw-r--r--drivers/bluetooth/hci_bcm.c1
-rw-r--r--drivers/bluetooth/hci_bcm4377.c1
-rw-r--r--drivers/bluetooth/hci_h5.c4
-rw-r--r--drivers/bluetooth/hci_intel.c1
-rw-r--r--drivers/bluetooth/hci_ldisc.c2
-rw-r--r--drivers/bluetooth/hci_serdev.c2
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))