diff mbox series

[v3] Bluetooth: btrtl: Add Realtek devcoredump support

Message ID 20230420105343.2014-1-hildawu@realtek.com (mailing list archive)
State Superseded
Headers show
Series [v3] Bluetooth: btrtl: Add Realtek devcoredump support | 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/BuildKernel success BuildKernel PASS
tedd_an/CheckAllWarning success CheckAllWarning PASS
tedd_an/CheckSparse success CheckSparse PASS
tedd_an/CheckSmatch success CheckSparse PASS
tedd_an/BuildKernel32 success BuildKernel32 PASS
tedd_an/TestRunnerSetup success TestRunnerSetup PASS
tedd_an/TestRunner_l2cap-tester success TestRunner PASS
tedd_an/TestRunner_iso-tester success TestRunner PASS
tedd_an/TestRunner_bnep-tester success TestRunner PASS
tedd_an/TestRunner_mgmt-tester success TestRunner PASS
tedd_an/TestRunner_rfcomm-tester success TestRunner PASS
tedd_an/TestRunner_sco-tester success TestRunner PASS
tedd_an/TestRunner_ioctl-tester success TestRunner PASS
tedd_an/TestRunner_mesh-tester success TestRunner PASS
tedd_an/TestRunner_smp-tester success TestRunner PASS
tedd_an/TestRunner_userchan-tester success TestRunner PASS
tedd_an/IncrementalBuild success Incremental Build PASS

Commit Message

Hilda Wu April 20, 2023, 10:53 a.m. UTC
From: Hilda Wu <hildawu@realtek.com>

Catch debug exception from controller and driver, and trigger a
devcoredump using hci devcoredump APIs. The debug exception data
will be parsed in userspace.

Signed-off-by: Alex Lu <alex_lu@realsil.com.cn>
Signed-off-by: Hilda Wu <hildawu@realtek.com>
---
Changes in v3:
 - Rebase, fixed merge confilt

Changes in v2:
 - According to devcoredump API revision, modified related part.
---
---
 drivers/bluetooth/btrtl.c | 145 +++++++++++++++++++++++++++++++-------
 drivers/bluetooth/btrtl.h |   6 ++
 drivers/bluetooth/btusb.c |  74 +++++++++++++++++++
 3 files changed, 198 insertions(+), 27 deletions(-)

Comments

bluez.test.bot@gmail.com April 20, 2023, 11:31 a.m. UTC | #1
This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=741684

---Test result---

Test Summary:
CheckPatch                    PASS      1.31 seconds
GitLint                       PASS      0.35 seconds
SubjectPrefix                 PASS      0.13 seconds
BuildKernel                   PASS      31.91 seconds
CheckAllWarning               PASS      34.92 seconds
CheckSparse                   PASS      39.98 seconds
CheckSmatch                   PASS      109.99 seconds
BuildKernel32                 PASS      31.62 seconds
TestRunnerSetup               PASS      444.88 seconds
TestRunner_l2cap-tester       PASS      17.21 seconds
TestRunner_iso-tester         PASS      21.05 seconds
TestRunner_bnep-tester        PASS      5.58 seconds
TestRunner_mgmt-tester        PASS      114.73 seconds
TestRunner_rfcomm-tester      PASS      8.97 seconds
TestRunner_sco-tester         PASS      8.28 seconds
TestRunner_ioctl-tester       PASS      9.62 seconds
TestRunner_mesh-tester        PASS      7.01 seconds
TestRunner_smp-tester         PASS      8.20 seconds
TestRunner_userchan-tester    PASS      5.83 seconds
IncrementalBuild              PASS      29.36 seconds



---
Regards,
Linux Bluetooth
Luiz Augusto von Dentz April 20, 2023, 11:12 p.m. UTC | #2
Hi,

