| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/10/14 11:44 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "The patch series modifies the btintel_pcie driver and introduces the btintel_pcie_debug module, which implements runtime debug configuration (YoYo) for Intel Bluetooth PCIe controllers. This driver binds specifically to physical Intel PCIe hardware (such as Lunar Lake, Panther Lake, Nova Lake, Blazar) that is not emulated in standard QEMU or GCE virtualized environments. Because the hardware is structurally unreachable during standard kernel fuzzing, the modified code cannot be executed.",
"WorthFuzzing": false
} |
| 1/1 | 2026/10/14 11:44 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit cf67a365d111ae83083862ed2f92b6c6271be6fa\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Wed Oct 14 11:44:30 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile\nindex d5eb2568af2e9..7d933755b2916 100644\n--- a/drivers/bluetooth/Makefile\n+++ b/drivers/bluetooth/Makefile\n@@ -14,7 +14,7 @@ obj-$(CONFIG_BT_HCIBTUSB)\t+= btusb.o\n obj-$(CONFIG_BT_HCIBTSDIO)\t+= btsdio.o\n \n obj-$(CONFIG_BT_INTEL)\t\t+= btintel.o\n-obj-$(CONFIG_BT_INTEL_PCIE)\t+= btintel_pcie.o btintel.o\n+obj-$(CONFIG_BT_INTEL_PCIE)\t+= btintel_pcie.o btintel.o btintel_pcie_debug.o\n obj-$(CONFIG_BT_ATH3K)\t\t+= ath3k.o\n obj-$(CONFIG_BT_MRVL)\t\t+= btmrvl.o\n obj-$(CONFIG_BT_MRVL_SDIO)\t+= btmrvl_sdio.o\ndiff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c\nindex 3a555aa50c873..aae8c0c833917 100644\n--- a/drivers/bluetooth/btintel_pcie.c\n+++ b/drivers/bluetooth/btintel_pcie.c\n@@ -203,6 +203,103 @@ static inline bool btintel_pcie_dbg_to_wifi(struct btintel_pcie_data *data)\n \treturn data-\u003edbg_path_cache != BTINTEL_PCIE_DRAM;\n }\n \n+/* Name of the optional INI file used to override the default dbg_path\n+ * (data-\u003edbg_path_cache) and yoyo ini settings.\n+ */\n+#define BTINTEL_PCIE_DBG_INI_FILE \"ibt_bt_dbg_cfg.ini\"\n+\n+/* Loads optional \"DBG_PATH=\u003cvalue\u003e\" and ENABLE_INI=\u003cvalue\u003e\n+ * overrides from BTINTEL_PCIE_DBG_INI_FILE\n+ * and applies them to data-\u003edbg_path_cache and data-\u003eenable_ini.\n+ *\n+ * DBG_PATH accepts BTINTEL_PCIE_WIFI_DBGC (0x06, default) and\n+ * BTINTEL_PCIE_DRAM (0x01, legacy); an invalid or missing entry leaves\n+ * the cached value set by the caller unchanged.\n+ *\n+ * ENABLE_INI accepts 1 (enabled) or 0 (disabled); an invalid or missing\n+ * entry leaves data-\u003eenable_ini unchanged.\n+ */\n+static void btintel_pcie_load_dbg_path_from_ini(struct btintel_pcie_data *data)\n+{\n+\tconst struct firmware *fw;\n+\tconst char *ini_file = BTINTEL_PCIE_DBG_INI_FILE;\n+\tchar *buf, *cursor, *line;\n+\tbool dbg_path_applied = false;\n+\tint err;\n+\n+\terr = request_firmware_direct(\u0026fw, ini_file, \u0026data-\u003epdev-\u003edev);\n+\tif (err \u003c 0) {\n+\t\tBT_DBG(\"%s not found (%d), using dbg_path=0x%02x\",\n+\t\t ini_file, err, data-\u003edbg_path_cache);\n+\t\treturn;\n+\t}\n+\n+\tbuf = kmemdup_nul(fw-\u003edata, fw-\u003esize, GFP_KERNEL);\n+\trelease_firmware(fw);\n+\tif (!buf)\n+\t\treturn;\n+\n+\tcursor = buf;\n+\twhile ((line = strsep(\u0026cursor, \"\\n\"))) {\n+\t\tchar *eq;\n+\t\tchar *val;\n+\t\tuint parsed;\n+\n+\t\tline = strim(line);\n+\t\tif (!line[0] || line[0] == '#' || line[0] == ';')\n+\t\t\tcontinue;\n+\n+\t\teq = strchr(line, '=');\n+\t\tif (!eq)\n+\t\t\tcontinue;\n+\n+\t\t*eq = '\\0';\n+\t\tline = strim(line);\n+\t\tval = strim(eq + 1);\n+\n+\t\t/* Accept \"DBG_PATH\"/\"dbg_path\"\n+\t\t * case-insensitively as the key.\n+\t\t */\n+\t\tif (!strcasecmp(line, \"DBG_PATH\")) {\n+\t\t\tBT_INFO(\"Read DBG_PATH from %s: '%s'\", ini_file, val);\n+\n+\t\t\t/* base 0 lets kstrtouint accept \"0x06\", \"6\", etc. */\n+\t\t\tif (kstrtouint(val, 0, \u0026parsed) == 0 \u0026\u0026\n+\t\t\t (parsed == BTINTEL_PCIE_DRAM ||\n+\t\t\t parsed == BTINTEL_PCIE_WIFI_DBGC)) {\n+\t\t\t\tdata-\u003edbg_path_cache = parsed;\n+\t\t\t\tdbg_path_applied = true;\n+\t\t\t\tBT_INFO(\"WRT dbg_path accepted: 0x%02x\",\n+\t\t\t\t\tdata-\u003edbg_path_cache);\n+\t\t\t} else {\n+\t\t\t\tBT_WARN(\"Invalid DBG_PATH='%s' in %s, using dbg_path=0x%02x\",\n+\t\t\t\t\tval, ini_file, data-\u003edbg_path_cache);\n+\t\t\t}\n+\t\t} else if (!strcasecmp(line, \"ENABLE_INI\")) {\n+\t\t\tBT_INFO(\"Read ENABLE_INI from %s: '%s'\", ini_file, val);\n+\n+\t\t\tif (kstrtouint(val, 0, \u0026parsed) == 0 \u0026\u0026\n+\t\t\t (parsed == 0 || parsed == 1)) {\n+\t\t\t\tdata-\u003eenable_ini = !!parsed;\n+\t\t\t\tBT_INFO(\"WRT enable_ini accepted: %u\",\n+\t\t\t\t\tdata-\u003eenable_ini);\n+\t\t\t} else {\n+\t\t\t\tBT_WARN(\"Invalid ENABLE_INI='%s' in %s, using enable_ini=%u\",\n+\t\t\t\t\tval, ini_file, data-\u003eenable_ini);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (dbg_path_applied)\n+\t\tBT_DBG(\"Loaded dbg_path=0x%02x from %s\", data-\u003edbg_path_cache, ini_file);\n+\telse\n+\t\tBT_WARN(\"No valid DBG_PATH in %s, dbg_path=0x%02x\", ini_file, data-\u003edbg_path_cache);\n+\n+\tBT_DBG(\"ENABLE_INI effective state: %u\", data-\u003eenable_ini);\n+\n+\tkfree(buf);\n+}\n+\n /* Helper function to allocate and setup a debug buffer group\n * @data: driver data structure\n * @buf: pointer to data_buf array pointer\n@@ -218,7 +315,8 @@ static int btintel_pcie_alloc_dbgc_buf(struct btintel_pcie_data *data,\n \t\t\t\t void **v_addr,\n \t\t\t\t struct btintel_pcie_dbgc_ctxt_buf *frag,\n \t\t\t\t u32 buf_index,\n-\t\t\t\t u32 buf_count)\n+\t\t\t\t u32 buf_count,\n+\t\t\t\t u32 per_buf_size)\n {\n \tstruct data_buf *b;\n \tint i;\n@@ -231,8 +329,7 @@ static int btintel_pcie_alloc_dbgc_buf(struct btintel_pcie_data *data,\n \t}\n \n \t*v_addr = dmam_alloc_coherent(\u0026data-\u003epdev-\u003edev,\n-\t\t\t\t buf_count *\n-\t\t\t\t\tBTINTEL_PCIE_DBGC_BUFFER_SIZE,\n+\t\t\t\t buf_count * per_buf_size,\n \t\t\t\t\tp_addr,\n \t\t\t\t\tGFP_KERNEL | __GFP_NOWARN);\n \tif (!*v_addr) {\n@@ -242,16 +339,40 @@ static int btintel_pcie_alloc_dbgc_buf(struct btintel_pcie_data *data,\n \n \tfor (i = 0; i \u003c buf_count; i++) {\n \t\tb = \u0026(*buf)[i];\n-\t\tb-\u003edata_p_addr = *p_addr + i * BTINTEL_PCIE_DBGC_BUFFER_SIZE;\n-\t\tb-\u003edata = *v_addr + i * BTINTEL_PCIE_DBGC_BUFFER_SIZE;\n+\t\tb-\u003edata_p_addr = *p_addr + i * per_buf_size;\n+\t\tb-\u003edata = *v_addr + i * per_buf_size;\n \t\tfrag[i].buf_addr_lsb = lower_32_bits(b-\u003edata_p_addr);\n \t\tfrag[i].buf_addr_msb = upper_32_bits(b-\u003edata_p_addr);\n-\t\tfrag[i].buf_size = BTINTEL_PCIE_DBGC_BUFFER_SIZE;\n+\t\tfrag[i].buf_size = per_buf_size;\n \t}\n \n+\tBT_INFO(\"dbgc buf %u allocated: frag_num=%u per_buf_size=%u total_size=%u\",\n+\t\tbuf_index + 1, buf_count, per_buf_size, buf_count * per_buf_size);\n+\n \treturn 0;\n }\n \n+/* Returns false if YoYo is enabled and @alloc_id is not configured */\n+static bool btintel_pcie_get_mdbgc_cfg(struct btintel_pcie_data *data,\n+\t\t\t\t u32 alloc_id, u32 *count, u32 *size)\n+{\n+\tconst struct btintel_pcie_buf_alloc *ba;\n+\n+\tba = btintel_pcie_yoyo_get_buf_alloc(\u0026data-\u003eyoyo, alloc_id);\n+\tif (ba) {\n+\t\t*count = ba-\u003emax_num_frags;\n+\t\t*size = ba-\u003ereq_buf_size / ba-\u003emax_num_frags;\n+\t\treturn true;\n+\t}\n+\n+\tif (data-\u003eyoyo.enabled)\n+\t\treturn false;\n+\n+\t*count = BTINTEL_PCIE_DBGC_BUFFER_COUNT;\n+\t*size = BTINTEL_PCIE_DBGC_BUFFER_SIZE;\n+\treturn true;\n+}\n+\n /* This function initializes the memory for MDBGC buffers and formats the\n * DBGC fragment which consists header info and DBGC buffer's LSB, MSB and\n * size as the payload\n@@ -261,10 +382,9 @@ static int btintel_pcie_setup_mdbgc(struct btintel_pcie_data *data)\n \tstruct btintel_pcie_mdbgc_ctxt db_frag;\n \tu32 frag_size = sizeof(db_frag);\n \tvoid *frag_v_addr;\n+\tu32 buf_count, buf_size;\n \tint err;\n \n-\tdata-\u003emdbgc.count = BTINTEL_PCIE_DBGC_BUFFER_COUNT;\n-\n \t/* Allocate fragment context structure */\n \tfrag_v_addr = dmam_alloc_coherent(\u0026data-\u003epdev-\u003edev, frag_size,\n \t\t\t\t\t \u0026data-\u003emdbgc.frag_p_addr,\n@@ -283,46 +403,71 @@ static int btintel_pcie_setup_mdbgc(struct btintel_pcie_data *data)\n \tdb_frag.ver = BTINTEL_PCIE_MDBGC_FRAG_VERSION;\n \n \t/* Allocate DBGC buffer 1 */\n-\tdb_frag.buf1_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_1;\n-\tdb_frag.buf1_count = data-\u003emdbgc.count;\n-\terr = btintel_pcie_alloc_dbgc_buf(data,\n-\t\t\t\t\t \u0026data-\u003emdbgc.buf1,\n-\t\t\t\t\t \u0026data-\u003emdbgc.buf1_p_addr,\n-\t\t\t\t\t \u0026data-\u003emdbgc.buf1_v_addr,\n-\t\t\t\t\t db_frag.buf1,\n-\t\t\t\t\t 0,\n-\t\t\t\t\t data-\u003emdbgc.count);\n-\tif (err)\n-\t\treturn err;\n+\tif (btintel_pcie_get_mdbgc_cfg(data, BTINTEL_PCIE_ALLOC_ID_DBGC1,\n+\t\t\t\t \u0026buf_count, \u0026buf_size)) {\n+\t\tdb_frag.buf1_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_1;\n+\t\tdata-\u003emdbgc.buf1_count = buf_count;\n+\t\tdata-\u003emdbgc.buf1_size = buf_size;\n+\t\tdb_frag.buf1_count = buf_count;\n+\n+\t\terr = btintel_pcie_alloc_dbgc_buf(data,\n+\t\t\t\t\t\t \u0026data-\u003emdbgc.buf1,\n+\t\t\t\t\t\t \u0026data-\u003emdbgc.buf1_p_addr,\n+\t\t\t\t\t\t \u0026data-\u003emdbgc.buf1_v_addr,\n+\t\t\t\t\t\t db_frag.buf1,\n+\t\t\t\t\t\t 0,\n+\t\t\t\t\t\t buf_count,\n+\t\t\t\t\t\t buf_size);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n \n \t/* Allocate DBGC buffer 2 */\n-\tdb_frag.buf2_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_2;\n-\tdb_frag.buf2_count = data-\u003emdbgc.count;\n-\terr = btintel_pcie_alloc_dbgc_buf(data,\n-\t\t\t\t\t \u0026data-\u003emdbgc.buf2,\n-\t\t\t\t\t \u0026data-\u003emdbgc.buf2_p_addr,\n-\t\t\t\t\t \u0026data-\u003emdbgc.buf2_v_addr,\n-\t\t\t\t\t db_frag.buf2,\n-\t\t\t\t\t 1,\n-\t\t\t\t\t data-\u003emdbgc.count);\n-\tif (err)\n-\t\treturn err;\n+\tif (btintel_pcie_get_mdbgc_cfg(data, BTINTEL_PCIE_ALLOC_ID_DBGC2,\n+\t\t\t\t \u0026buf_count, \u0026buf_size)) {\n+\t\tdb_frag.buf2_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_2;\n+\t\tdata-\u003emdbgc.buf2_count = buf_count;\n+\t\tdata-\u003emdbgc.buf2_size = buf_size;\n+\t\tdb_frag.buf2_count = buf_count;\n+\n+\t\terr = btintel_pcie_alloc_dbgc_buf(data,\n+\t\t\t\t\t\t \u0026data-\u003emdbgc.buf2,\n+\t\t\t\t\t\t \u0026data-\u003emdbgc.buf2_p_addr,\n+\t\t\t\t\t\t \u0026data-\u003emdbgc.buf2_v_addr,\n+\t\t\t\t\t\t db_frag.buf2,\n+\t\t\t\t\t\t 1,\n+\t\t\t\t\t\t buf_count,\n+\t\t\t\t\t\t buf_size);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n \n \t/* Allocate DBGC buffer 3 */\n-\tdb_frag.buf3_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_3;\n-\tdb_frag.buf3_count = data-\u003emdbgc.count;\n-\terr = btintel_pcie_alloc_dbgc_buf(data,\n-\t\t\t\t\t \u0026data-\u003emdbgc.buf3,\n-\t\t\t\t\t \u0026data-\u003emdbgc.buf3_p_addr,\n-\t\t\t\t\t \u0026data-\u003emdbgc.buf3_v_addr,\n-\t\t\t\t\t db_frag.buf3,\n-\t\t\t\t\t 2,\n-\t\t\t\t\t data-\u003emdbgc.count);\n-\tif (err)\n-\t\treturn err;\n+\tif (btintel_pcie_get_mdbgc_cfg(data, BTINTEL_PCIE_ALLOC_ID_DBGC3,\n+\t\t\t\t \u0026buf_count, \u0026buf_size)) {\n+\t\tdb_frag.buf3_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_3;\n+\t\tdata-\u003emdbgc.buf3_count = buf_count;\n+\t\tdata-\u003emdbgc.buf3_size = buf_size;\n+\t\tdb_frag.buf3_count = buf_count;\n+\n+\t\terr = btintel_pcie_alloc_dbgc_buf(data,\n+\t\t\t\t\t\t \u0026data-\u003emdbgc.buf3,\n+\t\t\t\t\t\t \u0026data-\u003emdbgc.buf3_p_addr,\n+\t\t\t\t\t\t \u0026data-\u003emdbgc.buf3_v_addr,\n+\t\t\t\t\t\t db_frag.buf3,\n+\t\t\t\t\t\t 2,\n+\t\t\t\t\t\t buf_count,\n+\t\t\t\t\t\t buf_size);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n \n \t/* Copy fragment to DMA coherent memory */\n \tmemcpy(data-\u003emdbgc.frag_v_addr, \u0026db_frag, sizeof(db_frag));\n+\tBT_INFO(\"MDBGC: buf1 frag=%u size=%u; buf2 frag=%u size=%u; buf3 frag=%u size=%u\",\n+\t\tdb_frag.buf1_count, db_frag.buf1_count * db_frag.buf1[0].buf_size,\n+\t\tdb_frag.buf2_count, db_frag.buf2_count * db_frag.buf2[0].buf_size,\n+\t\tdb_frag.buf3_count, db_frag.buf3_count * db_frag.buf3[0].buf_size);\n \treturn 0;\n }\n \n@@ -334,9 +479,21 @@ static int btintel_pcie_setup_dbgc(struct btintel_pcie_data *data)\n {\n \tstruct btintel_pcie_dbgc_ctxt db_frag;\n \tu32 frag_size = sizeof(db_frag);\n+\tconst struct btintel_pcie_buf_alloc *ba;\n+\tu32 buf_count, buf_size;\n \tint err;\n \n-\tdata-\u003edbgc.count = BTINTEL_PCIE_DBGC_BUFFER_COUNT;\n+\tba = btintel_pcie_yoyo_get_buf_alloc(\u0026data-\u003eyoyo,\n+\t\t\t\t\t BTINTEL_PCIE_ALLOC_ID_DBGC1);\n+\tbuf_count = ba ? ba-\u003emax_num_frags : BTINTEL_PCIE_DBGC_BUFFER_COUNT;\n+\tbuf_size = ba ? ba-\u003ereq_buf_size / ba-\u003emax_num_frags :\n+\t\tBTINTEL_PCIE_DBGC_BUFFER_SIZE;\n+\n+\tBT_INFO(\"dbgc setup: frag_num=%u per_buf_size=%u total_size=%u\",\n+\t\tbuf_count, buf_size, buf_count * buf_size);\n+\n+\tdata-\u003edbgc.count = buf_count;\n+\tdata-\u003edbgc.buf_size = buf_size;\n \n \t/* Allocate fragment context structure */\n \tdata-\u003edbgc.frag_v_addr = dmam_alloc_coherent(\u0026data-\u003epdev-\u003edev,\n@@ -354,8 +511,9 @@ static int btintel_pcie_setup_dbgc(struct btintel_pcie_data *data)\n \tmemset(\u0026db_frag, 0, sizeof(db_frag));\n \tdb_frag.magic_num = BTINTEL_PCIE_MAGIC_NUM;\n \tdb_frag.ver = BTINTEL_PCIE_DBGC_FRAG_VERSION;\n-\tdb_frag.total_size = BTINTEL_PCIE_DBGC_FRAG_PAYLOAD_SIZE;\n-\tdb_frag.num_buf = BTINTEL_PCIE_DBGC_FRAG_BUFFER_COUNT;\n+\tdb_frag.total_size = sizeof(db_frag.num_buf) +\n+\t\t\t buf_count * sizeof(db_frag.bufs[0]);\n+\tdb_frag.num_buf = buf_count;\n \n \t/* Allocate DBGC buffers */\n \terr = btintel_pcie_alloc_dbgc_buf(data,\n@@ -364,7 +522,8 @@ static int btintel_pcie_setup_dbgc(struct btintel_pcie_data *data)\n \t\t\t\t\t \u0026data-\u003edbgc.buf_v_addr,\n \t\t\t\t\t db_frag.bufs,\n \t\t\t\t\t 0,\n-\t\t\t\t\t data-\u003edbgc.count);\n+\t\t\t\t\t buf_count,\n+\t\t\t\t\t buf_size);\n \tif (err)\n \t\treturn err;\n \n@@ -857,7 +1016,8 @@ static u32 btintel_pcie_dump_list_total_size(struct list_head *list)\n }\n \n static int btintel_pcie_dump_dram(struct list_head *list,\n-\t\t\t\t u8 count, struct data_buf *bufs,\n+\t\t\t\t u8 count, u32 buf_size,\n+\t\t\t\t struct data_buf *bufs,\n \t\t\t\t u32 write_ptr, u32 wrap_ctr, u32 cur_frag,\n \t\t\t\t u32 region_id, const char *name)\n {\n@@ -869,7 +1029,7 @@ static int btintel_pcie_dump_dram(struct list_head *list,\n \tint i;\n \n \tmon_hdr_size = sizeof(*mon_dump);\n-\tranges_size = count * (sizeof(*range) + BTINTEL_PCIE_DBGC_BUFFER_SIZE);\n+\tranges_size = count * (sizeof(*range) + buf_size);\n \tpayload_size = mon_hdr_size + ranges_size;\n \ttotal_size = sizeof(*dump_data) + payload_size;\n \n@@ -898,12 +1058,10 @@ static int btintel_pcie_dump_dram(struct list_head *list,\n \n \trange = (void *)mon_dump-\u003edata;\n \tfor (i = 0; i \u003c count; i++) {\n-\t\trange-\u003erange_data_size =\n-\t\t\tcpu_to_le32(BTINTEL_PCIE_DBGC_BUFFER_SIZE);\n+\t\trange-\u003erange_data_size = cpu_to_le32(buf_size);\n \t\trange-\u003edram_base_addr = cpu_to_le64(bufs[i].data_p_addr);\n-\t\tmemcpy(range-\u003edata, bufs[i].data,\n-\t\t BTINTEL_PCIE_DBGC_BUFFER_SIZE);\n-\t\trange = (void *)range-\u003edata + BTINTEL_PCIE_DBGC_BUFFER_SIZE;\n+\t\tmemcpy(range-\u003edata, bufs[i].data, buf_size);\n+\t\trange = (void *)range-\u003edata + buf_size;\n \t}\n \n \tlist_add_tail(\u0026entry-\u003elist, list);\n@@ -912,7 +1070,8 @@ static int btintel_pcie_dump_dram(struct list_head *list,\n \n static int\n btintel_pcie_dump_dram_monitor(struct btintel_pcie_data *data,\n-\t\t\t struct list_head *list, u8 count,\n+\t\t\t\t struct list_head *list, u8 count,\n+\t\t\t\t u32 buf_size,\n \t\t\t struct data_buf *bufs, u32 status_reg,\n \t\t\t u32 wrap_reg, u8 allocation_id, u32 region_id,\n \t\t\t const char *name)\n@@ -920,6 +1079,9 @@ btintel_pcie_dump_dram_monitor(struct btintel_pcie_data *data,\n \tu32 allocation_offset, write_ptr, wrap_ctr, wr_ptr_status;\n \tu8 cur_frag;\n \n+\tif (!count)\n+\t\treturn -ENOENT;\n+\n \tallocation_offset = allocation_id *\n \t\t\t BTINTEL_PCIE_DBGC_ALLOCATION_OFFSET;\n \twr_ptr_status = btintel_pcie_rd_dev_mem(data, status_reg +\n@@ -941,8 +1103,8 @@ btintel_pcie_dump_dram_monitor(struct btintel_pcie_data *data,\n \t\t \"allocation=%u wr_ptr_status=0x%08x write_ptr=0x%06x cur_frag=%u wrap_ctr=0x%08x\",\n \t\t allocation_id, wr_ptr_status, write_ptr, cur_frag, wrap_ctr);\n \n-\treturn btintel_pcie_dump_dram(list, count, bufs, write_ptr, wrap_ctr,\n-\t\t\t\t cur_frag, region_id, name);\n+\treturn btintel_pcie_dump_dram(list, count, buf_size, bufs, write_ptr,\n+\t\t\t\t wrap_ctr, cur_frag, region_id, name);\n }\n \n static int btintel_pcie_dump_target_region(struct btintel_pcie_data *data,\n@@ -1223,6 +1385,7 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)\n \tu8 hw_variant;\n \tu32 file_len;\n \tu8 count;\n+\tu32 buf_size;\n \tint ret;\n \tLIST_HEAD(dump_list);\n \n@@ -1231,10 +1394,12 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)\n \n \tif (btintel_pcie_is_mdbgc_supported(data)) {\n \t\tmdbgc = \u0026data-\u003emdbgc;\n-\t\tcount = mdbgc-\u003ecount;\n+\t\tcount = mdbgc-\u003ebuf1_count;\n+\t\tbuf_size = mdbgc-\u003ebuf1_size;\n \t} else {\n \t\tdbgc = \u0026data-\u003edbgc;\n \t\tcount = dbgc-\u003ecount;\n+\t\tbuf_size = dbgc-\u003ebuf_size;\n \t}\n \n \thw_variant = INTEL_HW_VARIANT(data-\u003ecnvi);\n@@ -1254,7 +1419,9 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)\n \t}\n \n \tif (btintel_pcie_is_mdbgc_supported(data)) {\n-\t\tret = btintel_pcie_dump_dram_monitor(data, \u0026dump_list, count,\n+\t\tret = btintel_pcie_dump_dram_monitor(data, \u0026dump_list,\n+\t\t\t\t\t\t mdbgc-\u003ebuf1_count,\n+\t\t\t\t\t\t mdbgc-\u003ebuf1_size,\n \t\t\t\t\t\t mdbgc-\u003ebuf1, status_reg,\n \t\t\t\t\t\t wrap_reg,\n \t\t\t\t\t\t BTINTEL_PCIE_MDBGC_ALLOCATIONID_1,\n@@ -1263,10 +1430,12 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)\n \t\tif (!ret)\n \t\t\tregions_mask |=\n \t\t\t\tBIT_ULL(BTINTEL_PCIE_INI_ID_DRAM_MONITOR1);\n-\t\telse\n+\t\telse if (ret != -ENOENT)\n \t\t\tbt_dev_warn(hdev, \"Failed to dump DRAM buf1: %d\", ret);\n \n-\t\tret = btintel_pcie_dump_dram_monitor(data, \u0026dump_list, count,\n+\t\tret = btintel_pcie_dump_dram_monitor(data, \u0026dump_list,\n+\t\t\t\t\t\t mdbgc-\u003ebuf2_count,\n+\t\t\t\t\t\t mdbgc-\u003ebuf2_size,\n \t\t\t\t\t\t mdbgc-\u003ebuf2, status_reg,\n \t\t\t\t\t\t wrap_reg,\n \t\t\t\t\t\t BTINTEL_PCIE_MDBGC_ALLOCATIONID_2,\n@@ -1275,10 +1444,12 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)\n \t\tif (!ret)\n \t\t\tregions_mask |=\n \t\t\t\tBIT_ULL(BTINTEL_PCIE_INI_ID_DRAM_MONITOR2);\n-\t\telse\n+\t\telse if (ret != -ENOENT)\n \t\t\tbt_dev_warn(hdev, \"Failed to dump DRAM buf2: %d\", ret);\n \n-\t\tret = btintel_pcie_dump_dram_monitor(data, \u0026dump_list, count,\n+\t\tret = btintel_pcie_dump_dram_monitor(data, \u0026dump_list,\n+\t\t\t\t\t\t mdbgc-\u003ebuf3_count,\n+\t\t\t\t\t\t mdbgc-\u003ebuf3_size,\n \t\t\t\t\t\t mdbgc-\u003ebuf3, status_reg,\n \t\t\t\t\t\t wrap_reg,\n \t\t\t\t\t\t BTINTEL_PCIE_MDBGC_ALLOCATIONID_3,\n@@ -1287,11 +1458,12 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)\n \t\tif (!ret)\n \t\t\tregions_mask |=\n \t\t\t\tBIT_ULL(BTINTEL_PCIE_INI_ID_DRAM_MONITOR3);\n-\t\telse\n+\t\telse if (ret != -ENOENT)\n \t\t\tbt_dev_warn(hdev, \"Failed to dump DRAM buf3: %d\", ret);\n \t} else {\n \t\tret = btintel_pcie_dump_dram_monitor(data, \u0026dump_list, count,\n-\t\t\t\t\t\t dbgc-\u003ebufs, status_reg,\n+\t\t\t\t\t\t buf_size, dbgc-\u003ebufs,\n+\t\t\t\t\t\t status_reg,\n \t\t\t\t\t\t wrap_reg,\n \t\t\t\t\t\t BTINTEL_PCIE_MDBGC_ALLOCATIONID_1,\n \t\t\t\t\t\t BTINTEL_PCIE_INI_ID_DRAM_MONITOR1,\n@@ -3183,7 +3355,7 @@ static int btintel_pcie_alloc(struct btintel_pcie_data *data)\n \t\terr = btintel_pcie_setup_dbgc(data);\n \t}\n \tif (err)\n-\t\tgoto exit_error_txq;\n+\t\tgoto exit_error_rxq;\n \n \t/* Setup Context Information */\n \tdata-\u003eci = v_addr;\n@@ -3194,6 +3366,9 @@ static int btintel_pcie_alloc(struct btintel_pcie_data *data)\n \n \treturn 0;\n \n+exit_error_rxq:\n+\t/* RX setup succeeded, so release its buffers before the shared unwind. */\n+\tbtintel_pcie_free_rxq_bufs(data, \u0026data-\u003erxq);\n exit_error_txq:\n \tbtintel_pcie_free_txq_bufs(data, \u0026data-\u003etxq);\n exit_error_pool:\n@@ -4097,10 +4272,25 @@ static int btintel_pcie_probe(struct pci_dev *pdev,\n \tdata-\u003eboot_stage_cache = 0x00;\n \tdata-\u003eimg_resp_cache = 0x00;\n \tdata-\u003edbg_path_cache = BTINTEL_PCIE_WIFI_DBGC;\n+\tdata-\u003eenable_ini = false;\n+\tbtintel_pcie_yoyo_init(\u0026data-\u003eyoyo);\n \t/* FLR can be invoked by echoing to debugfs path, so explicitly\n \t * initialized\n \t */\n \tdata-\u003ereset_type = BTINTEL_PCIE_IOSF_PRR_FLR;\n+\n+\tbtintel_pcie_load_dbg_path_from_ini(data);\n+\tif (data-\u003edbg_path_cache != BTINTEL_PCIE_DRAM)\n+\t\tdata-\u003eenable_ini = false;\n+\n+\tif (data-\u003eenable_ini) {\n+\t\terr = btintel_pcie_yoyo_load_and_parse(\u0026data-\u003eyoyo, \u0026pdev-\u003edev);\n+\t\tif (err) {\n+\t\t\tBT_WARN(\"YoYo is not configured (%d)\", err);\n+\t\t\tbtintel_pcie_yoyo_cleanup(\u0026data-\u003eyoyo);\n+\t\t}\n+\t}\n+\n \terr = btintel_pcie_config_pcie(pdev, data);\n \tif (err)\n \t\tgoto exit_error;\n@@ -4128,11 +4318,14 @@ static int btintel_pcie_probe(struct pci_dev *pdev,\n \tif (err)\n \t\tgoto exit_error;\n \n+\tdata-\u003eyoyo.hdev = data-\u003ehdev;\n \tbt_dev_dbg(data-\u003ehdev, \"cnvi: 0x%8.8x cnvr: 0x%8.8x\", data-\u003ecnvi,\n \t\t data-\u003ecnvr);\n \treturn 0;\n \n exit_error:\n+\tbtintel_pcie_yoyo_cleanup(\u0026data-\u003eyoyo);\n+\n \t/* reset device before exit */\n \tbtintel_pcie_reset_bt(data);\n \n@@ -4173,6 +4366,8 @@ static void btintel_pcie_remove(struct pci_dev *pdev)\n \tif (current_work() != \u0026data-\u003ereset_work)\n \t\tdisable_work_sync(\u0026data-\u003ereset_work);\n \n+\tbtintel_pcie_yoyo_cleanup(\u0026data-\u003eyoyo);\n+\n \tbtintel_pcie_disable_interrupts(data);\n \n \tbtintel_pcie_synchronize_irqs(data);\ndiff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h\nindex 3030b4e8b7503..d68f83a629224 100644\n--- a/drivers/bluetooth/btintel_pcie.h\n+++ b/drivers/bluetooth/btintel_pcie.h\n@@ -6,6 +6,8 @@\n * Copyright (C) 2024 Intel Corporation\n */\n \n+#include \"btintel_pcie_debug.h\"\n+\n /* Control and Status Register(BTINTEL_PCIE_CSR) */\n #define BTINTEL_PCIE_CSR_BASE\t\t\t(0x000)\n #define BTINTEL_PCIE_CSR_FUNC_CTRL_REG\t\t(BTINTEL_PCIE_CSR_BASE + 0x024)\n@@ -466,6 +468,7 @@ struct rxq {\n */\n struct btintel_pcie_dbgc {\n \tu16\t\tcount;\n+\tu32\t\tbuf_size;\n \n \tvoid\t\t*frag_v_addr;\n \tdma_addr_t\tfrag_p_addr;\n@@ -477,7 +480,12 @@ struct btintel_pcie_dbgc {\n };\n \n struct btintel_pcie_mdbgc {\n-\tu32\t\tcount;\n+\tu32\t\tbuf1_count;\n+\tu32\t\tbuf1_size;\n+\tu32\t\tbuf2_count;\n+\tu32\t\tbuf2_size;\n+\tu32\t\tbuf3_count;\n+\tu32\t\tbuf3_size;\n \n \tvoid\t\t*frag_v_addr;\n \tdma_addr_t\tfrag_p_addr;\n@@ -737,6 +745,8 @@ struct btintel_pcie_data {\n \tu32\tboot_stage_cache;\n \tu32\timg_resp_cache;\n \tu32\tdbg_path_cache;\n+\tbool\tenable_ini;\n+\tstruct btintel_pcie_yoyo_ctx yoyo;\n \n \tu32\tcnvi;\n \tu32\tcnvr;\ndiff --git a/drivers/bluetooth/btintel_pcie_debug.c b/drivers/bluetooth/btintel_pcie_debug.c\nnew file mode 100644\nindex 0000000000000..5af00784bf962\n--- /dev/null\n+++ b/drivers/bluetooth/btintel_pcie_debug.c\n@@ -0,0 +1,331 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * Intel Bluetooth YoYo Debug Framework\n+ *\n+ * Copyright (C) 2026 Intel Corporation\n+ *\n+ * Runtime-configurable TLV-based debug collection framework for loading and\n+ * parsing the optional YoYo firmware configuration used to enable debug\n+ * regions, triggers, HCI commands, and configuration sets.\n+ */\n+\n+#include \u003clinux/errno.h\u003e\n+#include \u003clinux/module.h\u003e\n+#include \u003clinux/stddef.h\u003e\n+#include \u003clinux/string.h\u003e\n+#include \u003clinux/unaligned.h\u003e\n+#include \u003cnet/bluetooth/bluetooth.h\u003e\n+#include \"btintel_pcie_debug.h\"\n+\n+/* TLV-specific parser DEBUG_INFO TLV type */\n+static int btintel_pcie_yoyo_parse_dbg_info(struct btintel_pcie_yoyo_ctx *ctx,\n+\t\t\t\t\t const struct btintel_pcie_tlv_dbg_info *info,\n+\t\t\t\t\t u32 len)\n+{\n+\tconst u8 *data = (const u8 *)info;\n+\tu32 domain, image_type, core_type, version;\n+\n+\tif (len != sizeof(*info) - sizeof(struct btintel_pcie_tlv_hdr))\n+\t\treturn -EBADMSG;\n+\n+\timage_type = get_unaligned_le32(data +\n+\t\t\t\t offsetof(struct btintel_pcie_tlv_dbg_info,\n+\t\t\t\t\t\timage_type));\n+\tcore_type = get_unaligned_le32(data +\n+\t\t\t\t offsetof(struct btintel_pcie_tlv_dbg_info,\n+\t\t\t\t\t core_type));\n+\tdomain = get_unaligned_le32(data +\n+\t\t\t\t offsetof(struct btintel_pcie_tlv_dbg_info,\n+\t\t\t\t\t dbg_hdr.domain));\n+\tversion = get_unaligned_le32(data +\n+\t\t\t\t offsetof(struct btintel_pcie_tlv_dbg_info,\n+\t\t\t\t\t dbg_hdr.tlv_data_version));\n+\n+\tif (domain != BTINTEL_PCIE_DOMAIN_BT ||\n+\t version != BTINTEL_PCIE_DBG_INFO_TLV_VERSION) {\n+\t\tBT_WARN(\"YoYo: unsupported domain/version (%u/%u), disabling\",\n+\t\t\tdomain, version);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (image_type != BTINTEL_PCIE_IMAGE_TLV_TYPE_EXTERNAL) {\n+\t\tBT_WARN(\"YoYo: unsupported image_type 0x%x, disabling\", image_type);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (core_type != BTINTEL_PCIE_CORE_TYPE_BT) {\n+\t\tBT_WARN(\"YoYo: non BT core_type %u, disabling\", core_type);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tctx-\u003edbg_info_present = true;\n+\tBT_DBG(\"YoYo: config='%.64s' image=%u core=%u\",\n+\t info-\u003econfig_name, image_type, core_type);\n+\treturn 0;\n+}\n+\n+static int btintel_pcie_yoyo_parse_buf_alloc(struct btintel_pcie_yoyo_ctx *ctx,\n+\t\t\t\t\t const struct btintel_pcie_tlv_buf_alloc *tlv,\n+\t\t\t\t\t u32 len)\n+{\n+\tu32 alloc_id, buf_location, domain, idx, max_num_frags, min_buf_size;\n+\tu32 req_buf_size, version;\n+\n+\tif (len != sizeof(*tlv) - sizeof(struct btintel_pcie_tlv_hdr)) {\n+\t\tBT_WARN(\"YoYo: unexpected buf alloc TLV length %u\", len);\n+\t\treturn -EBADMSG;\n+\t}\n+\n+\tdomain = get_unaligned_le32(\u0026tlv-\u003edbg_hdr.domain);\n+\tversion = get_unaligned_le32(\u0026tlv-\u003edbg_hdr.tlv_data_version);\n+\tif (domain != BTINTEL_PCIE_DOMAIN_BT ||\n+\t version != BTINTEL_PCIE_BUF_ALLOC_TLV_VERSION) {\n+\t\tBT_WARN(\"YoYo: unsupported buf allocation domain/version (%u/%u)\",\n+\t\t\tdomain, version);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\talloc_id = get_unaligned_le32(\u0026tlv-\u003ealloc_id);\n+\tif (alloc_id \u003c BTINTEL_PCIE_ALLOC_ID_DBGC1 ||\n+\t alloc_id \u003e BTINTEL_PCIE_ALLOC_ID_DBGC3) {\n+\t\tBT_WARN(\"YoYo: invalid buf allocation id %u\", alloc_id);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tidx = alloc_id - BTINTEL_PCIE_ALLOC_ID_DBGC1;\n+\tbuf_location = get_unaligned_le32(\u0026tlv-\u003ebuf_location);\n+\tmax_num_frags = get_unaligned_le32(\u0026tlv-\u003emax_num_frags);\n+\tmin_buf_size = get_unaligned_le32(\u0026tlv-\u003emin_buf_size);\n+\treq_buf_size = get_unaligned_le32(\u0026tlv-\u003ereq_buf_size);\n+\n+\tif (buf_location != BTINTEL_PCIE_BUF_LOC_DRAM) {\n+\t\tBT_WARN(\"YoYo: buf allocation id=%u unsupported buffer location %u\",\n+\t\t\talloc_id, buf_location);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!max_num_frags || max_num_frags \u003e BTINTEL_PCIE_MAX_BUF_FRAGS ||\n+\t min_buf_size \u003c BTINTEL_PCIE_MIN_BUF_SIZE ||\n+\t min_buf_size \u003e BTINTEL_PCIE_MAX_BUF_SIZE ||\n+\t req_buf_size \u003e BTINTEL_PCIE_MAX_BUF_SIZE ||\n+\t req_buf_size % max_num_frags ||\n+\t req_buf_size / max_num_frags \u003c min_buf_size) {\n+\t\tBT_WARN(\"YoYo: buf allocation id=%u req size=%u max frags=%u min size=%u\",\n+\t\t\talloc_id, req_buf_size, max_num_frags, min_buf_size);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tctx-\u003ebuf_alloc[idx].alloc_id = alloc_id;\n+\tctx-\u003ebuf_alloc[idx].buf_location = buf_location;\n+\tctx-\u003ebuf_alloc[idx].req_buf_size = req_buf_size;\n+\tctx-\u003ebuf_alloc[idx].max_num_frags = max_num_frags;\n+\tctx-\u003ebuf_alloc[idx].min_buf_size = min_buf_size;\n+\tctx-\u003ebuf_alloc[idx].present = true;\n+\n+\tif (idx + 1 \u003e ctx-\u003enum_buf_allocs)\n+\t\tctx-\u003enum_buf_allocs = idx + 1;\n+\n+\tBT_DBG(\"YoYo: buf allocation id=%u loc=%u req size=%u max frags=%u min size=%u\",\n+\t alloc_id, ctx-\u003ebuf_alloc[idx].buf_location,\n+\t ctx-\u003ebuf_alloc[idx].req_buf_size,\n+\t ctx-\u003ebuf_alloc[idx].max_num_frags,\n+\t ctx-\u003ebuf_alloc[idx].min_buf_size);\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * Parse the optional YoYo firmware TLV stream and validate each record.\n+ * This is the entry point for the runtime debug configuration payload.\n+ */\n+static int btintel_pcie_yoyo_parse_tlv_buffer(struct btintel_pcie_yoyo_ctx *ctx,\n+\t\t\t\t\t const u8 *buf, size_t buf_len)\n+{\n+\tconst struct btintel_pcie_tlv_hdr *tlv;\n+\tconst u8 *ptr = buf;\n+\tsize_t remaining = buf_len;\n+\tu32 count = 0;\n+\tint ret = 0;\n+\n+\twhile (remaining \u003e= sizeof(*tlv)) {\n+\t\tsize_t tlv_size;\n+\t\tu32 type, len;\n+\n+\t\ttlv = (const struct btintel_pcie_tlv_hdr *)ptr;\n+\t\ttype = get_unaligned_le32(\u0026tlv-\u003etype);\n+\t\tlen = get_unaligned_le32(\u0026tlv-\u003elength);\n+\n+\t\tif (len \u003e remaining - sizeof(*tlv)) {\n+\t\t\tBT_ERR(\"YoYo: tlv %u truncated (len=%u rem=%zu)\", count,\n+\t\t\t len, remaining);\n+\t\t\treturn -EBADMSG;\n+\t\t}\n+\t\ttlv_size = sizeof(*tlv) + len;\n+\n+\t\tswitch (type) {\n+\t\tcase BTINTEL_PCIE_TLV_TYPE_DBG_INFO:\n+\t\t\tret = btintel_pcie_yoyo_parse_dbg_info(ctx,\n+\t\t\t\t\t\t\t (const void *)tlv, len);\n+\t\t\tif (ret) {\n+\t\t\t\tctx-\u003edbg_info_present = false;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase BTINTEL_PCIE_TLV_TYPE_DBG_BUF_ALLOC:\n+\t\t\tret = btintel_pcie_yoyo_parse_buf_alloc(ctx,\n+\t\t\t\t\t\t\t\t(const void *)tlv, len);\n+\t\t\tbreak;\n+\t\tcase BTINTEL_PCIE_TLV_TYPE_DBG_REGION:\n+\t\tcase BTINTEL_PCIE_TLV_TYPE_DBG_TRIGGER:\n+\t\tcase BTINTEL_PCIE_TLV_TYPE_DBG_HCMD:\n+\t\tcase BTINTEL_PCIE_TLV_TYPE_DBG_CONFIG_SET:\n+\t\tcase BTINTEL_PCIE_TLV_TYPE_DBG_PRESET_OVERRIDE:\n+\t\t\tBT_DBG(\"YoYo: valid tlv type 0x%x len=%u\", type, len);\n+\t\t\tbreak;\n+\t\tdefault: /* Log and continue, do not fail*/\n+\t\t\tBT_DBG(\"YoYo: unknown tlv type 0x%x len=%u\", type, len);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tptr += tlv_size;\n+\t\tremaining -= tlv_size;\n+\n+\t\tif (ret) {\n+\t\t\tBT_ERR(\"YoYo: error parsing tlv type 0x%x (ret=%d)\", type, ret);\n+\t\t\treturn ret;\n+\t\t}\n+\n+\t\tcount++;\n+\t}\n+\n+\t/* If no TLVs were parsed, the YoYo binary is considered invalid */\n+\tif (remaining || count == 0) {\n+\t\tBT_ERR(\"YoYo: trailing %zu bytes after tlv stream\", remaining);\n+\t\treturn -EBADMSG;\n+\t}\n+\tif (!ctx-\u003enum_buf_allocs) {\n+\t\tBT_ERR(\"YoYo: mandatory buffer allocation TLV missing\");\n+\t\treturn -EBADMSG;\n+\t}\n+\n+\tBT_DBG(\"YoYo: parsed %u tlv's\", count);\n+\treturn 0;\n+}\n+\n+/**\n+ * btintel_yoyo_init - Initialize the YoYo context\n+ * @ctx: Pre-allocated context (typically embedded in driver data)\n+ */\n+int btintel_pcie_yoyo_init(struct btintel_pcie_yoyo_ctx *ctx)\n+{\n+\tif (!ctx)\n+\t\treturn -EINVAL;\n+\n+\tmemset(ctx, 0, sizeof(*ctx));\n+\tINIT_LIST_HEAD(\u0026ctx-\u003eregion_list);\n+\tINIT_LIST_HEAD(\u0026ctx-\u003etrigger_list);\n+\tINIT_LIST_HEAD(\u0026ctx-\u003ehcmd_list);\n+\tINIT_LIST_HEAD(\u0026ctx-\u003econfig_set_list);\n+\n+\t/* set it to true after successful TLV parsing */\n+\tctx-\u003eenabled = false;\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_init);\n+\n+/**\n+ * btintel_yoyo_cleanup - Clean up the YoYo context\n+ * @ctx: YoYo context to clean up\n+ */\n+void btintel_pcie_yoyo_cleanup(struct btintel_pcie_yoyo_ctx *ctx)\n+{\n+\tif (!ctx)\n+\t\treturn;\n+\n+\tctx-\u003eenabled = false;\n+\tctx-\u003edbg_info_present = false;\n+\tctx-\u003enum_buf_allocs = 0;\n+\tmemset(ctx-\u003ebuf_alloc, 0, sizeof(ctx-\u003ebuf_alloc));\n+}\n+EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_cleanup);\n+\n+/**\n+ * btintel_yoyo_load_and_parse - Load ibt_debug_yoyo.bin and parse TLVs\n+ * @ctx: Initialized YoYo context\n+ * @dev: Device for firmware loading (typically \u0026pdev-\u003edev)\n+ *\n+ * Uses request_firmware_direct, since the YoYo binary\n+ * is optional. On success, sets ctx-\u003eenabled.\n+ */\n+int btintel_pcie_yoyo_load_and_parse(struct btintel_pcie_yoyo_ctx *ctx,\n+\t\t\t\t struct device *dev)\n+{\n+\tconst struct firmware *fw;\n+\tint ret;\n+\n+\tif (!ctx)\n+\t\treturn -EINVAL;\n+\n+\tret = request_firmware_direct(\u0026fw, BTINTEL_PCIE_YOYO_FW_NAME, dev);\n+\tif (ret) {\n+\t\tBT_WARN(\"YoYo: failed to load %s (%d)\",\n+\t\t\tBTINTEL_PCIE_YOYO_FW_NAME, ret);\n+\t\treturn ret;\n+\t}\n+\n+\t/* Sanity check firmware size */\n+\tif (fw-\u003esize \u003c sizeof(struct btintel_pcie_tlv_hdr)) {\n+\t\trelease_firmware(fw);\n+\t\treturn -EBADMSG;\n+\t}\n+\n+\tBT_DBG(\"YoYo: loaded %s (%zu bytes)\", BTINTEL_PCIE_YOYO_FW_NAME,\n+\t fw-\u003esize);\n+\n+\tret = btintel_pcie_yoyo_parse_tlv_buffer(ctx, fw-\u003edata, fw-\u003esize);\n+\trelease_firmware(fw);\n+\n+\t/* File Corruption / TLV validation failed */\n+\tif (ret) {\n+\t\tBT_ERR(\"YoYo: tlv parsing failed (%d)\", ret);\n+\t\treturn ret;\n+\t}\n+\tif (!ctx-\u003edbg_info_present) {\n+\t\tBT_ERR(\"YoYo: Invalid BT debug Info tlv, using legacy DBGC defaults\");\n+\t\treturn -EBADMSG;\n+\t}\n+\n+\tctx-\u003eenabled = true;\n+\n+\tBT_INFO(\"YoYo: feature enabled and configured\");\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_load_and_parse);\n+\n+/**\n+ * btintel_pcie_yoyo_get_buf_alloc - Query buffer allocation config for a DBGC\n+ * @ctx: YoYo context\n+ * @alloc_id: Allocation ID (1=DBGC1, 2=DBGC2, 3=DBGC3)\n+ *\n+ * Return the parsed configuration, or NULL if no matching TLV was present.\n+ */\n+const struct btintel_pcie_buf_alloc *\n+btintel_pcie_yoyo_get_buf_alloc(struct btintel_pcie_yoyo_ctx *ctx, u32 alloc_id)\n+{\n+\tu32 idx;\n+\n+\tif (!ctx || !ctx-\u003eenabled ||\n+\t alloc_id \u003c BTINTEL_PCIE_ALLOC_ID_DBGC1 ||\n+\t alloc_id \u003e BTINTEL_PCIE_ALLOC_ID_DBGC3)\n+\t\treturn NULL;\n+\n+\tidx = alloc_id - BTINTEL_PCIE_ALLOC_ID_DBGC1;\n+\tif (!ctx-\u003ebuf_alloc[idx].present)\n+\t\treturn NULL;\n+\n+\treturn \u0026ctx-\u003ebuf_alloc[idx];\n+}\n+EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_get_buf_alloc);\n+\n+MODULE_DESCRIPTION(\"Intel Bluetooth yoyo debug framework\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/drivers/bluetooth/btintel_pcie_debug.h b/drivers/bluetooth/btintel_pcie_debug.h\nnew file mode 100644\nindex 0000000000000..5ed368fb13d1e\n--- /dev/null\n+++ b/drivers/bluetooth/btintel_pcie_debug.h\n@@ -0,0 +1,171 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/*\n+ * Intel Bluetooth YoYo Debug Framework\n+ *\n+ * Copyright (C) 2026 Intel Corporation\n+ *\n+ */\n+\n+#ifndef __BTINTEL_PCIE_DEBUG_H__\n+#define __BTINTEL_PCIE_DEBUG_H__\n+\n+#include \u003clinux/list.h\u003e\n+#include \u003clinux/types.h\u003e\n+#include \u003clinux/device.h\u003e\n+#include \u003clinux/firmware.h\u003e\n+\n+/* External YoYo binary file */\n+#define BTINTEL_PCIE_YOYO_FW_NAME\t\"intel/ibt_debug_yoyo.bin\"\n+\n+/* TLV type codes */\n+#define BTINTEL_PCIE_TLV_TYPE_DBG_INFO\t\t0x1000005\n+#define BTINTEL_PCIE_TLV_TYPE_DBG_BUF_ALLOC\t\t0x1000006\n+#define BTINTEL_PCIE_TLV_TYPE_DBG_HCMD\t\t0x1000007\n+#define BTINTEL_PCIE_TLV_TYPE_DBG_REGION\t\t0x1000008\n+#define BTINTEL_PCIE_TLV_TYPE_DBG_TRIGGER\t\t0x1000009\n+#define BTINTEL_PCIE_TLV_TYPE_DBG_CONFIG_SET\t\t0x100000A\n+#define BTINTEL_PCIE_TLV_TYPE_DBG_PRESET_OVERRIDE\t0x100000B\n+\n+/* Supported TLV type versions */\n+#define BTINTEL_PCIE_DBG_INFO_TLV_VERSION\t2\n+#define BTINTEL_PCIE_BUF_ALLOC_TLV_VERSION\t1\n+/* Debug Info TLV */\n+#define BTINTEL_PCIE_CONFIG_NAME_LEN\t\t64\n+#define BTINTEL_PCIE_DOMAIN_BT\t\t\t0\n+#define BTINTEL_PCIE_CORE_TYPE_BT\t\t1\n+/* Buffer allocation TLV */\n+#define BTINTEL_PCIE_MAX_BUF_ALLOC\t\t3\n+#define BTINTEL_PCIE_MAX_BUF_FRAGS\t\t16\n+#define BTINTEL_PCIE_MIN_BUF_SIZE\t\t(32 * 1024)\n+#define BTINTEL_PCIE_MAX_BUF_SIZE\t\t(4 * 1024 * 1024)\n+\n+enum btintel_pcie_image_tlv_type {\n+\tBTINTEL_PCIE_IMAGE_TLV_TYPE_EXTERNAL\t= 0x1,\n+\tBTINTEL_PCIE_IMAGE_TLV_TYPE_INTERNAL\t= 0x2,\n+\tBTINTEL_PCIE_IMAGE_TLV_TYPE_UNKNOWN\t= 0xff,\n+};\n+\n+/* Allocation IDs */\n+enum btintel_dbg_alloc_id {\n+\tBTINTEL_PCIE_ALLOC_ID_INVALID\t= 0,\n+\tBTINTEL_PCIE_ALLOC_ID_DBGC1\t\t= 1,\n+\tBTINTEL_PCIE_ALLOC_ID_DBGC2\t\t= 2,\n+\tBTINTEL_PCIE_ALLOC_ID_DBGC3\t\t= 3,\n+\tBTINTEL_PCIE_ALLOC_ID_MAX,\n+};\n+\n+/* Buffer locations */\n+enum btintel_dbg_buf_location {\n+\tBTINTEL_PCIE_BUF_LOC_INVALID\t\t= 0,\n+\tBTINTEL_PCIE_BUF_LOC_SRAM\t\t= 1,\n+\tBTINTEL_PCIE_BUF_LOC_DRAM\t\t= 2,\n+\tBTINTEL_PCIE_BUF_LOC_NPK\t\t= 3,\n+\tBTINTEL_PCIE_BUF_LOC_MAX,\n+};\n+\n+/* TLV header */\n+struct btintel_pcie_tlv_hdr {\n+\t__le32 type;\n+\t__le32 length;\n+} __packed;\n+\n+/* Debug header common to all debug TLVs */\n+struct btintel_pcie_dbg_hdr {\n+\t__le32 tlv_data_version;\n+\t__le32 domain;\n+} __packed;\n+\n+/* Address/value pair */\n+struct btintel_pcie_addr_value {\n+\t__le32 address;\n+\t__le32 value;\n+} __packed;\n+\n+/*\n+ * struct btintel_pcie_tlv_dbg_info - YoYo DEBUG_INFO TLV\n+ * @hdr: TLV type and payload length\n+ * @dbg_hdr: Debug TLV version and domain\n+ * @image_type: Firmware image type\n+ * @core_type: Firmware core type\n+ * @config_name: Fixed-size name of the firmware configuration\n+ *\n+ * Describes the firmware image targeted by the YoYo configuration. Fields\n+ * are stored in little-endian format in the packed firmware TLV.\n+ */\n+struct btintel_pcie_tlv_dbg_info {\n+\tstruct btintel_pcie_tlv_hdr hdr;\n+\tstruct btintel_pcie_dbg_hdr dbg_hdr;\n+\t__le32 image_type;\n+\t__le32 core_type;\n+\tu8 config_name[BTINTEL_PCIE_CONFIG_NAME_LEN];\n+} __packed;\n+\n+/*\n+ * struct btintel_pcie_tlv_buf_alloc - YoYo buffer allocation TLV\n+ * @hdr: Common TLV header\n+ * @dbg_hdr: Debug TLV version and domain\n+ * @alloc_id: DBGC allocation identifier (DBGC1..DBGC3)\n+ * @buf_location: Requested buffer location (SRAM / DRAM / NPK)\n+ * @req_buf_size: Total requested allocation size in bytes\n+ * @max_num_frags: Maximum number of buffer fragments (1..16)\n+ * @min_buf_size: Minimum buffer size in bytes\n+ *\n+ * Describes the buffer sizing override for one DBGC allocation.\n+ */\n+struct btintel_pcie_tlv_buf_alloc {\n+\tstruct btintel_pcie_tlv_hdr hdr;\n+\tstruct btintel_pcie_dbg_hdr dbg_hdr;\n+\t__le32 alloc_id;\n+\t__le32 buf_location;\n+\t__le32 req_buf_size;\n+\t__le32 max_num_frags;\n+\t__le32 min_buf_size;\n+} __packed;\n+\n+/* Parsed buffer allocation entry in the YoYo context */\n+struct btintel_pcie_buf_alloc {\n+\tu32\talloc_id;\n+\tu32\tbuf_location;\n+\tu32\treq_buf_size;\n+\tu32\tmax_num_frags;\n+\tu32\tmin_buf_size;\n+\tbool\tpresent;\n+};\n+\n+/*\n+ * struct btintel_pcie_yoyo_ctx- Runtime state for YoYo debug configuration\n+ * @enabled: Whether the loaded YoYo configuration passed validation\n+ * @region_list: Parsed debug-region entries\n+ * @trigger_list: Parsed debug-trigger entries\n+ * @hcmd_list: Parsed HCI command entries\n+ * @config_set_list: Parsed configuration-set entries\n+ * @buf_alloc: Parsed buffer allocation entries\n+ * @num_buf_allocs: Number of parsed buffer allocation entries\n+ * @hdev: Associated HCI device; NULL until successful HCI registration\n+ *\n+ * Stores the validation state and parsed TLV data for the optional YoYo\n+ * firmware configuration.\n+ */\n+struct btintel_pcie_yoyo_ctx {\n+\tbool\t\t\t enabled;\n+\tbool\t\t\t dbg_info_present;\n+\tstruct list_head\t region_list;\n+\tstruct list_head\t trigger_list;\n+\tstruct list_head\t hcmd_list;\n+\tstruct list_head\t config_set_list;\n+\tstruct btintel_pcie_buf_alloc buf_alloc[BTINTEL_PCIE_MAX_BUF_ALLOC];\n+\tint\t\t\t num_buf_allocs;\n+\tstruct hci_dev\t\t *hdev;\n+};\n+\n+int btintel_pcie_yoyo_init(struct btintel_pcie_yoyo_ctx *ctx);\n+void btintel_pcie_yoyo_cleanup(struct btintel_pcie_yoyo_ctx *ctx);\n+\n+/* Load and parse the external .bin file */\n+int btintel_pcie_yoyo_load_and_parse(struct btintel_pcie_yoyo_ctx *ctx,\n+\t\t\t\t struct device *dev);\n+\n+const struct btintel_pcie_buf_alloc *\n+btintel_pcie_yoyo_get_buf_alloc(struct btintel_pcie_yoyo_ctx *ctx, u32 alloc_id);\n+\n+#endif /* __BTINTEL_PCIE_DEBUG_H__ */\n"
} |
| 2/1 | 2026/10/14 11:44 | agent | patch-evaluator |
1mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch series modifies the btintel_pcie driver and introduces the btintel_pcie_debug module, which implements runtime debug configuration (YoYo) for Intel Bluetooth PCIe controllers. This driver binds specifically to physical Intel PCIe hardware (such as Lunar Lake, Panther Lake, Nova Lake, Blazar) that is not emulated in standard QEMU or GCE virtualized environments. Because the hardware is structurally unreachable during standard kernel fuzzing, the modified code cannot be executed.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit cf67a365d111ae83083862ed2f92b6c6271be6fa
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Oct 14 11:44:30 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index d5eb2568af2e9..7d933755b2916 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -14,7 +14,7 @@ obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
obj-$(CONFIG_BT_INTEL) += btintel.o
-obj-$(CONFIG_BT_INTEL_PCIE) += btintel_pcie.o btintel.o
+obj-$(CONFIG_BT_INTEL_PCIE) += btintel_pcie.o btintel.o btintel_pcie_debug.o
obj-$(CONFIG_BT_ATH3K) += ath3k.o
obj-$(CONFIG_BT_MRVL) += btmrvl.o
obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index 3a555aa50c873..aae8c0c833917 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -203,6 +203,103 @@ static inline bool btintel_pcie_dbg_to_wifi(struct btintel_pcie_data *data)
return data->dbg_path_cache != BTINTEL_PCIE_DRAM;
}
+/* Name of the optional INI file used to override the default dbg_path
+ * (data->dbg_path_cache) and yoyo ini settings.
+ */
+#define BTINTEL_PCIE_DBG_INI_FILE "ibt_bt_dbg_cfg.ini"
+
+/* Loads optional "DBG_PATH=<value>" and ENABLE_INI=<value>
+ * overrides from BTINTEL_PCIE_DBG_INI_FILE
+ * and applies them to data->dbg_path_cache and data->enable_ini.
+ *
+ * DBG_PATH accepts BTINTEL_PCIE_WIFI_DBGC (0x06, default) and
+ * BTINTEL_PCIE_DRAM (0x01, legacy); an invalid or missing entry leaves
+ * the cached value set by the caller unchanged.
+ *
+ * ENABLE_INI accepts 1 (enabled) or 0 (disabled); an invalid or missing
+ * entry leaves data->enable_ini unchanged.
+ */
+static void btintel_pcie_load_dbg_path_from_ini(struct btintel_pcie_data *data)
+{
+ const struct firmware *fw;
+ const char *ini_file = BTINTEL_PCIE_DBG_INI_FILE;
+ char *buf, *cursor, *line;
+ bool dbg_path_applied = false;
+ int err;
+
+ err = request_firmware_direct(&fw, ini_file, &data->pdev->dev);
+ if (err < 0) {
+ BT_DBG("%s not found (%d), using dbg_path=0x%02x",
+ ini_file, err, data->dbg_path_cache);
+ return;
+ }
+
+ buf = kmemdup_nul(fw->data, fw->size, GFP_KERNEL);
+ release_firmware(fw);
+ if (!buf)
+ return;
+
+ cursor = buf;
+ while ((line = strsep(&cursor, "\n"))) {
+ char *eq;
+ char *val;
+ uint parsed;
+
+ line = strim(line);
+ if (!line[0] || line[0] == '#' || line[0] == ';')
+ continue;
+
+ eq = strchr(line, '=');
+ if (!eq)
+ continue;
+
+ *eq = '\0';
+ line = strim(line);
+ val = strim(eq + 1);
+
+ /* Accept "DBG_PATH"/"dbg_path"
+ * case-insensitively as the key.
+ */
+ if (!strcasecmp(line, "DBG_PATH")) {
+ BT_INFO("Read DBG_PATH from %s: '%s'", ini_file, val);
+
+ /* base 0 lets kstrtouint accept "0x06", "6", etc. */
+ if (kstrtouint(val, 0, &parsed) == 0 &&
+ (parsed == BTINTEL_PCIE_DRAM ||
+ parsed == BTINTEL_PCIE_WIFI_DBGC)) {
+ data->dbg_path_cache = parsed;
+ dbg_path_applied = true;
+ BT_INFO("WRT dbg_path accepted: 0x%02x",
+ data->dbg_path_cache);
+ } else {
+ BT_WARN("Invalid DBG_PATH='%s' in %s, using dbg_path=0x%02x",
+ val, ini_file, data->dbg_path_cache);
+ }
+ } else if (!strcasecmp(line, "ENABLE_INI")) {
+ BT_INFO("Read ENABLE_INI from %s: '%s'", ini_file, val);
+
+ if (kstrtouint(val, 0, &parsed) == 0 &&
+ (parsed == 0 || parsed == 1)) {
+ data->enable_ini = !!parsed;
+ BT_INFO("WRT enable_ini accepted: %u",
+ data->enable_ini);
+ } else {
+ BT_WARN("Invalid ENABLE_INI='%s' in %s, using enable_ini=%u",
+ val, ini_file, data->enable_ini);
+ }
+ }
+ }
+
+ if (dbg_path_applied)
+ BT_DBG("Loaded dbg_path=0x%02x from %s", data->dbg_path_cache, ini_file);
+ else
+ BT_WARN("No valid DBG_PATH in %s, dbg_path=0x%02x", ini_file, data->dbg_path_cache);
+
+ BT_DBG("ENABLE_INI effective state: %u", data->enable_ini);
+
+ kfree(buf);
+}
+
/* Helper function to allocate and setup a debug buffer group
* @data: driver data structure
* @buf: pointer to data_buf array pointer
@@ -218,7 +315,8 @@ static int btintel_pcie_alloc_dbgc_buf(struct btintel_pcie_data *data,
void **v_addr,
struct btintel_pcie_dbgc_ctxt_buf *frag,
u32 buf_index,
- u32 buf_count)
+ u32 buf_count,
+ u32 per_buf_size)
{
struct data_buf *b;
int i;
@@ -231,8 +329,7 @@ static int btintel_pcie_alloc_dbgc_buf(struct btintel_pcie_data *data,
}
*v_addr = dmam_alloc_coherent(&data->pdev->dev,
- buf_count *
- BTINTEL_PCIE_DBGC_BUFFER_SIZE,
+ buf_count * per_buf_size,
p_addr,
GFP_KERNEL | __GFP_NOWARN);
if (!*v_addr) {
@@ -242,16 +339,40 @@ static int btintel_pcie_alloc_dbgc_buf(struct btintel_pcie_data *data,
for (i = 0; i < buf_count; i++) {
b = &(*buf)[i];
- b->data_p_addr = *p_addr + i * BTINTEL_PCIE_DBGC_BUFFER_SIZE;
- b->data = *v_addr + i * BTINTEL_PCIE_DBGC_BUFFER_SIZE;
+ b->data_p_addr = *p_addr + i * per_buf_size;
+ b->data = *v_addr + i * per_buf_size;
frag[i].buf_addr_lsb = lower_32_bits(b->data_p_addr);
frag[i].buf_addr_msb = upper_32_bits(b->data_p_addr);
- frag[i].buf_size = BTINTEL_PCIE_DBGC_BUFFER_SIZE;
+ frag[i].buf_size = per_buf_size;
}
+ BT_INFO("dbgc buf %u allocated: frag_num=%u per_buf_size=%u total_size=%u",
+ buf_index + 1, buf_count, per_buf_size, buf_count * per_buf_size);
+
return 0;
}
+/* Returns false if YoYo is enabled and @alloc_id is not configured */
+static bool btintel_pcie_get_mdbgc_cfg(struct btintel_pcie_data *data,
+ u32 alloc_id, u32 *count, u32 *size)
+{
+ const struct btintel_pcie_buf_alloc *ba;
+
+ ba = btintel_pcie_yoyo_get_buf_alloc(&data->yoyo, alloc_id);
+ if (ba) {
+ *count = ba->max_num_frags;
+ *size = ba->req_buf_size / ba->max_num_frags;
+ return true;
+ }
+
+ if (data->yoyo.enabled)
+ return false;
+
+ *count = BTINTEL_PCIE_DBGC_BUFFER_COUNT;
+ *size = BTINTEL_PCIE_DBGC_BUFFER_SIZE;
+ return true;
+}
+
/* This function initializes the memory for MDBGC buffers and formats the
* DBGC fragment which consists header info and DBGC buffer's LSB, MSB and
* size as the payload
@@ -261,10 +382,9 @@ static int btintel_pcie_setup_mdbgc(struct btintel_pcie_data *data)
struct btintel_pcie_mdbgc_ctxt db_frag;
u32 frag_size = sizeof(db_frag);
void *frag_v_addr;
+ u32 buf_count, buf_size;
int err;
- data->mdbgc.count = BTINTEL_PCIE_DBGC_BUFFER_COUNT;
-
/* Allocate fragment context structure */
frag_v_addr = dmam_alloc_coherent(&data->pdev->dev, frag_size,
&data->mdbgc.frag_p_addr,
@@ -283,46 +403,71 @@ static int btintel_pcie_setup_mdbgc(struct btintel_pcie_data *data)
db_frag.ver = BTINTEL_PCIE_MDBGC_FRAG_VERSION;
/* Allocate DBGC buffer 1 */
- db_frag.buf1_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_1;
- db_frag.buf1_count = data->mdbgc.count;
- err = btintel_pcie_alloc_dbgc_buf(data,
- &data->mdbgc.buf1,
- &data->mdbgc.buf1_p_addr,
- &data->mdbgc.buf1_v_addr,
- db_frag.buf1,
- 0,
- data->mdbgc.count);
- if (err)
- return err;
+ if (btintel_pcie_get_mdbgc_cfg(data, BTINTEL_PCIE_ALLOC_ID_DBGC1,
+ &buf_count, &buf_size)) {
+ db_frag.buf1_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_1;
+ data->mdbgc.buf1_count = buf_count;
+ data->mdbgc.buf1_size = buf_size;
+ db_frag.buf1_count = buf_count;
+
+ err = btintel_pcie_alloc_dbgc_buf(data,
+ &data->mdbgc.buf1,
+ &data->mdbgc.buf1_p_addr,
+ &data->mdbgc.buf1_v_addr,
+ db_frag.buf1,
+ 0,
+ buf_count,
+ buf_size);
+ if (err)
+ return err;
+ }
/* Allocate DBGC buffer 2 */
- db_frag.buf2_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_2;
- db_frag.buf2_count = data->mdbgc.count;
- err = btintel_pcie_alloc_dbgc_buf(data,
- &data->mdbgc.buf2,
- &data->mdbgc.buf2_p_addr,
- &data->mdbgc.buf2_v_addr,
- db_frag.buf2,
- 1,
- data->mdbgc.count);
- if (err)
- return err;
+ if (btintel_pcie_get_mdbgc_cfg(data, BTINTEL_PCIE_ALLOC_ID_DBGC2,
+ &buf_count, &buf_size)) {
+ db_frag.buf2_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_2;
+ data->mdbgc.buf2_count = buf_count;
+ data->mdbgc.buf2_size = buf_size;
+ db_frag.buf2_count = buf_count;
+
+ err = btintel_pcie_alloc_dbgc_buf(data,
+ &data->mdbgc.buf2,
+ &data->mdbgc.buf2_p_addr,
+ &data->mdbgc.buf2_v_addr,
+ db_frag.buf2,
+ 1,
+ buf_count,
+ buf_size);
+ if (err)
+ return err;
+ }
/* Allocate DBGC buffer 3 */
- db_frag.buf3_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_3;
- db_frag.buf3_count = data->mdbgc.count;
- err = btintel_pcie_alloc_dbgc_buf(data,
- &data->mdbgc.buf3,
- &data->mdbgc.buf3_p_addr,
- &data->mdbgc.buf3_v_addr,
- db_frag.buf3,
- 2,
- data->mdbgc.count);
- if (err)
- return err;
+ if (btintel_pcie_get_mdbgc_cfg(data, BTINTEL_PCIE_ALLOC_ID_DBGC3,
+ &buf_count, &buf_size)) {
+ db_frag.buf3_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_3;
+ data->mdbgc.buf3_count = buf_count;
+ data->mdbgc.buf3_size = buf_size;
+ db_frag.buf3_count = buf_count;
+
+ err = btintel_pcie_alloc_dbgc_buf(data,
+ &data->mdbgc.buf3,
+ &data->mdbgc.buf3_p_addr,
+ &data->mdbgc.buf3_v_addr,
+ db_frag.buf3,
+ 2,
+ buf_count,
+ buf_size);
+ if (err)
+ return err;
+ }
/* Copy fragment to DMA coherent memory */
memcpy(data->mdbgc.frag_v_addr, &db_frag, sizeof(db_frag));
+ BT_INFO("MDBGC: buf1 frag=%u size=%u; buf2 frag=%u size=%u; buf3 frag=%u size=%u",
+ db_frag.buf1_count, db_frag.buf1_count * db_frag.buf1[0].buf_size,
+ db_frag.buf2_count, db_frag.buf2_count * db_frag.buf2[0].buf_size,
+ db_frag.buf3_count, db_frag.buf3_count * db_frag.buf3[0].buf_size);
return 0;
}
@@ -334,9 +479,21 @@ static int btintel_pcie_setup_dbgc(struct btintel_pcie_data *data)
{
struct btintel_pcie_dbgc_ctxt db_frag;
u32 frag_size = sizeof(db_frag);
+ const struct btintel_pcie_buf_alloc *ba;
+ u32 buf_count, buf_size;
int err;
- data->dbgc.count = BTINTEL_PCIE_DBGC_BUFFER_COUNT;
+ ba = btintel_pcie_yoyo_get_buf_alloc(&data->yoyo,
+ BTINTEL_PCIE_ALLOC_ID_DBGC1);
+ buf_count = ba ? ba->max_num_frags : BTINTEL_PCIE_DBGC_BUFFER_COUNT;
+ buf_size = ba ? ba->req_buf_size / ba->max_num_frags :
+ BTINTEL_PCIE_DBGC_BUFFER_SIZE;
+
+ BT_INFO("dbgc setup: frag_num=%u per_buf_size=%u total_size=%u",
+ buf_count, buf_size, buf_count * buf_size);
+
+ data->dbgc.count = buf_count;
+ data->dbgc.buf_size = buf_size;
/* Allocate fragment context structure */
data->dbgc.frag_v_addr = dmam_alloc_coherent(&data->pdev->dev,
@@ -354,8 +511,9 @@ static int btintel_pcie_setup_dbgc(struct btintel_pcie_data *data)
memset(&db_frag, 0, sizeof(db_frag));
db_frag.magic_num = BTINTEL_PCIE_MAGIC_NUM;
db_frag.ver = BTINTEL_PCIE_DBGC_FRAG_VERSION;
- db_frag.total_size = BTINTEL_PCIE_DBGC_FRAG_PAYLOAD_SIZE;
- db_frag.num_buf = BTINTEL_PCIE_DBGC_FRAG_BUFFER_COUNT;
+ db_frag.total_size = sizeof(db_frag.num_buf) +
+ buf_count * sizeof(db_frag.bufs[0]);
+ db_frag.num_buf = buf_count;
/* Allocate DBGC buffers */
err = btintel_pcie_alloc_dbgc_buf(data,
@@ -364,7 +522,8 @@ static int btintel_pcie_setup_dbgc(struct btintel_pcie_data *data)
&data->dbgc.buf_v_addr,
db_frag.bufs,
0,
- data->dbgc.count);
+ buf_count,
+ buf_size);
if (err)
return err;
@@ -857,7 +1016,8 @@ static u32 btintel_pcie_dump_list_total_size(struct list_head *list)
}
static int btintel_pcie_dump_dram(struct list_head *list,
- u8 count, struct data_buf *bufs,
+ u8 count, u32 buf_size,
+ struct data_buf *bufs,
u32 write_ptr, u32 wrap_ctr, u32 cur_frag,
u32 region_id, const char *name)
{
@@ -869,7 +1029,7 @@ static int btintel_pcie_dump_dram(struct list_head *list,
int i;
mon_hdr_size = sizeof(*mon_dump);
- ranges_size = count * (sizeof(*range) + BTINTEL_PCIE_DBGC_BUFFER_SIZE);
+ ranges_size = count * (sizeof(*range) + buf_size);
payload_size = mon_hdr_size + ranges_size;
total_size = sizeof(*dump_data) + payload_size;
@@ -898,12 +1058,10 @@ static int btintel_pcie_dump_dram(struct list_head *list,
range = (void *)mon_dump->data;
for (i = 0; i < count; i++) {
- range->range_data_size =
- cpu_to_le32(BTINTEL_PCIE_DBGC_BUFFER_SIZE);
+ range->range_data_size = cpu_to_le32(buf_size);
range->dram_base_addr = cpu_to_le64(bufs[i].data_p_addr);
- memcpy(range->data, bufs[i].data,
- BTINTEL_PCIE_DBGC_BUFFER_SIZE);
- range = (void *)range->data + BTINTEL_PCIE_DBGC_BUFFER_SIZE;
+ memcpy(range->data, bufs[i].data, buf_size);
+ range = (void *)range->data + buf_size;
}
list_add_tail(&entry->list, list);
@@ -912,7 +1070,8 @@ static int btintel_pcie_dump_dram(struct list_head *list,
static int
btintel_pcie_dump_dram_monitor(struct btintel_pcie_data *data,
- struct list_head *list, u8 count,
+ struct list_head *list, u8 count,
+ u32 buf_size,
struct data_buf *bufs, u32 status_reg,
u32 wrap_reg, u8 allocation_id, u32 region_id,
const char *name)
@@ -920,6 +1079,9 @@ btintel_pcie_dump_dram_monitor(struct btintel_pcie_data *data,
u32 allocation_offset, write_ptr, wrap_ctr, wr_ptr_status;
u8 cur_frag;
+ if (!count)
+ return -ENOENT;
+
allocation_offset = allocation_id *
BTINTEL_PCIE_DBGC_ALLOCATION_OFFSET;
wr_ptr_status = btintel_pcie_rd_dev_mem(data, status_reg +
@@ -941,8 +1103,8 @@ btintel_pcie_dump_dram_monitor(struct btintel_pcie_data *data,
"allocation=%u wr_ptr_status=0x%08x write_ptr=0x%06x cur_frag=%u wrap_ctr=0x%08x",
allocation_id, wr_ptr_status, write_ptr, cur_frag, wrap_ctr);
- return btintel_pcie_dump_dram(list, count, bufs, write_ptr, wrap_ctr,
- cur_frag, region_id, name);
+ return btintel_pcie_dump_dram(list, count, buf_size, bufs, write_ptr,
+ wrap_ctr, cur_frag, region_id, name);
}
static int btintel_pcie_dump_target_region(struct btintel_pcie_data *data,
@@ -1223,6 +1385,7 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)
u8 hw_variant;
u32 file_len;
u8 count;
+ u32 buf_size;
int ret;
LIST_HEAD(dump_list);
@@ -1231,10 +1394,12 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)
if (btintel_pcie_is_mdbgc_supported(data)) {
mdbgc = &data->mdbgc;
- count = mdbgc->count;
+ count = mdbgc->buf1_count;
+ buf_size = mdbgc->buf1_size;
} else {
dbgc = &data->dbgc;
count = dbgc->count;
+ buf_size = dbgc->buf_size;
}
hw_variant = INTEL_HW_VARIANT(data->cnvi);
@@ -1254,7 +1419,9 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)
}
if (btintel_pcie_is_mdbgc_supported(data)) {
- ret = btintel_pcie_dump_dram_monitor(data, &dump_list, count,
+ ret = btintel_pcie_dump_dram_monitor(data, &dump_list,
+ mdbgc->buf1_count,
+ mdbgc->buf1_size,
mdbgc->buf1, status_reg,
wrap_reg,
BTINTEL_PCIE_MDBGC_ALLOCATIONID_1,
@@ -1263,10 +1430,12 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)
if (!ret)
regions_mask |=
BIT_ULL(BTINTEL_PCIE_INI_ID_DRAM_MONITOR1);
- else
+ else if (ret != -ENOENT)
bt_dev_warn(hdev, "Failed to dump DRAM buf1: %d", ret);
- ret = btintel_pcie_dump_dram_monitor(data, &dump_list, count,
+ ret = btintel_pcie_dump_dram_monitor(data, &dump_list,
+ mdbgc->buf2_count,
+ mdbgc->buf2_size,
mdbgc->buf2, status_reg,
wrap_reg,
BTINTEL_PCIE_MDBGC_ALLOCATIONID_2,
@@ -1275,10 +1444,12 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)
if (!ret)
regions_mask |=
BIT_ULL(BTINTEL_PCIE_INI_ID_DRAM_MONITOR2);
- else
+ else if (ret != -ENOENT)
bt_dev_warn(hdev, "Failed to dump DRAM buf2: %d", ret);
- ret = btintel_pcie_dump_dram_monitor(data, &dump_list, count,
+ ret = btintel_pcie_dump_dram_monitor(data, &dump_list,
+ mdbgc->buf3_count,
+ mdbgc->buf3_size,
mdbgc->buf3, status_reg,
wrap_reg,
BTINTEL_PCIE_MDBGC_ALLOCATIONID_3,
@@ -1287,11 +1458,12 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)
if (!ret)
regions_mask |=
BIT_ULL(BTINTEL_PCIE_INI_ID_DRAM_MONITOR3);
- else
+ else if (ret != -ENOENT)
bt_dev_warn(hdev, "Failed to dump DRAM buf3: %d", ret);
} else {
ret = btintel_pcie_dump_dram_monitor(data, &dump_list, count,
- dbgc->bufs, status_reg,
+ buf_size, dbgc->bufs,
+ status_reg,
wrap_reg,
BTINTEL_PCIE_MDBGC_ALLOCATIONID_1,
BTINTEL_PCIE_INI_ID_DRAM_MONITOR1,
@@ -3183,7 +3355,7 @@ static int btintel_pcie_alloc(struct btintel_pcie_data *data)
err = btintel_pcie_setup_dbgc(data);
}
if (err)
- goto exit_error_txq;
+ goto exit_error_rxq;
/* Setup Context Information */
data->ci = v_addr;
@@ -3194,6 +3366,9 @@ static int btintel_pcie_alloc(struct btintel_pcie_data *data)
return 0;
+exit_error_rxq:
+ /* RX setup succeeded, so release its buffers before the shared unwind. */
+ btintel_pcie_free_rxq_bufs(data, &data->rxq);
exit_error_txq:
btintel_pcie_free_txq_bufs(data, &data->txq);
exit_error_pool:
@@ -4097,10 +4272,25 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
data->boot_stage_cache = 0x00;
data->img_resp_cache = 0x00;
data->dbg_path_cache = BTINTEL_PCIE_WIFI_DBGC;
+ data->enable_ini = false;
+ btintel_pcie_yoyo_init(&data->yoyo);
/* FLR can be invoked by echoing to debugfs path, so explicitly
* initialized
*/
data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR;
+
+ btintel_pcie_load_dbg_path_from_ini(data);
+ if (data->dbg_path_cache != BTINTEL_PCIE_DRAM)
+ data->enable_ini = false;
+
+ if (data->enable_ini) {
+ err = btintel_pcie_yoyo_load_and_parse(&data->yoyo, &pdev->dev);
+ if (err) {
+ BT_WARN("YoYo is not configured (%d)", err);
+ btintel_pcie_yoyo_cleanup(&data->yoyo);
+ }
+ }
+
err = btintel_pcie_config_pcie(pdev, data);
if (err)
goto exit_error;
@@ -4128,11 +4318,14 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
if (err)
goto exit_error;
+ data->yoyo.hdev = data->hdev;
bt_dev_dbg(data->hdev, "cnvi: 0x%8.8x cnvr: 0x%8.8x", data->cnvi,
data->cnvr);
return 0;
exit_error:
+ btintel_pcie_yoyo_cleanup(&data->yoyo);
+
/* reset device before exit */
btintel_pcie_reset_bt(data);
@@ -4173,6 +4366,8 @@ static void btintel_pcie_remove(struct pci_dev *pdev)
if (current_work() != &data->reset_work)
disable_work_sync(&data->reset_work);
+ btintel_pcie_yoyo_cleanup(&data->yoyo);
+
btintel_pcie_disable_interrupts(data);
btintel_pcie_synchronize_irqs(data);
diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h
index 3030b4e8b7503..d68f83a629224 100644
--- a/drivers/bluetooth/btintel_pcie.h
+++ b/drivers/bluetooth/btintel_pcie.h
@@ -6,6 +6,8 @@
* Copyright (C) 2024 Intel Corporation
*/
+#include "btintel_pcie_debug.h"
+
/* Control and Status Register(BTINTEL_PCIE_CSR) */
#define BTINTEL_PCIE_CSR_BASE (0x000)
#define BTINTEL_PCIE_CSR_FUNC_CTRL_REG (BTINTEL_PCIE_CSR_BASE + 0x024)
@@ -466,6 +468,7 @@ struct rxq {
*/
struct btintel_pcie_dbgc {
u16 count;
+ u32 buf_size;
void *frag_v_addr;
dma_addr_t frag_p_addr;
@@ -477,7 +480,12 @@ struct btintel_pcie_dbgc {
};
struct btintel_pcie_mdbgc {
- u32 count;
+ u32 buf1_count;
+ u32 buf1_size;
+ u32 buf2_count;
+ u32 buf2_size;
+ u32 buf3_count;
+ u32 buf3_size;
void *frag_v_addr;
dma_addr_t frag_p_addr;
@@ -737,6 +745,8 @@ struct btintel_pcie_data {
u32 boot_stage_cache;
u32 img_resp_cache;
u32 dbg_path_cache;
+ bool enable_ini;
+ struct btintel_pcie_yoyo_ctx yoyo;
u32 cnvi;
u32 cnvr;
diff --git a/drivers/bluetooth/btintel_pcie_debug.c b/drivers/bluetooth/btintel_pcie_debug.c
new file mode 100644
index 0000000000000..5af00784bf962
--- /dev/null
+++ b/drivers/bluetooth/btintel_pcie_debug.c
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Bluetooth YoYo Debug Framework
+ *
+ * Copyright (C) 2026 Intel Corporation
+ *
+ * Runtime-configurable TLV-based debug collection framework for loading and
+ * parsing the optional YoYo firmware configuration used to enable debug
+ * regions, triggers, HCI commands, and configuration sets.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/unaligned.h>
+#include <net/bluetooth/bluetooth.h>
+#include "btintel_pcie_debug.h"
+
+/* TLV-specific parser DEBUG_INFO TLV type */
+static int btintel_pcie_yoyo_parse_dbg_info(struct btintel_pcie_yoyo_ctx *ctx,
+ const struct btintel_pcie_tlv_dbg_info *info,
+ u32 len)
+{
+ const u8 *data = (const u8 *)info;
+ u32 domain, image_type, core_type, version;
+
+ if (len != sizeof(*info) - sizeof(struct btintel_pcie_tlv_hdr))
+ return -EBADMSG;
+
+ image_type = get_unaligned_le32(data +
+ offsetof(struct btintel_pcie_tlv_dbg_info,
+ image_type));
+ core_type = get_unaligned_le32(data +
+ offsetof(struct btintel_pcie_tlv_dbg_info,
+ core_type));
+ domain = get_unaligned_le32(data +
+ offsetof(struct btintel_pcie_tlv_dbg_info,
+ dbg_hdr.domain));
+ version = get_unaligned_le32(data +
+ offsetof(struct btintel_pcie_tlv_dbg_info,
+ dbg_hdr.tlv_data_version));
+
+ if (domain != BTINTEL_PCIE_DOMAIN_BT ||
+ version != BTINTEL_PCIE_DBG_INFO_TLV_VERSION) {
+ BT_WARN("YoYo: unsupported domain/version (%u/%u), disabling",
+ domain, version);
+ return -EINVAL;
+ }
+
+ if (image_type != BTINTEL_PCIE_IMAGE_TLV_TYPE_EXTERNAL) {
+ BT_WARN("YoYo: unsupported image_type 0x%x, disabling", image_type);
+ return -EINVAL;
+ }
+
+ if (core_type != BTINTEL_PCIE_CORE_TYPE_BT) {
+ BT_WARN("YoYo: non BT core_type %u, disabling", core_type);
+ return -EINVAL;
+ }
+
+ ctx->dbg_info_present = true;
+ BT_DBG("YoYo: config='%.64s' image=%u core=%u",
+ info->config_name, image_type, core_type);
+ return 0;
+}
+
+static int btintel_pcie_yoyo_parse_buf_alloc(struct btintel_pcie_yoyo_ctx *ctx,
+ const struct btintel_pcie_tlv_buf_alloc *tlv,
+ u32 len)
+{
+ u32 alloc_id, buf_location, domain, idx, max_num_frags, min_buf_size;
+ u32 req_buf_size, version;
+
+ if (len != sizeof(*tlv) - sizeof(struct btintel_pcie_tlv_hdr)) {
+ BT_WARN("YoYo: unexpected buf alloc TLV length %u", len);
+ return -EBADMSG;
+ }
+
+ domain = get_unaligned_le32(&tlv->dbg_hdr.domain);
+ version = get_unaligned_le32(&tlv->dbg_hdr.tlv_data_version);
+ if (domain != BTINTEL_PCIE_DOMAIN_BT ||
+ version != BTINTEL_PCIE_BUF_ALLOC_TLV_VERSION) {
+ BT_WARN("YoYo: unsupported buf allocation domain/version (%u/%u)",
+ domain, version);
+ return -EINVAL;
+ }
+
+ alloc_id = get_unaligned_le32(&tlv->alloc_id);
+ if (alloc_id < BTINTEL_PCIE_ALLOC_ID_DBGC1 ||
+ alloc_id > BTINTEL_PCIE_ALLOC_ID_DBGC3) {
+ BT_WARN("YoYo: invalid buf allocation id %u", alloc_id);
+ return -EINVAL;
+ }
+
+ idx = alloc_id - BTINTEL_PCIE_ALLOC_ID_DBGC1;
+ buf_location = get_unaligned_le32(&tlv->buf_location);
+ max_num_frags = get_unaligned_le32(&tlv->max_num_frags);
+ min_buf_size = get_unaligned_le32(&tlv->min_buf_size);
+ req_buf_size = get_unaligned_le32(&tlv->req_buf_size);
+
+ if (buf_location != BTINTEL_PCIE_BUF_LOC_DRAM) {
+ BT_WARN("YoYo: buf allocation id=%u unsupported buffer location %u",
+ alloc_id, buf_location);
+ return -EINVAL;
+ }
+
+ if (!max_num_frags || max_num_frags > BTINTEL_PCIE_MAX_BUF_FRAGS ||
+ min_buf_size < BTINTEL_PCIE_MIN_BUF_SIZE ||
+ min_buf_size > BTINTEL_PCIE_MAX_BUF_SIZE ||
+ req_buf_size > BTINTEL_PCIE_MAX_BUF_SIZE ||
+ req_buf_size % max_num_frags ||
+ req_buf_size / max_num_frags < min_buf_size) {
+ BT_WARN("YoYo: buf allocation id=%u req size=%u max frags=%u min size=%u",
+ alloc_id, req_buf_size, max_num_frags, min_buf_size);
+ return -EINVAL;
+ }
+
+ ctx->buf_alloc[idx].alloc_id = alloc_id;
+ ctx->buf_alloc[idx].buf_location = buf_location;
+ ctx->buf_alloc[idx].req_buf_size = req_buf_size;
+ ctx->buf_alloc[idx].max_num_frags = max_num_frags;
+ ctx->buf_alloc[idx].min_buf_size = min_buf_size;
+ ctx->buf_alloc[idx].present = true;
+
+ if (idx + 1 > ctx->num_buf_allocs)
+ ctx->num_buf_allocs = idx + 1;
+
+ BT_DBG("YoYo: buf allocation id=%u loc=%u req size=%u max frags=%u min size=%u",
+ alloc_id, ctx->buf_alloc[idx].buf_location,
+ ctx->buf_alloc[idx].req_buf_size,
+ ctx->buf_alloc[idx].max_num_frags,
+ ctx->buf_alloc[idx].min_buf_size);
+
+ return 0;
+}
+
+/*
+ * Parse the optional YoYo firmware TLV stream and validate each record.
+ * This is the entry point for the runtime debug configuration payload.
+ */
+static int btintel_pcie_yoyo_parse_tlv_buffer(struct btintel_pcie_yoyo_ctx *ctx,
+ const u8 *buf, size_t buf_len)
+{
+ const struct btintel_pcie_tlv_hdr *tlv;
+ const u8 *ptr = buf;
+ size_t remaining = buf_len;
+ u32 count = 0;
+ int ret = 0;
+
+ while (remaining >= sizeof(*tlv)) {
+ size_t tlv_size;
+ u32 type, len;
+
+ tlv = (const struct btintel_pcie_tlv_hdr *)ptr;
+ type = get_unaligned_le32(&tlv->type);
+ len = get_unaligned_le32(&tlv->length);
+
+ if (len > remaining - sizeof(*tlv)) {
+ BT_ERR("YoYo: tlv %u truncated (len=%u rem=%zu)", count,
+ len, remaining);
+ return -EBADMSG;
+ }
+ tlv_size = sizeof(*tlv) + len;
+
+ switch (type) {
+ case BTINTEL_PCIE_TLV_TYPE_DBG_INFO:
+ ret = btintel_pcie_yoyo_parse_dbg_info(ctx,
+ (const void *)tlv, len);
+ if (ret) {
+ ctx->dbg_info_present = false;
+ }
+ break;
+ case BTINTEL_PCIE_TLV_TYPE_DBG_BUF_ALLOC:
+ ret = btintel_pcie_yoyo_parse_buf_alloc(ctx,
+ (const void *)tlv, len);
+ break;
+ case BTINTEL_PCIE_TLV_TYPE_DBG_REGION:
+ case BTINTEL_PCIE_TLV_TYPE_DBG_TRIGGER:
+ case BTINTEL_PCIE_TLV_TYPE_DBG_HCMD:
+ case BTINTEL_PCIE_TLV_TYPE_DBG_CONFIG_SET:
+ case BTINTEL_PCIE_TLV_TYPE_DBG_PRESET_OVERRIDE:
+ BT_DBG("YoYo: valid tlv type 0x%x len=%u", type, len);
+ break;
+ default: /* Log and continue, do not fail*/
+ BT_DBG("YoYo: unknown tlv type 0x%x len=%u", type, len);
+ break;
+ }
+
+ ptr += tlv_size;
+ remaining -= tlv_size;
+
+ if (ret) {
+ BT_ERR("YoYo: error parsing tlv type 0x%x (ret=%d)", type, ret);
+ return ret;
+ }
+
+ count++;
+ }
+
+ /* If no TLVs were parsed, the YoYo binary is considered invalid */
+ if (remaining || count == 0) {
+ BT_ERR("YoYo: trailing %zu bytes after tlv stream", remaining);
+ return -EBADMSG;
+ }
+ if (!ctx->num_buf_allocs) {
+ BT_ERR("YoYo: mandatory buffer allocation TLV missing");
+ return -EBADMSG;
+ }
+
+ BT_DBG("YoYo: parsed %u tlv's", count);
+ return 0;
+}
+
+/**
+ * btintel_yoyo_init - Initialize the YoYo context
+ * @ctx: Pre-allocated context (typically embedded in driver data)
+ */
+int btintel_pcie_yoyo_init(struct btintel_pcie_yoyo_ctx *ctx)
+{
+ if (!ctx)
+ return -EINVAL;
+
+ memset(ctx, 0, sizeof(*ctx));
+ INIT_LIST_HEAD(&ctx->region_list);
+ INIT_LIST_HEAD(&ctx->trigger_list);
+ INIT_LIST_HEAD(&ctx->hcmd_list);
+ INIT_LIST_HEAD(&ctx->config_set_list);
+
+ /* set it to true after successful TLV parsing */
+ ctx->enabled = false;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_init);
+
+/**
+ * btintel_yoyo_cleanup - Clean up the YoYo context
+ * @ctx: YoYo context to clean up
+ */
+void btintel_pcie_yoyo_cleanup(struct btintel_pcie_yoyo_ctx *ctx)
+{
+ if (!ctx)
+ return;
+
+ ctx->enabled = false;
+ ctx->dbg_info_present = false;
+ ctx->num_buf_allocs = 0;
+ memset(ctx->buf_alloc, 0, sizeof(ctx->buf_alloc));
+}
+EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_cleanup);
+
+/**
+ * btintel_yoyo_load_and_parse - Load ibt_debug_yoyo.bin and parse TLVs
+ * @ctx: Initialized YoYo context
+ * @dev: Device for firmware loading (typically &pdev->dev)
+ *
+ * Uses request_firmware_direct, since the YoYo binary
+ * is optional. On success, sets ctx->enabled.
+ */
+int btintel_pcie_yoyo_load_and_parse(struct btintel_pcie_yoyo_ctx *ctx,
+ struct device *dev)
+{
+ const struct firmware *fw;
+ int ret;
+
+ if (!ctx)
+ return -EINVAL;
+
+ ret = request_firmware_direct(&fw, BTINTEL_PCIE_YOYO_FW_NAME, dev);
+ if (ret) {
+ BT_WARN("YoYo: failed to load %s (%d)",
+ BTINTEL_PCIE_YOYO_FW_NAME, ret);
+ return ret;
+ }
+
+ /* Sanity check firmware size */
+ if (fw->size < sizeof(struct btintel_pcie_tlv_hdr)) {
+ release_firmware(fw);
+ return -EBADMSG;
+ }
+
+ BT_DBG("YoYo: loaded %s (%zu bytes)", BTINTEL_PCIE_YOYO_FW_NAME,
+ fw->size);
+
+ ret = btintel_pcie_yoyo_parse_tlv_buffer(ctx, fw->data, fw->size);
+ release_firmware(fw);
+
+ /* File Corruption / TLV validation failed */
+ if (ret) {
+ BT_ERR("YoYo: tlv parsing failed (%d)", ret);
+ return ret;
+ }
+ if (!ctx->dbg_info_present) {
+ BT_ERR("YoYo: Invalid BT debug Info tlv, using legacy DBGC defaults");
+ return -EBADMSG;
+ }
+
+ ctx->enabled = true;
+
+ BT_INFO("YoYo: feature enabled and configured");
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_load_and_parse);
+
+/**
+ * btintel_pcie_yoyo_get_buf_alloc - Query buffer allocation config for a DBGC
+ * @ctx: YoYo context
+ * @alloc_id: Allocation ID (1=DBGC1, 2=DBGC2, 3=DBGC3)
+ *
+ * Return the parsed configuration, or NULL if no matching TLV was present.
+ */
+const struct btintel_pcie_buf_alloc *
+btintel_pcie_yoyo_get_buf_alloc(struct btintel_pcie_yoyo_ctx *ctx, u32 alloc_id)
+{
+ u32 idx;
+
+ if (!ctx || !ctx->enabled ||
+ alloc_id < BTINTEL_PCIE_ALLOC_ID_DBGC1 ||
+ alloc_id > BTINTEL_PCIE_ALLOC_ID_DBGC3)
+ return NULL;
+
+ idx = alloc_id - BTINTEL_PCIE_ALLOC_ID_DBGC1;
+ if (!ctx->buf_alloc[idx].present)
+ return NULL;
+
+ return &ctx->buf_alloc[idx];
+}
+EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_get_buf_alloc);
+
+MODULE_DESCRIPTION("Intel Bluetooth yoyo debug framework");
+MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/btintel_pcie_debug.h b/drivers/bluetooth/btintel_pcie_debug.h
new file mode 100644
index 0000000000000..5ed368fb13d1e
--- /dev/null
+++ b/drivers/bluetooth/btintel_pcie_debug.h
@@ -0,0 +1,171 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Intel Bluetooth YoYo Debug Framework
+ *
+ * Copyright (C) 2026 Intel Corporation
+ *
+ */
+
+#ifndef __BTINTEL_PCIE_DEBUG_H__
+#define __BTINTEL_PCIE_DEBUG_H__
+
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+
+/* External YoYo binary file */
+#define BTINTEL_PCIE_YOYO_FW_NAME "intel/ibt_debug_yoyo.bin"
+
+/* TLV type codes */
+#define BTINTEL_PCIE_TLV_TYPE_DBG_INFO 0x1000005
+#define BTINTEL_PCIE_TLV_TYPE_DBG_BUF_ALLOC 0x1000006
+#define BTINTEL_PCIE_TLV_TYPE_DBG_HCMD 0x1000007
+#define BTINTEL_PCIE_TLV_TYPE_DBG_REGION 0x1000008
+#define BTINTEL_PCIE_TLV_TYPE_DBG_TRIGGER 0x1000009
+#define BTINTEL_PCIE_TLV_TYPE_DBG_CONFIG_SET 0x100000A
+#define BTINTEL_PCIE_TLV_TYPE_DBG_PRESET_OVERRIDE 0x100000B
+
+/* Supported TLV type versions */
+#define BTINTEL_PCIE_DBG_INFO_TLV_VERSION 2
+#define BTINTEL_PCIE_BUF_ALLOC_TLV_VERSION 1
+/* Debug Info TLV */
+#define BTINTEL_PCIE_CONFIG_NAME_LEN 64
+#define BTINTEL_PCIE_DOMAIN_BT 0
+#define BTINTEL_PCIE_CORE_TYPE_BT 1
+/* Buffer allocation TLV */
+#define BTINTEL_PCIE_MAX_BUF_ALLOC 3
+#define BTINTEL_PCIE_MAX_BUF_FRAGS 16
+#define BTINTEL_PCIE_MIN_BUF_SIZE (32 * 1024)
+#define BTINTEL_PCIE_MAX_BUF_SIZE (4 * 1024 * 1024)
+
+enum btintel_pcie_image_tlv_type {
+ BTINTEL_PCIE_IMAGE_TLV_TYPE_EXTERNAL = 0x1,
+ BTINTEL_PCIE_IMAGE_TLV_TYPE_INTERNAL = 0x2,
+ BTINTEL_PCIE_IMAGE_TLV_TYPE_UNKNOWN = 0xff,
+};
+
+/* Allocation IDs */
+enum btintel_dbg_alloc_id {
+ BTINTEL_PCIE_ALLOC_ID_INVALID = 0,
+ BTINTEL_PCIE_ALLOC_ID_DBGC1 = 1,
+ BTINTEL_PCIE_ALLOC_ID_DBGC2 = 2,
+ BTINTEL_PCIE_ALLOC_ID_DBGC3 = 3,
+ BTINTEL_PCIE_ALLOC_ID_MAX,
+};
+
+/* Buffer locations */
+enum btintel_dbg_buf_location {
+ BTINTEL_PCIE_BUF_LOC_INVALID = 0,
+ BTINTEL_PCIE_BUF_LOC_SRAM = 1,
+ BTINTEL_PCIE_BUF_LOC_DRAM = 2,
+ BTINTEL_PCIE_BUF_LOC_NPK = 3,
+ BTINTEL_PCIE_BUF_LOC_MAX,
+};
+
+/* TLV header */
+struct btintel_pcie_tlv_hdr {
+ __le32 type;
+ __le32 length;
+} __packed;
+
+/* Debug header common to all debug TLVs */
+struct btintel_pcie_dbg_hdr {
+ __le32 tlv_data_version;
+ __le32 domain;
+} __packed;
+
+/* Address/value pair */
+struct btintel_pcie_addr_value {
+ __le32 address;
+ __le32 value;
+} __packed;
+
+/*
+ * struct btintel_pcie_tlv_dbg_info - YoYo DEBUG_INFO TLV
+ * @hdr: TLV type and payload length
+ * @dbg_hdr: Debug TLV version and domain
+ * @image_type: Firmware image type
+ * @core_type: Firmware core type
+ * @config_name: Fixed-size name of the firmware configuration
+ *
+ * Describes the firmware image targeted by the YoYo configuration. Fields
+ * are stored in little-endian format in the packed firmware TLV.
+ */
+struct btintel_pcie_tlv_dbg_info {
+ struct btintel_pcie_tlv_hdr hdr;
+ struct btintel_pcie_dbg_hdr dbg_hdr;
+ __le32 image_type;
+ __le32 core_type;
+ u8 config_name[BTINTEL_PCIE_CONFIG_NAME_LEN];
+} __packed;
+
+/*
+ * struct btintel_pcie_tlv_buf_alloc - YoYo buffer allocation TLV
+ * @hdr: Common TLV header
+ * @dbg_hdr: Debug TLV version and domain
+ * @alloc_id: DBGC allocation identifier (DBGC1..DBGC3)
+ * @buf_location: Requested buffer location (SRAM / DRAM / NPK)
+ * @req_buf_size: Total requested allocation size in bytes
+ * @max_num_frags: Maximum number of buffer fragments (1..16)
+ * @min_buf_size: Minimum buffer size in bytes
+ *
+ * Describes the buffer sizing override for one DBGC allocation.
+ */
+struct btintel_pcie_tlv_buf_alloc {
+ struct btintel_pcie_tlv_hdr hdr;
+ struct btintel_pcie_dbg_hdr dbg_hdr;
+ __le32 alloc_id;
+ __le32 buf_location;
+ __le32 req_buf_size;
+ __le32 max_num_frags;
+ __le32 min_buf_size;
+} __packed;
+
+/* Parsed buffer allocation entry in the YoYo context */
+struct btintel_pcie_buf_alloc {
+ u32 alloc_id;
+ u32 buf_location;
+ u32 req_buf_size;
+ u32 max_num_frags;
+ u32 min_buf_size;
+ bool present;
+};
+
+/*
+ * struct btintel_pcie_yoyo_ctx- Runtime state for YoYo debug configuration
+ * @enabled: Whether the loaded YoYo configuration passed validation
+ * @region_list: Parsed debug-region entries
+ * @trigger_list: Parsed debug-trigger entries
+ * @hcmd_list: Parsed HCI command entries
+ * @config_set_list: Parsed configuration-set entries
+ * @buf_alloc: Parsed buffer allocation entries
+ * @num_buf_allocs: Number of parsed buffer allocation entries
+ * @hdev: Associated HCI device; NULL until successful HCI registration
+ *
+ * Stores the validation state and parsed TLV data for the optional YoYo
+ * firmware configuration.
+ */
+struct btintel_pcie_yoyo_ctx {
+ bool enabled;
+ bool dbg_info_present;
+ struct list_head region_list;
+ struct list_head trigger_list;
+ struct list_head hcmd_list;
+ struct list_head config_set_list;
+ struct btintel_pcie_buf_alloc buf_alloc[BTINTEL_PCIE_MAX_BUF_ALLOC];
+ int num_buf_allocs;
+ struct hci_dev *hdev;
+};
+
+int btintel_pcie_yoyo_init(struct btintel_pcie_yoyo_ctx *ctx);
+void btintel_pcie_yoyo_cleanup(struct btintel_pcie_yoyo_ctx *ctx);
+
+/* Load and parse the external .bin file */
+int btintel_pcie_yoyo_load_and_parse(struct btintel_pcie_yoyo_ctx *ctx,
+ struct device *dev);
+
+const struct btintel_pcie_buf_alloc *
+btintel_pcie_yoyo_get_buf_alloc(struct btintel_pcie_yoyo_ctx *ctx, u32 alloc_id);
+
+#endif /* __BTINTEL_PCIE_DEBUG_H__ */
|
| 3/2 | 2026/10/14 11:44 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 18140 output: 31 thoughts: 148 Thoughts: Okay, here's my assessment of whether this patch series is fuzz-worthy, presented as my internal thought process: **Fuzzing Evaluation: Bluetooth Intel PCIe Driver Patch Series** Right, let's get down to it. The user wants an opinion on whether this patch series justifies a fuzzing campaign with syzkaller. My initial instinct is to dig in and understand the scope of the change. First, let's review what's being touched. We have changes to `drivers/bluetooth/Makefile`, `btintel_pcie.c`, `btintel_pcie.h`, `btintel_pcie_debug.c`, and `btintel_pcie_debug.h`. Ok, so it's all within the `drivers/bluetooth` directory, specifically dealing with `btintel_pcie`. That suggests it's related to Intel PCIe Bluetooth devices, which is a good starting point. I need to confirm that suspicion though. Now, I need to understand the function of `btintel_pcie`. Is it *really* a driver for Intel PCIe Bluetooth? I'll need to confirm what is going on with the patch, and the nature of the patch series. I need to quickly check the code and Kconfig to confirm my suspicion. The patch series is focused on the Intel PCIe Bluetooth driver so I'll review the code, and how the driver is configured. I'll need to determine the scope of this patch and see if it interacts with anything that might be prone to fuzzing vulnerabilities. |
| 4/2 | 2026/10/14 11:44 | tool | grepper |
0mArgs:{
"Expression": "BT_INTEL_PCIE",
"PathPrefixes": [
"drivers/bluetooth"
]
}Results: {
"Output": "drivers/bluetooth/Kconfig=464=config BT_NXPUART\n--\ndrivers/bluetooth/Kconfig-477-\ndrivers/bluetooth/Kconfig:478:config BT_INTEL_PCIE\ndrivers/bluetooth/Kconfig-479-\ttristate \"Intel HCI PCIe driver\"\n--\ndrivers/bluetooth/Makefile=16=obj-$(CONFIG_BT_INTEL)\t\t+= btintel.o\ndrivers/bluetooth/Makefile:17:obj-$(CONFIG_BT_INTEL_PCIE)\t+= btintel_pcie.o btintel.o btintel_pcie_debug.o\ndrivers/bluetooth/Makefile-18-obj-$(CONFIG_BT_ATH3K)\t\t+= ath3k.o\n--\ndrivers/bluetooth/btintel.h=264=struct btintel_data {\n--\ndrivers/bluetooth/btintel.h-296-\ndrivers/bluetooth/btintel.h:297:#if IS_ENABLED(CONFIG_BT_INTEL) || IS_ENABLED(CONFIG_BT_INTEL_PCIE)\ndrivers/bluetooth/btintel.h-298-\n"
} |
| 5/2 | 2026/10/14 11:44 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 18922 output: 34 thoughts: 19 Thoughts: Here's my take on the thought process: **Diving into the Bluetooth Configuration** Okay, let's zero in on the Bluetooth configuration. My intuition, based on previous debugging and experience, is telling me the issue might be buried within the `Kconfig` files that define how Bluetooth features are enabled and configured. Specifically, I'm going to navigate to `drivers/bluetooth/Kconfig`. That file is the central hub for a lot of Bluetooth settings. I'm going to start my scan around line 478, since I have a mental note of where some common core options tend to be defined. Hopefully, this pinpointed approach can accelerate my investigation. |
| 6/2 | 2026/10/14 11:44 | tool | read-file |
0mArgs:{
"File": "drivers/bluetooth/Kconfig",
"FirstLine": 475,
"LineCount": 25
}Results: {
"Contents": " 475:\t\t Say Y here to compile support for NXP Bluetooth UART device into\n 476:\t\t the kernel, or say M here to compile as a module (btnxpuart).\n 477:\t\n 478:\tconfig BT_INTEL_PCIE\n 479:\t\ttristate \"Intel HCI PCIe driver\"\n 480:\t\tdepends on PCI \u0026\u0026 ACPI\n 481:\t\tselect BT_INTEL\n 482:\t\tselect FW_LOADER\n 483:\t\thelp\n 484:\t\t Intel Bluetooth transport driver for PCIe.\n 485:\t\t This driver is required if you want to use Intel Bluetooth device\n 486:\t\t with PCIe interface.\n 487:\t\n 488:\t\t Say Y here to compiler support for Intel Bluetooth PCIe device into\n 489:\t\t the kernel or say M to compile it as module (btintel_pcie)\n 490:\tendmenu\n"
} |
| 7/2 | 2026/10/14 11:44 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 19367 output: 40 thoughts: 327 Thoughts: **Analyzing Fuzzing Worthiness of the Intel Bluetooth PCIe Driver** Okay, let's break this down. I need to determine if this Intel Bluetooth PCIe driver, `BT_INTEL_PCIE`, is something worth fuzzing. The guidelines are pretty clear in Sections 2 and 3: I need to consider when to return `WorthFuzzing=false` based on negative criteria, and when to return `WorthFuzzing=true` based on positive criteria. Specifically, Section 2 is important. It says I should *only* return `WorthFuzzing=false` if the modified code falls *strictly* into a few very specific categories. The key point here is "Structurally unreachable hardware" and "Unreachable execution paths." So, I need to know if `BT_INTEL_PCIE` falls into either of those. My first thought: is this driver emulated within a standard QEMU environment, or does it *require* specific physical hardware, like a real Intel PCIe Bluetooth card? This is the critical question. I immediately need to determine if QEMU emulates the Intel PCIe Bluetooth device. If it requires physical hardware I can't reach, it's a no-go for fuzzing. If it's emulated, it's definitely a candidate. I'll check the PCI IDs that the `btintel_pcie` driver binds to. That's the quickest path to confirm. That will provide insight into whether this is a virtual device that might be fuzzable. |
| 8/2 | 2026/10/14 11:44 | tool | grepper |
0mArgs:{
"Expression": "MODULE_DEVICE_TABLE\\(pci",
"PathPrefixes": [
"drivers/bluetooth/btintel_pcie.c"
]
}Results: {
"Output": "drivers/bluetooth/btintel_pcie.c=46=static const struct pci_device_id btintel_pcie_table[] = {\n--\ndrivers/bluetooth/btintel_pcie.c-63-};\ndrivers/bluetooth/btintel_pcie.c:64:MODULE_DEVICE_TABLE(pci, btintel_pcie_table);\ndrivers/bluetooth/btintel_pcie.c-65-\n"
} |
| 9/2 | 2026/10/14 11:44 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 20171 output: 38 thoughts: 16 Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person: **Analyzing the Contents of `btintel_pcie_table`** Right, let's dive into this. The initial thought, "Let's check the contents of `btintel_pcie_table`," is pretty straightforward. I'm assuming we're dealing with some system relating to Bluetooth and PCIe interaction, likely on an Intel platform, given the naming convention. That table probably holds critical information – perhaps configuration data, device mappings, interrupt assignments, or even some kind of firmware interface related to the Bluetooth controller's PCIe endpoint. My immediate concerns center around what *kind* of table it is. Is it a static configuration table, a runtime-generated structure, or something more dynamic? Is it in firmware, in the kernel space, or is it user-accessible? The specific context – the surrounding code, the system architecture – is going to be key to interpreting the data. I'll need to consider how the Bluetooth controller interacts with the PCIe bus, the driver model, and any relevant platform-specific quirks or workarounds. I'll be looking for clues on how the system manages power, resource allocation, and any potential handoffs between the Bluetooth controller and other system components. I'm prepared to see interesting entries, especially if it relates to a recent issue. Let's see what we've got. |
| 10/2 | 2026/10/14 11:45 | tool | read-file |
0mArgs:{
"File": "drivers/bluetooth/btintel_pcie.c",
"FirstLine": 40,
"LineCount": 30
}Results: {
"Contents": " 40:\t\n 41:\t#define POLL_INTERVAL_US\t10\n 42:\t\n 43:\t#define BTINTEL_PCIE_DMA_ALIGN_128B\t128 /* 128 byte aligned */\n 44:\t\n 45:\t/* Intel Bluetooth PCIe device id table */\n 46:\tstatic const struct pci_device_id btintel_pcie_table[] = {\n 47:\t\t/* BlazarI, Wildcat Lake */\n 48:\t\t{ BTINTEL_PCI_DEVICE(0x4D76, PCI_ANY_ID) },\n 49:\t\t/* BlazarI, Lunar Lake */\n 50:\t\t{ BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) },\n 51:\t\t/* Scorpious, Panther Lake-H484 */\n 52:\t\t{ BTINTEL_PCI_DEVICE(0xE376, PCI_ANY_ID) },\n 53:\t\t /* Scorpious, Panther Lake-H404 */\n 54:\t\t{ BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) },\n 55:\t\t /* Scorpious2, Nova Lake-PCD-H */\n 56:\t\t{ BTINTEL_PCI_DEVICE(0xD346, PCI_ANY_ID) },\n 57:\t\t /* Scorpious2, Nova Lake-PCD-S */\n 58:\t\t{ BTINTEL_PCI_DEVICE(0x6E74, PCI_ANY_ID) },\n 59:\t\t /* Draco */\n 60:\t\t{ BTINTEL_PCI_DEVICE(0x2731, PCI_ANY_ID) },\n 61:\t\t{ BTINTEL_PCI_DEVICE(0x2732, PCI_ANY_ID) },\n 62:\t\t{ 0 }\n 63:\t};\n 64:\tMODULE_DEVICE_TABLE(pci, btintel_pcie_table);\n 65:\t\n 66:\tstruct btintel_pcie_dev_recovery {\n 67:\t\tstruct list_head list;\n 68:\t\tu8 count;\n 69:\t\ttime64_t last_error;\n"
} |
| 11/2 | 2026/10/14 11:45 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 21093 output: 19 thoughts: 639 Thoughts: **My Assessment of Fuzzing Reachability for Intel Bluetooth PCIe Drivers** Okay, so I'm looking at these PCI IDs – Intel Lunar Lake, Panther Lake, Nova Lake, Blazar... I see these all relate to PCIe Bluetooth devices. The question now is whether there's any form of virtual bus emulation or software emulation available for `btintel_pcie`. I need to know if I can fuzz it. Hmm, QEMU *doesn't* emulate Intel Bluetooth PCIe cards. That's a problem. Can syzkaller even fuzz PCI devices at all in this case? The answer is no, not unless there's virtual bus emulation in place, or we're dealing with virtio, or potentially USB gadget interfaces (like `btusb` via `raw-gadget` or `dummy_hcd`). Right, so syzkaller *can* fuzz PCI drivers... but standard virtualized environments like GCE or QEMU don't provide a way for us to actually *use* those Intel PCIe Bluetooth cards. The cards themselves, the *hardware*, is missing. Okay, time to re-read the triage philosophy and negative criteria very carefully. This is crucial: The goal is to find crashes, regressions, exposed latent bugs, and newly triggered assertions from patch series. The primary gate is *reachability*. I can only fuzz code that *executes* in standard virtualized environments. If the code is structurally unreachable, *it MUST NOT be fuzzed*, no matter if it adds assertions. "No Functional Change" or "Refactoring" claims are irrelevant; I need to assess reachability. According to the negative criteria, I'm to return `WorthFuzzing=false` if the modified code falls into certain categories. Specifically, unreachable hardware. Vendor-specific PCIe switches, SmartNICs, or GPU drivers are explicitly called out. That's a direct match to what I'm looking at. That includes, mlxsw, pds_core, qed, ionic, amdgpu. These are all examples. And, more importantly to me, the driver is in the same class as those – it requires *physical* ASIC/PCIe cards that *aren't* emulated in standard QEMU. It also falls under unreachable execution paths – driver teardown callbacks that run only with physical PCI hot-unplug or manual unbinding. And of course code paths that only occur on different architectures. So, according to the positive criteria, I need to return `WorthFuzzing=true` if the patch touches reachable, executable code accessible through virtual buses such as: virtio, USB gadget, loopback, netlink, binder, sockets, etc. Now, let me double-check. I'm going to look more closely: Is `btintel_pcie` actually *used* anywhere else? I need to check if either `btintel_pcie_debug.c` or `btintel_pcie.c` is called from `btintel` or `btusb` or *anything* else that's more reachable. I need to trace the code and see if there is any way to reach any of it with a virtualized environment. |
| 12/2 | 2026/10/14 11:45 | tool | grepper |
0mArgs:{
"Expression": "btintel_pcie"
}Results: {
"Output": "\nFull output is too long, showing 200 out of 1925 lines.\nUse more precise expression or PathPrefixes if possible.\n\nNumber of matching lines per file (9 files in total):\nMAINTAINERS:1\nNext/merge.log:2\ndrivers/bluetooth/Kconfig:1\ndrivers/bluetooth/Makefile:1\ndrivers/bluetooth/btintel.c:1\ndrivers/bluetooth/btintel_pcie.c:510\ndrivers/bluetooth/btintel_pcie.h:35\ndrivers/bluetooth/btintel_pcie_debug.c:28\ndrivers/bluetooth/btintel_pcie_debug.h:21\n\nMAINTAINERS=4885=T:\tgit git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git\nMAINTAINERS:4886:F:\tDocumentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie\nMAINTAINERS-4887-F:\tDocumentation/devicetree/bindings/net/bluetooth/\n--\nNext/merge.log=11965=Merge made by the 'ort' strategy.\n--\nNext/merge.log-11972- drivers/bluetooth/btintel.h | 19 +\nNext/merge.log:11973: drivers/bluetooth/btintel_pcie.c | 1535 ++++++-\nNext/merge.log:11974: drivers/bluetooth/btintel_pcie.h | 257 +-\nNext/merge.log-11975- drivers/bluetooth/btmrvl_main.c | 4 +-\n--\ndrivers/bluetooth/Kconfig=478=config BT_INTEL_PCIE\n--\ndrivers/bluetooth/Kconfig-488-\t Say Y here to compiler support for Intel Bluetooth PCIe device into\ndrivers/bluetooth/Kconfig:489:\t the kernel or say M to compile it as module (btintel_pcie)\ndrivers/bluetooth/Kconfig-490-endmenu\n--\ndrivers/bluetooth/Makefile=16=obj-$(CONFIG_BT_INTEL)\t\t+= btintel.o\ndrivers/bluetooth/Makefile:17:obj-$(CONFIG_BT_INTEL_PCIE)\t+= btintel_pcie.o btintel.o btintel_pcie_debug.o\ndrivers/bluetooth/Makefile-18-obj-$(CONFIG_BT_ATH3K)\t\t+= ath3k.o\n--\ndrivers/bluetooth/btintel.c=2062=static int btintel_boot(struct hci_dev *hdev, u32 boot_addr)\n--\ndrivers/bluetooth/btintel.c-2094-\t\t * D0 entry by writing 0 to sleep control register (check\ndrivers/bluetooth/btintel.c:2095:\t\t * btintel_pcie_recv_event())\ndrivers/bluetooth/btintel.c-2096-\t\t * Firmware acks with alive interrupt indicating host is full ready to\n--\ndrivers/bluetooth/btintel_pcie.c-29-#include \"btintel.h\"\ndrivers/bluetooth/btintel_pcie.c:30:#include \"btintel_pcie.h\"\ndrivers/bluetooth/btintel_pcie.c-31-\n--\ndrivers/bluetooth/btintel_pcie.c-45-/* Intel Bluetooth PCIe device id table */\ndrivers/bluetooth/btintel_pcie.c:46:static const struct pci_device_id btintel_pcie_table[] = {\ndrivers/bluetooth/btintel_pcie.c-47-\t/* BlazarI, Wildcat Lake */\n--\ndrivers/bluetooth/btintel_pcie.c-63-};\ndrivers/bluetooth/btintel_pcie.c:64:MODULE_DEVICE_TABLE(pci, btintel_pcie_table);\ndrivers/bluetooth/btintel_pcie.c-65-\ndrivers/bluetooth/btintel_pcie.c:66:struct btintel_pcie_dev_recovery {\ndrivers/bluetooth/btintel_pcie.c-67-\tstruct list_head list;\n--\ndrivers/bluetooth/btintel_pcie.c=110=enum btintel_dsm_internal_product_reset_mode {\n--\ndrivers/bluetooth/btintel_pcie.c-120- */\ndrivers/bluetooth/btintel_pcie.c:121:struct btintel_pcie_dbgc_ctxt_buf {\ndrivers/bluetooth/btintel_pcie.c-122-\tu32\tbuf_addr_lsb;\n--\ndrivers/bluetooth/btintel_pcie.c-133- */\ndrivers/bluetooth/btintel_pcie.c:134:struct btintel_pcie_dbgc_ctxt {\ndrivers/bluetooth/btintel_pcie.c-135-\tu32\tmagic_num;\n--\ndrivers/bluetooth/btintel_pcie.c-138-\tu32 num_buf;\ndrivers/bluetooth/btintel_pcie.c:139:\tstruct btintel_pcie_dbgc_ctxt_buf bufs[BTINTEL_PCIE_DBGC_BUFFER_COUNT];\ndrivers/bluetooth/btintel_pcie.c-140-};\ndrivers/bluetooth/btintel_pcie.c-141-\ndrivers/bluetooth/btintel_pcie.c:142:struct btintel_pcie_mdbgc_ctxt {\ndrivers/bluetooth/btintel_pcie.c-143-\tu32 magic_num;\n--\ndrivers/bluetooth/btintel_pcie.c-146-\tu32 buf1_count;\ndrivers/bluetooth/btintel_pcie.c:147:\tstruct btintel_pcie_dbgc_ctxt_buf buf1[BTINTEL_PCIE_DBGC_BUFFER_COUNT];\ndrivers/bluetooth/btintel_pcie.c-148-\tu32 buf2_index;\ndrivers/bluetooth/btintel_pcie.c-149-\tu32 buf2_count;\ndrivers/bluetooth/btintel_pcie.c:150:\tstruct btintel_pcie_dbgc_ctxt_buf buf2[BTINTEL_PCIE_DBGC_BUFFER_COUNT];\ndrivers/bluetooth/btintel_pcie.c-151-\tu32 buf3_index;\ndrivers/bluetooth/btintel_pcie.c-152-\tu32 buf3_count;\ndrivers/bluetooth/btintel_pcie.c:153:\tstruct btintel_pcie_dbgc_ctxt_buf buf3[BTINTEL_PCIE_DBGC_BUFFER_COUNT];\ndrivers/bluetooth/btintel_pcie.c-154-};\ndrivers/bluetooth/btintel_pcie.c-155-\ndrivers/bluetooth/btintel_pcie.c:156:struct btintel_pcie_trigger_evt {\ndrivers/bluetooth/btintel_pcie.c-157-\tu8 type;\n--\ndrivers/bluetooth/btintel_pcie.c-162-\ndrivers/bluetooth/btintel_pcie.c:163:struct btintel_pcie_fwtrigger_evt {\ndrivers/bluetooth/btintel_pcie.c-164-\t__le32 reserved;\n--\ndrivers/bluetooth/btintel_pcie.c-171-\ndrivers/bluetooth/btintel_pcie.c:172:static LIST_HEAD(btintel_pcie_recovery_list);\ndrivers/bluetooth/btintel_pcie.c:173:static DEFINE_SPINLOCK(btintel_pcie_recovery_lock);\ndrivers/bluetooth/btintel_pcie.c-174-\ndrivers/bluetooth/btintel_pcie.c:175:static inline char *btintel_pcie_alivectxt_state2str(u32 alive_intr_ctxt)\ndrivers/bluetooth/btintel_pcie.c-176-{\n--\ndrivers/bluetooth/btintel_pcie.c-200- */\ndrivers/bluetooth/btintel_pcie.c:201:static inline bool btintel_pcie_dbg_to_wifi(struct btintel_pcie_data *data)\ndrivers/bluetooth/btintel_pcie.c-202-{\n--\ndrivers/bluetooth/btintel_pcie.c-221- */\ndrivers/bluetooth/btintel_pcie.c:222:static void btintel_pcie_load_dbg_path_from_ini(struct btintel_pcie_data *data)\ndrivers/bluetooth/btintel_pcie.c-223-{\n--\ndrivers/bluetooth/btintel_pcie.c-311- */\ndrivers/bluetooth/btintel_pcie.c:312:static int btintel_pcie_alloc_dbgc_buf(struct btintel_pcie_data *data,\ndrivers/bluetooth/btintel_pcie.c-313-\t\t\t\t struct data_buf **buf,\n--\ndrivers/bluetooth/btintel_pcie.c-315-\t\t\t\t void **v_addr,\ndrivers/bluetooth/btintel_pcie.c:316:\t\t\t\t struct btintel_pcie_dbgc_ctxt_buf *frag,\ndrivers/bluetooth/btintel_pcie.c-317-\t\t\t\t u32 buf_index,\n--\ndrivers/bluetooth/btintel_pcie.c-355-/* Returns false if YoYo is enabled and @alloc_id is not configured */\ndrivers/bluetooth/btintel_pcie.c:356:static bool btintel_pcie_get_mdbgc_cfg(struct btintel_pcie_data *data,\ndrivers/bluetooth/btintel_pcie.c-357-\t\t\t\t u32 alloc_id, u32 *count, u32 *size)\ndrivers/bluetooth/btintel_pcie.c-358-{\ndrivers/bluetooth/btintel_pcie.c:359:\tconst struct btintel_pcie_buf_alloc *ba;\ndrivers/bluetooth/btintel_pcie.c-360-\ndrivers/bluetooth/btintel_pcie.c:361:\tba = btintel_pcie_yoyo_get_buf_alloc(\u0026data-\u003eyoyo, alloc_id);\ndrivers/bluetooth/btintel_pcie.c-362-\tif (ba) {\n--\ndrivers/bluetooth/btintel_pcie.c-379- */\ndrivers/bluetooth/btintel_pcie.c:380:static int btintel_pcie_setup_mdbgc(struct btintel_pcie_data *data)\ndrivers/bluetooth/btintel_pcie.c-381-{\ndrivers/bluetooth/btintel_pcie.c:382:\tstruct btintel_pcie_mdbgc_ctxt db_frag;\ndrivers/bluetooth/btintel_pcie.c-383-\tu32 frag_size = sizeof(db_frag);\n--\ndrivers/bluetooth/btintel_pcie.c-405-\t/* Allocate DBGC buffer 1 */\ndrivers/bluetooth/btintel_pcie.c:406:\tif (btintel_pcie_get_mdbgc_cfg(data, BTINTEL_PCIE_ALLOC_ID_DBGC1,\ndrivers/bluetooth/btintel_pcie.c-407-\t\t\t\t \u0026buf_count, \u0026buf_size)) {\n--\ndrivers/bluetooth/btintel_pcie.c-412-\ndrivers/bluetooth/btintel_pcie.c:413:\t\terr = btintel_pcie_alloc_dbgc_buf(data,\ndrivers/bluetooth/btintel_pcie.c-414-\t\t\t\t\t\t \u0026data-\u003emdbgc.buf1,\n--\ndrivers/bluetooth/btintel_pcie.c-425-\t/* Allocate DBGC buffer 2 */\ndrivers/bluetooth/btintel_pcie.c:426:\tif (btintel_pcie_get_mdbgc_cfg(data, BTINTEL_PCIE_ALLOC_ID_DBGC2,\ndrivers/bluetooth/btintel_pcie.c-427-\t\t\t\t \u0026buf_count, \u0026buf_size)) {\n--\ndrivers/bluetooth/btintel_pcie.c-432-\ndrivers/bluetooth/btintel_pcie.c:433:\t\terr = btintel_pcie_alloc_dbgc_buf(data,\ndrivers/bluetooth/btintel_pcie.c-434-\t\t\t\t\t\t \u0026data-\u003emdbgc.buf2,\n--\ndrivers/bluetooth/btintel_pcie.c-445-\t/* Allocate DBGC buffer 3 */\ndrivers/bluetooth/btintel_pcie.c:446:\tif (btintel_pcie_get_mdbgc_cfg(data, BTINTEL_PCIE_ALLOC_ID_DBGC3,\ndrivers/bluetooth/btintel_pcie.c-447-\t\t\t\t \u0026buf_count, \u0026buf_size)) {\n--\ndrivers/bluetooth/btintel_pcie.c-452-\ndrivers/bluetooth/btintel_pcie.c:453:\t\terr = btintel_pcie_alloc_dbgc_buf(data,\ndrivers/bluetooth/btintel_pcie.c-454-\t\t\t\t\t\t \u0026data-\u003emdbgc.buf3,\n--\ndrivers/bluetooth/btintel_pcie.c-477- */\ndrivers/bluetooth/btintel_pcie.c:478:static int btintel_pcie_setup_dbgc(struct btintel_pcie_data *data)\ndrivers/bluetooth/btintel_pcie.c-479-{\ndrivers/bluetooth/btintel_pcie.c:480:\tstruct btintel_pcie_dbgc_ctxt db_frag;\ndrivers/bluetooth/btintel_pcie.c-481-\tu32 frag_size = sizeof(db_frag);\ndrivers/bluetooth/btintel_pcie.c:482:\tconst struct btintel_pcie_buf_alloc *ba;\ndrivers/bluetooth/btintel_pcie.c-483-\tu32 buf_count, buf_size;\n--\ndrivers/bluetooth/btintel_pcie.c-485-\ndrivers/bluetooth/btintel_pcie.c:486:\tba = btintel_pcie_yoyo_get_buf_alloc(\u0026data-\u003eyoyo,\ndrivers/bluetooth/btintel_pcie.c-487-\t\t\t\t\t BTINTEL_PCIE_ALLOC_ID_DBGC1);\n--\ndrivers/bluetooth/btintel_pcie.c-507-\ndrivers/bluetooth/btintel_pcie.c:508:\tdata-\u003edbgc.frag_size = sizeof(struct btintel_pcie_dbgc_ctxt);\ndrivers/bluetooth/btintel_pcie.c-509-\n--\ndrivers/bluetooth/btintel_pcie.c-518-\t/* Allocate DBGC buffers */\ndrivers/bluetooth/btintel_pcie.c:519:\terr = btintel_pcie_alloc_dbgc_buf(data,\ndrivers/bluetooth/btintel_pcie.c-520-\t\t\t\t\t \u0026data-\u003edbgc.bufs,\n--\ndrivers/bluetooth/btintel_pcie.c=544=static inline void ipc_print_urbd1(struct hci_dev *hdev, struct urbd1 *urbd1,\n--\ndrivers/bluetooth/btintel_pcie.c-550-\ndrivers/bluetooth/btintel_pcie.c:551:static struct btintel_pcie_data *btintel_pcie_get_data(struct msix_entry *entry)\ndrivers/bluetooth/btintel_pcie.c-552-{\n--\ndrivers/bluetooth/btintel_pcie.c-555-\ndrivers/bluetooth/btintel_pcie.c:556:\treturn container_of(entries, struct btintel_pcie_data, msix_entries[0]);\ndrivers/bluetooth/btintel_pcie.c-557-}\n--\ndrivers/bluetooth/btintel_pcie.c-561- */\ndrivers/bluetooth/btintel_pcie.c:562:static void btintel_pcie_set_tx_db(struct btintel_pcie_data *data, u16 index)\ndrivers/bluetooth/btintel_pcie.c-563-{\n--\ndrivers/bluetooth/btintel_pcie.c-568-\ndrivers/bluetooth/btintel_pcie.c:569:\tbtintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_HBUS_TARG_WRPTR, val);\ndrivers/bluetooth/btintel_pcie.c-570-}\n--\ndrivers/bluetooth/btintel_pcie.c-574- */\ndrivers/bluetooth/btintel_pcie.c:575:static void btintel_pcie_prepare_tx(struct txq *txq, u16 tfd_index,\ndrivers/bluetooth/btintel_pcie.c-576-\t\t\t\t struct sk_buff *skb)\n--\ndrivers/bluetooth/btintel_pcie.c-592-\ndrivers/bluetooth/btintel_pcie.c:593:static inline void btintel_pcie_dump_debug_registers(struct hci_dev *hdev)\ndrivers/bluetooth/btintel_pcie.c-594-{\ndrivers/bluetooth/btintel_pcie.c:595:\tstruct btintel_pcie_data *data = hci_get_drvdata(hdev);\ndrivers/bluetooth/btintel_pcie.c-596-\tu16 cr_hia, cr_tia;\n--\ndrivers/bluetooth/btintel_pcie.c-608-\ndrivers/bluetooth/btintel_pcie.c:609:\treg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_BOOT_STAGE_REG);\ndrivers/bluetooth/btintel_pcie.c-610-\tsnprintf(buf, sizeof(buf), \"boot stage: 0x%8.8x\", reg);\n--\ndrivers/bluetooth/btintel_pcie.c-617-\ndrivers/bluetooth/btintel_pcie.c:618:\treg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_STATUS_REG);\ndrivers/bluetooth/btintel_pcie.c-619-\tsnprintf(buf, sizeof(buf), \"ipc status: 0x%8.8x\", reg);\n--\ndrivers/bluetooth/btintel_pcie.c-622-\ndrivers/bluetooth/btintel_pcie.c:623:\treg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_CONTROL_REG);\ndrivers/bluetooth/btintel_pcie.c-624-\tsnprintf(buf, sizeof(buf), \"ipc control: 0x%8.8x\", reg);\n--\ndrivers/bluetooth/btintel_pcie.c-627-\ndrivers/bluetooth/btintel_pcie.c:628:\treg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG);\ndrivers/bluetooth/btintel_pcie.c-629-\tsnprintf(buf, sizeof(buf), \"ipc sleep control: 0x%8.8x\", reg);\n\n"
} |
| 13/2 | 2026/10/14 11:45 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 27214 output: 22 thoughts: 223 Thoughts: **Investigating the btintel Driver's PCI Express Interaction** Okay, first things first, I need to pinpoint how `btintel.c` interacts with the PCI Express side of things. Let's see, around line 2095 in `btintel.c`, the comment confirms a connection with `btintel_pcie` through `btintel_pcie_recv_event()`. I'm starting to wonder if `btintel_pcie_debug.c` is exclusively called from `btintel_pcie.c` – a question worth investigating. Let's trace calls to the `btintel_pcie_yoyo_*` functions. In `btintel_pcie.c`, I'm seeing: `btintel_pcie_yoyo_init`, `btintel_pcie_yoyo_load_and_parse`, `btintel_pcie_yoyo_cleanup`, and `btintel_pcie_yoyo_get_buf_alloc`. Now, the crucial check: are these `btintel_pcie_yoyo_*` functions called *anywhere* outside of `btintel_pcie.c`? A quick grep for `btintel_pcie_yoyo` should give me a definitive answer. |
| 14/2 | 2026/10/14 11:45 | tool | grepper |
0mArgs:{
"Expression": "btintel_pcie_yoyo"
}Results: {
"Output": "drivers/bluetooth/btintel_pcie.c=356=static bool btintel_pcie_get_mdbgc_cfg(struct btintel_pcie_data *data,\n--\ndrivers/bluetooth/btintel_pcie.c-360-\ndrivers/bluetooth/btintel_pcie.c:361:\tba = btintel_pcie_yoyo_get_buf_alloc(\u0026data-\u003eyoyo, alloc_id);\ndrivers/bluetooth/btintel_pcie.c-362-\tif (ba) {\n--\ndrivers/bluetooth/btintel_pcie.c=478=static int btintel_pcie_setup_dbgc(struct btintel_pcie_data *data)\n--\ndrivers/bluetooth/btintel_pcie.c-485-\ndrivers/bluetooth/btintel_pcie.c:486:\tba = btintel_pcie_yoyo_get_buf_alloc(\u0026data-\u003eyoyo,\ndrivers/bluetooth/btintel_pcie.c-487-\t\t\t\t\t BTINTEL_PCIE_ALLOC_ID_DBGC1);\n--\ndrivers/bluetooth/btintel_pcie.c=4228=static int btintel_pcie_probe(struct pci_dev *pdev,\n--\ndrivers/bluetooth/btintel_pcie.c-4275-\tdata-\u003eenable_ini = false;\ndrivers/bluetooth/btintel_pcie.c:4276:\tbtintel_pcie_yoyo_init(\u0026data-\u003eyoyo);\ndrivers/bluetooth/btintel_pcie.c-4277-\t/* FLR can be invoked by echoing to debugfs path, so explicitly\n--\ndrivers/bluetooth/btintel_pcie.c-4286-\tif (data-\u003eenable_ini) {\ndrivers/bluetooth/btintel_pcie.c:4287:\t\terr = btintel_pcie_yoyo_load_and_parse(\u0026data-\u003eyoyo, \u0026pdev-\u003edev);\ndrivers/bluetooth/btintel_pcie.c-4288-\t\tif (err) {\ndrivers/bluetooth/btintel_pcie.c-4289-\t\t\tBT_WARN(\"YoYo is not configured (%d)\", err);\ndrivers/bluetooth/btintel_pcie.c:4290:\t\t\tbtintel_pcie_yoyo_cleanup(\u0026data-\u003eyoyo);\ndrivers/bluetooth/btintel_pcie.c-4291-\t\t}\n--\ndrivers/bluetooth/btintel_pcie.c-4326-exit_error:\ndrivers/bluetooth/btintel_pcie.c:4327:\tbtintel_pcie_yoyo_cleanup(\u0026data-\u003eyoyo);\ndrivers/bluetooth/btintel_pcie.c-4328-\n--\ndrivers/bluetooth/btintel_pcie.c=4341=static void btintel_pcie_remove(struct pci_dev *pdev)\n--\ndrivers/bluetooth/btintel_pcie.c-4368-\ndrivers/bluetooth/btintel_pcie.c:4369:\tbtintel_pcie_yoyo_cleanup(\u0026data-\u003eyoyo);\ndrivers/bluetooth/btintel_pcie.c-4370-\n--\ndrivers/bluetooth/btintel_pcie.h=725=struct btintel_pcie_data {\n--\ndrivers/bluetooth/btintel_pcie.h-748-\tbool\tenable_ini;\ndrivers/bluetooth/btintel_pcie.h:749:\tstruct btintel_pcie_yoyo_ctx yoyo;\ndrivers/bluetooth/btintel_pcie.h-750-\n--\ndrivers/bluetooth/btintel_pcie_debug.c-20-/* TLV-specific parser DEBUG_INFO TLV type */\ndrivers/bluetooth/btintel_pcie_debug.c:21:static int btintel_pcie_yoyo_parse_dbg_info(struct btintel_pcie_yoyo_ctx *ctx,\ndrivers/bluetooth/btintel_pcie_debug.c-22-\t\t\t\t\t const struct btintel_pcie_tlv_dbg_info *info,\n--\ndrivers/bluetooth/btintel_pcie_debug.c-66-\ndrivers/bluetooth/btintel_pcie_debug.c:67:static int btintel_pcie_yoyo_parse_buf_alloc(struct btintel_pcie_yoyo_ctx *ctx,\ndrivers/bluetooth/btintel_pcie_debug.c-68-\t\t\t\t\t const struct btintel_pcie_tlv_buf_alloc *tlv,\n--\ndrivers/bluetooth/btintel_pcie_debug.c-140- */\ndrivers/bluetooth/btintel_pcie_debug.c:141:static int btintel_pcie_yoyo_parse_tlv_buffer(struct btintel_pcie_yoyo_ctx *ctx,\ndrivers/bluetooth/btintel_pcie_debug.c-142-\t\t\t\t\t const u8 *buf, size_t buf_len)\n--\ndrivers/bluetooth/btintel_pcie_debug.c-166-\t\tcase BTINTEL_PCIE_TLV_TYPE_DBG_INFO:\ndrivers/bluetooth/btintel_pcie_debug.c:167:\t\t\tret = btintel_pcie_yoyo_parse_dbg_info(ctx,\ndrivers/bluetooth/btintel_pcie_debug.c-168-\t\t\t\t\t\t\t (const void *)tlv, len);\n--\ndrivers/bluetooth/btintel_pcie_debug.c-173-\t\tcase BTINTEL_PCIE_TLV_TYPE_DBG_BUF_ALLOC:\ndrivers/bluetooth/btintel_pcie_debug.c:174:\t\t\tret = btintel_pcie_yoyo_parse_buf_alloc(ctx,\ndrivers/bluetooth/btintel_pcie_debug.c-175-\t\t\t\t\t\t\t\t(const void *)tlv, len);\n--\ndrivers/bluetooth/btintel_pcie_debug.c-217- */\ndrivers/bluetooth/btintel_pcie_debug.c:218:int btintel_pcie_yoyo_init(struct btintel_pcie_yoyo_ctx *ctx)\ndrivers/bluetooth/btintel_pcie_debug.c-219-{\n--\ndrivers/bluetooth/btintel_pcie_debug.c-233-}\ndrivers/bluetooth/btintel_pcie_debug.c:234:EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_init);\ndrivers/bluetooth/btintel_pcie_debug.c-235-\n--\ndrivers/bluetooth/btintel_pcie_debug.c-239- */\ndrivers/bluetooth/btintel_pcie_debug.c:240:void btintel_pcie_yoyo_cleanup(struct btintel_pcie_yoyo_ctx *ctx)\ndrivers/bluetooth/btintel_pcie_debug.c-241-{\n--\ndrivers/bluetooth/btintel_pcie_debug.c-249-}\ndrivers/bluetooth/btintel_pcie_debug.c:250:EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_cleanup);\ndrivers/bluetooth/btintel_pcie_debug.c-251-\n--\ndrivers/bluetooth/btintel_pcie_debug.c-259- */\ndrivers/bluetooth/btintel_pcie_debug.c:260:int btintel_pcie_yoyo_load_and_parse(struct btintel_pcie_yoyo_ctx *ctx,\ndrivers/bluetooth/btintel_pcie_debug.c-261-\t\t\t\t struct device *dev)\n--\ndrivers/bluetooth/btintel_pcie_debug.c-284-\ndrivers/bluetooth/btintel_pcie_debug.c:285:\tret = btintel_pcie_yoyo_parse_tlv_buffer(ctx, fw-\u003edata, fw-\u003esize);\ndrivers/bluetooth/btintel_pcie_debug.c-286-\trelease_firmware(fw);\n--\ndrivers/bluetooth/btintel_pcie_debug.c-302-}\ndrivers/bluetooth/btintel_pcie_debug.c:303:EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_load_and_parse);\ndrivers/bluetooth/btintel_pcie_debug.c-304-\ndrivers/bluetooth/btintel_pcie_debug.c-305-/**\ndrivers/bluetooth/btintel_pcie_debug.c:306: * btintel_pcie_yoyo_get_buf_alloc - Query buffer allocation config for a DBGC\ndrivers/bluetooth/btintel_pcie_debug.c-307- * @ctx: YoYo context\n--\ndrivers/bluetooth/btintel_pcie_debug.c=312=const struct btintel_pcie_buf_alloc *\ndrivers/bluetooth/btintel_pcie_debug.c:313:btintel_pcie_yoyo_get_buf_alloc(struct btintel_pcie_yoyo_ctx *ctx, u32 alloc_id)\ndrivers/bluetooth/btintel_pcie_debug.c-314-{\n--\ndrivers/bluetooth/btintel_pcie_debug.c-327-}\ndrivers/bluetooth/btintel_pcie_debug.c:328:EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_get_buf_alloc);\ndrivers/bluetooth/btintel_pcie_debug.c-329-\n--\ndrivers/bluetooth/btintel_pcie_debug.h=126=struct btintel_pcie_buf_alloc {\n--\ndrivers/bluetooth/btintel_pcie_debug.h-135-/*\ndrivers/bluetooth/btintel_pcie_debug.h:136: * struct btintel_pcie_yoyo_ctx- Runtime state for YoYo debug configuration\ndrivers/bluetooth/btintel_pcie_debug.h-137- * @enabled: Whether the loaded YoYo configuration passed validation\n--\ndrivers/bluetooth/btintel_pcie_debug.h-148- */\ndrivers/bluetooth/btintel_pcie_debug.h:149:struct btintel_pcie_yoyo_ctx {\ndrivers/bluetooth/btintel_pcie_debug.h-150-\tbool\t\t\t enabled;\n--\ndrivers/bluetooth/btintel_pcie_debug.h-160-\ndrivers/bluetooth/btintel_pcie_debug.h:161:int btintel_pcie_yoyo_init(struct btintel_pcie_yoyo_ctx *ctx);\ndrivers/bluetooth/btintel_pcie_debug.h:162:void btintel_pcie_yoyo_cleanup(struct btintel_pcie_yoyo_ctx *ctx);\ndrivers/bluetooth/btintel_pcie_debug.h-163-\ndrivers/bluetooth/btintel_pcie_debug.h-164-/* Load and parse the external .bin file */\ndrivers/bluetooth/btintel_pcie_debug.h:165:int btintel_pcie_yoyo_load_and_parse(struct btintel_pcie_yoyo_ctx *ctx,\ndrivers/bluetooth/btintel_pcie_debug.h-166-\t\t\t\t struct device *dev);\n--\ndrivers/bluetooth/btintel_pcie_debug.h=168=const struct btintel_pcie_buf_alloc *\ndrivers/bluetooth/btintel_pcie_debug.h:169:btintel_pcie_yoyo_get_buf_alloc(struct btintel_pcie_yoyo_ctx *ctx, u32 alloc_id);\ndrivers/bluetooth/btintel_pcie_debug.h-170-\n"
} |
| 15/2 | 2026/10/14 11:45 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 30598 output: 33 thoughts: 129 Thoughts: **Analyzing the `btintel_pcie` Driver** Okay, let's break this down. From what I see, `btintel_pcie` is *specifically* for Intel Bluetooth chips that are hooked up via PCIe – devices like Wildcat Lake, Lunar Lake, Panther Lake, Nova Lake, and Draco. This driver has a very narrow scope. My immediate question is: can I even *interact* with this hardware in a standard virtual environment like QEMU or even Google Compute Engine? The answer, if I'm understanding this correctly, is no. Standard QEMU doesn't offer emulation of these particular Intel PCIe Bluetooth devices. That's a key limitation. My next line of thought is whether there's some *other* virtual bus or software interface that could allow access. Could it be a virtio, perhaps? Or maybe USB gadget, loopback, netlink, or even vhci? Hold on... does vhci... utilize `btintel_pcie`? That's the critical question now. I need to investigate that connection. The best place to start is likely in `hci_vhci.c`. I need to review that source code to see if there's any interaction or dependency. |
| 16/2 | 2026/10/14 11:45 | tool | grepper |
0mError:no matches Args: {
"Expression": "btintel",
"PathPrefixes": [
"drivers/bluetooth/hci_vhci.c"
]
}Results: {
"error": "no matches"
} |
| 17/2 | 2026/10/14 11:45 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 31034 output: 45 thoughts: 85 Thoughts: Here's my summary, as I see it: **Digging into the Bluetooth HCI Driver Landscape** Okay, so I'm trying to wrap my head around this HCI driver situation. I know `hci_vhci.c` is a virtual HCI driver, that much is clear. And it's independent of the `btintel_pcie` driver, which is key. But then the question hits me: what about USB gadgets? That's going to be the `CONFIG_BT_HCIBTUSB` route, which is fundamentally different from a PCIe connection. I need to keep that distinction in mind. Now, what about that `btintel_pcie` driver? Right, it's a `pci_driver`. That's the link. So, the next logical step is to see exactly how `btintel_pcie_driver` gets registered within the system. That'll give me the information I need to understand its relationship to the whole architecture. |
| 18/2 | 2026/10/14 11:45 | tool | grepper |
0mArgs:{
"Expression": "module_pci_driver|pci_register_driver",
"PathPrefixes": [
"drivers/bluetooth/btintel_pcie.c"
]
}Results: {
"Output": "drivers/bluetooth/btintel_pcie.c=4640=static int __init btintel_pcie_init(void)\ndrivers/bluetooth/btintel_pcie.c-4641-{\ndrivers/bluetooth/btintel_pcie.c:4642:\treturn pci_register_driver(\u0026btintel_pcie_driver);\ndrivers/bluetooth/btintel_pcie.c-4643-}\n"
} |
| 19/2 | 2026/10/14 11:45 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 31487 output: 129 thoughts: 689 Thoughts: **My Assessment: Not Worth Fuzzing** Okay, let's break this down systematically. I see that `btintel_pcie` is registered as a PCI driver via `pci_register_driver`. The crucial point is that it *only* probes and attaches to a device if a PCI device ID matches what's defined in `btintel_pcie_table`. I've checked those IDs: 0x4D76, 0xA876, 0xE376, 0xE476, 0xD346, 0x6E74, 0x2731, and 0x2732. My understanding of the available emulated hardware in both QEMU and GCE is pretty solid, and these IDs *are not* emulated. Now, let's go back to the reachability guidelines. "Reachability is the primary gate," it says. The code *must* be executable in a standard virtualized environment. The document is very clear: code that falls under "Structurally unreachable hardware" *must not* be fuzzed. And this applies specifically to things like "vendor-specific PCIe switches, SmartNICs, or GPU drivers requiring physical ASIC/PCIe cards not emulated in standard QEMU". I recognize `btintel_pcie` as precisely that: an Intel-specific PCIe driver designed for physical Intel Bluetooth controllers, the likes of which are found in Lunar Lake, Panther Lake, Nova Lake, Blazar, and similar platforms. It's designed for *actual* PCI hardware. This clearly means it is *not* emulated in QEMU or GCE. A quick review of the patch series shows that all the modified code is in `drivers/bluetooth/Makefile`, `drivers/bluetooth/btintel_pcie.c`, `drivers/bluetooth/btintel_pcie.h`, `drivers/bluetooth/btintel_pcie_debug.c`, and `drivers/bluetooth/btintel_pcie_debug.h`. Therefore, the modified code is structurally unreachable. By definition, I must set `WorthFuzzing` to `false`. Now, let's make sure the `set-results` parameters are correct: * `WorthFuzzing`: `false` – Yes, absolutely. * `Reasoning`: This is because the code requires specific physical PCI hardware that is not emulated in standard QEMU or GCE environments. That's clear. * `FocusSymbols`: I'll set this to an empty list `[]` (or null/empty), since `WorthFuzzing` is `false`. * `EnableConfigs`: Also an empty list `[]` or null. And, a quick sanity check of the tool schema confirms these parameters are valid. Ready to call `set-results`. |
| 20/2 | 2026/10/14 11:46 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch series modifies the btintel_pcie driver and introduces the btintel_pcie_debug module, which implements runtime debug configuration (YoYo) for Intel Bluetooth PCIe controllers. This driver binds specifically to physical Intel PCIe hardware (such as Lunar Lake, Panther Lake, Nova Lake, Blazar) that is not emulated in standard QEMU or GCE virtualized environments. Because the hardware is structurally unreachable during standard kernel fuzzing, the modified code cannot be executed.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch series modifies the btintel_pcie driver and introduces the btintel_pcie_debug module, which implements runtime debug configuration (YoYo) for Intel Bluetooth PCIe controllers. This driver binds specifically to physical Intel PCIe hardware (such as Lunar Lake, Panther Lake, Nova Lake, Blazar) that is not emulated in standard QEMU or GCE virtualized environments. Because the hardware is structurally unreachable during standard kernel fuzzing, the modified code cannot be executed.",
"WorthFuzzing": false
} |
| 21/1 | 2026/10/14 11:46 | action | If |
0mArgs:{
"WorthFuzzing": false
}Results: null |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|