diff options
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/Kconfig | 12 | ||||
-rw-r--r-- | drivers/bluetooth/btintel.c | 13 | ||||
-rw-r--r-- | drivers/bluetooth/btintel.h | 6 | ||||
-rw-r--r-- | drivers/bluetooth/btintel_pcie.c | 141 | ||||
-rw-r--r-- | drivers/bluetooth/btintel_pcie.h | 19 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_sdio.c | 4 | ||||
-rw-r--r-- | drivers/bluetooth/btmtksdio.c | 2 | ||||
-rw-r--r-- | drivers/bluetooth/btnxpuart.c | 58 | ||||
-rw-r--r-- | drivers/bluetooth/btusb.c | 302 | ||||
-rw-r--r-- | drivers/bluetooth/hci_aml.c | 3 |
10 files changed, 383 insertions, 177 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 7771edf54fb3..4ab32abf0f48 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -56,18 +56,6 @@ config BT_HCIBTUSB_POLL_SYNC Say Y here to enable USB poll_sync for Bluetooth USB devices by default. -config BT_HCIBTUSB_AUTO_ISOC_ALT - bool "Automatically adjust alternate setting for Isoc endpoints" - depends on BT_HCIBTUSB - default y if CHROME_PLATFORMS - help - Say Y here to automatically adjusting the alternate setting for - HCI_USER_CHANNEL whenever a SCO link is established. - - When enabled, btusb intercepts the HCI_EV_SYNC_CONN_COMPLETE packets - and configures isoc endpoint alternate setting automatically when - HCI_USER_CHANNEL is in use. - config BT_HCIBTUSB_BCM bool "Broadcom protocol support" depends on BT_HCIBTUSB diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 48e2f400957b..55cc1652bfe4 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -2719,7 +2719,7 @@ static int btintel_uefi_get_dsbr(u32 *dsbr_var) } __packed data; efi_status_t status; - unsigned long data_size = 0; + unsigned long data_size = sizeof(data); efi_guid_t guid = EFI_GUID(0xe65d8884, 0xd4af, 0x4b20, 0x8d, 0x03, 0x77, 0x2e, 0xcc, 0x3d, 0xa5, 0x31); @@ -2730,15 +2730,9 @@ static int btintel_uefi_get_dsbr(u32 *dsbr_var) return -EOPNOTSUPP; status = efi.get_variable(BTINTEL_EFI_DSBR, &guid, NULL, &data_size, - NULL); - - if (status != EFI_BUFFER_TOO_SMALL || !data_size) - return -EIO; - - status = efi.get_variable(BTINTEL_EFI_DSBR, &guid, NULL, &data_size, &data); - if (status != EFI_SUCCESS) + if (status != EFI_SUCCESS || data_size != sizeof(data)) return -ENXIO; *dsbr_var = data.dsbr; @@ -3688,7 +3682,7 @@ int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name) } EXPORT_SYMBOL_GPL(btintel_configure_setup); -int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) +static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) { struct intel_tlv *tlv = (void *)&skb->data[5]; @@ -3716,7 +3710,6 @@ int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) recv_frame: return hci_recv_frame(hdev, skb); } -EXPORT_SYMBOL_GPL(btintel_diagnostics); int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb) { diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 2aece3effa4e..1d12c4113c66 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -277,7 +277,6 @@ 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_diagnostics(struct hci_dev *hdev, struct sk_buff *skb); #else static inline int btintel_check_bdaddr(struct hci_dev *hdev) @@ -411,9 +410,4 @@ 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_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) -{ - return -EOPNOTSUPP; -} #endif diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 0a759ea26fd3..50fe17f1e1d1 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -208,6 +208,96 @@ static void btintel_pcie_prepare_tx(struct txq *txq, u16 tfd_index, memcpy(buf->data, skb->data, tfd->size); } +static inline void btintel_pcie_dump_debug_registers(struct hci_dev *hdev) +{ + struct btintel_pcie_data *data = hci_get_drvdata(hdev); + u16 cr_hia, cr_tia; + u32 reg, mbox_reg; + struct sk_buff *skb; + u8 buf[80]; + + skb = alloc_skb(1024, GFP_ATOMIC); + if (!skb) + return; + + snprintf(buf, sizeof(buf), "%s", "---- Dump of debug registers ---"); + bt_dev_dbg(hdev, "%s", buf); + skb_put_data(skb, buf, strlen(buf)); + + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_BOOT_STAGE_REG); + snprintf(buf, sizeof(buf), "boot stage: 0x%8.8x", reg); + bt_dev_dbg(hdev, "%s", buf); + skb_put_data(skb, buf, strlen(buf)); + data->boot_stage_cache = reg; + + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_STATUS_REG); + snprintf(buf, sizeof(buf), "ipc status: 0x%8.8x", reg); + skb_put_data(skb, buf, strlen(buf)); + bt_dev_dbg(hdev, "%s", buf); + + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_CONTROL_REG); + snprintf(buf, sizeof(buf), "ipc control: 0x%8.8x", reg); + skb_put_data(skb, buf, strlen(buf)); + bt_dev_dbg(hdev, "%s", buf); + + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG); + snprintf(buf, sizeof(buf), "ipc sleep control: 0x%8.8x", reg); + skb_put_data(skb, buf, strlen(buf)); + bt_dev_dbg(hdev, "%s", buf); + + /*Read the Mail box status and registers*/ + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_MBOX_STATUS_REG); + snprintf(buf, sizeof(buf), "mbox status: 0x%8.8x", reg); + skb_put_data(skb, buf, strlen(buf)); + if (reg & BTINTEL_PCIE_CSR_MBOX_STATUS_MBOX1) { + mbox_reg = btintel_pcie_rd_reg32(data, + BTINTEL_PCIE_CSR_MBOX_1_REG); + snprintf(buf, sizeof(buf), "mbox_1: 0x%8.8x", mbox_reg); + skb_put_data(skb, buf, strlen(buf)); + bt_dev_dbg(hdev, "%s", buf); + } + + if (reg & BTINTEL_PCIE_CSR_MBOX_STATUS_MBOX2) { + mbox_reg = btintel_pcie_rd_reg32(data, + BTINTEL_PCIE_CSR_MBOX_2_REG); + snprintf(buf, sizeof(buf), "mbox_2: 0x%8.8x", mbox_reg); + skb_put_data(skb, buf, strlen(buf)); + bt_dev_dbg(hdev, "%s", buf); + } + + if (reg & BTINTEL_PCIE_CSR_MBOX_STATUS_MBOX3) { + mbox_reg = btintel_pcie_rd_reg32(data, + BTINTEL_PCIE_CSR_MBOX_3_REG); + snprintf(buf, sizeof(buf), "mbox_3: 0x%8.8x", mbox_reg); + skb_put_data(skb, buf, strlen(buf)); + bt_dev_dbg(hdev, "%s", buf); + } + + if (reg & BTINTEL_PCIE_CSR_MBOX_STATUS_MBOX4) { + mbox_reg = btintel_pcie_rd_reg32(data, + BTINTEL_PCIE_CSR_MBOX_4_REG); + snprintf(buf, sizeof(buf), "mbox_4: 0x%8.8x", mbox_reg); + skb_put_data(skb, buf, strlen(buf)); + bt_dev_dbg(hdev, "%s", buf); + } + + cr_hia = data->ia.cr_hia[BTINTEL_PCIE_RXQ_NUM]; + cr_tia = data->ia.cr_tia[BTINTEL_PCIE_RXQ_NUM]; + snprintf(buf, sizeof(buf), "rxq: cr_tia: %u cr_hia: %u", cr_tia, cr_hia); + skb_put_data(skb, buf, strlen(buf)); + bt_dev_dbg(hdev, "%s", buf); + + cr_hia = data->ia.cr_hia[BTINTEL_PCIE_TXQ_NUM]; + cr_tia = data->ia.cr_tia[BTINTEL_PCIE_TXQ_NUM]; + snprintf(buf, sizeof(buf), "txq: cr_tia: %u cr_hia: %u", cr_tia, cr_hia); + skb_put_data(skb, buf, strlen(buf)); + bt_dev_dbg(hdev, "%s", buf); + snprintf(buf, sizeof(buf), "--------------------------------"); + bt_dev_dbg(hdev, "%s", buf); + + hci_recv_diag(hdev, skb); +} + static int btintel_pcie_send_sync(struct btintel_pcie_data *data, struct sk_buff *skb) { @@ -237,8 +327,11 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data, /* Wait for the complete interrupt - URBD0 */ ret = wait_event_timeout(data->tx_wait_q, data->tx_wait_done, msecs_to_jiffies(BTINTEL_PCIE_TX_WAIT_TIMEOUT_MS)); - if (!ret) + if (!ret) { + bt_dev_err(data->hdev, "tx completion timeout"); + btintel_pcie_dump_debug_registers(data->hdev); return -ETIME; + } return 0; } @@ -756,6 +849,26 @@ static int btintel_pcie_read_device_mem(struct btintel_pcie_data *data, return 0; } +static inline bool btintel_pcie_in_lockdown(struct btintel_pcie_data *data) +{ + return (data->boot_stage_cache & + BTINTEL_PCIE_CSR_BOOT_STAGE_ROM_LOCKDOWN) || + (data->boot_stage_cache & + BTINTEL_PCIE_CSR_BOOT_STAGE_IML_LOCKDOWN); +} + +static inline bool btintel_pcie_in_error(struct btintel_pcie_data *data) +{ + return (data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_DEVICE_ERR) || + (data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_ABORT_HANDLER); +} + +static void btintel_pcie_msix_gp1_handler(struct btintel_pcie_data *data) +{ + bt_dev_err(data->hdev, "Received gp1 mailbox interrupt"); + btintel_pcie_dump_debug_registers(data->hdev); +} + /* This function handles the MSI-X interrupt for gp0 cause (bit 0 in * BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES) which is sent for boot stage and image response. */ @@ -779,6 +892,18 @@ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data) if (reg != data->img_resp_cache) data->img_resp_cache = reg; + if (btintel_pcie_in_error(data)) { + bt_dev_err(data->hdev, "Controller in error state"); + btintel_pcie_dump_debug_registers(data->hdev); + return; + } + + if (btintel_pcie_in_lockdown(data)) { + bt_dev_err(data->hdev, "Controller in lockdown state"); + btintel_pcie_dump_debug_registers(data->hdev); + return; + } + data->gp0_received = true; old_ctxt = data->alive_intr_ctxt; @@ -889,7 +1014,6 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data) static int btintel_pcie_recv_event(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_event_hdr *hdr = (void *)skb->data; - const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 }; struct btintel_pcie_data *data = hci_get_drvdata(hdev); if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff && @@ -945,15 +1069,6 @@ static int btintel_pcie_recv_event(struct hci_dev *hdev, struct sk_buff *skb) } } - /* Handle all diagnostics events separately. May still call - * hci_recv_frame. - */ - if (len >= sizeof(diagnostics_hdr) && - memcmp(&skb->data[2], diagnostics_hdr, - sizeof(diagnostics_hdr)) == 0) { - return btintel_diagnostics(hdev, skb); - } - /* This is a debug event that comes from IML and OP image when it * starts execution. There is no need pass this event to stack. */ @@ -1343,6 +1458,9 @@ static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id) if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HWEXP) btintel_pcie_msix_hw_exp_handler(data); + if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP1) + btintel_pcie_msix_gp1_handler(data); + /* This interrupt is triggered by the firmware after updating * boot_stage register and image_response register */ @@ -2028,6 +2146,7 @@ static int btintel_pcie_setup(struct hci_dev *hdev) while ((err = btintel_pcie_setup_internal(hdev)) && fw_dl_retry++ < 1) { bt_dev_err(hdev, "Firmware download retry count: %d", fw_dl_retry); + btintel_pcie_dump_debug_registers(hdev); err = btintel_pcie_reset_bt(data); if (err) { bt_dev_err(hdev, "Failed to do shr reset: %d", err); diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index 873178019cad..21b964b15c1c 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -12,10 +12,17 @@ #define BTINTEL_PCIE_CSR_HW_REV_REG (BTINTEL_PCIE_CSR_BASE + 0x028) #define BTINTEL_PCIE_CSR_RF_ID_REG (BTINTEL_PCIE_CSR_BASE + 0x09C) #define BTINTEL_PCIE_CSR_BOOT_STAGE_REG (BTINTEL_PCIE_CSR_BASE + 0x108) +#define BTINTEL_PCIE_CSR_IPC_CONTROL_REG (BTINTEL_PCIE_CSR_BASE + 0x10C) +#define BTINTEL_PCIE_CSR_IPC_STATUS_REG (BTINTEL_PCIE_CSR_BASE + 0x110) #define BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG (BTINTEL_PCIE_CSR_BASE + 0x114) #define BTINTEL_PCIE_CSR_CI_ADDR_LSB_REG (BTINTEL_PCIE_CSR_BASE + 0x118) #define BTINTEL_PCIE_CSR_CI_ADDR_MSB_REG (BTINTEL_PCIE_CSR_BASE + 0x11C) #define BTINTEL_PCIE_CSR_IMG_RESPONSE_REG (BTINTEL_PCIE_CSR_BASE + 0x12C) +#define BTINTEL_PCIE_CSR_MBOX_1_REG (BTINTEL_PCIE_CSR_BASE + 0x170) +#define BTINTEL_PCIE_CSR_MBOX_2_REG (BTINTEL_PCIE_CSR_BASE + 0x174) +#define BTINTEL_PCIE_CSR_MBOX_3_REG (BTINTEL_PCIE_CSR_BASE + 0x178) +#define BTINTEL_PCIE_CSR_MBOX_4_REG (BTINTEL_PCIE_CSR_BASE + 0x17C) +#define BTINTEL_PCIE_CSR_MBOX_STATUS_REG (BTINTEL_PCIE_CSR_BASE + 0x180) #define BTINTEL_PCIE_PRPH_DEV_ADDR_REG (BTINTEL_PCIE_CSR_BASE + 0x440) #define BTINTEL_PCIE_PRPH_DEV_RD_REG (BTINTEL_PCIE_CSR_BASE + 0x458) #define BTINTEL_PCIE_CSR_HBUS_TARG_WRPTR (BTINTEL_PCIE_CSR_BASE + 0x460) @@ -41,6 +48,9 @@ #define BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW (BIT(2)) #define BTINTEL_PCIE_CSR_BOOT_STAGE_ROM_LOCKDOWN (BIT(10)) #define BTINTEL_PCIE_CSR_BOOT_STAGE_IML_LOCKDOWN (BIT(11)) +#define BTINTEL_PCIE_CSR_BOOT_STAGE_DEVICE_ERR (BIT(12)) +#define BTINTEL_PCIE_CSR_BOOT_STAGE_ABORT_HANDLER (BIT(13)) +#define BTINTEL_PCIE_CSR_BOOT_STAGE_DEVICE_HALTED (BIT(14)) #define BTINTEL_PCIE_CSR_BOOT_STAGE_MAC_ACCESS_ON (BIT(16)) #define BTINTEL_PCIE_CSR_BOOT_STAGE_ALIVE (BIT(23)) #define BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY (BIT(24)) @@ -89,6 +99,7 @@ enum msix_fh_int_causes { /* Causes for the HW register interrupts */ 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 */ }; @@ -121,6 +132,14 @@ enum btintel_pcie_tlv_type { BTINTEL_FW_BUILD, }; +/* causes for the MBOX interrupts */ +enum msix_mbox_int_causes { + BTINTEL_PCIE_CSR_MBOX_STATUS_MBOX1 = BIT(0), /* cause MBOX1 */ + BTINTEL_PCIE_CSR_MBOX_STATUS_MBOX2 = BIT(1), /* cause MBOX2 */ + BTINTEL_PCIE_CSR_MBOX_STATUS_MBOX3 = BIT(2), /* cause MBOX3 */ + BTINTEL_PCIE_CSR_MBOX_STATUS_MBOX4 = BIT(3), /* cause MBOX4 */ +}; + #define BTINTEL_PCIE_MSIX_NON_AUTO_CLEAR_CAUSE BIT(7) /* Minimum and Maximum number of MSI-X Vector diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 07cd308f7abf..93932a0d8625 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -100,7 +100,9 @@ static int btmrvl_sdio_probe_of(struct device *dev, } /* Configure wakeup (enabled by default) */ - device_init_wakeup(dev, true); + ret = devm_device_init_wakeup(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to init wakeup\n"); } } diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 1d26207b2ba7..c16a3518b8ff 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -1414,7 +1414,7 @@ static int btmtksdio_probe(struct sdio_func *func, */ pm_runtime_put_noidle(bdev->dev); - err = device_init_wakeup(bdev->dev, true); + err = devm_device_init_wakeup(bdev->dev); if (err) bt_dev_err(hdev, "failed to initialize device wakeup"); diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 604ab2bba231..b34623a69b8a 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -17,6 +17,7 @@ #include <linux/crc32.h> #include <linux/string_helpers.h> #include <linux/gpio/consumer.h> +#include <linux/of_irq.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -143,7 +144,9 @@ struct ps_data { bool driver_sent_cmd; u16 h2c_ps_interval; u16 c2h_ps_interval; + bool wakeup_source; struct gpio_desc *h2c_ps_gpio; + s32 irq_handler; struct hci_dev *hdev; struct work_struct work; struct timer_list ps_timer; @@ -476,12 +479,21 @@ static void ps_timeout_func(struct timer_list *t) } } +static irqreturn_t ps_host_wakeup_irq_handler(int irq, void *priv) +{ + struct btnxpuart_dev *nxpdev = (struct btnxpuart_dev *)priv; + + bt_dev_dbg(nxpdev->hdev, "Host wakeup interrupt"); + return IRQ_HANDLED; +} static int ps_setup(struct hci_dev *hdev) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); struct serdev_device *serdev = nxpdev->serdev; struct ps_data *psdata = &nxpdev->psdata; + int ret; + /* Out-Of-Band Device Wakeup */ psdata->h2c_ps_gpio = devm_gpiod_get_optional(&serdev->dev, "device-wakeup", GPIOD_OUT_LOW); if (IS_ERR(psdata->h2c_ps_gpio)) { @@ -493,11 +505,37 @@ static int ps_setup(struct hci_dev *hdev) if (device_property_read_u8(&serdev->dev, "nxp,wakein-pin", &psdata->h2c_wakeup_gpio)) { psdata->h2c_wakeup_gpio = 0xff; /* 0xff: use default pin/gpio */ } else if (!psdata->h2c_ps_gpio) { - bt_dev_warn(hdev, "nxp,wakein-pin property without device-wakeup GPIO"); + bt_dev_warn(hdev, "nxp,wakein-pin property without device-wakeup-gpios"); psdata->h2c_wakeup_gpio = 0xff; } - device_property_read_u8(&serdev->dev, "nxp,wakeout-pin", &psdata->c2h_wakeup_gpio); + /* Out-Of-Band Host Wakeup */ + if (of_property_read_bool(serdev->dev.of_node, "wakeup-source")) { + psdata->irq_handler = of_irq_get_byname(serdev->dev.of_node, "wakeup"); + bt_dev_info(nxpdev->hdev, "irq_handler: %d", psdata->irq_handler); + if (psdata->irq_handler > 0) + psdata->wakeup_source = true; + } + + if (device_property_read_u8(&serdev->dev, "nxp,wakeout-pin", &psdata->c2h_wakeup_gpio)) { + psdata->c2h_wakeup_gpio = 0xff; + if (psdata->wakeup_source) { + bt_dev_warn(hdev, "host wakeup interrupt without nxp,wakeout-pin"); + psdata->wakeup_source = false; + } + } else if (!psdata->wakeup_source) { + bt_dev_warn(hdev, "nxp,wakeout-pin property without host wakeup interrupt"); + psdata->c2h_wakeup_gpio = 0xff; + } + + if (psdata->wakeup_source) { + ret = devm_request_irq(&serdev->dev, psdata->irq_handler, + ps_host_wakeup_irq_handler, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + dev_name(&serdev->dev), nxpdev); + disable_irq(psdata->irq_handler); + device_init_wakeup(&serdev->dev, true); + } psdata->hdev = hdev; INIT_WORK(&psdata->work, ps_work_func); @@ -637,12 +675,10 @@ static void ps_init(struct hci_dev *hdev) psdata->ps_state = PS_STATE_AWAKE; - if (psdata->c2h_wakeup_gpio) { + if (psdata->c2h_wakeup_gpio != 0xff) psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_GPIO; - } else { + else psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE; - psdata->c2h_wakeup_gpio = 0xff; - } psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID; if (psdata->h2c_ps_gpio) @@ -1821,6 +1857,11 @@ static int nxp_serdev_suspend(struct device *dev) struct ps_data *psdata = &nxpdev->psdata; ps_control(psdata->hdev, PS_STATE_SLEEP); + + if (psdata->wakeup_source) { + enable_irq_wake(psdata->irq_handler); + enable_irq(psdata->irq_handler); + } return 0; } @@ -1829,6 +1870,11 @@ static int nxp_serdev_resume(struct device *dev) struct btnxpuart_dev *nxpdev = dev_get_drvdata(dev); struct ps_data *psdata = &nxpdev->psdata; + if (psdata->wakeup_source) { + disable_irq(psdata->irq_handler); + disable_irq_wake(psdata->irq_handler); + } + ps_control(psdata->hdev, PS_STATE_AWAKE); return 0; } diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index a42dedb78e0a..9ab661d2d1e6 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -21,6 +21,7 @@ #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> +#include <net/bluetooth/hci_drv.h> #include "btintel.h" #include "btbcm.h" @@ -34,7 +35,6 @@ static bool force_scofix; static bool enable_autosuspend = IS_ENABLED(CONFIG_BT_HCIBTUSB_AUTOSUSPEND); static bool enable_poll_sync = IS_ENABLED(CONFIG_BT_HCIBTUSB_POLL_SYNC); static bool reset = true; -static bool auto_isoc_alt = IS_ENABLED(CONFIG_BT_HCIBTUSB_AUTO_ISOC_ALT); static struct usb_driver btusb_driver; @@ -513,6 +513,7 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, /* Realtek 8851BE Bluetooth devices */ + { USB_DEVICE(0x0bda, 0xb850), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3600), .driver_info = BTUSB_REALTEK }, /* Realtek 8852AE Bluetooth devices */ @@ -678,6 +679,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3584), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3605), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3607), .driver_info = BTUSB_MEDIATEK | @@ -716,8 +719,12 @@ 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, 0x3613), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3628), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3630), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, /* Additional Realtek 8723AE Bluetooth devices */ { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK }, @@ -1118,42 +1125,6 @@ static inline void btusb_free_frags(struct btusb_data *data) spin_unlock_irqrestore(&data->rxlock, flags); } -static void btusb_sco_connected(struct btusb_data *data, struct sk_buff *skb) -{ - struct hci_event_hdr *hdr = (void *) skb->data; - struct hci_ev_sync_conn_complete *ev = - (void *) skb->data + sizeof(*hdr); - struct hci_dev *hdev = data->hdev; - unsigned int notify_air_mode; - - if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT) - return; - - if (skb->len < sizeof(*hdr) || hdr->evt != HCI_EV_SYNC_CONN_COMPLETE) - return; - - if (skb->len != sizeof(*hdr) + sizeof(*ev) || ev->status) - return; - - switch (ev->air_mode) { - case BT_CODEC_CVSD: - notify_air_mode = HCI_NOTIFY_ENABLE_SCO_CVSD; - break; - - case BT_CODEC_TRANSPARENT: - notify_air_mode = HCI_NOTIFY_ENABLE_SCO_TRANSP; - break; - - default: - return; - } - - bt_dev_info(hdev, "enabling SCO with air mode %u", ev->air_mode); - data->sco_num = 1; - data->air_mode = notify_air_mode; - schedule_work(&data->work); -} - static int btusb_recv_event(struct btusb_data *data, struct sk_buff *skb) { if (data->intr_interval) { @@ -1161,10 +1132,6 @@ static int btusb_recv_event(struct btusb_data *data, struct sk_buff *skb) schedule_delayed_work(&data->rx_work, 0); } - /* Configure altsetting for HCI_USER_CHANNEL on SCO connected */ - if (auto_isoc_alt && hci_dev_test_flag(data->hdev, HCI_USER_CHANNEL)) - btusb_sco_connected(data, skb); - return data->recv_event(data->hdev, skb); } @@ -3014,9 +2981,8 @@ static void btusb_coredump_qca(struct hci_dev *hdev) static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) { int ret = 0; + unsigned int skip = 0; u8 pkt_type; - u8 *sk_ptr; - unsigned int sk_len; u16 seqno; u32 dump_size; @@ -3025,18 +2991,13 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) struct usb_device *udev = btdata->udev; pkt_type = hci_skb_pkt_type(skb); - sk_ptr = skb->data; - sk_len = skb->len; - - if (pkt_type == HCI_ACLDATA_PKT) { - sk_ptr += HCI_ACL_HDR_SIZE; - sk_len -= HCI_ACL_HDR_SIZE; - } + skip = sizeof(struct hci_event_hdr); + if (pkt_type == HCI_ACLDATA_PKT) + skip += sizeof(struct hci_acl_hdr); - sk_ptr += HCI_EVENT_HDR_SIZE; - sk_len -= HCI_EVENT_HDR_SIZE; + skb_pull(skb, skip); + dump_hdr = (struct qca_dump_hdr *)skb->data; - dump_hdr = (struct qca_dump_hdr *)sk_ptr; seqno = le16_to_cpu(dump_hdr->seqno); if (seqno == 0) { set_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags); @@ -3056,16 +3017,15 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) btdata->qca_dump.ram_dump_size = dump_size; btdata->qca_dump.ram_dump_seqno = 0; - sk_ptr += offsetof(struct qca_dump_hdr, data0); - sk_len -= offsetof(struct qca_dump_hdr, data0); + + skb_pull(skb, offsetof(struct qca_dump_hdr, data0)); usb_disable_autosuspend(udev); bt_dev_info(hdev, "%s memdump size(%u)\n", (pkt_type == HCI_ACLDATA_PKT) ? "ACL" : "event", dump_size); } else { - sk_ptr += offsetof(struct qca_dump_hdr, data); - sk_len -= offsetof(struct qca_dump_hdr, data); + skb_pull(skb, offsetof(struct qca_dump_hdr, data)); } if (!btdata->qca_dump.ram_dump_size) { @@ -3085,7 +3045,6 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) return ret; } - skb_pull(skb, skb->len - sk_len); hci_devcd_append(hdev, skb); btdata->qca_dump.ram_dump_seqno++; if (seqno == QCA_LAST_SEQUENCE_NUM) { @@ -3113,68 +3072,58 @@ out: /* Return: true if the ACL packet is a dump packet, false otherwise. */ static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb) { - u8 *sk_ptr; - unsigned int sk_len; - struct hci_event_hdr *event_hdr; struct hci_acl_hdr *acl_hdr; struct qca_dump_hdr *dump_hdr; + struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); + bool is_dump = false; - sk_ptr = skb->data; - sk_len = skb->len; - - acl_hdr = hci_acl_hdr(skb); - if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE) + if (!clone) return false; - sk_ptr += HCI_ACL_HDR_SIZE; - sk_len -= HCI_ACL_HDR_SIZE; - event_hdr = (struct hci_event_hdr *)sk_ptr; - - if ((event_hdr->evt != HCI_VENDOR_PKT) || - (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE))) - return false; + acl_hdr = skb_pull_data(clone, sizeof(*acl_hdr)); + if (!acl_hdr || (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE)) + goto out; - sk_ptr += HCI_EVENT_HDR_SIZE; - sk_len -= HCI_EVENT_HDR_SIZE; + event_hdr = skb_pull_data(clone, sizeof(*event_hdr)); + if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT)) + goto out; - dump_hdr = (struct qca_dump_hdr *)sk_ptr; - if ((sk_len < offsetof(struct qca_dump_hdr, data)) || - (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || - (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) - return false; + dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr)); + if (!dump_hdr || (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || + (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) + goto out; - return true; + is_dump = true; +out: + consume_skb(clone); + return is_dump; } /* Return: true if the event packet is a dump packet, false otherwise. */ static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb) { - u8 *sk_ptr; - unsigned int sk_len; - struct hci_event_hdr *event_hdr; struct qca_dump_hdr *dump_hdr; + struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); + bool is_dump = false; - sk_ptr = skb->data; - sk_len = skb->len; - - event_hdr = hci_event_hdr(skb); - - if ((event_hdr->evt != HCI_VENDOR_PKT) - || (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE))) + if (!clone) return false; - sk_ptr += HCI_EVENT_HDR_SIZE; - sk_len -= HCI_EVENT_HDR_SIZE; + event_hdr = skb_pull_data(clone, sizeof(*event_hdr)); + if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT)) + goto out; - dump_hdr = (struct qca_dump_hdr *)sk_ptr; - if ((sk_len < offsetof(struct qca_dump_hdr, data)) || - (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || - (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) - return false; + dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr)); + if (!dump_hdr || (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || + (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) + goto out; - return true; + is_dump = true; +out: + consume_skb(clone); + return is_dump; } static int btusb_recv_acl_qca(struct hci_dev *hdev, struct sk_buff *skb) @@ -3771,31 +3720,133 @@ static const struct file_operations force_poll_sync_fops = { .llseek = default_llseek, }; -static ssize_t isoc_alt_show(struct device *dev, - struct device_attribute *attr, - char *buf) +#define BTUSB_HCI_DRV_OP_SUPPORTED_ALTSETTINGS \ + hci_opcode_pack(HCI_DRV_OGF_DRIVER_SPECIFIC, 0x0000) +#define BTUSB_HCI_DRV_SUPPORTED_ALTSETTINGS_SIZE 0 +struct btusb_hci_drv_rp_supported_altsettings { + __u8 num; + __u8 altsettings[]; +} __packed; + +#define BTUSB_HCI_DRV_OP_SWITCH_ALTSETTING \ + hci_opcode_pack(HCI_DRV_OGF_DRIVER_SPECIFIC, 0x0001) +#define BTUSB_HCI_DRV_SWITCH_ALTSETTING_SIZE 1 +struct btusb_hci_drv_cmd_switch_altsetting { + __u8 altsetting; +} __packed; + +static const struct { + u16 opcode; + const char *desc; +} btusb_hci_drv_supported_commands[] = { + /* Common commands */ + { HCI_DRV_OP_READ_INFO, "Read Info" }, + + /* Driver specific commands */ + { BTUSB_HCI_DRV_OP_SUPPORTED_ALTSETTINGS, "Supported Altsettings" }, + { BTUSB_HCI_DRV_OP_SWITCH_ALTSETTING, "Switch Altsetting" }, +}; +static int btusb_hci_drv_read_info(struct hci_dev *hdev, void *data, + u16 data_len) +{ + struct hci_drv_rp_read_info *rp; + size_t rp_size; + int err, i; + u16 opcode, num_supported_commands = + ARRAY_SIZE(btusb_hci_drv_supported_commands); + + rp_size = sizeof(*rp) + num_supported_commands * 2; + + rp = kmalloc(rp_size, GFP_KERNEL); + if (!rp) + return -ENOMEM; + + strscpy_pad(rp->driver_name, btusb_driver.name); + + rp->num_supported_commands = cpu_to_le16(num_supported_commands); + for (i = 0; i < num_supported_commands; i++) { + opcode = btusb_hci_drv_supported_commands[i].opcode; + bt_dev_info(hdev, + "Supported HCI Drv command (0x%02x|0x%04x): %s", + hci_opcode_ogf(opcode), + hci_opcode_ocf(opcode), + btusb_hci_drv_supported_commands[i].desc); + rp->supported_commands[i] = cpu_to_le16(opcode); + } + + err = hci_drv_cmd_complete(hdev, HCI_DRV_OP_READ_INFO, + HCI_DRV_STATUS_SUCCESS, rp, rp_size); + + kfree(rp); + return err; +} + +static int btusb_hci_drv_supported_altsettings(struct hci_dev *hdev, void *data, + u16 data_len) { - struct btusb_data *data = dev_get_drvdata(dev); + struct btusb_data *drvdata = hci_get_drvdata(hdev); + struct btusb_hci_drv_rp_supported_altsettings *rp; + size_t rp_size; + int err; + u8 i; + + /* There are at most 7 alt (0 - 6) */ + rp = kmalloc(sizeof(*rp) + 7, GFP_KERNEL); + + rp->num = 0; + if (!drvdata->isoc) + goto done; + + for (i = 0; i <= 6; i++) { + if (btusb_find_altsetting(drvdata, i)) + rp->altsettings[rp->num++] = i; + } - return sysfs_emit(buf, "%d\n", data->isoc_altsetting); +done: + rp_size = sizeof(*rp) + rp->num; + + err = hci_drv_cmd_complete(hdev, BTUSB_HCI_DRV_OP_SUPPORTED_ALTSETTINGS, + HCI_DRV_STATUS_SUCCESS, rp, rp_size); + kfree(rp); + return err; } -static ssize_t isoc_alt_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int btusb_hci_drv_switch_altsetting(struct hci_dev *hdev, void *data, + u16 data_len) { - struct btusb_data *data = dev_get_drvdata(dev); - int alt; - int ret; + struct btusb_hci_drv_cmd_switch_altsetting *cmd = data; + u8 status; - if (kstrtoint(buf, 10, &alt)) - return -EINVAL; + if (cmd->altsetting > 6) { + status = HCI_DRV_STATUS_INVALID_PARAMETERS; + } else { + if (btusb_switch_alt_setting(hdev, cmd->altsetting)) + status = HCI_DRV_STATUS_UNSPECIFIED_ERROR; + else + status = HCI_DRV_STATUS_SUCCESS; + } - ret = btusb_switch_alt_setting(data->hdev, alt); - return ret < 0 ? ret : count; + return hci_drv_cmd_status(hdev, BTUSB_HCI_DRV_OP_SWITCH_ALTSETTING, + status); } -static DEVICE_ATTR_RW(isoc_alt); +static const struct hci_drv_handler btusb_hci_drv_common_handlers[] = { + { btusb_hci_drv_read_info, HCI_DRV_READ_INFO_SIZE }, +}; + +static const struct hci_drv_handler btusb_hci_drv_specific_handlers[] = { + { btusb_hci_drv_supported_altsettings, + BTUSB_HCI_DRV_SUPPORTED_ALTSETTINGS_SIZE }, + { btusb_hci_drv_switch_altsetting, + BTUSB_HCI_DRV_SWITCH_ALTSETTING_SIZE }, +}; + +static struct hci_drv btusb_hci_drv = { + .common_handler_count = ARRAY_SIZE(btusb_hci_drv_common_handlers), + .common_handlers = btusb_hci_drv_common_handlers, + .specific_handler_count = ARRAY_SIZE(btusb_hci_drv_specific_handlers), + .specific_handlers = btusb_hci_drv_specific_handlers, +}; static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -3936,12 +3987,13 @@ static int btusb_probe(struct usb_interface *intf, data->reset_gpio = reset_gpio; } - hdev->open = btusb_open; - hdev->close = btusb_close; - hdev->flush = btusb_flush; - hdev->send = btusb_send_frame; - hdev->notify = btusb_notify; - hdev->wakeup = btusb_wakeup; + hdev->open = btusb_open; + hdev->close = btusb_close; + hdev->flush = btusb_flush; + hdev->send = btusb_send_frame; + hdev->notify = btusb_notify; + hdev->wakeup = btusb_wakeup; + hdev->hci_drv = &btusb_hci_drv; #ifdef CONFIG_PM err = btusb_config_oob_wake(hdev); @@ -4160,10 +4212,6 @@ static int btusb_probe(struct usb_interface *intf, data->isoc, data); if (err < 0) goto out_free_dev; - - err = device_create_file(&intf->dev, &dev_attr_isoc_alt); - if (err) - goto out_free_dev; } if (IS_ENABLED(CONFIG_BT_HCIBTUSB_BCM) && data->diag) { @@ -4210,10 +4258,8 @@ static void btusb_disconnect(struct usb_interface *intf) hdev = data->hdev; usb_set_intfdata(data->intf, NULL); - if (data->isoc) { - device_remove_file(&intf->dev, &dev_attr_isoc_alt); + if (data->isoc) usb_set_intfdata(data->isoc, NULL); - } if (data->diag) usb_set_intfdata(data->diag, NULL); diff --git a/drivers/bluetooth/hci_aml.c b/drivers/bluetooth/hci_aml.c index dc9541e76d81..1394c575aa6d 100644 --- a/drivers/bluetooth/hci_aml.c +++ b/drivers/bluetooth/hci_aml.c @@ -313,8 +313,7 @@ static int aml_download_firmware(struct hci_dev *hdev, const char *fw_name) goto exit; exit: - if (firmware) - release_firmware(firmware); + release_firmware(firmware); return ret; } |