]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Bluetooth: btintel_pcie: Refactor Device Coredump
authorKiran K <kiran.k@intel.com>
Wed, 6 Aug 2025 06:48:49 +0000 (12:18 +0530)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Sat, 27 Sep 2025 15:37:00 +0000 (11:37 -0400)
As device coredumps are not HCI traces, maintain the device coredump at
the driver level and eliminate the dependency on hdev_devcd*()

Signed-off-by: Kiran K <kiran.k@intel.com>
Fixes: 07e6bddb54b4 ("Bluetooth: btintel_pcie: Add support for device coredump")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
drivers/bluetooth/btintel_pcie.c
drivers/bluetooth/btintel_pcie.h

index a625a5b2154bd53c1aa12140bf6da635fde3c25e..6d3963bd56a9c686d071f828e3c8b10630c36bf4 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/interrupt.h>
 
 #include <linux/unaligned.h>
+#include <linux/devcoredump.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -559,25 +560,6 @@ 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;
@@ -622,30 +604,35 @@ 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)
+static void *btintel_pcie_copy_tlv(void *dest, enum btintel_pcie_tlv_type type,
+                                  void *data, size_t size)
 {
        struct intel_tlv *tlv;
 
-       tlv = skb_put(skb, sizeof(*tlv) + size);
+       tlv = dest;
        tlv->type = type;
        tlv->len = size;
        memcpy(tlv->val, data, tlv->len);
+       return dest + sizeof(*tlv) + size;
 }
 
 static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data)
 {
-       u32 offset, prev_size, wr_ptr_status, dump_size, i;
+       u32 offset, prev_size, wr_ptr_status, dump_size, data_len;
        struct btintel_pcie_dbgc *dbgc = &data->dbgc;
-       u8 buf_idx, dump_time_len, fw_build;
        struct hci_dev *hdev = data->hdev;
+       u8 *pdata, *p, buf_idx;
        struct intel_tlv *tlv;
        struct timespec64 now;
-       struct sk_buff *skb;
        struct tm tm_now;
-       char buf[256];
-       u16 hdr_len;
-       int ret;
+       char fw_build[128];
+       char ts[128];
+       char vendor[64];
+       char driver[64];
+
+       if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
+               return -EOPNOTSUPP;
+
 
        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;
@@ -662,88 +649,84 @@ static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data)
        else
                return -EINVAL;
 
+       snprintf(vendor, sizeof(vendor), "Vendor: Intel\n");
+       snprintf(driver, sizeof(driver), "Driver: %s\n",
+                data->dmp_hdr.driver_name);
+
        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",
+       snprintf(ts, sizeof(ts), "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) - dump_time_len,
+       snprintf(fw_build, sizeof(fw_build),
                            "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;
+       data_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) + strlen(ts) +
+               sizeof(*tlv) + strlen(fw_build) +
+               sizeof(*tlv) + strlen(vendor) +
+               sizeof(*tlv) + strlen(driver);
 
-       dump_size = hdr_len + sizeof(hdr_len);
+       /*
+        * sizeof(u32) - signature
+        * sizeof(data_len) - to store tlv data size
+        * data_len - TLV data
+        */
+       dump_size = sizeof(u32) + sizeof(data_len) + data_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;
-       }
+       pdata = vmalloc(dump_size);
+       if (!pdata)
+               return -ENOMEM;
+       p = pdata;
+
+       *(u32 *)p = BTINTEL_PCIE_MAGIC_NUM;
+       p += sizeof(u32);
 
-       skb_put_data(skb, &hdr_len, sizeof(hdr_len));
+       *(u32 *)p = data_len;
+       p += sizeof(u32);
 
-       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));
+       p = btintel_pcie_copy_tlv(p, BTINTEL_VENDOR, vendor, strlen(vendor));
+       p = btintel_pcie_copy_tlv(p, BTINTEL_DRIVER, driver, strlen(driver));
+       p = btintel_pcie_copy_tlv(p, BTINTEL_DUMP_TIME, ts, strlen(ts));
+       p = btintel_pcie_copy_tlv(p, BTINTEL_FW_BUILD, fw_build,
+                                 strlen(fw_build));
+       p = btintel_pcie_copy_tlv(p, BTINTEL_CNVI_BT, &data->dmp_hdr.cnvi_bt,
+                                 sizeof(data->dmp_hdr.cnvi_bt));
+       p = btintel_pcie_copy_tlv(p, BTINTEL_WRITE_PTR, &data->dmp_hdr.write_ptr,
+                                 sizeof(data->dmp_hdr.write_ptr));
+       p = btintel_pcie_copy_tlv(p, BTINTEL_WRAP_CTR, &data->dmp_hdr.wrap_ctr,
+                                 sizeof(data->dmp_hdr.wrap_ctr));
 
        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;
+       p = btintel_pcie_copy_tlv(p, BTINTEL_TRIGGER_REASON, &data->dmp_hdr.trigger_reason,
+                                 sizeof(data->dmp_hdr.trigger_reason));
+       p = btintel_pcie_copy_tlv(p, BTINTEL_FW_SHA, &data->dmp_hdr.fw_git_sha1,
+                                 sizeof(data->dmp_hdr.fw_git_sha1));
+       p = btintel_pcie_copy_tlv(p, BTINTEL_CNVR_TOP, &data->dmp_hdr.cnvr_top,
+                                 sizeof(data->dmp_hdr.cnvr_top));
+       p = btintel_pcie_copy_tlv(p, BTINTEL_CNVI_TOP, &data->dmp_hdr.cnvi_top,
+                                 sizeof(data->dmp_hdr.cnvi_top));
+
+       memcpy(p, dbgc->bufs[0].data, dbgc->count * BTINTEL_PCIE_DBGC_BUFFER_SIZE);
+       dev_coredumpv(&hdev->dev, pdata, dump_size, GFP_KERNEL);
+       return 0;
 }
 
 static void btintel_pcie_dump_traces(struct hci_dev *hdev)
@@ -765,51 +748,6 @@ static void btintel_pcie_dump_traces(struct hci_dev *hdev)
                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.
@@ -1383,6 +1321,11 @@ static void btintel_pcie_rx_work(struct work_struct *work)
                                        struct btintel_pcie_data, rx_work);
        struct sk_buff *skb;
 
+       if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) {
+               btintel_pcie_dump_traces(data->hdev);
+               clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
+       }
+
        if (test_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags)) {
                /* Unlike usb products, controller will not send hardware
                 * exception event on exception. Instead controller writes the
@@ -1395,11 +1338,6 @@ 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))) {
                btintel_pcie_recv_frame(data, skb);
@@ -2190,13 +2128,6 @@ static int btintel_pcie_setup_internal(struct hci_dev *hdev)
        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);
@@ -2326,7 +2257,6 @@ static void btintel_pcie_removal_work(struct work_struct *wk)
        btintel_pcie_synchronize_irqs(data);
 
        flush_work(&data->rx_work);
-       flush_work(&data->hdev->dump.dump_rx);
 
        bt_dev_dbg(data->hdev, "Release bluetooth interface");
        btintel_pcie_release_hdev(data);
index 0fa876c5b954a0bfa165185846f66024dd21f658..04b21f968ad30ff75d256dedc3b1a7ddb9009801 100644 (file)
@@ -132,6 +132,8 @@ enum btintel_pcie_tlv_type {
        BTINTEL_CNVI_TOP,
        BTINTEL_DUMP_TIME,
        BTINTEL_FW_BUILD,
+       BTINTEL_VENDOR,
+       BTINTEL_DRIVER
 };
 
 /* causes for the MBOX interrupts */