forked from raspberrypi/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bluetooth: btusb: mediatek: add MediaTek devcoredump support
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 <[email protected]> Signed-off-by: Chris Lu <[email protected]> Co-developed-by: Sean Wang <[email protected]> Signed-off-by: Sean Wang <[email protected]> Signed-off-by: Jing Cai <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
- Loading branch information
1 parent
25b6d75
commit 0b70151
Showing
3 changed files
with
154 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,6 +53,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 btmediatek_data *data = hci_get_priv(hdev); | ||
char buf[80]; | ||
|
||
snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n", | ||
data->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 btmediatek_data *data = hci_get_priv(hdev); | ||
|
||
switch (state) { | ||
case HCI_DEVCOREDUMP_IDLE: | ||
data->cd_info.state = HCI_DEVCOREDUMP_IDLE; | ||
break; | ||
case HCI_DEVCOREDUMP_ACTIVE: | ||
data->cd_info.state = HCI_DEVCOREDUMP_ACTIVE; | ||
break; | ||
case HCI_DEVCOREDUMP_TIMEOUT: | ||
case HCI_DEVCOREDUMP_ABORT: | ||
case HCI_DEVCOREDUMP_DONE: | ||
data->cd_info.state = HCI_DEVCOREDUMP_IDLE; | ||
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) | ||
{ | ||
|
@@ -300,6 +350,68 @@ void btmtk_reset_sync(struct hci_dev *hdev) | |
} | ||
EXPORT_SYMBOL_GPL(btmtk_reset_sync); | ||
|
||
int btmtk_register_coredump(struct hci_dev *hdev, const char *name, | ||
u32 fw_version) | ||
{ | ||
struct btmediatek_data *data = hci_get_priv(hdev); | ||
|
||
if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) | ||
return -EOPNOTSUPP; | ||
|
||
data->cd_info.fw_version = fw_version; | ||
data->cd_info.state = HCI_DEVCOREDUMP_IDLE; | ||
data->cd_info.driver_name = name; | ||
|
||
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 btmediatek_data *data = hci_get_priv(hdev); | ||
int err; | ||
|
||
if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) | ||
return 0; | ||
|
||
switch (data->cd_info.state) { | ||
case HCI_DEVCOREDUMP_IDLE: | ||
err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE); | ||
if (err < 0) | ||
break; | ||
data->cd_info.cnt = 0; | ||
|
||
/* It is supposed coredump can be done within 5 seconds */ | ||
schedule_delayed_work(&hdev->dump.dump_timeout, | ||
msecs_to_jiffies(5000)); | ||
fallthrough; | ||
case HCI_DEVCOREDUMP_ACTIVE: | ||
default: | ||
err = hci_devcd_append(hdev, skb); | ||
if (err < 0) | ||
break; | ||
data->cd_info.cnt++; | ||
|
||
/* Mediatek coredump data would be more than MTK_COREDUMP_NUM */ | ||
if (data->cd_info.cnt > MTK_COREDUMP_NUM && | ||
skb->len > sizeof(MTK_COREDUMP_END) && | ||
!memcmp((char *)&skb->data[skb->len - sizeof(MTK_COREDUMP_END)], | ||
MTK_COREDUMP_END, sizeof(MTK_COREDUMP_END) - 1)) { | ||
bt_dev_info(hdev, "Mediatek coredump end"); | ||
hci_devcd_complete(hdev); | ||
} | ||
|
||
break; | ||
} | ||
|
||
if (err < 0) | ||
kfree_skb(skb); | ||
|
||
return err; | ||
} | ||
EXPORT_SYMBOL_GPL(btmtk_process_coredump); | ||
|
||
MODULE_AUTHOR("Sean Wang <[email protected]>"); | ||
MODULE_AUTHOR("Mark Chen <[email protected]>"); | ||
MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters