Bluetooth: btusb: Helper function to download firmware to Intel adapters
authorKiran K <kiran.k@intel.com>
Thu, 19 Nov 2020 11:39:42 +0000 (17:09 +0530)
committerJohan Hedberg <johan.hedberg@intel.com>
Mon, 7 Dec 2020 15:01:15 +0000 (17:01 +0200)
Define a helper function to download firmware for new generation Intel
controllers

Signed-off-by: Kiran K <kiran.k@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
drivers/bluetooth/btusb.c

index 3864db1..f896628 100644 (file)
@@ -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;