On Thu, Apr 20, 2023 at 3:53 AM <hildawu@realtek.com> wrote:
>
> From: Hilda Wu <hildawu@realtek.com>
>
> Catch debug exception from controller and driver, and trigger a
> devcoredump using hci devcoredump APIs. The debug exception data
> will be parsed in userspace.
>
> Signed-off-by: Alex Lu <alex_lu@realsil.com.cn>
> Signed-off-by: Hilda Wu <hildawu@realtek.com>
> ---
> Changes in v3:
>  - Rebase, fixed merge confilt
>
> Changes in v2:
>  - According to devcoredump API revision, modified related part.
> ---
> ---
>  drivers/bluetooth/btrtl.c | 145 +++++++++++++++++++++++++++++++-------
>  drivers/bluetooth/btrtl.h |   6 ++
>  drivers/bluetooth/btusb.c |  74 +++++++++++++++++++
>  3 files changed, 198 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
> index 2915c82d719d..ffb94d6481e2 100644
> --- a/drivers/bluetooth/btrtl.c
> +++ b/drivers/bluetooth/btrtl.c
> @@ -32,6 +32,8 @@
>  #define RTL_ROM_LMP_8851B      0x8851
>  #define RTL_CONFIG_MAGIC       0x8723ab55
>
> +#define RTL_VSC_OP_COREDUMP    0xfcff
> +
>  #define IC_MATCH_FL_LMPSUBV    (1 << 0)
>  #define IC_MATCH_FL_HCIREV     (1 << 1)
>  #define IC_MATCH_FL_HCIVER     (1 << 2)
> @@ -81,6 +83,7 @@ struct id_table {
>         bool has_msft_ext;
>         char *fw_name;
>         char *cfg_name;
> +       char *hw_info;
>  };
>
>  struct btrtl_device_info {
> @@ -102,21 +105,24 @@ static const struct id_table ic_id_table[] = {
>           .config_needed = false,
>           .has_rom_version = false,
>           .fw_name = "rtl_bt/rtl8723a_fw.bin",
> -         .cfg_name = NULL },
> +         .cfg_name = NULL,
> +         .hw_info = "rtl8723au" },
>
>         /* 8723BS */
>         { IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_UART),
>           .config_needed = true,
>           .has_rom_version = true,
>           .fw_name  = "rtl_bt/rtl8723bs_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8723bs_config" },
> +         .cfg_name = "rtl_bt/rtl8723bs_config",
> +         .hw_info  = "rtl8723bs" },
>
>         /* 8723B */
>         { IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_USB),
>           .config_needed = false,
>           .has_rom_version = true,
>           .fw_name  = "rtl_bt/rtl8723b_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8723b_config" },
> +         .cfg_name = "rtl_bt/rtl8723b_config",
> +         .hw_info  = "rtl8723bu" },
>
>         /* 8723CS-CG */
>         { .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
> @@ -127,7 +133,8 @@ static const struct id_table ic_id_table[] = {
>           .config_needed = true,
>           .has_rom_version = true,
>           .fw_name  = "rtl_bt/rtl8723cs_cg_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8723cs_cg_config" },
> +         .cfg_name = "rtl_bt/rtl8723cs_cg_config",
> +         .hw_info  = "rtl8723cs-cg" },
>
>         /* 8723CS-VF */
>         { .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
> @@ -138,7 +145,8 @@ static const struct id_table ic_id_table[] = {
>           .config_needed = true,
>           .has_rom_version = true,
>           .fw_name  = "rtl_bt/rtl8723cs_vf_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8723cs_vf_config" },
> +         .cfg_name = "rtl_bt/rtl8723cs_vf_config",
> +         .hw_info  = "rtl8723cs-vf" },
>
>         /* 8723CS-XX */
>         { .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
> @@ -149,28 +157,32 @@ static const struct id_table ic_id_table[] = {
>           .config_needed = true,
>           .has_rom_version = true,
>           .fw_name  = "rtl_bt/rtl8723cs_xx_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8723cs_xx_config" },
> +         .cfg_name = "rtl_bt/rtl8723cs_xx_config",
> +         .hw_info  = "rtl8723cs" },
>
>         /* 8723D */
>         { IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_USB),
>           .config_needed = true,
>           .has_rom_version = true,
>           .fw_name  = "rtl_bt/rtl8723d_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8723d_config" },
> +         .cfg_name = "rtl_bt/rtl8723d_config",
> +         .hw_info  = "rtl8723du" },
>
>         /* 8723DS */
>         { IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_UART),
>           .config_needed = true,
>           .has_rom_version = true,
>           .fw_name  = "rtl_bt/rtl8723ds_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8723ds_config" },
> +         .cfg_name = "rtl_bt/rtl8723ds_config",
> +         .hw_info  = "rtl8723ds" },
>
>         /* 8821A */
>         { IC_INFO(RTL_ROM_LMP_8821A, 0xa, 0x6, HCI_USB),
>           .config_needed = false,
>           .has_rom_version = true,
>           .fw_name  = "rtl_bt/rtl8821a_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8821a_config" },
> +         .cfg_name = "rtl_bt/rtl8821a_config",
> +         .hw_info  = "rtl8821au" },
>
>         /* 8821C */
>         { IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_USB),
> @@ -178,7 +190,8 @@ static const struct id_table ic_id_table[] = {
>           .has_rom_version = true,
>           .has_msft_ext = true,
>           .fw_name  = "rtl_bt/rtl8821c_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8821c_config" },
> +         .cfg_name = "rtl_bt/rtl8821c_config",
> +         .hw_info  = "rtl8821cu" },
>
>         /* 8821CS */
>         { IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_UART),
> @@ -186,14 +199,16 @@ static const struct id_table ic_id_table[] = {
>           .has_rom_version = true,
>           .has_msft_ext = true,
>           .fw_name  = "rtl_bt/rtl8821cs_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8821cs_config" },
> +         .cfg_name = "rtl_bt/rtl8821cs_config",
> +         .hw_info  = "rtl8821cs" },
>
>         /* 8761A */
>         { IC_INFO(RTL_ROM_LMP_8761A, 0xa, 0x6, HCI_USB),
>           .config_needed = false,
>           .has_rom_version = true,
>           .fw_name  = "rtl_bt/rtl8761a_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8761a_config" },
> +         .cfg_name = "rtl_bt/rtl8761a_config",
> +         .hw_info  = "rtl8761au" },
>
>         /* 8761B */
>         { IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_UART),
> @@ -201,14 +216,16 @@ static const struct id_table ic_id_table[] = {
>           .has_rom_version = true,
>           .has_msft_ext = true,
>           .fw_name  = "rtl_bt/rtl8761b_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8761b_config" },
> +         .cfg_name = "rtl_bt/rtl8761b_config",
> +         .hw_info  = "rtl8761btv" },
>
>         /* 8761BU */
>         { IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_USB),
>           .config_needed = false,
>           .has_rom_version = true,
>           .fw_name  = "rtl_bt/rtl8761bu_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8761bu_config" },
> +         .cfg_name = "rtl_bt/rtl8761bu_config",
> +         .hw_info  = "rtl8761bu" },
>
>         /* 8822C with UART interface */
>         { IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0x8, HCI_UART),
> @@ -216,7 +233,8 @@ static const struct id_table ic_id_table[] = {
>           .has_rom_version = true,
>           .has_msft_ext = true,
>           .fw_name  = "rtl_bt/rtl8822cs_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8822cs_config" },
> +         .cfg_name = "rtl_bt/rtl8822cs_config",
> +         .hw_info  = "rtl8822cs" },
>
>         /* 8822C with UART interface */
>         { IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_UART),
> @@ -224,7 +242,8 @@ static const struct id_table ic_id_table[] = {
>           .has_rom_version = true,
>           .has_msft_ext = true,
>           .fw_name  = "rtl_bt/rtl8822cs_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8822cs_config" },
> +         .cfg_name = "rtl_bt/rtl8822cs_config",
> +         .hw_info  = "rtl8822cs" },
>
>         /* 8822C with USB interface */
>         { IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_USB),
> @@ -232,7 +251,8 @@ static const struct id_table ic_id_table[] = {
>           .has_rom_version = true,
>           .has_msft_ext = true,
>           .fw_name  = "rtl_bt/rtl8822cu_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8822cu_config" },
> +         .cfg_name = "rtl_bt/rtl8822cu_config",
> +         .hw_info  = "rtl8822cu" },
>
>         /* 8822B */
>         { IC_INFO(RTL_ROM_LMP_8822B, 0xb, 0x7, HCI_USB),
> @@ -240,7 +260,8 @@ static const struct id_table ic_id_table[] = {
>           .has_rom_version = true,
>           .has_msft_ext = true,
>           .fw_name  = "rtl_bt/rtl8822b_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8822b_config" },
> +         .cfg_name = "rtl_bt/rtl8822b_config",
> +         .hw_info  = "rtl8822bu" },
>
>         /* 8852A */
>         { IC_INFO(RTL_ROM_LMP_8852A, 0xa, 0xb, HCI_USB),
> @@ -248,7 +269,8 @@ static const struct id_table ic_id_table[] = {
>           .has_rom_version = true,
>           .has_msft_ext = true,
>           .fw_name  = "rtl_bt/rtl8852au_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8852au_config" },
> +         .cfg_name = "rtl_bt/rtl8852au_config",
> +         .hw_info  = "rtl8852au" },
>
>         /* 8852B with UART interface */
>         { IC_INFO(RTL_ROM_LMP_8852A, 0xb, 0xb, HCI_UART),
> @@ -256,7 +278,8 @@ static const struct id_table ic_id_table[] = {
>           .has_rom_version = true,
>           .has_msft_ext = true,
>           .fw_name  = "rtl_bt/rtl8852bs_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8852bs_config" },
> +         .cfg_name = "rtl_bt/rtl8852bs_config",
> +         .hw_info  = "rtl8852bs" },
>
>         /* 8852B */
>         { IC_INFO(RTL_ROM_LMP_8852A, 0xb, 0xb, HCI_USB),
> @@ -264,7 +287,8 @@ static const struct id_table ic_id_table[] = {
>           .has_rom_version = true,
>           .has_msft_ext = true,
>           .fw_name  = "rtl_bt/rtl8852bu_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8852bu_config" },
> +         .cfg_name = "rtl_bt/rtl8852bu_config",
> +         .hw_info  = "rtl8852bu" },
>
>         /* 8852C */
>         { IC_INFO(RTL_ROM_LMP_8852A, 0xc, 0xc, HCI_USB),
> @@ -272,7 +296,8 @@ static const struct id_table ic_id_table[] = {
>           .has_rom_version = true,
>           .has_msft_ext = true,
>           .fw_name  = "rtl_bt/rtl8852cu_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8852cu_config" },
> +         .cfg_name = "rtl_bt/rtl8852cu_config",
> +         .hw_info  = "rtl8852cu" },
>
>         /* 8851B */
>         { IC_INFO(RTL_ROM_LMP_8851B, 0xb, 0xc, HCI_USB),
> @@ -280,9 +305,16 @@ static const struct id_table ic_id_table[] = {
>           .has_rom_version = true,
>           .has_msft_ext = false,
>           .fw_name  = "rtl_bt/rtl8851bu_fw.bin",
> -         .cfg_name = "rtl_bt/rtl8851bu_config" },
> +         .cfg_name = "rtl_bt/rtl8851bu_config",
> +         .hw_info  = "rtl8851bu" },
>         };
>
> +static struct {
> +       const char *driver_name;
> +       char *controller;
> +       u32  fw_version;
> +} coredump_info;
> +
>  static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
>                                              u8 hci_ver, u8 hci_bus,
>                                              u8 chip_type)
> @@ -707,6 +739,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
>         num_patches = le16_to_cpu(epatch_info->num_patches);
>         BT_DBG("fw_version=%x, num_patches=%d",
>                le32_to_cpu(epatch_info->fw_version), num_patches);
> +       coredump_info.fw_version = le32_to_cpu(epatch_info->fw_version);
>
>         /* After the rtl_epatch_header there is a funky patch metadata section.
>          * Assuming 2 patches, the layout is:
> @@ -903,6 +936,50 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev,
>         return ret;
>  }
>
> +static void btrtl_coredump(struct hci_dev *hdev)
> +{
> +       static const u8 param[] = { 0x00, 0x00 };
> +
> +       __hci_cmd_send(hdev, RTL_VSC_OP_COREDUMP, sizeof(param), param);
> +}
> +
> +static void btrtl_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> +       char buf[80];
> +
> +       if (coredump_info.controller)
> +               snprintf(buf, sizeof(buf), "Controller Name: %s\n",
> +                        coredump_info.controller);
> +       else
> +               snprintf(buf, sizeof(buf), "Controller Name: Unknown\n");
> +       skb_put_data(skb, buf, strlen(buf));
> +
> +       snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n",
> +                coredump_info.fw_version);
> +       skb_put_data(skb, buf, strlen(buf));
> +
> +       snprintf(buf, sizeof(buf), "Driver: %s\n", coredump_info.driver_name);
> +       skb_put_data(skb, buf, strlen(buf));
> +
> +       snprintf(buf, sizeof(buf), "Vendor: Realtek\n");
> +       skb_put_data(skb, buf, strlen(buf));
> +}
> +
> +static int btrtl_register_devcoredump_support(struct hci_dev *hdev)
> +{
> +       int err;
> +
> +       err = hci_devcd_register(hdev, btrtl_coredump, btrtl_dmp_hdr, NULL);
> +
> +       return err;
> +}
> +
> +void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name)
> +{
> +       coredump_info.driver_name = driver_name;
> +}
> +EXPORT_SYMBOL_GPL(btrtl_set_driver_name);

If there are multiple drivers calling the above they will likely
overwrite driver_name.

> +
>  static bool rtl_has_chip_type(u16 lmp_subver)
>  {
>         switch (lmp_subver) {
> @@ -1113,6 +1190,9 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
>         if (btrtl_dev->ic_info->has_msft_ext)
>                 hci_set_msft_opcode(hdev, 0xFCF0);
>
> +       if (btrtl_dev->ic_info)
> +               coredump_info.controller = btrtl_dev->ic_info->hw_info;

Ditto, coredump_info needs to be stored on a per hdev basis, probably
inside btrtl_device_info.

> +
>         return btrtl_dev;
>
>  err_free:
> @@ -1125,6 +1205,8 @@ EXPORT_SYMBOL_GPL(btrtl_initialize);
>  int btrtl_download_firmware(struct hci_dev *hdev,
>                             struct btrtl_device_info *btrtl_dev)
>  {
> +       int err = 0;
> +
>         /* Match a set of subver values that correspond to stock firmware,
>          * which is not compatible with standard btusb.
>          * If matched, upload an alternative firmware that does conform to
> @@ -1133,12 +1215,14 @@ int btrtl_download_firmware(struct hci_dev *hdev,
>          */
>         if (!btrtl_dev->ic_info) {
>                 rtl_dev_info(hdev, "assuming no firmware upload needed");
> -               return 0;
> +               err = 0;
> +               goto done;
>         }
>
>         switch (btrtl_dev->ic_info->lmp_subver) {
>         case RTL_ROM_LMP_8723A:
> -               return btrtl_setup_rtl8723a(hdev, btrtl_dev);
> +               err = btrtl_setup_rtl8723a(hdev, btrtl_dev);
> +               break;
>         case RTL_ROM_LMP_8723B:
>         case RTL_ROM_LMP_8821A:
>         case RTL_ROM_LMP_8761A:
> @@ -1146,11 +1230,18 @@ int btrtl_download_firmware(struct hci_dev *hdev,
>         case RTL_ROM_LMP_8852A:
>         case RTL_ROM_LMP_8703B:
>         case RTL_ROM_LMP_8851B:
> -               return btrtl_setup_rtl8723b(hdev, btrtl_dev);
> +               err = btrtl_setup_rtl8723b(hdev, btrtl_dev);
> +               break;
>         default:
>                 rtl_dev_info(hdev, "assuming no firmware upload needed");
> -               return 0;
> +               break;
>         }
> +
> +done:
> +       if (!err)
> +               err = btrtl_register_devcoredump_support(hdev);
> +
> +       return err;
>  }
>  EXPORT_SYMBOL_GPL(btrtl_download_firmware);
>
> diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h
> index adb4c2c9abc5..fe2888c2d175 100644
> --- a/drivers/bluetooth/btrtl.h
> +++ b/drivers/bluetooth/btrtl.h
> @@ -139,6 +139,7 @@ int btrtl_get_uart_settings(struct hci_dev *hdev,
>                             struct btrtl_device_info *btrtl_dev,
>                             unsigned int *controller_baudrate,
>                             u32 *device_baudrate, bool *flow_control);
> +void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name);
>
>  #else
>
> @@ -182,4 +183,9 @@ static inline int btrtl_get_uart_settings(struct hci_dev *hdev,
>         return -ENOENT;
>  }
>
> +static inline void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name)
> +{
> +       return -EOPNOTSUPP;
> +}
> +
>  #endif
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 3aa189b1986d..5fa90347a4e1 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -869,10 +869,49 @@ static void btusb_intel_cmd_timeout(struct hci_dev *hdev)
>         gpiod_set_value_cansleep(reset_gpio, 0);
>  }
>
> +#define RTK_DEVCOREDUMP_CODE_MEMDUMP           0x01
> +#define RTK_DEVCOREDUMP_CODE_HW_ERR            0x02
> +#define RTK_DEVCOREDUMP_CODE_CMD_TIMEOUT       0x03
> +
> +#define RTK_SUB_EVENT_CODE_COREDUMP            0x34
> +
> +struct rtk_dev_coredump_hdr {
> +       u8 type;
> +       u8 code;
> +       u8 reserved[2];
> +} __packed;
> +
> +static inline void btusb_rtl_alloc_devcoredump(struct hci_dev *hdev,
> +               struct rtk_dev_coredump_hdr *hdr, u8 *buf, u32 len)
> +{
> +       struct sk_buff *skb;
> +
> +       skb = alloc_skb(len + sizeof(*hdr), GFP_ATOMIC);
> +       if (!skb)
> +               return;
> +
> +       skb_put_data(skb, hdr, sizeof(*hdr));
> +       if (len)
> +               skb_put_data(skb, buf, len);
> +
> +       if (!hci_devcd_init(hdev, skb->len)) {
> +               hci_devcd_append(hdev, skb);
> +               hci_devcd_complete(hdev);
> +       } else {
> +               bt_dev_err(hdev, "RTL: Failed to generate devcoredump");
> +               kfree_skb(skb);
> +       }
> +}
> +
>  static void btusb_rtl_cmd_timeout(struct hci_dev *hdev)
>  {
>         struct btusb_data *data = hci_get_drvdata(hdev);
>         struct gpio_desc *reset_gpio = data->reset_gpio;
> +       struct rtk_dev_coredump_hdr hdr = {
> +               .type = RTK_DEVCOREDUMP_CODE_CMD_TIMEOUT,
> +       };
> +
> +       btusb_rtl_alloc_devcoredump(hdev, &hdr, NULL, 0);
>
>         if (++data->cmd_timeout_cnt < 5)
>                 return;
> @@ -899,6 +938,18 @@ static void btusb_rtl_cmd_timeout(struct hci_dev *hdev)
>         gpiod_set_value_cansleep(reset_gpio, 0);
>  }
>
> +static void btusb_rtl_hw_error(struct hci_dev *hdev, u8 code)
> +{
> +       struct rtk_dev_coredump_hdr hdr = {
> +               .type = RTK_DEVCOREDUMP_CODE_HW_ERR,
> +               .code = code,
> +       };
> +
> +       bt_dev_info(hdev, "RTL: hw err, trigger devcoredump");

This probably should be printed as an error with bt_dev_err and print
the code as well.

> +       btusb_rtl_alloc_devcoredump(hdev, &hdr, NULL, 0);
> +}
> +
>  static void btusb_qca_cmd_timeout(struct hci_dev *hdev)
>  {
>         struct btusb_data *data = hci_get_drvdata(hdev);
> @@ -2539,6 +2590,25 @@ static int btusb_setup_realtek(struct hci_dev *hdev)
>         return ret;
>  }
>
> +static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> +       if (skb->data[0] == HCI_VENDOR_PKT && skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
> +               struct rtk_dev_coredump_hdr hdr = {
> +                       .code = RTK_DEVCOREDUMP_CODE_MEMDUMP,
> +               };
> +
> +               bt_dev_info(hdev, "RTL: received coredump vendor evt, len %u",
> +                       skb->len);

The above should probably be using bt_dev_dbg instead bt_dev_info.

> +               btusb_rtl_alloc_devcoredump(hdev, &hdr, skb->data, skb->len);
> +               kfree_skb(skb);
> +
> +               return 0;
> +       }
> +
> +       return hci_recv_frame(hdev, skb);
> +}
> +
>  /* UHW CR mapping */
>  #define MTK_BT_MISC            0x70002510
>  #define MTK_BT_SUBSYS_RST      0x70002610
> @@ -3978,6 +4048,8 @@ static int btusb_probe(struct usb_interface *intf,
>         } else if (id->driver_info & BTUSB_REALTEK) {
>                 /* Allocate extra space for Realtek device */
>                 priv_size += sizeof(struct btrealtek_data);
> +
> +               data->recv_event = btusb_recv_event_realtek;
>         }
>
>         data->recv_acl = hci_recv_frame;
> @@ -4136,9 +4208,11 @@ static int btusb_probe(struct usb_interface *intf,
>
>         if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) &&
>             (id->driver_info & BTUSB_REALTEK)) {
> +               btrtl_set_driver_name(hdev, btusb_driver.name);
>                 hdev->setup = btusb_setup_realtek;
>                 hdev->shutdown = btrtl_shutdown_realtek;
>                 hdev->cmd_timeout = btusb_rtl_cmd_timeout;
> +               hdev->hw_error = btusb_rtl_hw_error;
>
>                 /* Realtek devices need to set remote wakeup on auto-suspend */
>                 set_bit(BTUSB_WAKEUP_AUTOSUSPEND, &data->flags);
> --
> 2.17.1
>
kernel test robot April 25, 2023, 9:02 p.m. UTC | #3
Hi,

kernel test robot noticed the following build errors:

[auto build test ERROR on bluetooth-next/master]
[also build test ERROR on next-20230425]
[cannot apply to bluetooth/master linus/master v6.3]
[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/hildawu-realtek-com/Bluetooth-btrtl-Add-Realtek-devcoredump-support/20230420-185852
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
patch link:    https://lore.kernel.org/r/20230420105343.2014-1-hildawu%40realtek.com
patch subject: [PATCH v3] Bluetooth: btrtl: Add Realtek devcoredump support
config: arm-randconfig-r013-20230424 (https://download.01.org/0day-ci/archive/20230426/202304260422.XHBgACOW-lkp@intel.com/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project 437b7602e4a998220871de78afcb020b9c14a661)
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
        # install arm cross compiling tool for clang build
        # apt-get install binutils-arm-linux-gnueabi
        # https://github.com/intel-lab-lkp/linux/commit/dd7adb785f34ba9037f5c73dac879071302c636a
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review hildawu-realtek-com/Bluetooth-btrtl-Add-Realtek-devcoredump-support/20230420-185852
        git checkout dd7adb785f34ba9037f5c73dac879071302c636a
        # 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=arm olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash drivers/

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/202304260422.XHBgACOW-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from drivers/bluetooth/btusb.c:27:
>> drivers/bluetooth/btrtl.h:188:2: error: void function 'btrtl_set_driver_name' should not return a value [-Wreturn-type]
           return -EOPNOTSUPP;
           ^      ~~~~~~~~~~~
   1 error generated.


vim +/btrtl_set_driver_name +188 drivers/bluetooth/btrtl.h

   185	
   186	static inline void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name)
   187	{
 > 188		return -EOPNOTSUPP;
   189	}
   190
diff mbox series

Patch

diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
index 2915c82d719d..ffb94d6481e2 100644
--- a/drivers/bluetooth/btrtl.c
+++ b/drivers/bluetooth/btrtl.c
@@ -32,6 +32,8 @@ 
 #define RTL_ROM_LMP_8851B	0x8851
 #define RTL_CONFIG_MAGIC	0x8723ab55
 
+#define RTL_VSC_OP_COREDUMP	0xfcff
+
 #define IC_MATCH_FL_LMPSUBV	(1 << 0)
 #define IC_MATCH_FL_HCIREV	(1 << 1)
 #define IC_MATCH_FL_HCIVER	(1 << 2)
@@ -81,6 +83,7 @@  struct id_table {
 	bool has_msft_ext;
 	char *fw_name;
 	char *cfg_name;
+	char *hw_info;
 };
 
 struct btrtl_device_info {
@@ -102,21 +105,24 @@  static const struct id_table ic_id_table[] = {
 	  .config_needed = false,
 	  .has_rom_version = false,
 	  .fw_name = "rtl_bt/rtl8723a_fw.bin",
-	  .cfg_name = NULL },
+	  .cfg_name = NULL,
+	  .hw_info = "rtl8723au" },
 
 	/* 8723BS */
 	{ IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_UART),
 	  .config_needed = true,
 	  .has_rom_version = true,
 	  .fw_name  = "rtl_bt/rtl8723bs_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8723bs_config" },
+	  .cfg_name = "rtl_bt/rtl8723bs_config",
+	  .hw_info  = "rtl8723bs" },
 
 	/* 8723B */
 	{ IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_USB),
 	  .config_needed = false,
 	  .has_rom_version = true,
 	  .fw_name  = "rtl_bt/rtl8723b_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8723b_config" },
