diff options
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/Kconfig | 12 | ||||
-rw-r--r-- | drivers/bluetooth/bfusb.c | 3 | ||||
-rw-r--r-- | drivers/bluetooth/bluecard_cs.c | 4 | ||||
-rw-r--r-- | drivers/bluetooth/btintel.c | 341 | ||||
-rw-r--r-- | drivers/bluetooth/btintel.h | 24 | ||||
-rw-r--r-- | drivers/bluetooth/btintel_pcie.c | 582 | ||||
-rw-r--r-- | drivers/bluetooth/btintel_pcie.h | 93 | ||||
-rw-r--r-- | drivers/bluetooth/btmtk.c | 10 | ||||
-rw-r--r-- | drivers/bluetooth/btmtksdio.c | 3 | ||||
-rw-r--r-- | drivers/bluetooth/btnxpuart.c | 392 | ||||
-rw-r--r-- | drivers/bluetooth/btqca.c | 27 | ||||
-rw-r--r-- | drivers/bluetooth/btqca.h | 4 | ||||
-rw-r--r-- | drivers/bluetooth/btrtl.c | 2 | ||||
-rw-r--r-- | drivers/bluetooth/btusb.c | 77 | ||||
-rw-r--r-- | drivers/bluetooth/hci_bcsp.c | 2 | ||||
-rw-r--r-- | drivers/bluetooth/hci_h5.c | 6 | ||||
-rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 19 | ||||
-rw-r--r-- | drivers/bluetooth/hci_qca.c | 37 | ||||
-rw-r--r-- | drivers/bluetooth/hci_uart.h | 1 | ||||
-rw-r--r-- | drivers/bluetooth/hci_vhci.c | 15 |
20 files changed, 1518 insertions, 136 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 4ab32abf0f48..7771edf54fb3 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -56,6 +56,18 @@ 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/bfusb.c b/drivers/bluetooth/bfusb.c index cab93935cc7f..0d6ad50da046 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -365,9 +365,8 @@ static void bfusb_rx_complete(struct urb *urb) buf += 3; } - if (count < len) { + if (count < len) bt_dev_err(data->hdev, "block extends over URB buffer ranges"); - } if ((hdr & 0xe1) == 0xc1) bfusb_recv_block(data, hdr, buf, len); diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 36eabf61717f..1c7f89e134b3 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -638,7 +638,7 @@ static int bluecard_hci_close(struct hci_dev *hdev) bluecard_hci_flush(hdev); /* Stop LED timer */ - del_timer_sync(&(info->timer)); + timer_delete_sync(&(info->timer)); /* Disable power LED */ outb(0x00, iobase + 0x30); @@ -885,7 +885,7 @@ static void bluecard_release(struct pcmcia_device *link) bluecard_close(info); - del_timer_sync(&(info->timer)); + timer_delete_sync(&(info->timer)); pcmcia_disable_device(link); } diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index d2540b28bc7a..48e2f400957b 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -35,6 +35,11 @@ enum { DSM_SET_RESET_METHOD = 3, }; +#define BTINTEL_BT_DOMAIN 0x12 +#define BTINTEL_SAR_LEGACY 0 +#define BTINTEL_SAR_INC_PWR 1 +#define BTINTEL_SAR_INC_PWR_SUPPORTED 0 + #define CMD_WRITE_BOOT_PARAMS 0xfc0e struct cmd_write_boot_params { __le32 boot_addr; @@ -478,6 +483,7 @@ int btintel_version_info_tlv(struct hci_dev *hdev, case 0x1c: /* Gale Peak (GaP) */ case 0x1d: /* BlazarU (BzrU) */ case 0x1e: /* BlazarI (Bzr) */ + case 0x1f: /* Scorpious Peak */ break; default: bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)", @@ -2756,6 +2762,7 @@ static int btintel_set_dsbr(struct hci_dev *hdev, struct intel_version_tlv *ver) /* DSBR command needs to be sent for, * 1. BlazarI or BlazarIW + B0 step product in IML image. * 2. Gale Peak2 or BlazarU in OP image. + * 3. Scorpious Peak in IML image. */ switch (cnvi) { @@ -2771,6 +2778,10 @@ static int btintel_set_dsbr(struct hci_dev *hdev, struct intel_version_tlv *ver) hdev->bus == HCI_USB) break; return 0; + case BTINTEL_CNVI_SCP: + if (ver->img_type == BTINTEL_IMG_IML) + break; + return 0; default: return 0; } @@ -2800,6 +2811,331 @@ static int btintel_set_dsbr(struct hci_dev *hdev, struct intel_version_tlv *ver) return 0; } +#ifdef CONFIG_ACPI +static acpi_status btintel_evaluate_acpi_method(struct hci_dev *hdev, + acpi_string method, + union acpi_object **ptr, + u8 pkg_size) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *p; + acpi_status status; + acpi_handle handle; + + handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev)); + if (!handle) { + bt_dev_dbg(hdev, "ACPI-BT: No ACPI support for Bluetooth device"); + return AE_NOT_EXIST; + } + + status = acpi_evaluate_object(handle, method, NULL, &buffer); + + if (ACPI_FAILURE(status)) { + bt_dev_dbg(hdev, "ACPI-BT: ACPI Failure: %s method: %s", + acpi_format_exception(status), method); + return status; + } + + p = buffer.pointer; + + if (p->type != ACPI_TYPE_PACKAGE || p->package.count < pkg_size) { + bt_dev_warn(hdev, "ACPI-BT: Invalid object type: %d or package count: %d", + p->type, p->package.count); + kfree(buffer.pointer); + return AE_ERROR; + } + + *ptr = buffer.pointer; + return 0; +} + +static union acpi_object *btintel_acpi_get_bt_pkg(union acpi_object *buffer) +{ + union acpi_object *domain, *bt_pkg; + int i; + + for (i = 1; i < buffer->package.count; i++) { + bt_pkg = &buffer->package.elements[i]; + domain = &bt_pkg->package.elements[0]; + if (domain->type == ACPI_TYPE_INTEGER && + domain->integer.value == BTINTEL_BT_DOMAIN) + return bt_pkg; + } + return ERR_PTR(-ENOENT); +} + +static int btintel_send_sar_ddc(struct hci_dev *hdev, struct btintel_cp_ddc_write *data, u8 len) +{ + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, 0xfc8b, len, data, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_warn(hdev, "Failed to send sar ddc id:0x%4.4x (%ld)", + le16_to_cpu(data->id), PTR_ERR(skb)); + return PTR_ERR(skb); + } + kfree_skb(skb); + return 0; +} + +static int btintel_send_edr(struct hci_dev *hdev, struct btintel_cp_ddc_write *cmd, + int id, struct btintel_sar_inc_pwr *sar) +{ + cmd->len = 5; + cmd->id = cpu_to_le16(id); + cmd->data[0] = sar->br >> 3; + cmd->data[1] = sar->edr2 >> 3; + cmd->data[2] = sar->edr3 >> 3; + return btintel_send_sar_ddc(hdev, cmd, 6); +} + +static int btintel_send_le(struct hci_dev *hdev, struct btintel_cp_ddc_write *cmd, + int id, struct btintel_sar_inc_pwr *sar) +{ + cmd->len = 3; + cmd->id = cpu_to_le16(id); + cmd->data[0] = min3(sar->le, sar->le_lr, sar->le_2mhz) >> 3; + return btintel_send_sar_ddc(hdev, cmd, 4); +} + +static int btintel_send_br(struct hci_dev *hdev, struct btintel_cp_ddc_write *cmd, + int id, struct btintel_sar_inc_pwr *sar) +{ + cmd->len = 3; + cmd->id = cpu_to_le16(id); + cmd->data[0] = sar->br >> 3; + return btintel_send_sar_ddc(hdev, cmd, 4); +} + +static int btintel_send_br_mutual(struct hci_dev *hdev, struct btintel_cp_ddc_write *cmd, + int id, struct btintel_sar_inc_pwr *sar) +{ + cmd->len = 3; + cmd->id = cpu_to_le16(id); + cmd->data[0] = sar->br; + return btintel_send_sar_ddc(hdev, cmd, 4); +} + +static int btintel_send_edr2(struct hci_dev *hdev, struct btintel_cp_ddc_write *cmd, + int id, struct btintel_sar_inc_pwr *sar) +{ + cmd->len = 3; + cmd->id = cpu_to_le16(id); + cmd->data[0] = sar->edr2; + return btintel_send_sar_ddc(hdev, cmd, 4); +} + +static int btintel_send_edr3(struct hci_dev *hdev, struct btintel_cp_ddc_write *cmd, + int id, struct btintel_sar_inc_pwr *sar) +{ + cmd->len = 3; + cmd->id = cpu_to_le16(id); + cmd->data[0] = sar->edr3; + return btintel_send_sar_ddc(hdev, cmd, 4); +} + +static int btintel_set_legacy_sar(struct hci_dev *hdev, struct btintel_sar_inc_pwr *sar) +{ + struct btintel_cp_ddc_write *cmd; + u8 buffer[64]; + int ret; + + cmd = (void *)buffer; + ret = btintel_send_br(hdev, cmd, 0x0131, sar); + if (ret) + return ret; + + ret = btintel_send_br(hdev, cmd, 0x0132, sar); + if (ret) + return ret; + + ret = btintel_send_le(hdev, cmd, 0x0133, sar); + if (ret) + return ret; + + ret = btintel_send_edr(hdev, cmd, 0x0137, sar); + if (ret) + return ret; + + ret = btintel_send_edr(hdev, cmd, 0x0138, sar); + if (ret) + return ret; + + ret = btintel_send_edr(hdev, cmd, 0x013b, sar); + if (ret) + return ret; + + ret = btintel_send_edr(hdev, cmd, 0x013c, sar); + + return ret; +} + +static int btintel_set_mutual_sar(struct hci_dev *hdev, struct btintel_sar_inc_pwr *sar) +{ + struct btintel_cp_ddc_write *cmd; + struct sk_buff *skb; + u8 buffer[64]; + bool enable; + int ret; + + cmd = (void *)buffer; + + cmd->len = 3; + cmd->id = cpu_to_le16(0x019e); + + if (sar->revision == BTINTEL_SAR_INC_PWR && + sar->inc_power_mode == BTINTEL_SAR_INC_PWR_SUPPORTED) + cmd->data[0] = 0x01; + else + cmd->data[0] = 0x00; + + ret = btintel_send_sar_ddc(hdev, cmd, 4); + if (ret) + return ret; + + if (sar->revision == BTINTEL_SAR_INC_PWR && + sar->inc_power_mode == BTINTEL_SAR_INC_PWR_SUPPORTED) { + cmd->len = 3; + cmd->id = cpu_to_le16(0x019f); + cmd->data[0] = sar->sar_2400_chain_a; + + ret = btintel_send_sar_ddc(hdev, cmd, 4); + if (ret) + return ret; + } + + ret = btintel_send_br_mutual(hdev, cmd, 0x01a0, sar); + if (ret) + return ret; + + ret = btintel_send_edr2(hdev, cmd, 0x01a1, sar); + if (ret) + return ret; + + ret = btintel_send_edr3(hdev, cmd, 0x01a2, sar); + if (ret) + return ret; + + ret = btintel_send_le(hdev, cmd, 0x01a3, sar); + if (ret) + return ret; + + enable = true; + skb = __hci_cmd_sync(hdev, 0xfe25, 1, &enable, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_warn(hdev, "Failed to send Intel SAR Enable (%ld)", PTR_ERR(skb)); + return PTR_ERR(skb); + } + + kfree_skb(skb); + return 0; +} + +static int btintel_sar_send_to_device(struct hci_dev *hdev, struct btintel_sar_inc_pwr *sar, + struct intel_version_tlv *ver) +{ + u16 cnvi, cnvr; + int ret; + + cnvi = ver->cnvi_top & 0xfff; + cnvr = ver->cnvr_top & 0xfff; + + if (cnvi < BTINTEL_CNVI_BLAZARI && cnvr < BTINTEL_CNVR_FMP2) { + bt_dev_info(hdev, "Applying legacy Bluetooth SAR"); + ret = btintel_set_legacy_sar(hdev, sar); + } else if (cnvi == BTINTEL_CNVI_GAP || cnvr == BTINTEL_CNVR_FMP2) { + bt_dev_info(hdev, "Applying mutual Bluetooth SAR"); + ret = btintel_set_mutual_sar(hdev, sar); + } else { + ret = -EOPNOTSUPP; + } + + return ret; +} + +static int btintel_acpi_set_sar(struct hci_dev *hdev, struct intel_version_tlv *ver) +{ + union acpi_object *bt_pkg, *buffer = NULL; + struct btintel_sar_inc_pwr sar; + acpi_status status; + u8 revision; + int ret; + + status = btintel_evaluate_acpi_method(hdev, "BRDS", &buffer, 2); + if (ACPI_FAILURE(status)) + return -ENOENT; + + bt_pkg = btintel_acpi_get_bt_pkg(buffer); + + if (IS_ERR(bt_pkg)) { + ret = PTR_ERR(bt_pkg); + goto error; + } + + if (!bt_pkg->package.count) { + ret = -EINVAL; + goto error; + } + + revision = buffer->package.elements[0].integer.value; + + if (revision > BTINTEL_SAR_INC_PWR) { + bt_dev_dbg(hdev, "BT_SAR: revision: 0x%2.2x not supported", revision); + ret = -EOPNOTSUPP; + goto error; + } + + memset(&sar, 0, sizeof(sar)); + + if (revision == BTINTEL_SAR_LEGACY && bt_pkg->package.count == 8) { + sar.revision = revision; + sar.bt_sar_bios = bt_pkg->package.elements[1].integer.value; + sar.br = bt_pkg->package.elements[2].integer.value; + sar.edr2 = bt_pkg->package.elements[3].integer.value; + sar.edr3 = bt_pkg->package.elements[4].integer.value; + sar.le = bt_pkg->package.elements[5].integer.value; + sar.le_2mhz = bt_pkg->package.elements[6].integer.value; + sar.le_lr = bt_pkg->package.elements[7].integer.value; + + } else if (revision == BTINTEL_SAR_INC_PWR && bt_pkg->package.count == 10) { + sar.revision = revision; + sar.bt_sar_bios = bt_pkg->package.elements[1].integer.value; + sar.inc_power_mode = bt_pkg->package.elements[2].integer.value; + sar.sar_2400_chain_a = bt_pkg->package.elements[3].integer.value; + sar.br = bt_pkg->package.elements[4].integer.value; + sar.edr2 = bt_pkg->package.elements[5].integer.value; + sar.edr3 = bt_pkg->package.elements[6].integer.value; + sar.le = bt_pkg->package.elements[7].integer.value; + sar.le_2mhz = bt_pkg->package.elements[8].integer.value; + sar.le_lr = bt_pkg->package.elements[9].integer.value; + } else { + ret = -EINVAL; + goto error; + } + + /* Apply only if it is enabled in BIOS */ + if (sar.bt_sar_bios != 1) { + bt_dev_dbg(hdev, "Bluetooth SAR is not enabled"); + ret = -EOPNOTSUPP; + goto error; + } + + ret = btintel_sar_send_to_device(hdev, &sar, ver); +error: + kfree(buffer); + return ret; +} +#endif /* CONFIG_ACPI */ + +static int btintel_set_specific_absorption_rate(struct hci_dev *hdev, + struct intel_version_tlv *ver) +{ +#ifdef CONFIG_ACPI + return btintel_acpi_set_sar(hdev, ver); +#endif + return 0; +} + int btintel_bootloader_setup_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver) { @@ -2877,6 +3213,9 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev, hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT); + /* Send sar values to controller */ + btintel_set_specific_absorption_rate(hdev, ver); + /* Set PPAG feature */ btintel_set_ppag(hdev, ver); @@ -2919,6 +3258,7 @@ void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) case 0x1c: case 0x1d: case 0x1e: + case 0x1f: hci_set_msft_opcode(hdev, 0xFC1E); break; default: @@ -3258,6 +3598,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) case 0x1b: case 0x1d: case 0x1e: + case 0x1f: /* Display version information of TLV type */ btintel_version_info_tlv(hdev, &ver_tlv); diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index fa43eb137821..2aece3effa4e 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -56,6 +56,10 @@ struct intel_tlv { #define BTINTEL_CNVI_BLAZARIW 0x901 #define BTINTEL_CNVI_GAP 0x910 #define BTINTEL_CNVI_BLAZARU 0x930 +#define BTINTEL_CNVI_SCP 0xA00 + +/* CNVR */ +#define BTINTEL_CNVR_FMP2 0x910 #define BTINTEL_IMG_BOOTLOADER 0x01 /* Bootloader image */ #define BTINTEL_IMG_IML 0x02 /* Intermediate image */ @@ -164,6 +168,26 @@ struct hci_ppag_enable_cmd { #define INTEL_TLV_DEBUG_EXCEPTION 0x02 #define INTEL_TLV_TEST_EXCEPTION 0xDE +struct btintel_cp_ddc_write { + u8 len; + __le16 id; + u8 data[]; +} __packed; + +/* Bluetooth SAR feature (BRDS), Revision 1 */ +struct btintel_sar_inc_pwr { + u8 revision; + u32 bt_sar_bios; /* Mode of SAR control to be used, 1:enabled in bios */ + u32 inc_power_mode; /* Increased power mode */ + u8 sar_2400_chain_a; /* Sar power restriction LB */ + u8 br; + u8 edr2; + u8 edr3; + u8 le; + u8 le_2mhz; + u8 le_lr; +}; + #define INTEL_HW_PLATFORM(cnvx_bt) ((u8)(((cnvx_bt) & 0x0000ff00) >> 8)) #define INTEL_HW_VARIANT(cnvx_bt) ((u8)(((cnvx_bt) & 0x003f0000) >> 16)) #define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 091ffe3e1495..c1e69fcc9c4f 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -36,6 +36,7 @@ /* Intel Bluetooth PCIe device id table */ static const struct pci_device_id btintel_pcie_table[] = { { BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) }, + { BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) }, { 0 } }; MODULE_DEVICE_TABLE(pci, btintel_pcie_table); @@ -48,6 +49,19 @@ MODULE_DEVICE_TABLE(pci, btintel_pcie_table); #define BTINTEL_PCIE_HCI_EVT_PKT 0x00000004 #define BTINTEL_PCIE_HCI_ISO_PKT 0x00000005 +#define BTINTEL_PCIE_MAGIC_NUM 0xA5A5A5A5 + +#define BTINTEL_PCIE_BLZR_HWEXP_SIZE 1024 +#define BTINTEL_PCIE_BLZR_HWEXP_DMP_ADDR 0xB00A7C00 + +#define BTINTEL_PCIE_SCP_HWEXP_SIZE 4096 +#define BTINTEL_PCIE_SCP_HWEXP_DMP_ADDR 0xB030F800 + +#define BTINTEL_PCIE_MAGIC_NUM 0xA5A5A5A5 + +#define BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER 0x17A2 +#define BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT 0x1E61 + /* Alive interrupt context */ enum { BTINTEL_PCIE_ROM, @@ -59,6 +73,83 @@ enum { BTINTEL_PCIE_D3 }; +/* Structure for dbgc fragment buffer + * @buf_addr_lsb: LSB of the buffer's physical address + * @buf_addr_msb: MSB of the buffer's physical address + * @buf_size: Total size of the buffer + */ +struct btintel_pcie_dbgc_ctxt_buf { + u32 buf_addr_lsb; + u32 buf_addr_msb; + u32 buf_size; +}; + +/* Structure for dbgc fragment + * @magic_num: 0XA5A5A5A5 + * @ver: For Driver-FW compatibility + * @total_size: Total size of the payload debug info + * @num_buf: Num of allocated debug bufs + * @bufs: All buffer's addresses and sizes + */ +struct btintel_pcie_dbgc_ctxt { + u32 magic_num; + u32 ver; + u32 total_size; + u32 num_buf; + struct btintel_pcie_dbgc_ctxt_buf bufs[BTINTEL_PCIE_DBGC_BUFFER_COUNT]; +}; + +/* 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 + */ +static int btintel_pcie_setup_dbgc(struct btintel_pcie_data *data) +{ + struct btintel_pcie_dbgc_ctxt db_frag; + struct data_buf *buf; + int i; + + data->dbgc.count = BTINTEL_PCIE_DBGC_BUFFER_COUNT; + data->dbgc.bufs = devm_kcalloc(&data->pdev->dev, data->dbgc.count, + sizeof(*buf), GFP_KERNEL); + if (!data->dbgc.bufs) + return -ENOMEM; + + data->dbgc.buf_v_addr = dmam_alloc_coherent(&data->pdev->dev, + data->dbgc.count * + BTINTEL_PCIE_DBGC_BUFFER_SIZE, + &data->dbgc.buf_p_addr, + GFP_KERNEL | __GFP_NOWARN); + if (!data->dbgc.buf_v_addr) + return -ENOMEM; + + data->dbgc.frag_v_addr = dmam_alloc_coherent(&data->pdev->dev, + sizeof(struct btintel_pcie_dbgc_ctxt), + &data->dbgc.frag_p_addr, + GFP_KERNEL | __GFP_NOWARN); + if (!data->dbgc.frag_v_addr) + return -ENOMEM; + + data->dbgc.frag_size = sizeof(struct btintel_pcie_dbgc_ctxt); + + db_frag.magic_num = BTINTEL_PCIE_MAGIC_NUM; + db_frag.ver = BTINTEL_PCIE_DBGC_FRAG_VERSION; + db_frag.total_size = BTINTEL_PCIE_DBGC_FRAG_PAYLOAD_SIZE; + db_frag.num_buf = BTINTEL_PCIE_DBGC_FRAG_BUFFER_COUNT; + + for (i = 0; i < data->dbgc.count; i++) { + buf = &data->dbgc.bufs[i]; + buf->data_p_addr = data->dbgc.buf_p_addr + i * BTINTEL_PCIE_DBGC_BUFFER_SIZE; + buf->data = data->dbgc.buf_v_addr + i * BTINTEL_PCIE_DBGC_BUFFER_SIZE; + db_frag.bufs[i].buf_addr_lsb = lower_32_bits(buf->data_p_addr); + db_frag.bufs[i].buf_addr_msb = upper_32_bits(buf->data_p_addr); + db_frag.bufs[i].buf_size = BTINTEL_PCIE_DBGC_BUFFER_SIZE; + } + + memcpy(data->dbgc.frag_v_addr, &db_frag, sizeof(db_frag)); + return 0; +} + static inline void ipc_print_ia_ring(struct hci_dev *hdev, struct ia *ia, u16 queue_num) { @@ -273,6 +364,271 @@ static int btintel_pcie_reset_bt(struct btintel_pcie_data *data) return reg == 0 ? 0 : -ENODEV; } +static void btintel_pcie_mac_init(struct btintel_pcie_data *data) +{ + u32 reg; + + /* Set MAC_INIT bit to start primary bootloader */ + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + reg &= ~(BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT | + BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON | + BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET); + reg |= (BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA | + BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT); + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg); +} + +static int btintel_pcie_add_dmp_data(struct hci_dev *hdev, const void *data, int size) +{ + struct sk_buff *skb; + int err; + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, data, size); + err = hci_devcd_append(hdev, skb); + if (err) { + bt_dev_err(hdev, "Failed to append data in the coredump"); + return err; + } + + return 0; +} + +static int btintel_pcie_get_mac_access(struct btintel_pcie_data *data) +{ + u32 reg; + int retry = 15; + + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + + reg |= BTINTEL_PCIE_CSR_FUNC_CTRL_STOP_MAC_ACCESS_DIS; + reg |= BTINTEL_PCIE_CSR_FUNC_CTRL_XTAL_CLK_REQ; + if ((reg & BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS) == 0) + reg |= BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_REQ; + + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg); + + do { + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + if (reg & BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS) + return 0; + /* Need delay here for Target Access harwdware to settle down*/ + usleep_range(1000, 1200); + + } while (--retry > 0); + + return -ETIME; +} + +static void btintel_pcie_release_mac_access(struct btintel_pcie_data *data) +{ + u32 reg; + + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + + if (reg & BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_REQ) + reg &= ~BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_REQ; + + if (reg & BTINTEL_PCIE_CSR_FUNC_CTRL_STOP_MAC_ACCESS_DIS) + reg &= ~BTINTEL_PCIE_CSR_FUNC_CTRL_STOP_MAC_ACCESS_DIS; + + if (reg & BTINTEL_PCIE_CSR_FUNC_CTRL_XTAL_CLK_REQ) + reg &= ~BTINTEL_PCIE_CSR_FUNC_CTRL_XTAL_CLK_REQ; + + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg); +} + +static void btintel_pcie_copy_tlv(struct sk_buff *skb, enum btintel_pcie_tlv_type type, + void *data, int size) +{ + struct intel_tlv *tlv; + + tlv = skb_put(skb, sizeof(*tlv) + size); + tlv->type = type; + tlv->len = size; + memcpy(tlv->val, data, tlv->len); +} + +static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data) +{ + u32 offset, prev_size, wr_ptr_status, dump_size, i; + struct btintel_pcie_dbgc *dbgc = &data->dbgc; + u8 buf_idx, dump_time_len, fw_build; + struct hci_dev *hdev = data->hdev; + struct intel_tlv *tlv; + struct timespec64 now; + struct sk_buff *skb; + struct tm tm_now; + char buf[256]; + u16 hdr_len; + int ret; + + wr_ptr_status = btintel_pcie_rd_dev_mem(data, BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS); + offset = wr_ptr_status & BTINTEL_PCIE_DBG_OFFSET_BIT_MASK; + + buf_idx = BTINTEL_PCIE_DBGC_DBG_BUF_IDX(wr_ptr_status); + if (buf_idx > dbgc->count) { + bt_dev_warn(hdev, "Buffer index is invalid"); + return -EINVAL; + } + + prev_size = buf_idx * BTINTEL_PCIE_DBGC_BUFFER_SIZE; + if (prev_size + offset >= prev_size) + data->dmp_hdr.write_ptr = prev_size + offset; + else + return -EINVAL; + + ktime_get_real_ts64(&now); + time64_to_tm(now.tv_sec, 0, &tm_now); + dump_time_len = snprintf(buf, sizeof(buf), "Dump Time: %02d-%02d-%04ld %02d:%02d:%02d", + tm_now.tm_mday, tm_now.tm_mon + 1, tm_now.tm_year + 1900, + tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec); + + fw_build = snprintf(buf + dump_time_len, sizeof(buf) - dump_time_len, + "Firmware Timestamp: Year %u WW %02u buildtype %u build %u", + 2000 + (data->dmp_hdr.fw_timestamp >> 8), + data->dmp_hdr.fw_timestamp & 0xff, data->dmp_hdr.fw_build_type, + data->dmp_hdr.fw_build_num); + + hdr_len = sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_bt) + + sizeof(*tlv) + sizeof(data->dmp_hdr.write_ptr) + + sizeof(*tlv) + sizeof(data->dmp_hdr.wrap_ctr) + + sizeof(*tlv) + sizeof(data->dmp_hdr.trigger_reason) + + sizeof(*tlv) + sizeof(data->dmp_hdr.fw_git_sha1) + + sizeof(*tlv) + sizeof(data->dmp_hdr.cnvr_top) + + sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_top) + + sizeof(*tlv) + dump_time_len + + sizeof(*tlv) + fw_build; + + dump_size = hdr_len + sizeof(hdr_len); + + skb = alloc_skb(dump_size, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + /* Add debug buffers data length to dump size */ + dump_size += BTINTEL_PCIE_DBGC_BUFFER_SIZE * dbgc->count; + + ret = hci_devcd_init(hdev, dump_size); + if (ret) { + bt_dev_err(hdev, "Failed to init devcoredump, err %d", ret); + kfree_skb(skb); + return ret; + } + + skb_put_data(skb, &hdr_len, sizeof(hdr_len)); + + btintel_pcie_copy_tlv(skb, BTINTEL_CNVI_BT, &data->dmp_hdr.cnvi_bt, + sizeof(data->dmp_hdr.cnvi_bt)); + + btintel_pcie_copy_tlv(skb, BTINTEL_WRITE_PTR, &data->dmp_hdr.write_ptr, + sizeof(data->dmp_hdr.write_ptr)); + + data->dmp_hdr.wrap_ctr = btintel_pcie_rd_dev_mem(data, + BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND); + + btintel_pcie_copy_tlv(skb, BTINTEL_WRAP_CTR, &data->dmp_hdr.wrap_ctr, + sizeof(data->dmp_hdr.wrap_ctr)); + + btintel_pcie_copy_tlv(skb, BTINTEL_TRIGGER_REASON, &data->dmp_hdr.trigger_reason, + sizeof(data->dmp_hdr.trigger_reason)); + + btintel_pcie_copy_tlv(skb, BTINTEL_FW_SHA, &data->dmp_hdr.fw_git_sha1, + sizeof(data->dmp_hdr.fw_git_sha1)); + + btintel_pcie_copy_tlv(skb, BTINTEL_CNVR_TOP, &data->dmp_hdr.cnvr_top, + sizeof(data->dmp_hdr.cnvr_top)); + + btintel_pcie_copy_tlv(skb, BTINTEL_CNVI_TOP, &data->dmp_hdr.cnvi_top, + sizeof(data->dmp_hdr.cnvi_top)); + + btintel_pcie_copy_tlv(skb, BTINTEL_DUMP_TIME, buf, dump_time_len); + + btintel_pcie_copy_tlv(skb, BTINTEL_FW_BUILD, buf + dump_time_len, fw_build); + + ret = hci_devcd_append(hdev, skb); + if (ret) + goto exit_err; + + for (i = 0; i < dbgc->count; i++) { + ret = btintel_pcie_add_dmp_data(hdev, dbgc->bufs[i].data, + BTINTEL_PCIE_DBGC_BUFFER_SIZE); + if (ret) + break; + } + +exit_err: + hci_devcd_complete(hdev); + return ret; +} + +static void btintel_pcie_dump_traces(struct hci_dev *hdev) +{ + struct btintel_pcie_data *data = hci_get_drvdata(hdev); + int ret = 0; + + ret = btintel_pcie_get_mac_access(data); + if (ret) { + bt_dev_err(hdev, "Failed to get mac access: (%d)", ret); + return; + } + + ret = btintel_pcie_read_dram_buffers(data); + + btintel_pcie_release_mac_access(data); + + if (ret) + bt_dev_err(hdev, "Failed to dump traces: (%d)", ret); +} + +static void btintel_pcie_dump_hdr(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct btintel_pcie_data *data = hci_get_drvdata(hdev); + u16 len = skb->len; + u16 *hdrlen_ptr; + char buf[80]; + + hdrlen_ptr = skb_put_zero(skb, sizeof(len)); + + snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n", + INTEL_HW_VARIANT(data->dmp_hdr.cnvi_bt)); + skb_put_data(skb, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "Firmware Build Number: %u\n", + data->dmp_hdr.fw_build_num); + skb_put_data(skb, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "Driver: %s\n", data->dmp_hdr.driver_name); + skb_put_data(skb, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "Vendor: Intel\n"); + skb_put_data(skb, buf, strlen(buf)); + + *hdrlen_ptr = skb->len - len; +} + +static void btintel_pcie_dump_notify(struct hci_dev *hdev, int state) +{ + struct btintel_pcie_data *data = hci_get_drvdata(hdev); + + switch (state) { + case HCI_DEVCOREDUMP_IDLE: + data->dmp_hdr.state = HCI_DEVCOREDUMP_IDLE; + break; + case HCI_DEVCOREDUMP_ACTIVE: + data->dmp_hdr.state = HCI_DEVCOREDUMP_ACTIVE; + break; + case HCI_DEVCOREDUMP_TIMEOUT: + case HCI_DEVCOREDUMP_ABORT: + case HCI_DEVCOREDUMP_DONE: + data->dmp_hdr.state = HCI_DEVCOREDUMP_IDLE; + break; + } +} + /* This function enables BT function by setting BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT bit in * BTINTEL_PCIE_CSR_FUNC_CTRL_REG register and wait for MSI-X with * BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0. @@ -329,20 +685,6 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data) return 0; } -/* BIT(0) - ROM, BIT(1) - IML and BIT(3) - OP - * Sometimes during firmware image switching from ROM to IML or IML to OP image, - * the previous image bit is not cleared by firmware when alive interrupt is - * received. Driver needs to take care of these sticky bits when deciding the - * current image running on controller. - * Ex: 0x10 and 0x11 - both represents that controller is running IML - */ -static inline bool btintel_pcie_in_rom(struct btintel_pcie_data *data) -{ - return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_ROM && - !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML) && - !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW); -} - static inline bool btintel_pcie_in_op(struct btintel_pcie_data *data) { return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW; @@ -393,6 +735,27 @@ static inline char *btintel_pcie_alivectxt_state2str(u32 alive_intr_ctxt) } } +static int btintel_pcie_read_device_mem(struct btintel_pcie_data *data, + void *buf, u32 dev_addr, int len) +{ + int err; + u32 *val = buf; + + /* Get device mac access */ + err = btintel_pcie_get_mac_access(data); + if (err) { + bt_dev_err(data->hdev, "Failed to get mac access %d", err); + return err; + } + + for (; len > 0; len -= 4, dev_addr += 4, val++) + *val = btintel_pcie_rd_dev_mem(data, dev_addr); + + btintel_pcie_release_mac_access(data); + + return 0; +} + /* 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. */ @@ -714,6 +1077,126 @@ exit_error: return ret; } +static void btintel_pcie_read_hwexp(struct btintel_pcie_data *data) +{ + int len, err, offset, pending; + struct sk_buff *skb; + u8 *buf, prefix[64]; + u32 addr, val; + u16 pkt_len; + + struct tlv { + u8 type; + __le16 len; + u8 val[]; + } __packed; + + struct tlv *tlv; + + switch (data->dmp_hdr.cnvi_top & 0xfff) { + case BTINTEL_CNVI_BLAZARI: + case BTINTEL_CNVI_BLAZARIW: + /* only from step B0 onwards */ + if (INTEL_CNVX_TOP_STEP(data->dmp_hdr.cnvi_top) != 0x01) + return; + len = BTINTEL_PCIE_BLZR_HWEXP_SIZE; /* exception data length */ + addr = BTINTEL_PCIE_BLZR_HWEXP_DMP_ADDR; + break; + case BTINTEL_CNVI_SCP: + len = BTINTEL_PCIE_SCP_HWEXP_SIZE; + addr = BTINTEL_PCIE_SCP_HWEXP_DMP_ADDR; + break; + default: + bt_dev_err(data->hdev, "Unsupported cnvi 0x%8.8x", data->dmp_hdr.cnvi_top); + return; + } + + buf = kzalloc(len, GFP_KERNEL); + if (!buf) + goto exit_on_error; + + btintel_pcie_mac_init(data); + + err = btintel_pcie_read_device_mem(data, buf, addr, len); + if (err) + goto exit_on_error; + + val = get_unaligned_le32(buf); + if (val != BTINTEL_PCIE_MAGIC_NUM) { + bt_dev_err(data->hdev, "Invalid exception dump signature: 0x%8.8x", + val); + goto exit_on_error; + } + + snprintf(prefix, sizeof(prefix), "Bluetooth: %s: ", bt_dev_name(data->hdev)); + + offset = 4; + do { + pending = len - offset; + if (pending < sizeof(*tlv)) + break; + tlv = (struct tlv *)(buf + offset); + + /* If type == 0, then there are no more TLVs to be parsed */ + if (!tlv->type) { + bt_dev_dbg(data->hdev, "Invalid TLV type 0"); + break; + } + pkt_len = le16_to_cpu(tlv->len); + offset += sizeof(*tlv); + pending = len - offset; + if (pkt_len > pending) + break; + + offset += pkt_len; + + /* Only TLVs of type == 1 are HCI events, no need to process other + * TLVs + */ + if (tlv->type != 1) + continue; + + bt_dev_dbg(data->hdev, "TLV packet length: %u", pkt_len); + if (pkt_len > HCI_MAX_EVENT_SIZE) + break; + skb = bt_skb_alloc(pkt_len, GFP_KERNEL); + if (!skb) + goto exit_on_error; + hci_skb_pkt_type(skb) = HCI_EVENT_PKT; + skb_put_data(skb, tlv->val, pkt_len); + + /* copy Intel specific pcie packet type */ + val = BTINTEL_PCIE_HCI_EVT_PKT; + memcpy(skb_push(skb, BTINTEL_PCIE_HCI_TYPE_LEN), &val, + BTINTEL_PCIE_HCI_TYPE_LEN); + + print_hex_dump(KERN_DEBUG, prefix, DUMP_PREFIX_OFFSET, 16, 1, + tlv->val, pkt_len, false); + + btintel_pcie_recv_frame(data, skb); + } while (offset < len); + +exit_on_error: + kfree(buf); +} + +static void btintel_pcie_msix_hw_exp_handler(struct btintel_pcie_data *data) +{ + bt_dev_err(data->hdev, "Received hw exception interrupt"); + + if (test_and_set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags)) + return; + + if (test_and_set_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags)) + return; + + /* Trigger device core dump when there is HW exception */ + if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) + data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT; + + queue_work(data->workqueue, &data->rx_work); +} + static void btintel_pcie_rx_work(struct work_struct *work) { struct btintel_pcie_data *data = container_of(work, @@ -722,6 +1205,23 @@ static void btintel_pcie_rx_work(struct work_struct *work) int err; struct hci_dev *hdev = data->hdev; + if (test_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags)) { + /* Unlike usb products, controller will not send hardware + * exception event on exception. Instead controller writes the + * hardware event to device memory along with optional debug + * events, raises MSIX and halts. Driver shall read the + * exception event from device memory and passes it stack for + * further processing. + */ + btintel_pcie_read_hwexp(data); + clear_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags); + } + + if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) { + btintel_pcie_dump_traces(data->hdev); + clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags); + } + /* Process the sk_buf in queue and send to the HCI layer */ while ((skb = skb_dequeue(&data->rx_skb_q))) { err = btintel_pcie_recv_frame(data, skb); @@ -840,6 +1340,10 @@ static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id) return IRQ_NONE; } + /* This interrupt is raised when there is an hardware exception */ + if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HWEXP) + btintel_pcie_msix_hw_exp_handler(data); + /* This interrupt is triggered by the firmware after updating * boot_stage register and image_response register */ @@ -920,7 +1424,8 @@ struct btintel_pcie_causes_list { static struct btintel_pcie_causes_list causes_list[] = { { BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0, BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK, 0x00 }, { BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1, BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK, 0x01 }, - { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x20 }, + { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x20 }, + { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HWEXP, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x23 }, }; /* This function configures the interrupt masks for both HW_INT_CAUSES and @@ -1007,6 +1512,11 @@ static void btintel_pcie_init_ci(struct btintel_pcie_data *data, ci->addr_urbdq1 = data->rxq.urbd1s_p_addr; ci->num_urbdq1 = data->rxq.count; ci->urbdq_db_vec = BTINTEL_PCIE_RXQ_NUM; + + ci->dbg_output_mode = 0x01; + ci->dbgc_addr = data->dbgc.frag_p_addr; + ci->dbgc_size = data->dbgc.frag_size; + ci->dbg_preset = 0x00; } static void btintel_pcie_free_txq_bufs(struct btintel_pcie_data *data, @@ -1219,6 +1729,11 @@ static int btintel_pcie_alloc(struct btintel_pcie_data *data) /* Setup Index Array */ btintel_pcie_setup_ia(data, p_addr, v_addr, &data->ia); + /* Setup data buffers for dbgc */ + err = btintel_pcie_setup_dbgc(data); + if (err) + goto exit_error_txq; + /* Setup Context Information */ p_addr += sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 4; v_addr += sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 4; @@ -1392,6 +1907,7 @@ static void btintel_pcie_release_hdev(struct btintel_pcie_data *data) static int btintel_pcie_setup_internal(struct hci_dev *hdev) { + struct btintel_pcie_data *data = hci_get_drvdata(hdev); const u8 param[1] = { 0xFF }; struct intel_version_tlv ver_tlv; struct sk_buff *skb; @@ -1449,6 +1965,7 @@ static int btintel_pcie_setup_internal(struct hci_dev *hdev) */ switch (INTEL_HW_VARIANT(ver_tlv.cnvi_bt)) { case 0x1e: /* BzrI */ + case 0x1f: /* ScP */ /* Display version information of TLV type */ btintel_version_info_tlv(hdev, &ver_tlv); @@ -1474,6 +1991,23 @@ static int btintel_pcie_setup_internal(struct hci_dev *hdev) break; } + data->dmp_hdr.cnvi_top = ver_tlv.cnvi_top; + data->dmp_hdr.cnvr_top = ver_tlv.cnvr_top; + data->dmp_hdr.fw_timestamp = ver_tlv.timestamp; + data->dmp_hdr.fw_build_type = ver_tlv.build_type; + data->dmp_hdr.fw_build_num = ver_tlv.build_num; + data->dmp_hdr.cnvi_bt = ver_tlv.cnvi_bt; + + if (ver_tlv.img_type == 0x02 || ver_tlv.img_type == 0x03) + data->dmp_hdr.fw_git_sha1 = ver_tlv.git_sha1; + + err = hci_devcd_register(hdev, btintel_pcie_dump_traces, btintel_pcie_dump_hdr, + btintel_pcie_dump_notify); + if (err) { + bt_dev_err(hdev, "Failed to register coredump (%d)", err); + goto exit_error; + } + btintel_print_fseq_info(hdev); exit_error: kfree_skb(skb); @@ -1538,6 +2072,7 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) goto exit_error; } + data->dmp_hdr.driver_name = KBUILD_MODNAME; return 0; exit_error: @@ -1650,11 +2185,28 @@ static void btintel_pcie_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +#ifdef CONFIG_DEV_COREDUMP +static void btintel_pcie_coredump(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct btintel_pcie_data *data = pci_get_drvdata(pdev); + + if (test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) + return; + + data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER; + queue_work(data->workqueue, &data->rx_work); +} +#endif + static struct pci_driver btintel_pcie_driver = { .name = KBUILD_MODNAME, .id_table = btintel_pcie_table, .probe = btintel_pcie_probe, .remove = btintel_pcie_remove, +#ifdef CONFIG_DEV_COREDUMP + .driver.coredump = btintel_pcie_coredump +#endif }; module_pci_driver(btintel_pcie_driver); diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index f9aada0543c4..873178019cad 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -16,6 +16,8 @@ #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_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) /* BTINTEL_PCIE_CSR Function Control Register */ @@ -23,6 +25,12 @@ #define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT (BIT(6)) #define BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT (BIT(7)) #define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS (BIT(20)) + +#define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_REQ (BIT(21)) +/* Stop MAC Access disconnection request */ +#define BTINTEL_PCIE_CSR_FUNC_CTRL_STOP_MAC_ACCESS_DIS (BIT(22)) +#define BTINTEL_PCIE_CSR_FUNC_CTRL_XTAL_CLK_REQ (BIT(23)) + #define BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_STS (BIT(28)) #define BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON (BIT(29)) #define BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET (BIT(31)) @@ -48,6 +56,30 @@ #define BTINTEL_PCIE_CSR_MSIX_IVAR_BASE (BTINTEL_PCIE_CSR_MSIX_BASE + 0x0880) #define BTINTEL_PCIE_CSR_MSIX_IVAR(cause) (BTINTEL_PCIE_CSR_MSIX_IVAR_BASE + (cause)) +/* IOSF Debug Register */ +#define BTINTEL_PCIE_DBGC_BASE_ADDR (0xf3800300) +#define BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS (BTINTEL_PCIE_DBGC_BASE_ADDR + 0x1C) +#define BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND (BTINTEL_PCIE_DBGC_BASE_ADDR + 0x2C) + +#define BTINTEL_PCIE_DBG_IDX_BIT_MASK 0x0F +#define BTINTEL_PCIE_DBGC_DBG_BUF_IDX(data) (((data) >> 24) & BTINTEL_PCIE_DBG_IDX_BIT_MASK) +#define BTINTEL_PCIE_DBG_OFFSET_BIT_MASK 0xFFFFFF + +/* The DRAM buffer count, each buffer size, and + * fragment buffer size + */ +#define BTINTEL_PCIE_DBGC_BUFFER_COUNT 16 +#define BTINTEL_PCIE_DBGC_BUFFER_SIZE (256 * 1024) /* 256 KB */ + +#define BTINTEL_PCIE_DBGC_FRAG_VERSION 1 +#define BTINTEL_PCIE_DBGC_FRAG_BUFFER_COUNT BTINTEL_PCIE_DBGC_BUFFER_COUNT + +/* Magic number(4), version(4), size of payload length(4) */ +#define BTINTEL_PCIE_DBGC_FRAG_HEADER_SIZE 12 + +/* Num of alloc Dbg buff (4) + (LSB(4), MSB(4), Size(4)) for each buffer */ +#define BTINTEL_PCIE_DBGC_FRAG_PAYLOAD_SIZE 196 + /* Causes for the FH register interrupts */ enum msix_fh_int_causes { BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0 = BIT(0), /* cause 0 */ @@ -57,6 +89,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_HWEXP = BIT(3), /* cause 35 */ }; /* PCIe device states @@ -69,6 +102,25 @@ enum { BTINTEL_PCIE_STATE_D3_HOT = 2, BTINTEL_PCIE_STATE_D3_COLD = 3, }; + +enum { + BTINTEL_PCIE_CORE_HALTED, + BTINTEL_PCIE_HWEXP_INPROGRESS, + BTINTEL_PCIE_COREDUMP_INPROGRESS +}; + +enum btintel_pcie_tlv_type { + BTINTEL_CNVI_BT, + BTINTEL_WRITE_PTR, + BTINTEL_WRAP_CTR, + BTINTEL_TRIGGER_REASON, + BTINTEL_FW_SHA, + BTINTEL_CNVR_TOP, + BTINTEL_CNVI_TOP, + BTINTEL_DUMP_TIME, + BTINTEL_FW_BUILD, +}; + #define BTINTEL_PCIE_MSIX_NON_AUTO_CLEAR_CAUSE BIT(7) /* Minimum and Maximum number of MSI-X Vector @@ -325,6 +377,37 @@ struct rxq { struct data_buf *bufs; }; +/* Structure for DRAM Buffer + * @count: Number of descriptors + * @buf: Array of data_buf structure + */ +struct btintel_pcie_dbgc { + u16 count; + + void *frag_v_addr; + dma_addr_t frag_p_addr; + u16 frag_size; + + dma_addr_t buf_p_addr; + void *buf_v_addr; + struct data_buf *bufs; +}; + +struct btintel_pcie_dump_header { + const char *driver_name; + u32 cnvi_top; + u32 cnvr_top; + u16 fw_timestamp; + u8 fw_build_type; + u32 fw_build_num; + u32 fw_git_sha1; + u32 cnvi_bt; + u32 write_ptr; + u32 wrap_ctr; + u16 trigger_reason; + int state; +}; + /* struct btintel_pcie_data * @pdev: pci device * @hdev: hdev device @@ -405,6 +488,8 @@ struct btintel_pcie_data { struct txq txq; struct rxq rxq; u32 alive_intr_ctxt; + struct btintel_pcie_dbgc dbgc; + struct btintel_pcie_dump_header dmp_hdr; }; static inline u32 btintel_pcie_rd_reg32(struct btintel_pcie_data *data, @@ -444,3 +529,11 @@ static inline void btintel_pcie_clr_reg_bits(struct btintel_pcie_data *data, r &= ~bits; iowrite32(r, data->base_addr + offset); } + +static inline u32 btintel_pcie_rd_dev_mem(struct btintel_pcie_data *data, + u32 addr) +{ + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_PRPH_DEV_ADDR_REG, addr); + return btintel_pcie_rd_reg32(data, BTINTEL_PCIE_PRPH_DEV_RD_REG); +} + diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index 68846c5bd4f7..4390fd571dbd 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -1330,13 +1330,6 @@ int btmtk_usb_setup(struct hci_dev *hdev) break; case 0x7922: case 0x7925: - /* Reset the device to ensure it's in the initial state before - * downloading the firmware to ensure. - */ - - if (!test_bit(BTMTK_FIRMWARE_LOADED, &btmtk_data->flags)) - btmtk_usb_subsys_reset(hdev, dev_id); - fallthrough; case 0x7961: btmtk_fw_get_filename(fw_bin_name, sizeof(fw_bin_name), dev_id, fw_version, fw_flavor); @@ -1345,12 +1338,9 @@ int btmtk_usb_setup(struct hci_dev *hdev) btmtk_usb_hci_wmt_sync); if (err < 0) { bt_dev_err(hdev, "Failed to set up firmware (%d)", err); - clear_bit(BTMTK_FIRMWARE_LOADED, &btmtk_data->flags); return err; } - set_bit(BTMTK_FIRMWARE_LOADED, &btmtk_data->flags); - /* It's Device EndPoint Reset Option Register */ err = btmtk_usb_uhw_reg_write(hdev, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT); diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index bd5464bde174..edd5eead1e93 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -610,7 +610,8 @@ static void btmtksdio_txrx_work(struct work_struct *work) } while (int_status || time_is_before_jiffies(txrx_timeout)); /* Enable interrupt */ - sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL); + if (bdev->func->irq_handler) + sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL); sdio_release_host(bdev->func); diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index aa5ec1d444a9..604ab2bba231 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * NXP Bluetooth driver - * Copyright 2023 NXP + * Copyright 2023-2025 NXP */ #include <linux/module.h> @@ -31,6 +31,7 @@ #define BTNXPUART_SERDEV_OPEN 4 #define BTNXPUART_IR_IN_PROGRESS 5 #define BTNXPUART_FW_DOWNLOAD_ABORT 6 +#define BTNXPUART_FW_DUMP_IN_PROGRESS 7 /* NXP HW err codes */ #define BTNXPUART_IR_HW_ERR 0xb0 @@ -98,14 +99,19 @@ #define PS_STATE_AWAKE 0 #define PS_STATE_SLEEP 1 -/* Bluetooth vendor command : Sleep mode */ +/* NXP Vendor Commands. Refer user manual UM11628 on nxp.com */ +/* Set custom BD Address */ +#define HCI_NXP_SET_BD_ADDR 0xfc22 +/* Set Auto-Sleep mode */ #define HCI_NXP_AUTO_SLEEP_MODE 0xfc23 -/* Bluetooth vendor command : Wakeup method */ +/* Set Wakeup method */ #define HCI_NXP_WAKEUP_METHOD 0xfc53 -/* Bluetooth vendor command : Set operational baudrate */ +/* Set operational baudrate */ #define HCI_NXP_SET_OPER_SPEED 0xfc09 -/* Bluetooth vendor command: Independent Reset */ +/* Independent Reset (Soft Reset) */ #define HCI_NXP_IND_RESET 0xfcfc +/* Bluetooth vendor command: Trigger FW dump */ +#define HCI_NXP_TRIGGER_DUMP 0xfe91 /* Bluetooth Power State : Vendor cmd params */ #define BT_PS_ENABLE 0x02 @@ -162,6 +168,12 @@ struct btnxpuart_data { const char *fw_name_old; }; +enum bootloader_param_change { + not_changed, + cmd_sent, + changed +}; + struct btnxpuart_dev { struct hci_dev *hdev; struct serdev_device *serdev; @@ -177,6 +189,7 @@ struct btnxpuart_dev { u32 fw_v1_sent_bytes; u32 fw_dnld_v3_offset; u32 fw_v3_offset_correction; + u32 fw_v3_prev_sent; u32 fw_v1_expected_len; u32 boot_reg_offset; wait_queue_head_t fw_dnld_done_wait_q; @@ -185,8 +198,8 @@ struct btnxpuart_dev { u32 new_baudrate; u32 current_baudrate; u32 fw_init_baudrate; - bool timeout_changed; - bool baudrate_changed; + enum bootloader_param_change timeout_changed; + enum bootloader_param_change baudrate_changed; bool helper_downloaded; struct ps_data psdata; @@ -204,10 +217,11 @@ struct btnxpuart_dev { #define NXP_NAK_V3 0x7b #define NXP_CRC_ERROR_V3 0x7c -/* Bootloader signature error codes */ -#define NXP_ACK_RX_TIMEOUT 0x0002 /* ACK not received from host */ -#define NXP_HDR_RX_TIMEOUT 0x0003 /* FW Header chunk not received */ -#define NXP_DATA_RX_TIMEOUT 0x0004 /* FW Data chunk not received */ +/* Bootloader signature error codes: Refer AN12820 from nxp.com */ +#define NXP_CRC_RX_ERROR BIT(0) /* CRC error in previous packet */ +#define NXP_ACK_RX_TIMEOUT BIT(2) /* ACK not received from host */ +#define NXP_HDR_RX_TIMEOUT BIT(3) /* FW Header chunk not received */ +#define NXP_DATA_RX_TIMEOUT BIT(4) /* FW Data chunk not received */ #define HDR_LEN 16 @@ -310,6 +324,35 @@ union nxp_v3_rx_timeout_nak_u { u8 buf[6]; }; +struct nxp_v3_crc_nak { + u8 nak; + u8 crc; +} __packed; + +union nxp_v3_crc_nak_u { + struct nxp_v3_crc_nak pkt; + u8 buf[2]; +}; + +/* FW dump */ +#define NXP_FW_DUMP_SIZE (1024 * 1000) + +struct nxp_fw_dump_hdr { + __le16 seq_num; + __le16 reserved; + __le16 buf_type; + __le16 buf_len; +}; + +union nxp_set_bd_addr_payload { + struct { + u8 param_id; + u8 param_len; + u8 param[6]; + } __packed data; + u8 buf[8]; +}; + static u8 crc8_table[CRC8_TABLE_SIZE]; /* Default configurations */ @@ -447,8 +490,14 @@ static int ps_setup(struct hci_dev *hdev) return PTR_ERR(psdata->h2c_ps_gpio); } - if (!psdata->h2c_ps_gpio) + 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"); psdata->h2c_wakeup_gpio = 0xff; + } + + device_property_read_u8(&serdev->dev, "nxp,wakeout-pin", &psdata->c2h_wakeup_gpio); psdata->hdev = hdev; INIT_WORK(&psdata->work, ps_work_func); @@ -540,9 +589,11 @@ static int send_wakeup_method_cmd(struct hci_dev *hdev, void *data) pcmd.c2h_wakeupmode = psdata->c2h_wakeupmode; pcmd.c2h_wakeup_gpio = psdata->c2h_wakeup_gpio; + pcmd.h2c_wakeup_gpio = 0xff; switch (psdata->h2c_wakeupmode) { case WAKEUP_METHOD_GPIO: pcmd.h2c_wakeupmode = BT_CTRL_WAKEUP_METHOD_GPIO; + pcmd.h2c_wakeup_gpio = psdata->h2c_wakeup_gpio; break; case WAKEUP_METHOD_DTR: pcmd.h2c_wakeupmode = BT_CTRL_WAKEUP_METHOD_DSR; @@ -552,7 +603,6 @@ static int send_wakeup_method_cmd(struct hci_dev *hdev, void *data) pcmd.h2c_wakeupmode = BT_CTRL_WAKEUP_METHOD_BREAK; break; } - pcmd.h2c_wakeup_gpio = 0xff; skb = nxp_drv_send_cmd(hdev, HCI_NXP_WAKEUP_METHOD, sizeof(pcmd), &pcmd); if (IS_ERR(skb)) { @@ -586,8 +636,13 @@ static void ps_init(struct hci_dev *hdev) usleep_range(5000, 10000); psdata->ps_state = PS_STATE_AWAKE; - psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE; - psdata->c2h_wakeup_gpio = 0xff; + + if (psdata->c2h_wakeup_gpio) { + psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_GPIO; + } 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) @@ -618,11 +673,6 @@ static void ps_init(struct hci_dev *hdev) psdata->cur_psmode = PS_MODE_DISABLE; psdata->target_ps_mode = DEFAULT_PS_MODE; - - if (psdata->cur_h2c_wakeupmode != psdata->h2c_wakeupmode) - hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL); - if (psdata->cur_psmode != psdata->target_ps_mode) - hci_cmd_sync_queue(hdev, send_ps_cmd, NULL, NULL); } /* NXP Firmware Download Feature */ @@ -637,8 +687,8 @@ static int nxp_download_firmware(struct hci_dev *hdev) nxpdev->boot_reg_offset = 0; nxpdev->fw_dnld_v3_offset = 0; nxpdev->fw_v3_offset_correction = 0; - nxpdev->baudrate_changed = false; - nxpdev->timeout_changed = false; + nxpdev->baudrate_changed = not_changed; + nxpdev->timeout_changed = not_changed; nxpdev->helper_downloaded = false; serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_PRI_BAUDRATE); @@ -651,8 +701,10 @@ static int nxp_download_firmware(struct hci_dev *hdev) &nxpdev->tx_state), msecs_to_jiffies(60000)); - release_firmware(nxpdev->fw); - memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); + if (nxpdev->fw && strlen(nxpdev->fw_name)) { + release_firmware(nxpdev->fw); + memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); + } if (err == 0) { bt_dev_err(hdev, "FW Download Timeout. offset: %d", @@ -767,6 +819,16 @@ static bool is_fw_downloading(struct btnxpuart_dev *nxpdev) return test_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); } +static bool ind_reset_in_progress(struct btnxpuart_dev *nxpdev) +{ + return test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state); +} + +static bool fw_dump_in_progress(struct btnxpuart_dev *nxpdev) +{ + return test_bit(BTNXPUART_FW_DUMP_IN_PROGRESS, &nxpdev->tx_state); +} + static bool process_boot_signature(struct btnxpuart_dev *nxpdev) { if (test_bit(BTNXPUART_CHECK_BOOT_SIGNATURE, &nxpdev->tx_state)) { @@ -860,15 +922,14 @@ static int nxp_recv_fw_req_v1(struct hci_dev *hdev, struct sk_buff *skb) len = __le16_to_cpu(req->len); if (!nxp_data->helper_fw_name) { - if (!nxpdev->timeout_changed) { - nxpdev->timeout_changed = nxp_fw_change_timeout(hdev, - len); + if (nxpdev->timeout_changed != changed) { + nxp_fw_change_timeout(hdev, len); + nxpdev->timeout_changed = changed; goto free_skb; } - if (!nxpdev->baudrate_changed) { - nxpdev->baudrate_changed = nxp_fw_change_baudrate(hdev, - len); - if (nxpdev->baudrate_changed) { + if (nxpdev->baudrate_changed != changed) { + if (nxp_fw_change_baudrate(hdev, len)) { + nxpdev->baudrate_changed = changed; serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_SEC_BAUDRATE); serdev_device_set_flow_control(nxpdev->serdev, true); @@ -1047,32 +1108,35 @@ static void nxp_handle_fw_download_error(struct hci_dev *hdev, struct v3_data_re struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); __u32 offset = __le32_to_cpu(req->offset); __u16 err = __le16_to_cpu(req->error); - union nxp_v3_rx_timeout_nak_u nak_tx_buf; - - switch (err) { - case NXP_ACK_RX_TIMEOUT: - case NXP_HDR_RX_TIMEOUT: - case NXP_DATA_RX_TIMEOUT: - nak_tx_buf.pkt.nak = NXP_NAK_V3; - nak_tx_buf.pkt.offset = __cpu_to_le32(offset); - nak_tx_buf.pkt.crc = crc8(crc8_table, nak_tx_buf.buf, - sizeof(nak_tx_buf) - 1, 0xff); - serdev_device_write_buf(nxpdev->serdev, nak_tx_buf.buf, - sizeof(nak_tx_buf)); - break; - default: - bt_dev_dbg(hdev, "Unknown bootloader error code: %d", err); - break; - + union nxp_v3_rx_timeout_nak_u timeout_nak_buf; + union nxp_v3_crc_nak_u crc_nak_buf; + + if (err & NXP_CRC_RX_ERROR) { + crc_nak_buf.pkt.nak = NXP_CRC_ERROR_V3; + crc_nak_buf.pkt.crc = crc8(crc8_table, crc_nak_buf.buf, + sizeof(crc_nak_buf) - 1, 0xff); + serdev_device_write_buf(nxpdev->serdev, crc_nak_buf.buf, + sizeof(crc_nak_buf)); + } else if (err & NXP_ACK_RX_TIMEOUT || + err & NXP_HDR_RX_TIMEOUT || + err & NXP_DATA_RX_TIMEOUT) { + timeout_nak_buf.pkt.nak = NXP_NAK_V3; + timeout_nak_buf.pkt.offset = __cpu_to_le32(offset); + timeout_nak_buf.pkt.crc = crc8(crc8_table, timeout_nak_buf.buf, + sizeof(timeout_nak_buf) - 1, 0xff); + serdev_device_write_buf(nxpdev->serdev, timeout_nak_buf.buf, + sizeof(timeout_nak_buf)); + } else { + bt_dev_err(hdev, "Unknown bootloader error code: %d", err); } - } static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); struct v3_data_req *req; - __u16 len; + __u16 len = 0; + __u16 err = 0; __u32 offset; if (!process_boot_signature(nxpdev)) @@ -1082,23 +1146,40 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb) if (!req || !nxpdev->fw) goto free_skb; - if (!req->error) { + err = __le16_to_cpu(req->error); + + if (!err) { nxp_send_ack(NXP_ACK_V3, hdev); + if (nxpdev->timeout_changed == cmd_sent) + nxpdev->timeout_changed = changed; + if (nxpdev->baudrate_changed == cmd_sent) + nxpdev->baudrate_changed = changed; } else { nxp_handle_fw_download_error(hdev, req); + if (nxpdev->timeout_changed == cmd_sent && + err == NXP_CRC_RX_ERROR) { + nxpdev->fw_v3_offset_correction -= nxpdev->fw_v3_prev_sent; + nxpdev->timeout_changed = not_changed; + } + if (nxpdev->baudrate_changed == cmd_sent && + err == NXP_CRC_RX_ERROR) { + nxpdev->fw_v3_offset_correction -= nxpdev->fw_v3_prev_sent; + nxpdev->baudrate_changed = not_changed; + } goto free_skb; } len = __le16_to_cpu(req->len); - if (!nxpdev->timeout_changed) { - nxpdev->timeout_changed = nxp_fw_change_timeout(hdev, len); + if (nxpdev->timeout_changed != changed) { + nxp_fw_change_timeout(hdev, len); + nxpdev->timeout_changed = cmd_sent; goto free_skb; } - if (!nxpdev->baudrate_changed) { - nxpdev->baudrate_changed = nxp_fw_change_baudrate(hdev, len); - if (nxpdev->baudrate_changed) { + if (nxpdev->baudrate_changed != changed) { + if (nxp_fw_change_baudrate(hdev, len)) { + nxpdev->baudrate_changed = cmd_sent; serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_SEC_BAUDRATE); serdev_device_set_flow_control(nxpdev->serdev, true); @@ -1130,6 +1211,7 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb) nxpdev->fw_dnld_v3_offset, len); free_skb: + nxpdev->fw_v3_prev_sent = len; kfree_skb(skb); return 0; } @@ -1168,7 +1250,7 @@ static int nxp_set_baudrate_cmd(struct hci_dev *hdev, void *data) static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev) { serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_PRI_BAUDRATE); - if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) + if (ind_reset_in_progress(nxpdev)) serdev_device_set_flow_control(nxpdev->serdev, false); else serdev_device_set_flow_control(nxpdev->serdev, true); @@ -1197,6 +1279,104 @@ static int nxp_set_ind_reset(struct hci_dev *hdev, void *data) return hci_recv_frame(hdev, skb); } +/* Firmware dump */ +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); + if (IS_ERR(skb)) + bt_dev_err(hdev, "Failed to trigger FW Dump. (%ld)", PTR_ERR(skb)); + else + kfree_skb(skb); +} + +static void nxp_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb) +{ + /* Nothing to be added in FW dump header */ +} + +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 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); + int err; + + 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"); + goto free_skb; + } + bt_dev_warn(hdev, "==== Start FW dump ==="); + err = hci_devcd_init(hdev, NXP_FW_DUMP_SIZE); + if (err < 0) + goto free_skb; + + schedule_delayed_work(&hdev->dump.dump_timeout, + msecs_to_jiffies(20000)); + } + + err = hci_devcd_append(hdev, skb_clone(skb, GFP_ATOMIC)); + if (err < 0) + goto free_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); + } + +free_skb: + kfree_skb(skb); + return 0; +} + +static int nxp_recv_acl_pkt(struct hci_dev *hdev, struct sk_buff *skb) +{ + __u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle); + + /* FW dump chunks are ACL packets with conn handle 0xfff */ + if ((handle & 0x0FFF) == 0xFFF) + return nxp_process_fw_dump(hdev, skb); + else + return hci_recv_frame(hdev, skb); +} + +static int nxp_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + union nxp_set_bd_addr_payload pcmd; + int err; + + pcmd.data.param_id = 0xfe; + pcmd.data.param_len = 6; + memcpy(pcmd.data.param, bdaddr, 6); + + /* BD address can be assigned only after first reset command. */ + err = __hci_cmd_sync_status(hdev, HCI_OP_RESET, 0, NULL, + HCI_INIT_TIMEOUT); + if (err) { + bt_dev_err(hdev, + "Reset before setting local-bd-addr failed (%d)", + err); + return err; + } + + err = __hci_cmd_sync_status(hdev, HCI_NXP_SET_BD_ADDR, sizeof(pcmd), + pcmd.buf, HCI_CMD_TIMEOUT); + if (err) { + bt_dev_err(hdev, "Changing device address failed (%d)", err); + return err; + } + + return 0; +} + /* NXP protocol */ static int nxp_setup(struct hci_dev *hdev) { @@ -1216,11 +1396,6 @@ static int nxp_setup(struct hci_dev *hdev) serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate); nxpdev->current_baudrate = nxpdev->fw_init_baudrate; - if (nxpdev->current_baudrate != HCI_NXP_SEC_BAUDRATE) { - nxpdev->new_baudrate = HCI_NXP_SEC_BAUDRATE; - hci_cmd_sync_queue(hdev, nxp_set_baudrate_cmd, NULL, NULL); - } - ps_init(hdev); if (test_and_clear_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) @@ -1229,6 +1404,22 @@ static int nxp_setup(struct hci_dev *hdev) return 0; } +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; + nxp_set_baudrate_cmd(hdev, NULL); + } + if (psdata->cur_h2c_wakeupmode != psdata->h2c_wakeupmode) + send_wakeup_method_cmd(hdev, NULL); + if (psdata->cur_psmode != psdata->target_ps_mode) + send_ps_cmd(hdev, NULL); + return 0; +} + static void nxp_hw_err(struct hci_dev *hdev, u8 code) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); @@ -1247,25 +1438,41 @@ static int nxp_shutdown(struct hci_dev *hdev) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); struct sk_buff *skb; - u8 *status; u8 pcmd = 0; - if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) { + if (ind_reset_in_progress(nxpdev)) { skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - status = skb_pull_data(skb, 1); - if (status) { - serdev_device_set_flow_control(nxpdev->serdev, false); - set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); - } - kfree_skb(skb); + 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 */ + if (!IS_ERR(skb)) + kfree_skb(skb); } return 0; } +static bool nxp_wakeup(struct hci_dev *hdev) +{ + struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); + struct ps_data *psdata = &nxpdev->psdata; + + if (psdata->c2h_wakeupmode != BT_HOST_WAKEUP_METHOD_NONE) + return true; + + return false; +} + +static void nxp_reset(struct hci_dev *hdev) +{ + struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); + + if (!ind_reset_in_progress(nxpdev) && !fw_dump_in_progress(nxpdev)) { + bt_dev_dbg(hdev, "CMD Timeout detected. Resetting."); + nxp_set_ind_reset(hdev, NULL); + } +} + static int btnxpuart_queue_skb(struct hci_dev *hdev, struct sk_buff *skb) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); @@ -1286,6 +1493,9 @@ static int nxp_enqueue(struct hci_dev *hdev, struct sk_buff *skb) struct wakeup_cmd_payload wakeup_parm; __le32 baudrate_parm; + if (fw_dump_in_progress(nxpdev)) + return -EBUSY; + /* if vendor commands are received from user space (e.g. hcitool), update * driver flags accordingly and ask driver to re-send the command to FW. * In case the payload for any command does not match expected payload @@ -1454,7 +1664,7 @@ static int btnxpuart_flush(struct hci_dev *hdev) } static const struct h4_recv_pkt nxp_recv_pkts[] = { - { H4_RECV_ACL, .recv = hci_recv_frame }, + { H4_RECV_ACL, .recv = nxp_recv_acl_pkt }, { H4_RECV_SCO, .recv = hci_recv_frame }, { H4_RECV_EVENT, .recv = hci_recv_frame }, { H4_RECV_ISO, .recv = hci_recv_frame }, @@ -1476,11 +1686,13 @@ static size_t btnxpuart_receive_buf(struct serdev_device *serdev, if (IS_ERR(nxpdev->rx_skb)) { int err = PTR_ERR(nxpdev->rx_skb); /* Safe to ignore out-of-sync bootloader signatures */ - if (!is_fw_downloading(nxpdev)) + if (!is_fw_downloading(nxpdev) && + !ind_reset_in_progress(nxpdev)) bt_dev_err(nxpdev->hdev, "Frame reassembly failed (%d)", err); return count; } - if (!is_fw_downloading(nxpdev)) + if (!is_fw_downloading(nxpdev) && + !ind_reset_in_progress(nxpdev)) nxpdev->hdev->stat.byte_rx += count; return count; } @@ -1499,6 +1711,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev) { struct hci_dev *hdev; struct btnxpuart_dev *nxpdev; + bdaddr_t ba = {0}; nxpdev = devm_kzalloc(&serdev->dev, sizeof(*nxpdev), GFP_KERNEL); if (!nxpdev) @@ -1543,11 +1756,21 @@ static int nxp_serdev_probe(struct serdev_device *serdev) hdev->close = btnxpuart_close; hdev->flush = btnxpuart_flush; hdev->setup = nxp_setup; + hdev->post_init = nxp_post_init; hdev->send = nxp_enqueue; hdev->hw_error = nxp_hw_err; hdev->shutdown = nxp_shutdown; + hdev->wakeup = nxp_wakeup; + hdev->reset = nxp_reset; + hdev->set_bdaddr = nxp_set_bdaddr; SET_HCIDEV_DEV(hdev, &serdev->dev); + device_property_read_u8_array(&nxpdev->serdev->dev, + "local-bd-address", + (u8 *)&ba, sizeof(ba)); + if (bacmp(&ba, BDADDR_ANY)) + set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); + if (hci_register_dev(hdev) < 0) { dev_err(&serdev->dev, "Can't register HCI device\n"); goto probe_fail; @@ -1556,6 +1779,8 @@ 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); + return 0; probe_fail: @@ -1583,6 +1808,7 @@ static void nxp_serdev_remove(struct serdev_device *serdev) nxp_set_baudrate_cmd(hdev, NULL); } } + ps_cleanup(nxpdev); hci_unregister_dev(hdev); hci_free_dev(hdev); @@ -1608,6 +1834,17 @@ static int nxp_serdev_resume(struct device *dev) } #endif +#ifdef CONFIG_DEV_COREDUMP +static void nxp_serdev_coredump(struct device *dev) +{ + struct btnxpuart_dev *nxpdev = dev_get_drvdata(dev); + struct hci_dev *hdev = nxpdev->hdev; + + if (hdev->dump.coredump) + hdev->dump.coredump(hdev); +} +#endif + static struct btnxpuart_data w8987_data __maybe_unused = { .helper_fw_name = NULL, .fw_name = FIRMWARE_W8987, @@ -1638,6 +1875,9 @@ static struct serdev_device_driver nxp_serdev_driver = { .name = "btnxpuart", .of_match_table = of_match_ptr(nxpuart_of_match_table), .pm = &nxp_pm_ops, +#ifdef CONFIG_DEV_COREDUMP + .coredump = nxp_serdev_coredump, +#endif }, }; diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index cdf09d9a9ad2..edefb9dc76aa 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -785,6 +785,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, const char *firmware_name, const char *rampatch_name) { struct qca_fw_config config = {}; + const char *variant = ""; int err; u8 rom_ver = 0; u32 soc_ver; @@ -815,6 +816,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, snprintf(config.fwname, sizeof(config.fwname), "qca/%s", rampatch_name); } else { switch (soc_type) { + case QCA_WCN3950: + snprintf(config.fwname, sizeof(config.fwname), + "qca/cmbtfw%02x.tlv", rom_ver); + break; case QCA_WCN3990: case QCA_WCN3991: case QCA_WCN3998: @@ -880,16 +885,23 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, } } else { switch (soc_type) { + case QCA_WCN3950: + if (le32_to_cpu(ver.soc_id) == QCA_WCN3950_SOC_ID_T) + variant = "t"; + else if (le32_to_cpu(ver.soc_id) == QCA_WCN3950_SOC_ID_S) + variant = "s"; + + snprintf(config.fwname, sizeof(config.fwname), + "qca/cmnv%02x%s.bin", rom_ver, variant); + break; case QCA_WCN3990: case QCA_WCN3991: case QCA_WCN3998: - if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) { - snprintf(config.fwname, sizeof(config.fwname), - "qca/crnv%02xu.bin", rom_ver); - } else { - snprintf(config.fwname, sizeof(config.fwname), - "qca/crnv%02x.bin", rom_ver); - } + if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) + variant = "u"; + + snprintf(config.fwname, sizeof(config.fwname), + "qca/crnv%02x%s.bin", rom_ver, variant); break; case QCA_WCN3988: snprintf(config.fwname, sizeof(config.fwname), @@ -948,6 +960,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, * VsMsftOpCode. */ switch (soc_type) { + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h index 9d28c8800225..8f3c1b1c77b3 100644 --- a/drivers/bluetooth/btqca.h +++ b/drivers/bluetooth/btqca.h @@ -41,6 +41,9 @@ #define QCA_WCN3991_SOC_ID 0x40014320 +#define QCA_WCN3950_SOC_ID_T 0x40074130 +#define QCA_WCN3950_SOC_ID_S 0x40075130 + /* QCA chipset version can be decided by patch and SoC * version, combination with upper 2 bytes from SoC * and lower 2 bytes from patch will be used. @@ -145,6 +148,7 @@ enum qca_btsoc_type { QCA_INVALID = -1, QCA_AR3002, QCA_ROME, + QCA_WCN3950, QCA_WCN3988, QCA_WCN3990, QCA_WCN3998, diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index d3eba0d4a57d..7838c89e529e 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -1215,6 +1215,8 @@ next: rtl_dev_err(hdev, "mandatory config file %s not found", btrtl_dev->ic_info->cfg_name); ret = btrtl_dev->cfg_len; + if (!ret) + ret = -EINVAL; goto err_free; } } diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 2a8d91963c63..5012b5ff92c8 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -34,6 +34,7 @@ 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; @@ -375,10 +376,38 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe0f3), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe100), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe103), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe10a), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe10d), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe11b), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe11c), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe11f), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe141), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe14a), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe14b), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe14d), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3623), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3624), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x2c7c, 0x0130), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x2c7c, 0x0131), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x2c7c, 0x0132), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, /* Broadcom BCM2035 */ { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, @@ -639,6 +668,10 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe102), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe152), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe153), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK | @@ -1085,6 +1118,42 @@ 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) { @@ -1092,6 +1161,10 @@ 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); } @@ -2436,6 +2509,8 @@ static int btusb_setup_csr(struct hci_dev *hdev) set_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks); set_bit(HCI_QUIRK_BROKEN_FILTER_CLEAR_ALL, &hdev->quirks); set_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks); + set_bit(HCI_QUIRK_BROKEN_READ_VOICE_SETTING, &hdev->quirks); + set_bit(HCI_QUIRK_BROKEN_READ_PAGE_SCAN_TYPE, &hdev->quirks); /* Clear the reset quirk since this is not an actual * early Bluetooth 1.1 device from CSR. @@ -2647,7 +2722,7 @@ static void btusb_mtk_claim_iso_intf(struct btusb_data *data) device_unlock(&btmtk_data->isopkt_intf->dev); if (err < 0) { btmtk_data->isopkt_intf = NULL; - bt_dev_err(data->hdev, "Failed to claim iso interface"); + bt_dev_err(data->hdev, "Failed to claim iso interface: %d", err); return; } diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 76878119d910..610d0e3c36d4 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -382,7 +382,7 @@ static void bcsp_pkt_cull(struct bcsp_struct *bcsp) } if (skb_queue_empty(&bcsp->unack)) - del_timer(&bcsp->tbcsp); + timer_delete(&bcsp->tbcsp); spin_unlock_irqrestore(&bcsp->unack.lock, flags); diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index c0436881a533..edafa228bf83 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -197,7 +197,7 @@ static void h5_peer_reset(struct hci_uart *hu) h5->state = H5_UNINITIALIZED; - del_timer(&h5->timer); + timer_delete(&h5->timer); skb_queue_purge(&h5->rel); skb_queue_purge(&h5->unrel); @@ -254,7 +254,7 @@ static int h5_close(struct hci_uart *hu) { struct h5 *h5 = hu->priv; - del_timer_sync(&h5->timer); + timer_delete_sync(&h5->timer); skb_queue_purge(&h5->unack); skb_queue_purge(&h5->rel); @@ -318,7 +318,7 @@ static void h5_pkt_cull(struct h5 *h5) } if (skb_queue_empty(&h5->unack)) - del_timer(&h5->timer); + timer_delete(&h5->timer); unlock: spin_unlock_irqrestore(&h5->unack.lock, flags); diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index d2d6ba8d2f8b..acba83156de9 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -102,7 +102,8 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) if (!skb) { percpu_down_read(&hu->proto_lock); - if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) + if (test_bit(HCI_UART_PROTO_READY, &hu->flags) || + test_bit(HCI_UART_PROTO_INIT, &hu->flags)) skb = hu->proto->dequeue(hu); percpu_up_read(&hu->proto_lock); @@ -124,7 +125,8 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) if (!percpu_down_read_trylock(&hu->proto_lock)) return 0; - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) && + !test_bit(HCI_UART_PROTO_INIT, &hu->flags)) goto no_schedule; set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); @@ -278,7 +280,8 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) percpu_down_read(&hu->proto_lock); - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) && + !test_bit(HCI_UART_PROTO_INIT, &hu->flags)) { percpu_up_read(&hu->proto_lock); return -EUNATCH; } @@ -585,7 +588,8 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) if (tty != hu->tty) return; - if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) + if (test_bit(HCI_UART_PROTO_READY, &hu->flags) || + test_bit(HCI_UART_PROTO_INIT, &hu->flags)) hci_uart_tx_wakeup(hu); } @@ -611,7 +615,8 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, percpu_down_read(&hu->proto_lock); - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) && + !test_bit(HCI_UART_PROTO_INIT, &hu->flags)) { percpu_up_read(&hu->proto_lock); return; } @@ -707,12 +712,16 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) hu->proto = p; + set_bit(HCI_UART_PROTO_INIT, &hu->flags); + err = hci_uart_register_dev(hu); if (err) { return err; } set_bit(HCI_UART_PROTO_READY, &hu->flags); + clear_bit(HCI_UART_PROTO_INIT, &hu->flags); + return 0; } diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 0ac2168f1dc4..e00590ba24fd 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -623,6 +623,7 @@ static int qca_open(struct hci_uart *hu) qcadev = serdev_device_get_drvdata(hu->serdev); switch (qcadev->btsoc_type) { + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: @@ -866,7 +867,7 @@ static void device_woke_up(struct hci_uart *hu) skb_queue_tail(&qca->txq, skb); /* Switch timers and change state to HCI_IBS_TX_AWAKE */ - del_timer(&qca->wake_retrans_timer); + timer_delete(&qca->wake_retrans_timer); idle_delay = msecs_to_jiffies(qca->tx_idle_delay); mod_timer(&qca->tx_idle_timer, jiffies + idle_delay); qca->tx_ibs_state = HCI_IBS_TX_AWAKE; @@ -1366,6 +1367,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) /* Give the controller time to process the request */ switch (qca_soc_type(hu)) { + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: @@ -1452,6 +1454,7 @@ static unsigned int qca_get_speed(struct hci_uart *hu, static int qca_check_speeds(struct hci_uart *hu) { switch (qca_soc_type(hu)) { + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: @@ -1494,6 +1497,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) * changing the baudrate of chip and host. */ switch (soc_type) { + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: @@ -1528,6 +1532,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) error: switch (soc_type) { + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: @@ -1746,6 +1751,7 @@ static int qca_regulator_init(struct hci_uart *hu) } switch (soc_type) { + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: @@ -1776,6 +1782,7 @@ static int qca_regulator_init(struct hci_uart *hu) qca_set_speed(hu, QCA_INIT_SPEED); switch (soc_type) { + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: @@ -1807,6 +1814,7 @@ static int qca_power_on(struct hci_dev *hdev) return 0; switch (soc_type) { + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: @@ -1891,6 +1899,7 @@ static int qca_setup(struct hci_uart *hu) soc_name = "qca2066"; break; + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: @@ -1925,6 +1934,7 @@ retry: clear_bit(QCA_SSR_TRIGGERED, &qca->flags); switch (soc_type) { + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: @@ -1958,6 +1968,7 @@ retry: } switch (soc_type) { + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: @@ -2046,6 +2057,17 @@ static const struct hci_uart_proto qca_proto = { .dequeue = qca_dequeue, }; +static const struct qca_device_data qca_soc_data_wcn3950 __maybe_unused = { + .soc_type = QCA_WCN3950, + .vregs = (struct qca_vreg []) { + { "vddio", 15000 }, + { "vddxo", 60000 }, + { "vddrf", 155000 }, + { "vddch0", 585000 }, + }, + .num_vregs = 4, +}; + static const struct qca_device_data qca_soc_data_wcn3988 __maybe_unused = { .soc_type = QCA_WCN3988, .vregs = (struct qca_vreg []) { @@ -2217,8 +2239,8 @@ static int qca_power_off(struct hci_dev *hdev) hu->hdev->hw_error = NULL; hu->hdev->reset = NULL; - del_timer_sync(&qca->wake_retrans_timer); - del_timer_sync(&qca->tx_idle_timer); + timer_delete_sync(&qca->wake_retrans_timer); + timer_delete_sync(&qca->tx_idle_timer); /* Stop sending shutdown command if soc crashes. */ if (soc_type != QCA_ROME @@ -2338,6 +2360,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) qcadev->btsoc_type = QCA_ROME; switch (qcadev->btsoc_type) { + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: @@ -2359,6 +2382,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) switch (qcadev->btsoc_type) { case QCA_WCN6855: case QCA_WCN7850: + case QCA_WCN6750: if (!device_property_present(&serdev->dev, "enable-gpios")) { /* * Backward compatibility with old DT sources. If the @@ -2374,11 +2398,11 @@ static int qca_serdev_probe(struct serdev_device *serdev) break; } fallthrough; + case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: case QCA_WCN3991: case QCA_WCN3998: - case QCA_WCN6750: qcadev->bt_power->dev = &serdev->dev; err = qca_init_regulators(qcadev->bt_power, data->vregs, data->num_vregs); @@ -2605,10 +2629,10 @@ static int __maybe_unused qca_suspend(struct device *dev) switch (qca->tx_ibs_state) { case HCI_IBS_TX_WAKING: - del_timer(&qca->wake_retrans_timer); + timer_delete(&qca->wake_retrans_timer); fallthrough; case HCI_IBS_TX_AWAKE: - del_timer(&qca->tx_idle_timer); + timer_delete(&qca->tx_idle_timer); serdev_device_write_flush(hu->serdev); cmd = HCI_IBS_SLEEP_IND; @@ -2683,6 +2707,7 @@ static const struct of_device_id qca_bluetooth_of_match[] = { { .compatible = "qcom,qca6174-bt" }, { .compatible = "qcom,qca6390-bt", .data = &qca_soc_data_qca6390}, { .compatible = "qcom,qca9377-bt" }, + { .compatible = "qcom,wcn3950-bt", .data = &qca_soc_data_wcn3950}, { .compatible = "qcom,wcn3988-bt", .data = &qca_soc_data_wcn3988}, { .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990}, { .compatible = "qcom,wcn3991-bt", .data = &qca_soc_data_wcn3991}, diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index fbf3079b92a5..5ea5dd80e297 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -90,6 +90,7 @@ struct hci_uart { #define HCI_UART_REGISTERED 1 #define HCI_UART_PROTO_READY 2 #define HCI_UART_NO_SUSPEND_NOTIFIER 3 +#define HCI_UART_PROTO_INIT 4 /* TX states */ #define HCI_UART_SENDING 1 diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 7651321d351c..59f4d7bdffdc 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -289,18 +289,18 @@ static void vhci_coredump(struct hci_dev *hdev) static void vhci_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb) { - char buf[80]; + const char *buf; - snprintf(buf, sizeof(buf), "Controller Name: vhci_ctrl\n"); + buf = "Controller Name: vhci_ctrl\n"; skb_put_data(skb, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Firmware Version: vhci_fw\n"); + buf = "Firmware Version: vhci_fw\n"; skb_put_data(skb, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Driver: vhci_drv\n"); + buf = "Driver: vhci_drv\n"; skb_put_data(skb, buf, strlen(buf)); - snprintf(buf, sizeof(buf), "Vendor: vhci\n"); + buf = "Vendor: vhci\n"; skb_put_data(skb, buf, strlen(buf)); } @@ -316,7 +316,7 @@ static inline void force_devcd_timeout(struct hci_dev *hdev, unsigned int timeout) { #ifdef CONFIG_DEV_COREDUMP - hdev->dump.timeout = msecs_to_jiffies(timeout * 1000); + hdev->dump.timeout = secs_to_jiffies(timeout); #endif } @@ -416,6 +416,7 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) hdev->wakeup = vhci_wakeup; hdev->setup = vhci_setup; set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); + set_bit(HCI_QUIRK_SYNC_FLOWCTL_SUPPORTED, &hdev->quirks); /* bit 6 is for external configuration */ if (opcode & 0x40) @@ -645,7 +646,7 @@ static int vhci_open(struct inode *inode, struct file *file) file->private_data = data; nonseekable_open(inode, file); - schedule_delayed_work(&data->open_timeout, msecs_to_jiffies(1000)); + schedule_delayed_work(&data->open_timeout, secs_to_jiffies(1)); return 0; } |