mutex_lock(&idev->hu_lock); if (idev->hu)
intel_lpm_host_wake(idev->hu);
mutex_unlock(&idev->hu_lock);
/* Host/Controller are now LPM resumed, trigger a new delayed suspend */
pm_runtime_get(&idev->pdev->dev);
pm_runtime_mark_last_busy(&idev->pdev->dev);
pm_runtime_put_autosuspend(&idev->pdev->dev);
list_for_each_entry(idev, &intel_device_list, list) { /* tty device and pdev device should share the same parent * which is the UART port.
*/ if (hu->tty->dev->parent != idev->pdev->dev.parent) continue;
/* Provide to idev a hu reference which is used to run LPM * transactions (lpm suspend/resume) from PM callbacks. * hu needs to be protected against concurrent removing during * these PM ops.
*/
mutex_lock(&idev->hu_lock);
idev->hu = powered ? hu : NULL;
mutex_unlock(&idev->hu_lock);
if (idev->irq < 0) break;
if (powered && device_can_wakeup(&idev->pdev->dev)) {
err = devm_request_threaded_irq(&idev->pdev->dev,
idev->irq, NULL,
intel_irq,
IRQF_ONESHOT, "bt-host-wake", idev); if (err) {
BT_ERR("hu %p, unable to allocate irq-%d",
hu, idev->irq); break;
}
/* Device will not accept speed change if Intel version has not been * previously requested.
*/
skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_CMD_TIMEOUT); if (IS_ERR(skb)) {
bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
PTR_ERR(skb)); return PTR_ERR(skb);
}
kfree_skb(skb);
skb = bt_skb_alloc(sizeof(speed_cmd), GFP_KERNEL); if (!skb) {
bt_dev_err(hdev, "Failed to alloc memory for baudrate packet"); return -ENOMEM;
}
/* 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;
/* 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");
hci_set_quirk(hdev, HCI_QUIRK_INVALID_BDADDR);
}
/* 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;
}
/* 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;
}
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;
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);
if (!test_bit(STATE_BOOTLOADER, &intel->flags) &&
!test_bit(STATE_BOOTING, &intel->flags)) goto recv;
hdr = (void *)skb->data;
/* When the firmware loading completes the device sends * out a vendor specific event indicating the result of * the firmware loading.
*/ if (skb->len == 7 && hdr->evt == 0xff && hdr->plen == 0x05 &&
skb->data[2] == 0x06) { if (skb->data[3] != 0x00)
set_bit(STATE_FIRMWARE_FAILED, &intel->flags);
if (test_and_clear_bit(STATE_DOWNLOADING, &intel->flags) &&
test_bit(STATE_FIRMWARE_LOADED, &intel->flags))
wake_up_bit(&intel->flags, STATE_DOWNLOADING);
/* When switching to the operational firmware the device * sends a vendor specific event indicating that the bootup * completed.
*/
} elseif (skb->len == 9 && hdr->evt == 0xff && hdr->plen == 0x07 &&
skb->data[2] == 0x02) { if (test_and_clear_bit(STATE_BOOTING, &intel->flags))
wake_up_bit(&intel->flags, STATE_BOOTING);
}
recv: return hci_recv_frame(hdev, skb);
}
/* When the BTINTEL_HCI_OP_RESET command is issued to boot into * the operational firmware, it will actually not send a command * complete event. To keep the flow control working inject that * event here.
*/ if (opcode == BTINTEL_HCI_OP_RESET)
inject_cmd_complete(hu->hdev, opcode);
}
/* Prepend skb with frame type */
memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
dev_err(&pdev->dev, "No IRQ, falling back to gpio-irq\n");
host_wake = devm_gpiod_get(&pdev->dev, "host-wake", GPIOD_IN); if (IS_ERR(host_wake)) {
dev_err(&pdev->dev, "Unable to retrieve IRQ\n"); goto no_irq;
}
idev->irq = gpiod_to_irq(host_wake); if (idev->irq < 0) {
dev_err(&pdev->dev, "No corresponding irq for gpio\n"); goto no_irq;
}
}
/* Only enable wake-up/irq when controller is powered */
device_set_wakeup_capable(&pdev->dev, true);
device_wakeup_disable(&pdev->dev);
no_irq:
platform_set_drvdata(pdev, idev);
/* Place this instance on the device list */
mutex_lock(&intel_device_list_lock);
list_add_tail(&idev->list, &intel_device_list);
mutex_unlock(&intel_device_list_lock);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.