diff mbox series

[v1] Bluetooth: btintel_pcie: Add support for device coredump

Message ID 20250227102625.20642-1-kiran.k@intel.com (mailing list archive)
State Superseded
Headers show
Series [v1] Bluetooth: btintel_pcie: Add support for device coredump | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
tedd_an/SubjectPrefix success Gitlint PASS
tedd_an/BuildKernel success BuildKernel PASS
tedd_an/CheckAllWarning success CheckAllWarning PASS

Commit Message

Kiran K Feb. 27, 2025, 10:26 a.m. UTC
1. Driver registers device coredump callback
2. Dumps firmware traces as part of coredump

Co-developed-by: Vijay Satija <vijay.satija@intel.com>
Signed-off-by: Vijay Satija <vijay.satija@intel.com>
Signed-off-by: Kiran K <kiran.k@intel.com>
---
 drivers/bluetooth/btintel.h      |   1 -
 drivers/bluetooth/btintel_pcie.c | 259 ++++++++++++++++++++++++++++++-
 drivers/bluetooth/btintel_pcie.h |  38 +++++
 3 files changed, 291 insertions(+), 7 deletions(-)

Comments

Dan Carpenter March 3, 2025, 7:10 a.m. UTC | #1
Hi Kiran,

kernel test robot noticed the following build warnings:

