kernel_samsung_a53x/drivers/soc/samsung/debug/debug-snapshot-qd.c

254 lines
6.4 KiB
C
Raw Normal View History

2024-06-15 21:02:09 +02:00
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*/
#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/platform_device.h>
#include <linux/kallsyms.h>
#include <linux/sched/clock.h>
#include <asm-generic/sections.h>
#include <soc/samsung/debug-snapshot.h>
#include "debug-snapshot-local.h"
#define DSS_QD_MAX_NUM_ENTRIES (48)
#define DSS_QD_MAX_NAME_LENGTH (16)
#define DSS_QD_ATTR_LOG (0)
#define DSS_QD_ATTR_ARRAY (1)
#define DSS_QD_ATTR_STRUCT (2)
#define DSS_QD_ATTR_STACK (3)
#define DSS_QD_ATTR_SYMBOL (4)
#define DSS_QD_ATTR_BINARY (5)
#define DSS_QD_ATTR_ELF (6)
#define DSS_QD_ATTR_SKIP_ENCRYPT (1 << 31)
struct dbg_snapshot_qd_region {
char name[DSS_QD_MAX_NAME_LENGTH];
char struct_name[DSS_QD_MAX_NAME_LENGTH];
u64 virt_addr;
u64 phys_addr;
u64 size;
u32 attr;
u32 magic;
};
struct dbg_snapshot_qd_table {
struct dbg_snapshot_qd_region *entry;
u32 num_regions;
u32 magic_key;
u32 version;
};
static struct dbg_snapshot_qd_table dss_qd_table;
static DEFINE_SPINLOCK(qd_lock);
static struct device *qdump_dev = NULL;
int dbg_snapshot_qd_add_region(void *v_entry, u32 attr)
{
struct dbg_snapshot_qd_region *entry =
(struct dbg_snapshot_qd_region *)v_entry;
struct dbg_snapshot_qd_region *qd_entry;
u32 entries, i;
int ret = 0;
if (!entry || !entry->virt_addr ||
!entry->phys_addr || !strlen(entry->name)) {
dev_err(qdump_dev, "Invalid entry details\n");
return -EINVAL;
}
if ((strlen(entry->name) > DSS_QD_MAX_NAME_LENGTH) ||
(strlen(entry->struct_name) > DSS_QD_MAX_NAME_LENGTH)) {
dev_err(qdump_dev, "over string names\n");
return -EINVAL;
}
spin_lock(&qd_lock);
entries = dss_qd_table.num_regions;
if (entries >= DSS_QD_MAX_NUM_ENTRIES) {
dev_err(qdump_dev, "entries is full, No allowed more\n");
spin_unlock(&qd_lock);
return -ENOMEM;
}
for (i = 0; i < entries; i++) {
qd_entry = &dss_qd_table.entry[i];
if (!strncmp(qd_entry->name, entry->name,
strlen(entry->name))) {
dev_err(qdump_dev, "entry name is exist in array : %s",
entry->name);
spin_unlock(&qd_lock);
return -EINVAL;
}
}
qd_entry = &dss_qd_table.entry[entries];
strlcpy(qd_entry->name, entry->name, sizeof(qd_entry->name));
strlcpy(qd_entry->struct_name, entry->struct_name, sizeof(qd_entry->struct_name));
qd_entry->virt_addr = entry->virt_addr;
qd_entry->phys_addr = entry->phys_addr;
qd_entry->size = entry->size;
qd_entry->magic = DSS_SIGN_MAGIC | entries;
qd_entry->attr = attr;
dss_qd_table.num_regions = entries + 1;
spin_unlock(&qd_lock);
dev_info(qdump_dev, "Success to add (0x%x: %s)\n",
entries, qd_entry->name);
return ret;
}
EXPORT_SYMBOL(dbg_snapshot_qd_add_region);
bool dbg_snapshot_qd_enable(void)
{
bool ret = false;
if (dss_dpm.dump_mode == QUICK_DUMP)
ret = true;
return ret;
}
EXPORT_SYMBOL(dbg_snapshot_qd_enable);
static void register_dss_log_item(void)
{
struct dbg_snapshot_qd_region qd_entry;
int item_num = dbg_snapshot_log_get_num_items();
struct dbg_snapshot_log_item *item;
int i;
for (i = 0; i < item_num; i++){
item = (struct dbg_snapshot_log_item *)
dbg_snapshot_log_get_item_by_index(i);
if (item->entry.enabled) {
strlcpy(qd_entry.name, item->name,
sizeof(qd_entry.name));
strlcpy(qd_entry.struct_name, item->name,
sizeof(qd_entry.struct_name));
qd_entry.virt_addr = item->entry.vaddr;
qd_entry.phys_addr = item->entry.paddr;
qd_entry.size = item->entry.size;
if (dbg_snapshot_qd_add_region(&qd_entry,
DSS_QD_ATTR_STRUCT))
dev_err(qdump_dev, "Failed to add "
"dss_log_item : %s\n",
item->name);
}
}
}
static void register_dss_item(void)
{
struct dbg_snapshot_qd_region qd_entry;
int item_num = dbg_snapshot_get_num_items();
struct dbg_snapshot_item *item;
int i;
for (i = 0; i < item_num; i++){
if (i == DSS_ITEM_KEVENTS_ID)
continue;
item = (struct dbg_snapshot_item *)
dbg_snapshot_get_item_by_index(i);
if (item->entry.enabled) {
strlcpy(qd_entry.name, item->name,
sizeof(qd_entry.name));
qd_entry.struct_name[0] = '\0';
qd_entry.virt_addr = item->entry.vaddr;
qd_entry.phys_addr = item->entry.paddr;
qd_entry.size = item->entry.size;
if (dbg_snapshot_qd_add_region(&qd_entry,
DSS_QD_ATTR_BINARY))
dev_err(qdump_dev, "Failed to add "
"dss_item : %s\n",
item->name);
}
}
}
static void dbg_snapshot_qd_list_dump(void)
{
struct dbg_snapshot_qd_region *entry;
unsigned long i, size = 0;
if (!qdump_dev)
return;
dev_info(qdump_dev, "quickdump physical / virtual memory layout:\n");
for (i = 0; i < dss_qd_table.num_regions; i++) {
entry = &dss_qd_table.entry[i];
dev_info(qdump_dev, "%-16s: -%16s: phys:0x%zx / virt:0x%zx / size:0x%zx\n",
entry->name,
entry->struct_name,
entry->phys_addr,
entry->virt_addr,
entry->size);
size += entry->size;
}
dev_info(qdump_dev, "total_quick_dump_size: %ldKB, quick_dump_entry: 0x%x\n",
size / SZ_1K, __raw_readq(dbg_snapshot_get_header_vaddr() + DSS_OFFSET_QD_ENTRY));
}
static int dbg_snapshot_qd_probe(struct platform_device *pdev)
{
/* Need to wait for checking whether quick-dump is enabled or not */
if (!dbg_snapshot_get_enable())
return -EPROBE_DEFER;
if (dss_dpm.dump_mode != QUICK_DUMP) {
dev_err(&pdev->dev, "No Quick dump mode\n");
return -ENODEV;
}
qdump_dev = &pdev->dev;
dss_qd_table.entry = devm_kzalloc(qdump_dev, (DSS_QD_MAX_NUM_ENTRIES *
sizeof(struct dbg_snapshot_qd_region)), GFP_KERNEL);
if (!dss_qd_table.entry) {
dev_err(&pdev->dev, "failed alloc of dss_qd_table\n");
dbg_snapshot_set_qd_entry(0);
return -ENOMEM;
}
qdump_dev = &pdev->dev;
dbg_snapshot_set_qd_entry((unsigned long)dss_qd_table.entry);
dss_qd_table.num_regions = 0;
dev_info(&pdev->dev, "Success to initialization\n");
register_dss_item();
register_dss_log_item();
dbg_snapshot_qd_list_dump();
dev_info(&pdev->dev, "%s successful.\n", __func__);
return 0;
}
static const struct of_device_id dbg_snapshot_qd_matches[] = {
{ .compatible = "debug-snapshot,qdump", },
{},
};
MODULE_DEVICE_TABLE(of, dbg_snapshot_qd_matches);
static struct platform_driver dbg_snapshot_qd_driver = {
.probe = dbg_snapshot_qd_probe,
.driver = {
.name = "debug-snapshot-qdump",
.of_match_table = of_match_ptr(dbg_snapshot_qd_matches),
},
};
module_platform_driver(dbg_snapshot_qd_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Debug-Snapshot-qdump");