Skip to content

Commit

Permalink
Bluetooth: btintel: Add helper function to download firmware
Browse files Browse the repository at this point in the history
1) add a helper function to download firmware for new generation
   Intel controllers

2) add a function to construct firmware / ddc file name for new
   generation Intel controllers

Signed-off-by: Kiran K <kiran.k@intel.com>
Signed-off-by: Amit K Bag <amit.k.bag@intel.com>
Signed-off-by: Raghuram Hegde <raghuram.hegde@intel.com>
Reviewed-by: Sathish Narasimman <Sathish.Narasimman@intel.com>
Reviewed-by: Chethan T N <chethan.tumkur.narayan@intel.com>
Reviewed-by: Srivatsa Ravishankar <ravishankar.srivatsa@intel.com>
  • Loading branch information
kirankrishnappa authored and intel-lab-lkp committed Sep 26, 2020
1 parent a46b7ed commit 5bb97dc
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 0 deletions.
6 changes: 6 additions & 0 deletions drivers/bluetooth/btintel.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ struct intel_debug_features {
__u8 page1[16];
} __packed;

#define INTEL_HW_PLATFORM(cnvx_bt) ((u8)(((cnvx_bt) & 0x0000ff00) >> 8))
#define INTEL_HW_VARIANT(cnvx_bt) ((u8)(((cnvx_bt) & 0x003f0000) >> 16))
#define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff)
#define INTEL_CNVX_TOP_STEP(cnvx_top) (((cnvx_top) & 0x0f000000) >> 24)
#define INTEL_CNVX_TOP_PACK_SWAB(t, s) __swab16(((__u16)(((t) << 4) | (s))))

#if IS_ENABLED(CONFIG_BT_INTEL)

int btintel_check_bdaddr(struct hci_dev *hdev);
Expand Down
183 changes: 183 additions & 0 deletions drivers/bluetooth/btusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -2354,6 +2354,189 @@ static bool btusb_setup_intel_new_get_fw_name(struct intel_version *ver,
return true;
}

static bool btusb_setup_intel_newgen_get_fw_name(const struct intel_version_tlv *ver_tlv,
char *fw_name, size_t len,
const char *suffix)
{
/*
* The firmware file name for new generation controllers will be
* ibt-<cnvi_top type+cnvi_top step>-<cnvr_top type+cnvr_top step>
*/
snprintf(fw_name, len, "intel/ibt-%04x-%04x.%s",
INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver_tlv->cnvi_top),
INTEL_CNVX_TOP_STEP(ver_tlv->cnvi_top)),
INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver_tlv->cnvr_top),
INTEL_CNVX_TOP_STEP(ver_tlv->cnvr_top)),
suffix);
return true;
}

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

err = btusb_setup_intel_newgen_get_fw_name(ver, fwname, sizeof(fwname),
"sfi");
if (!err) {
bt_dev_err(hdev, "Unsupported Intel firmware naming");
return -EINVAL;
}

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,
Expand Down

0 comments on commit 5bb97dc

Please sign in to comment.