in hci_intel.c [523:865]
static int intel_setup(struct hci_uart *hu)
{
struct intel_data *intel = hu->priv;
struct hci_dev *hdev = hu->hdev;
struct sk_buff *skb;
struct intel_version ver;
struct intel_boot_params params;
struct intel_device *idev;
const struct firmware *fw;
char fwname[64];
u32 boot_param;
ktime_t calltime, delta, rettime;
unsigned long long duration;
unsigned int init_speed, oper_speed;
int speed_change = 0;
int err;
bt_dev_dbg(hdev, "start intel_setup");
hu->hdev->set_diag = btintel_set_diag;
hu->hdev->set_bdaddr = btintel_set_bdaddr;
/* Set the default boot parameter to 0x0 and it is updated to
* SKU specific boot parameter after reading Intel_Write_Boot_Params
* command while downloading the firmware.
*/
boot_param = 0x00000000;
calltime = ktime_get();
if (hu->init_speed)
init_speed = hu->init_speed;
else
init_speed = hu->proto->init_speed;
if (hu->oper_speed)
oper_speed = hu->oper_speed;
else
oper_speed = hu->proto->oper_speed;
if (oper_speed && init_speed && oper_speed != init_speed)
speed_change = 1;
/* Check that the controller is ready */
err = intel_wait_booting(hu);
clear_bit(STATE_BOOTING, &intel->flags);
/* In case of timeout, try to continue anyway */
if (err && err != -ETIMEDOUT)
return err;
set_bit(STATE_BOOTLOADER, &intel->flags);
/* Read the Intel version information to determine if the device
* is in bootloader mode or if it already has operational firmware
* loaded.
*/
err = btintel_read_version(hdev, &ver);
if (err)
return err;
/* The hardware platform number has a fixed value of 0x37 and
* for now only accept this single value.
*/
if (ver.hw_platform != 0x37) {
bt_dev_err(hdev, "Unsupported Intel hardware platform (%u)",
ver.hw_platform);
return -EINVAL;
}
/* 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 (ver.hw_variant) {
case 0x0b: /* LnP */
case 0x0c: /* WsP */
case 0x12: /* ThP */
break;
default:
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
ver.hw_variant);
return -EINVAL;
}
btintel_version_info(hdev, &ver);
/* The firmware variant determines if the device is in bootloader
* mode or is running operational firmware. The value 0x06 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.fw_variant == 0x23) {
clear_bit(STATE_BOOTLOADER, &intel->flags);
btintel_check_bdaddr(hdev);
return 0;
}
/* 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.fw_variant != 0x06) {
bt_dev_err(hdev, "Unsupported Intel firmware variant (%u)",
ver.fw_variant);
return -ENODEV;
}
/* Read the secure boot parameters to identify the operating
* details of the bootloader.
*/
err = btintel_read_boot_params(hdev, ¶ms);
if (err)
return err;
/* 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 (params.limited_cce != 0x00) {
bt_dev_err(hdev, "Unsupported Intel firmware loading method (%u)",
params.limited_cce);
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(¶ms.otp_bdaddr, BDADDR_ANY)) {
bt_dev_info(hdev, "No device address configured");
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
}
/* With this Intel bootloader only the hardware variant and device
* revision information are used to select the right firmware for SfP
* and WsP.
*
* The firmware filename is ibt-<hw_variant>-<dev_revid>.sfi.
*
* Currently the supported hardware variants are:
* 11 (0x0b) for iBT 3.0 (LnP/SfP)
* 12 (0x0c) for iBT 3.5 (WsP)
*
* For ThP/JfP and for future SKU's, the FW name varies based on HW
* variant, HW revision and FW revision, as these are dependent on CNVi
* and RF Combination.
*
* 18 (0x12) for iBT3.5 (ThP/JfP)
*
* The firmware file name for these will be
* ibt-<hw_variant>-<hw_revision>-<fw_revision>.sfi.
*
*/
switch (ver.hw_variant) {
case 0x0b: /* SfP */
case 0x0c: /* WsP */
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi",
ver.hw_variant, le16_to_cpu(params.dev_revid));
break;
case 0x12: /* ThP */
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.sfi",
ver.hw_variant, ver.hw_revision, ver.fw_revision);
break;
default:
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
ver.hw_variant);
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);
/* Save the DDC file name for later */
switch (ver.hw_variant) {
case 0x0b: /* SfP */
case 0x0c: /* WsP */
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc",
ver.hw_variant, le16_to_cpu(params.dev_revid));
break;
case 0x12: /* ThP */
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.ddc",
ver.hw_variant, ver.hw_revision, ver.fw_revision);
break;
default:
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
ver.hw_variant);
return -EINVAL;
}
if (fw->size < 644) {
bt_dev_err(hdev, "Invalid size of firmware file (%zu)",
fw->size);
err = -EBADF;
goto done;
}
set_bit(STATE_DOWNLOADING, &intel->flags);
/* Start firmware downloading and get boot parameter */
err = btintel_download_firmware(hdev, &ver, fw, &boot_param);
if (err < 0)
goto done;
set_bit(STATE_FIRMWARE_LOADED, &intel->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
* STATE_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(&intel->flags, STATE_DOWNLOADING,
TASK_INTERRUPTIBLE,
msecs_to_jiffies(5000));
if (err == -EINTR) {
bt_dev_err(hdev, "Firmware loading interrupted");
err = -EINTR;
goto done;
}
if (err) {
bt_dev_err(hdev, "Firmware loading timeout");
err = -ETIMEDOUT;
goto done;
}
if (test_bit(STATE_FIRMWARE_FAILED, &intel->flags)) {
bt_dev_err(hdev, "Firmware loading failed");
err = -ENOEXEC;
goto done;
}
rettime = ktime_get();
delta = ktime_sub(rettime, calltime);
duration = (unsigned long long) ktime_to_ns(delta) >> 10;
bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);
done:
release_firmware(fw);
/* Check if there was an error and if is not -EALREADY which means the
* firmware has already been loaded.
*/
if (err < 0 && err != -EALREADY)
return err;
/* We need to restore the default speed before Intel reset */
if (speed_change) {
err = intel_set_baudrate(hu, init_speed);
if (err)
return err;
}
calltime = ktime_get();
set_bit(STATE_BOOTING, &intel->flags);
err = btintel_send_intel_reset(hdev, boot_param);
if (err)
return err;
/* The bootloader will not indicate when the device is ready. This
* is done by the operational firmware sending bootup notification.
*
* Booting into operational firmware should not take longer than
* 1 second. However if that happens, then just fail the setup
* since something went wrong.
*/
bt_dev_info(hdev, "Waiting for device to boot");
err = intel_wait_booting(hu);
if (err)
return err;
clear_bit(STATE_BOOTING, &intel->flags);
rettime = ktime_get();
delta = ktime_sub(rettime, calltime);
duration = (unsigned long long) ktime_to_ns(delta) >> 10;
bt_dev_info(hdev, "Device booted in %llu usecs", duration);
/* Enable LPM if matching pdev with wakeup enabled, set TX active
* until further LPM TX notification.
*/
mutex_lock(&intel_device_list_lock);
list_for_each_entry(idev, &intel_device_list, list) {
if (!hu->tty->dev)
break;
if (hu->tty->dev->parent == idev->pdev->dev.parent) {
if (device_may_wakeup(&idev->pdev->dev)) {
set_bit(STATE_LPM_ENABLED, &intel->flags);
set_bit(STATE_TX_ACTIVE, &intel->flags);
}
break;
}
}
mutex_unlock(&intel_device_list_lock);
/* Ignore errors, device can work without DDC parameters */
btintel_load_ddc_config(hdev, fwname);
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_CMD_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
kfree_skb(skb);
if (speed_change) {
err = intel_set_baudrate(hu, oper_speed);
if (err)
return err;
}
bt_dev_info(hdev, "Setup complete");
clear_bit(STATE_BOOTLOADER, &intel->flags);
return 0;
}