diff mbox series

[v5,3/3] Bluetooth: btusb: mediatek: add MediaTek devcoredump support

Message ID ddcbc509b5024882583d5c143ec5f4520bef860a.1683065391.git.objelf@gmail.com (mailing list archive)
State Superseded
Headers show
Series [v5,1/3] Bluetooth: btusb: mediatek: use readx_poll_timeout instead of open coding | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
tedd_an/CheckPatch success CheckPatch PASS
tedd_an/GitLint success Gitlint PASS
tedd_an/SubjectPrefix success Gitlint PASS
tedd_an/IncrementalBuild success Incremental Build PASS

Commit Message

Sean Wang May 2, 2023, 11:02 p.m. UTC
From: Jing Cai <jing.cai@mediatek.com>

This patch implement function .coredump() and dmp_hdr() in btusb
driver for MediaTek controller.  FW core dump was triggered by FW
specific event to show something unexpected happened in the controller.

The driver would be responsible for collecting and uploading the device
core dump pieces in hci driver using core dump API. Once we finished
the whole process, the driver would reset the controller to recover the
kind of fatal error.

Co-developed-by: Chris Lu <chris.lu@mediatek.com>
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Co-developed-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Jing Cai <jing.cai@mediatek.com>
---
v2, v3: rebase onto the latest codebase
v4: update the newest API usage for the coredump which was already
    into the upstream
v5: support devcoredump on hdev basis
---
 drivers/bluetooth/btmtk.c | 117 ++++++++++++++++++++++++++++++++++++++
 drivers/bluetooth/btmtk.h |  28 +++++++++
 drivers/bluetooth/btusb.c |  14 +++++
 3 files changed, 159 insertions(+)

Comments

kernel test robot May 3, 2023, 9:42 a.m. UTC | #1
Hi,

kernel test robot noticed the following build errors:

[auto build test ERROR on bluetooth/master]
[also build test ERROR on bluetooth-next/master linus/master v6.3 next-20230428]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/sean-wang-mediatek-com/Bluetooth-btmtk-introduce-btmtk-reset-work/20230503-070640
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git master
patch link:    https://lore.kernel.org/r/ddcbc509b5024882583d5c143ec5f4520bef860a.1683065391.git.objelf%40gmail.com
patch subject: [PATCH v5 3/3] Bluetooth: btusb: mediatek: add MediaTek devcoredump support
config: x86_64-randconfig-a016-20230501 (https://download.01.org/0day-ci/archive/20230503/202305031708.UQZ6jRn6-lkp@intel.com/config)
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/635545fc4095e7e6b159177a07b0359b7eafe482
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review sean-wang-mediatek-com/Bluetooth-btmtk-introduce-btmtk-reset-work/20230503-070640
        git checkout 635545fc4095e7e6b159177a07b0359b7eafe482
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/bluetooth/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202305031708.UQZ6jRn6-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/bluetooth/btmtk.c:97:7: error: use of undeclared identifier 'HCI_DEVCOREDUMP_IDLE'
           case HCI_DEVCOREDUMP_IDLE:
                ^
   drivers/bluetooth/btmtk.c:100:7: error: use of undeclared identifier 'HCI_DEVCOREDUMP_ACTIVE'; did you mean 'BTMTK_COREDUMP_ACTIVE'?
           case HCI_DEVCOREDUMP_ACTIVE:
                ^~~~~~~~~~~~~~~~~~~~~~
                BTMTK_COREDUMP_ACTIVE
   drivers/bluetooth/btmtk.c:25:2: note: 'BTMTK_COREDUMP_ACTIVE' declared here
           BTMTK_COREDUMP_ACTIVE,
           ^
   drivers/bluetooth/btmtk.c:103:7: error: use of undeclared identifier 'HCI_DEVCOREDUMP_TIMEOUT'
           case HCI_DEVCOREDUMP_TIMEOUT:
                ^
   drivers/bluetooth/btmtk.c:104:7: error: use of undeclared identifier 'HCI_DEVCOREDUMP_ABORT'
           case HCI_DEVCOREDUMP_ABORT:
                ^
   drivers/bluetooth/btmtk.c:105:7: error: use of undeclared identifier 'HCI_DEVCOREDUMP_DONE'
           case HCI_DEVCOREDUMP_DONE:
                ^
   drivers/bluetooth/btmtk.c:367:9: error: implicit declaration of function 'hci_devcd_register' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
           return hci_devcd_register(hdev, btmtk_coredump, btmtk_coredump_hdr,
                  ^
   drivers/bluetooth/btmtk.c:385:9: error: implicit declaration of function 'hci_devcd_init' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
                   err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE);
                         ^
   drivers/bluetooth/btmtk.c:385:9: note: did you mean 'hci_sock_init'?
   include/net/bluetooth/bluetooth.h:577:5: note: 'hci_sock_init' declared here
   int hci_sock_init(void);
       ^
>> drivers/bluetooth/btmtk.c:389:32: error: no member named 'dump' in 'struct hci_dev'
                   schedule_delayed_work(&hdev->dump.dump_timeout,
                                          ~~~~  ^
   drivers/bluetooth/btmtk.c:394:9: error: implicit declaration of function 'hci_devcd_append' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
                   err = hci_devcd_append(hdev, skb);
                         ^
   drivers/bluetooth/btmtk.c:394:9: note: did you mean 'hci_dev_open'?
   include/net/bluetooth/hci_core.h:1500:5: note: 'hci_dev_open' declared here
   int hci_dev_open(__u16 dev);
       ^
   drivers/bluetooth/btmtk.c:401:4: error: implicit declaration of function 'hci_devcd_complete' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
                           hci_devcd_complete(hdev);
                           ^
   drivers/bluetooth/btmtk.c:401:4: note: did you mean 'hci_devcd_append'?
   drivers/bluetooth/btmtk.c:394:9: note: 'hci_devcd_append' declared here
                   err = hci_devcd_append(hdev, skb);
                         ^
   10 errors generated.


vim +389 drivers/bluetooth/btmtk.c

   371	
   372	int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
   373	{
   374		struct btmtk_data *data = hci_get_priv(hdev);
   375		int err;
   376	
   377		if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
   378			return 0;
   379	
   380		switch (data->cd_info.state) {
   381		case BTMTK_COREDUMP_DISABLED:
   382			err = -EINVAL;
   383			break;
   384		case BTMTK_COREDUMP_INIT:
 > 385			err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE);
   386			if (err < 0)
   387				break;
   388			/* It is supposed coredump can be done within 5 seconds */
 > 389			schedule_delayed_work(&hdev->dump.dump_timeout,
   390					      msecs_to_jiffies(5000));
   391			fallthrough;
   392		case BTMTK_COREDUMP_ACTIVE:
   393		default:
   394			err = hci_devcd_append(hdev, skb);
   395			if (err < 0)
   396				break;
   397	
   398			if (skb->len > 12 &&
   399			    !strncmp((char *)&skb->data[skb->len - 13],
   400				     MTK_COREDUMP_END, 12))
   401				hci_devcd_complete(hdev);
   402	
   403			break;
   404		}
   405	
   406		if (err < 0) {
   407			data->cd_info.state = BTMTK_COREDUMP_DISABLED;
   408			kfree_skb(skb);
   409		}
   410	
   411		return err;
   412	}
   413	EXPORT_SYMBOL_GPL(btmtk_process_coredump);
   414
Luiz Augusto von Dentz May 8, 2023, 7:54 p.m. UTC | #2
Hi Sean,

On Tue, May 2, 2023 at 4:02 PM <sean.wang@mediatek.com> wrote:
>
> From: Jing Cai <jing.cai@mediatek.com>
>
> This patch implement function .coredump() and dmp_hdr() in btusb
> driver for MediaTek controller.  FW core dump was triggered by FW
> specific event to show something unexpected happened in the controller.
>
> The driver would be responsible for collecting and uploading the device
> core dump pieces in hci driver using core dump API. Once we finished
> the whole process, the driver would reset the controller to recover the
> kind of fatal error.
>
> Co-developed-by: Chris Lu <chris.lu@mediatek.com>
> Signed-off-by: Chris Lu <chris.lu@mediatek.com>
> Co-developed-by: Sean Wang <sean.wang@mediatek.com>
> Signed-off-by: Sean Wang <sean.wang@mediatek.com>
> Signed-off-by: Jing Cai <jing.cai@mediatek.com>
> ---
> v2, v3: rebase onto the latest codebase
> v4: update the newest API usage for the coredump which was already
>     into the upstream
> v5: support devcoredump on hdev basis
> ---
>  drivers/bluetooth/btmtk.c | 117 ++++++++++++++++++++++++++++++++++++++
>  drivers/bluetooth/btmtk.h |  28 +++++++++
>  drivers/bluetooth/btusb.c |  14 +++++
>  3 files changed, 159 insertions(+)
>
> diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
> index ac2fac7e3c5f..657792f9dcab 100644
> --- a/drivers/bluetooth/btmtk.c
> +++ b/drivers/bluetooth/btmtk.c
> @@ -19,6 +19,12 @@
>  #define MTK_SEC_MAP_COMMON_SIZE        12
>  #define MTK_SEC_MAP_NEED_SEND_SIZE     52
>
> +enum {
> +       BTMTK_COREDUMP_INIT,
> +       BTMTK_COREDUMP_DISABLED,
> +       BTMTK_COREDUMP_ACTIVE,
> +};
> +
>  struct btmtk_patch_header {
>         u8 datetime[16];
>         u8 platform[4];
> @@ -53,6 +59,56 @@ struct btmtk_section_map {
>         };
>  } __packed;
>
> +static void btmtk_coredump(struct hci_dev *hdev)
> +{
> +       int err;
> +
> +       err = __hci_cmd_send(hdev, 0xfd5b, 0, NULL);
> +       if (err < 0)
> +               bt_dev_err(hdev, "Coredump failed (%d)", err);
> +}
> +
> +static void btmtk_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> +       struct btmtk_data *data = hci_get_priv(hdev);
> +       char buf[80];
> +
> +       snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n",
> +                data->cd_info.dev_id);
> +       skb_put_data(skb, buf, strlen(buf));
> +
> +       snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n",
> +                data->cd_info.fw_version);
> +       skb_put_data(skb, buf, strlen(buf));
> +
> +       snprintf(buf, sizeof(buf), "Driver: %s\n",
> +                data->cd_info.driver_name);
> +       skb_put_data(skb, buf, strlen(buf));
> +
> +       snprintf(buf, sizeof(buf), "Vendor: MediaTek\n");
> +       skb_put_data(skb, buf, strlen(buf));
> +}
> +
> +static void btmtk_coredump_notify(struct hci_dev *hdev, int state)
> +{
> +       struct btmtk_data *data = hci_get_priv(hdev);
> +
> +       switch (state) {
> +       case HCI_DEVCOREDUMP_IDLE:
> +               data->cd_info.state = BTMTK_COREDUMP_INIT;
> +               break;
> +       case HCI_DEVCOREDUMP_ACTIVE:
> +               data->cd_info.state = BTMTK_COREDUMP_ACTIVE;
> +               break;
> +       case HCI_DEVCOREDUMP_TIMEOUT:
> +       case HCI_DEVCOREDUMP_ABORT:
> +       case HCI_DEVCOREDUMP_DONE:
> +               data->cd_info.state = BTMTK_COREDUMP_INIT;
> +               btmtk_reset_sync(hdev);
> +               break;
> +       }
> +}