+	  .cfg_name = "rtl_bt/rtl8723b_config",
+	  .hw_info  = "rtl8723bu" },
 
 	/* 8723CS-CG */
 	{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
@@ -127,7 +133,8 @@  static const struct id_table ic_id_table[] = {
 	  .config_needed = true,
 	  .has_rom_version = true,
 	  .fw_name  = "rtl_bt/rtl8723cs_cg_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8723cs_cg_config" },
+	  .cfg_name = "rtl_bt/rtl8723cs_cg_config",
+	  .hw_info  = "rtl8723cs-cg" },
 
 	/* 8723CS-VF */
 	{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
@@ -138,7 +145,8 @@  static const struct id_table ic_id_table[] = {
 	  .config_needed = true,
 	  .has_rom_version = true,
 	  .fw_name  = "rtl_bt/rtl8723cs_vf_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8723cs_vf_config" },
+	  .cfg_name = "rtl_bt/rtl8723cs_vf_config",
+	  .hw_info  = "rtl8723cs-vf" },
 
 	/* 8723CS-XX */
 	{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
@@ -149,28 +157,32 @@  static const struct id_table ic_id_table[] = {
 	  .config_needed = true,
 	  .has_rom_version = true,
 	  .fw_name  = "rtl_bt/rtl8723cs_xx_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8723cs_xx_config" },
+	  .cfg_name = "rtl_bt/rtl8723cs_xx_config",
+	  .hw_info  = "rtl8723cs" },
 
 	/* 8723D */
 	{ IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_USB),
 	  .config_needed = true,
 	  .has_rom_version = true,
 	  .fw_name  = "rtl_bt/rtl8723d_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8723d_config" },