https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Kiran-K/Bluetooth-btintel_pcie-Add-support-for-device-coredump/20250227-181131
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
patch link:    https://lore.kernel.org/r/20250227102625.20642-1-kiran.k%40intel.com
patch subject: [PATCH v1] Bluetooth: btintel_pcie: Add support for device coredump
config: sparc-randconfig-r071-20250302 (https://download.01.org/0day-ci/archive/20250302/202503022332.biRVCDMP-lkp@intel.com/config)
compiler: sparc-linux-gcc (GCC) 14.2.0

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202503022332.biRVCDMP-lkp@intel.com/

New smatch warnings:
drivers/bluetooth/btintel_pcie.c:493 btintel_pcie_read_dram_buffers() error: snprintf() is printing too much 100 vs 70

vim +493 drivers/bluetooth/btintel_pcie.c

b8cc1a1cce30cc Kiran K 2025-02-27  454  static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data)
b8cc1a1cce30cc Kiran K 2025-02-27  455  {
b8cc1a1cce30cc Kiran K 2025-02-27  456  	u32 offset, prev_size, wr_ptr_status, dump_size, i;
b8cc1a1cce30cc Kiran K 2025-02-27  457  	struct btintel_pcie_dbgc *dbgc = &data->dbgc;
b8cc1a1cce30cc Kiran K 2025-02-27  458  	u8 buf_idx, dump_time_len, fw_build;
b8cc1a1cce30cc Kiran K 2025-02-27  459  	struct hci_dev *hdev = data->hdev;
b8cc1a1cce30cc Kiran K 2025-02-27  460  	struct intel_tlv *tlv;
b8cc1a1cce30cc Kiran K 2025-02-27  461  	struct timespec64 now;
b8cc1a1cce30cc Kiran K 2025-02-27  462  	struct sk_buff *skb;
b8cc1a1cce30cc Kiran K 2025-02-27  463  	struct tm tm_now;
b8cc1a1cce30cc Kiran K 2025-02-27  464  	char buf[100];
b8cc1a1cce30cc Kiran K 2025-02-27  465  	u16 hdr_len;
b8cc1a1cce30cc Kiran K 2025-02-27  466  	int ret;
b8cc1a1cce30cc Kiran K 2025-02-27  467  
b8cc1a1cce30cc Kiran K 2025-02-27  468  	wr_ptr_status = btintel_pcie_rd_dev_mem(data, BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS);
b8cc1a1cce30cc Kiran K 2025-02-27  469  	offset = wr_ptr_status & BTINTEL_PCIE_DBG_OFFSET_BIT_MASK;
b8cc1a1cce30cc Kiran K 2025-02-27  470  
b8cc1a1cce30cc Kiran K 2025-02-27  471  	buf_idx = BTINTEL_PCIE_DBGC_DBG_BUF_IDX(wr_ptr_status);
b8cc1a1cce30cc Kiran K 2025-02-27  472  	if (buf_idx > dbgc->count) {
b8cc1a1cce30cc Kiran K 2025-02-27  473  		bt_dev_warn(hdev, "Buffer index is invalid");
b8cc1a1cce30cc Kiran K 2025-02-27  474  		return -EINVAL;
b8cc1a1cce30cc Kiran K 2025-02-27  475  	}
b8cc1a1cce30cc Kiran K 2025-02-27  476  
b8cc1a1cce30cc Kiran K 2025-02-27  477  	prev_size = buf_idx * BTINTEL_PCIE_DBGC_BUFFER_SIZE;
b8cc1a1cce30cc Kiran K 2025-02-27  478  	if (prev_size + offset >= prev_size)
b8cc1a1cce30cc Kiran K 2025-02-27  479  		data->dmp_hdr.write_ptr = prev_size + offset;
b8cc1a1cce30cc Kiran K 2025-02-27  480  	else
b8cc1a1cce30cc Kiran K 2025-02-27  481  		return -EINVAL;
b8cc1a1cce30cc Kiran K 2025-02-27  482  
b8cc1a1cce30cc Kiran K 2025-02-27  483  	ktime_get_real_ts64(&now);
b8cc1a1cce30cc Kiran K 2025-02-27  484  	time64_to_tm(now.tv_sec, 0, &tm_now);
b8cc1a1cce30cc Kiran K 2025-02-27  485  	dump_time_len = snprintf(buf, sizeof(buf), "Dump Time: %02d-%02d-%04ld %02d:%02d:%02d",
b8cc1a1cce30cc Kiran K 2025-02-27  486  				 tm_now.tm_mday, tm_now.tm_mon + 1, tm_now.tm_year + 1900,
b8cc1a1cce30cc Kiran K 2025-02-27  487  				 tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec);
b8cc1a1cce30cc Kiran K 2025-02-27  488  
b8cc1a1cce30cc Kiran K 2025-02-27  489  	fw_build = snprintf(buf + dump_time_len, sizeof(buf),
                                                                                         ^^^^^^^^^^^

This size should be "sizeof(buf) - dump_time_len".  It's better to
use scnprintf() here vs snprintf().  The scnprintf() function returns
the number of bytes which were actually printed vs the number which
were printed if there was enough space.

b8cc1a1cce30cc Kiran K 2025-02-27  490  			    "Firmware Timestamp: Year %u WW %02u buildtype %u build %u",
b8cc1a1cce30cc Kiran K 2025-02-27  491  			    2000 + (data->dmp_hdr.fw_timestamp >> 8),
b8cc1a1cce30cc Kiran K 2025-02-27  492  			    data->dmp_hdr.fw_timestamp & 0xff, data->dmp_hdr.fw_build_type,
b8cc1a1cce30cc Kiran K 2025-02-27 @493  			    data->dmp_hdr.fw_build_num);
b8cc1a1cce30cc Kiran K 2025-02-27  494  
b8cc1a1cce30cc Kiran K 2025-02-27  495  	hdr_len = sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_bt) +
b8cc1a1cce30cc Kiran K 2025-02-27  496  		  sizeof(*tlv) + sizeof(data->dmp_hdr.write_ptr) +
b8cc1a1cce30cc Kiran K 2025-02-27  497  		  sizeof(*tlv) + sizeof(data->dmp_hdr.wrap_ctr) +
b8cc1a1cce30cc Kiran K 2025-02-27  498  		  sizeof(*tlv) + sizeof(data->dmp_hdr.trigger_reason) +
b8cc1a1cce30cc Kiran K 2025-02-27  499  		  sizeof(*tlv) + sizeof(data->dmp_hdr.fw_git_sha1) +
b8cc1a1cce30cc Kiran K 2025-02-27  500  		  sizeof(*tlv) + sizeof(data->dmp_hdr.cnvr_top) +
b8cc1a1cce30cc Kiran K 2025-02-27  501  		  sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_top) +
b8cc1a1cce30cc Kiran K 2025-02-27  502  		  sizeof(*tlv) + dump_time_len +
b8cc1a1cce30cc Kiran K 2025-02-27  503  		  sizeof(*tlv) + fw_build;
b8cc1a1cce30cc Kiran K 2025-02-27  504  
b8cc1a1cce30cc Kiran K 2025-02-27  505  	dump_size = hdr_len + sizeof(hdr_len);
b8cc1a1cce30cc Kiran K 2025-02-27  506  
b8cc1a1cce30cc Kiran K 2025-02-27  507  	skb = alloc_skb(dump_size, GFP_KERNEL);
b8cc1a1cce30cc Kiran K 2025-02-27  508  	if (!skb)
b8cc1a1cce30cc Kiran K 2025-02-27  509  		return -ENOMEM;
b8cc1a1cce30cc Kiran K 2025-02-27  510  
b8cc1a1cce30cc Kiran K 2025-02-27  511  	/* Add debug buffers data length to dump size */
b8cc1a1cce30cc Kiran K 2025-02-27  512  	dump_size += BTINTEL_PCIE_DBGC_BUFFER_SIZE * dbgc->count;
b8cc1a1cce30cc Kiran K 2025-02-27  513  
b8cc1a1cce30cc Kiran K 2025-02-27  514  	ret = hci_devcd_init(hdev, dump_size);
b8cc1a1cce30cc Kiran K 2025-02-27  515  	if (ret) {
b8cc1a1cce30cc Kiran K 2025-02-27  516  		bt_dev_err(hdev, "Failed to init devcoredump, err %d", ret);
b8cc1a1cce30cc Kiran K 2025-02-27  517  		kfree_skb(skb);
b8cc1a1cce30cc Kiran K 2025-02-27  518  		return ret;
b8cc1a1cce30cc Kiran K 2025-02-27  519  	}
b8cc1a1cce30cc Kiran K 2025-02-27  520  
b8cc1a1cce30cc Kiran K 2025-02-27  521  	skb_put_data(skb, &hdr_len, sizeof(hdr_len));
b8cc1a1cce30cc Kiran K 2025-02-27  522  
b8cc1a1cce30cc Kiran K 2025-02-27  523  	btintel_pcie_copy_tlv(skb, BTINTEL_CNVI_BT, &data->dmp_hdr.cnvi_bt,
b8cc1a1cce30cc Kiran K 2025-02-27  524  			      sizeof(data->dmp_hdr.cnvi_bt));
b8cc1a1cce30cc Kiran K 2025-02-27  525  
b8cc1a1cce30cc Kiran K 2025-02-27  526  	btintel_pcie_copy_tlv(skb, BTINTEL_WRITE_PTR, &data->dmp_hdr.write_ptr,
b8cc1a1cce30cc Kiran K 2025-02-27  527  			      sizeof(data->dmp_hdr.write_ptr));
b8cc1a1cce30cc Kiran K 2025-02-27  528  
b8cc1a1cce30cc Kiran K 2025-02-27  529  	data->dmp_hdr.wrap_ctr = btintel_pcie_rd_dev_mem(data,
b8cc1a1cce30cc Kiran K 2025-02-27  530  							 BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND);
b8cc1a1cce30cc Kiran K 2025-02-27  531  
b8cc1a1cce30cc Kiran K 2025-02-27  532  	btintel_pcie_copy_tlv(skb, BTINTEL_WRAP_CTR, &data->dmp_hdr.wrap_ctr,
b8cc1a1cce30cc Kiran K 2025-02-27  533  			      sizeof(data->dmp_hdr.wrap_ctr));
b8cc1a1cce30cc Kiran K 2025-02-27  534  
b8cc1a1cce30cc Kiran K 2025-02-27  535  	btintel_pcie_copy_tlv(skb, BTINTEL_TRIGGER_REASON, &data->dmp_hdr.trigger_reason,
b8cc1a1cce30cc Kiran K 2025-02-27  536  			      sizeof(data->dmp_hdr.trigger_reason));
b8cc1a1cce30cc Kiran K 2025-02-27  537  
b8cc1a1cce30cc Kiran K 2025-02-27  538  	btintel_pcie_copy_tlv(skb, BTINTEL_FW_SHA, &data->dmp_hdr.fw_git_sha1,
b8cc1a1cce30cc Kiran K 2025-02-27  539  			      sizeof(data->dmp_hdr.fw_git_sha1));
b8cc1a1cce30cc Kiran K 2025-02-27  540  
b8cc1a1cce30cc Kiran K 2025-02-27  541  	btintel_pcie_copy_tlv(skb, BTINTEL_CNVR_TOP, &data->dmp_hdr.cnvr_top,
b8cc1a1cce30cc Kiran K 2025-02-27  542  			      sizeof(data->dmp_hdr.cnvr_top));
b8cc1a1cce30cc Kiran K 2025-02-27  543  
b8cc1a1cce30cc Kiran K 2025-02-27  544  	btintel_pcie_copy_tlv(skb, BTINTEL_CNVI_TOP, &data->dmp_hdr.cnvi_top,
b8cc1a1cce30cc Kiran K 2025-02-27  545  			      sizeof(data->dmp_hdr.cnvi_top));
b8cc1a1cce30cc Kiran K 2025-02-27  546  
b8cc1a1cce30cc Kiran K 2025-02-27  547  	btintel_pcie_copy_tlv(skb, BTINTEL_DUMP_TIME, buf, dump_time_len);
b8cc1a1cce30cc Kiran K 2025-02-27  548  
b8cc1a1cce30cc Kiran K 2025-02-27  549  	btintel_pcie_copy_tlv(skb, BTINTEL_FW_BUILD, buf + dump_time_len, fw_build);
b8cc1a1cce30cc Kiran K 2025-02-27  550  
b8cc1a1cce30cc Kiran K 2025-02-27  551  	ret = hci_devcd_append(hdev, skb);
b8cc1a1cce30cc Kiran K 2025-02-27  552  	if (ret)
b8cc1a1cce30cc Kiran K 2025-02-27  553  		goto exit_err;
b8cc1a1cce30cc Kiran K 2025-02-27  554  
b8cc1a1cce30cc Kiran K 2025-02-27  555  	for (i = 0; i < dbgc->count; i++) {
b8cc1a1cce30cc Kiran K 2025-02-27  556  		ret = btintel_pcie_add_dmp_data(hdev, dbgc->bufs[i].data,
b8cc1a1cce30cc Kiran K 2025-02-27  557  						BTINTEL_PCIE_DBGC_BUFFER_SIZE);
b8cc1a1cce30cc Kiran K 2025-02-27  558  		if (ret)
b8cc1a1cce30cc Kiran K 2025-02-27  559  			break;
b8cc1a1cce30cc Kiran K 2025-02-27  560  	}
b8cc1a1cce30cc Kiran K 2025-02-27  561  
b8cc1a1cce30cc Kiran K 2025-02-27  562  exit_err:
b8cc1a1cce30cc Kiran K 2025-02-27  563  	hci_devcd_complete(hdev);
b8cc1a1cce30cc Kiran K 2025-02-27  564  	return ret;
b8cc1a1cce30cc Kiran K 2025-02-27  565  }
Kiran K March 3, 2025, 4:31 p.m. UTC | #2
Hi Dan,

