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