Commit 5ea7c81a authored by Kiran K's avatar Kiran K Committed by Marcel Holtmann
Browse files

Bluetooth: btusb: Refactor of firmware download flow for Intel conrollers



Address the scalability to support new generation Intel controller with
respect to readability and enhancement to new firmware download sequence

Signed-off-by: default avatarKiran K <kiran.k@intel.com>
Reviewed-by: default avatarChethan T N <chethan.tumkur.narayan@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 3a0377d9
Loading
Loading
Loading
Loading
+80 −65
Original line number Diff line number Diff line
@@ -511,7 +511,6 @@ struct btusb_data {
	unsigned cmd_timeout_cnt;
};


static void btusb_intel_cmd_timeout(struct hci_dev *hdev)
{
	struct btusb_data *data = hci_get_drvdata(hdev);
@@ -2278,46 +2277,25 @@ static bool btusb_setup_intel_new_get_fw_name(struct intel_version *ver,
	return true;
}

static int btusb_setup_intel_new(struct hci_dev *hdev)
static int btusb_intel_download_firmware(struct hci_dev *hdev,
					 struct intel_version *ver,
					 struct intel_boot_params *params)
{
	struct btusb_data *data = hci_get_drvdata(hdev);
	struct intel_version ver;
	struct intel_boot_params params;
	struct intel_debug_features features;
	const struct firmware *fw;
	u32 boot_param;
	char fwname[64];
	ktime_t calltime, delta, rettime;
	unsigned long long duration;
	int err;
	struct btusb_data *data = hci_get_drvdata(hdev);

	BT_DBG("%s", hdev->name);

	/* Set the default boot parameter to 0x0 and it is updated to
	 * SKU specific boot parameter after reading Intel_Write_Boot_Params
	 * command while downloading the firmware.
	 */
	boot_param = 0x00000000;

	calltime = ktime_get();

	/* Read the Intel version information to determine if the device
	 * is in bootloader mode or if it already has operational firmware
	 * loaded.
	 */
	err = btintel_read_version(hdev, &ver);
	if (err) {
		bt_dev_err(hdev, "Intel Read version failed (%d)", err);
		btintel_reset_to_bootloader(hdev);
		return err;
	}
	if (!ver || !params)
		return -EINVAL;

	/* The hardware platform number has a fixed value of 0x37 and
	 * for now only accept this single value.
	 */
	if (ver.hw_platform != 0x37) {
	if (ver->hw_platform != 0x37) {
		bt_dev_err(hdev, "Unsupported Intel hardware platform (%u)",
			   ver.hw_platform);
			   ver->hw_platform);
		return -EINVAL;
	}

@@ -2327,7 +2305,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
	 * This check has been put in place to ensure correct forward
	 * compatibility options when newer hardware variants come along.
	 */
	switch (ver.hw_variant) {
	switch (ver->hw_variant) {
	case 0x0b:	/* SfP */
	case 0x0c:	/* WsP */
	case 0x11:	/* JfP */
@@ -2337,11 +2315,11 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
		break;
	default:
		bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
			   ver.hw_variant);
			   ver->hw_variant);
		return -EINVAL;
	}

	btintel_version_info(hdev, &ver);
	btintel_version_info(hdev, ver);

	/* The firmware variant determines if the device is in bootloader
	 * mode or is running operational firmware. The value 0x06 identifies
@@ -2356,25 +2334,25 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
	 * It is not possible to use the Secure Boot Parameters in this
	 * case since that command is only available in bootloader mode.
	 */
	if (ver.fw_variant == 0x23) {
	if (ver->fw_variant == 0x23) {
		clear_bit(BTUSB_BOOTLOADER, &data->flags);
		btintel_check_bdaddr(hdev);
		goto finish;
		return 0;
	}

	/* If the device is not in bootloader mode, then the only possible
	 * choice is to return an error and abort the device initialization.
	 */
	if (ver.fw_variant != 0x06) {
	if (ver->fw_variant != 0x06) {
		bt_dev_err(hdev, "Unsupported Intel firmware variant (%u)",
			   ver.fw_variant);
			   ver->fw_variant);
		return -ENODEV;
	}

	/* Read the secure boot parameters to identify the operating
	 * details of the bootloader.
	 */
	err = btintel_read_boot_params(hdev, &params);
	err = btintel_read_boot_params(hdev, params);
	if (err)
		return err;

@@ -2382,16 +2360,16 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
	 * with a command complete event. If the boot parameters indicate
	 * that this bootloader does not send them, then abort the setup.
	 */
	if (params.limited_cce != 0x00) {
	if (params->limited_cce != 0x00) {
		bt_dev_err(hdev, "Unsupported Intel firmware loading method (%u)",
			   params.limited_cce);
			   params->limited_cce);
		return -EINVAL;
	}

	/* If the OTP has no valid Bluetooth device address, then there will
	 * also be no valid address for the operational firmware.
	 */
	if (!bacmp(&params.otp_bdaddr, BDADDR_ANY)) {
	if (!bacmp(&params->otp_bdaddr, BDADDR_ANY)) {
		bt_dev_info(hdev, "No device address configured");
		set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
	}
@@ -2417,7 +2395,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
	 * ibt-<hw_variant>-<hw_revision>-<fw_revision>.sfi.
	 *
	 */
	err = btusb_setup_intel_new_get_fw_name(&ver, &params, fwname,
	err = btusb_setup_intel_new_get_fw_name(ver, params, fwname,
						sizeof(fwname), "sfi");
	if (!err) {
		bt_dev_err(hdev, "Unsupported Intel firmware naming");
@@ -2432,16 +2410,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)

	bt_dev_info(hdev, "Found device firmware: %s", fwname);

	/* Save the DDC file name for later use to apply once the firmware
	 * downloading is done.
	 */
	err = btusb_setup_intel_new_get_fw_name(&ver, &params, fwname,
						sizeof(fwname), "ddc");
	if (!err) {
		bt_dev_err(hdev, "Unsupported Intel firmware naming");
		return -EINVAL;
	}

	if (fw->size < 644) {
		bt_dev_err(hdev, "Invalid size of firmware file (%zu)",
			   fw->size);
@@ -2496,18 +2464,58 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
		goto done;
	}

done:
	release_firmware(fw);
	return err;
}

static int btusb_setup_intel_new(struct hci_dev *hdev)
{
	struct btusb_data *data = hci_get_drvdata(hdev);
	struct intel_version ver;
	struct intel_boot_params params;
	u32 boot_param;
	char ddcname[64];
	ktime_t calltime, delta, rettime;
	unsigned long long duration;
	int err;
	struct intel_debug_features features;

	BT_DBG("%s", hdev->name);

	/* Set the default boot parameter to 0x0 and it is updated to
	 * SKU specific boot parameter after reading Intel_Write_Boot_Params
	 * command while downloading the firmware.
	 */
	boot_param = 0x00000000;

	calltime = ktime_get();

	/* Read the Intel version information to determine if the device
	 * is in bootloader mode or if it already has operational firmware
	 * loaded.
	 */
	err = btintel_read_version(hdev, &ver);
	if (err) {
		bt_dev_err(hdev, "Intel Read version failed (%d)", err);
		btintel_reset_to_bootloader(hdev);
		return err;
	}

	err = btusb_intel_download_firmware(hdev, &ver, &params);
	if (err)
		return err;

	/* controller is already having an operational firmware */
	if (ver.fw_variant == 0x23)
		goto finish;

	rettime = ktime_get();
	delta = ktime_sub(rettime, calltime);
	duration = (unsigned long long) ktime_to_ns(delta) >> 10;

	bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);

done:
	release_firmware(fw);

	if (err < 0)
		return err;

	calltime = ktime_get();

	set_bit(BTUSB_BOOTING, &data->flags);
@@ -2551,13 +2559,20 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)

	clear_bit(BTUSB_BOOTLOADER, &data->flags);

	/* Once the device is running in operational mode, it needs to apply
	 * the device configuration (DDC) parameters.
	err = btusb_setup_intel_new_get_fw_name(&ver, &params, ddcname,
						sizeof(ddcname), "ddc");

	if (!err) {
		bt_dev_err(hdev, "Unsupported Intel firmware naming");
	} else {
		/* Once the device is running in operational mode, it needs to
		 * apply the device configuration (DDC) parameters.
		 *
	 * The device can work without DDC parameters, so even if it fails
	 * to load the file, no need to fail the setup.
		 * The device can work without DDC parameters, so even if it
		 * fails to load the file, no need to fail the setup.
		 */
	btintel_load_ddc_config(hdev, fwname);
		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.