| From a0987f5890e5f876d89739e2708adc0b788f0816 Mon Sep 17 00:00:00 2001 |
| From: Hilda Wu <hildawu@realtek.com> |
| Date: Thu, 27 Apr 2023 11:27:55 +0800 |
| Subject: [PATCH] FROMGIT:BACKPORT: Bluetooth: btrtl: Add Realtek devcoredump |
| support |
| |
| 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> |
| Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> |
| (cherry picked from commit ab93c2a3445889c311a40a82601cf304869a893b |
| git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master) |
| |
| BACKPORT Notes: Add private size |
| |
| BUG=b:172017254 |
| TEST=Build |
| |
| Change-Id: I8204352af23076ee7fb526ada43208426090b7b9 |
| Signed-off-by: Alex Lu <alex_lu@realsil.com.cn> |
| Signed-off-by: Hilda Wu <hildawu@realtek.com> |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/4583806 |
| Reviewed-by: Ying Hsu <yinghsu@chromium.org> |
| Commit-Queue: Ying Hsu <yinghsu@chromium.org> |
| Reviewed-by: Manish Mandlik <mmandlik@chromium.org> |
| --- |
| drivers/bluetooth/btrtl.c | 139 +++++++++++++++++++++++++++++++------- |
| drivers/bluetooth/btrtl.h | 12 ++++ |
| drivers/bluetooth/btusb.c | 75 ++++++++++++++++++++ |
| 3 files changed, 201 insertions(+), 25 deletions(-) |
| |
| diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c |
| index b1081499b99f803233198a1a4710b296f05af8e1..6c1c4a7de97ea3e1884af69feb9c2d076f3ab87b 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), |
| @@ -193,7 +206,8 @@ static const struct id_table ic_id_table[] = { |
| .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 +215,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 +232,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 +241,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 +250,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 +259,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 +268,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), |
| @@ -264,7 +285,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 +294,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,7 +303,8 @@ 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 const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev, |
| @@ -590,6 +614,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, |
| unsigned char **_buf) |
| { |
| static const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; |
| + struct btrealtek_data *coredump_info = hci_get_priv(hdev); |
| struct rtl_epatch_header *epatch_info; |
| unsigned char *buf; |
| int i, len; |
| @@ -705,8 +730,10 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, |
| |
| epatch_info = (struct rtl_epatch_header *)btrtl_dev->fw_data; |
| 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->rtl_dump.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 +930,53 @@ 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) |
| +{ |
| + struct btrealtek_data *coredump_info = hci_get_priv(hdev); |
| + char buf[80]; |
| + |
| + if (coredump_info->rtl_dump.controller) |
| + snprintf(buf, sizeof(buf), "Controller Name: %s\n", |
| + coredump_info->rtl_dump.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->rtl_dump.fw_version); |
| + skb_put_data(skb, buf, strlen(buf)); |
| + |
| + snprintf(buf, sizeof(buf), "Driver: %s\n", coredump_info->rtl_dump.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) |
| +{ |
| + struct btrealtek_data *coredump_info = hci_get_priv(hdev); |
| + |
| + coredump_info->rtl_dump.driver_name = driver_name; |
| +} |
| +EXPORT_SYMBOL_GPL(btrtl_set_driver_name); |
| + |
| static bool rtl_has_chip_type(u16 lmp_subver) |
| { |
| switch (lmp_subver) { |
| @@ -964,6 +1038,7 @@ EXPORT_SYMBOL_GPL(btrtl_free); |
| struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, |
| const char *postfix) |
| { |
| + struct btrealtek_data *coredump_info = hci_get_priv(hdev); |
| struct btrtl_device_info *btrtl_dev; |
| struct sk_buff *skb; |
| struct hci_rp_read_local_version *resp; |
| @@ -1114,6 +1189,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->rtl_dump.controller = btrtl_dev->ic_info->hw_info; |
| + |
| return btrtl_dev; |
| |
| err_free: |
| @@ -1126,6 +1204,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 |
| @@ -1134,12 +1214,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: |
| @@ -1147,11 +1229,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 adb4c2c9abc501cf25762e725c35126854221f86..decdf359f8e6d0fa57b97a1d08bee5d9e462948d 100644 |
| --- a/drivers/bluetooth/btrtl.h |
| +++ b/drivers/bluetooth/btrtl.h |
| @@ -109,8 +109,15 @@ enum { |
| __REALTEK_NUM_FLAGS, |
| }; |
| |
| +struct rtl_dump_info { |
| + const char *driver_name; |
| + char *controller; |
| + u32 fw_version; |
| +}; |
| + |
| struct btrealtek_data { |
| DECLARE_BITMAP(flags, __REALTEK_NUM_FLAGS); |
| + struct rtl_dump_info rtl_dump; |
| }; |
| |
| #define btrealtek_set_flag(hdev, nr) \ |
| @@ -139,6 +146,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 +190,8 @@ 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) |
| +{ |
| +} |
| + |
| #endif |
| diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c |
| index 7607cf34701163cf8326200958291c53673ef518..28c302dd6a40bcc6338b92ef779a740588d3eb91 100644 |
| --- a/drivers/bluetooth/btusb.c |
| +++ b/drivers/bluetooth/btusb.c |
| @@ -876,10 +876,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 (!reset_gpio) { |
| btusb_reset(hdev); |
| @@ -903,6 +942,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_err(hdev, "RTL: hw err, trigger devcoredump (%d)", code); |
| + |
| + 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); |
| @@ -2554,6 +2605,26 @@ 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_dbg(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 |
| @@ -4206,6 +4277,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; |
| @@ -4381,8 +4454,10 @@ static int btusb_probe(struct usb_interface *intf, |
| if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) && |
| (id->driver_info & BTUSB_REALTEK)) { |
| hdev->setup = btusb_setup_realtek; |
| + btrtl_set_driver_name(hdev, btusb_driver.name); |
| 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.34.1 |
| |