Thanks for your comment.

>Subject: Re: [PATCH v1] Bluetooth: btintel_pcie: Add support for device
>coredump
>
>Hi Kiran,
>
>kernel test robot noticed the following build warnings:
>
>https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
>url:    https://github.com/intel-lab-lkp/linux/commits/Kiran-K/Bluetooth-
>btintel_pcie-Add-support-for-device-coredump/20250227-181131
>base:   https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-
>next.git master
>patch link:    https://lore.kernel.org/r/20250227102625.20642-1-
>kiran.k%40intel.com
>patch subject: [PATCH v1] Bluetooth: btintel_pcie: Add support for device
>coredump
>config: sparc-randconfig-r071-20250302 (https://download.01.org/0day-
>ci/archive/20250302/202503022332.biRVCDMP-lkp@intel.com/config)
>compiler: sparc-linux-gcc (GCC) 14.2.0
>
>If you fix the issue in a separate patch/commit (i.e. not just a new version of
>the same patch/commit), kindly add following tags
>| Reported-by: kernel test robot <lkp@intel.com>
>| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
>| Closes: https://lore.kernel.org/r/202503022332.biRVCDMP-lkp@intel.com/
>
>New smatch warnings:
>drivers/bluetooth/btintel_pcie.c:493 btintel_pcie_read_dram_buffers() error:
>snprintf() is printing too much 100 vs 70

Ack. I have fixed this issue in v2 version of the patch.