+	  .cfg_name = "rtl_bt/rtl8723d_config",
+	  .hw_info  = "rtl8723du" },
 
 	/* 8723DS */
 	{ IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_UART),
 	  .config_needed = true,
 	  .has_rom_version = true,
 	  .fw_name  = "rtl_bt/rtl8723ds_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8723ds_config" },
+	  .cfg_name = "rtl_bt/rtl8723ds_config",
+	  .hw_info  = "rtl8723ds" },
 
 	/* 8821A */
 	{ IC_INFO(RTL_ROM_LMP_8821A, 0xa, 0x6, HCI_USB),
 	  .config_needed = false,
 	  .has_rom_version = true,
 	  .fw_name  = "rtl_bt/rtl8821a_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8821a_config" },
+	  .cfg_name = "rtl_bt/rtl8821a_config",
+	  .hw_info  = "rtl8821au" },
 
 	/* 8821C */
 	{ IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_USB),
@@ -178,7 +190,8 @@  static const struct id_table ic_id_table[] = {
 	  .has_rom_version = true,
 	  .has_msft_ext = true,
 	  .fw_name  = "rtl_bt/rtl8821c_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8821c_config" },
+	  .cfg_name = "rtl_bt/rtl8821c_config",
+	  .hw_info  = "rtl8821cu" },
 
 	/* 8821CS */
 	{ IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_UART),