Don't really like where this is going, why can't you just use the
state from devcd?

> +
>  int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
>                               wmt_cmd_sync_func_t wmt_cmd_sync)
>  {
> @@ -295,6 +351,67 @@ void btmtk_reset_sync(struct hci_dev *hdev)
>  }
>  EXPORT_SYMBOL_GPL(btmtk_reset_sync);
>
> +int btmtk_register_coredump(struct hci_dev *hdev, u32 dev_id,
> +                            const char *name, u32 fw_version)
> +{
> +       struct btmtk_data *data = hci_get_priv(hdev);
> +
> +       if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
> +               return -EOPNOTSUPP;
> +
> +       data->cd_info.dev_id = dev_id;
> +       data->cd_info.fw_version = fw_version;
> +       data->cd_info.state = BTMTK_COREDUMP_INIT;
> +       strncpy(data->cd_info.driver_name, name, MTK_DRIVER_NAME_LEN - 1);

Im not really sure why every devcd is having to store the driver name
as a copy, the driver name is already accessible via
hdev->dev->driver->name.

@Manish Mandlik we might want to fix any code that still is doing
copies of driver name like above.

> +
> +       return hci_devcd_register(hdev, btmtk_coredump, btmtk_coredump_hdr,
> +                                 btmtk_coredump_notify);
> +}
> +EXPORT_SYMBOL_GPL(btmtk_register_coredump);
> +
> +int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> +       struct btmtk_data *data = hci_get_priv(hdev);
> +       int err;
> +
> +       if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
> +               return 0;
> +
> +       switch (data->cd_info.state) {
> +       case BTMTK_COREDUMP_DISABLED:
> +               err = -EINVAL;
> +               break;
> +       case BTMTK_COREDUMP_INIT:
> +               err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE);
> +               if (err < 0)
> +                       break;
> +               /* It is supposed coredump can be done within 5 seconds */
> +               schedule_delayed_work(&hdev->dump.dump_timeout,
> +                                     msecs_to_jiffies(5000));
> +               fallthrough;
> +       case BTMTK_COREDUMP_ACTIVE:
> +       default:
> +               err = hci_devcd_append(hdev, skb);
> +               if (err < 0)
> +                       break;
> +
> +               if (skb->len > 12 &&
> +                   !strncmp((char *)&skb->data[skb->len - 13],
> +                            MTK_COREDUMP_END, 12))
> +                       hci_devcd_complete(hdev);
> +
> +               break;
> +       }
> +
> +       if (err < 0) {
> +               data->cd_info.state = BTMTK_COREDUMP_DISABLED;
> +               kfree_skb(skb);
> +       }
> +
> +       return err;
> +}
> +EXPORT_SYMBOL_GPL(btmtk_process_coredump);
> +
>  MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
>  MODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>");
>  MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION);
> diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
> index 6245662f6ccb..7eb162f0e7aa 100644
> --- a/drivers/bluetooth/btmtk.h
> +++ b/drivers/bluetooth/btmtk.h
> @@ -21,6 +21,10 @@
>  #define MT7921_DLSTATUS 0x7c053c10
>  #define BT_DL_STATE BIT(1)
>
> +#define MTK_DRIVER_NAME_LEN            16
> +#define MTK_COREDUMP_SIZE              (1024 * 1000)
> +#define MTK_COREDUMP_END               "coredump end"
> +
>  enum {
>         BTMTK_WMT_PATCH_DWNLD = 0x1,
>         BTMTK_WMT_TEST = 0x2,
> @@ -119,12 +123,20 @@ struct btmtk_hci_wmt_params {
>         u32 *status;
>  };
>
> +struct btmtk_coredump_info {
> +       char driver_name[MTK_DRIVER_NAME_LEN];
> +       u32 dev_id;
> +       u32 fw_version;
> +       int state;
> +};
> +
>  typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,
>                                    struct btmtk_hci_wmt_params *);
>
>  typedef int (*btmtk_reset_sync_func_t)(struct hci_dev *, void *);
>
>  struct btmtk_data {
> +       struct btmtk_coredump_info cd_info;
>         btmtk_reset_sync_func_t reset_sync;
>  };
>
> @@ -139,6 +151,11 @@ int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
>                          wmt_cmd_sync_func_t wmt_cmd_sync);
>
>  void btmtk_reset_sync(struct hci_dev *hdev);
> +
> +int btmtk_register_coredump(struct hci_dev *hdev, u32 dev_id, const char *name,
> +                            u32 fw_version);
> +
> +int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb);
>  #else
>
>  static inline int btmtk_set_bdaddr(struct hci_dev *hdev,
> @@ -162,4 +179,15 @@ static int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
>  static void btmtk_reset_sync(struct hci_dev *hdev)
>  {
>  }
> +
> +static int btmtk_register_coredump(struct hci_dev *hdev, u32 dev_id, const char *name,
> +                            u32 fw_version)
> +{
> +       return -EOPNOTSUPP;
> +}
> +
> +static int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> +       return -EOPNOTSUPP;
> +}
>  #endif
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 034edd8ad777..1c2a0cbcf62e 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -3035,6 +3035,10 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
>         }
>
>         btmtk_data->reset_sync = btusb_mtk_reset_work;
> +       err = btmtk_register_coredump(hdev, dev_id, btusb_driver.name,
> +                               fw_version);
> +       if (err < 0)
> +               bt_dev_err(hdev, "Failed to register coredump (%d)", err);
>
>         switch (dev_id) {
>         case 0x7663:
> @@ -3189,6 +3193,7 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
>  {
>         struct btusb_data *data = hci_get_drvdata(hdev);
>         u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle);
> +       struct sk_buff *skb_cd;
>
>         switch (handle) {
>         case 0xfc6f:            /* Firmware dump from device */
> @@ -3196,6 +3201,15 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
>                  * suspend and thus disable auto-suspend.
>                  */
>                 usb_disable_autosuspend(data->udev);
> +
> +               /* We need to forward the diagnostic packet to userspace daemon
> +                * for backward compatibility, so we have to clone the packet
> +                * extraly for the in-kernel coredump support.
> +                */
> +               skb_cd = skb_clone(skb, GFP_ATOMIC);
> +               if (skb_cd)
> +                       btmtk_process_coredump(hdev, skb_cd);
> +
>                 fallthrough;
>         case 0x05ff:            /* Firmware debug logging 1 */
>         case 0x05fe:            /* Firmware debug logging 2 */
> --
> 2.25.1
>
diff mbox series

Patch

diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index ac2fac7e3c5f..657792f9dcab 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -19,6 +19,12 @@ 
 #define MTK_SEC_MAP_COMMON_SIZE	12
 #define MTK_SEC_MAP_NEED_SEND_SIZE	52
 
+enum {
+	BTMTK_COREDUMP_INIT,
+	BTMTK_COREDUMP_DISABLED,
+	BTMTK_COREDUMP_ACTIVE,
+};
+
 struct btmtk_patch_header {
 	u8 datetime[16];
 	u8 platform[4];
@@ -53,6 +59,56 @@  struct btmtk_section_map {
 	};
 } __packed;
 
+static void btmtk_coredump(struct hci_dev *hdev)
+{
+	int err;
+
+	err = __hci_cmd_send(hdev, 0xfd5b, 0, NULL);
+	if (err < 0)
+		bt_dev_err(hdev, "Coredump failed (%d)", err);
+}
+
+static void btmtk_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct btmtk_data *data = hci_get_priv(hdev);
+	char buf[80];
+
+	snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n",
+		 data->cd_info.dev_id);
+	skb_put_data(skb, buf, strlen(buf));
+
+	snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n",
+		 data->cd_info.fw_version);
+	skb_put_data(skb, buf, strlen(buf));
+
+	snprintf(buf, sizeof(buf), "Driver: %s\n",
+		 data->cd_info.driver_name);
+	skb_put_data(skb, buf, strlen(buf));
+
+	snprintf(buf, sizeof(buf), "Vendor: MediaTek\n");
+	skb_put_data(skb, buf, strlen(buf));
+}
+
+static void btmtk_coredump_notify(struct hci_dev *hdev, int state)
+{
+	struct btmtk_data *data = hci_get_priv(hdev);
+
+	switch (state) {
+	case HCI_DEVCOREDUMP_IDLE:
+		data->cd_info.state = BTMTK_COREDUMP_INIT;
+		break;
+	case HCI_DEVCOREDUMP_ACTIVE:
+		data->cd_info.state = BTMTK_COREDUMP_ACTIVE;
+		break;
+	case HCI_DEVCOREDUMP_TIMEOUT:
+	case HCI_DEVCOREDUMP_ABORT:
+	case HCI_DEVCOREDUMP_DONE:
+		data->cd_info.state = BTMTK_COREDUMP_INIT;
+		btmtk_reset_sync(hdev);
+		break;
+	}
+}
+
 int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
 			      wmt_cmd_sync_func_t wmt_cmd_sync)
 {
@@ -295,6 +351,67 @@  void btmtk_reset_sync(struct hci_dev *hdev)
 }
 EXPORT_SYMBOL_GPL(btmtk_reset_sync);
 