>
>vim +493 drivers/bluetooth/btintel_pcie.c
>
>b8cc1a1cce30cc Kiran K 2025-02-27  454  static int
>btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data)
>b8cc1a1cce30cc Kiran K 2025-02-27  455  {
>b8cc1a1cce30cc Kiran K 2025-02-27  456  	u32 offset, prev_size,
>wr_ptr_status, dump_size, i;
>b8cc1a1cce30cc Kiran K 2025-02-27  457  	struct btintel_pcie_dbgc *dbgc
>= &data->dbgc;
>b8cc1a1cce30cc Kiran K 2025-02-27  458  	u8 buf_idx, dump_time_len,
>fw_build;
>b8cc1a1cce30cc Kiran K 2025-02-27  459  	struct hci_dev *hdev = data-
>>hdev;
>b8cc1a1cce30cc Kiran K 2025-02-27  460  	struct intel_tlv *tlv;
>b8cc1a1cce30cc Kiran K 2025-02-27  461  	struct timespec64 now;
>b8cc1a1cce30cc Kiran K 2025-02-27  462  	struct sk_buff *skb;
>b8cc1a1cce30cc Kiran K 2025-02-27  463  	struct tm tm_now;
>b8cc1a1cce30cc Kiran K 2025-02-27  464  	char buf[100];
>b8cc1a1cce30cc Kiran K 2025-02-27  465  	u16 hdr_len;
>b8cc1a1cce30cc Kiran K 2025-02-27  466  	int ret;
>b8cc1a1cce30cc Kiran K 2025-02-27  467
>b8cc1a1cce30cc Kiran K 2025-02-27  468  	wr_ptr_status =
>btintel_pcie_rd_dev_mem(data,
>BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS);
>b8cc1a1cce30cc Kiran K 2025-02-27  469  	offset = wr_ptr_status &
>BTINTEL_PCIE_DBG_OFFSET_BIT_MASK;
>b8cc1a1cce30cc Kiran K 2025-02-27  470
>b8cc1a1cce30cc Kiran K 2025-02-27  471  	buf_idx =
>BTINTEL_PCIE_DBGC_DBG_BUF_IDX(wr_ptr_status);
>b8cc1a1cce30cc Kiran K 2025-02-27  472  	if (buf_idx > dbgc->count) {
>b8cc1a1cce30cc Kiran K 2025-02-27  473  		bt_dev_warn(hdev,
>"Buffer index is invalid");
>b8cc1a1cce30cc Kiran K 2025-02-27  474  		return -EINVAL;
>b8cc1a1cce30cc Kiran K 2025-02-27  475  	}
>b8cc1a1cce30cc Kiran K 2025-02-27  476
>b8cc1a1cce30cc Kiran K 2025-02-27  477  	prev_size = buf_idx *
>BTINTEL_PCIE_DBGC_BUFFER_SIZE;
>b8cc1a1cce30cc Kiran K 2025-02-27  478  	if (prev_size + offset >=
>prev_size)
>b8cc1a1cce30cc Kiran K 2025-02-27  479  		data-
>>dmp_hdr.write_ptr = prev_size + offset;
>b8cc1a1cce30cc Kiran K 2025-02-27  480  	else
>b8cc1a1cce30cc Kiran K 2025-02-27  481  		return -EINVAL;
>b8cc1a1cce30cc Kiran K 2025-02-27  482
>b8cc1a1cce30cc Kiran K 2025-02-27  483  	ktime_get_real_ts64(&now);
>b8cc1a1cce30cc Kiran K 2025-02-27  484  	time64_to_tm(now.tv_sec, 0,
>&tm_now);
>b8cc1a1cce30cc Kiran K 2025-02-27  485  	dump_time_len = snprintf(buf,
>sizeof(buf), "Dump Time: %02d-%02d-%04ld %02d:%02d:%02d",
>b8cc1a1cce30cc Kiran K 2025-02-27  486
>tm_now.tm_mday, tm_now.tm_mon + 1, tm_now.tm_year + 1900,
>b8cc1a1cce30cc Kiran K 2025-02-27  487
>tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec);
>b8cc1a1cce30cc Kiran K 2025-02-27  488
>b8cc1a1cce30cc Kiran K 2025-02-27  489  	fw_build = snprintf(buf +
>dump_time_len, sizeof(buf),
>                                                                                         ^^^^^^^^^^^
>
>This size should be "sizeof(buf) - dump_time_len".  It's better to use scnprintf()
>here vs snprintf().  The scnprintf() function returns the number of bytes which
>were actually printed vs the number which were printed if there was enough
>space.
>
>b8cc1a1cce30cc Kiran K 2025-02-27  490  			    "Firmware
>Timestamp: Year %u WW %02u buildtype %u build %u",
>b8cc1a1cce30cc Kiran K 2025-02-27  491  			    2000 + (data-
>>dmp_hdr.fw_timestamp >> 8),
>b8cc1a1cce30cc Kiran K 2025-02-27  492  			    data-
>>dmp_hdr.fw_timestamp & 0xff, data->dmp_hdr.fw_build_type,
>b8cc1a1cce30cc Kiran K 2025-02-27 @493  			    data-
>>dmp_hdr.fw_build_num);
>b8cc1a1cce30cc Kiran K 2025-02-27  494
>b8cc1a1cce30cc Kiran K 2025-02-27  495  	hdr_len = sizeof(*tlv) +
>sizeof(data->dmp_hdr.cnvi_bt) +
>b8cc1a1cce30cc Kiran K 2025-02-27  496  		  sizeof(*tlv) +
>sizeof(data->dmp_hdr.write_ptr) +
>b8cc1a1cce30cc Kiran K 2025-02-27  497  		  sizeof(*tlv) +
>sizeof(data->dmp_hdr.wrap_ctr) +
>b8cc1a1cce30cc Kiran K 2025-02-27  498  		  sizeof(*tlv) +
>sizeof(data->dmp_hdr.trigger_reason) +
>b8cc1a1cce30cc Kiran K 2025-02-27  499  		  sizeof(*tlv) +
>sizeof(data->dmp_hdr.fw_git_sha1) +
>b8cc1a1cce30cc Kiran K 2025-02-27  500  		  sizeof(*tlv) +
>sizeof(data->dmp_hdr.cnvr_top) +
>b8cc1a1cce30cc Kiran K 2025-02-27  501  		  sizeof(*tlv) +
>sizeof(data->dmp_hdr.cnvi_top) +
>b8cc1a1cce30cc Kiran K 2025-02-27  502  		  sizeof(*tlv) +
>dump_time_len +
>b8cc1a1cce30cc Kiran K 2025-02-27  503  		  sizeof(*tlv) +
>fw_build;
>b8cc1a1cce30cc Kiran K 2025-02-27  504
>b8cc1a1cce30cc Kiran K 2025-02-27  505  	dump_size = hdr_len +
>sizeof(hdr_len);
>b8cc1a1cce30cc Kiran K 2025-02-27  506
>b8cc1a1cce30cc Kiran K 2025-02-27  507  	skb = alloc_skb(dump_size,
>GFP_KERNEL);
>b8cc1a1cce30cc Kiran K 2025-02-27  508  	if (!skb)
>b8cc1a1cce30cc Kiran K 2025-02-27  509  		return -ENOMEM;
>b8cc1a1cce30cc Kiran K 2025-02-27  510
>b8cc1a1cce30cc Kiran K 2025-02-27  511  	/* Add debug buffers data
>length to dump size */
>b8cc1a1cce30cc Kiran K 2025-02-27  512  	dump_size +=
>BTINTEL_PCIE_DBGC_BUFFER_SIZE * dbgc->count;
>b8cc1a1cce30cc Kiran K 2025-02-27  513
>b8cc1a1cce30cc Kiran K 2025-02-27  514  	ret = hci_devcd_init(hdev,
>dump_size);
>b8cc1a1cce30cc Kiran K 2025-02-27  515  	if (ret) {
>b8cc1a1cce30cc Kiran K 2025-02-27  516  		bt_dev_err(hdev,
>"Failed to init devcoredump, err %d", ret);
>b8cc1a1cce30cc Kiran K 2025-02-27  517  		kfree_skb(skb);
>b8cc1a1cce30cc Kiran K 2025-02-27  518  		return ret;
>b8cc1a1cce30cc Kiran K 2025-02-27  519  	}
>b8cc1a1cce30cc Kiran K 2025-02-27  520
>b8cc1a1cce30cc Kiran K 2025-02-27  521  	skb_put_data(skb, &hdr_len,
>sizeof(hdr_len));
>b8cc1a1cce30cc Kiran K 2025-02-27  522
>b8cc1a1cce30cc Kiran K 2025-02-27  523  	btintel_pcie_copy_tlv(skb,
>BTINTEL_CNVI_BT, &data->dmp_hdr.cnvi_bt,
>b8cc1a1cce30cc Kiran K 2025-02-27  524  			      sizeof(data-
>>dmp_hdr.cnvi_bt));
>b8cc1a1cce30cc Kiran K 2025-02-27  525
>b8cc1a1cce30cc Kiran K 2025-02-27  526  	btintel_pcie_copy_tlv(skb,
>BTINTEL_WRITE_PTR, &data->dmp_hdr.write_ptr,
>b8cc1a1cce30cc Kiran K 2025-02-27  527  			      sizeof(data-
>>dmp_hdr.write_ptr));
>b8cc1a1cce30cc Kiran K 2025-02-27  528
>b8cc1a1cce30cc Kiran K 2025-02-27  529  	data->dmp_hdr.wrap_ctr =
>btintel_pcie_rd_dev_mem(data,
>b8cc1a1cce30cc Kiran K 2025-02-27  530
>			 BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND);
>b8cc1a1cce30cc Kiran K 2025-02-27  531
>b8cc1a1cce30cc Kiran K 2025-02-27  532  	btintel_pcie_copy_tlv(skb,
>BTINTEL_WRAP_CTR, &data->dmp_hdr.wrap_ctr,
>b8cc1a1cce30cc Kiran K 2025-02-27  533  			      sizeof(data-
>>dmp_hdr.wrap_ctr));
>b8cc1a1cce30cc Kiran K 2025-02-27  534
>b8cc1a1cce30cc Kiran K 2025-02-27  535  	btintel_pcie_copy_tlv(skb,
>BTINTEL_TRIGGER_REASON, &data->dmp_hdr.trigger_reason,
>b8cc1a1cce30cc Kiran K 2025-02-27  536  			      sizeof(data-
>>dmp_hdr.trigger_reason));
>b8cc1a1cce30cc Kiran K 2025-02-27  537
>b8cc1a1cce30cc Kiran K 2025-02-27  538  	btintel_pcie_copy_tlv(skb,
>BTINTEL_FW_SHA, &data->dmp_hdr.fw_git_sha1,
>b8cc1a1cce30cc Kiran K 2025-02-27  539  			      sizeof(data-
>>dmp_hdr.fw_git_sha1));
>b8cc1a1cce30cc Kiran K 2025-02-27  540
>b8cc1a1cce30cc Kiran K 2025-02-27  541  	btintel_pcie_copy_tlv(skb,
>BTINTEL_CNVR_TOP, &data->dmp_hdr.cnvr_top,
>b8cc1a1cce30cc Kiran K 2025-02-27  542  			      sizeof(data-
>>dmp_hdr.cnvr_top));
>b8cc1a1cce30cc Kiran K 2025-02-27  543
>b8cc1a1cce30cc Kiran K 2025-02-27  544  	btintel_pcie_copy_tlv(skb,
>BTINTEL_CNVI_TOP, &data->dmp_hdr.cnvi_top,
>b8cc1a1cce30cc Kiran K 2025-02-27  545  			      sizeof(data-
>>dmp_hdr.cnvi_top));
>b8cc1a1cce30cc Kiran K 2025-02-27  546
>b8cc1a1cce30cc Kiran K 2025-02-27  547  	btintel_pcie_copy_tlv(skb,
>BTINTEL_DUMP_TIME, buf, dump_time_len);
>b8cc1a1cce30cc Kiran K 2025-02-27  548
>b8cc1a1cce30cc Kiran K 2025-02-27  549  	btintel_pcie_copy_tlv(skb,
>BTINTEL_FW_BUILD, buf + dump_time_len, fw_build);
>b8cc1a1cce30cc Kiran K 2025-02-27  550
>b8cc1a1cce30cc Kiran K 2025-02-27  551  	ret = hci_devcd_append(hdev,
>skb);
>b8cc1a1cce30cc Kiran K 2025-02-27  552  	if (ret)
>b8cc1a1cce30cc Kiran K 2025-02-27  553  		goto exit_err;
>b8cc1a1cce30cc Kiran K 2025-02-27  554
>b8cc1a1cce30cc Kiran K 2025-02-27  555  	for (i = 0; i < dbgc->count; i++) {
>b8cc1a1cce30cc Kiran K 2025-02-27  556  		ret =
>btintel_pcie_add_dmp_data(hdev, dbgc->bufs[i].data,
>b8cc1a1cce30cc Kiran K 2025-02-27  557
>		BTINTEL_PCIE_DBGC_BUFFER_SIZE);
>b8cc1a1cce30cc Kiran K 2025-02-27  558  		if (ret)
>b8cc1a1cce30cc Kiran K 2025-02-27  559  			break;
>b8cc1a1cce30cc Kiran K 2025-02-27  560  	}
>b8cc1a1cce30cc Kiran K 2025-02-27  561 b8cc1a1cce30cc Kiran K 2025-02-27
>562  exit_err:
>b8cc1a1cce30cc Kiran K 2025-02-27  563  	hci_devcd_complete(hdev);
>b8cc1a1cce30cc Kiran K 2025-02-27  564  	return ret;
>b8cc1a1cce30cc Kiran K 2025-02-27  565  }
>
>--
>0-DAY CI Kernel Test Service
>https://github.com/intel/lkp-tests/wiki
>

