diff options
Diffstat (limited to 'drivers/bluetooth/btintel.c')
| -rw-r--r-- | drivers/bluetooth/btintel.c | 633 |
1 files changed, 583 insertions, 50 deletions
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 5d735391545a..9d29ab811f80 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -9,9 +9,11 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/regmap.h> +#include <linux/string_choices.h> #include <linux/acpi.h> #include <acpi/acpi_bus.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> +#include <linux/efi.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -26,11 +28,18 @@ #define ECDSA_OFFSET 644 #define ECDSA_HEADER_LEN 320 +#define BTINTEL_EFI_DSBR L"UefiCnvCommonDSBR" + enum { DSM_SET_WDISABLE2_DELAY = 1, 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; @@ -79,7 +88,7 @@ int btintel_check_bdaddr(struct hci_dev *hdev) if (!bacmp(&bda->bdaddr, BDADDR_INTEL)) { bt_dev_err(hdev, "Found Intel default device address (%pMR)", &bda->bdaddr); - set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + hci_set_quirk(hdev, HCI_QUIRK_INVALID_BDADDR); } kfree_skb(skb); @@ -472,7 +481,10 @@ int btintel_version_info_tlv(struct hci_dev *hdev, case 0x19: /* Slr-F */ case 0x1b: /* Mgr */ case 0x1c: /* Gale Peak (GaP) */ + case 0x1d: /* BlazarU (BzrU) */ case 0x1e: /* BlazarI (Bzr) */ + case 0x1f: /* Scorpious Peak */ + case 0x22: /* BlazarIW (BzrIW) */ break; default: bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)", @@ -502,13 +514,13 @@ int btintel_version_info_tlv(struct hci_dev *hdev, bt_dev_info(hdev, "Device revision is %u", version->dev_rev_id); bt_dev_info(hdev, "Secure boot is %s", - version->secure_boot ? "enabled" : "disabled"); + str_enabled_disabled(version->secure_boot)); bt_dev_info(hdev, "OTP lock is %s", - version->otp_lock ? "enabled" : "disabled"); + str_enabled_disabled(version->otp_lock)); bt_dev_info(hdev, "API lock is %s", - version->api_lock ? "enabled" : "disabled"); + str_enabled_disabled(version->api_lock)); bt_dev_info(hdev, "Debug lock is %s", - version->debug_lock ? "enabled" : "disabled"); + str_enabled_disabled(version->debug_lock)); bt_dev_info(hdev, "Minimum firmware build %u week %u %u", version->min_fw_build_nn, version->min_fw_build_cw, 2000 + version->min_fw_build_yy); @@ -544,7 +556,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 @@ -878,7 +890,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"); @@ -923,16 +935,16 @@ int btintel_read_boot_params(struct hci_dev *hdev, le16_to_cpu(params->dev_revid)); bt_dev_info(hdev, "Secure boot is %s", - params->secure_boot ? "enabled" : "disabled"); + str_enabled_disabled(params->secure_boot)); bt_dev_info(hdev, "OTP lock is %s", - params->otp_lock ? "enabled" : "disabled"); + str_enabled_disabled(params->otp_lock)); bt_dev_info(hdev, "API lock is %s", - params->api_lock ? "enabled" : "disabled"); + str_enabled_disabled(params->api_lock)); bt_dev_info(hdev, "Debug lock is %s", - params->debug_lock ? "enabled" : "disabled"); + str_enabled_disabled(params->debug_lock)); bt_dev_info(hdev, "Minimum firmware build %u week %u %u", params->min_fw_build_nn, params->min_fw_build_cw, @@ -1036,7 +1048,7 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev, * as needed. * * Send set of commands with 4 byte alignment from the - * firmware data buffer as a single Data fragement. + * firmware data buffer as a single Data fragment. */ if (!(frag_len % 4)) { err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr); @@ -1248,6 +1260,12 @@ static void btintel_reset_to_bootloader(struct hci_dev *hdev) struct intel_reset params; struct sk_buff *skb; + /* PCIe transport uses shared hardware reset mechanism for recovery + * which gets triggered in pcie *setup* function on error. + */ + if (hdev->bus == HCI_PCI) + return; + /* Send Intel Reset command. This will result in * re-enumeration of BT controller. * @@ -1263,13 +1281,14 @@ static void btintel_reset_to_bootloader(struct hci_dev *hdev) * boot_param: Boot address * */ + params.reset_type = 0x01; params.patch_enable = 0x01; params.ddc_reload = 0x01; 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)", @@ -1837,6 +1856,37 @@ static int btintel_boot_wait(struct hci_dev *hdev, ktime_t calltime, int msec) return 0; } +static int btintel_boot_wait_d0(struct hci_dev *hdev, ktime_t calltime, + int msec) +{ + ktime_t delta, rettime; + unsigned long long duration; + int err; + + bt_dev_info(hdev, "Waiting for device transition to d0"); + + err = btintel_wait_on_flag_timeout(hdev, INTEL_WAIT_FOR_D0, + TASK_INTERRUPTIBLE, + msecs_to_jiffies(msec)); + if (err == -EINTR) { + bt_dev_err(hdev, "Device d0 move interrupted"); + return -EINTR; + } + + if (err) { + bt_dev_err(hdev, "Device d0 move timeout"); + return -ETIMEDOUT; + } + + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + duration = (unsigned long long)ktime_to_ns(delta) >> 10; + + bt_dev_info(hdev, "Device moved to D0 in %llu usecs", duration); + + return 0; +} + static int btintel_boot(struct hci_dev *hdev, u32 boot_addr) { ktime_t calltime; @@ -1845,6 +1895,7 @@ static int btintel_boot(struct hci_dev *hdev, u32 boot_addr) calltime = ktime_get(); btintel_set_flag(hdev, INTEL_BOOTING); + btintel_set_flag(hdev, INTEL_WAIT_FOR_D0); err = btintel_send_intel_reset(hdev, boot_addr); if (err) { @@ -1857,13 +1908,28 @@ static int btintel_boot(struct hci_dev *hdev, u32 boot_addr) * is done by the operational firmware sending bootup notification. * * Booting into operational firmware should not take longer than - * 1 second. However if that happens, then just fail the setup + * 5 second. However if that happens, then just fail the setup * since something went wrong. */ - err = btintel_boot_wait(hdev, calltime, 1000); - if (err == -ETIMEDOUT) + err = btintel_boot_wait(hdev, calltime, 5000); + if (err == -ETIMEDOUT) { btintel_reset_to_bootloader(hdev); + goto exit_error; + } + + if (hdev->bus == HCI_PCI) { + /* In case of PCIe, after receiving bootup event, driver performs + * D0 entry by writing 0 to sleep control register (check + * btintel_pcie_recv_event()) + * Firmware acks with alive interrupt indicating host is full ready to + * perform BT operation. Lets wait here till INTEL_WAIT_FOR_D0 + * bit is cleared. + */ + calltime = ktime_get(); + err = btintel_boot_wait_d0(hdev, calltime, 2000); + } +exit_error: return err; } @@ -1962,7 +2028,7 @@ static int btintel_download_fw(struct hci_dev *hdev, */ if (!bacmp(¶ms->otp_bdaddr, BDADDR_ANY)) { bt_dev_info(hdev, "No device address configured"); - set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + hci_set_quirk(hdev, HCI_QUIRK_INVALID_BDADDR); } download: @@ -2148,7 +2214,7 @@ static void btintel_get_fw_name_tlv(const struct intel_version_tlv *ver, /* Only Blazar product supports downloading of intermediate loader * image */ - if ((ver->cnvi_top & 0xfff) >= BTINTEL_CNVI_BLAZARI) { + if (INTEL_HW_VARIANT(ver->cnvi_bt) >= 0x1e) { u8 zero[BTINTEL_FWID_MAXLEN]; if (ver->img_type == BTINTEL_IMG_BOOTLOADER) { @@ -2230,7 +2296,7 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev, */ if (!bacmp(&ver->otp_bd_addr, BDADDR_ANY)) { bt_dev_info(hdev, "No device address configured"); - set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + hci_set_quirk(hdev, HCI_QUIRK_INVALID_BDADDR); } } @@ -2240,7 +2306,7 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev, * firmware image which doesn't exist. Lets compare the version * of IML image */ - if ((ver->cnvi_top & 0xfff) >= BTINTEL_CNVI_BLAZARI) + if (INTEL_HW_VARIANT(ver->cnvi_bt) >= 0x1e) btintel_get_iml_tlv(ver, fwname, sizeof(fwname), "sfi"); else btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi"); @@ -2605,7 +2671,7 @@ static u8 btintel_classify_pkt_type(struct hci_dev *hdev, struct sk_buff *skb) * Distinguish ISO data packets form ACL data packets * based on their connection handle value range. */ - if (hci_skb_pkt_type(skb) == HCI_ACLDATA_PKT) { + if (iso_capable(hdev) && hci_skb_pkt_type(skb) == HCI_ACLDATA_PKT) { __u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle); if (hci_handle(handle) >= BTINTEL_ISODATA_HANDLE_BASE) @@ -2615,6 +2681,456 @@ static u8 btintel_classify_pkt_type(struct hci_dev *hdev, struct sk_buff *skb) return hci_skb_pkt_type(skb); } +/* + * UefiCnvCommonDSBR UEFI variable provides information from the OEM platforms + * if they have replaced the BRI (Bluetooth Radio Interface) resistor to + * overcome the potential STEP errors on their designs. Based on the + * configauration, bluetooth firmware shall adjust the BRI response line drive + * strength. The below structure represents DSBR data. + * struct { + * u8 header; + * u32 dsbr; + * } __packed; + * + * header - defines revision number of the structure + * dsbr - defines drive strength BRI response + * bit0 + * 0 - instructs bluetooth firmware to use default values + * 1 - instructs bluetooth firmware to override default values + * bit3:1 + * Reserved + * bit7:4 + * DSBR override values (only if bit0 is set. Default value is 0xF + * bit31:7 + * Reserved + * Expected values for dsbr field: + * 1. 0xF1 - indicates that the resistor on board is 33 Ohm + * 2. 0x00 or 0xB1 - indicates that the resistor on board is 10 Ohm + * 3. Non existing UEFI variable or invalid (none of the above) - indicates + * that the resistor on board is 10 Ohm + * Even if uefi variable is not present, driver shall send 0xfc0a command to + * firmware to use default values. + * + */ +static int btintel_uefi_get_dsbr(u32 *dsbr_var) +{ + struct btintel_dsbr { + u8 header; + u32 dsbr; + } __packed data; + + efi_status_t status; + unsigned long data_size = sizeof(data); + efi_guid_t guid = EFI_GUID(0xe65d8884, 0xd4af, 0x4b20, 0x8d, 0x03, + 0x77, 0x2e, 0xcc, 0x3d, 0xa5, 0x31); + + if (!IS_ENABLED(CONFIG_EFI)) + return -EOPNOTSUPP; + + if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) + return -EOPNOTSUPP; + + status = efi.get_variable(BTINTEL_EFI_DSBR, &guid, NULL, &data_size, + &data); + + if (status != EFI_SUCCESS || data_size != sizeof(data)) + return -ENXIO; + + *dsbr_var = data.dsbr; + return 0; +} + +static int btintel_set_dsbr(struct hci_dev *hdev, struct intel_version_tlv *ver) +{ + struct btintel_dsbr_cmd { + u8 enable; + u8 dsbr; + } __packed; + + struct btintel_dsbr_cmd cmd; + struct sk_buff *skb; + u32 dsbr, cnvi; + u8 status; + int err; + + cnvi = ver->cnvi_top & 0xfff; + /* 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) { + case BTINTEL_CNVI_BLAZARI: + case BTINTEL_CNVI_BLAZARIW: + if (ver->img_type == BTINTEL_IMG_IML && + INTEL_CNVX_TOP_STEP(ver->cnvi_top) == 0x01) + break; + return 0; + case BTINTEL_CNVI_GAP: + case BTINTEL_CNVI_BLAZARU: + if (ver->img_type == BTINTEL_IMG_OP && + hdev->bus == HCI_USB) + break; + return 0; + case BTINTEL_CNVI_SCP: + if (ver->img_type == BTINTEL_IMG_IML) + break; + return 0; + default: + return 0; + } + + dsbr = 0; + err = btintel_uefi_get_dsbr(&dsbr); + if (err < 0) + bt_dev_dbg(hdev, "Error reading efi: %ls (%d)", + BTINTEL_EFI_DSBR, err); + + cmd.enable = dsbr & BIT(0); + cmd.dsbr = dsbr >> 4 & 0xF; + + bt_dev_info(hdev, "dsbr: enable: 0x%2.2x value: 0x%2.2x", cmd.enable, + cmd.dsbr); + + skb = __hci_cmd_sync(hdev, 0xfc0a, sizeof(cmd), &cmd, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) + return -bt_to_errno(PTR_ERR(skb)); + + status = skb->data[0]; + kfree_skb(skb); + + if (status) + return -bt_to_errno(status); + + 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) { @@ -2631,6 +3147,13 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev, */ boot_param = 0x00000000; + /* In case of PCIe, this function might get called multiple times with + * same hdev instance if there is any error on firmware download. + * Need to clear stale bits of previous firmware download attempt. + */ + for (int i = 0; i < __INTEL_NUM_FLAGS; i++) + btintel_clear_flag(hdev, i); + btintel_set_flag(hdev, INTEL_BOOTLOADER); err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param); @@ -2649,8 +3172,15 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev, if (err) return err; + /* set drive strength of BRI response */ + err = btintel_set_dsbr(hdev, ver); + if (err) { + bt_dev_err(hdev, "Failed to send dsbr command (%d)", err); + return err; + } + /* If image type returned is BTINTEL_IMG_IML, then controller supports - * intermediae loader image + * intermediate loader image */ if (ver->img_type == BTINTEL_IMG_IML) { err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param); @@ -2678,6 +3208,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); @@ -2710,7 +3243,7 @@ void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) case 0x12: /* ThP */ case 0x13: /* HrP */ case 0x14: /* CcP */ - /* All Intel new genration controllers support the Microsoft vendor + /* All Intel new generation controllers support the Microsoft vendor * extension are using 0xFC1E for VsMsftOpCode. */ case 0x17: @@ -2718,7 +3251,10 @@ void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) case 0x19: case 0x1b: case 0x1c: + case 0x1d: case 0x1e: + case 0x1f: + case 0x22: hci_set_msft_opcode(hdev, 0xFC1E); break; default: @@ -2901,9 +3437,9 @@ static int btintel_setup_combined(struct hci_dev *hdev) } /* Apply the common HCI quirks for Intel device */ - set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); - set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); - set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks); + hci_set_quirk(hdev, HCI_QUIRK_STRICT_DUPLICATE_FILTER); + hci_set_quirk(hdev, HCI_QUIRK_SIMULTANEOUS_DISCOVERY); + hci_set_quirk(hdev, HCI_QUIRK_NON_PERSISTENT_DIAG); /* Set up the quality report callback for Intel devices */ hdev->set_quality_report = btintel_set_quality_report; @@ -2941,11 +3477,8 @@ static int btintel_setup_combined(struct hci_dev *hdev) */ if (!btintel_test_flag(hdev, INTEL_ROM_LEGACY_NO_WBS_SUPPORT)) - set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, - &hdev->quirks); - if (ver.hw_variant == 0x08 && ver.fw_variant == 0x22) - set_bit(HCI_QUIRK_VALID_LE_STATES, - &hdev->quirks); + hci_set_quirk(hdev, + HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED); err = btintel_legacy_rom_setup(hdev, &ver); break; @@ -2954,18 +3487,17 @@ static int btintel_setup_combined(struct hci_dev *hdev) case 0x12: /* ThP */ case 0x13: /* HrP */ case 0x14: /* CcP */ - set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks); fallthrough; case 0x0c: /* WsP */ /* Apply the device specific HCI quirks * * All Legacy bootloader devices support WBS */ - set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, - &hdev->quirks); + hci_set_quirk(hdev, + HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED); /* These variants don't seem to support LE Coded PHY */ - set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks); + hci_set_quirk(hdev, HCI_QUIRK_BROKEN_LE_CODED); /* Setup MSFT Extension support */ btintel_set_msft_opcode(hdev, ver.hw_variant); @@ -3041,13 +3573,10 @@ static int btintel_setup_combined(struct hci_dev *hdev) * * All Legacy bootloader devices support WBS */ - set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); + hci_set_quirk(hdev, HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED); /* These variants don't seem to support LE Coded PHY */ - set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks); - - /* Set Valid LE States quirk */ - set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks); + hci_set_quirk(hdev, HCI_QUIRK_BROKEN_LE_CODED); /* Setup MSFT Extension support */ btintel_set_msft_opcode(hdev, ver.hw_variant); @@ -3063,7 +3592,10 @@ static int btintel_setup_combined(struct hci_dev *hdev) case 0x17: case 0x19: case 0x1b: + case 0x1d: case 0x1e: + case 0x1f: + case 0x22: /* Display version information of TLV type */ btintel_version_info_tlv(hdev, &ver_tlv); @@ -3071,10 +3603,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) * * All TLV based devices support WBS */ - set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); - - /* Apply LE States quirk from solar onwards */ - set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks); + hci_set_quirk(hdev, HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED); /* Setup MSFT Extension support */ btintel_set_msft_opcode(hdev, @@ -3082,6 +3611,9 @@ static int btintel_setup_combined(struct hci_dev *hdev) btintel_set_dsm_reset_method(hdev, &ver_tlv); err = btintel_bootloader_setup_tlv(hdev, &ver_tlv); + if (err) + goto exit_error; + btintel_register_devcoredump_support(hdev); btintel_print_fseq_info(hdev); break; @@ -3168,13 +3700,12 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) case INTEL_TLV_TEST_EXCEPTION: /* Generate devcoredump from exception */ if (!hci_devcd_init(hdev, skb->len)) { - hci_devcd_append(hdev, skb); + hci_devcd_append(hdev, skb_clone(skb, GFP_ATOMIC)); hci_devcd_complete(hdev); } else { bt_dev_err(hdev, "Failed to generate devcoredump"); - kfree_skb(skb); } - return 0; + break; default: bt_dev_err(hdev, "Invalid exception type %02X", tlv->val[0]); } @@ -3201,7 +3732,8 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb) * indicating that the bootup completed. */ btintel_bootup(hdev, ptr, len); - break; + kfree_skb(skb); + return 0; case 0x06: /* When the firmware loading completes the * device sends out a vendor specific event @@ -3209,7 +3741,8 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb) * loading. */ btintel_secure_send_result(hdev, ptr, len); - break; + kfree_skb(skb); + return 0; } } |
