diff options
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/btintel.c | 6 | ||||
-rw-r--r-- | drivers/bluetooth/btintel.h | 2 | ||||
-rw-r--r-- | drivers/bluetooth/btintel_pcie.c | 347 | ||||
-rw-r--r-- | drivers/bluetooth/btintel_pcie.h | 4 | ||||
-rw-r--r-- | drivers/bluetooth/btmtkuart.c | 2 | ||||
-rw-r--r-- | drivers/bluetooth/btnxpuart.c | 131 | ||||
-rw-r--r-- | drivers/bluetooth/btrtl.c | 2 | ||||
-rw-r--r-- | drivers/bluetooth/btusb.c | 145 | ||||
-rw-r--r-- | drivers/bluetooth/hci_bcm4377.c | 2 | ||||
-rw-r--r-- | drivers/bluetooth/hci_intel.c | 10 | ||||
-rw-r--r-- | drivers/bluetooth/hci_qca.c | 1 |
11 files changed, 519 insertions, 133 deletions
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 06016ac3965c..be69d21c9aa7 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -555,7 +555,7 @@ int btintel_parse_version_tlv(struct hci_dev *hdev, /* Consume Command Complete Status field */ skb_pull(skb, 1); - /* Event parameters contatin multiple TLVs. Read each of them + /* Event parameters contain multiple TLVs. Read each of them * and only keep the required data. Also, it use existing legacy * version field like hw_platform, hw_variant, and fw_variant * to keep the existing setup flow @@ -889,7 +889,7 @@ int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param) params.boot_param = cpu_to_le32(boot_param); - skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params), ¶ms, + skb = __hci_cmd_sync(hdev, BTINTEL_HCI_OP_RESET, sizeof(params), ¶ms, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "Failed to send Intel Reset command"); @@ -1287,7 +1287,7 @@ static void btintel_reset_to_bootloader(struct hci_dev *hdev) params.boot_option = 0x00; params.boot_param = cpu_to_le32(0x00000000); - skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params), + skb = __hci_cmd_sync(hdev, BTINTEL_HCI_OP_RESET, sizeof(params), ¶ms, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "FW download error recovery failed (%ld)", diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 1d12c4113c66..431998049e68 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -52,6 +52,8 @@ struct intel_tlv { u8 val[]; } __packed; +#define BTINTEL_HCI_OP_RESET 0xfc01 + #define BTINTEL_CNVI_BLAZARI 0x900 #define BTINTEL_CNVI_BLAZARIW 0x901 #define BTINTEL_CNVI_GAP 0x910 diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index f4e3fb54fe76..6e7bbbd35279 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -35,12 +35,20 @@ /* Intel Bluetooth PCIe device id table */ static const struct pci_device_id btintel_pcie_table[] = { + { BTINTEL_PCI_DEVICE(0x4D76, PCI_ANY_ID) }, { BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) }, { BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) }, { 0 } }; MODULE_DEVICE_TABLE(pci, btintel_pcie_table); +struct btintel_pcie_dev_recovery { + struct list_head list; + u8 count; + time64_t last_error; + char name[]; +}; + /* Intel PCIe uses 4 bytes of HCI type instead of 1 byte BT SIG HCI type */ #define BTINTEL_PCIE_HCI_TYPE_LEN 4 #define BTINTEL_PCIE_HCI_CMD_PKT 0x00000001 @@ -62,6 +70,9 @@ MODULE_DEVICE_TABLE(pci, btintel_pcie_table); #define BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER 0x17A2 #define BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT 0x1E61 +#define BTINTEL_PCIE_RESET_WINDOW_SECS 5 +#define BTINTEL_PCIE_FLR_MAX_RETRY 1 + /* Alive interrupt context */ enum { BTINTEL_PCIE_ROM, @@ -99,6 +110,36 @@ 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); + +static inline char *btintel_pcie_alivectxt_state2str(u32 alive_intr_ctxt) +{ + switch (alive_intr_ctxt) { + case BTINTEL_PCIE_ROM: + return "rom"; + case BTINTEL_PCIE_FW_DL: + return "fw_dl"; + case BTINTEL_PCIE_D0: + return "d0"; + case BTINTEL_PCIE_D3: + return "d3"; + case BTINTEL_PCIE_HCI_RESET: + return "hci_reset"; + case BTINTEL_PCIE_INTEL_HCI_RESET1: + return "intel_reset1"; + case BTINTEL_PCIE_INTEL_HCI_RESET2: + return "intel_reset2"; + default: + return "unknown"; + } +} + /* This function initializes the memory for DBGC buffers and formats the * DBGC fragment which consists header info and DBGC buffer's LSB, MSB and * size as the payload @@ -299,10 +340,14 @@ static inline void btintel_pcie_dump_debug_registers(struct hci_dev *hdev) } static int btintel_pcie_send_sync(struct btintel_pcie_data *data, - struct sk_buff *skb) + struct sk_buff *skb, u32 pkt_type, u16 opcode) { int ret; u16 tfd_index; + u32 old_ctxt; + bool wait_on_alive = false; + struct hci_dev *hdev = data->hdev; + struct txq *txq = &data->txq; tfd_index = data->ia.tr_hia[BTINTEL_PCIE_TXQ_NUM]; @@ -310,6 +355,26 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data, if (tfd_index > txq->count) return -ERANGE; + /* Firmware raises alive interrupt on HCI_OP_RESET or + * BTINTEL_HCI_OP_RESET + */ + wait_on_alive = (pkt_type == BTINTEL_PCIE_HCI_CMD_PKT && + (opcode == BTINTEL_HCI_OP_RESET || opcode == HCI_OP_RESET)); + + if (wait_on_alive) { + data->gp0_received = false; + old_ctxt = data->alive_intr_ctxt; + data->alive_intr_ctxt = + (opcode == BTINTEL_HCI_OP_RESET ? BTINTEL_PCIE_INTEL_HCI_RESET1 : + BTINTEL_PCIE_HCI_RESET); + bt_dev_dbg(data->hdev, "sending cmd: 0x%4.4x alive context changed: %s -> %s", + opcode, btintel_pcie_alivectxt_state2str(old_ctxt), + btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); + } + + memcpy(skb_push(skb, BTINTEL_PCIE_HCI_TYPE_LEN), &pkt_type, + BTINTEL_PCIE_HCI_TYPE_LEN); + /* Prepare for TX. It updates the TFD with the length of data and * address of the DMA buffer, and copy the data to the DMA buffer */ @@ -328,11 +393,24 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data, ret = wait_event_timeout(data->tx_wait_q, data->tx_wait_done, msecs_to_jiffies(BTINTEL_PCIE_TX_WAIT_TIMEOUT_MS)); if (!ret) { - bt_dev_err(data->hdev, "tx completion timeout"); + bt_dev_err(data->hdev, "Timeout (%u ms) on tx completion", + BTINTEL_PCIE_TX_WAIT_TIMEOUT_MS); btintel_pcie_dump_debug_registers(data->hdev); return -ETIME; } + if (wait_on_alive) { + ret = wait_event_timeout(data->gp0_wait_q, + data->gp0_received, + msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS)); + if (!ret) { + hdev->stat.err_tx++; + bt_dev_err(hdev, "Timeout (%u ms) on alive interrupt, alive context: %s", + BTINTEL_DEFAULT_INTR_TIMEOUT_MS, + btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); + return -ETIME; + } + } return 0; } @@ -811,28 +889,6 @@ static void btintel_pcie_wr_sleep_cntrl(struct btintel_pcie_data *data, btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG, dxstate); } -static inline char *btintel_pcie_alivectxt_state2str(u32 alive_intr_ctxt) -{ - switch (alive_intr_ctxt) { - case BTINTEL_PCIE_ROM: - return "rom"; - case BTINTEL_PCIE_FW_DL: - return "fw_dl"; - case BTINTEL_PCIE_D0: - return "d0"; - case BTINTEL_PCIE_D3: - return "d3"; - case BTINTEL_PCIE_HCI_RESET: - return "hci_reset"; - case BTINTEL_PCIE_INTEL_HCI_RESET1: - return "intel_reset1"; - case BTINTEL_PCIE_INTEL_HCI_RESET2: - return "intel_reset2"; - default: - return "unknown"; - } -} - static int btintel_pcie_read_device_mem(struct btintel_pcie_data *data, void *buf, u32 dev_addr, int len) { @@ -928,11 +984,13 @@ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data) case BTINTEL_PCIE_INTEL_HCI_RESET1: if (btintel_pcie_in_op(data)) { submit_rx = true; + signal_waitq = true; break; } if (btintel_pcie_in_iml(data)) { submit_rx = true; + signal_waitq = true; data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL; break; } @@ -1930,7 +1988,9 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, __u16 opcode = ~0; int ret; u32 type; - u32 old_ctxt; + + if (test_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags)) + return -ENODEV; /* Due to the fw limitation, the type header of the packet should be * 4 bytes unlike 1 byte for UART. In UART, the firmware can read @@ -1955,17 +2015,14 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, struct hci_command_hdr *cmd = (void *)skb->data; __u16 opcode = le16_to_cpu(cmd->opcode); - /* When the 0xfc01 command is issued to boot into - * the operational firmware, it will actually not - * send a command complete event. To keep the flow + /* When the BTINTEL_HCI_OP_RESET command is issued to + * boot into the operational firmware, it will actually + * not send a command complete event. To keep the flow * control working inject that event here. */ - if (opcode == 0xfc01) + if (opcode == BTINTEL_HCI_OP_RESET) btintel_pcie_inject_cmd_complete(hdev, opcode); } - /* Firmware raises alive interrupt on HCI_OP_RESET */ - if (opcode == HCI_OP_RESET) - data->gp0_received = false; hdev->stat.cmd_tx++; break; @@ -1984,38 +2041,14 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, bt_dev_err(hdev, "Unknown HCI packet type"); return -EILSEQ; } - memcpy(skb_push(skb, BTINTEL_PCIE_HCI_TYPE_LEN), &type, - BTINTEL_PCIE_HCI_TYPE_LEN); - ret = btintel_pcie_send_sync(data, skb); + ret = btintel_pcie_send_sync(data, skb, type, opcode); if (ret) { hdev->stat.err_tx++; bt_dev_err(hdev, "Failed to send frame (%d)", ret); goto exit_error; } - if (type == BTINTEL_PCIE_HCI_CMD_PKT && - (opcode == HCI_OP_RESET || opcode == 0xfc01)) { - old_ctxt = data->alive_intr_ctxt; - data->alive_intr_ctxt = - (opcode == 0xfc01 ? BTINTEL_PCIE_INTEL_HCI_RESET1 : - BTINTEL_PCIE_HCI_RESET); - bt_dev_dbg(data->hdev, "sent cmd: 0x%4.4x alive context changed: %s -> %s", - opcode, btintel_pcie_alivectxt_state2str(old_ctxt), - btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); - if (opcode == HCI_OP_RESET) { - ret = wait_event_timeout(data->gp0_wait_q, - data->gp0_received, - msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS)); - if (!ret) { - hdev->stat.err_tx++; - bt_dev_err(hdev, "No alive interrupt received for %s", - btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); - ret = -ETIME; - goto exit_error; - } - } - } hdev->stat.byte_tx += skb->len; kfree_skb(skb); @@ -2192,9 +2225,191 @@ static int btintel_pcie_setup(struct hci_dev *hdev) } btintel_pcie_start_rx(data); } + + if (!err) + set_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags); return err; } +static struct btintel_pcie_dev_recovery * +btintel_pcie_get_recovery(struct pci_dev *pdev, struct device *dev) +{ + struct btintel_pcie_dev_recovery *tmp, *data = NULL; + const char *name = pci_name(pdev); + struct hci_dev *hdev = to_hci_dev(dev); + + spin_lock(&btintel_pcie_recovery_lock); + list_for_each_entry(tmp, &btintel_pcie_recovery_list, list) { + if (strcmp(tmp->name, name)) + continue; + data = tmp; + break; + } + spin_unlock(&btintel_pcie_recovery_lock); + + if (data) { + bt_dev_dbg(hdev, "Found restart data for BDF: %s", data->name); + return data; + } + + data = kzalloc(struct_size(data, name, strlen(name) + 1), GFP_ATOMIC); + if (!data) + return NULL; + + strscpy_pad(data->name, name, strlen(name) + 1); + spin_lock(&btintel_pcie_recovery_lock); + list_add_tail(&data->list, &btintel_pcie_recovery_list); + spin_unlock(&btintel_pcie_recovery_lock); + + return data; +} + +static void btintel_pcie_free_restart_list(void) +{ + struct btintel_pcie_dev_recovery *tmp; + + while ((tmp = list_first_entry_or_null(&btintel_pcie_recovery_list, + typeof(*tmp), list))) { + list_del(&tmp->list); + kfree(tmp); + } +} + +static void btintel_pcie_inc_recovery_count(struct pci_dev *pdev, + struct device *dev) +{ + struct btintel_pcie_dev_recovery *data; + time64_t retry_window; + + data = btintel_pcie_get_recovery(pdev, dev); + if (!data) + return; + + retry_window = ktime_get_boottime_seconds() - data->last_error; + if (data->count == 0) { + data->last_error = ktime_get_boottime_seconds(); + data->count++; + } else if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS && + data->count <= BTINTEL_PCIE_FLR_MAX_RETRY) { + data->count++; + } else if (retry_window > BTINTEL_PCIE_RESET_WINDOW_SECS) { + data->last_error = 0; + data->count = 0; + } +} + +static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data); + +static void btintel_pcie_removal_work(struct work_struct *wk) +{ + struct btintel_pcie_removal *removal = + container_of(wk, struct btintel_pcie_removal, work); + struct pci_dev *pdev = removal->pdev; + struct btintel_pcie_data *data; + int err; + + pci_lock_rescan_remove(); + + if (!pdev->bus) + goto error; + + data = pci_get_drvdata(pdev); + + btintel_pcie_disable_interrupts(data); + btintel_pcie_synchronize_irqs(data); + + flush_work(&data->rx_work); + flush_work(&data->hdev->dump.dump_rx); + + bt_dev_dbg(data->hdev, "Release bluetooth interface"); + btintel_pcie_release_hdev(data); + + err = pci_reset_function(pdev); + if (err) { + BT_ERR("Failed resetting the pcie device (%d)", err); + goto error; + } + + btintel_pcie_enable_interrupts(data); + btintel_pcie_config_msix(data); + + err = btintel_pcie_enable_bt(data); + if (err) { + BT_ERR("Failed to enable bluetooth hardware after reset (%d)", + err); + goto error; + } + + btintel_pcie_reset_ia(data); + btintel_pcie_start_rx(data); + data->flags = 0; + + err = btintel_pcie_setup_hdev(data); + if (err) { + BT_ERR("Failed registering hdev (%d)", err); + goto error; + } +error: + pci_dev_put(pdev); + pci_unlock_rescan_remove(); + kfree(removal); +} + +static void btintel_pcie_reset(struct hci_dev *hdev) +{ + struct btintel_pcie_removal *removal; + struct btintel_pcie_data *data; + + data = hci_get_drvdata(hdev); + + if (!test_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags)) + return; + + if (test_and_set_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags)) + return; + + removal = kzalloc(sizeof(*removal), GFP_ATOMIC); + if (!removal) + return; + + removal->pdev = data->pdev; + INIT_WORK(&removal->work, btintel_pcie_removal_work); + pci_dev_get(removal->pdev); + schedule_work(&removal->work); +} + +static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code) +{ + struct btintel_pcie_dev_recovery *data; + struct btintel_pcie_data *dev_data = hci_get_drvdata(hdev); + struct pci_dev *pdev = dev_data->pdev; + time64_t retry_window; + + if (code == 0x13) { + bt_dev_err(hdev, "Encountered top exception"); + return; + } + + data = btintel_pcie_get_recovery(pdev, &hdev->dev); + if (!data) + return; + + retry_window = ktime_get_boottime_seconds() - data->last_error; + + if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS && + data->count >= BTINTEL_PCIE_FLR_MAX_RETRY) { + bt_dev_err(hdev, "Exhausted maximum: %d recovery attempts: %d", + BTINTEL_PCIE_FLR_MAX_RETRY, data->count); + bt_dev_dbg(hdev, "Boot time: %lld seconds", + ktime_get_boottime_seconds()); + bt_dev_dbg(hdev, "last error at: %lld seconds", + data->last_error); + return; + } + btintel_pcie_inc_recovery_count(pdev, &hdev->dev); + btintel_pcie_reset(hdev); +} + static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) { int err; @@ -2216,9 +2431,10 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) hdev->send = btintel_pcie_send_frame; hdev->setup = btintel_pcie_setup; hdev->shutdown = btintel_shutdown_combined; - hdev->hw_error = btintel_hw_error; + hdev->hw_error = btintel_pcie_hw_error; hdev->set_diag = btintel_set_diag; hdev->set_bdaddr = btintel_set_bdaddr; + hdev->reset = btintel_pcie_reset; err = hci_register_dev(hdev); if (err < 0) { @@ -2366,7 +2582,20 @@ static struct pci_driver btintel_pcie_driver = { .driver.coredump = btintel_pcie_coredump #endif }; -module_pci_driver(btintel_pcie_driver); + +static int __init btintel_pcie_init(void) +{ + return pci_register_driver(&btintel_pcie_driver); +} + +static void __exit btintel_pcie_exit(void) +{ + pci_unregister_driver(&btintel_pcie_driver); + btintel_pcie_free_restart_list(); +} + +module_init(btintel_pcie_init); +module_exit(btintel_pcie_exit); MODULE_AUTHOR("Tedd Ho-Jeong An <tedd.an@intel.com>"); MODULE_DESCRIPTION("Intel Bluetooth PCIe transport driver ver " VERSION); diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index 7dad4523236c..0fa876c5b954 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -117,7 +117,9 @@ enum { enum { BTINTEL_PCIE_CORE_HALTED, BTINTEL_PCIE_HWEXP_INPROGRESS, - BTINTEL_PCIE_COREDUMP_INPROGRESS + BTINTEL_PCIE_COREDUMP_INPROGRESS, + BTINTEL_PCIE_RECOVERY_IN_PROGRESS, + BTINTEL_PCIE_SETUP_DONE }; enum btintel_pcie_tlv_type { diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index 51400a891f6e..76995cfcd534 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -316,7 +316,7 @@ mtk_stp_split(struct btmtkuart_dev *bdev, const unsigned char *data, int count, /* Resync STP when unexpected data is being read */ if (shdr->prefix != 0x80 || bdev->stp_dlen > 2048) { - bt_dev_err(bdev->hdev, "stp format unexpect (%d, %d)", + bt_dev_err(bdev->hdev, "stp format unexpected (%d, %d)", shdr->prefix, bdev->stp_dlen); bdev->stp_cursor = 2; bdev->stp_dlen = 0; diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 24f9b52605a1..73a4a325c867 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -18,6 +18,8 @@ #include <linux/string_helpers.h> #include <linux/gpio/consumer.h> #include <linux/of_irq.h> +#include <linux/regulator/consumer.h> +#include <linux/reset.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -73,7 +75,8 @@ #define FW_AUTH_ENC 0xc0 #define HCI_NXP_PRI_BAUDRATE 115200 -#define HCI_NXP_SEC_BAUDRATE 3000000 +#define HCI_NXP_SEC_BAUDRATE_3M 3000000 +#define HCI_NXP_SEC_BAUDRATE_4M 4000000 #define MAX_FW_FILE_NAME_LEN 50 @@ -201,12 +204,14 @@ struct btnxpuart_dev { u32 new_baudrate; u32 current_baudrate; u32 fw_init_baudrate; + u32 secondary_baudrate; enum bootloader_param_change timeout_changed; enum bootloader_param_change baudrate_changed; bool helper_downloaded; struct ps_data psdata; struct btnxpuart_data *nxp_data; + struct reset_control *pdn; }; #define NXP_V1_FW_REQ_PKT 0xa5 @@ -365,17 +370,26 @@ static u8 crc8_table[CRC8_TABLE_SIZE]; static struct sk_buff *nxp_drv_send_cmd(struct hci_dev *hdev, u16 opcode, u32 plen, - void *param) + void *param, + bool resp) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); struct ps_data *psdata = &nxpdev->psdata; - struct sk_buff *skb; + struct sk_buff *skb = NULL; /* set flag to prevent nxp_enqueue from parsing values from this command and * calling hci_cmd_sync_queue() again. */ psdata->driver_sent_cmd = true; - skb = __hci_cmd_sync(hdev, opcode, plen, param, HCI_CMD_TIMEOUT); + if (resp) { + skb = __hci_cmd_sync(hdev, opcode, plen, param, HCI_CMD_TIMEOUT); + } else { + __hci_cmd_send(hdev, opcode, plen, param); + /* Allow command to be sent before tx_work is cancelled + * by btnxpuart_flush() + */ + msleep(20); + } psdata->driver_sent_cmd = false; return skb; @@ -595,7 +609,8 @@ static int send_ps_cmd(struct hci_dev *hdev, void *data) pcmd.ps_cmd = BT_PS_DISABLE; pcmd.c2h_ps_interval = __cpu_to_le16(psdata->c2h_ps_interval); - skb = nxp_drv_send_cmd(hdev, HCI_NXP_AUTO_SLEEP_MODE, sizeof(pcmd), &pcmd); + skb = nxp_drv_send_cmd(hdev, HCI_NXP_AUTO_SLEEP_MODE, sizeof(pcmd), + &pcmd, true); if (IS_ERR(skb)) { bt_dev_err(hdev, "Setting Power Save mode failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); @@ -644,7 +659,8 @@ static int send_wakeup_method_cmd(struct hci_dev *hdev, void *data) break; } - skb = nxp_drv_send_cmd(hdev, HCI_NXP_WAKEUP_METHOD, sizeof(pcmd), &pcmd); + skb = nxp_drv_send_cmd(hdev, HCI_NXP_WAKEUP_METHOD, sizeof(pcmd), + &pcmd, true); if (IS_ERR(skb)) { bt_dev_err(hdev, "Setting wake-up method failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); @@ -802,7 +818,10 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len) nxpdev->fw_v3_offset_correction += req_len; } else if (req_len == sizeof(uart_config)) { uart_config.clkdiv.address = __cpu_to_le32(clkdivaddr); - uart_config.clkdiv.value = __cpu_to_le32(0x00c00000); + if (nxpdev->new_baudrate == HCI_NXP_SEC_BAUDRATE_4M) + uart_config.clkdiv.value = __cpu_to_le32(0x01000000); + else + uart_config.clkdiv.value = __cpu_to_le32(0x00c00000); uart_config.uartdiv.address = __cpu_to_le32(uartdivaddr); uart_config.uartdiv.value = __cpu_to_le32(1); uart_config.mcr.address = __cpu_to_le32(uartmcraddr); @@ -966,12 +985,13 @@ static int nxp_recv_fw_req_v1(struct hci_dev *hdev, struct sk_buff *skb) goto free_skb; } if (nxpdev->baudrate_changed != changed) { + nxpdev->new_baudrate = nxpdev->secondary_baudrate; if (nxp_fw_change_baudrate(hdev, len)) { nxpdev->baudrate_changed = changed; serdev_device_set_baudrate(nxpdev->serdev, - HCI_NXP_SEC_BAUDRATE); + nxpdev->secondary_baudrate); serdev_device_set_flow_control(nxpdev->serdev, true); - nxpdev->current_baudrate = HCI_NXP_SEC_BAUDRATE; + nxpdev->current_baudrate = nxpdev->secondary_baudrate; } goto free_skb; } @@ -992,7 +1012,7 @@ static int nxp_recv_fw_req_v1(struct hci_dev *hdev, struct sk_buff *skb) nxpdev->helper_downloaded = true; serdev_device_wait_until_sent(nxpdev->serdev, 0); serdev_device_set_baudrate(nxpdev->serdev, - HCI_NXP_SEC_BAUDRATE); + HCI_NXP_SEC_BAUDRATE_3M); serdev_device_set_flow_control(nxpdev->serdev, true); } else { clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); @@ -1216,12 +1236,13 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb) } if (nxpdev->baudrate_changed != changed) { + nxpdev->new_baudrate = nxpdev->secondary_baudrate; if (nxp_fw_change_baudrate(hdev, len)) { nxpdev->baudrate_changed = cmd_sent; serdev_device_set_baudrate(nxpdev->serdev, - HCI_NXP_SEC_BAUDRATE); + nxpdev->secondary_baudrate); serdev_device_set_flow_control(nxpdev->serdev, true); - nxpdev->current_baudrate = HCI_NXP_SEC_BAUDRATE; + nxpdev->current_baudrate = nxpdev->secondary_baudrate; } goto free_skb; } @@ -1265,7 +1286,8 @@ static int nxp_set_baudrate_cmd(struct hci_dev *hdev, void *data) if (!psdata) return 0; - skb = nxp_drv_send_cmd(hdev, HCI_NXP_SET_OPER_SPEED, 4, (u8 *)&new_baudrate); + skb = nxp_drv_send_cmd(hdev, HCI_NXP_SET_OPER_SPEED, 4, + (u8 *)&new_baudrate, true); if (IS_ERR(skb)) { bt_dev_err(hdev, "Setting baudrate failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); @@ -1323,7 +1345,7 @@ static void nxp_coredump(struct hci_dev *hdev) struct sk_buff *skb; u8 pcmd = 2; - skb = nxp_drv_send_cmd(hdev, HCI_NXP_TRIGGER_DUMP, 1, &pcmd); + skb = nxp_drv_send_cmd(hdev, HCI_NXP_TRIGGER_DUMP, 1, &pcmd, true); if (IS_ERR(skb)) bt_dev_err(hdev, "Failed to trigger FW Dump. (%ld)", PTR_ERR(skb)); else @@ -1365,7 +1387,6 @@ static int nxp_process_fw_dump(struct hci_dev *hdev, struct sk_buff *skb) if (buf_len == 0) { bt_dev_warn(hdev, "==== FW dump complete ==="); - clear_bit(BTNXPUART_FW_DUMP_IN_PROGRESS, &nxpdev->tx_state); hci_devcd_complete(hdev); nxp_set_ind_reset(hdev, NULL); } @@ -1419,6 +1440,10 @@ static int nxp_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) static int nxp_setup(struct hci_dev *hdev) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); + struct serdev_device *serdev = nxpdev->serdev; + char device_string[30]; + char event_string[50]; + char *envp[] = {device_string, event_string, NULL}; int err = 0; if (nxp_check_boot_sign(nxpdev)) { @@ -1431,6 +1456,12 @@ static int nxp_setup(struct hci_dev *hdev) clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); } + snprintf(device_string, 30, "BTNXPUART_DEV=%s", dev_name(&serdev->dev)); + snprintf(event_string, 50, "BTNXPUART_STATE=FW_READY"); + bt_dev_dbg(hdev, "==== Send uevent: %s:%s ===", device_string, + event_string); + kobject_uevent_env(&serdev->dev.kobj, KOBJ_CHANGE, envp); + serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate); nxpdev->current_baudrate = nxpdev->fw_init_baudrate; @@ -1447,8 +1478,8 @@ static int nxp_post_init(struct hci_dev *hdev) struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); struct ps_data *psdata = &nxpdev->psdata; - if (nxpdev->current_baudrate != HCI_NXP_SEC_BAUDRATE) { - nxpdev->new_baudrate = HCI_NXP_SEC_BAUDRATE; + if (nxpdev->current_baudrate != nxpdev->secondary_baudrate) { + nxpdev->new_baudrate = nxpdev->secondary_baudrate; nxp_set_baudrate_cmd(hdev, NULL); } if (psdata->cur_h2c_wakeupmode != psdata->h2c_wakeupmode) @@ -1479,7 +1510,13 @@ static int nxp_shutdown(struct hci_dev *hdev) u8 pcmd = 0; if (ind_reset_in_progress(nxpdev)) { - skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd); + if (test_and_clear_bit(BTNXPUART_FW_DUMP_IN_PROGRESS, + &nxpdev->tx_state)) + skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, + &pcmd, false); + else + skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, + &pcmd, true); serdev_device_set_flow_control(nxpdev->serdev, false); set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); /* HCI_NXP_IND_RESET command may not returns any response */ @@ -1745,11 +1782,41 @@ static const struct serdev_device_ops btnxpuart_client_ops = { .write_wakeup = btnxpuart_write_wakeup, }; +static void nxp_coredump_notify(struct hci_dev *hdev, int state) +{ + struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); + struct serdev_device *serdev = nxpdev->serdev; + char device_string[30]; + char event_string[50]; + char *envp[] = {device_string, event_string, NULL}; + + snprintf(device_string, 30, "BTNXPUART_DEV=%s", dev_name(&serdev->dev)); + switch (state) { + case HCI_DEVCOREDUMP_ACTIVE: + snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_ACTIVE"); + break; + case HCI_DEVCOREDUMP_DONE: + snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_DONE"); + break; + case HCI_DEVCOREDUMP_TIMEOUT: + snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_TIMEOUT"); + break; + default: + snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_STATE_%d", + state); + break; + } + bt_dev_dbg(hdev, "==== Send uevent: %s:%s ===", device_string, + event_string); + kobject_uevent_env(&serdev->dev.kobj, KOBJ_CHANGE, envp); +} + static int nxp_serdev_probe(struct serdev_device *serdev) { struct hci_dev *hdev; struct btnxpuart_dev *nxpdev; bdaddr_t ba = {0}; + int err; nxpdev = devm_kzalloc(&serdev->dev, sizeof(*nxpdev), GFP_KERNEL); if (!nxpdev) @@ -1773,10 +1840,31 @@ static int nxp_serdev_probe(struct serdev_device *serdev) if (!nxpdev->fw_init_baudrate) nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE; + device_property_read_u32(&nxpdev->serdev->dev, "max-speed", + &nxpdev->secondary_baudrate); + if (!nxpdev->secondary_baudrate || + (nxpdev->secondary_baudrate != HCI_NXP_SEC_BAUDRATE_3M && + nxpdev->secondary_baudrate != HCI_NXP_SEC_BAUDRATE_4M)) { + if (nxpdev->secondary_baudrate) + dev_err(&serdev->dev, + "Invalid max-speed. Using default 3000000."); + nxpdev->secondary_baudrate = HCI_NXP_SEC_BAUDRATE_3M; + } + set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); crc8_populate_msb(crc8_table, POLYNOMIAL8); + nxpdev->pdn = devm_reset_control_get_optional_shared(&serdev->dev, NULL); + if (IS_ERR(nxpdev->pdn)) + return PTR_ERR(nxpdev->pdn); + + err = devm_regulator_get_enable(&serdev->dev, "vcc"); + if (err) { + dev_err(&serdev->dev, "Failed to enable vcc regulator\n"); + return err; + } + /* Initialize and register HCI device */ hdev = hci_alloc_dev(); if (!hdev) { @@ -1784,6 +1872,8 @@ static int nxp_serdev_probe(struct serdev_device *serdev) return -ENOMEM; } + reset_control_deassert(nxpdev->pdn); + nxpdev->hdev = hdev; hdev->bus = HCI_UART; @@ -1817,11 +1907,13 @@ static int nxp_serdev_probe(struct serdev_device *serdev) if (ps_setup(hdev)) goto probe_fail; - hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr, NULL); + hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr, + nxp_coredump_notify); return 0; probe_fail: + reset_control_assert(nxpdev->pdn); hci_free_dev(hdev); return -ENODEV; } @@ -1849,6 +1941,7 @@ static void nxp_serdev_remove(struct serdev_device *serdev) ps_cleanup(nxpdev); hci_unregister_dev(hdev); + reset_control_assert(nxpdev->pdn); hci_free_dev(hdev); } diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index 4d182cf6e037..6abd962502e3 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -693,7 +693,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, /* Loop from the end of the firmware parsing instructions, until * we find an instruction that identifies the "project ID" for the - * hardware supported by this firwmare file. + * hardware supported by this firmware file. * Once we have that, we double-check that project_id is suitable * for the hardware we are working with. */ diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index f9eeec0aed57..8085fabadde8 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -298,75 +298,77 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, /* QCA WCN6855 chipset */ - { USB_DEVICE(0x0cf3, 0xe600), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0c7), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0cc), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0c9), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0d6), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0ca), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0e3), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0cb), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9309), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0cc), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9409), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0ce), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe0d0), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9108), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0d6), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9109), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0de), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9208), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0df), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9209), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0e1), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9308), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0e3), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9408), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0ea), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9508), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0489, 0xe0ec), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9509), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x04ca, 0x3022), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9608), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x04ca, 0x3023), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9609), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x04ca, 0x3024), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x10ab, 0x9f09), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x04ca, 0x3a22), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x04ca, 0x3022), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x04ca, 0x3a24), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0c7), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x04ca, 0x3a26), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0c9), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x04ca, 0x3a27), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0ca), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x0cf3, 0xe600), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0cb), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9108), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0ce), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9109), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0de), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9208), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0df), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9209), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0e1), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9308), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0ea), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9309), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x0489, 0xe0ec), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9408), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x04ca, 0x3023), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9409), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x04ca, 0x3024), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9508), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x04ca, 0x3a22), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9509), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x04ca, 0x3a24), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9608), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x04ca, 0x3a26), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9609), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x04ca, 0x3a27), .driver_info = BTUSB_QCA_WCN6855 | + { USB_DEVICE(0x10ab, 0x9f09), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x28de, 0x1401), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, /* QCA WCN785x chipset */ @@ -515,6 +517,11 @@ static const struct usb_device_id quirks_table[] = { /* Realtek 8851BE Bluetooth devices */ { USB_DEVICE(0x0bda, 0xb850), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3600), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3601), .driver_info = BTUSB_REALTEK }, + + /* Realtek 8851BU Bluetooth devices */ + { USB_DEVICE(0x3625, 0x010b), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, /* Realtek 8852AE Bluetooth devices */ { USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK | @@ -565,6 +572,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3591), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3618), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe123), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe125), .driver_info = BTUSB_REALTEK | @@ -705,6 +714,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe139), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe14e), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe14f), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe150), .driver_info = BTUSB_MEDIATEK | @@ -725,6 +736,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3630), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x2c7c, 0x7009), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, /* Additional Realtek 8723AE Bluetooth devices */ { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK }, @@ -2594,12 +2607,12 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) else urb = alloc_ctrl_urb(hdev, skb); - /* When the 0xfc01 command is issued to boot into - * the operational firmware, it will actually not - * send a command complete event. To keep the flow + /* When the BTINTEL_HCI_OP_RESET command is issued to + * boot into the operational firmware, it will actually + * not send a command complete event. To keep the flow * control working inject that event here. */ - if (opcode == 0xfc01) + if (opcode == BTINTEL_HCI_OP_RESET) inject_cmd_complete(hdev, opcode); } else { urb = alloc_ctrl_urb(hdev, skb); @@ -3179,6 +3192,12 @@ struct qca_device_info { u8 ver_offset; /* offset of version structure in rampatch */ }; +struct qca_custom_firmware { + u32 rom_version; + u16 board_id; + const char *subdirectory; +}; + static const struct qca_device_info qca_devices_table[] = { { 0x00000100, 20, 4, 8 }, /* Rome 1.0 */ { 0x00000101, 20, 4, 8 }, /* Rome 1.1 */ @@ -3192,6 +3211,11 @@ static const struct qca_device_info qca_devices_table[] = { { 0x00190200, 40, 4, 16 }, /* WCN785x 2.0 */ }; +static const struct qca_custom_firmware qca_custom_btfws[] = { + { 0x00130201, 0x030A, "QCA2066" }, + { }, +}; + static u16 qca_extract_board_id(const struct qca_version *ver) { u16 flag = le16_to_cpu(ver->flag); @@ -3218,6 +3242,26 @@ static u16 qca_extract_board_id(const struct qca_version *ver) return board_id; } +static const char *qca_get_fw_subdirectory(const struct qca_version *ver) +{ + const struct qca_custom_firmware *ptr; + u32 rom_ver; + u16 board_id; + + rom_ver = le32_to_cpu(ver->rom_version); + board_id = qca_extract_board_id(ver); + if (!board_id) + return NULL; + + for (ptr = qca_custom_btfws; ptr->rom_version; ptr++) { + if (ptr->rom_version == rom_ver && + ptr->board_id == board_id) + return ptr->subdirectory; + } + + return NULL; +} + static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request, void *data, u16 size) { @@ -3322,15 +3366,22 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev, { struct qca_rampatch_version *rver; const struct firmware *fw; + const char *fw_subdir; u32 ver_rom, ver_patch, rver_rom; u16 rver_rom_low, rver_rom_high, rver_patch; - char fwname[64]; + char fwname[80]; int err; ver_rom = le32_to_cpu(ver->rom_version); ver_patch = le32_to_cpu(ver->patch_version); - snprintf(fwname, sizeof(fwname), "qca/rampatch_usb_%08x.bin", ver_rom); + fw_subdir = qca_get_fw_subdirectory(ver); + if (fw_subdir) + snprintf(fwname, sizeof(fwname), "qca/%s/rampatch_usb_%08x.bin", + fw_subdir, ver_rom); + else + snprintf(fwname, sizeof(fwname), "qca/rampatch_usb_%08x.bin", + ver_rom); err = request_firmware(&fw, fwname, &hdev->dev); if (err) { @@ -3374,10 +3425,11 @@ static void btusb_generate_qca_nvm_name(char *fwname, size_t max_size, const struct qca_version *ver) { u32 rom_version = le32_to_cpu(ver->rom_version); - const char *variant; + const char *variant, *fw_subdir; int len; u16 board_id; + fw_subdir = qca_get_fw_subdirectory(ver); board_id = qca_extract_board_id(ver); switch (le32_to_cpu(ver->ram_version)) { @@ -3390,7 +3442,12 @@ static void btusb_generate_qca_nvm_name(char *fwname, size_t max_size, break; } - len = snprintf(fwname, max_size, "qca/nvm_usb_%08x", rom_version); + if (fw_subdir) + len = snprintf(fwname, max_size, "qca/%s/nvm_usb_%08x", + fw_subdir, rom_version); + else + len = snprintf(fwname, max_size, "qca/nvm_usb_%08x", + rom_version); if (variant) len += snprintf(fwname + len, max_size - len, "%s", variant); if (board_id) @@ -3403,7 +3460,7 @@ static int btusb_setup_qca_load_nvm(struct hci_dev *hdev, const struct qca_device_info *info) { const struct firmware *fw; - char fwname[64]; + char fwname[80]; int err; btusb_generate_qca_nvm_name(fwname, sizeof(fwname), ver); @@ -3802,6 +3859,8 @@ static int btusb_hci_drv_supported_altsettings(struct hci_dev *hdev, void *data, /* There are at most 7 alt (0 - 6) */ rp = kmalloc(sizeof(*rp) + 7, GFP_KERNEL); + if (!rp) + return -ENOMEM; rp->num = 0; if (!drvdata->isoc) diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c index 8a9aa33776b0..45e6d84224ee 100644 --- a/drivers/bluetooth/hci_bcm4377.c +++ b/drivers/bluetooth/hci_bcm4377.c @@ -420,7 +420,7 @@ struct bcm4377_ring_state { * payloads_dma:DMA address for payload buffer * events: pointer to array of completions if waiting is allowed * msgids: bitmap to keep track of used message ids - * lock: Spinlock to protect access to ring structurs used in the irq handler + * lock: Spinlock to protect access to ring structures used in the irq handler */ struct bcm4377_transfer_ring { enum bcm4377_transfer_ring_id ring_id; diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index d22fbb7f9fc5..9b353c3d6442 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -1029,12 +1029,12 @@ static struct sk_buff *intel_dequeue(struct hci_uart *hu) struct hci_command_hdr *cmd = (void *)skb->data; __u16 opcode = le16_to_cpu(cmd->opcode); - /* When the 0xfc01 command is issued to boot into - * the operational firmware, it will actually not - * send a command complete event. To keep the flow - * control working inject that event here. + /* When the BTINTEL_HCI_OP_RESET command is issued to boot into + * the operational firmware, it will actually not send a command + * complete event. To keep the flow control working inject that + * event here. */ - if (opcode == 0xfc01) + if (opcode == BTINTEL_HCI_OP_RESET) inject_cmd_complete(hu->hdev, opcode); } diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 33c43503714b..4cff4d9be313 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1264,6 +1264,7 @@ static const struct h4_recv_pkt qca_recv_pkts[] = { { H4_RECV_ACL, .recv = qca_recv_acl_data }, { H4_RECV_SCO, .recv = hci_recv_frame }, { H4_RECV_EVENT, .recv = qca_recv_event }, + { H4_RECV_ISO, .recv = hci_recv_frame }, { QCA_IBS_WAKE_IND_EVENT, .recv = qca_ibs_wake_ind }, { QCA_IBS_WAKE_ACK_EVENT, .recv = qca_ibs_wake_ack }, { QCA_IBS_SLEEP_IND_EVENT, .recv = qca_ibs_sleep_ind }, |