Thanks,
Kiran
diff mbox series

Patch

diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
index 4c21e69887a3..19530ea14905 100644
--- a/drivers/bluetooth/btintel.h
+++ b/drivers/bluetooth/btintel.h
@@ -190,7 +190,6 @@  enum {
 struct btintel_data {
 	DECLARE_BITMAP(flags, __INTEL_NUM_FLAGS);
 	int (*acpi_reset_method)(struct hci_dev *hdev);
-	u32	cnvi_top;
 };
 
 #define btintel_set_flag(hdev, nr)					\
diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index cecb926bce1c..0726f5de9792 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -59,6 +59,8 @@  MODULE_DEVICE_TABLE(pci, btintel_pcie_table);
 
 #define BTINTEL_PCIE_MAGIC_NUM	0xA5A5A5A5
 
+#define BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER	0x17A2
+
 /* Alive interrupt context */
 enum {
 	BTINTEL_PCIE_ROM,
@@ -375,6 +377,25 @@  static void btintel_pcie_mac_init(struct btintel_pcie_data *data)
 	btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg);
 }
 
+static int btintel_pcie_add_dmp_data(struct hci_dev *hdev, const void *data, int size)
+{
+	struct sk_buff *skb;
+	int err;
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	skb_put_data(skb, data, size);
+	err = hci_devcd_append(hdev, skb);
+	if (err) {
+		bt_dev_err(hdev, "Failed to append data in the coredump");
+		return err;
+	}
+
+	return 0;
+}
+
 static int btintel_pcie_get_mac_access(struct btintel_pcie_data *data)
 {
 	u32 reg;
@@ -419,6 +440,194 @@  static void btintel_pcie_release_mac_access(struct btintel_pcie_data *data)
 	btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg);
 }
 
