Bluetooth: btintel: read ROM debug registers on FW download failure

The bootloader records init sequence progress and debug info in four
core debug registers, useful for debugging FW download failures.

Add btintel_get_rom_debug_info() to issue BTINTEL_GET_ROM_DEBUG_INFO
(0xfcde) and log these registers, and invoke it from every FW download
failure and timeout path: btintel_download_fw() (legacy .sfi flow) and
btintel_prepare_fw_download_tlv() (TLV flow), before resetting to the
bootloader.

Tested by corrupting the operational firmware file to force a
download timeout; the driver logged the debug registers on each
failure and retry, e.g.:

  Bluetooth: hci0: Firmware loading timeout
  Bluetooth: Intel get rom debug info: dr0:0x80000001 dr1:0x00000000 dr2:0x00000001 dr3:0x00df0071

Signed-off-by: Ravindra <ravindra@intel.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Ravindra 2026-09-21 11:18:30 +05:30 committed by Luiz Augusto von Dentz
parent c4154fc347
commit eb2a7f1bc8
2 changed files with 54 additions and 2 deletions

View File

@ -972,6 +972,41 @@ int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param)
}
EXPORT_SYMBOL_GPL(btintel_send_intel_reset);
static void btintel_get_rom_debug_info(struct hci_dev *hdev)
{
struct btintel_rp_get_rom_debug_info *rom_debug_info;
struct sk_buff *skb;
skb = __hci_cmd_sync(hdev, BTINTEL_GET_ROM_DEBUG_INFO, 0, NULL,
HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Failed to send Intel get rom debug info command (%ld)",
PTR_ERR(skb));
return;
}
if (skb->len != sizeof(*rom_debug_info)) {
bt_dev_err(hdev,
"Intel get rom debug info size mismatch (%u != %zu)",
skb->len, sizeof(*rom_debug_info));
kfree_skb(skb);
return;
}
rom_debug_info = (struct btintel_rp_get_rom_debug_info *)skb->data;
/* A non-zero status here would have already been turned into an
* error by the HCI core and reported via the IS_ERR(skb) check above.
*/
bt_dev_info(hdev, "Intel get rom debug info: dr0:0x%08x dr1:0x%08x dr2:0x%08x dr3:0x%08x",
le32_to_cpu(rom_debug_info->debug_reg0),
le32_to_cpu(rom_debug_info->debug_reg1),
le32_to_cpu(rom_debug_info->debug_reg2),
le32_to_cpu(rom_debug_info->debug_reg3));
kfree_skb(skb);
}
int btintel_read_boot_params(struct hci_dev *hdev,
struct intel_boot_params *params)
{
@ -2221,6 +2256,8 @@ static int btintel_download_fw(struct hci_dev *hdev,
goto done;
}
btintel_get_rom_debug_info(hdev);
/* When FW download fails, send Intel Reset to retry
* FW download.
*/
@ -2240,8 +2277,10 @@ static int btintel_download_fw(struct hci_dev *hdev,
* of this device.
*/
err = btintel_download_wait(hdev, calltime, 5000);
if (err == -ETIMEDOUT)
if (err == -ETIMEDOUT) {
btintel_get_rom_debug_info(hdev);
btintel_reset_to_bootloader(hdev);
}
done:
release_firmware(fw);
@ -2474,6 +2513,8 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
goto done;
}
btintel_get_rom_debug_info(hdev);
/* When FW download fails, send Intel Reset to retry
* FW download.
*/
@ -2493,8 +2534,10 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
* of this device.
*/
err = btintel_download_wait(hdev, calltime, 5000);
if (err == -ETIMEDOUT)
if (err == -ETIMEDOUT) {
btintel_get_rom_debug_info(hdev);
btintel_reset_to_bootloader(hdev);
}
done:
intel_data->cnvi_bt = ver->cnvi_bt;

View File

@ -178,6 +178,15 @@ struct hci_ppag_enable_cmd {
__le32 ppag_enable_flags;
} __packed;
#define BTINTEL_GET_ROM_DEBUG_INFO 0xfcde
struct btintel_rp_get_rom_debug_info {
__u8 status;
__le32 debug_reg0;
__le32 debug_reg1;
__le32 debug_reg2;
__le32 debug_reg3;
} __packed;
#define INTEL_TLV_TYPE_ID 0x01
#define INTEL_TLV_SYSTEM_EXCEPTION 0x00