@@ -186,14 +199,16 @@  static const struct id_table ic_id_table[] = {
 	  .has_rom_version = true,
 	  .has_msft_ext = true,
 	  .fw_name  = "rtl_bt/rtl8821cs_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8821cs_config" },
+	  .cfg_name = "rtl_bt/rtl8821cs_config",
+	  .hw_info  = "rtl8821cs" },
 
 	/* 8761A */
 	{ IC_INFO(RTL_ROM_LMP_8761A, 0xa, 0x6, HCI_USB),
 	  .config_needed = false,
 	  .has_rom_version = true,
 	  .fw_name  = "rtl_bt/rtl8761a_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8761a_config" },
+	  .cfg_name = "rtl_bt/rtl8761a_config",
+	  .hw_info  = "rtl8761au" },
 
 	/* 8761B */
 	{ IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_UART),
@@ -201,14 +216,16 @@  static const struct id_table ic_id_table[] = {
 	  .has_rom_version = true,
 	  .has_msft_ext = true,
 	  .fw_name  = "rtl_bt/rtl8761b_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8761b_config" },
+	  .cfg_name = "rtl_bt/rtl8761b_config",
+	  .hw_info  = "rtl8761btv" },
 
 	/* 8761BU */
 	{ IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_USB),
 	  .config_needed = false,
 	  .has_rom_version = true,
 	  .fw_name  = "rtl_bt/rtl8761bu_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8761bu_config" },