+static void btintel_pcie_copy_tlv(struct sk_buff *skb, enum btintel_pcie_tlv_type type,
+				  void *data, int size)
+{
+	struct intel_tlv *tlv;
+
+	tlv = skb_put(skb, sizeof(*tlv) + size);
+	tlv->type = type;
+	tlv->len = size;
+	memcpy(tlv->val, data, tlv->len);
+}
+
+static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data)
+{
+	u32 offset, prev_size, wr_ptr_status, dump_size, i;
+	struct btintel_pcie_dbgc *dbgc = &data->dbgc;
+	u8 buf_idx, dump_time_len, fw_build;
+	struct hci_dev *hdev = data->hdev;
+	struct intel_tlv *tlv;
+	struct timespec64 now;
+	struct sk_buff *skb;
+	struct tm tm_now;
+	char buf[100];
+	u16 hdr_len;
+	int ret;
+
+	wr_ptr_status = btintel_pcie_rd_dev_mem(data, BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS);
+	offset = wr_ptr_status & BTINTEL_PCIE_DBG_OFFSET_BIT_MASK;
+
+	buf_idx = BTINTEL_PCIE_DBGC_DBG_BUF_IDX(wr_ptr_status);
+	if (buf_idx > dbgc->count) {
+		bt_dev_warn(hdev, "Buffer index is invalid");
+		return -EINVAL;
+	}
+
+	prev_size = buf_idx * BTINTEL_PCIE_DBGC_BUFFER_SIZE;
+	if (prev_size + offset >= prev_size)
+		data->dmp_hdr.write_ptr = prev_size + offset;
+	else
+		return -EINVAL;
+
+	ktime_get_real_ts64(&now);
+	time64_to_tm(now.tv_sec, 0, &tm_now);
+	dump_time_len = snprintf(buf, sizeof(buf), "Dump Time: %02d-%02d-%04ld %02d:%02d:%02d",
+				 tm_now.tm_mday, tm_now.tm_mon + 1, tm_now.tm_year + 1900,
+				 tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec);
+
+	fw_build = snprintf(buf + dump_time_len, sizeof(buf),
+			    "Firmware Timestamp: Year %u WW %02u buildtype %u build %u",
+			    2000 + (data->dmp_hdr.fw_timestamp >> 8),
+			    data->dmp_hdr.fw_timestamp & 0xff, data->dmp_hdr.fw_build_type,
+			    data->dmp_hdr.fw_build_num);
+
+	hdr_len = sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_bt) +
+		  sizeof(*tlv) + sizeof(data->dmp_hdr.write_ptr) +
+		  sizeof(*tlv) + sizeof(data->dmp_hdr.wrap_ctr) +
+		  sizeof(*tlv) + sizeof(data->dmp_hdr.trigger_reason) +
+		  sizeof(*tlv) + sizeof(data->dmp_hdr.fw_git_sha1) +
+		  sizeof(*tlv) + sizeof(data->dmp_hdr.cnvr_top) +
+		  sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_top) +
+		  sizeof(*tlv) + dump_time_len +
+		  sizeof(*tlv) + fw_build;
+
+	dump_size = hdr_len + sizeof(hdr_len);
+
+	skb = alloc_skb(dump_size, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	/* Add debug buffers data length to dump size */
+	dump_size += BTINTEL_PCIE_DBGC_BUFFER_SIZE * dbgc->count;
+
+	ret = hci_devcd_init(hdev, dump_size);
+	if (ret) {
+		bt_dev_err(hdev, "Failed to init devcoredump, err %d", ret);
+		kfree_skb(skb);
+		return ret;
+	}
+
+	skb_put_data(skb, &hdr_len, sizeof(hdr_len));
+
+	btintel_pcie_copy_tlv(skb, BTINTEL_CNVI_BT, &data->dmp_hdr.cnvi_bt,
+			      sizeof(data->dmp_hdr.cnvi_bt));
+
+	btintel_pcie_copy_tlv(skb, BTINTEL_WRITE_PTR, &data->dmp_hdr.write_ptr,
+			      sizeof(data->dmp_hdr.write_ptr));
+
+	data->dmp_hdr.wrap_ctr = btintel_pcie_rd_dev_mem(data,
+							 BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND);
+
+	btintel_pcie_copy_tlv(skb, BTINTEL_WRAP_CTR, &data->dmp_hdr.wrap_ctr,
+			      sizeof(data->dmp_hdr.wrap_ctr));
+
+	btintel_pcie_copy_tlv(skb, BTINTEL_TRIGGER_REASON, &data->dmp_hdr.trigger_reason,
+			      sizeof(data->dmp_hdr.trigger_reason));
+
+	btintel_pcie_copy_tlv(skb, BTINTEL_FW_SHA, &data->dmp_hdr.fw_git_sha1,
+			      sizeof(data->dmp_hdr.fw_git_sha1));
+
+	btintel_pcie_copy_tlv(skb, BTINTEL_CNVR_TOP, &data->dmp_hdr.cnvr_top,
+			      sizeof(data->dmp_hdr.cnvr_top));
+
+	btintel_pcie_copy_tlv(skb, BTINTEL_CNVI_TOP, &data->dmp_hdr.cnvi_top,
+			      sizeof(data->dmp_hdr.cnvi_top));
+
+	btintel_pcie_copy_tlv(skb, BTINTEL_DUMP_TIME, buf, dump_time_len);
+
+	btintel_pcie_copy_tlv(skb, BTINTEL_FW_BUILD, buf + dump_time_len, fw_build);
+
+	ret = hci_devcd_append(hdev, skb);
+	if (ret)
+		goto exit_err;
+
+	for (i = 0; i < dbgc->count; i++) {
+		ret = btintel_pcie_add_dmp_data(hdev, dbgc->bufs[i].data,
+						BTINTEL_PCIE_DBGC_BUFFER_SIZE);
+		if (ret)
+			break;
+	}
+
+exit_err:
+	hci_devcd_complete(hdev);
+	return ret;
+}
+
+static void btintel_pcie_dump_traces(struct hci_dev *hdev)
+{
+	struct btintel_pcie_data *data = hci_get_drvdata(hdev);
+	int ret = 0;
+
+	ret = btintel_pcie_get_mac_access(data);
+	if (ret) {
+		bt_dev_err(hdev, "Failed to get mac access: (%d)", ret);
+		return;
+	}
+
+	ret = btintel_pcie_read_dram_buffers(data);
+
+	btintel_pcie_release_mac_access(data);
+
+	if (ret)
+		bt_dev_err(hdev, "Failed to dump traces: (%d)", ret);
+}
+
+static void btintel_pcie_dump_hdr(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct btintel_pcie_data *data = hci_get_drvdata(hdev);
+	u16 len = skb->len;
+	u16 *hdrlen_ptr;
+	char buf[80];
+
+	hdrlen_ptr = skb_put_zero(skb, sizeof(len));
+
+	snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n",
+		 INTEL_HW_VARIANT(data->dmp_hdr.cnvi_bt));
+	skb_put_data(skb, buf, strlen(buf));
+
+	snprintf(buf, sizeof(buf), "Firmware Build Number: %u\n",
+		 data->dmp_hdr.fw_build_num);
+	skb_put_data(skb, buf, strlen(buf));
+
+	snprintf(buf, sizeof(buf), "Driver: %s\n", data->dmp_hdr.driver_name);
+	skb_put_data(skb, buf, strlen(buf));
+
+	snprintf(buf, sizeof(buf), "Vendor: Intel\n");
+	skb_put_data(skb, buf, strlen(buf));
+
+	*hdrlen_ptr = skb->len - len;
+}
+
+static void btintel_pcie_dump_notify(struct hci_dev *hdev, int state)
+{
+	struct btintel_pcie_data *data = hci_get_drvdata(hdev);
+
+	switch (state) {
+	case HCI_DEVCOREDUMP_IDLE:
+		data->dmp_hdr.state = HCI_DEVCOREDUMP_IDLE;
+		break;
+	case HCI_DEVCOREDUMP_ACTIVE:
+		data->dmp_hdr.state = HCI_DEVCOREDUMP_ACTIVE;
+		break;
+	case HCI_DEVCOREDUMP_TIMEOUT:
+	case HCI_DEVCOREDUMP_ABORT:
+	case HCI_DEVCOREDUMP_DONE:
+		data->dmp_hdr.state = HCI_DEVCOREDUMP_IDLE;
+		break;
+	}
+}
+
 /* This function enables BT function by setting BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT bit in
  * BTINTEL_PCIE_CSR_FUNC_CTRL_REG register and wait for MSI-X with
  * BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0.
@@ -883,7 +1092,6 @@  static int btintel_pcie_recv_frame(struct btintel_pcie_data *data,
 
 static void btintel_pcie_read_hwexp(struct btintel_pcie_data *data)
 {
-	struct btintel_data *intel_data = hci_get_priv(data->hdev);
 	int len, err, offset, pending;
 	struct sk_buff *skb;
 	u8 *buf, prefix[64];
@@ -898,11 +1106,11 @@  static void btintel_pcie_read_hwexp(struct btintel_pcie_data *data)
 
 	struct tlv *tlv;
 
-	switch (intel_data->cnvi_top & 0xfff) {
+	switch (data->dmp_hdr.cnvi_top & 0xfff) {
 	case BTINTEL_CNVI_BLAZARI:
 	case BTINTEL_CNVI_BLAZARIW:
 		/* only from step B0 onwards */