+int btmtk_register_coredump(struct hci_dev *hdev, u32 dev_id,
+			     const char *name, u32 fw_version)
+{
+	struct btmtk_data *data = hci_get_priv(hdev);
+
+	if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
+		return -EOPNOTSUPP;
+
+	data->cd_info.dev_id = dev_id;
+	data->cd_info.fw_version = fw_version;
+	data->cd_info.state = BTMTK_COREDUMP_INIT;
+	strncpy(data->cd_info.driver_name, name, MTK_DRIVER_NAME_LEN - 1);
+
+	return hci_devcd_register(hdev, btmtk_coredump, btmtk_coredump_hdr,
+				  btmtk_coredump_notify);
+}
+EXPORT_SYMBOL_GPL(btmtk_register_coredump);
+
+int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct btmtk_data *data = hci_get_priv(hdev);
+	int err;
+
+	if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
+		return 0;
+
+	switch (data->cd_info.state) {
+	case BTMTK_COREDUMP_DISABLED:
+		err = -EINVAL;
+		break;
+	case BTMTK_COREDUMP_INIT:
+		err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE);
+		if (err < 0)
+			break;
+		/* It is supposed coredump can be done within 5 seconds */
+		schedule_delayed_work(&hdev->dump.dump_timeout,
+				      msecs_to_jiffies(5000));
+		fallthrough;
+	case BTMTK_COREDUMP_ACTIVE:
+	default:
+		err = hci_devcd_append(hdev, skb);
+		if (err < 0)
+			break;
+
+		if (skb->len > 12 &&
+		    !strncmp((char *)&skb->data[skb->len - 13],
+			     MTK_COREDUMP_END, 12))
+			hci_devcd_complete(hdev);
+
+		break;
+	}
+
+	if (err < 0) {
+		data->cd_info.state = BTMTK_COREDUMP_DISABLED;
+		kfree_skb(skb);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(btmtk_process_coredump);
+
 MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
 MODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>");
 MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION);
diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
index 6245662f6ccb..7eb162f0e7aa 100644
--- a/drivers/bluetooth/btmtk.h
+++ b/drivers/bluetooth/btmtk.h
@@ -21,6 +21,10 @@ 
 #define MT7921_DLSTATUS 0x7c053c10
 #define BT_DL_STATE BIT(1)
 
+#define MTK_DRIVER_NAME_LEN		16
+#define MTK_COREDUMP_SIZE		(1024 * 1000)
+#define MTK_COREDUMP_END		"coredump end"
+
 enum {
 	BTMTK_WMT_PATCH_DWNLD = 0x1,
 	BTMTK_WMT_TEST = 0x2,
@@ -119,12 +123,20 @@  struct btmtk_hci_wmt_params {
 	u32 *status;
 };
 
+struct btmtk_coredump_info {
+	char driver_name[MTK_DRIVER_NAME_LEN];
+	u32 dev_id;
+	u32 fw_version;
+	int state;
+};
+
 typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,
 				   struct btmtk_hci_wmt_params *);
 
 typedef int (*btmtk_reset_sync_func_t)(struct hci_dev *, void *);
 
 struct btmtk_data {
+	struct btmtk_coredump_info cd_info;
 	btmtk_reset_sync_func_t reset_sync;
 };
 