+	  .cfg_name = "rtl_bt/rtl8761bu_config",
+	  .hw_info  = "rtl8761bu" },
 
 	/* 8822C with UART interface */
 	{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0x8, HCI_UART),
@@ -216,7 +233,8 @@  static const struct id_table ic_id_table[] = {
 	  .has_rom_version = true,
 	  .has_msft_ext = true,
 	  .fw_name  = "rtl_bt/rtl8822cs_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8822cs_config" },
+	  .cfg_name = "rtl_bt/rtl8822cs_config",
+	  .hw_info  = "rtl8822cs" },
 
 	/* 8822C with UART interface */
 	{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_UART),
@@ -224,7 +242,8 @@  static const struct id_table ic_id_table[] = {
 	  .has_rom_version = true,
 	  .has_msft_ext = true,
 	  .fw_name  = "rtl_bt/rtl8822cs_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8822cs_config" },
+	  .cfg_name = "rtl_bt/rtl8822cs_config",
+	  .hw_info  = "rtl8822cs" },
 
 	/* 8822C with USB interface */
 	{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_USB),
@@ -232,7 +251,8 @@  static const struct id_table ic_id_table[] = {
 	  .has_rom_version = true,
 	  .has_msft_ext = true,
 	  .fw_name  = "rtl_bt/rtl8822cu_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8822cu_config" },
+	  .cfg_name = "rtl_bt/rtl8822cu_config",
+	  .hw_info  = "rtl8822cu" },
 
 	/* 8822B */
 	{ IC_INFO(RTL_ROM_LMP_8822B, 0xb, 0x7, HCI_USB),
@@ -240,7 +260,8 @@  static const struct id_table ic_id_table[] = {
 	  .has_rom_version = true,
 	  .has_msft_ext = true,
 	  .fw_name  = "rtl_bt/rtl8822b_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8822b_config" },
+	  .cfg_name = "rtl_bt/rtl8822b_config",
+	  .hw_info  = "rtl8822bu" },
 
 	/* 8852A */
 	{ IC_INFO(RTL_ROM_LMP_8852A, 0xa, 0xb, HCI_USB),
@@ -248,7 +269,8 @@  static const struct id_table ic_id_table[] = {
 	  .has_rom_version = true,
 	  .has_msft_ext = true,
 	  .fw_name  = "rtl_bt/rtl8852au_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8852au_config" },
+	  .cfg_name = "rtl_bt/rtl8852au_config",
+	  .hw_info  = "rtl8852au" },
 
 	/* 8852B with UART interface */
 	{ IC_INFO(RTL_ROM_LMP_8852A, 0xb, 0xb, HCI_UART),
@@ -256,7 +278,8 @@  static const struct id_table ic_id_table[] = {
 	  .has_rom_version = true,
 	  .has_msft_ext = true,
 	  .fw_name  = "rtl_bt/rtl8852bs_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8852bs_config" },
+	  .cfg_name = "rtl_bt/rtl8852bs_config",
+	  .hw_info  = "rtl8852bs" },
 
 	/* 8852B */
 	{ IC_INFO(RTL_ROM_LMP_8852A, 0xb, 0xb, HCI_USB),
@@ -264,7 +287,8 @@  static const struct id_table ic_id_table[] = {
 	  .has_rom_version = true,
 	  .has_msft_ext = true,
 	  .fw_name  = "rtl_bt/rtl8852bu_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8852bu_config" },
+	  .cfg_name = "rtl_bt/rtl8852bu_config",
+	  .hw_info  = "rtl8852bu" },
 
 	/* 8852C */
 	{ IC_INFO(RTL_ROM_LMP_8852A, 0xc, 0xc, HCI_USB),
@@ -272,7 +296,8 @@  static const struct id_table ic_id_table[] = {
 	  .has_rom_version = true,
 	  .has_msft_ext = true,
 	  .fw_name  = "rtl_bt/rtl8852cu_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8852cu_config" },
+	  .cfg_name = "rtl_bt/rtl8852cu_config",
+	  .hw_info  = "rtl8852cu" },
 
 	/* 8851B */
 	{ IC_INFO(RTL_ROM_LMP_8851B, 0xb, 0xc, HCI_USB),
@@ -280,9 +305,16 @@  static const struct id_table ic_id_table[] = {
 	  .has_rom_version = true,
 	  .has_msft_ext = false,
 	  .fw_name  = "rtl_bt/rtl8851bu_fw.bin",
-	  .cfg_name = "rtl_bt/rtl8851bu_config" },
+	  .cfg_name = "rtl_bt/rtl8851bu_config",
+	  .hw_info  = "rtl8851bu" },
 	};
 
+static struct {
+	const char *driver_name;
+	char *controller;
+	u32  fw_version;
+} coredump_info;
+
 static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
 					     u8 hci_ver, u8 hci_bus,
 					     u8 chip_type)
@@ -707,6 +739,7 @@  static int rtlbt_parse_firmware(struct hci_dev *hdev,
 	num_patches = le16_to_cpu(epatch_info->num_patches);
 	BT_DBG("fw_version=%x, num_patches=%d",
 	       le32_to_cpu(epatch_info->fw_version), num_patches);
+	coredump_info.fw_version = le32_to_cpu(epatch_info->fw_version);
 
 	/* After the rtl_epatch_header there is a funky patch metadata section.
 	 * Assuming 2 patches, the layout is:
@@ -903,6 +936,50 @@  static int btrtl_setup_rtl8723b(struct hci_dev *hdev,
 	return ret;
 }
 
+static void btrtl_coredump(struct hci_dev *hdev)
+{
+	static const u8 param[] = { 0x00, 0x00 };
+
+	__hci_cmd_send(hdev, RTL_VSC_OP_COREDUMP, sizeof(param), param);
+}
+
+static void btrtl_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	char buf[80];
+
+	if (coredump_info.controller)
+		snprintf(buf, sizeof(buf), "Controller Name: %s\n",
+			 coredump_info.controller);
+	else
+		snprintf(buf, sizeof(buf), "Controller Name: Unknown\n");
+	skb_put_data(skb, buf, strlen(buf));
+
+	snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n",
+		 coredump_info.fw_version);
+	skb_put_data(skb, buf, strlen(buf));
+
+	snprintf(buf, sizeof(buf), "Driver: %s\n", coredump_info.driver_name);
+	skb_put_data(skb, buf, strlen(buf));
+
+	snprintf(buf, sizeof(buf), "Vendor: Realtek\n");
+	skb_put_data(skb, buf, strlen(buf));
+}
+
+static int btrtl_register_devcoredump_support(struct hci_dev *hdev)
+{
+	int err;
+
+	err = hci_devcd_register(hdev, btrtl_coredump, btrtl_dmp_hdr, NULL);
+
+	return err;
+}
+
+void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name)
+{
+	coredump_info.driver_name = driver_name;
+}
+EXPORT_SYMBOL_GPL(btrtl_set_driver_name);
+
 static bool rtl_has_chip_type(u16 lmp_subver)
 {
 	switch (lmp_subver) {
@@ -1113,6 +1190,9 @@  struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
 	if (btrtl_dev->ic_info->has_msft_ext)
 		hci_set_msft_opcode(hdev, 0xFCF0);
 
+	if (btrtl_dev->ic_info)
+		coredump_info.controller = btrtl_dev->ic_info->hw_info;
+
 	return btrtl_dev;
 
 err_free:
@@ -1125,6 +1205,8 @@  EXPORT_SYMBOL_GPL(btrtl_initialize);
 int btrtl_download_firmware(struct hci_dev *hdev,
 			    struct btrtl_device_info *btrtl_dev)
 {
+	int err = 0;
+
 	/* Match a set of subver values that correspond to stock firmware,
 	 * which is not compatible with standard btusb.
 	 * If matched, upload an alternative firmware that does conform to
@@ -1133,12 +1215,14 @@  int btrtl_download_firmware(struct hci_dev *hdev,
 	 */
 	if (!btrtl_dev->ic_info) {
 		rtl_dev_info(hdev, "assuming no firmware upload needed");
-		return 0;
+		err = 0;
+		goto done;
 	}
 
 	switch (btrtl_dev->ic_info->lmp_subver) {
 	case RTL_ROM_LMP_8723A:
-		return btrtl_setup_rtl8723a(hdev, btrtl_dev);
+		err = btrtl_setup_rtl8723a(hdev, btrtl_dev);
+		break;
 	case RTL_ROM_LMP_8723B:
 	case RTL_ROM_LMP_8821A:
 	case RTL_ROM_LMP_8761A:
@@ -1146,11 +1230,18 @@  int btrtl_download_firmware(struct hci_dev *hdev,
 	case RTL_ROM_LMP_8852A:
 	case RTL_ROM_LMP_8703B:
 	case RTL_ROM_LMP_8851B:
-		return btrtl_setup_rtl8723b(hdev, btrtl_dev);
+		err = btrtl_setup_rtl8723b(hdev, btrtl_dev);
+		break;
 	default:
 		rtl_dev_info(hdev, "assuming no firmware upload needed");
-		return 0;
+		break;
 	}
+
+done:
+	if (!err)
+		err = btrtl_register_devcoredump_support(hdev);
+
+	return err;
 }
 EXPORT_SYMBOL_GPL(btrtl_download_firmware);
 
diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h
index adb4c2c9abc5..fe2888c2d175 100644
--- a/drivers/bluetooth/btrtl.h
+++ b/drivers/bluetooth/btrtl.h
@@ -139,6 +139,7 @@  int btrtl_get_uart_settings(struct hci_dev *hdev,
 			    struct btrtl_device_info *btrtl_dev,
 			    unsigned int *controller_baudrate,
 			    u32 *device_baudrate, bool *flow_control);
+void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name);
 
 #else
 
@@ -182,4 +183,9 @@  static inline int btrtl_get_uart_settings(struct hci_dev *hdev,
 	return -ENOENT;
 }
 
+static inline void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name)
+{
+	return -EOPNOTSUPP;
+}
+
 #endif
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 3aa189b1986d..5fa90347a4e1 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -869,10 +869,49 @@  static void btusb_intel_cmd_timeout(struct hci_dev *hdev)
 	gpiod_set_value_cansleep(reset_gpio, 0);
 }
 
+#define RTK_DEVCOREDUMP_CODE_MEMDUMP		0x01
+#define RTK_DEVCOREDUMP_CODE_HW_ERR		0x02
+#define RTK_DEVCOREDUMP_CODE_CMD_TIMEOUT	0x03
+
+#define RTK_SUB_EVENT_CODE_COREDUMP		0x34
+
+struct rtk_dev_coredump_hdr {
+	u8 type;
+	u8 code;
+	u8 reserved[2];
+} __packed;
+
+static inline void btusb_rtl_alloc_devcoredump(struct hci_dev *hdev,
+		struct rtk_dev_coredump_hdr *hdr, u8 *buf, u32 len)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(len + sizeof(*hdr), GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	skb_put_data(skb, hdr, sizeof(*hdr));
+	if (len)
+		skb_put_data(skb, buf, len);
+
+	if (!hci_devcd_init(hdev, skb->len)) {
+		hci_devcd_append(hdev, skb);
+		hci_devcd_complete(hdev);
+	} else {
+		bt_dev_err(hdev, "RTL: Failed to generate devcoredump");
+		kfree_skb(skb);
+	}
+}
+
 static void btusb_rtl_cmd_timeout(struct hci_dev *hdev)
 {
 	struct btusb_data *data = hci_get_drvdata(hdev);
 	struct gpio_desc *reset_gpio = data->reset_gpio;
+	struct rtk_dev_coredump_hdr hdr = {
+		.type = RTK_DEVCOREDUMP_CODE_CMD_TIMEOUT,
+	};
+
+	btusb_rtl_alloc_devcoredump(hdev, &hdr, NULL, 0);
 
 	if (++data->cmd_timeout_cnt < 5)
 		return;
@@ -899,6 +938,18 @@  static void btusb_rtl_cmd_timeout(struct hci_dev *hdev)
 	gpiod_set_value_cansleep(reset_gpio, 0);
 }
 
+static void btusb_rtl_hw_error(struct hci_dev *hdev, u8 code)
+{
+	struct rtk_dev_coredump_hdr hdr = {
+		.type = RTK_DEVCOREDUMP_CODE_HW_ERR,
+		.code = code,
+	};
+
+	bt_dev_info(hdev, "RTL: hw err, trigger devcoredump");
+
+	btusb_rtl_alloc_devcoredump(hdev, &hdr, NULL, 0);
+}
+
 static void btusb_qca_cmd_timeout(struct hci_dev *hdev)
 {
 	struct btusb_data *data = hci_get_drvdata(hdev);
@@ -2539,6 +2590,25 @@  static int btusb_setup_realtek(struct hci_dev *hdev)
 	return ret;
 }
 
+static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	if (skb->data[0] == HCI_VENDOR_PKT && skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
+		struct rtk_dev_coredump_hdr hdr = {
+			.code = RTK_DEVCOREDUMP_CODE_MEMDUMP,
+		};
+
+		bt_dev_info(hdev, "RTL: received coredump vendor evt, len %u",
+			skb->len);
+
+		btusb_rtl_alloc_devcoredump(hdev, &hdr, skb->data, skb->len);
+		kfree_skb(skb);
+
+		return 0;
+	}
+
+	return hci_recv_frame(hdev, skb);
+}
+
 /* UHW CR mapping */
 #define MTK_BT_MISC		0x70002510
 #define MTK_BT_SUBSYS_RST	0x70002610
@@ -3978,6 +4048,8 @@  static int btusb_probe(struct usb_interface *intf,
 	} else if (id->driver_info & BTUSB_REALTEK) {
 		/* Allocate extra space for Realtek device */
 		priv_size += sizeof(struct btrealtek_data);
+
+		data->recv_event = btusb_recv_event_realtek;
 	}
 
 	data->recv_acl = hci_recv_frame;
@@ -4136,9 +4208,11 @@  static int btusb_probe(struct usb_interface *intf,
 
 	if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) &&
 	    (id->driver_info & BTUSB_REALTEK)) {
+		btrtl_set_driver_name(hdev, btusb_driver.name);
 		hdev->setup = btusb_setup_realtek;
 		hdev->shutdown = btrtl_shutdown_realtek;
 		hdev->cmd_timeout = btusb_rtl_cmd_timeout;
+		hdev->hw_error = btusb_rtl_hw_error;
 
 		/* Realtek devices need to set remote wakeup on auto-suspend */
 		set_bit(BTUSB_WAKEUP_AUTOSUSPEND, &data->flags);