-		if (INTEL_CNVX_TOP_STEP(intel_data->cnvi_top) != 0x01)
+		if (INTEL_CNVX_TOP_STEP(data->dmp_hdr.cnvi_top) != 0x01)
 			return;
 		len = BTINTEL_PCIE_BLZR_HWEXP_SIZE; /* exception data length */
 		addr = BTINTEL_PCIE_BLZR_HWEXP_DMP_ADDR;
@@ -912,7 +1120,7 @@  static void btintel_pcie_read_hwexp(struct btintel_pcie_data *data)
 		addr = BTINTEL_PCIE_SCP_HWEXP_DMP_ADDR;
 	break;
 	default:
-		bt_dev_err(data->hdev, "Unsupported cnvi 0x%8.8x", intel_data->cnvi_top);
+		bt_dev_err(data->hdev, "Unsupported cnvi 0x%8.8x", data->dmp_hdr.cnvi_top);
 		return;
 	}
 
@@ -1017,6 +1225,11 @@  static void btintel_pcie_rx_work(struct work_struct *work)
 		clear_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags);
 	}
 
+	if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) {
+		btintel_pcie_dump_traces(data->hdev);
+		clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
+	}
+
 	/* Process the sk_buf in queue and send to the HCI layer */
 	while ((skb = skb_dequeue(&data->rx_skb_q))) {
 		err = btintel_pcie_recv_frame(data, skb);
@@ -1702,7 +1915,7 @@  static void btintel_pcie_release_hdev(struct btintel_pcie_data *data)
 
 static int btintel_pcie_setup_internal(struct hci_dev *hdev)
 {
-	struct btintel_data *data = hci_get_priv(hdev);
+	struct btintel_pcie_data *data = hci_get_drvdata(hdev);
 	const u8 param[1] = { 0xFF };
 	struct intel_version_tlv ver_tlv;
 	struct sk_buff *skb;
@@ -1741,7 +1954,6 @@  static int btintel_pcie_setup_internal(struct hci_dev *hdev)
 		goto exit_error;
 	}
 
-	data->cnvi_top = ver_tlv.cnvi_top;
 	switch (INTEL_HW_PLATFORM(ver_tlv.cnvi_bt)) {
 	case 0x37:
 		break;
@@ -1787,6 +1999,23 @@  static int btintel_pcie_setup_internal(struct hci_dev *hdev)
 		break;
 	}
 
+	data->dmp_hdr.cnvi_top = ver_tlv.cnvi_top;
+	data->dmp_hdr.cnvr_top = ver_tlv.cnvr_top;
+	data->dmp_hdr.fw_timestamp = ver_tlv.timestamp;
+	data->dmp_hdr.fw_build_type = ver_tlv.build_type;
+	data->dmp_hdr.fw_build_num = ver_tlv.build_num;
+	data->dmp_hdr.cnvi_bt = ver_tlv.cnvi_bt;
+
+	if (ver_tlv.img_type == 0x02 || ver_tlv.img_type == 0x03)
+		data->dmp_hdr.fw_git_sha1 = ver_tlv.git_sha1;
+
+	err = hci_devcd_register(hdev, btintel_pcie_dump_traces, btintel_pcie_dump_hdr,
+				 btintel_pcie_dump_notify);
+	if (err) {
+		bt_dev_err(hdev, "Failed to register coredump (%d)", err);
+		goto exit_error;
+	}
+
 	btintel_print_fseq_info(hdev);
 exit_error:
 	kfree_skb(skb);
@@ -1851,6 +2080,7 @@  static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
 		goto exit_error;
 	}
 
