* [PATCH v2] Bluetooth: btintel: load unlocker.sfi to allow unsigned firmware
@ 2026-09-29 2:10 Kiran K
2026-09-29 6:59 ` [v2] " bluez.test.bot
2026-09-29 15:04 ` [PATCH v2] " Luiz Augusto von Dentz
0 siblings, 2 replies; 4+ messages in thread
From: Kiran K @ 2026-09-29 2:10 UTC (permalink / raw)
To: linux-bluetooth
Cc: chethan.tumkur.narayan, chandrashekar.devegowda, Kiran K,
Ravindra
When an unsigned operational firmware image is needed for debug, the
controller requires intel/unlocker.sfi to be loaded first. Without the
unlocker image, the controller rejects the unsigned operational firmware.
Support both firmware download flows based on the unlock policy advertised
in the version TLV:
BlazarI/BlazarIW/BlazarU/Gale Peak (unlock_policy == 0):
Boot ROM -> unlocker.sfi -> IML -> OPFW
Scorpius Peak onwards (unlock_policy == 1):
Boot ROM -> IML -> unlocker.sfi -> OPFW
Parse the new INTEL_TLV_UNLOCK_POLICY and INTEL_TLV_PLATFORM_ID TLVs
into struct intel_version_tlv, track the pending unlocker load through
a new btintel_data::unlocker flag, and pick intel/unlocker.sfi as the
firmware filename when that flag is set. If the unlocker image is not
present in the firmware search path, the driver silently falls through
to the normal firmware download path. If the unlocker image is present
but fails to download to the controller, the driver logs the error and
aborts bootloader setup, since continuing would leave the controller in
an inconsistent state.
[ 413.375247] Bluetooth: hci0: Found device firmware: intel/unlocker.sfi
[ 413.501051] Bluetooth: hci0: Waiting for firmware download to complete
[ 413.501058] Bluetooth: hci0: Firmware loaded in 122864 usecs
[ 413.501537] Bluetooth: hci0: Found device firmware: intel/ibt-02a2-01a1.sfi
[ 413.501547] Bluetooth: hci0: Boot Address: 0x10001000
[ 413.501548] Bluetooth: hci0: Firmware Version: 137-39.26
[ 414.103473] Bluetooth: hci0: Waiting for firmware download to complete
[ 414.103478] Bluetooth: hci0: Firmware loaded in 587841 usecs
[ 414.149576] Bluetooth: hci0: Applying Intel DDC parameters completed
[ 414.150089] Bluetooth: hci0: Firmware timestamp 2026.39 buildtype 3 build 86921
[ 414.150092] Bluetooth: hci0: Firmware SHA1: 0xeb2e0a4b
[ 414.150093] Bluetooth: hci0: Platform ID: 570c6ffbcbe6
[ 414.150094] Bluetooth: hci0: Fseq status: Success (0x00)
[ 414.150730] Bluetooth: hci0: Fseq executed: 15.255.00.98
[ 414.150734] Bluetooth: hci0: Fseq BT Top: 06.32.00.02
Assisted-by: Copilot:Claude Opus 4.7
Signed-off-by: Ravindra <ravindra@intel.com>
Signed-off-by: Kiran K <kiran.k@intel.com>
---
changes in v2:
- Updated commit message
drivers/bluetooth/btintel.c | 92 +++++++++++++++++++++++++++++++++++--
drivers/bluetooth/btintel.h | 5 ++
2 files changed, 93 insertions(+), 4 deletions(-)
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index f298c91f4f4e..3bcb13de1a4d 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -576,8 +576,13 @@ int btintel_version_info_tlv(struct hci_dev *hdev,
bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant,
2000 + (version->timestamp >> 8), version->timestamp & 0xff,
version->build_type, version->build_num);
- if (version->img_type == BTINTEL_IMG_OP)
+
+ if (version->img_type == BTINTEL_IMG_OP) {
bt_dev_info(hdev, "Firmware SHA1: 0x%8.8x", version->git_sha1);
+ bt_dev_info(hdev, "Platform ID: %6phN", version->platform_id);
+ }
+
+ bt_dev_info(hdev, "Unlock policy: 0x%2.2x", version->unlock_policy);
return 0;
}
@@ -604,11 +609,14 @@ static u8 btintel_version_tlv_min_len(u8 type)
case INTEL_TLV_DEBUG_LOCK:
case INTEL_TLV_LIMITED_CCE:
case INTEL_TLV_SBE_TYPE:
+ case INTEL_TLV_UNLOCK_POLICY:
return sizeof(u8);
case INTEL_TLV_MIN_FW:
return 3;
case INTEL_TLV_OTP_BDADDR:
return sizeof(bdaddr_t);
+ case INTEL_TLV_PLATFORM_ID:
+ return sizeof(((struct intel_version_tlv *)0)->platform_id);
default:
return 0;
}
@@ -716,6 +724,13 @@ int btintel_parse_version_tlv(struct hci_dev *hdev,
snprintf(version->fw_id, sizeof(version->fw_id),
"%.*s", tlv->len, tlv->val);
break;
+ case INTEL_TLV_UNLOCK_POLICY:
+ version->unlock_policy = tlv->val[0];
+ break;
+ case INTEL_TLV_PLATFORM_ID:
+ memcpy(version->platform_id, tlv->val,
+ sizeof(version->platform_id));
+ break;
default:
/* Ignore rest of information */
break;
@@ -2429,6 +2444,7 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
char fwname[128];
int err;
ktime_t calltime;
+ struct btintel_data *data = hci_get_priv(hdev);
if (!ver || !boot_param)
return -EINVAL;
@@ -2472,7 +2488,12 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
else
btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
} else {
- btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
+ if (data->unlocker) {
+ strscpy(fwname, "intel/unlocker.sfi");
+ data->unlocker = false;
+ } else {
+ btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
+ }
}
err = firmware_request_nowarn(&fw, fwname, &hdev->dev);
@@ -3489,6 +3510,36 @@ static int btintel_set_specific_absorption_rate(struct hci_dev *hdev,
return 0;
}
+/* Attempt to load intel/unlocker.sfi if it is present in the firmware
+ * search path. If the file is not available the device will be booted
+ * with a signed operational firmware, which is the common case, so its
+ * absence must be treated as normal and not logged as an error.
+ */
+static int btintel_try_load_unlocker(struct hci_dev *hdev,
+ struct intel_version_tlv *ver)
+{
+ struct btintel_data *data = hci_get_priv(hdev);
+ const struct firmware *fw;
+ u32 boot_param = 0;
+ int err;
+
+ err = firmware_request_nowarn(&fw, "intel/unlocker.sfi", &hdev->dev);
+ if (err) {
+ bt_dev_dbg(hdev, "intel/unlocker.sfi not present (%d), skipping unlocker load",
+ err);
+ return 0;
+ }
+ release_firmware(fw);
+
+ data->unlocker = true;
+ err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
+ if (err) {
+ bt_dev_err(hdev, "Failed to load intel/unlocker.sfi (%d)", err);
+ data->unlocker = false;
+ }
+ return err;
+}
+
int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
struct intel_version_tlv *ver)
{
@@ -3496,6 +3547,8 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
char ddcname[64];
int err;
struct intel_version_tlv new_ver;
+ struct btintel_data *data = hci_get_priv(hdev);
+ u8 hw_variant = INTEL_HW_VARIANT(ver->cnvi_bt);
bt_dev_dbg(hdev, "");
@@ -3514,6 +3567,26 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
btintel_set_flag(hdev, INTEL_BOOTLOADER);
+ data->unlocker = false;
+
+ /* Legacy unlocker flow (BlazarI / BlazarIW / BlazarU / Gale Peak):
+ * Boot ROM -> unlocker.sfi -> IML -> OPFW
+ */
+ if (ver->api_lock && ver->unlock_policy == 0) {
+ switch (hw_variant) {
+ case BTINTEL_HWID_BZRI:
+ case BTINTEL_HWID_BZRIW:
+ case BTINTEL_HWID_BZRU:
+ case BTINTEL_HWID_GAP:
+ err = btintel_try_load_unlocker(hdev, ver);
+ if (err)
+ return err;
+ break;
+ default:
+ break;
+ }
+ }
+
err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
if (err)
return err;
@@ -3537,8 +3610,19 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
return err;
}
- /* If image type returned is BTINTEL_IMG_IML, then controller supports
- * intermediate loader image
+ /* New unlocker flow (Scorpius Peak onwards):
+ * Boot ROM -> IML -> unlocker.sfi -> OPFW
+ */
+ if (hw_variant >= BTINTEL_HWID_SCP &&
+ ver->api_lock && ver->unlock_policy == 1) {
+ err = btintel_try_load_unlocker(hdev, ver);
+ if (err)
+ return err;
+ }
+
+ /* Transition to Operational Firmware
+ * If image type returned is BTINTEL_IMG_IML, then controller supports
+ * intermediate loader image.
*/
if (ver->img_type == BTINTEL_IMG_IML) {
err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
index ff7c1d623007..9526acf65959 100644
--- a/drivers/bluetooth/btintel.h
+++ b/drivers/bluetooth/btintel.h
@@ -43,6 +43,8 @@ enum {
INTEL_TLV_OTP_BDADDR,
INTEL_TLV_UNLOCKED_STATE,
INTEL_TLV_GIT_SHA1,
+ INTEL_TLV_UNLOCK_POLICY = 0x3c,
+ INTEL_TLV_PLATFORM_ID = 0x3d,
INTEL_TLV_FW_ID = 0x50
};
@@ -108,6 +110,8 @@ struct intel_version_tlv {
u32 git_sha1;
u8 fw_id[BTINTEL_FWID_MAXLEN];
bdaddr_t otp_bd_addr;
+ u8 unlock_policy;
+ u8 platform_id[6];
};
struct intel_version {
@@ -261,6 +265,7 @@ struct btintel_data {
DECLARE_BITMAP(flags, __INTEL_NUM_FLAGS);
int (*acpi_reset_method)(struct hci_dev *hdev);
u32 cnvi_bt;
+ bool unlocker;
};
#define btintel_set_flag(hdev, nr) \
--
2.54.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* RE: [v2] Bluetooth: btintel: load unlocker.sfi to allow unsigned firmware
2026-09-29 2:10 [PATCH v2] Bluetooth: btintel: load unlocker.sfi to allow unsigned firmware Kiran K
@ 2026-09-29 6:59 ` bluez.test.bot
2026-09-29 15:04 ` [PATCH v2] " Luiz Augusto von Dentz
1 sibling, 0 replies; 4+ messages in thread
From: bluez.test.bot @ 2026-09-29 6:59 UTC (permalink / raw)
To: linux-bluetooth, kiran.k
[-- Attachment #1: Type: text/plain, Size: 1301 bytes --]
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/series/1175689/
---Test result---
Test Summary:
CheckPatch PASS 0.86 seconds
VerifyFixes PASS 0.10 seconds
VerifySignedoff PASS 0.10 seconds
GitLint FAIL 0.28 seconds
SubjectPrefix PASS 0.09 seconds
BuildKernel PASS 29.10 seconds
CheckAllWarning PASS 33.15 seconds
CheckSparse PASS 35.38 seconds
BuildKernel32 PASS 29.08 seconds
CheckKernelLLVM PASS 36.56 seconds
TestRunnerSetup PASS 715.39 seconds
IncrementalBuild PASS 26.55 seconds
Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[v2] Bluetooth: btintel: load unlocker.sfi to allow unsigned firmware
35: B1 Line exceeds max length (82>80): "[ 414.150089] Bluetooth: hci0: Firmware timestamp 2026.39 buildtype 3 build 86921"
https://github.com/bluez/bluetooth-next/pull/835
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2] Bluetooth: btintel: load unlocker.sfi to allow unsigned firmware
2026-09-29 2:10 [PATCH v2] Bluetooth: btintel: load unlocker.sfi to allow unsigned firmware Kiran K
2026-09-29 6:59 ` [v2] " bluez.test.bot
@ 2026-09-29 15:04 ` Luiz Augusto von Dentz
2026-09-29 16:13 ` K, Kiran
1 sibling, 1 reply; 4+ messages in thread
From: Luiz Augusto von Dentz @ 2026-09-29 15:04 UTC (permalink / raw)
To: Kiran K
Cc: linux-bluetooth, chethan.tumkur.narayan, chandrashekar.devegowda,
Ravindra
Hi Kiran,
On Mon, Sep 28, 2026 at 9:50 PM Kiran K <kiran.k@intel.com> wrote:
>
> When an unsigned operational firmware image is needed for debug, the
> controller requires intel/unlocker.sfi to be loaded first. Without the
> unlocker image, the controller rejects the unsigned operational firmware.
>
> Support both firmware download flows based on the unlock policy advertised
> in the version TLV:
>
> BlazarI/BlazarIW/BlazarU/Gale Peak (unlock_policy == 0):
> Boot ROM -> unlocker.sfi -> IML -> OPFW
>
> Scorpius Peak onwards (unlock_policy == 1):
> Boot ROM -> IML -> unlocker.sfi -> OPFW
>
> Parse the new INTEL_TLV_UNLOCK_POLICY and INTEL_TLV_PLATFORM_ID TLVs
> into struct intel_version_tlv, track the pending unlocker load through
> a new btintel_data::unlocker flag, and pick intel/unlocker.sfi as the
> firmware filename when that flag is set. If the unlocker image is not
> present in the firmware search path, the driver silently falls through
> to the normal firmware download path. If the unlocker image is present
> but fails to download to the controller, the driver logs the error and
> aborts bootloader setup, since continuing would leave the controller in
> an inconsistent state.
>
> [ 413.375247] Bluetooth: hci0: Found device firmware: intel/unlocker.sfi
> [ 413.501051] Bluetooth: hci0: Waiting for firmware download to complete
> [ 413.501058] Bluetooth: hci0: Firmware loaded in 122864 usecs
> [ 413.501537] Bluetooth: hci0: Found device firmware: intel/ibt-02a2-01a1.sfi
> [ 413.501547] Bluetooth: hci0: Boot Address: 0x10001000
> [ 413.501548] Bluetooth: hci0: Firmware Version: 137-39.26
> [ 414.103473] Bluetooth: hci0: Waiting for firmware download to complete
> [ 414.103478] Bluetooth: hci0: Firmware loaded in 587841 usecs
> [ 414.149576] Bluetooth: hci0: Applying Intel DDC parameters completed
> [ 414.150089] Bluetooth: hci0: Firmware timestamp 2026.39 buildtype 3 build 86921
> [ 414.150092] Bluetooth: hci0: Firmware SHA1: 0xeb2e0a4b
> [ 414.150093] Bluetooth: hci0: Platform ID: 570c6ffbcbe6
> [ 414.150094] Bluetooth: hci0: Fseq status: Success (0x00)
> [ 414.150730] Bluetooth: hci0: Fseq executed: 15.255.00.98
> [ 414.150734] Bluetooth: hci0: Fseq BT Top: 06.32.00.02
>
> Assisted-by: Copilot:Claude Opus 4.7
> Signed-off-by: Ravindra <ravindra@intel.com>
> Signed-off-by: Kiran K <kiran.k@intel.com>
> ---
> changes in v2:
> - Updated commit message
>
> drivers/bluetooth/btintel.c | 92 +++++++++++++++++++++++++++++++++++--
> drivers/bluetooth/btintel.h | 5 ++
> 2 files changed, 93 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
> index f298c91f4f4e..3bcb13de1a4d 100644
> --- a/drivers/bluetooth/btintel.c
> +++ b/drivers/bluetooth/btintel.c
> @@ -576,8 +576,13 @@ int btintel_version_info_tlv(struct hci_dev *hdev,
> bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant,
> 2000 + (version->timestamp >> 8), version->timestamp & 0xff,
> version->build_type, version->build_num);
> - if (version->img_type == BTINTEL_IMG_OP)
> +
> + if (version->img_type == BTINTEL_IMG_OP) {
> bt_dev_info(hdev, "Firmware SHA1: 0x%8.8x", version->git_sha1);
> + bt_dev_info(hdev, "Platform ID: %6phN", version->platform_id);
> + }
> +
> + bt_dev_info(hdev, "Unlock policy: 0x%2.2x", version->unlock_policy);
>
> return 0;
> }
> @@ -604,11 +609,14 @@ static u8 btintel_version_tlv_min_len(u8 type)
> case INTEL_TLV_DEBUG_LOCK:
> case INTEL_TLV_LIMITED_CCE:
> case INTEL_TLV_SBE_TYPE:
> + case INTEL_TLV_UNLOCK_POLICY:
> return sizeof(u8);
> case INTEL_TLV_MIN_FW:
> return 3;
> case INTEL_TLV_OTP_BDADDR:
> return sizeof(bdaddr_t);
> + case INTEL_TLV_PLATFORM_ID:
> + return sizeof(((struct intel_version_tlv *)0)->platform_id);
> default:
> return 0;
> }
> @@ -716,6 +724,13 @@ int btintel_parse_version_tlv(struct hci_dev *hdev,
> snprintf(version->fw_id, sizeof(version->fw_id),
> "%.*s", tlv->len, tlv->val);
> break;
> + case INTEL_TLV_UNLOCK_POLICY:
> + version->unlock_policy = tlv->val[0];
> + break;
> + case INTEL_TLV_PLATFORM_ID:
> + memcpy(version->platform_id, tlv->val,
> + sizeof(version->platform_id));
> + break;
> default:
> /* Ignore rest of information */
> break;
> @@ -2429,6 +2444,7 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
> char fwname[128];
> int err;
> ktime_t calltime;
> + struct btintel_data *data = hci_get_priv(hdev);
>
> if (!ver || !boot_param)
> return -EINVAL;
> @@ -2472,7 +2488,12 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
> else
> btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
> } else {
> - btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
> + if (data->unlocker) {
> + strscpy(fwname, "intel/unlocker.sfi");
> + data->unlocker = false;
> + } else {
> + btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
> + }
> }
>
> err = firmware_request_nowarn(&fw, fwname, &hdev->dev);
> @@ -3489,6 +3510,36 @@ static int btintel_set_specific_absorption_rate(struct hci_dev *hdev,
> return 0;
> }
>
> +/* Attempt to load intel/unlocker.sfi if it is present in the firmware
> + * search path. If the file is not available the device will be booted
> + * with a signed operational firmware, which is the common case, so its
> + * absence must be treated as normal and not logged as an error.
> + */
> +static int btintel_try_load_unlocker(struct hci_dev *hdev,
> + struct intel_version_tlv *ver)
> +{
> + struct btintel_data *data = hci_get_priv(hdev);
> + const struct firmware *fw;
> + u32 boot_param = 0;
> + int err;
> +
> + err = firmware_request_nowarn(&fw, "intel/unlocker.sfi", &hdev->dev);
> + if (err) {
> + bt_dev_dbg(hdev, "intel/unlocker.sfi not present (%d), skipping unlocker load",
> + err);
> + return 0;
> + }
> + release_firmware(fw);
> +
> + data->unlocker = true;
> + err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
> + if (err) {
> + bt_dev_err(hdev, "Failed to load intel/unlocker.sfi (%d)", err);
> + data->unlocker = false;
> + }
> + return err;
> +}
> +
> int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
> struct intel_version_tlv *ver)
> {
> @@ -3496,6 +3547,8 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
> char ddcname[64];
> int err;
> struct intel_version_tlv new_ver;
> + struct btintel_data *data = hci_get_priv(hdev);
> + u8 hw_variant = INTEL_HW_VARIANT(ver->cnvi_bt);
>
> bt_dev_dbg(hdev, "");
>
> @@ -3514,6 +3567,26 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
>
> btintel_set_flag(hdev, INTEL_BOOTLOADER);
>
> + data->unlocker = false;
> +
> + /* Legacy unlocker flow (BlazarI / BlazarIW / BlazarU / Gale Peak):
> + * Boot ROM -> unlocker.sfi -> IML -> OPFW
> + */
> + if (ver->api_lock && ver->unlock_policy == 0) {
> + switch (hw_variant) {
> + case BTINTEL_HWID_BZRI:
> + case BTINTEL_HWID_BZRIW:
> + case BTINTEL_HWID_BZRU:
> + case BTINTEL_HWID_GAP:
> + err = btintel_try_load_unlocker(hdev, ver);
> + if (err)
> + return err;
> + break;
> + default:
> + break;
> + }
> + }
> +
> err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
> if (err)
> return err;
> @@ -3537,8 +3610,19 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
> return err;
> }
>
> - /* If image type returned is BTINTEL_IMG_IML, then controller supports
> - * intermediate loader image
> + /* New unlocker flow (Scorpius Peak onwards):
> + * Boot ROM -> IML -> unlocker.sfi -> OPFW
> + */
> + if (hw_variant >= BTINTEL_HWID_SCP &&
> + ver->api_lock && ver->unlock_policy == 1) {
> + err = btintel_try_load_unlocker(hdev, ver);
> + if (err)
> + return err;
> + }
> +
> + /* Transition to Operational Firmware
> + * If image type returned is BTINTEL_IMG_IML, then controller supports
> + * intermediate loader image.
> */
> if (ver->img_type == BTINTEL_IMG_IML) {
> err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
> diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
> index ff7c1d623007..9526acf65959 100644
> --- a/drivers/bluetooth/btintel.h
> +++ b/drivers/bluetooth/btintel.h
> @@ -43,6 +43,8 @@ enum {
> INTEL_TLV_OTP_BDADDR,
> INTEL_TLV_UNLOCKED_STATE,
> INTEL_TLV_GIT_SHA1,
> + INTEL_TLV_UNLOCK_POLICY = 0x3c,
> + INTEL_TLV_PLATFORM_ID = 0x3d,
> INTEL_TLV_FW_ID = 0x50
> };
>
> @@ -108,6 +110,8 @@ struct intel_version_tlv {
> u32 git_sha1;
> u8 fw_id[BTINTEL_FWID_MAXLEN];
> bdaddr_t otp_bd_addr;
> + u8 unlock_policy;
> + u8 platform_id[6];
> };
>
> struct intel_version {
> @@ -261,6 +265,7 @@ struct btintel_data {
> DECLARE_BITMAP(flags, __INTEL_NUM_FLAGS);
> int (*acpi_reset_method)(struct hci_dev *hdev);
> u32 cnvi_bt;
> + bool unlocker;
> };
>
> #define btintel_set_flag(hdev, nr) \
> --
> 2.54.0
There are some comments from sashiko that we need to clear:
https://sashiko.dev/#/patchset/20260929021056.1396791-1-kiran.k%40intel.com
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 4+ messages in thread
* RE: [PATCH v2] Bluetooth: btintel: load unlocker.sfi to allow unsigned firmware
2026-09-29 15:04 ` [PATCH v2] " Luiz Augusto von Dentz
@ 2026-09-29 16:13 ` K, Kiran
0 siblings, 0 replies; 4+ messages in thread
From: K, Kiran @ 2026-09-29 16:13 UTC (permalink / raw)
To: Luiz Augusto von Dentz
Cc: linux-bluetooth@vger.kernel.org, Tumkur Narayan, Chethan,
Devegowda, Chandrashekar, Ravindra
Hi Luiz,
>Subject: Re: [PATCH v2] Bluetooth: btintel: load unlocker.sfi to allow unsigned
>firmware
>
>Hi Kiran,
>
>On Mon, Sep 28, 2026 at 9:50 PM Kiran K <kiran.k@intel.com> wrote:
>>
>> When an unsigned operational firmware image is needed for debug, the
>> controller requires intel/unlocker.sfi to be loaded first. Without the
>> unlocker image, the controller rejects the unsigned operational firmware.
>>
>> Support both firmware download flows based on the unlock policy
>> advertised in the version TLV:
>>
>> BlazarI/BlazarIW/BlazarU/Gale Peak (unlock_policy == 0):
>> Boot ROM -> unlocker.sfi -> IML -> OPFW
>>
>> Scorpius Peak onwards (unlock_policy == 1):
>> Boot ROM -> IML -> unlocker.sfi -> OPFW
>>
>> Parse the new INTEL_TLV_UNLOCK_POLICY and INTEL_TLV_PLATFORM_ID
>TLVs
>> into struct intel_version_tlv, track the pending unlocker load through
>> a new btintel_data::unlocker flag, and pick intel/unlocker.sfi as the
>> firmware filename when that flag is set. If the unlocker image is not
>> present in the firmware search path, the driver silently falls through
>> to the normal firmware download path. If the unlocker image is present
>> but fails to download to the controller, the driver logs the error and
>> aborts bootloader setup, since continuing would leave the controller
>> in an inconsistent state.
>>
>> [ 413.375247] Bluetooth: hci0: Found device firmware:
>> intel/unlocker.sfi [ 413.501051] Bluetooth: hci0: Waiting for
>> firmware download to complete [ 413.501058] Bluetooth: hci0: Firmware
>> loaded in 122864 usecs [ 413.501537] Bluetooth: hci0: Found device
>> firmware: intel/ibt-02a2-01a1.sfi [ 413.501547] Bluetooth: hci0: Boot
>> Address: 0x10001000 [ 413.501548] Bluetooth: hci0: Firmware Version:
>> 137-39.26 [ 414.103473] Bluetooth: hci0: Waiting for firmware
>> download to complete [ 414.103478] Bluetooth: hci0: Firmware loaded
>> in 587841 usecs [ 414.149576] Bluetooth: hci0: Applying Intel DDC
>> parameters completed [ 414.150089] Bluetooth: hci0: Firmware
>> timestamp 2026.39 buildtype 3 build 86921 [ 414.150092] Bluetooth:
>> hci0: Firmware SHA1: 0xeb2e0a4b [ 414.150093] Bluetooth: hci0:
>> Platform ID: 570c6ffbcbe6 [ 414.150094] Bluetooth: hci0: Fseq status:
>> Success (0x00) [ 414.150730] Bluetooth: hci0: Fseq executed:
>> 15.255.00.98 [ 414.150734] Bluetooth: hci0: Fseq BT Top: 06.32.00.02
>>
>> Assisted-by: Copilot:Claude Opus 4.7
>> Signed-off-by: Ravindra <ravindra@intel.com>
>> Signed-off-by: Kiran K <kiran.k@intel.com>
>> ---
>> changes in v2:
>> - Updated commit message
>>
>> drivers/bluetooth/btintel.c | 92
>> +++++++++++++++++++++++++++++++++++--
>> drivers/bluetooth/btintel.h | 5 ++
>> 2 files changed, 93 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
>> index f298c91f4f4e..3bcb13de1a4d 100644
>> --- a/drivers/bluetooth/btintel.c
>> +++ b/drivers/bluetooth/btintel.c
>> @@ -576,8 +576,13 @@ int btintel_version_info_tlv(struct hci_dev *hdev,
>> bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u",
>variant,
>> 2000 + (version->timestamp >> 8), version->timestamp & 0xff,
>> version->build_type, version->build_num);
>> - if (version->img_type == BTINTEL_IMG_OP)
>> +
>> + if (version->img_type == BTINTEL_IMG_OP) {
>> bt_dev_info(hdev, "Firmware SHA1: 0x%8.8x",
>> version->git_sha1);
>> + bt_dev_info(hdev, "Platform ID: %6phN", version->platform_id);
>> + }
>> +
>> + bt_dev_info(hdev, "Unlock policy: 0x%2.2x",
>> + version->unlock_policy);
>>
>> return 0;
>> }
>> @@ -604,11 +609,14 @@ static u8 btintel_version_tlv_min_len(u8 type)
>> case INTEL_TLV_DEBUG_LOCK:
>> case INTEL_TLV_LIMITED_CCE:
>> case INTEL_TLV_SBE_TYPE:
>> + case INTEL_TLV_UNLOCK_POLICY:
>> return sizeof(u8);
>> case INTEL_TLV_MIN_FW:
>> return 3;
>> case INTEL_TLV_OTP_BDADDR:
>> return sizeof(bdaddr_t);
>> + case INTEL_TLV_PLATFORM_ID:
>> + return sizeof(((struct intel_version_tlv
>> + *)0)->platform_id);
>> default:
>> return 0;
>> }
>> @@ -716,6 +724,13 @@ int btintel_parse_version_tlv(struct hci_dev *hdev,
>> snprintf(version->fw_id, sizeof(version->fw_id),
>> "%.*s", tlv->len, tlv->val);
>> break;
>> + case INTEL_TLV_UNLOCK_POLICY:
>> + version->unlock_policy = tlv->val[0];
>> + break;
>> + case INTEL_TLV_PLATFORM_ID:
>> + memcpy(version->platform_id, tlv->val,
>> + sizeof(version->platform_id));
>> + break;
>> default:
>> /* Ignore rest of information */
>> break;
>> @@ -2429,6 +2444,7 @@ static int btintel_prepare_fw_download_tlv(struct
>hci_dev *hdev,
>> char fwname[128];
>> int err;
>> ktime_t calltime;
>> + struct btintel_data *data = hci_get_priv(hdev);
>>
>> if (!ver || !boot_param)
>> return -EINVAL;
>> @@ -2472,7 +2488,12 @@ static int btintel_prepare_fw_download_tlv(struct
>hci_dev *hdev,
>> else
>> btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
>> } else {
>> - btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
>> + if (data->unlocker) {
>> + strscpy(fwname, "intel/unlocker.sfi");
>> + data->unlocker = false;
>> + } else {
>> + btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
>> + }
>> }
>>
>> err = firmware_request_nowarn(&fw, fwname, &hdev->dev); @@
>> -3489,6 +3510,36 @@ static int btintel_set_specific_absorption_rate(struct
>hci_dev *hdev,
>> return 0;
>> }
>>
>> +/* Attempt to load intel/unlocker.sfi if it is present in the
>> +firmware
>> + * search path. If the file is not available the device will be
>> +booted
>> + * with a signed operational firmware, which is the common case, so
>> +its
>> + * absence must be treated as normal and not logged as an error.
>> + */
>> +static int btintel_try_load_unlocker(struct hci_dev *hdev,
>> + struct intel_version_tlv *ver) {
>> + struct btintel_data *data = hci_get_priv(hdev);
>> + const struct firmware *fw;
>> + u32 boot_param = 0;
>> + int err;
>> +
>> + err = firmware_request_nowarn(&fw, "intel/unlocker.sfi", &hdev->dev);
>> + if (err) {
>> + bt_dev_dbg(hdev, "intel/unlocker.sfi not present (%d), skipping
>unlocker load",
>> + err);
>> + return 0;
>> + }
>> + release_firmware(fw);
>> +
>> + data->unlocker = true;
>> + err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
>> + if (err) {
>> + bt_dev_err(hdev, "Failed to load intel/unlocker.sfi (%d)", err);
>> + data->unlocker = false;
>> + }
>> + return err;
>> +}
>> +
>> int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
>> struct intel_version_tlv *ver) { @@
>> -3496,6 +3547,8 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
>> char ddcname[64];
>> int err;
>> struct intel_version_tlv new_ver;
>> + struct btintel_data *data = hci_get_priv(hdev);
>> + u8 hw_variant = INTEL_HW_VARIANT(ver->cnvi_bt);
>>
>> bt_dev_dbg(hdev, "");
>>
>> @@ -3514,6 +3567,26 @@ int btintel_bootloader_setup_tlv(struct hci_dev
>> *hdev,
>>
>> btintel_set_flag(hdev, INTEL_BOOTLOADER);
>>
>> + data->unlocker = false;
>> +
>> + /* Legacy unlocker flow (BlazarI / BlazarIW / BlazarU / Gale Peak):
>> + * Boot ROM -> unlocker.sfi -> IML -> OPFW
>> + */
>> + if (ver->api_lock && ver->unlock_policy == 0) {
>> + switch (hw_variant) {
>> + case BTINTEL_HWID_BZRI:
>> + case BTINTEL_HWID_BZRIW:
>> + case BTINTEL_HWID_BZRU:
>> + case BTINTEL_HWID_GAP:
>> + err = btintel_try_load_unlocker(hdev, ver);
>> + if (err)
>> + return err;
>> + break;
>> + default:
>> + break;
>> + }
>> + }
>> +
>> err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
>> if (err)
>> return err;
>> @@ -3537,8 +3610,19 @@ int btintel_bootloader_setup_tlv(struct hci_dev
>*hdev,
>> return err;
>> }
>>
>> - /* If image type returned is BTINTEL_IMG_IML, then controller supports
>> - * intermediate loader image
>> + /* New unlocker flow (Scorpius Peak onwards):
>> + * Boot ROM -> IML -> unlocker.sfi -> OPFW
>> + */
>> + if (hw_variant >= BTINTEL_HWID_SCP &&
>> + ver->api_lock && ver->unlock_policy == 1) {
>> + err = btintel_try_load_unlocker(hdev, ver);
>> + if (err)
>> + return err;
>> + }
>> +
>> + /* Transition to Operational Firmware
>> + * If image type returned is BTINTEL_IMG_IML, then controller supports
>> + * intermediate loader image.
>> */
>> if (ver->img_type == BTINTEL_IMG_IML) {
>> err = btintel_prepare_fw_download_tlv(hdev, ver,
>> &boot_param); diff --git a/drivers/bluetooth/btintel.h
>> b/drivers/bluetooth/btintel.h index ff7c1d623007..9526acf65959 100644
>> --- a/drivers/bluetooth/btintel.h
>> +++ b/drivers/bluetooth/btintel.h
>> @@ -43,6 +43,8 @@ enum {
>> INTEL_TLV_OTP_BDADDR,
>> INTEL_TLV_UNLOCKED_STATE,
>> INTEL_TLV_GIT_SHA1,
>> + INTEL_TLV_UNLOCK_POLICY = 0x3c,
>> + INTEL_TLV_PLATFORM_ID = 0x3d,
>> INTEL_TLV_FW_ID = 0x50
>> };
>>
>> @@ -108,6 +110,8 @@ struct intel_version_tlv {
>> u32 git_sha1;
>> u8 fw_id[BTINTEL_FWID_MAXLEN];
>> bdaddr_t otp_bd_addr;
>> + u8 unlock_policy;
>> + u8 platform_id[6];
>> };
>>
>> struct intel_version {
>> @@ -261,6 +265,7 @@ struct btintel_data {
>> DECLARE_BITMAP(flags, __INTEL_NUM_FLAGS);
>> int (*acpi_reset_method)(struct hci_dev *hdev);
>> u32 cnvi_bt;
>> + bool unlocker;
>> };
>>
>> #define btintel_set_flag(hdev, nr) \
>> --
>> 2.54.0
>
>There are some comments from sashiko that we need to clear:
>
>https://sashiko.dev/#/patchset/20260929021056.1396791-1-
>kiran.k%40intel.com
Comment[1]: Ack. I will fix it v3 version of the patch.
Comment[2]:
In case of PCIe, this comment is not applicable. The controller is
always present in bootmode when btintel_bootloader_setup_tlv() runs,
because the driver invokes a shared hardware reset during driver
unbound.
In case of USB transport, if the controller is already in OP mode,
then the driver shall not attempt to load the unlocker. The unlocker
flow is gated on the bootloader path, so the else branch is the only
path taken while data->unlocker is set, and the flag cannot leak into
a later call within the same setup.
Comment[3]:
In case of USB, the controller can already be in OP mode. In that
path btintel_try_load_unlocker() would end up calling
btintel_prepare_fw_download_tlv(), which takes the BTINTEL_IMG_OP
branch and ignores data->unlocker, so it does not actually download
intel/unlocker.sfi. The firmware_request_nowarn() lookup for
intel/unlocker.sfi and the extra work is indeed spurious.
I'll gate both the legacy and the new unlocker paths on
ver->img_type != BTINTEL_IMG_OP in v3 so the check is skipped when
the controller is already running operational firmware.
>
>
>--
>Luiz Augusto von Dentz
Thanks,
Kiran
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-29 16:13 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-29 2:10 [PATCH v2] Bluetooth: btintel: load unlocker.sfi to allow unsigned firmware Kiran K
2026-09-29 6:59 ` [v2] " bluez.test.bot
2026-09-29 15:04 ` [PATCH v2] " Luiz Augusto von Dentz
2026-09-29 16:13 ` K, Kiran
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox