162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* Copyright (C) 2021 MediaTek Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include <linux/module.h> 662306a36Sopenharmony_ci#include <linux/firmware.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 962306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "btmtk.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define VERSION "0.1" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* It is for mt79xx download rom patch*/ 1662306a36Sopenharmony_ci#define MTK_FW_ROM_PATCH_HEADER_SIZE 32 1762306a36Sopenharmony_ci#define MTK_FW_ROM_PATCH_GD_SIZE 64 1862306a36Sopenharmony_ci#define MTK_FW_ROM_PATCH_SEC_MAP_SIZE 64 1962306a36Sopenharmony_ci#define MTK_SEC_MAP_COMMON_SIZE 12 2062306a36Sopenharmony_ci#define MTK_SEC_MAP_NEED_SEND_SIZE 52 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct btmtk_patch_header { 2362306a36Sopenharmony_ci u8 datetime[16]; 2462306a36Sopenharmony_ci u8 platform[4]; 2562306a36Sopenharmony_ci __le16 hwver; 2662306a36Sopenharmony_ci __le16 swver; 2762306a36Sopenharmony_ci __le32 magicnum; 2862306a36Sopenharmony_ci} __packed; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistruct btmtk_global_desc { 3162306a36Sopenharmony_ci __le32 patch_ver; 3262306a36Sopenharmony_ci __le32 sub_sys; 3362306a36Sopenharmony_ci __le32 feature_opt; 3462306a36Sopenharmony_ci __le32 section_num; 3562306a36Sopenharmony_ci} __packed; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct btmtk_section_map { 3862306a36Sopenharmony_ci __le32 sectype; 3962306a36Sopenharmony_ci __le32 secoffset; 4062306a36Sopenharmony_ci __le32 secsize; 4162306a36Sopenharmony_ci union { 4262306a36Sopenharmony_ci __le32 u4SecSpec[13]; 4362306a36Sopenharmony_ci struct { 4462306a36Sopenharmony_ci __le32 dlAddr; 4562306a36Sopenharmony_ci __le32 dlsize; 4662306a36Sopenharmony_ci __le32 seckeyidx; 4762306a36Sopenharmony_ci __le32 alignlen; 4862306a36Sopenharmony_ci __le32 sectype; 4962306a36Sopenharmony_ci __le32 dlmodecrctype; 5062306a36Sopenharmony_ci __le32 crc; 5162306a36Sopenharmony_ci __le32 reserved[6]; 5262306a36Sopenharmony_ci } bin_info_spec; 5362306a36Sopenharmony_ci }; 5462306a36Sopenharmony_ci} __packed; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void btmtk_coredump(struct hci_dev *hdev) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci int err; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci err = __hci_cmd_send(hdev, 0xfd5b, 0, NULL); 6162306a36Sopenharmony_ci if (err < 0) 6262306a36Sopenharmony_ci bt_dev_err(hdev, "Coredump failed (%d)", err); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic void btmtk_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct btmediatek_data *data = hci_get_priv(hdev); 6862306a36Sopenharmony_ci char buf[80]; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n", 7162306a36Sopenharmony_ci data->dev_id); 7262306a36Sopenharmony_ci skb_put_data(skb, buf, strlen(buf)); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n", 7562306a36Sopenharmony_ci data->cd_info.fw_version); 7662306a36Sopenharmony_ci skb_put_data(skb, buf, strlen(buf)); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "Driver: %s\n", 7962306a36Sopenharmony_ci data->cd_info.driver_name); 8062306a36Sopenharmony_ci skb_put_data(skb, buf, strlen(buf)); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "Vendor: MediaTek\n"); 8362306a36Sopenharmony_ci skb_put_data(skb, buf, strlen(buf)); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic void btmtk_coredump_notify(struct hci_dev *hdev, int state) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct btmediatek_data *data = hci_get_priv(hdev); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci switch (state) { 9162306a36Sopenharmony_ci case HCI_DEVCOREDUMP_IDLE: 9262306a36Sopenharmony_ci data->cd_info.state = HCI_DEVCOREDUMP_IDLE; 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci case HCI_DEVCOREDUMP_ACTIVE: 9562306a36Sopenharmony_ci data->cd_info.state = HCI_DEVCOREDUMP_ACTIVE; 9662306a36Sopenharmony_ci break; 9762306a36Sopenharmony_ci case HCI_DEVCOREDUMP_TIMEOUT: 9862306a36Sopenharmony_ci case HCI_DEVCOREDUMP_ABORT: 9962306a36Sopenharmony_ci case HCI_DEVCOREDUMP_DONE: 10062306a36Sopenharmony_ci data->cd_info.state = HCI_DEVCOREDUMP_IDLE; 10162306a36Sopenharmony_ci btmtk_reset_sync(hdev); 10262306a36Sopenharmony_ci break; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ciint btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, 10762306a36Sopenharmony_ci wmt_cmd_sync_func_t wmt_cmd_sync) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct btmtk_hci_wmt_params wmt_params; 11062306a36Sopenharmony_ci struct btmtk_patch_header *hdr; 11162306a36Sopenharmony_ci struct btmtk_global_desc *globaldesc = NULL; 11262306a36Sopenharmony_ci struct btmtk_section_map *sectionmap; 11362306a36Sopenharmony_ci const struct firmware *fw; 11462306a36Sopenharmony_ci const u8 *fw_ptr; 11562306a36Sopenharmony_ci const u8 *fw_bin_ptr; 11662306a36Sopenharmony_ci int err, dlen, i, status; 11762306a36Sopenharmony_ci u8 flag, first_block, retry; 11862306a36Sopenharmony_ci u32 section_num, dl_size, section_offset; 11962306a36Sopenharmony_ci u8 cmd[64]; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci err = request_firmware(&fw, fwname, &hdev->dev); 12262306a36Sopenharmony_ci if (err < 0) { 12362306a36Sopenharmony_ci bt_dev_err(hdev, "Failed to load firmware file (%d)", err); 12462306a36Sopenharmony_ci return err; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci fw_ptr = fw->data; 12862306a36Sopenharmony_ci fw_bin_ptr = fw_ptr; 12962306a36Sopenharmony_ci hdr = (struct btmtk_patch_header *)fw_ptr; 13062306a36Sopenharmony_ci globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE); 13162306a36Sopenharmony_ci section_num = le32_to_cpu(globaldesc->section_num); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s", 13462306a36Sopenharmony_ci le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver), hdr->datetime); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci for (i = 0; i < section_num; i++) { 13762306a36Sopenharmony_ci first_block = 1; 13862306a36Sopenharmony_ci fw_ptr = fw_bin_ptr; 13962306a36Sopenharmony_ci sectionmap = (struct btmtk_section_map *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE + 14062306a36Sopenharmony_ci MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci section_offset = le32_to_cpu(sectionmap->secoffset); 14362306a36Sopenharmony_ci dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (dl_size > 0) { 14662306a36Sopenharmony_ci retry = 20; 14762306a36Sopenharmony_ci while (retry > 0) { 14862306a36Sopenharmony_ci cmd[0] = 0; /* 0 means legacy dl mode. */ 14962306a36Sopenharmony_ci memcpy(cmd + 1, 15062306a36Sopenharmony_ci fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE + 15162306a36Sopenharmony_ci MTK_FW_ROM_PATCH_GD_SIZE + 15262306a36Sopenharmony_ci MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i + 15362306a36Sopenharmony_ci MTK_SEC_MAP_COMMON_SIZE, 15462306a36Sopenharmony_ci MTK_SEC_MAP_NEED_SEND_SIZE + 1); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci wmt_params.op = BTMTK_WMT_PATCH_DWNLD; 15762306a36Sopenharmony_ci wmt_params.status = &status; 15862306a36Sopenharmony_ci wmt_params.flag = 0; 15962306a36Sopenharmony_ci wmt_params.dlen = MTK_SEC_MAP_NEED_SEND_SIZE + 1; 16062306a36Sopenharmony_ci wmt_params.data = &cmd; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci err = wmt_cmd_sync(hdev, &wmt_params); 16362306a36Sopenharmony_ci if (err < 0) { 16462306a36Sopenharmony_ci bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", 16562306a36Sopenharmony_ci err); 16662306a36Sopenharmony_ci goto err_release_fw; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (status == BTMTK_WMT_PATCH_UNDONE) { 17062306a36Sopenharmony_ci break; 17162306a36Sopenharmony_ci } else if (status == BTMTK_WMT_PATCH_PROGRESS) { 17262306a36Sopenharmony_ci msleep(100); 17362306a36Sopenharmony_ci retry--; 17462306a36Sopenharmony_ci } else if (status == BTMTK_WMT_PATCH_DONE) { 17562306a36Sopenharmony_ci goto next_section; 17662306a36Sopenharmony_ci } else { 17762306a36Sopenharmony_ci bt_dev_err(hdev, "Failed wmt patch dwnld status (%d)", 17862306a36Sopenharmony_ci status); 17962306a36Sopenharmony_ci err = -EIO; 18062306a36Sopenharmony_ci goto err_release_fw; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci fw_ptr += section_offset; 18562306a36Sopenharmony_ci wmt_params.op = BTMTK_WMT_PATCH_DWNLD; 18662306a36Sopenharmony_ci wmt_params.status = NULL; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci while (dl_size > 0) { 18962306a36Sopenharmony_ci dlen = min_t(int, 250, dl_size); 19062306a36Sopenharmony_ci if (first_block == 1) { 19162306a36Sopenharmony_ci flag = 1; 19262306a36Sopenharmony_ci first_block = 0; 19362306a36Sopenharmony_ci } else if (dl_size - dlen <= 0) { 19462306a36Sopenharmony_ci flag = 3; 19562306a36Sopenharmony_ci } else { 19662306a36Sopenharmony_ci flag = 2; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci wmt_params.flag = flag; 20062306a36Sopenharmony_ci wmt_params.dlen = dlen; 20162306a36Sopenharmony_ci wmt_params.data = fw_ptr; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci err = wmt_cmd_sync(hdev, &wmt_params); 20462306a36Sopenharmony_ci if (err < 0) { 20562306a36Sopenharmony_ci bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", 20662306a36Sopenharmony_ci err); 20762306a36Sopenharmony_ci goto err_release_fw; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci dl_size -= dlen; 21162306a36Sopenharmony_ci fw_ptr += dlen; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_cinext_section: 21562306a36Sopenharmony_ci continue; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci /* Wait a few moments for firmware activation done */ 21862306a36Sopenharmony_ci usleep_range(100000, 120000); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cierr_release_fw: 22162306a36Sopenharmony_ci release_firmware(fw); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci return err; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btmtk_setup_firmware_79xx); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ciint btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname, 22862306a36Sopenharmony_ci wmt_cmd_sync_func_t wmt_cmd_sync) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct btmtk_hci_wmt_params wmt_params; 23162306a36Sopenharmony_ci const struct firmware *fw; 23262306a36Sopenharmony_ci const u8 *fw_ptr; 23362306a36Sopenharmony_ci size_t fw_size; 23462306a36Sopenharmony_ci int err, dlen; 23562306a36Sopenharmony_ci u8 flag, param; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci err = request_firmware(&fw, fwname, &hdev->dev); 23862306a36Sopenharmony_ci if (err < 0) { 23962306a36Sopenharmony_ci bt_dev_err(hdev, "Failed to load firmware file (%d)", err); 24062306a36Sopenharmony_ci return err; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* Power on data RAM the firmware relies on. */ 24462306a36Sopenharmony_ci param = 1; 24562306a36Sopenharmony_ci wmt_params.op = BTMTK_WMT_FUNC_CTRL; 24662306a36Sopenharmony_ci wmt_params.flag = 3; 24762306a36Sopenharmony_ci wmt_params.dlen = sizeof(param); 24862306a36Sopenharmony_ci wmt_params.data = ¶m; 24962306a36Sopenharmony_ci wmt_params.status = NULL; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci err = wmt_cmd_sync(hdev, &wmt_params); 25262306a36Sopenharmony_ci if (err < 0) { 25362306a36Sopenharmony_ci bt_dev_err(hdev, "Failed to power on data RAM (%d)", err); 25462306a36Sopenharmony_ci goto err_release_fw; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci fw_ptr = fw->data; 25862306a36Sopenharmony_ci fw_size = fw->size; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* The size of patch header is 30 bytes, should be skip */ 26162306a36Sopenharmony_ci if (fw_size < 30) { 26262306a36Sopenharmony_ci err = -EINVAL; 26362306a36Sopenharmony_ci goto err_release_fw; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci fw_size -= 30; 26762306a36Sopenharmony_ci fw_ptr += 30; 26862306a36Sopenharmony_ci flag = 1; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci wmt_params.op = BTMTK_WMT_PATCH_DWNLD; 27162306a36Sopenharmony_ci wmt_params.status = NULL; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci while (fw_size > 0) { 27462306a36Sopenharmony_ci dlen = min_t(int, 250, fw_size); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* Tell device the position in sequence */ 27762306a36Sopenharmony_ci if (fw_size - dlen <= 0) 27862306a36Sopenharmony_ci flag = 3; 27962306a36Sopenharmony_ci else if (fw_size < fw->size - 30) 28062306a36Sopenharmony_ci flag = 2; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci wmt_params.flag = flag; 28362306a36Sopenharmony_ci wmt_params.dlen = dlen; 28462306a36Sopenharmony_ci wmt_params.data = fw_ptr; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci err = wmt_cmd_sync(hdev, &wmt_params); 28762306a36Sopenharmony_ci if (err < 0) { 28862306a36Sopenharmony_ci bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", 28962306a36Sopenharmony_ci err); 29062306a36Sopenharmony_ci goto err_release_fw; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci fw_size -= dlen; 29462306a36Sopenharmony_ci fw_ptr += dlen; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci wmt_params.op = BTMTK_WMT_RST; 29862306a36Sopenharmony_ci wmt_params.flag = 4; 29962306a36Sopenharmony_ci wmt_params.dlen = 0; 30062306a36Sopenharmony_ci wmt_params.data = NULL; 30162306a36Sopenharmony_ci wmt_params.status = NULL; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* Activate funciton the firmware providing to */ 30462306a36Sopenharmony_ci err = wmt_cmd_sync(hdev, &wmt_params); 30562306a36Sopenharmony_ci if (err < 0) { 30662306a36Sopenharmony_ci bt_dev_err(hdev, "Failed to send wmt rst (%d)", err); 30762306a36Sopenharmony_ci goto err_release_fw; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* Wait a few moments for firmware activation done */ 31162306a36Sopenharmony_ci usleep_range(10000, 12000); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cierr_release_fw: 31462306a36Sopenharmony_ci release_firmware(fw); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci return err; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btmtk_setup_firmware); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ciint btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci struct sk_buff *skb; 32362306a36Sopenharmony_ci long ret; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci skb = __hci_cmd_sync(hdev, 0xfc1a, 6, bdaddr, HCI_INIT_TIMEOUT); 32662306a36Sopenharmony_ci if (IS_ERR(skb)) { 32762306a36Sopenharmony_ci ret = PTR_ERR(skb); 32862306a36Sopenharmony_ci bt_dev_err(hdev, "changing Mediatek device address failed (%ld)", 32962306a36Sopenharmony_ci ret); 33062306a36Sopenharmony_ci return ret; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci kfree_skb(skb); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci return 0; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btmtk_set_bdaddr); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_civoid btmtk_reset_sync(struct hci_dev *hdev) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct btmediatek_data *reset_work = hci_get_priv(hdev); 34162306a36Sopenharmony_ci int err; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci hci_dev_lock(hdev); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci err = hci_cmd_sync_queue(hdev, reset_work->reset_sync, NULL, NULL); 34662306a36Sopenharmony_ci if (err) 34762306a36Sopenharmony_ci bt_dev_err(hdev, "failed to reset (%d)", err); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci hci_dev_unlock(hdev); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btmtk_reset_sync); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ciint btmtk_register_coredump(struct hci_dev *hdev, const char *name, 35462306a36Sopenharmony_ci u32 fw_version) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct btmediatek_data *data = hci_get_priv(hdev); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) 35962306a36Sopenharmony_ci return -EOPNOTSUPP; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci data->cd_info.fw_version = fw_version; 36262306a36Sopenharmony_ci data->cd_info.state = HCI_DEVCOREDUMP_IDLE; 36362306a36Sopenharmony_ci data->cd_info.driver_name = name; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci return hci_devcd_register(hdev, btmtk_coredump, btmtk_coredump_hdr, 36662306a36Sopenharmony_ci btmtk_coredump_notify); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btmtk_register_coredump); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ciint btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct btmediatek_data *data = hci_get_priv(hdev); 37362306a36Sopenharmony_ci int err; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) { 37662306a36Sopenharmony_ci kfree_skb(skb); 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci switch (data->cd_info.state) { 38162306a36Sopenharmony_ci case HCI_DEVCOREDUMP_IDLE: 38262306a36Sopenharmony_ci err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE); 38362306a36Sopenharmony_ci if (err < 0) 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci data->cd_info.cnt = 0; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* It is supposed coredump can be done within 5 seconds */ 38862306a36Sopenharmony_ci schedule_delayed_work(&hdev->dump.dump_timeout, 38962306a36Sopenharmony_ci msecs_to_jiffies(5000)); 39062306a36Sopenharmony_ci fallthrough; 39162306a36Sopenharmony_ci case HCI_DEVCOREDUMP_ACTIVE: 39262306a36Sopenharmony_ci default: 39362306a36Sopenharmony_ci err = hci_devcd_append(hdev, skb); 39462306a36Sopenharmony_ci if (err < 0) 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci data->cd_info.cnt++; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* Mediatek coredump data would be more than MTK_COREDUMP_NUM */ 39962306a36Sopenharmony_ci if (data->cd_info.cnt > MTK_COREDUMP_NUM && 40062306a36Sopenharmony_ci skb->len > MTK_COREDUMP_END_LEN) 40162306a36Sopenharmony_ci if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN], 40262306a36Sopenharmony_ci MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) { 40362306a36Sopenharmony_ci bt_dev_info(hdev, "Mediatek coredump end"); 40462306a36Sopenharmony_ci hci_devcd_complete(hdev); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (err < 0) 41162306a36Sopenharmony_ci kfree_skb(skb); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return err; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(btmtk_process_coredump); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ciMODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); 41862306a36Sopenharmony_ciMODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>"); 41962306a36Sopenharmony_ciMODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION); 42062306a36Sopenharmony_ciMODULE_VERSION(VERSION); 42162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 42262306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_MT7622); 42362306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_MT7663); 42462306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_MT7668); 42562306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_MT7961); 42662306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_MT7925); 427