Merge "remoteproc: qcom: pas: Rename subsystem minidump elf name"
This commit is contained in:
commit
1522b16b3e
@ -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 <linux/firmware.h>
|
||||
@ -17,9 +18,11 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soc/qcom/mdt_loader.h>
|
||||
#include <linux/soc/qcom/smem.h>
|
||||
#include <linux/devcoredump.h>
|
||||
#include <trace/hooks/remoteproc.h>
|
||||
#include <trace/events/rproc_qcom.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
@ -58,7 +58,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);
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright (C) 2016 Linaro Ltd
|
||||
* Copyright (C) 2014 Sony Mobile Communications AB
|
||||
* Copyright (c) 2012-2013, 2020-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
@ -28,6 +29,7 @@
|
||||
#include <linux/soc/qcom/smem_state.h>
|
||||
#include <linux/soc/qcom/qcom_aoss.h>
|
||||
#include <trace/events/rproc_qcom.h>
|
||||
#include <soc/qcom/qcom_ramdump.h>
|
||||
|
||||
#include "qcom_common.h"
|
||||
#include "qcom_pil_info.h"
|
||||
@ -66,6 +68,7 @@ struct adsp_data {
|
||||
|
||||
struct qcom_adsp {
|
||||
struct device *dev;
|
||||
struct device *minidump_dev;
|
||||
struct rproc *rproc;
|
||||
|
||||
struct qcom_q6v5 q6v5;
|
||||
@ -144,7 +147,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");
|
||||
@ -719,6 +722,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;
|
||||
|
||||
desc = of_device_get_match_data(&pdev->dev);
|
||||
@ -828,11 +832,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:
|
||||
@ -854,6 +868,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);
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -41,6 +42,21 @@ do { \
|
||||
#define set_phdr_property(arg, class, member, value) \
|
||||
set_xhdr_property(phdr, arg, class, member, value)
|
||||
|
||||
#define RAMDUMP_NUM_DEVICES 256
|
||||
#define RAMDUMP_NAME "ramdump"
|
||||
|
||||
static struct class *ramdump_class;
|
||||
static dev_t ramdump_dev;
|
||||
static DEFINE_MUTEX(rd_minor_mutex);
|
||||
static DEFINE_IDA(rd_minor_id);
|
||||
static bool ramdump_devnode_inited;
|
||||
|
||||
struct ramdump_device {
|
||||
char name[256];
|
||||
struct cdev cdev;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
struct qcom_ramdump_desc {
|
||||
void *data;
|
||||
struct completion dump_done;
|
||||
@ -250,6 +266,106 @@ int qcom_fw_elf_dump(struct firmware *fw, struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_fw_elf_dump);
|
||||
|
||||
static int ramdump_devnode_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ramdump_class = class_create(THIS_MODULE, RAMDUMP_NAME);
|
||||
ret = alloc_chrdev_region(&ramdump_dev, 0, RAMDUMP_NUM_DEVICES,
|
||||
RAMDUMP_NAME);
|
||||
if (ret) {
|
||||
pr_err("%s: unable to allocate major\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ramdump_devnode_inited = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *qcom_create_ramdump_device(const char *dev_name, struct device *parent)
|
||||
{
|
||||
int ret, minor;
|
||||
struct ramdump_device *rd_dev;
|
||||
|
||||
if (!dev_name) {
|
||||
pr_err("%s: Invalid device name.\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mutex_lock(&rd_minor_mutex);
|
||||
if (!ramdump_devnode_inited) {
|
||||
ret = ramdump_devnode_init();
|
||||
if (ret) {
|
||||
mutex_unlock(&rd_minor_mutex);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&rd_minor_mutex);
|
||||
|
||||
rd_dev = kzalloc(sizeof(struct ramdump_device), GFP_KERNEL);
|
||||
|
||||
if (!rd_dev)
|
||||
return NULL;
|
||||
|
||||
/* get a minor number */
|
||||
minor = ida_simple_get(&rd_minor_id, 0, RAMDUMP_NUM_DEVICES,
|
||||
GFP_KERNEL);
|
||||
if (minor < 0) {
|
||||
pr_err("%s: No more minor numbers left! rc:%d\n", __func__,
|
||||
minor);
|
||||
ret = -ENODEV;
|
||||
goto fail_out_of_minors;
|
||||
}
|
||||
|
||||
snprintf(rd_dev->name, ARRAY_SIZE(rd_dev->name), "%s",
|
||||
dev_name);
|
||||
|
||||
rd_dev->dev = device_create(ramdump_class, parent,
|
||||
MKDEV(MAJOR(ramdump_dev), minor),
|
||||
rd_dev, rd_dev->name);
|
||||
if (IS_ERR(rd_dev->dev)) {
|
||||
ret = PTR_ERR(rd_dev->dev);
|
||||
pr_err("%s: device_create failed for %s (%d)\n", __func__,
|
||||
dev_name, ret);
|
||||
goto fail_return_minor;
|
||||
}
|
||||
|
||||
cdev_init(&rd_dev->cdev, NULL);
|
||||
ret = cdev_add(&rd_dev->cdev, MKDEV(MAJOR(ramdump_dev), minor), 1);
|
||||
if (ret) {
|
||||
pr_err("%s: cdev_add failed for %s (%d)\n", __func__,
|
||||
dev_name, ret);
|
||||
goto fail_cdev_add;
|
||||
}
|
||||
|
||||
return (void *)rd_dev->dev;
|
||||
|
||||
fail_cdev_add:
|
||||
device_unregister(rd_dev->dev);
|
||||
fail_return_minor:
|
||||
ida_simple_remove(&rd_minor_id, minor);
|
||||
fail_out_of_minors:
|
||||
kfree(rd_dev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_create_ramdump_device);
|
||||
|
||||
void qcom_destroy_ramdump_device(void *dev)
|
||||
{
|
||||
struct ramdump_device *rd_dev = container_of(dev, struct ramdump_device, dev);
|
||||
int minor = MINOR(rd_dev->cdev.dev);
|
||||
|
||||
if (IS_ERR_OR_NULL(rd_dev))
|
||||
return;
|
||||
|
||||
cdev_del(&rd_dev->cdev);
|
||||
device_unregister(rd_dev->dev);
|
||||
ida_simple_remove(&rd_minor_id, minor);
|
||||
kfree(rd_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_destroy_ramdump_device);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Ramdump driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _QCOM_RAMDUMP_HEADER
|
||||
@ -18,11 +19,21 @@ struct qcom_dump_segment {
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_QCOM_RAMDUMP)
|
||||
extern void *qcom_create_ramdump_device(const char *dev_name, struct device *parent);
|
||||
extern void qcom_destroy_ramdump_device(void *dev);
|
||||
extern int qcom_elf_dump(struct list_head *segs, struct device *dev, unsigned char class);
|
||||
extern int qcom_dump(struct list_head *head, struct device *dev);
|
||||
extern int qcom_fw_elf_dump(struct firmware *fw, struct device *dev);
|
||||
extern bool dump_enabled(void);
|
||||
#else
|
||||
static inline void *qcom_create_ramdump_device(const char *dev_name,
|
||||
struct device *parent)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void qcom_destroy_ramdump_device(void *dev)
|
||||
{
|
||||
}
|
||||
static inline int qcom_elf_dump(struct list_head *segs, struct device *dev, unsigned char class)
|
||||
{
|
||||
return -ENODEV;
|
||||
|
Loading…
Reference in New Issue
Block a user