diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index 8efe60487b48..45e20bfa427c 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -263,3 +263,11 @@ config PSTORE_BLK_FTRACE_SIZE NOTE that, both Kconfig and module parameters can configure pstore/blk, but module parameters have priority over Kconfig. + +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. diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index bbf241a431f2..32318e6d6519 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -24,6 +24,11 @@ #include #include +#ifdef CONFIG_PSTORE_MCU_LOG +#include +#include +#endif + #include "internal.h" #define PSTORE_NAMELEN 64 @@ -130,7 +135,16 @@ 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 + size_t size = 0; + struct pstore_record *record = ps->record; + if (record->type == PSTORE_TYPE_MCU_LOG) { + size = ramoops_pstore_read_for_mcu_log(ps->record); + size = simple_read_from_buffer(userbuf, count, ppos, record->buf, size); + return size; + } +#endif if (ps->record->type == PSTORE_TYPE_FTRACE) return seq_read(file, userbuf, count, ppos); return simple_read_from_buffer(userbuf, count, ppos, diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index b1ebf7b61732..1673f3cb23f3 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -58,6 +58,9 @@ static const char * const pstore_type_names[] = { "powerpc-common", "pmsg", "powerpc-opal", +#ifdef CONFIG_PSTORE_MCU_LOG + "mcu-log", +#endif }; static int pstore_new_entry; diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 7183fe4b5f72..cb4c621bb2b2 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -81,6 +81,9 @@ struct ramoops_context { 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; @@ -88,6 +91,9 @@ struct ramoops_context { size_t console_size; size_t ftrace_size; size_t pmsg_size; +#ifdef CONFIG_PSTORE_MCU_LOG + size_t mcu_log_size; +#endif u32 flags; struct persistent_ram_ecc_info ecc_info; unsigned int max_dump_cnt; @@ -98,6 +104,10 @@ struct ramoops_context { 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; }; @@ -174,6 +184,28 @@ static bool prz_ok(struct persistent_ram_zone *prz) persistent_ram_ecc_string(prz, NULL, 0)); } +#ifdef CONFIG_PSTORE_MCU_LOG +ssize_t ramoops_pstore_read_for_mcu_log(struct pstore_record *record) +{ + struct ramoops_context *cxt = record->psi->data; + struct persistent_ram_zone *prz; + + if (!cxt) + return 0; + + prz = cxt->mcu_przs[record->id]; + + if (!prz) + return 0; + + persistent_ram_free_old(prz); + persistent_ram_save_old(prz); + record->buf = prz->old_log; + record->size = prz->old_log_size; + return record->size; +} +#endif + static ssize_t ramoops_pstore_read(struct pstore_record *record) { ssize_t size = 0; @@ -257,12 +289,27 @@ 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++, record); + if (!prz_ok(prz)) + continue; + } + } +#endif if (!prz_ok(prz)) { size = 0; goto out; } +#ifdef CONFIG_PSTORE_MCU_LOG + if (record->type == PSTORE_TYPE_MCU_LOG) { + persistent_ram_free_old(prz); + persistent_ram_save_old(prz); + } +#endif + size = persistent_ram_old_size(prz) - header_length; /* ECC correction notice */ @@ -468,6 +515,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, @@ -687,6 +743,10 @@ static int ramoops_parse_dt(struct platform_device *pdev, parse_u32("ecc-size", pdata->ecc_info.ecc_size, 0); parse_u32("flags", pdata->flags, 0); parse_u32("max-reason", pdata->max_reason, pdata->max_reason); +#ifdef CONFIG_PSTORE_MCU_LOG + parse_u32("mcu-log-size", pdata->mcu_log_size, 0); + parse_u32("mcu-log-count", pdata->max_mcu_log_cnt, 0); +#endif #undef parse_u32 @@ -722,6 +782,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 /* * Only a single ramoops area allowed at a time, so fail extra @@ -746,14 +809,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)) @@ -762,7 +832,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; @@ -772,11 +845,19 @@ static int ramoops_probe(struct platform_device *pdev) cxt->pmsg_size = pdata->pmsg_size; 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("dmesg", dev, cxt, &cxt->dprzs, &paddr, dump_mem_sz, cxt->record_size, &cxt->max_dump_cnt, 0, 0); @@ -804,6 +885,17 @@ static int ramoops_probe(struct platform_device *pdev) 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. @@ -822,7 +914,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 diff --git a/include/linux/pstore.h b/include/linux/pstore.h index eb93a54cff31..2aac7a063196 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -38,6 +38,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 /* End of the list */ PSTORE_TYPE_MAX @@ -202,6 +205,9 @@ struct pstore_info { #define PSTORE_FLAGS_CONSOLE BIT(1) #define PSTORE_FLAGS_FTRACE BIT(2) #define PSTORE_FLAGS_PMSG BIT(3) +#ifdef CONFIG_PSTORE_MCU_LOG +#define PSTORE_FLAGS_MCU_LOG BIT(4) +#endif extern int pstore_register(struct pstore_info *); extern void pstore_unregister(struct pstore_info *); diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index 9f16afec7290..ff42d9a3fc90 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -116,6 +116,9 @@ void *persistent_ram_old(struct persistent_ram_zone *prz); void persistent_ram_free_old(struct persistent_ram_zone *prz); ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz, char *str, size_t len); +#ifdef CONFIG_PSTORE_MCU_LOG +ssize_t ramoops_pstore_read_for_mcu_log(struct pstore_record *record); +#endif /* * Ramoops platform data @@ -133,6 +136,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 max_reason; u32 flags; struct persistent_ram_ecc_info ecc_info;