@@ -139,6 +151,11 @@  int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
 			 wmt_cmd_sync_func_t wmt_cmd_sync);
 
 void btmtk_reset_sync(struct hci_dev *hdev);
+
+int btmtk_register_coredump(struct hci_dev *hdev, u32 dev_id, const char *name,
+			     u32 fw_version);
+
+int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb);
 #else
 
 static inline int btmtk_set_bdaddr(struct hci_dev *hdev,
@@ -162,4 +179,15 @@  static int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
 static void btmtk_reset_sync(struct hci_dev *hdev)
 {
 }
+
+static int btmtk_register_coredump(struct hci_dev *hdev, u32 dev_id, const char *name,
+			     u32 fw_version)
+{
+	return -EOPNOTSUPP;
+}
+
+static int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	return -EOPNOTSUPP;
+}
 #endif
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 034edd8ad777..1c2a0cbcf62e 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -3035,6 +3035,10 @@  static int btusb_mtk_setup(struct hci_dev *hdev)
 	}
 
 	btmtk_data->reset_sync = btusb_mtk_reset_work;
+	err = btmtk_register_coredump(hdev, dev_id, btusb_driver.name,
+				fw_version);
+	if (err < 0)
+		bt_dev_err(hdev, "Failed to register coredump (%d)", err);
 
 	switch (dev_id) {
 	case 0x7663:
@@ -3189,6 +3193,7 @@  static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct btusb_data *data = hci_get_drvdata(hdev);
 	u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle);
+	struct sk_buff *skb_cd;
 
 	switch (handle) {
 	case 0xfc6f:		/* Firmware dump from device */
@@ -3196,6 +3201,15 @@  static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
 		 * suspend and thus disable auto-suspend.
 		 */
 		usb_disable_autosuspend(data->udev);
+
+		/* We need to forward the diagnostic packet to userspace daemon
+		 * for backward compatibility, so we have to clone the packet
+		 * extraly for the in-kernel coredump support.
+		 */
+		skb_cd = skb_clone(skb, GFP_ATOMIC);
+		if (skb_cd)
+			btmtk_process_coredump(hdev, skb_cd);
+
 		fallthrough;
 	case 0x05ff:		/* Firmware debug logging 1 */
 	case 0x05fe:		/* Firmware debug logging 2 */