diff mbox series

[RFC] Bluetooth: btintel: Check firmware version before download

Message ID 20210201220626.890923-1-luiz.dentz@gmail.com (mailing list archive)
State New, archived
Headers show
Series [RFC] Bluetooth: btintel: Check firmware version before download | expand

Commit Message

Luiz Augusto von Dentz Feb. 1, 2021, 10:06 p.m. UTC
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This checking the firmware build number, week and years matches and then
skip the download process.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
 drivers/bluetooth/btintel.c | 88 ++++++++++++++++++++++++++++---------
 drivers/bluetooth/btintel.h |  5 ++-
 drivers/bluetooth/btusb.c   | 22 +++++-----
 3 files changed, 83 insertions(+), 32 deletions(-)

Comments

Luiz Augusto von Dentz Feb. 1, 2021, 10:13 p.m. UTC | #1
Hi,

On Mon, Feb 1, 2021 at 2:06 PM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> This checking the firmware build number, week and years matches and then
> skip the download process.
>
> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> ---
>  drivers/bluetooth/btintel.c | 88 ++++++++++++++++++++++++++++---------
>  drivers/bluetooth/btintel.h |  5 ++-
>  drivers/bluetooth/btusb.c   | 22 +++++-----
>  3 files changed, 83 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
> index 88ce5f0ffc4b..bf7b910966c8 100644
> --- a/drivers/bluetooth/btintel.c
> +++ b/drivers/bluetooth/btintel.c
> @@ -24,6 +24,14 @@
>  #define ECDSA_OFFSET           644
>  #define ECDSA_HEADER_LEN       320
>
> +#define CMD_WRITE_BOOT_PARAMS  0xfc0e
> +struct cmd_write_boot_params {
> +       u32 boot_addr;
> +       u8  fw_build_num;
> +       u8  fw_build_ww;
> +       u8  fw_build_yy;
> +} _packed;
> +
>  int btintel_check_bdaddr(struct hci_dev *hdev)
>  {
>         struct hci_rp_read_bd_addr *bda;
> @@ -841,7 +849,7 @@ static int btintel_sfi_ecdsa_header_secure_send(struct hci_dev *hdev,
>
>  static int btintel_download_firmware_payload(struct hci_dev *hdev,
>                                              const struct firmware *fw,
> -                                            u32 *boot_param, size_t offset)
> +                                            size_t offset)
>  {
>         int err;
>         const u8 *fw_ptr;
> @@ -854,20 +862,6 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev,
>         while (fw_ptr - fw->data < fw->size) {
>                 struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
>
> -               /* Each SKU has a different reset parameter to use in the
> -                * HCI_Intel_Reset command and it is embedded in the firmware
> -                * data. So, instead of using static value per SKU, check
> -                * the firmware data and save it for later use.
> -                */
> -               if (le16_to_cpu(cmd->opcode) == 0xfc0e) {
> -                       /* The boot parameter is the first 32-bit value
> -                        * and rest of 3 octets are reserved.
> -                        */
> -                       *boot_param = get_unaligned_le32(fw_ptr + sizeof(*cmd));
> -
> -                       bt_dev_dbg(hdev, "boot_param=0x%x", *boot_param);
> -               }
> -
>                 frag_len += sizeof(*cmd) + cmd->plen;
>
>                 /* The parameter length of the secure send command requires
> @@ -896,28 +890,84 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev,
>         return err;
>  }
>
> +static bool btintel_firmware_version(struct hci_dev *hdev,
> +                                    u8 num, u8 ww, u8 yy,
> +                                    const struct firmware *fw,
> +                                    u32 *boot_addr)
> +{
> +       const u8 *fw_ptr;
> +       u32 frag_len;
> +
> +       fw_ptr = fw->data;
> +       frag_len = 0;
> +
> +       while (fw_ptr - fw->data < fw->size) {
> +               struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
> +
> +               /* Each SKU has a different reset parameter to use in the
> +                * HCI_Intel_Reset command and it is embedded in the firmware
> +                * data. So, instead of using static value per SKU, check
> +                * the firmware data and save it for later use.
> +                */
> +               if (le16_to_cpu(cmd->opcode) == CMD_WRITE_BOOT_PARAMS) {
> +                       struct cmd_write_boot_params *params;
> +
> +                       params = (void *)(fw_ptr + sizeof(*cmd));
> +
> +                       bt_dev_dbg(hdev, "Boot Address: 0x%x\n"
> +                                  "Firmware Version: %u-%u.%u",
> +                                  le32_to_cpu(params->boot_addr),
> +                                  params->fw_build_num, params->fw_build_ww,
> +                                  params->fw_build_yy);
> +
> +                       if (num == params->fw_build_num &&
> +                           ww == params->fw_build_ww &&
> +                           yy == params->fw_build_yy)
> +                               return true;
> +                       else
> +                               return false;
> +               }
> +
> +               frag_len += sizeof(*cmd) + cmd->plen;
> +       }
> +
> +       return false;
> +}
> +
>  int btintel_download_firmware(struct hci_dev *hdev,
> +                             struct intel_version *ver,
>                               const struct firmware *fw,
>                               u32 *boot_param)
>  {
>         int err;
>
> +       /* Skip download if firmware has the same version */
> +       if (btintel_firmware_version(hdev, ver->fw_build_num, ver->fw_build_ww,
> +                                    ver->fw_build_yy, fw, boot_param))
> +               return -EALREADY;
> +
>         err = btintel_sfi_rsa_header_secure_send(hdev, fw);
>         if (err)
>                 return err;
>
> -       return btintel_download_firmware_payload(hdev, fw, boot_param,
> -                                                RSA_HEADER_LEN);
> +       return btintel_download_firmware_payload(hdev, fw, RSA_HEADER_LEN);
>  }
>  EXPORT_SYMBOL_GPL(btintel_download_firmware);
>
>  int btintel_download_firmware_newgen(struct hci_dev *hdev,
> +                                    struct intel_version_tlv *ver,
>                                      const struct firmware *fw, u32 *boot_param,
>                                      u8 hw_variant, u8 sbe_type)
>  {
>         int err;
>         u32 css_header_ver;
>
> +       /* 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))
> +               return -EALREADY;
> +

Can someone please confirm these parameters above are the same on
Write Boot Parameters? The LTV seems to have changed the version
information.

>         /* iBT hardware variants 0x0b, 0x0c, 0x11, 0x12, 0x13, 0x14 support
>          * only RSA secure boot engine. Hence, the corresponding sfi file will
>          * have RSA header of 644 bytes followed by Command Buffer.
> @@ -947,7 +997,7 @@ int btintel_download_firmware_newgen(struct hci_dev *hdev,
>                 if (err)
>                         return err;
>
> -               err = btintel_download_firmware_payload(hdev, fw, boot_param, RSA_HEADER_LEN);
> +               err = btintel_download_firmware_payload(hdev, fw, RSA_HEADER_LEN);
>                 if (err)
>                         return err;
>         } else if (hw_variant >= 0x17) {
> @@ -968,7 +1018,6 @@ int btintel_download_firmware_newgen(struct hci_dev *hdev,
>                                 return err;
>
>                         err = btintel_download_firmware_payload(hdev, fw,
> -                                                               boot_param,
>                                                                 RSA_HEADER_LEN + ECDSA_HEADER_LEN);
>                         if (err)
>                                 return err;
> @@ -978,7 +1027,6 @@ int btintel_download_firmware_newgen(struct hci_dev *hdev,
>                                 return err;
>
>                         err = btintel_download_firmware_payload(hdev, fw,
> -                                                               boot_param,
>                                                                 RSA_HEADER_LEN + ECDSA_HEADER_LEN);
>                         if (err)
>                                 return err;
> diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
> index 6511b091caf5..51f1f2c883b4 100644
> --- a/drivers/bluetooth/btintel.h
> +++ b/drivers/bluetooth/btintel.h
> @@ -163,9 +163,10 @@ struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
>  int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param);
>  int btintel_read_boot_params(struct hci_dev *hdev,
>                              struct intel_boot_params *params);
> -int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw,
> -                             u32 *boot_param);
> +int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver,
> +                             const struct firmware *fw, u32 *boot_param);
>  int btintel_download_firmware_newgen(struct hci_dev *hdev,
> +                                    struct intel_version_tlv *ver,
>                                      const struct firmware *fw,
>                                      u32 *boot_param, u8 hw_variant,
>                                      u8 sbe_type);
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 4266c057746e..a06e86f52da3 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -2612,14 +2612,15 @@ static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
>         set_bit(BTUSB_DOWNLOADING, &data->flags);
>
>         /* Start firmware downloading and get boot parameter */
> -       err = btintel_download_firmware_newgen(hdev, fw, boot_param,
> +       err = btintel_download_firmware_newgen(hdev, ver, 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);
> +               if (err != -EALREADY)
> +                       /* 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);
> @@ -2806,12 +2807,13 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
>         set_bit(BTUSB_DOWNLOADING, &data->flags);
>
>         /* Start firmware downloading and get boot parameter */
> -       err = btintel_download_firmware(hdev, fw, boot_param);
> +       err = btintel_download_firmware(hdev, ver, fw, boot_param);
>         if (err < 0) {
> -               /* When FW download fails, send Intel Reset to retry
> -                * FW download.
> -                */
> -               btintel_reset_to_bootloader(hdev);
> +               if (err != -EALREADY)
> +                       /* 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);
> --
> 2.26.2

@Abhishek: Could you please test this with the use case that you had
where you would want to skip the firmware download?
bluez.test.bot@gmail.com Feb. 1, 2021, 11:19 p.m. UTC | #2
This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=425661

---Test result---

##############################
    Test: CheckPatch - PASS
    

    ##############################
    Test: CheckGitLint - PASS
    

    ##############################
    Test: CheckBuildK - FAIL
    drivers/bluetooth/hci_intel.c: In function ‘intel_setup’:
drivers/bluetooth/hci_intel.c:738:40: error: passing argument 2 of ‘btintel_download_firmware’ from incompatible pointer type [-Werror=incompatible-pointer-types]
  738 |  err = btintel_download_firmware(hdev, fw, &boot_param);
      |                                        ^~
      |                                        |
      |                                        const struct firmware *
In file included from drivers/bluetooth/hci_intel.c:26:
drivers/bluetooth/btintel.h:166:74: note: expected ‘struct intel_version *’ but argument is of type ‘const struct firmware *’
  166 | int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver,
      |                                                    ~~~~~~~~~~~~~~~~~~~~~~^~~
drivers/bluetooth/hci_intel.c:738:44: error: passing argument 3 of ‘btintel_download_firmware’ from incompatible pointer type [-Werror=incompatible-pointer-types]
  738 |  err = btintel_download_firmware(hdev, fw, &boot_param);
      |                                            ^~~~~~~~~~~
      |                                            |
      |                                            u32 * {aka unsigned int *}
In file included from drivers/bluetooth/hci_intel.c:26:
drivers/bluetooth/btintel.h:167:33: note: expected ‘const struct firmware *’ but argument is of type ‘u32 *’ {aka ‘unsigned int *’}
  167 |          const struct firmware *fw, u32 *boot_param);
      |          ~~~~~~~~~~~~~~~~~~~~~~~^~
drivers/bluetooth/hci_intel.c:738:8: error: too few arguments to function ‘btintel_download_firmware’
  738 |  err = btintel_download_firmware(hdev, fw, &boot_param);
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~
In file included from drivers/bluetooth/hci_intel.c:26:
drivers/bluetooth/btintel.h:166:5: note: declared here
  166 | int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver,
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
make[2]: *** [scripts/Makefile.build:279: drivers/bluetooth/hci_intel.o] Error 1
make[1]: *** [scripts/Makefile.build:496: drivers/bluetooth] Error 2
make: *** [Makefile:1805: drivers] Error 2


    ##############################
    Test: CheckTestRunner: Setup - PASS
    

    ##############################
    Test: CheckTestRunner: l2cap-tester - PASS
    Total: 40, Passed: 34 (85.0%), Failed: 0, Not Run: 6

    ##############################
    Test: CheckTestRunner: bnep-tester - PASS
    Total: 1, Passed: 1 (100.0%), Failed: 0, Not Run: 0

    ##############################
    Test: CheckTestRunner: mgmt-tester - PASS
    Total: 416, Passed: 400 (96.2%), Failed: 0, Not Run: 16

    ##############################
    Test: CheckTestRunner: rfcomm-tester - PASS
    Total: 9, Passed: 9 (100.0%), Failed: 0, Not Run: 0

    ##############################
    Test: CheckTestRunner: sco-tester - PASS
    Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0

    ##############################
    Test: CheckTestRunner: smp-tester - PASS
    Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0

    ##############################
    Test: CheckTestRunner: userchan-tester - PASS
    Total: 3, Passed: 3 (100.0%), Failed: 0, Not Run: 0

    

---
Regards,
Linux Bluetooth
diff mbox series

Patch

diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 88ce5f0ffc4b..bf7b910966c8 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -24,6 +24,14 @@ 
 #define ECDSA_OFFSET		644
 #define ECDSA_HEADER_LEN	320
 
+#define CMD_WRITE_BOOT_PARAMS	0xfc0e
+struct cmd_write_boot_params {
+	u32 boot_addr;
+	u8  fw_build_num;
+	u8  fw_build_ww;
+	u8  fw_build_yy;
+} _packed;
+
 int btintel_check_bdaddr(struct hci_dev *hdev)
 {
 	struct hci_rp_read_bd_addr *bda;
@@ -841,7 +849,7 @@  static int btintel_sfi_ecdsa_header_secure_send(struct hci_dev *hdev,
 
 static int btintel_download_firmware_payload(struct hci_dev *hdev,
 					     const struct firmware *fw,
-					     u32 *boot_param, size_t offset)
+					     size_t offset)
 {
 	int err;
 	const u8 *fw_ptr;
@@ -854,20 +862,6 @@  static int btintel_download_firmware_payload(struct hci_dev *hdev,
 	while (fw_ptr - fw->data < fw->size) {
 		struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
 
-		/* Each SKU has a different reset parameter to use in the
-		 * HCI_Intel_Reset command and it is embedded in the firmware
-		 * data. So, instead of using static value per SKU, check
-		 * the firmware data and save it for later use.
-		 */
-		if (le16_to_cpu(cmd->opcode) == 0xfc0e) {
-			/* The boot parameter is the first 32-bit value
-			 * and rest of 3 octets are reserved.
-			 */
-			*boot_param = get_unaligned_le32(fw_ptr + sizeof(*cmd));
-
-			bt_dev_dbg(hdev, "boot_param=0x%x", *boot_param);
-		}
-
 		frag_len += sizeof(*cmd) + cmd->plen;
 
 		/* The parameter length of the secure send command requires
@@ -896,28 +890,84 @@  static int btintel_download_firmware_payload(struct hci_dev *hdev,
 	return err;
 }
 
+static bool btintel_firmware_version(struct hci_dev *hdev,
+				     u8 num, u8 ww, u8 yy,
+				     const struct firmware *fw,
+				     u32 *boot_addr)
+{
+	const u8 *fw_ptr;
+	u32 frag_len;
+
+	fw_ptr = fw->data;
+	frag_len = 0;
+
+	while (fw_ptr - fw->data < fw->size) {
+		struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
+
+		/* Each SKU has a different reset parameter to use in the
+		 * HCI_Intel_Reset command and it is embedded in the firmware
+		 * data. So, instead of using static value per SKU, check
+		 * the firmware data and save it for later use.
+		 */
+		if (le16_to_cpu(cmd->opcode) == CMD_WRITE_BOOT_PARAMS) {
+			struct cmd_write_boot_params *params;
+
+			params = (void *)(fw_ptr + sizeof(*cmd));
+
+			bt_dev_dbg(hdev, "Boot Address: 0x%x\n"
+				   "Firmware Version: %u-%u.%u",
+				   le32_to_cpu(params->boot_addr),
+				   params->fw_build_num, params->fw_build_ww,
+				   params->fw_build_yy);
+
+			if (num == params->fw_build_num &&
+			    ww == params->fw_build_ww &&
+			    yy == params->fw_build_yy)
+				return true;
+			else
+				return false;
+		}
+
+		frag_len += sizeof(*cmd) + cmd->plen;
+	}
+
+	return false;
+}
+
 int btintel_download_firmware(struct hci_dev *hdev,
+			      struct intel_version *ver,
 			      const struct firmware *fw,
 			      u32 *boot_param)
 {
 	int err;
 
+	/* Skip download if firmware has the same version */
+	if (btintel_firmware_version(hdev, ver->fw_build_num, ver->fw_build_ww,
+				     ver->fw_build_yy, fw, boot_param))
+		return -EALREADY;
+
 	err = btintel_sfi_rsa_header_secure_send(hdev, fw);
 	if (err)
 		return err;
 
-	return btintel_download_firmware_payload(hdev, fw, boot_param,
-						 RSA_HEADER_LEN);
+	return btintel_download_firmware_payload(hdev, fw, RSA_HEADER_LEN);
 }
 EXPORT_SYMBOL_GPL(btintel_download_firmware);
 
 int btintel_download_firmware_newgen(struct hci_dev *hdev,
+				     struct intel_version_tlv *ver,
 				     const struct firmware *fw, u32 *boot_param,
 				     u8 hw_variant, u8 sbe_type)
 {
 	int err;
 	u32 css_header_ver;
 
+	/* 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))
+		return -EALREADY;
+
 	/* iBT hardware variants 0x0b, 0x0c, 0x11, 0x12, 0x13, 0x14 support
 	 * only RSA secure boot engine. Hence, the corresponding sfi file will
 	 * have RSA header of 644 bytes followed by Command Buffer.
@@ -947,7 +997,7 @@  int btintel_download_firmware_newgen(struct hci_dev *hdev,
 		if (err)
 			return err;
 
-		err = btintel_download_firmware_payload(hdev, fw, boot_param, RSA_HEADER_LEN);
+		err = btintel_download_firmware_payload(hdev, fw, RSA_HEADER_LEN);
 		if (err)
 			return err;
 	} else if (hw_variant >= 0x17) {
@@ -968,7 +1018,6 @@  int btintel_download_firmware_newgen(struct hci_dev *hdev,
 				return err;
 
 			err = btintel_download_firmware_payload(hdev, fw,
-								boot_param,
 								RSA_HEADER_LEN + ECDSA_HEADER_LEN);
 			if (err)
 				return err;
@@ -978,7 +1027,6 @@  int btintel_download_firmware_newgen(struct hci_dev *hdev,
 				return err;
 
 			err = btintel_download_firmware_payload(hdev, fw,
-								boot_param,
 								RSA_HEADER_LEN + ECDSA_HEADER_LEN);
 			if (err)
 				return err;
diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
index 6511b091caf5..51f1f2c883b4 100644
--- a/drivers/bluetooth/btintel.h
+++ b/drivers/bluetooth/btintel.h
@@ -163,9 +163,10 @@  struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
 int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param);
 int btintel_read_boot_params(struct hci_dev *hdev,
 			     struct intel_boot_params *params);
-int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw,
-			      u32 *boot_param);
+int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver,
+			      const struct firmware *fw, u32 *boot_param);
 int btintel_download_firmware_newgen(struct hci_dev *hdev,
+				     struct intel_version_tlv *ver,
 				     const struct firmware *fw,
 				     u32 *boot_param, u8 hw_variant,
 				     u8 sbe_type);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 4266c057746e..a06e86f52da3 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -2612,14 +2612,15 @@  static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
 	set_bit(BTUSB_DOWNLOADING, &data->flags);
 
 	/* Start firmware downloading and get boot parameter */
-	err = btintel_download_firmware_newgen(hdev, fw, boot_param,
+	err = btintel_download_firmware_newgen(hdev, ver, 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);
+		if (err != -EALREADY)
+			/* 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);
@@ -2806,12 +2807,13 @@  static int btusb_intel_download_firmware(struct hci_dev *hdev,
 	set_bit(BTUSB_DOWNLOADING, &data->flags);
 
 	/* Start firmware downloading and get boot parameter */
-	err = btintel_download_firmware(hdev, fw, boot_param);
+	err = btintel_download_firmware(hdev, ver, fw, boot_param);
 	if (err < 0) {
-		/* When FW download fails, send Intel Reset to retry
-		 * FW download.
-		 */
-		btintel_reset_to_bootloader(hdev);
+		if (err != -EALREADY)
+			/* 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);