mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 19:47:08 +02:00
soc: qcom: ramdump: Add support to create/destroy ramdump device
There was a requirement from client drivers to create ramdump device with a given name so that they control the name of the elf. This change adds the support to create/destroy ramdump device. Change-Id: I411cc92a1b41d44e8b6fef95d383613280dae0c2 Signed-off-by: Mukesh Ojha <quic_mojha@quicinc.com> Signed-off-by: Naman Jain <quic_namajain@quicinc.com>
This commit is contained in:
parent
88f0bf1775
commit
d9691a6342
|
|
@ -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>
|
||||
|
|
@ -43,6 +44,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;
|
||||
|
|
@ -252,6 +268,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");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _QCOM_RAMDUMP_HEADER
|
||||
|
|
@ -19,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