diff options
author | Hsiu-Chang Chen <hsiuchangchen@google.com> | 2021-11-23 19:05:16 +0800 |
---|---|---|
committer | Victor Hsu <hsuvictor@google.com> | 2021-12-13 17:02:33 +0800 |
commit | aa8d11a216b3aa69ba637fc2118c50fb91cd09ab (patch) | |
tree | 2df1873f801feb777b64cdb03cf934647a9cc1dc /cnss2 | |
parent | 749813d67d19088575e70e142343b60ffc1bd482 (diff) | |
download | cnss2-aa8d11a216b3aa69ba637fc2118c50fb91cd09ab.tar.gz |
wcn6740: Implement wlan coredump feature
Bug: 204519778
Change-Id: Ic85052cd12d8e5b02637044998267a39795631b8
Diffstat (limited to 'cnss2')
-rw-r--r-- | cnss2/Makefile | 1 | ||||
-rw-r--r-- | cnss2/main.c | 28 | ||||
-rw-r--r-- | cnss2/main.h | 9 | ||||
-rw-r--r-- | cnss2/pci.c | 17 | ||||
-rw-r--r-- | cnss2/pci_platform_google.c | 132 |
5 files changed, 180 insertions, 7 deletions
diff --git a/cnss2/Makefile b/cnss2/Makefile index f85e728..244fbc7 100644 --- a/cnss2/Makefile +++ b/cnss2/Makefile @@ -6,6 +6,7 @@ ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y) ccflags-y += -I$(WLAN_PLATFORM_ROOT)/inc ccflags-y += -I$(WLAN_PLATFORM_ROOT)/cnss_utils ccflags-y += -DCONFIG_WCN_GOOGLE +ccflags-y += -DCONFIG_QCOM_RAMDUMP -DCONFIG_QCOM_MEMORY_DUMP_V2 else ccflags-y += -I$(srctree)/drivers/net/wireless/cnss_utils/ endif diff --git a/cnss2/main.c b/cnss2/main.c index 73e253f..050d911 100644 --- a/cnss2/main.c +++ b/cnss2/main.c @@ -2225,6 +2225,13 @@ static void cnss_destroy_ramdump_device(struct cnss_plat_data *plat_priv, #endif #if IS_ENABLED(CONFIG_QCOM_RAMDUMP) + +#if IS_ENABLED(CONFIG_WCN_GOOGLE) +int cnss_do_ramdump(struct cnss_plat_data *plat_priv) +{ + return 0; +} +#else int cnss_do_ramdump(struct cnss_plat_data *plat_priv) { struct cnss_ramdump_info *ramdump_info = &plat_priv->ramdump_info; @@ -2239,7 +2246,7 @@ int cnss_do_ramdump(struct cnss_plat_data *plat_priv) return qcom_dump(&head, ramdump_info->ramdump_dev); } - +#endif int cnss_do_elf_ramdump(struct cnss_plat_data *plat_priv) { struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2; @@ -2314,7 +2321,9 @@ int cnss_do_elf_ramdump(struct cnss_plat_data *plat_priv) static int cnss_init_dump_entry(struct cnss_plat_data *plat_priv) { struct cnss_ramdump_info *ramdump_info; +#if !IS_ENABLED(CONFIG_WCN_GOOGLE) struct msm_dump_entry dump_entry; +#endif ramdump_info = &plat_priv->ramdump_info; ramdump_info->dump_data.addr = ramdump_info->ramdump_pa; @@ -2323,11 +2332,15 @@ static int cnss_init_dump_entry(struct cnss_plat_data *plat_priv) ramdump_info->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2; strlcpy(ramdump_info->dump_data.name, CNSS_DUMP_NAME, sizeof(ramdump_info->dump_data.name)); +#if IS_ENABLED(CONFIG_WCN_GOOGLE) + return 0; +#else dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN; dump_entry.addr = virt_to_phys(&ramdump_info->dump_data); return msm_dump_data_register_nominidump(MSM_DUMP_TABLE_APPS, &dump_entry); +#endif } static int cnss_register_ramdump_v1(struct cnss_plat_data *plat_priv) @@ -2398,6 +2411,7 @@ static void cnss_unregister_ramdump_v1(struct cnss_plat_data *plat_priv) ramdump_info->ramdump_pa); } +#if !IS_ENABLED(CONFIG_WCN_GOOGLE) /** * cnss_ignore_dump_data_reg_fail - Ignore Ramdump table register failure * @ret: Error returned by msm_dump_data_register_nominidump @@ -2411,13 +2425,17 @@ static int cnss_ignore_dump_data_reg_fail(int ret) { return ret; } +#endif static int cnss_register_ramdump_v2(struct cnss_plat_data *plat_priv) { int ret = 0; struct cnss_ramdump_info_v2 *info_v2; struct cnss_dump_data *dump_data; + +#if !IS_ENABLED(CONFIG_WCN_GOOGLE) struct msm_dump_entry dump_entry; +#endif struct device *dev = &plat_priv->plat_dev->dev; u32 ramdump_size = 0; @@ -2440,6 +2458,9 @@ static int cnss_register_ramdump_v2(struct cnss_plat_data *plat_priv) dump_data->seg_version = CNSS_DUMP_SEG_VER; strlcpy(dump_data->name, CNSS_DUMP_NAME, sizeof(dump_data->name)); + +#if !IS_ENABLED(CONFIG_WCN_GOOGLE) + dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN; dump_entry.addr = virt_to_phys(dump_data); @@ -2451,7 +2472,7 @@ static int cnss_register_ramdump_v2(struct cnss_plat_data *plat_priv) ret ? "Error" : "Ignoring", ret); goto free_ramdump; } - +#endif info_v2->ramdump_dev = cnss_create_ramdump_device(plat_priv); if (!info_v2->ramdump_dev) { cnss_pr_err("Failed to create ramdump device!\n"); @@ -3270,6 +3291,9 @@ static int cnss_probe(struct platform_device *plat_dev) cnss_get_cpr_info(plat_priv); cnss_aop_mbox_init(plat_priv); cnss_init_control_params(plat_priv); +#if IS_ENABLED(CONFIG_WCN_GOOGLE) + plat_priv->recovery_enabled = true; +#endif //CONFIG_WCN_GOOGLE ret = cnss_get_resources(plat_priv); if (ret) diff --git a/cnss2/main.h b/cnss2/main.h index 924ce1e..8f7f849 100644 --- a/cnss2/main.h +++ b/cnss2/main.h @@ -21,9 +21,15 @@ #include <linux/time64.h> #ifdef CONFIG_CNSS_OUT_OF_TREE #include "cnss2.h" +#if IS_ENABLED(CONFIG_QCOM_MEMORY_DUMP_V2) +#include "memory_dump.h" +#endif +#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART) || \ + IS_ENABLED(CONFIG_QCOM_RAMDUMP) +#include "qcom_ramdump.h" +#endif #else #include <net/cnss2.h> -#endif #if IS_ENABLED(CONFIG_QCOM_MEMORY_DUMP_V2) #include <soc/qcom/memory_dump.h> #endif @@ -31,6 +37,7 @@ IS_ENABLED(CONFIG_QCOM_RAMDUMP) #include <soc/qcom/qcom_ramdump.h> #endif +#endif /* CONFIG_CNSS_OUT_OF_TREE */ #if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART) #include <soc/qcom/subsystem_notif.h> #include <soc/qcom/subsystem_restart.h> diff --git a/cnss2/pci.c b/cnss2/pci.c index 4b764b1..f84a86f 100644 --- a/cnss2/pci.c +++ b/cnss2/pci.c @@ -4401,22 +4401,24 @@ static void cnss_pci_add_dump_seg(struct cnss_pci_data *pci_priv, enum cnss_fw_dump_type type, int seg_no, void *va, dma_addr_t dma, size_t size) { +#if !IS_ENABLED(CONFIG_WCN_GOOGLE) struct cnss_plat_data *plat_priv = pci_priv->plat_priv; struct device *dev = &pci_priv->pci_dev->dev; phys_addr_t pa; - +#endif dump_seg->address = dma; dump_seg->v_address = va; dump_seg->size = size; dump_seg->type = type; - cnss_pr_dbg("Seg: %x, va: %pK, dma: %pa, size: 0x%zx\n", + cnss_pr_dbg("Seg: %x, va: %x, dma: %pa, size: 0x%zx\n", seg_no, va, &dma, size); - +#if !IS_ENABLED(CONFIG_WCN_GOOGLE) if (cnss_va_to_pa(dev, size, va, dma, &pa, DMA_ATTR_FORCE_CONTIGUOUS)) return; cnss_minidump_add_region(plat_priv, type, seg_no, va, pa, size); +#endif } static void cnss_pci_remove_dump_seg(struct cnss_pci_data *pci_priv, @@ -5187,6 +5189,9 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, ret = cnss_register_ramdump(plat_priv); if (ret) goto unregister_subsys; +#if IS_ENABLED(CONFIG_WCN_GOOGLE) + cnss_register_sscd(); +#endif /* CONFIG_WCN_GOOGLE */ ret = cnss_pci_init_smmu(pci_priv); if (ret) @@ -5258,6 +5263,9 @@ dereg_pci_event: deinit_smmu: cnss_pci_deinit_smmu(pci_priv); unregister_ramdump: +#if IS_ENABLED(CONFIG_WCN_GOOGLE) + cnss_unregister_sscd(); +#endif /* CONFIG_WCN_GOOGLE */ cnss_unregister_ramdump(plat_priv); unregister_subsys: cnss_unregister_subsys(plat_priv); @@ -5295,6 +5303,9 @@ static void cnss_pci_remove(struct pci_dev *pci_dev) cnss_pci_disable_bus(pci_priv); cnss_dereg_pci_event(pci_priv); cnss_pci_deinit_smmu(pci_priv); +#if IS_ENABLED(CONFIG_WCN_GOOGLE) + cnss_unregister_sscd(); +#endif /* CONFIG_WCN_GOOGLE */ if (plat_priv) { cnss_unregister_ramdump(plat_priv); cnss_unregister_subsys(plat_priv); diff --git a/cnss2/pci_platform_google.c b/cnss2/pci_platform_google.c index 27b19e9..6446d3c 100644 --- a/cnss2/pci_platform_google.c +++ b/cnss2/pci_platform_google.c @@ -5,6 +5,7 @@ #include <linux/of_gpio.h> #include <linux/of_reserved_mem.h> #include <linux/exynos-pci-ctrl.h> +#include <linux/platform_data/sscoredump.h> #include "pci_platform.h" #include "debug.h" #include "bus.h" @@ -302,4 +303,133 @@ int cnss_pci_set_link_bandwidth(struct cnss_pci_data *pci_priv, // static int cnss_pci_set_link_down(struct cnss_pci_data *pci_priv) // { // return 0; -// }
\ No newline at end of file +// } + +/* + * The following functions are for ssrdump. + */ + +#define DEVICE_NAME "wlan" + +static struct sscd_platform_data sscd_pdata; + +static struct platform_device sscd_dev = { + .name = DEVICE_NAME, + .driver_override = SSCD_NAME, + .id = -1, + .dev = { + .platform_data = &sscd_pdata, + .release = sscd_release, + }, +}; + +void cnss_register_sscd(void) +{ + platform_device_register(&sscd_dev); +} + +void cnss_unregister_sscd(void) +{ + platform_device_unregister(&sscd_dev); +} + +void sscd_release(struct device *dev) +{ + cnss_pr_info("%s: enter\n", __FUNCTION__); +} + +static void sscd_set_coredump(void *buf, int buf_len, const char *info) +{ + struct sscd_platform_data *pdata = dev_get_platdata(&sscd_dev.dev); + struct sscd_segment seg; + + if (pdata->sscd_report) { + memset(&seg, 0, sizeof(seg)); + seg.addr = buf; + seg.size = buf_len; + pdata->sscd_report(&sscd_dev, &seg, 1, 0, info); + } +} + +int qcom_elf_dump(struct list_head *segs, struct device *dev) +{ + struct qcom_dump_segment *segment; + struct elf32_phdr *phdr; + struct elf32_hdr *ehdr; + size_t data_size; + size_t offset; + int phnum = 0; + void *data; + void __iomem *ptr; + + if (!segs || list_empty(segs)) + return -EINVAL; + + data_size = sizeof(*ehdr); + list_for_each_entry(segment, segs, node) { + data_size += sizeof(*phdr) + segment->size; + + phnum++; + } + + data = vmalloc(data_size); + if (!data) + return -ENOMEM; + + cnss_pr_info("Creating elf with size %d\n", data_size); + ehdr = data; + + memset(ehdr, 0, sizeof(*ehdr)); + memcpy(ehdr->e_ident, ELFMAG, SELFMAG); + ehdr->e_ident[EI_CLASS] = ELFCLASS32; + ehdr->e_ident[EI_DATA] = ELFDATA2LSB; + ehdr->e_ident[EI_VERSION] = EV_CURRENT; + ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE; + ehdr->e_type = ET_CORE; + ehdr->e_machine = EM_NONE; + ehdr->e_version = EV_CURRENT; + ehdr->e_entry = 0; + ehdr->e_phoff = sizeof(*ehdr); + ehdr->e_ehsize = sizeof(*ehdr); + ehdr->e_phentsize = sizeof(*phdr); + ehdr->e_phnum = phnum; + + phdr = data + ehdr->e_phoff; + offset = ehdr->e_phoff + sizeof(*phdr) * ehdr->e_phnum; + list_for_each_entry(segment, segs, node) { + memset(phdr, 0, sizeof(*phdr)); + phdr->p_type = PT_LOAD; + phdr->p_offset = offset; + phdr->p_vaddr = segment->da; + phdr->p_paddr = segment->da; + phdr->p_filesz = segment->size; + phdr->p_memsz = segment->size; + phdr->p_flags = PF_R | PF_W | PF_X; + phdr->p_align = 0; + + if (segment->va) { + memcpy(data + offset, segment->va, segment->size); + } else { + ptr = devm_ioremap(dev, segment->da, segment->size); + if (!ptr) { + dev_err(dev, + "invalid coredump segment (%pad, %zu)\n", + &segment->da, segment->size); + memset(data + offset, 0xff, segment->size); + } else + memcpy_fromio(data + offset, ptr, + segment->size); + } + + offset += phdr->p_filesz; + phdr++; + } + + /* + * SSCD integration + */ + sscd_set_coredump(data, data_size, "Test Crash Info"); + + vfree(data); + return 0; +} |