diff options
Diffstat (limited to 'drivers/bluetooth/btintel.c')
-rw-r--r-- | drivers/bluetooth/btintel.c | 239 |
1 files changed, 201 insertions, 38 deletions
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index f1705b46fc88..9359bff47296 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -1037,8 +1037,9 @@ static bool btintel_firmware_version(struct hci_dev *hdev, params = (void *)(fw_ptr + sizeof(*cmd)); - bt_dev_info(hdev, "Boot Address: 0x%x", - le32_to_cpu(params->boot_addr)); + *boot_addr = le32_to_cpu(params->boot_addr); + + bt_dev_info(hdev, "Boot Address: 0x%x", *boot_addr); bt_dev_info(hdev, "Firmware Version: %u-%u.%u", params->fw_build_num, params->fw_build_ww, @@ -1071,9 +1072,6 @@ int btintel_download_firmware(struct hci_dev *hdev, /* Skip version checking */ break; default: - /* Skip reading firmware file version in bootloader mode */ - if (ver->fw_variant == 0x06) - break; /* Skip download if firmware has the same version */ if (btintel_firmware_version(hdev, ver->fw_build_num, @@ -1114,19 +1112,16 @@ static int btintel_download_fw_tlv(struct hci_dev *hdev, int err; u32 css_header_ver; - /* Skip reading firmware file version in bootloader mode */ - if (ver->img_type != 0x01) { - /* Skip download if firmware has the same version */ - if (btintel_firmware_version(hdev, ver->min_fw_build_nn, - ver->min_fw_build_cw, - ver->min_fw_build_yy, - fw, boot_param)) { - bt_dev_info(hdev, "Firmware already loaded"); - /* Return -EALREADY to indicate that firmware has - * already been loaded. - */ - return -EALREADY; - } + /* Skip download if firmware has the same version */ + if (btintel_firmware_version(hdev, ver->min_fw_build_nn, + ver->min_fw_build_cw, + ver->min_fw_build_yy, + fw, boot_param)) { + bt_dev_info(hdev, "Firmware already loaded"); + /* Return -EALREADY to indicate that firmware has + * already been loaded. + */ + return -EALREADY; } /* The firmware variant determines if the device is in bootloader @@ -1285,12 +1280,16 @@ static int btintel_read_debug_features(struct hci_dev *hdev, static int btintel_set_debug_features(struct hci_dev *hdev, const struct intel_debug_features *features) { - u8 mask[11] = { 0x0a, 0x92, 0x02, 0x07, 0x00, 0x00, 0x00, 0x00, + u8 mask[11] = { 0x0a, 0x92, 0x02, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + u8 period[5] = { 0x04, 0x91, 0x02, 0x05, 0x00 }; + u8 trace_enable = 0x02; struct sk_buff *skb; - if (!features) + if (!features) { + bt_dev_warn(hdev, "Debug features not read"); return -EINVAL; + } if (!(features->page1[0] & 0x3f)) { bt_dev_info(hdev, "Telemetry exception format not supported"); @@ -1303,11 +1302,95 @@ static int btintel_set_debug_features(struct hci_dev *hdev, PTR_ERR(skb)); return PTR_ERR(skb); } + kfree_skb(skb); + + skb = __hci_cmd_sync(hdev, 0xfc8b, 5, period, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Setting periodicity for link statistics traces failed (%ld)", + PTR_ERR(skb)); + return PTR_ERR(skb); + } + kfree_skb(skb); + + skb = __hci_cmd_sync(hdev, 0xfca1, 1, &trace_enable, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Enable tracing of link statistics events failed (%ld)", + PTR_ERR(skb)); + return PTR_ERR(skb); + } + kfree_skb(skb); + + bt_dev_info(hdev, "set debug features: trace_enable 0x%02x mask 0x%02x", + trace_enable, mask[3]); + + return 0; +} + +static int btintel_reset_debug_features(struct hci_dev *hdev, + const struct intel_debug_features *features) +{ + u8 mask[11] = { 0x0a, 0x92, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 }; + u8 trace_enable = 0x00; + struct sk_buff *skb; + + if (!features) { + bt_dev_warn(hdev, "Debug features not read"); + return -EINVAL; + } + + if (!(features->page1[0] & 0x3f)) { + bt_dev_info(hdev, "Telemetry exception format not supported"); + return 0; + } + + /* Should stop the trace before writing ddc event mask. */ + skb = __hci_cmd_sync(hdev, 0xfca1, 1, &trace_enable, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Stop tracing of link statistics events failed (%ld)", + PTR_ERR(skb)); + return PTR_ERR(skb); + } + kfree_skb(skb); + skb = __hci_cmd_sync(hdev, 0xfc8b, 11, mask, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Setting Intel telemetry ddc write event mask failed (%ld)", + PTR_ERR(skb)); + return PTR_ERR(skb); + } kfree_skb(skb); + + bt_dev_info(hdev, "reset debug features: trace_enable 0x%02x mask 0x%02x", + trace_enable, mask[3]); + return 0; } +int btintel_set_quality_report(struct hci_dev *hdev, bool enable) +{ + struct intel_debug_features features; + int err; + + bt_dev_dbg(hdev, "enable %d", enable); + + /* Read the Intel supported features and if new exception formats + * supported, need to load the additional DDC config to enable. + */ + err = btintel_read_debug_features(hdev, &features); + if (err) + return err; + + /* Set or reset the debug features. */ + if (enable) + err = btintel_set_debug_features(hdev, &features); + else + err = btintel_reset_debug_features(hdev, &features); + + return err; +} +EXPORT_SYMBOL_GPL(btintel_set_quality_report); + static const struct firmware *btintel_legacy_rom_get_fw(struct hci_dev *hdev, struct intel_version *ver) { @@ -1893,7 +1976,6 @@ static int btintel_bootloader_setup(struct hci_dev *hdev, u32 boot_param; char ddcname[64]; int err; - struct intel_debug_features features; BT_DBG("%s", hdev->name); @@ -1934,14 +2016,7 @@ static int btintel_bootloader_setup(struct hci_dev *hdev, btintel_load_ddc_config(hdev, ddcname); } - /* Read the Intel supported features and if new exception formats - * supported, need to load the additional DDC config to enable. - */ - err = btintel_read_debug_features(hdev, &features); - if (!err) { - /* Set DDC mask for available debug features */ - btintel_set_debug_features(hdev, &features); - } + hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT); /* Read the Intel version information after loading the FW */ err = btintel_read_version(hdev, &new_ver); @@ -2083,13 +2158,102 @@ done: return err; } +static int btintel_get_codec_config_data(struct hci_dev *hdev, + __u8 link, struct bt_codec *codec, + __u8 *ven_len, __u8 **ven_data) +{ + int err = 0; + + if (!ven_data || !ven_len) + return -EINVAL; + + *ven_len = 0; + *ven_data = NULL; + + if (link != ESCO_LINK) { + bt_dev_err(hdev, "Invalid link type(%u)", link); + return -EINVAL; + } + + *ven_data = kmalloc(sizeof(__u8), GFP_KERNEL); + if (!*ven_data) { + err = -ENOMEM; + goto error; + } + + /* supports only CVSD and mSBC offload codecs */ + switch (codec->id) { + case 0x02: + **ven_data = 0x00; + break; + case 0x05: + **ven_data = 0x01; + break; + default: + err = -EINVAL; + bt_dev_err(hdev, "Invalid codec id(%u)", codec->id); + goto error; + } + /* codec and its capabilities are pre-defined to ids + * preset id = 0x00 represents CVSD codec with sampling rate 8K + * preset id = 0x01 represents mSBC codec with sampling rate 16K + */ + *ven_len = sizeof(__u8); + return err; + +error: + kfree(*ven_data); + *ven_data = NULL; + return err; +} + +static int btintel_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id) +{ + /* Intel uses 1 as data path id for all the usecases */ + *data_path_id = 1; + return 0; +} + +static int btintel_configure_offload(struct hci_dev *hdev) +{ + struct sk_buff *skb; + int err = 0; + struct intel_offload_use_cases *use_cases; + + skb = __hci_cmd_sync(hdev, 0xfc86, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Reading offload use cases failed (%ld)", + PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len < sizeof(*use_cases)) { + err = -EIO; + goto error; + } + + use_cases = (void *)skb->data; + + if (use_cases->status) { + err = -bt_to_errno(skb->data[0]); + goto error; + } + + if (use_cases->preset[0] & 0x03) { + hdev->get_data_path_id = btintel_get_data_path_id; + hdev->get_codec_config_data = btintel_get_codec_config_data; + } +error: + kfree_skb(skb); + return err; +} + static int btintel_bootloader_setup_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver) { u32 boot_param; char ddcname[64]; int err; - struct intel_debug_features features; struct intel_version_tlv new_ver; bt_dev_dbg(hdev, ""); @@ -2125,14 +2289,10 @@ static int btintel_bootloader_setup_tlv(struct hci_dev *hdev, */ btintel_load_ddc_config(hdev, ddcname); - /* Read the Intel supported features and if new exception formats - * supported, need to load the additional DDC config to enable. - */ - err = btintel_read_debug_features(hdev, &features); - if (!err) { - /* Set DDC mask for available debug features */ - btintel_set_debug_features(hdev, &features); - } + /* Read supported use cases and set callbacks to fetch datapath id */ + btintel_configure_offload(hdev); + + hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT); /* Read the Intel version information after loading the FW */ err = btintel_read_version_tlv(hdev, &new_ver); @@ -2232,6 +2392,9 @@ static int btintel_setup_combined(struct hci_dev *hdev) set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks); + /* Set up the quality report callback for Intel devices */ + hdev->set_quality_report = btintel_set_quality_report; + /* For Legacy device, check the HW platform value and size */ if (skb->len == sizeof(ver) && skb->data[1] == 0x37) { bt_dev_dbg(hdev, "Read the legacy Intel version information"); |