fs: pstore: add mcu log

Signed-off-by: Huibin Hong <huibin.hong@rock-chips.com>
Change-Id: Iaa73a2826f5f4d52095399fb7879b8d099676b4e
This commit is contained in:
Huibin Hong
2021-03-10 17:12:22 +08:00
committed by Tao Huang
parent 2ea9965c24
commit f1b65cf0e1
6 changed files with 175 additions and 42 deletions

View File

@@ -165,3 +165,11 @@ config PSTORE_RAM
"ramoops.ko".
For more information, see Documentation/admin-guide/ramoops.rst.
config PSTORE_MCU_LOG
bool "Print mcu log by linux"
depends on PSTORE
help
When your soc has several mcu, you can get their log by cat command
through linux shell
If unsure, say N.

View File

@@ -37,6 +37,11 @@
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#ifdef CONFIG_PSTORE_MCU_LOG
#include <linux/pstore_ram.h>
#include <linux/io.h>
#endif
#include "internal.h"
#define PSTORE_NAMELEN 64
@@ -139,7 +144,42 @@ static ssize_t pstore_file_read(struct file *file, char __user *userbuf,
{
struct seq_file *sf = file->private_data;
struct pstore_private *ps = sf->private;
#ifdef CONFIG_PSTORE_MCU_LOG
struct pstore_record *record = ps->record;
struct ramoops_context *cxt = record->psi->data;
struct persistent_ram_zone *prz;
struct persistent_ram_buffer *buffer;
char *log_tmp;
size_t size, start, n;
if (ps->record->type == PSTORE_TYPE_MCU_LOG) {
if (!cxt)
return count;
prz = cxt->mcu_przs[record->id];
if (!prz)
return count;
buffer = prz->buffer;
if (!buffer)
return count;
size = atomic_read(&buffer->size);
start = atomic_read(&buffer->start);
log_tmp = kmalloc(size, GFP_KERNEL);
if (!log_tmp)
return count;
memcpy_fromio(log_tmp, &buffer->data[start], size - start);
memcpy_fromio(log_tmp + size - start, &buffer->data[0], start);
n = simple_read_from_buffer(userbuf, count, ppos, log_tmp, size);
kfree(log_tmp);
return n;
}
#endif
if (ps->record->type == PSTORE_TYPE_FTRACE)
return seq_read(file, userbuf, count, ppos);
return simple_read_from_buffer(userbuf, count, ppos,
@@ -372,6 +412,11 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record)
scnprintf(name, sizeof(name), "powerpc-opal-%s-%llu",
record->psi->name, record->id);
break;
#ifdef CONFIG_PSTORE_MCU_LOG
case PSTORE_TYPE_MCU_LOG:
scnprintf(name, sizeof(name), "mcu-log-%llu", record->id);
break;
#endif
case PSTORE_TYPE_UNKNOWN:
scnprintf(name, sizeof(name), "unknown-%s-%llu",
record->psi->name, record->id);

View File

@@ -83,32 +83,6 @@ MODULE_PARM_DESC(ramoops_ecc,
"ECC buffer size in bytes (1 is a special value, means 16 "
"bytes ECC)");
struct ramoops_context {
struct persistent_ram_zone **dprzs; /* Oops dump zones */
struct persistent_ram_zone *cprz; /* Console zone */
struct persistent_ram_zone **fprzs; /* Ftrace zones */
struct persistent_ram_zone *mprz; /* PMSG zone */
phys_addr_t phys_addr;
unsigned long size;
unsigned int memtype;
size_t record_size;
size_t console_size;
size_t ftrace_size;
size_t pmsg_size;
int dump_oops;
u32 flags;
struct persistent_ram_ecc_info ecc_info;
unsigned int max_dump_cnt;
unsigned int dump_write_cnt;
/* _read_cnt need clear on ramoops_pstore_open */
unsigned int dump_read_cnt;
unsigned int console_read_cnt;
unsigned int max_ftrace_cnt;
unsigned int ftrace_read_cnt;
unsigned int pmsg_read_cnt;
struct pstore_info pstore;
};
static struct platform_device *dummy;
static struct ramoops_platform_data *dummy_data;
@@ -326,14 +300,29 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record)
record->id = 0;
}
}
#ifdef CONFIG_PSTORE_MCU_LOG
if (!prz_ok(prz)) {
while (cxt->mcu_log_read_cnt < cxt->max_mcu_log_cnt && !prz) {
prz = ramoops_get_next_prz(cxt->mcu_przs, &cxt->mcu_log_read_cnt,
cxt->max_mcu_log_cnt, &record->id,
&record->type,
PSTORE_TYPE_MCU_LOG, 0);
if (!prz_ok(prz))
continue;
}
}
#endif
if (!prz_ok(prz)) {
size = 0;
goto out;
}
size = persistent_ram_old_size(prz) - header_length;
#ifdef CONFIG_PSTORE_MCU_LOG
/* don't copy mcu log */
if (record->type == PSTORE_TYPE_MCU_LOG)
goto out;
#endif
/* ECC correction notice */
record->ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);
@@ -538,6 +527,15 @@ static void ramoops_free_przs(struct ramoops_context *cxt)
kfree(cxt->fprzs);
cxt->max_ftrace_cnt = 0;
}
#ifdef CONFIG_PSTORE_MCU_LOG
/* Free mcu log PRZs */
if (cxt->mcu_przs) {
for (i = 0; i < cxt->max_mcu_log_cnt; i++)
persistent_ram_free(cxt->mcu_przs[i]);
kfree(cxt->mcu_przs);
cxt->max_mcu_log_cnt = 0;
}
#endif
}
static int ramoops_init_przs(const char *name,
@@ -716,7 +714,10 @@ static int ramoops_parse_dt(struct platform_device *pdev,
parse_size("pmsg-size", pdata->pmsg_size);
parse_size("ecc-size", pdata->ecc_info.ecc_size);
parse_size("flags", pdata->flags);
#ifdef CONFIG_PSTORE_MCU_LOG
parse_size("mcu-log-size", pdata->mcu_log_size);
parse_size("mcu-log-count", pdata->max_mcu_log_cnt);
#endif
#undef parse_size
return 0;
@@ -731,6 +732,9 @@ static int ramoops_probe(struct platform_device *pdev)
size_t dump_mem_sz;
phys_addr_t paddr;
int err = -EINVAL;
#ifdef CONFIG_PSTORE_MCU_LOG
int i = 0;
#endif
if (dev_of_node(dev) && !pdata) {
pdata = &pdata_local;
@@ -755,14 +759,21 @@ static int ramoops_probe(struct platform_device *pdev)
pr_err("NULL platform data\n");
goto fail_out;
}
#ifdef CONFIG_PSTORE_MCU_LOG
if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size &&
!pdata->ftrace_size && !pdata->pmsg_size && !pdata->mcu_log_size)) {
pr_err("The memory size and the record/console size must be "
"non-zero\n");
goto fail_out;
}
#else
if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size &&
!pdata->ftrace_size && !pdata->pmsg_size)) {
pr_err("The memory size and the record/console size must be "
"non-zero\n");
goto fail_out;
}
#endif
if (pdata->record_size && !is_power_of_2(pdata->record_size))
pdata->record_size = rounddown_pow_of_two(pdata->record_size);
if (pdata->console_size && !is_power_of_2(pdata->console_size))
@@ -771,7 +782,10 @@ static int ramoops_probe(struct platform_device *pdev)
pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size);
if (pdata->pmsg_size && !is_power_of_2(pdata->pmsg_size))
pdata->pmsg_size = rounddown_pow_of_two(pdata->pmsg_size);
#ifdef CONFIG_PSTORE_MCU_LOG
if (pdata->mcu_log_size && !is_power_of_2(pdata->mcu_log_size))
pdata->mcu_log_size = rounddown_pow_of_two(pdata->mcu_log_size);
#endif
cxt->size = pdata->mem_size;
cxt->phys_addr = pdata->mem_address;
cxt->memtype = pdata->mem_type;
@@ -782,11 +796,18 @@ static int ramoops_probe(struct platform_device *pdev)
cxt->dump_oops = pdata->dump_oops;
cxt->flags = pdata->flags;
cxt->ecc_info = pdata->ecc_info;
#ifdef CONFIG_PSTORE_MCU_LOG
cxt->mcu_log_size = pdata->mcu_log_size;
cxt->max_mcu_log_cnt = pdata->max_mcu_log_cnt;
#endif
paddr = cxt->phys_addr;
dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size
- cxt->pmsg_size;
#ifdef CONFIG_PSTORE_MCU_LOG
dump_mem_sz -= cxt->mcu_log_size;
#endif
err = ramoops_init_przs("dump", dev, cxt, &cxt->dprzs, &paddr,
dump_mem_sz, cxt->record_size,
&cxt->max_dump_cnt, 0, 0);
@@ -813,7 +834,17 @@ static int ramoops_probe(struct platform_device *pdev)
cxt->pmsg_size, 0);
if (err)
goto fail_init_mprz;
#ifdef CONFIG_PSTORE_MCU_LOG
err = ramoops_init_przs("mcu_log", dev, cxt, &cxt->mcu_przs, &paddr,
cxt->mcu_log_size, -1,
&cxt->max_mcu_log_cnt, 0, 0);
for (i = 0; i < cxt->max_mcu_log_cnt; i++)
pr_info("mcu%d log start:0x%08x size:0x%08x\n",
i, cxt->mcu_przs[i]->paddr, cxt->mcu_przs[i]->size);
if (err)
goto fail_clear;
#endif
cxt->pstore.data = cxt;
/*
* Prepare frontend flags based on which areas are initialized.
@@ -830,7 +861,10 @@ static int ramoops_probe(struct platform_device *pdev)
cxt->pstore.flags |= PSTORE_FLAGS_FTRACE;
if (cxt->pmsg_size)
cxt->pstore.flags |= PSTORE_FLAGS_PMSG;
#ifdef CONFIG_PSTORE_MCU_LOG
if (cxt->mcu_log_size)
cxt->pstore.flags |= PSTORE_FLAGS_MCU_LOG;
#endif
/*
* Since bufsize is only used for dmesg crash dumps, it
* must match the size of the dprz record (after PRZ header

View File

@@ -29,13 +29,6 @@
#include <linux/vmalloc.h>
#include <asm/page.h>
struct persistent_ram_buffer {
uint32_t sig;
atomic_t start;
atomic_t size;
uint8_t data[0];
};
#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
static inline size_t buffer_size(struct persistent_ram_zone *prz)

View File

@@ -44,6 +44,9 @@ enum pstore_type_id {
PSTORE_TYPE_PPC_COMMON = 6,
PSTORE_TYPE_PMSG = 7,
PSTORE_TYPE_PPC_OPAL = 8,
#ifdef CONFIG_PSTORE_MCU_LOG
PSTORE_TYPE_MCU_LOG = 9,
#endif
PSTORE_TYPE_UNKNOWN = 255
};
@@ -196,7 +199,9 @@ struct pstore_info {
#define PSTORE_FLAGS_CONSOLE (1 << 1)
#define PSTORE_FLAGS_FTRACE (1 << 2)
#define PSTORE_FLAGS_PMSG (1 << 3)
#ifdef CONFIG_PSTORE_MCU_LOG
#define PSTORE_FLAGS_MCU_LOG (1 << 4)
#endif
extern int pstore_register(struct pstore_info *);
extern void pstore_unregister(struct pstore_info *);

View File

@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/pstore.h>
/*
* Choose whether access to the RAM zone requires locking or not. If a zone
@@ -34,6 +35,13 @@
struct persistent_ram_buffer;
struct rs_control;
struct persistent_ram_buffer {
uint32_t sig;
atomic_t start;
atomic_t size;
uint8_t data[0];
};
struct persistent_ram_ecc_info {
int block_size;
int ecc_size;
@@ -63,6 +71,42 @@ struct persistent_ram_zone {
size_t old_log_size;
};
struct ramoops_context {
struct persistent_ram_zone **dprzs; /* Oops dump zones */
struct persistent_ram_zone *cprz; /* Console zone */
struct persistent_ram_zone **fprzs; /* Ftrace zones */
struct persistent_ram_zone *mprz; /* PMSG zone */
#ifdef CONFIG_PSTORE_MCU_LOG
struct persistent_ram_zone **mcu_przs; /* MCU log zones */
#endif
phys_addr_t phys_addr;
unsigned long size;
unsigned int memtype;
size_t record_size;
size_t console_size;
size_t ftrace_size;
size_t pmsg_size;
#ifdef CONFIG_PSTORE_MCU_LOG
size_t mcu_log_size;
#endif
int dump_oops;
u32 flags;
struct persistent_ram_ecc_info ecc_info;
unsigned int max_dump_cnt;
unsigned int dump_write_cnt;
/* _read_cnt need clear on ramoops_pstore_open */
unsigned int dump_read_cnt;
unsigned int console_read_cnt;
unsigned int max_ftrace_cnt;
unsigned int ftrace_read_cnt;
unsigned int pmsg_read_cnt;
#ifdef CONFIG_PSTORE_MCU_LOG
unsigned int mcu_log_read_cnt;
unsigned int max_mcu_log_cnt;
#endif
struct pstore_info pstore;
};
struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
u32 sig, struct persistent_ram_ecc_info *ecc_info,
unsigned int memtype, u32 flags);
@@ -97,6 +141,10 @@ struct ramoops_platform_data {
unsigned long console_size;
unsigned long ftrace_size;
unsigned long pmsg_size;
#ifdef CONFIG_PSTORE_MCU_LOG
unsigned long mcu_log_size;
unsigned long max_mcu_log_cnt;
#endif
int dump_oops;
u32 flags;
struct persistent_ram_ecc_info ecc_info;