From 85e68f3f03ceb9ba1adc03784eb754100d065a0d Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 13 May 2022 16:12:09 +0530 Subject: [PATCH] remoteproc: qcom: pas: Rename subsystem minidump elf name Currently, the name of ELF remain same whether it is subsystem's minidump or full dump and it was difficult for parsing tool to identify the elf's between them. As previous patch adds the support of creation of ramdump device with a given name, now we would be creating separate dummy minidump device for a subsystem with a name appended by _md. which will help us in creating different name for subsystem's minidump e.g remoteproc-adsp-md_2022-05-08_18-19-32.elf . Change-Id: I6b49532b425b480e7351b7d1c86bb0ce29b09e1a Signed-off-by: Mukesh Ojha Signed-off-by: Naman Jain --- drivers/remoteproc/qcom_common.c | 115 ++++++++++++++++++++++++++++- drivers/remoteproc/qcom_common.h | 3 +- drivers/remoteproc/qcom_q6v5_pas.c | 18 ++++- 3 files changed, 131 insertions(+), 5 deletions(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index b8a6622db9c1..2bb72c8337d0 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -5,6 +5,7 @@ * Copyright (C) 2016 Linaro Ltd * Copyright (C) 2015 Sony Mobile Communications Inc * Copyright (c) 2012-2013, 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -17,9 +18,11 @@ #include #include #include +#include #include #include +#include "remoteproc_elf_helpers.h" #include "remoteproc_internal.h" #include "qcom_common.h" @@ -171,7 +174,114 @@ static int qcom_add_minidump_segments(struct rproc *rproc, struct minidump_subsy return 0; } -void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, rproc_dumpfn_t dumpfn) +static void qcom_rproc_minidump(struct rproc *rproc, struct device *md_dev) +{ + struct rproc_dump_segment *segment; + void *shdr; + void *ehdr; + size_t data_size; + size_t strtbl_size = 0; + size_t strtbl_index = 1; + size_t offset; + void *data; + u8 class = rproc->elf_class; + int shnum; + unsigned int dump_conf = rproc->dump_conf; + char *str_tbl = "STR_TBL"; + + if (list_empty(&rproc->dump_segments) || + dump_conf == RPROC_COREDUMP_DISABLED) + return; + + if (class == ELFCLASSNONE) { + dev_err(&rproc->dev, "Elf class is not set\n"); + return; + } + + /* + * We allocate two extra section headers. The first one is null. + * Second section header is for the string table. Also space is + * allocated for string table. + */ + data_size = elf_size_of_hdr(class) + 2 * elf_size_of_shdr(class); + shnum = 2; + + /* the extra byte is for the null character at index 0 */ + strtbl_size += strlen(str_tbl) + 2; + + list_for_each_entry(segment, &rproc->dump_segments, node) { + data_size += elf_size_of_shdr(class); + strtbl_size += strlen(segment->priv) + 1; + data_size += segment->size; + shnum++; + } + + data_size += strtbl_size; + + data = vmalloc(data_size); + if (!data) + return; + + ehdr = data; + memset(ehdr, 0, elf_size_of_hdr(class)); + /* e_ident field is common for both elf32 and elf64 */ + elf_hdr_init_ident(ehdr, class); + elf_hdr_set_e_type(class, ehdr, ET_CORE); + elf_hdr_set_e_machine(class, ehdr, rproc->elf_machine); + elf_hdr_set_e_version(class, ehdr, EV_CURRENT); + elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr); + elf_hdr_set_e_shoff(class, ehdr, elf_size_of_hdr(class)); + elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class)); + elf_hdr_set_e_shentsize(class, ehdr, elf_size_of_shdr(class)); + elf_hdr_set_e_shnum(class, ehdr, shnum); + elf_hdr_set_e_shstrndx(class, ehdr, 1); + + /* + * The zeroth index of the section header is reserved and is rarely used. + * Set the section header as null (SHN_UNDEF) and move to the next one. + */ + shdr = data + elf_hdr_get_e_shoff(class, ehdr); + memset(shdr, 0, elf_size_of_shdr(class)); + shdr += elf_size_of_shdr(class); + + /* Initialize the string table. */ + offset = elf_hdr_get_e_shoff(class, ehdr) + + elf_size_of_shdr(class) * elf_hdr_get_e_shnum(class, ehdr); + memset(data + offset, 0, strtbl_size); + + /* Fill in the string table section header. */ + memset(shdr, 0, elf_size_of_shdr(class)); + elf_shdr_set_sh_type(class, shdr, SHT_STRTAB); + elf_shdr_set_sh_offset(class, shdr, offset); + elf_shdr_set_sh_size(class, shdr, strtbl_size); + elf_shdr_set_sh_entsize(class, shdr, 0); + elf_shdr_set_sh_flags(class, shdr, 0); + elf_shdr_set_sh_name(class, shdr, elf_strtbl_add(str_tbl, ehdr, class, &strtbl_index)); + offset += elf_shdr_get_sh_size(class, shdr); + shdr += elf_size_of_shdr(class); + + list_for_each_entry(segment, &rproc->dump_segments, node) { + memset(shdr, 0, elf_size_of_shdr(class)); + elf_shdr_set_sh_type(class, shdr, SHT_PROGBITS); + elf_shdr_set_sh_offset(class, shdr, offset); + elf_shdr_set_sh_addr(class, shdr, segment->da); + elf_shdr_set_sh_size(class, shdr, segment->size); + elf_shdr_set_sh_entsize(class, shdr, 0); + elf_shdr_set_sh_flags(class, shdr, SHF_WRITE); + elf_shdr_set_sh_name(class, shdr, + elf_strtbl_add(segment->priv, ehdr, class, &strtbl_index)); + + /* No need to copy segments for inline dumps */ + segment->dump(rproc, segment, data + offset, 0, segment->size); + offset += elf_shdr_get_sh_size(class, shdr); + shdr += elf_size_of_shdr(class); + } + + dev_coredumpv(md_dev, data, data_size, GFP_KERNEL); +} + +void qcom_minidump(struct rproc *rproc, struct device *md_dev, + unsigned int minidump_id, rproc_dumpfn_t dumpfn) { int ret; struct minidump_subsystem *subsystem; @@ -213,9 +323,10 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, rproc_dumpfn_t } if (rproc->elf_class == ELFCLASS64) - rproc_coredump_using_sections(rproc); + qcom_rproc_minidump(rproc, md_dev); else rproc_coredump(rproc); + clean_minidump: qcom_minidump_cleanup(rproc); } diff --git a/drivers/remoteproc/qcom_common.h b/drivers/remoteproc/qcom_common.h index af55811b6fc8..13368967c3ab 100644 --- a/drivers/remoteproc/qcom_common.h +++ b/drivers/remoteproc/qcom_common.h @@ -61,7 +61,8 @@ extern bool qcom_device_shutdown_in_progress; typedef void (*rproc_dumpfn_t)(struct rproc *rproc, struct rproc_dump_segment *segment, void *dest, size_t offset, size_t size); -void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, rproc_dumpfn_t dumpfn); +void qcom_minidump(struct rproc *rproc, struct device *md_dev, + unsigned int minidump_id, rproc_dumpfn_t dumpfn); void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink, const char *ssr_name); diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 5d9a9fa025d6..aac11dba804e 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -33,6 +33,7 @@ #define CREATE_TRACE_POINTS #include +#include #include "qcom_common.h" #include "qcom_pil_info.h" @@ -78,6 +79,7 @@ struct adsp_data { struct qcom_adsp { struct device *dev; + struct device *minidump_dev; struct rproc *rproc; struct qcom_q6v5 q6v5; @@ -168,7 +170,7 @@ static void adsp_minidump(struct rproc *rproc) if (rproc->dump_conf == RPROC_COREDUMP_DISABLED) goto exit; - qcom_minidump(rproc, adsp->minidump_id, adsp_segment_dump); + qcom_minidump(rproc, adsp->minidump_dev, adsp->minidump_id, adsp_segment_dump); exit: trace_rproc_qcom_event(dev_name(adsp->dev), "adsp_minidump", "exit"); @@ -999,6 +1001,7 @@ static int adsp_probe(struct platform_device *pdev) struct rproc *rproc; const char *fw_name; const struct rproc_ops *ops = &adsp_ops; + char md_dev_name[32]; int ret; bool signal_aop; @@ -1132,11 +1135,21 @@ static int adsp_probe(struct platform_device *pdev) if (ret) goto remove_subdevs; + snprintf(md_dev_name, ARRAY_SIZE(md_dev_name), "%s-md", pdev->dev.of_node->name); + adsp->minidump_dev = qcom_create_ramdump_device(md_dev_name, NULL); + if (!adsp->minidump_dev) { + dev_err(&pdev->dev, "Unable to create %s minidump device.\n", md_dev_name); + ret = -ENOMEM; + goto remove_attr_txn_id; + } + ret = rproc_add(rproc); if (ret) - goto remove_attr_txn_id; + goto destroy_minidump_dev; return 0; +destroy_minidump_dev: + qcom_destroy_ramdump_device(adsp->minidump_dev); remove_attr_txn_id: device_remove_file(adsp->dev, &dev_attr_txn_id); remove_subdevs: @@ -1158,6 +1171,7 @@ static int adsp_remove(struct platform_device *pdev) struct qcom_adsp *adsp = platform_get_drvdata(pdev); rproc_del(adsp->rproc); + qcom_destroy_ramdump_device(adsp->minidump_dev); device_remove_file(adsp->dev, &dev_attr_txn_id); qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev); qcom_remove_sysmon_subdev(adsp->sysmon);