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"); | 
