From 12190dbddeff24bcb03a8bdc03d1621e7628280b Mon Sep 17 00:00:00 2001 From: Deepak Kumar Singh Date: Tue, 8 Dec 2020 21:30:51 +0530 Subject: [PATCH] trace: Add minidump support for ipc log buffers Enable minidump for ipc log buffers. Change-Id: Ie890c81783bab22b3ee6d510a045de4c93f9b3f9 Signed-off-by: Deepak Kumar Singh --- include/linux/ipc_logging.h | 7 ++-- kernel/trace/Kconfig | 8 +++++ kernel/trace/ipc_logging.c | 65 ++++++++++++++++++++++++++++++++++--- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/include/linux/ipc_logging.h b/include/linux/ipc_logging.h index d741e8f0e116..a749ac2679e8 100644 --- a/include/linux/ipc_logging.h +++ b/include/linux/ipc_logging.h @@ -42,12 +42,13 @@ struct decode_context { * * @max_num_pages: Number of pages of logging space required (max. 10) * @mod_name : Name of the directory entry under DEBUGFS - * @user_version : Version number of user-defined message formats + * @feature_version : First 16 bit for version number of user-defined message + * formats and next 16 bit for enabling minidump * * returns context id on success, NULL on failure */ void *ipc_log_context_create(int max_num_pages, const char *modname, - uint16_t user_version); + uint32_t feature_version); /* * msg_encode_start: Start encoding a log message @@ -223,7 +224,7 @@ int ipc_log_context_destroy(void *ctxt); #else static inline void *ipc_log_context_create(int max_num_pages, - const char *modname, uint16_t user_version) + const char *modname, uint32_t feature_version) { return NULL; } static inline void msg_encode_start(struct encode_context *ectxt, diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 7958380183ea..b404e9f239b4 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -99,6 +99,14 @@ config IPC_LOGGING If in doubt, say no. +config IPC_LOG_MINIDUMP_BUFFERS + int "Ipc log buffers count that can be dumped with minidump" + depends on IPC_LOGGING + default 0 + help + This option is used to configure maximum number of ipc log + buffers that can be dumped by minidump. + config PREEMPTIRQ_TRACEPOINTS bool depends on TRACE_PREEMPT_TOGGLE || TRACE_IRQFLAGS diff --git a/kernel/trace/ipc_logging.c b/kernel/trace/ipc_logging.c index 22b9061b2dbe..1e353eb74597 100644 --- a/kernel/trace/ipc_logging.c +++ b/kernel/trace/ipc_logging.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ #include @@ -21,12 +21,17 @@ #include #include #include +#include #include "ipc_logging_private.h" #define LOG_PAGE_DATA_SIZE sizeof(((struct ipc_log_page *)0)->data) #define LOG_PAGE_FLAG (1 << 31) +#define MAX_MINIDUMP_BUFFERS CONFIG_IPC_LOG_MINIDUMP_BUFFERS +/*16th bit is used for minidump feature*/ +#define FEATURE_MASK 0x10000 +static int minidump_buf_cnt; static LIST_HEAD(ipc_log_context_list); static DEFINE_RWLOCK(context_list_lock_lha1); static void *get_deserialization_func(struct ipc_log_context *ilctxt, @@ -126,6 +131,31 @@ static struct ipc_log_page *get_next_page(struct ipc_log_context *ilctxt, return pg; } +static void register_minidump(u64 vaddr, u64 size, + const char *buf_name, int index) +{ + struct md_region md_entry; + int ret; + + if (msm_minidump_enabled() + && (minidump_buf_cnt < MAX_MINIDUMP_BUFFERS)) { + scnprintf(md_entry.name, sizeof(md_entry.name), "%s_%d", + buf_name, index); + md_entry.virt_addr = vaddr; + md_entry.phys_addr = virt_to_phys((void *)vaddr); + md_entry.size = size; + + ret = msm_minidump_add_region(&md_entry); + if (ret < 0) { + pr_err( + "Failed to register log buffer %s_%d in Minidump ret %d\n", + buf_name, index, ret); + + return; + } + minidump_buf_cnt++; + } +} /** * ipc_log_read - do non-destructive read of the log * @@ -787,17 +817,19 @@ static void *get_deserialization_func(struct ipc_log_context *ilctxt, * * @max_num_pages: Number of pages of logging space required (max. 10) * @mod_name : Name of the directory entry under DEBUGFS - * @user_version : Version number of user-defined message formats + * @feature_version : First 16 bit for version number of user-defined message + * formats and next 16 bit for enabling minidump * * returns context id on success, NULL on failure */ void *ipc_log_context_create(int max_num_pages, - const char *mod_name, uint16_t user_version) + const char *mod_name, uint32_t feature_version) { struct ipc_log_context *ctxt = NULL, *tmp; struct ipc_log_page *pg = NULL; int page_cnt; unsigned long flags; + int enable_minidump; /* check if ipc ctxt already exists */ read_lock_irq(&context_list_lock_lha1); @@ -819,6 +851,16 @@ void *ipc_log_context_create(int max_num_pages, INIT_LIST_HEAD(&ctxt->page_list); INIT_LIST_HEAD(&ctxt->dfunc_info_list); spin_lock_init(&ctxt->context_lock_lhb1); + + enable_minidump = feature_version & FEATURE_MASK; + + spin_lock_irqsave(&ctxt->context_lock_lhb1, flags); + if (enable_minidump) { + register_minidump((u64)ctxt, sizeof(struct ipc_log_context), + "ipc_ctxt", minidump_buf_cnt); + } + spin_unlock_irqrestore(&ctxt->context_lock_lhb1, flags); + for (page_cnt = 0; page_cnt < max_num_pages; page_cnt++) { pg = kzalloc(sizeof(struct ipc_log_page), GFP_KERNEL); if (!pg) @@ -834,13 +876,18 @@ void *ipc_log_context_create(int max_num_pages, spin_lock_irqsave(&ctxt->context_lock_lhb1, flags); list_add_tail(&pg->hdr.list, &ctxt->page_list); + + if (enable_minidump) { + register_minidump((u64)pg, sizeof(struct ipc_log_page), + mod_name, minidump_buf_cnt); + } spin_unlock_irqrestore(&ctxt->context_lock_lhb1, flags); } ctxt->log_id = (uint64_t)(uintptr_t)ctxt; ctxt->version = IPC_LOG_VERSION; strlcpy(ctxt->name, mod_name, IPC_LOG_MAX_CONTEXT_NAME_LEN); - ctxt->user_version = user_version; + ctxt->user_version = feature_version & 0xffff; ctxt->first_page = get_first_page(ctxt); ctxt->last_page = pg; ctxt->write_page = ctxt->first_page; @@ -857,8 +904,12 @@ void *ipc_log_context_create(int max_num_pages, ctxt->nmagic = ~(IPC_LOG_CONTEXT_MAGIC_NUM); write_lock_irqsave(&context_list_lock_lha1, flags); - list_add_tail(&ctxt->list, &ipc_log_context_list); + if (enable_minidump && (minidump_buf_cnt < MAX_MINIDUMP_BUFFERS)) + list_add(&ctxt->list, &ipc_log_context_list); + else + list_add_tail(&ctxt->list, &ipc_log_context_list); write_unlock_irqrestore(&context_list_lock_lha1, flags); + return (void *)ctxt; release_ipc_log_context: @@ -925,6 +976,10 @@ EXPORT_SYMBOL(ipc_log_context_destroy); static int __init ipc_logging_init(void) { check_and_create_debugfs(); + + register_minidump((u64)&ipc_log_context_list, sizeof(struct list_head), + "ipc_log_ctxt_list", minidump_buf_cnt); + return 0; }