+	data->dmp_hdr.driver_name = KBUILD_MODNAME;
 	return 0;
 
 exit_error:
@@ -1963,11 +2193,28 @@  static void btintel_pcie_remove(struct pci_dev *pdev)
 	pci_set_drvdata(pdev, NULL);
 }
 
+#ifdef CONFIG_DEV_COREDUMP
+static void btintel_pcie_coredump(struct device *dev)
+{
+	struct  pci_dev *pdev = to_pci_dev(dev);
+	struct btintel_pcie_data *data = pci_get_drvdata(pdev);
+
+	if (test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
+		return;
+
+	data->dmp_hdr.trigger_reason  = BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER;
+	queue_work(data->workqueue, &data->rx_work);
+}
+#endif
+
 static struct pci_driver btintel_pcie_driver = {
 	.name = KBUILD_MODNAME,
 	.id_table = btintel_pcie_table,
 	.probe = btintel_pcie_probe,
 	.remove = btintel_pcie_remove,
+#ifdef CONFIG_DEV_COREDUMP
+	.driver.coredump = btintel_pcie_coredump
+#endif
 };
 module_pci_driver(btintel_pcie_driver);
 
diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h
index d17808ebe725..873178019cad 100644
--- a/drivers/bluetooth/btintel_pcie.h
+++ b/drivers/bluetooth/btintel_pcie.h
@@ -56,6 +56,15 @@ 
 #define BTINTEL_PCIE_CSR_MSIX_IVAR_BASE		(BTINTEL_PCIE_CSR_MSIX_BASE + 0x0880)
 #define BTINTEL_PCIE_CSR_MSIX_IVAR(cause)	(BTINTEL_PCIE_CSR_MSIX_IVAR_BASE + (cause))
 
+/* IOSF Debug Register */
+#define BTINTEL_PCIE_DBGC_BASE_ADDR			(0xf3800300)
+#define BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS		(BTINTEL_PCIE_DBGC_BASE_ADDR + 0x1C)
+#define BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND		(BTINTEL_PCIE_DBGC_BASE_ADDR + 0x2C)
+
+#define BTINTEL_PCIE_DBG_IDX_BIT_MASK		0x0F
+#define BTINTEL_PCIE_DBGC_DBG_BUF_IDX(data)	(((data) >> 24) & BTINTEL_PCIE_DBG_IDX_BIT_MASK)
+#define BTINTEL_PCIE_DBG_OFFSET_BIT_MASK	0xFFFFFF
+
 /* The DRAM buffer count, each buffer size, and
  * fragment buffer size
  */
@@ -97,6 +106,19 @@  enum {
 enum {
 	BTINTEL_PCIE_CORE_HALTED,
 	BTINTEL_PCIE_HWEXP_INPROGRESS,
+	BTINTEL_PCIE_COREDUMP_INPROGRESS
+};
+
+enum btintel_pcie_tlv_type {
+	BTINTEL_CNVI_BT,
+	BTINTEL_WRITE_PTR,
+	BTINTEL_WRAP_CTR,
+	BTINTEL_TRIGGER_REASON,
+	BTINTEL_FW_SHA,
+	BTINTEL_CNVR_TOP,
+	BTINTEL_CNVI_TOP,
+	BTINTEL_DUMP_TIME,
+	BTINTEL_FW_BUILD,
 };
 
 #define BTINTEL_PCIE_MSIX_NON_AUTO_CLEAR_CAUSE	BIT(7)
@@ -371,6 +393,21 @@  struct btintel_pcie_dbgc {
 	struct data_buf *bufs;
 };
 
+struct btintel_pcie_dump_header {
+	const char	*driver_name;
+	u32		cnvi_top;
+	u32		cnvr_top;
+	u16		fw_timestamp;
+	u8		fw_build_type;
+	u32		fw_build_num;
+	u32		fw_git_sha1;
+	u32		cnvi_bt;
+	u32		write_ptr;
+	u32		wrap_ctr;
+	u16		trigger_reason;
+	int		state;
+};
+
 /* struct btintel_pcie_data
  * @pdev: pci device
  * @hdev: hdev device
@@ -452,6 +489,7 @@  struct btintel_pcie_data {
 	struct rxq	rxq;
 	u32	alive_intr_ctxt;
 	struct btintel_pcie_dbgc	dbgc;
+	struct btintel_pcie_dump_header dmp_hdr;
 };
 
 static inline u32 btintel_pcie_rd_reg32(struct btintel_pcie_data *data,