Commit 044014ce authored by Hilda Wu's avatar Hilda Wu Committed by Luiz Augusto von Dentz

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: default avatarAlex Lu <alex_lu@realsil.com.cn>
Signed-off-by: default avatarHilda Wu <hildawu@realtek.com>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent ae753361
This diff is collapsed.
...@@ -109,8 +109,16 @@ enum { ...@@ -109,8 +109,16 @@ enum {
__REALTEK_NUM_FLAGS, __REALTEK_NUM_FLAGS,
}; };
struct rtl_dump_info {
const char *driver_name;
char *controller;
u32 fw_version;
};
struct btrealtek_data { struct btrealtek_data {
DECLARE_BITMAP(flags, __REALTEK_NUM_FLAGS); DECLARE_BITMAP(flags, __REALTEK_NUM_FLAGS);
struct rtl_dump_info rtl_dump;
}; };
#define btrealtek_set_flag(hdev, nr) \ #define btrealtek_set_flag(hdev, nr) \
...@@ -139,6 +147,7 @@ int btrtl_get_uart_settings(struct hci_dev *hdev, ...@@ -139,6 +147,7 @@ int btrtl_get_uart_settings(struct hci_dev *hdev,
struct btrtl_device_info *btrtl_dev, struct btrtl_device_info *btrtl_dev,
unsigned int *controller_baudrate, unsigned int *controller_baudrate,
u32 *device_baudrate, bool *flow_control); u32 *device_baudrate, bool *flow_control);
void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name);
#else #else
...@@ -182,4 +191,8 @@ static inline int btrtl_get_uart_settings(struct hci_dev *hdev, ...@@ -182,4 +191,8 @@ static inline int btrtl_get_uart_settings(struct hci_dev *hdev,
return -ENOENT; return -ENOENT;
} }
static inline void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name)
{
}
#endif #endif
...@@ -887,10 +887,49 @@ static void btusb_intel_cmd_timeout(struct hci_dev *hdev) ...@@ -887,10 +887,49 @@ static void btusb_intel_cmd_timeout(struct hci_dev *hdev)
gpiod_set_value_cansleep(reset_gpio, 0); 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) static void btusb_rtl_cmd_timeout(struct hci_dev *hdev)
{ {
struct btusb_data *data = hci_get_drvdata(hdev); struct btusb_data *data = hci_get_drvdata(hdev);
struct gpio_desc *reset_gpio = data->reset_gpio; 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) if (++data->cmd_timeout_cnt < 5)
return; return;
...@@ -917,6 +956,18 @@ static void btusb_rtl_cmd_timeout(struct hci_dev *hdev) ...@@ -917,6 +956,18 @@ static void btusb_rtl_cmd_timeout(struct hci_dev *hdev)
gpiod_set_value_cansleep(reset_gpio, 0); 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) static void btusb_qca_cmd_timeout(struct hci_dev *hdev)
{ {
struct btusb_data *data = hci_get_drvdata(hdev); struct btusb_data *data = hci_get_drvdata(hdev);
...@@ -2562,6 +2613,25 @@ static int btusb_setup_realtek(struct hci_dev *hdev) ...@@ -2562,6 +2613,25 @@ static int btusb_setup_realtek(struct hci_dev *hdev)
return ret; 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 */ /* UHW CR mapping */
#define MTK_BT_MISC 0x70002510 #define MTK_BT_MISC 0x70002510
#define MTK_BT_SUBSYS_RST 0x70002610 #define MTK_BT_SUBSYS_RST 0x70002610
...@@ -4201,6 +4271,8 @@ static int btusb_probe(struct usb_interface *intf, ...@@ -4201,6 +4271,8 @@ static int btusb_probe(struct usb_interface *intf,
} else if (id->driver_info & BTUSB_REALTEK) { } else if (id->driver_info & BTUSB_REALTEK) {
/* Allocate extra space for Realtek device */ /* Allocate extra space for Realtek device */
priv_size += sizeof(struct btrealtek_data); priv_size += sizeof(struct btrealtek_data);
data->recv_event = btusb_recv_event_realtek;
} }
data->recv_acl = hci_recv_frame; data->recv_acl = hci_recv_frame;
...@@ -4364,9 +4436,11 @@ static int btusb_probe(struct usb_interface *intf, ...@@ -4364,9 +4436,11 @@ static int btusb_probe(struct usb_interface *intf,
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) && if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) &&
(id->driver_info & BTUSB_REALTEK)) { (id->driver_info & BTUSB_REALTEK)) {
btrtl_set_driver_name(hdev, btusb_driver.name);
hdev->setup = btusb_setup_realtek; hdev->setup = btusb_setup_realtek;
hdev->shutdown = btrtl_shutdown_realtek; hdev->shutdown = btrtl_shutdown_realtek;
hdev->cmd_timeout = btusb_rtl_cmd_timeout; hdev->cmd_timeout = btusb_rtl_cmd_timeout;
hdev->hw_error = btusb_rtl_hw_error;
/* Realtek devices need to set remote wakeup on auto-suspend */ /* Realtek devices need to set remote wakeup on auto-suspend */
set_bit(BTUSB_WAKEUP_AUTOSUSPEND, &data->flags); set_bit(BTUSB_WAKEUP_AUTOSUSPEND, &data->flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment