From 7a776002f4f0609d606b36467c04d78f9a52a066 Mon Sep 17 00:00:00 2001 From: wang_yonghai Date: Tue, 22 Oct 2024 15:53:25 +0800 Subject: [PATCH] add kernel-6.6 pstore and blackbox Signed-off-by: wang_yonghai --- drivers/staging/blackbox/blackbox_common.c | 48 +------- drivers/staging/blackbox/blackbox_core.c | 9 +- drivers/staging/blackbox/blackbox_storage.c | 27 ++--- drivers/staging/hievent/hievent_driver.c | 1 + .../staging/hisysevent/hiview_hisysevent.c | 35 +----- drivers/staging/zerohung/zrhung_event.c | 27 +++++ fs/pstore/Kconfig | 63 ++++++++++ fs/pstore/internal.h | 3 + fs/pstore/platform.c | 109 ++++++++++++++++++ fs/pstore/ram.c | 47 +++++++- include/dfx/zrhung.h | 1 + include/linux/pstore.h | 8 ++ include/linux/pstore_ram.h | 1 + 13 files changed, 276 insertions(+), 103 deletions(-) diff --git a/drivers/staging/blackbox/blackbox_common.c b/drivers/staging/blackbox/blackbox_common.c index 5e4d16ce1cb2..cfd5212b695e 100644 --- a/drivers/staging/blackbox/blackbox_common.c +++ b/drivers/staging/blackbox/blackbox_common.c @@ -24,9 +24,6 @@ void sys_reset(void) void change_own(char *path, int uid, int gid) { -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 10, 197) - mm_segment_t old_fs; -#endif int ret = -1; if (unlikely(!path || uid == -1 || gid == -1)) { @@ -34,17 +31,9 @@ void change_own(char *path, int uid, int gid) return; } -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 10, 197) - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif ret = ksys_chown(path, uid, gid); if (ret != 0) bbox_print_err("ksys_chown [%s] failed, ret: %d\n", path, ret); - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 10, 197) - set_fs(old_fs); -#endif } int full_write_file(const char *pfile_path, char *buf, @@ -52,9 +41,6 @@ int full_write_file(const char *pfile_path, char *buf, { struct file *filp = NULL; char *pathname = NULL; -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 10, 197) - mm_segment_t old_fs; -#endif loff_t pos = 0; int ret = -1; @@ -70,16 +56,7 @@ int full_write_file(const char *pfile_path, char *buf, return -EBADF; } -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 10, 197) - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif - - ret = vfs_write(filp, buf, buf_size, &pos); - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 10, 197) - set_fs(old_fs); -#endif + ret = __kernel_write(filp, (const void *)buf, buf_size, &pos); file_close(filp); @@ -101,11 +78,7 @@ int file_exists(const char *name) if (ret) return ret; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0) ret = inode_permission(&nop_mnt_idmap, d_inode(path.dentry), MAY_ACCESS); -#else - ret = inode_permission(d_inode(path.dentry), MAY_ACCESS); -#endif path_put(&path); return ret; } @@ -127,11 +100,7 @@ static int create_new_dir(char *name) if (IS_ERR(dentry)) return PTR_ERR(dentry); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0) ret = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, BBOX_DIR_LIMIT); -#else - ret = vfs_mkdir(d_inode(path.dentry), dentry, BBOX_DIR_LIMIT); -#endif if (ret && ret != -EEXIST) bbox_print_err("Create dir [%s] failed! ret: %d\n", name, ret); @@ -228,19 +197,8 @@ static inline void unlock_dir(struct dentry *dentry) struct file *file_open(const char *filename, int open_mode, int mode) { struct file *filp = NULL; -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 10, 197) - mm_segment_t old_fs; -#endif - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 10, 197) - old_fs = get_fs(); - set_fs(KERNEL_DS); -#endif filp = filp_open(filename, open_mode, mode); -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 10, 197) - set_fs(old_fs); -#endif return filp; } @@ -267,11 +225,7 @@ int file_delete(struct file *filp) if (dentry->d_parent == parent) { dget(dentry); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0) ret = vfs_unlink(&nop_mnt_idmap, d_inode(parent), dentry, NULL); -#else - ret = vfs_unlink(d_inode(parent), dentry, NULL); -#endif dput(dentry); } diff --git a/drivers/staging/blackbox/blackbox_core.c b/drivers/staging/blackbox/blackbox_core.c index 950e0ebdd5c0..c5fa94dc6f31 100644 --- a/drivers/staging/blackbox/blackbox_core.c +++ b/drivers/staging/blackbox/blackbox_core.c @@ -204,6 +204,7 @@ static void save_history_log(const char *log_root_dir, struct error_info *info, { char history_log_path[PATH_MAX_LEN]; char *buf; + const char *bbox_sysreset; if (unlikely(!log_root_dir || !info || !timestamp)) { bbox_print_err("log_root_dir: %p, info: %p, timestamp: %p\n", @@ -215,13 +216,9 @@ static void save_history_log(const char *log_root_dir, struct error_info *info, if (!buf) return; memset(buf, 0, HISTORY_LOG_MAX_LEN + 1); - - scnprintf(buf, HISTORY_LOG_MAX_LEN, HISTORY_LOG_FORMAT, - get_top_category(info->module, info->event), info->module, - info->category, info->event, timestamp, - need_sys_reset ? "true" : "false", info->error_desc, log_root_dir); #ifdef CONFIG_DFX_ZEROHUNG - zrhung_send_event("KERNEL_VENDOR", info->category, info->error_desc); + bbox_sysreset = need_sys_reset ? "true" : "false"; + zrhung_send_event_bbox("KERNEL_VENDOR", info->category, timestamp, bbox_sysreset); #endif memset(history_log_path, 0, sizeof(history_log_path)); scnprintf(history_log_path, sizeof(history_log_path) - 1, diff --git a/drivers/staging/blackbox/blackbox_storage.c b/drivers/staging/blackbox/blackbox_storage.c index 635e3aa036ab..117d05ea4109 100644 --- a/drivers/staging/blackbox/blackbox_storage.c +++ b/drivers/staging/blackbox/blackbox_storage.c @@ -20,8 +20,11 @@ char *storage_material = #endif const struct reboot_crashlog_storage *storage_lastword __ro_after_init; +bool g_blackbox_flag = false; +EXPORT_SYMBOL(g_blackbox_flag); + #if IS_ENABLED(CONFIG_DEF_BLACKBOX_STORAGE_BY_MEMORY) -static DEFINE_SEMAPHORE(kmsg_sem); +static DEFINE_SEMAPHORE(kmsg_sem, 1); static char *lastlog; unsigned int lastlog_len; static int get_log_by_memory(void *in, unsigned int inlen) @@ -45,7 +48,7 @@ static void do_kmsg_dump(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason) { struct fault_log_info *pinfo; - + struct kmsg_dump_iter iter; if (unlikely(!lastlog)) return; @@ -54,6 +57,7 @@ static void do_kmsg_dump(struct kmsg_dumper *dumper, bbox_print_err("down_trylock failed!\n"); return; } + kmsg_dump_rewind(&iter); pinfo = (struct fault_log_info *)lastlog; (void)kmsg_dump_get_buffer(dumper, true, lastlog + sizeof(*pinfo), lastlog_len - sizeof(*pinfo), (size_t *)&pinfo->len); @@ -121,7 +125,6 @@ static int get_log_by_pstore(void *in, unsigned int inlen) char pstore_file[PATH_MAX_LEN]; struct file *filp = NULL; char *pathname = NULL; - mm_segment_t old_fs; void *pbuf = NULL; loff_t pos = 0; static int retry; @@ -142,21 +145,10 @@ static int get_log_by_pstore(void *in, unsigned int inlen) PTR_ERR(filp)); return -EBADF; } - memset(in, 0, inlen); - pbuf = in; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - ret = vfs_read(filp, pbuf, inlen, &pos); - if (ret < 0) { - pathname = getfullpath(filp); - bbox_print_err("read %s failed! err is [%d]\n", pathname ? pathname : "", - ret); - goto __error; - } - set_fs(old_fs); + printk("bbox %s %d, read %s is succ\n", __func__, __LINE__, getfullpath(filp) ? getfullpath(filp) : ""); + g_blackbox_flag = true; + file_close(filp); file_delete(filp); return 0; @@ -164,7 +156,6 @@ static int get_log_by_pstore(void *in, unsigned int inlen) return -EBADF; __error: - set_fs(old_fs); file_close(filp); return -EIO; } diff --git a/drivers/staging/hievent/hievent_driver.c b/drivers/staging/hievent/hievent_driver.c index 36fa7eb06b09..9697432f22d2 100644 --- a/drivers/staging/hievent/hievent_driver.c +++ b/drivers/staging/hievent/hievent_driver.c @@ -252,6 +252,7 @@ int hievent_write_internal(const char *buffer, size_t buf_len) return retval; } +EXPORT_SYMBOL(hievent_write_internal); static unsigned int hievent_poll(struct file *filep, poll_table *wait) { diff --git a/drivers/staging/hisysevent/hiview_hisysevent.c b/drivers/staging/hisysevent/hiview_hisysevent.c index 8503dd7ae644..af2236fa807c 100644 --- a/drivers/staging/hisysevent/hiview_hisysevent.c +++ b/drivers/staging/hisysevent/hiview_hisysevent.c @@ -30,6 +30,8 @@ static int CHECK_CODE = 0x7BCDABCD; #define HISYSEVENT_INFO_BUF_LEN (2048 - 6) // 2KB - 6 (read_gap) +int hievent_write_internal(const char *buffer, size_t buf_len); + /* hisysevent struct */ struct hiview_hisysevent { /* hisysevent builder */ @@ -94,12 +96,10 @@ int hisysevent_write(struct hiview_hisysevent *event) { struct hisysevent_raw_data *raw_data; int ret; + int retval; struct file *filp; unsigned long vcount; struct iovec vec[3]; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 192) - mm_segment_t oldfs; -#endif struct iov_iter iter; if (!event) { @@ -130,35 +130,12 @@ int hisysevent_write(struct hiview_hisysevent *event) goto event_wrote_err; } - filp = filp_open(HISYSEVENT_WRITER_DEV, O_WRONLY, 0); - - if (!filp || IS_ERR(filp)) { - ret = PTR_ERR(filp); - pr_err("failed to access '%s', res=%d", HISYSEVENT_WRITER_DEV, ret); + retval = hievent_write_internal(raw_data->data, raw_data->len + 1); + if (retval < 0) { + retval = -EIO; goto event_wrote_err; } - vcount = 0; - vec[vcount].iov_base = &CHECK_CODE; - vec[vcount++].iov_len = sizeof(CHECK_CODE); - vec[vcount].iov_base = raw_data->data; - vec[vcount++].iov_len = raw_data->len + 1; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 192) - oldfs = get_fs(); - set_fs(KERNEL_DS); -#endif - iov_iter_init(&iter, WRITE, vec, vcount, iov_length(vec, vcount)); - ret = vfs_iter_write(filp, &iter, &filp->f_pos, 0); -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 192) - set_fs(oldfs); -#endif - - if (ret < 0) - pr_err("failed to write hisysevent, ret=%d", ret); - - filp_close(filp, NULL); - event_wrote_err: raw_data_destroy(raw_data); return ret; diff --git a/drivers/staging/zerohung/zrhung_event.c b/drivers/staging/zerohung/zrhung_event.c index 04b94a77e46e..739d8bbbba87 100644 --- a/drivers/staging/zerohung/zrhung_event.c +++ b/drivers/staging/zerohung/zrhung_event.c @@ -11,6 +11,33 @@ #include #include +int zrhung_send_event_bbox(const char *domain, const char *event_name, const char *timestamp, const char *reset) +{ + struct hiview_hisysevent *event = NULL; + int ret = 0; + + event = hisysevent_create(domain, event_name, FAULT); + if (!event) { + pr_err("failed to create event"); + return -EINVAL; + } + ret = hisysevent_put_string(event, "BBOX_TIME", timestamp); + if (ret != 0) { + pr_err("failed to put BBOX_TIME to event, ret=%d", ret); + goto hisysevent_end; + } + ret = hisysevent_put_string(event, "BBOX_SYSRESET", reset); + if (ret != 0) { + pr_err("failed to put BBOX_SYSRESET to event, ret=%d", ret); + goto hisysevent_end; + } + ret = hisysevent_write(event); + +hisysevent_end: + hisysevent_destroy(&event); + return ret; +} + int zrhung_send_event(const char *domain, const char *event_name, const char *msg_buf) { struct hiview_hisysevent *event = NULL; diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index 3acc38600cd1..70dd4971da2c 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -13,6 +13,16 @@ config PSTORE If you don't have a platform persistent store driver, say N. +config PSTORE_DEFLATE_COMPRESS + tristate "DEFLATE (ZLIB) compression" + default y + depends on PSTORE + select CRYPTO_DEFLATE + help + This option enables DEFLATE (also known as ZLIB) compression + algorithm support. + + config PSTORE_DEFAULT_KMSG_BYTES int "Default kernel log storage space" if EXPERT depends on PSTORE @@ -34,6 +44,26 @@ config PSTORE_COMPRESS blown crypto API. This reduces the risk of secondary oopses or other problems while pstore is recording panic metadata. +choice + prompt "Default pstore compression algorithm" + depends on PSTORE_COMPRESS + help + This option chooses the default active compression algorithm. + This change be changed at boot with "pstore.compress=..." on + the kernel command line. + + Currently, pstore has support for 6 compression algorithms: + deflate, lzo, lz4, lz4hc, 842 and zstd. + + The default compression algorithm is deflate. + config PSTORE_DEFLATE_COMPRESS_DEFAULT + bool "deflate" if PSTORE_DEFLATE_COMPRESS +endchoice +config PSTORE_COMPRESS_DEFAULT + string + depends on PSTORE_COMPRESS + default "deflate" if PSTORE_DEFLATE_COMPRESS_DEFAULT + config PSTORE_CONSOLE bool "Log kernel console messages" depends on PSTORE @@ -65,6 +95,18 @@ config PSTORE_FTRACE If unsure, say N. +config PSTORE_BLACKBOX + bool "Store customised fault log" + depends on PSTORE + depends on BLACKBOX + help + Enable storing the customised fault log for BlackBox. + + With the option enabled, pstore will store the customised kernel + fault log for BlackBox when oops or panic happened. + + If unsure, say N. + config PSTORE_RAM tristate "Log panic/oops to a RAM buffer" depends on PSTORE @@ -189,3 +231,24 @@ 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_BLK_BLACKBOX_SIZE + int "Size in Kbytes of fault log for BlackBox to store" + depends on PSTORE_BLK + depends on PSTORE_BLACKBOX + default 64 + help + This just sets size of fault log (blackbox_size) for pstore/blk. + The size is in KB and must be a multiple of 4. + + NOTE that, both Kconfig and module parameters can configure + pstore/blk, but module parameters have priority over Kconfig. + +config PSTORE_BLACKBOX_STACK_SIZE + int "Default stack size for BlackBox" if EXPERT + depends on PSTORE + depends on PSTORE_BLACKBOX + default 1024 + help + Defines default size of pstore stack size for blackbox. + Can be enlarged if needed. not recommended to shrink it. diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h index 801d6c0b170c..824ef8e84dab 100644 --- a/fs/pstore/internal.h +++ b/fs/pstore/internal.h @@ -49,4 +49,7 @@ extern void pstore_record_init(struct pstore_record *record, int __init pstore_init_fs(void); void __exit pstore_exit_fs(void); +#ifdef CONFIG_PSTORE_BLACKBOX +extern bool pstore_ready; /* flag which pstore_blk is ready */ +#endif #endif diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 03425928d2fb..7ec9a3529f73 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -17,6 +17,10 @@ #include #include #include +#ifdef CONFIG_PSTORE_BLACKBOX +#include +#include +#endif #include #include #include @@ -51,6 +55,7 @@ static const char * const pstore_type_names[] = { "powerpc-common", "pmsg", "powerpc-opal", + "blackbox", }; static int pstore_new_entry; @@ -270,6 +275,110 @@ void pstore_record_init(struct pstore_record *record, record->time = ns_to_timespec64(ktime_get_real_fast_ns()); } +/* + * Store the customised fault log + */ +#ifdef CONFIG_PSTORE_BLACKBOX +#define PSTORE_FLAG "PSTORE" +#define CALLSTACK_MAX_ENTRIES 20 +static void dump_stacktrace(char *pbuf, size_t buf_size, bool is_panic) +{ + int i; + size_t stack_len = 0; + size_t com_len = 0; + unsigned long entries[CALLSTACK_MAX_ENTRIES]; + unsigned int nr_entries; + char tmp_buf[ERROR_DESC_MAX_LEN]; + bool find_panic = false; + + if (unlikely(!pbuf || !buf_size)) + return; + memset(pbuf, 0, buf_size); + memset(tmp_buf, 0, sizeof(tmp_buf)); + nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 0); + com_len = scnprintf(pbuf, buf_size, "Comm:%s,CPU:%d,Stack:", + current->comm, raw_smp_processor_id()); + for (i = 0; i < nr_entries; i++) { + if (stack_len >= sizeof(tmp_buf)) { + tmp_buf[sizeof(tmp_buf) - 1] = '\0'; + break; + } + stack_len += scnprintf(tmp_buf + stack_len, sizeof(tmp_buf) - stack_len, + "%pS-", (void *)entries[i]); + if (!find_panic && is_panic) { + if (strncmp(tmp_buf, "panic", strlen("panic")) == 0) + find_panic = true; + else + (void)memset(tmp_buf, 0, sizeof(tmp_buf)); + } + } + if (com_len >= buf_size) + return; + stack_len = min(buf_size - com_len, strlen(tmp_buf)); + memcpy(pbuf + com_len, tmp_buf, stack_len); + *(pbuf + buf_size - 1) = '\0'; +} + +void pstore_blackbox_dump(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason) +{ + struct fault_log_info *pfault_log_info; + struct pstore_record record; + struct kmsg_dump_iter iter; + size_t dst_size; + const char *why; + char *dst; + unsigned long flags = 0; + int ret; + +#if defined(CONFIG_PSTORE_BLK) || defined(CONFIG_PSTORE_RAM) + if (!pstore_ready) + return; +#endif + kmsg_dump_rewind(&iter); + why = kmsg_dump_reason_str(reason); + + if (pstore_cannot_block_path(reason)) { + if (!spin_trylock_irqsave(&psinfo->buf_lock, flags)) { + pr_err("dump skipped in %s path because of concurrent dump\n", + in_nmi() ? "NMI" : why); + return; + } + } else { + spin_lock_irqsave(&psinfo->buf_lock, flags); + } + + pfault_log_info = (struct fault_log_info *)psinfo->buf; + + memset(pfault_log_info, 0, sizeof(*pfault_log_info)); + + pstore_record_init(&record, psinfo); + + record.type = PSTORE_TYPE_BLACKBOX; + record.reason = reason; + + memcpy(pfault_log_info->flag, LOG_FLAG, strlen(LOG_FLAG)); + strncpy(pfault_log_info->info.event, why, + min(strlen(why), sizeof(pfault_log_info->info.event) - 1)); + strncpy(pfault_log_info->info.module, PSTORE_FLAG, + min(strlen(PSTORE_FLAG), sizeof(pfault_log_info->info.module) - 1)); + get_timestamp(pfault_log_info->info.error_time, TIMESTAMP_MAX_LEN); + dump_stacktrace(pfault_log_info->info.error_desc, sizeof(pfault_log_info->info.error_desc), false); + + record.buf = psinfo->buf; + dst = psinfo->buf; + dst_size = psinfo->bufsize; + + dst_size -= sizeof(struct fault_log_info); + (void)kmsg_dump_get_buffer(&iter, true, dst + sizeof(struct fault_log_info), dst_size, + &(pfault_log_info->len)); + + record.size = sizeof(struct fault_log_info) + pfault_log_info->len; + ret = psinfo->write(&record); + spin_unlock_irqrestore(&psinfo->buf_lock, flags); +} +EXPORT_SYMBOL_GPL(pstore_blackbox_dump); +#endif + /* * callback from kmsg_dump. Save as much as we can (up to kmsg_bytes) from the * end of the buffer. diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 88b34fdbf759..70a1ae218bee 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -45,6 +45,14 @@ static ulong ramoops_pmsg_size = MIN_MEM_SIZE; module_param_named(pmsg_size, ramoops_pmsg_size, ulong, 0400); MODULE_PARM_DESC(pmsg_size, "size of user space message log"); +static ulong ramoops_blackbox_size = MIN_MEM_SIZE; +module_param_named(blackbox_size, ramoops_blackbox_size, ulong, 0400); +MODULE_PARM_DESC(blackbox_size, "size of blackbox log"); +#if IS_ENABLED(CONFIG_PSTORE_BLACKBOX) +bool pstore_ready; +#endif + + static unsigned long long mem_address; module_param_hw(mem_address, ullong, other, 0400); MODULE_PARM_DESC(mem_address, @@ -82,6 +90,7 @@ struct ramoops_context { struct persistent_ram_zone *cprz; /* Console zone */ struct persistent_ram_zone **fprzs; /* Ftrace zones */ struct persistent_ram_zone *mprz; /* PMSG zone */ + struct persistent_ram_zone *bprz; /* BLACKBOX zone */ phys_addr_t phys_addr; unsigned long size; unsigned int memtype; @@ -89,6 +98,7 @@ struct ramoops_context { size_t console_size; size_t ftrace_size; size_t pmsg_size; + size_t blackbox_size; u32 flags; struct persistent_ram_ecc_info ecc_info; unsigned int max_dump_cnt; @@ -99,6 +109,7 @@ struct ramoops_context { unsigned int max_ftrace_cnt; unsigned int ftrace_read_cnt; unsigned int pmsg_read_cnt; + unsigned int blackbox_read_cnt; struct pstore_info pstore; }; @@ -112,6 +123,7 @@ static int ramoops_pstore_open(struct pstore_info *psi) cxt->console_read_cnt = 0; cxt->ftrace_read_cnt = 0; cxt->pmsg_read_cnt = 0; + cxt->blackbox_read_cnt = 0; return 0; } @@ -215,6 +227,9 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record) if (!prz_ok(prz) && !cxt->pmsg_read_cnt++) prz = ramoops_get_next_prz(&cxt->mprz, 0 /* single */, record); + if (!prz_ok(prz) && !cxt->blackbox_read_cnt++) + prz = ramoops_get_next_prz(&cxt->bprz, 0 /* single */, record); + /* ftrace is last since it may want to dynamically allocate memory. */ if (!prz_ok(prz)) { if (!(cxt->flags & RAMOOPS_FLAG_FTRACE_PER_CPU) && @@ -336,6 +351,11 @@ static int notrace ramoops_pstore_write(struct pstore_record *record) } else if (record->type == PSTORE_TYPE_PMSG) { pr_warn_ratelimited("PMSG shouldn't call %s\n", __func__); return -EINVAL; + } else if (record->type == PSTORE_TYPE_BLACKBOX) { + if (!cxt->bprz) + return -ENOMEM; + persistent_ram_write(cxt->bprz, record->buf, record->size); + return 0; } if (record->type != PSTORE_TYPE_DMESG) @@ -427,6 +447,9 @@ static int ramoops_pstore_erase(struct pstore_record *record) case PSTORE_TYPE_PMSG: prz = cxt->mprz; break; + case PSTORE_TYPE_BLACKBOX: + prz = cxt->bprz; + break; default: return -EINVAL; } @@ -687,6 +710,7 @@ static int ramoops_parse_dt(struct platform_device *pdev, parse_u32("console-size", pdata->console_size, 0); parse_u32("ftrace-size", pdata->ftrace_size, 0); parse_u32("pmsg-size", pdata->pmsg_size, 0); + parse_u32("blackbox-size", pdata->blackbox_size, 0); 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); @@ -707,9 +731,11 @@ static int ramoops_parse_dt(struct platform_device *pdev, parent_node = of_get_parent(of_node); if (!of_node_name_eq(parent_node, "reserved-memory") && !pdata->console_size && !pdata->ftrace_size && - !pdata->pmsg_size && !pdata->ecc_info.ecc_size) { + !pdata->pmsg_size && !pdata->ecc_info.ecc_size && + !pdata->blackbox_size) { pdata->console_size = pdata->record_size; pdata->pmsg_size = pdata->record_size; + pdata->blackbox_size = pdata->record_size; } of_node_put(parent_node); @@ -752,7 +778,7 @@ static int ramoops_probe(struct platform_device *pdev) } if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size && - !pdata->ftrace_size && !pdata->pmsg_size)) { + !pdata->ftrace_size && !pdata->pmsg_size && !pdata->blackbox_size)) { pr_err("The memory size and the record/console size must be " "non-zero\n"); err = -EINVAL; @@ -767,6 +793,8 @@ 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); + if (pdata->blackbox_size && !is_power_of_2(pdata->blackbox_size)) + pdata->blackbox_size = rounddown_pow_of_two(pdata->blackbox_size); cxt->size = pdata->mem_size; cxt->phys_addr = pdata->mem_address; @@ -775,13 +803,22 @@ static int ramoops_probe(struct platform_device *pdev) cxt->console_size = pdata->console_size; cxt->ftrace_size = pdata->ftrace_size; cxt->pmsg_size = pdata->pmsg_size; + cxt->blackbox_size = pdata->blackbox_size; cxt->flags = pdata->flags; cxt->ecc_info = pdata->ecc_info; paddr = cxt->phys_addr; dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size - - cxt->pmsg_size; + - cxt->pmsg_size - cxt->blackbox_size; + err = ramoops_init_prz("blackbox", dev, cxt, &cxt->bprz, &paddr, + cxt->blackbox_size, 0); + if (err) + goto fail_init; +#if IS_ENABLED(CONFIG_PSTORE_BLACKBOX) + else + pstore_ready = true; +#endif err = ramoops_init_przs("dmesg", dev, cxt, &cxt->dprzs, &paddr, dump_mem_sz, cxt->record_size, &cxt->max_dump_cnt, 0, 0); @@ -827,6 +864,8 @@ static int ramoops_probe(struct platform_device *pdev) cxt->pstore.flags |= PSTORE_FLAGS_FTRACE; if (cxt->pmsg_size) cxt->pstore.flags |= PSTORE_FLAGS_PMSG; + if (cxt->blackbox_size) + cxt->pstore.flags |= PSTORE_FLAGS_BLACKBOX; /* * Since bufsize is only used for dmesg crash dumps, it @@ -860,6 +899,7 @@ static int ramoops_probe(struct platform_device *pdev) ramoops_console_size = pdata->console_size; ramoops_pmsg_size = pdata->pmsg_size; ramoops_ftrace_size = pdata->ftrace_size; + ramoops_blackbox_size = pdata->blackbox_size; pr_info("using 0x%lx@0x%llx, ecc: %d\n", cxt->size, (unsigned long long)cxt->phys_addr, @@ -931,6 +971,7 @@ static void __init ramoops_register_dummy(void) pdata.console_size = ramoops_console_size; pdata.ftrace_size = ramoops_ftrace_size; pdata.pmsg_size = ramoops_pmsg_size; + pdata.blackbox_size = ramoops_blackbox_size; /* If "max_reason" is set, its value has priority over "dump_oops". */ if (ramoops_max_reason >= 0) pdata.max_reason = ramoops_max_reason; diff --git a/include/dfx/zrhung.h b/include/dfx/zrhung.h index a63462a2885b..49ba205a3dc8 100644 --- a/include/dfx/zrhung.h +++ b/include/dfx/zrhung.h @@ -6,6 +6,7 @@ #ifndef ZRHUNG_H #define ZRHUNG_H +int zrhung_send_event_bbox(const char *domain, const char *event_name, const char *timestamp, const char *reset); int zrhung_send_event(const char *domain, const char *event_name, const char *msg_buf); #endif /* ZRHUNG_H */ diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 638507a3c8ff..df2c4ee0573a 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -39,6 +39,8 @@ enum pstore_type_id { PSTORE_TYPE_PMSG = 7, PSTORE_TYPE_PPC_OPAL = 8, + PSTORE_TYPE_BLACKBOX = 9, + /* End of the list */ PSTORE_TYPE_MAX }; @@ -206,6 +208,7 @@ struct pstore_info { #define PSTORE_FLAGS_CONSOLE BIT(1) #define PSTORE_FLAGS_FTRACE BIT(2) #define PSTORE_FLAGS_PMSG BIT(3) +#define PSTORE_FLAGS_BLACKBOX BIT(4) extern int pstore_register(struct pstore_info *); extern void pstore_unregister(struct pstore_info *); @@ -286,4 +289,9 @@ pstore_ftrace_write_timestamp(struct pstore_ftrace_record *rec, u64 val) } #endif +#ifdef CONFIG_PSTORE_BLACKBOX +extern void pstore_blackbox_dump(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason); +#endif + #endif /*_LINUX_PSTORE_H*/ diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index 9d65ff94e216..95981aa83318 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -34,6 +34,7 @@ struct ramoops_platform_data { unsigned long console_size; unsigned long ftrace_size; unsigned long pmsg_size; + unsigned long blackbox_size; int max_reason; u32 flags; struct persistent_ram_ecc_info ecc_info; -- Gitee