Commit 3f43a378 authored by Kiran K's avatar Kiran K Committed by Johan Hedberg
Browse files

Bluetooth: btusb: Helper function to download firmware to Intel adapters



Define a helper function to download firmware for new generation Intel
controllers

Signed-off-by: default avatarKiran K <kiran.k@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
parent 9a93b8b8
Loading
Loading
Loading
Loading
+165 −0
Original line number Diff line number Diff line
@@ -2400,6 +2400,167 @@ static void btusb_setup_intel_newgen_get_fw_name(const struct intel_version_tlv
		 suffix);
}

static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
						struct intel_version_tlv *ver,
						u32 *boot_param)
{
	const struct firmware *fw;
	char fwname[64];
	int err;
	struct btusb_data *data = hci_get_drvdata(hdev);

	if (!ver || !boot_param)
		return -EINVAL;

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

	/* The firmware variant determines if the device is in bootloader
	 * mode or is running operational firmware. The value 0x03 identifies
	 * the bootloader and the value 0x23 identifies the operational
	 * firmware.
	 *
	 * When the operational firmware is already present, then only
	 * the check for valid Bluetooth device address is needed. This
	 * determines if the device will be added as configured or
	 * unconfigured controller.
	 *
	 * It is not possible to use the Secure Boot Parameters in this
	 * case since that command is only available in bootloader mode.
	 */
	if (ver->img_type == 0x03) {
		clear_bit(BTUSB_BOOTLOADER, &data->flags);
		btintel_check_bdaddr(hdev);
		return 0;
	}

	/* Check for supported iBT hardware variants of this firmware
	 * loading method.
	 *
	 * This check has been put in place to ensure correct forward
	 * compatibility options when newer hardware variants come along.
	 */
	switch (INTEL_HW_VARIANT(ver->cnvi_bt)) {
	case 0x17:	/* TyP */
	case 0x18:	/* Slr */
	case 0x19:	/* Slr-F */
		break;
	default:
		bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)",
			   INTEL_HW_VARIANT(ver->cnvi_bt));
		return -EINVAL;
	}

	/* 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->img_type != 0x01) {
		bt_dev_err(hdev, "Unsupported Intel firmware variant (0x%x)",
			   ver->img_type);
		return -ENODEV;
	}

	/* It is required that every single firmware fragment is acknowledged
	 * with a command complete event. If the boot parameters indicate
	 * that this bootloader does not send them, then abort the setup.
	 */
	if (ver->limited_cce != 0x00) {
		bt_dev_err(hdev, "Unsupported Intel firmware loading method (0x%x)",
			   ver->limited_cce);
		return -EINVAL;
	}

	/* Secure boot engine type should be either 1 (ECDSA) or 0 (RSA) */
	if (ver->sbe_type > 0x01) {
		bt_dev_err(hdev, "Unsupported Intel secure boot engine type (0x%x)",
			   ver->sbe_type);
		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(&ver->otp_bd_addr, BDADDR_ANY)) {
		bt_dev_info(hdev, "No device address configured");
		set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
	}

	btusb_setup_intel_newgen_get_fw_name(ver, fwname, sizeof(fwname), "sfi");
	err = request_firmware(&fw, fwname, &hdev->dev);
	if (err < 0) {
		bt_dev_err(hdev, "Failed to load Intel firmware file (%d)", err);
		return err;
	}

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

	if (fw->size < 644) {
		bt_dev_err(hdev, "Invalid size of firmware file (%zu)",
			   fw->size);
		err = -EBADF;
		goto done;
	}

	set_bit(BTUSB_DOWNLOADING, &data->flags);

	/* Start firmware downloading and get boot parameter */
	err = btintel_download_firmware_newgen(hdev, fw, boot_param,
					       INTEL_HW_VARIANT(ver->cnvi_bt),
					       ver->sbe_type);
	if (err < 0) {
		/* When FW download fails, send Intel Reset to retry
		 * FW download.
		 */
		btintel_reset_to_bootloader(hdev);
		goto done;
	}
	set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);

	bt_dev_info(hdev, "Waiting for firmware download to complete");

	/* Before switching the device into operational mode and with that
	 * booting the loaded firmware, wait for the bootloader notification
	 * that all fragments have been successfully received.
	 *
	 * When the event processing receives the notification, then the
	 * BTUSB_DOWNLOADING flag will be cleared.
	 *
	 * The firmware loading should not take longer than 5 seconds
	 * and thus just timeout if that happens and fail the setup
	 * of this device.
	 */
	err = wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING,
				  TASK_INTERRUPTIBLE,
				  msecs_to_jiffies(5000));
	if (err == -EINTR) {
		bt_dev_err(hdev, "Firmware loading interrupted");
		goto done;
	}

	if (err) {
		bt_dev_err(hdev, "Firmware loading timeout");
		err = -ETIMEDOUT;
		btintel_reset_to_bootloader(hdev);
		goto done;
	}

	if (test_bit(BTUSB_FIRMWARE_FAILED, &data->flags)) {
		bt_dev_err(hdev, "Firmware loading failed");
		err = -ENOEXEC;
		goto done;
	}

done:
	release_firmware(fw);
	return err;
}

static int btusb_intel_download_firmware(struct hci_dev *hdev,
					 struct intel_version *ver,
					 struct intel_boot_params *params,
@@ -2768,6 +2929,10 @@ static int btusb_setup_intel_newgen(struct hci_dev *hdev)

	btintel_version_info_tlv(hdev, &version);

	err = btusb_intel_download_firmware_newgen(hdev, &version, &boot_param);
	if (err)
		return err;

	/* check if controller is already having an operational firmware */
	if (version.img_type == 0x03)
		goto finish;