mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-10 22:40:54 -04:00
soc: qcom: Enable ftrace support in minidump
Register and dump ftrace buffer on kernel panic, to minidump table. The dumps are collected in parsed format. Change-Id: I10605467d2b566425cc2cb4fd67dbc59fcd592e7 Signed-off-by: Neeraj Upadhyay <neeraju@codeaurora.org>
This commit is contained in:
parent
b9483eb801
commit
52a0d3dcb7
4 changed files with 143 additions and 2 deletions
|
|
@ -487,6 +487,14 @@ config QCOM_DYN_MINIDUMP_STACK
|
|||
where CPU is unable to register it from IPI_CPU_STOP. The stack data
|
||||
can be used to unwind stack frames.
|
||||
|
||||
config QCOM_MINIDUMP_FTRACE
|
||||
bool "QCOM Minidump Support"
|
||||
depends on QGKI && QCOM_MINIDUMP
|
||||
help
|
||||
This enables ftrace buffer registration in minidump table.
|
||||
This allows dumping ftrace buffer content as part of
|
||||
minidump dumps.
|
||||
|
||||
config MINIDUMP_MAX_ENTRIES
|
||||
int "Minidump Maximum num of entries"
|
||||
default 200
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
#include <asm/stacktrace.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched/task.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
|
@ -54,6 +56,13 @@ static struct md_suspend_context_data md_suspend_context;
|
|||
|
||||
static bool is_vmap_stack __read_mostly;
|
||||
|
||||
#ifdef CONFIG_QCOM_MINIDUMP_FTRACE
|
||||
#define MD_FTRACE_BUF_SIZE SZ_2M
|
||||
|
||||
static char *md_ftrace_buf_addr;
|
||||
static size_t md_ftrace_buf_current;
|
||||
#endif
|
||||
|
||||
static void __init register_log_buf(void)
|
||||
{
|
||||
char **log_bufp;
|
||||
|
|
@ -489,6 +498,45 @@ static void register_irq_stack(void)
|
|||
static inline void register_irq_stack(void) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_QCOM_MINIDUMP_FTRACE
|
||||
void minidump_add_trace_event(char *buf, size_t size)
|
||||
{
|
||||
char *addr;
|
||||
|
||||
if (!READ_ONCE(md_ftrace_buf_addr) ||
|
||||
(size > (size_t)MD_FTRACE_BUF_SIZE))
|
||||
return;
|
||||
|
||||
if ((md_ftrace_buf_current + size) > (size_t)MD_FTRACE_BUF_SIZE)
|
||||
md_ftrace_buf_current = 0;
|
||||
addr = md_ftrace_buf_addr + md_ftrace_buf_current;
|
||||
memcpy(addr, buf, size);
|
||||
md_ftrace_buf_current += size;
|
||||
}
|
||||
|
||||
static void md_register_trace_buf(void)
|
||||
{
|
||||
struct md_region md_entry;
|
||||
void *buffer_start;
|
||||
|
||||
buffer_start = kmalloc(MD_FTRACE_BUF_SIZE, GFP_KERNEL);
|
||||
|
||||
if (!buffer_start)
|
||||
return;
|
||||
|
||||
strlcpy(md_entry.name, "KFTRACE", sizeof(md_entry.name));
|
||||
md_entry.virt_addr = (uintptr_t)buffer_start;
|
||||
md_entry.phys_addr = virt_to_phys(buffer_start);
|
||||
md_entry.size = MD_FTRACE_BUF_SIZE;
|
||||
if (msm_minidump_add_region(&md_entry) < 0)
|
||||
pr_err("Failed to add ftrace buffer entry in Minidump\n");
|
||||
|
||||
/* Complete registration before adding enteries */
|
||||
smp_mb();
|
||||
WRITE_ONCE(md_ftrace_buf_addr, buffer_start);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init msm_minidump_log_init(void)
|
||||
{
|
||||
register_kernel_sections();
|
||||
|
|
@ -499,6 +547,9 @@ static int __init msm_minidump_log_init(void)
|
|||
register_suspend_context();
|
||||
#endif
|
||||
register_log_buf();
|
||||
#ifdef CONFIG_QCOM_MINIDUMP_FTRACE
|
||||
md_register_trace_buf();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
late_initcall(msm_minidump_log_init);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __MINIDUMP_H
|
||||
|
|
@ -56,5 +56,11 @@ static inline int msm_minidump_remove_region(const struct md_region *entry)
|
|||
}
|
||||
static inline bool msm_minidump_enabled(void) { return false; }
|
||||
static inline void dump_stack_minidump(u64 sp) {}
|
||||
static inline void add_trace_event(char *buf, size_t size) {}
|
||||
#endif
|
||||
#ifdef CONFIG_QCOM_MINIDUMP_FTRACE
|
||||
extern void minidump_add_trace_event(char *buf, size_t size);
|
||||
#else
|
||||
static inline void minidump_add_trace_event(char *buf, size_t size) {}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <linux/percpu.h>
|
||||
#include <linux/splice.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/rwsem.h>
|
||||
|
|
@ -47,6 +48,8 @@
|
|||
#include <linux/sched/rt.h>
|
||||
#include <linux/coresight-stm.h>
|
||||
|
||||
#include <soc/qcom/minidump.h>
|
||||
|
||||
#include "trace.h"
|
||||
#include "trace_output.h"
|
||||
|
||||
|
|
@ -119,7 +122,13 @@ cpumask_var_t __read_mostly tracing_buffer_mask;
|
|||
* Set 2 if you want to dump the buffer of the CPU that triggered oops
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_QCOM_MINIDUMP_FTRACE
|
||||
enum ftrace_dump_mode ftrace_dump_on_oops = DUMP_ALL;
|
||||
static bool minidump_ftrace_in_oops;
|
||||
static bool minidump_ftrace_dump = true;
|
||||
#else
|
||||
enum ftrace_dump_mode ftrace_dump_on_oops;
|
||||
#endif
|
||||
|
||||
/* When set, tracing will stop when a WARN*() is hit */
|
||||
int __disable_trace_on_warning;
|
||||
|
|
@ -8842,11 +8851,32 @@ static __init int tracer_init_tracefs(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_QCOM_MINIDUMP_FTRACE
|
||||
static bool trace_oops_enter(void)
|
||||
{
|
||||
if (minidump_ftrace_in_oops)
|
||||
return true;
|
||||
minidump_ftrace_in_oops = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void trace_oops_exit(void)
|
||||
{
|
||||
minidump_ftrace_in_oops = false;
|
||||
}
|
||||
#else
|
||||
static bool trace_oops_enter(void) { return false; }
|
||||
static void trace_oops_exit(void) { }
|
||||
#endif
|
||||
|
||||
static int trace_panic_handler(struct notifier_block *this,
|
||||
unsigned long event, void *unused)
|
||||
{
|
||||
if (trace_oops_enter())
|
||||
return NOTIFY_OK;
|
||||
if (ftrace_dump_on_oops)
|
||||
ftrace_dump(ftrace_dump_on_oops);
|
||||
trace_oops_exit();
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
|
|
@ -8860,6 +8890,8 @@ static int trace_die_handler(struct notifier_block *self,
|
|||
unsigned long val,
|
||||
void *data)
|
||||
{
|
||||
if (trace_oops_enter())
|
||||
return NOTIFY_OK;
|
||||
switch (val) {
|
||||
case DIE_OOPS:
|
||||
if (ftrace_dump_on_oops)
|
||||
|
|
@ -8868,6 +8900,7 @@ static int trace_die_handler(struct notifier_block *self,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
trace_oops_exit();
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
|
|
@ -8889,6 +8922,19 @@ static struct notifier_block trace_die_notifier = {
|
|||
*/
|
||||
#define KERN_TRACE KERN_EMERG
|
||||
|
||||
#ifdef CONFIG_QCOM_MINIDUMP_FTRACE
|
||||
static void trace_dump_seq_buffer(struct trace_seq *s)
|
||||
{
|
||||
if (minidump_ftrace_in_oops && minidump_ftrace_dump)
|
||||
minidump_add_trace_event(s->buffer, s->seq.len);
|
||||
}
|
||||
#else
|
||||
static void trace_dump_seq_buffer(struct trace_seq *s)
|
||||
{
|
||||
printk(KERN_TRACE "%s", s->buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
trace_printk_seq(struct trace_seq *s)
|
||||
{
|
||||
|
|
@ -8907,7 +8953,7 @@ trace_printk_seq(struct trace_seq *s)
|
|||
/* should be zero ended, but we are paranoid. */
|
||||
s->buffer[s->seq.len] = 0;
|
||||
|
||||
printk(KERN_TRACE "%s", s->buffer);
|
||||
trace_dump_seq_buffer(s);
|
||||
|
||||
trace_seq_init(s);
|
||||
}
|
||||
|
|
@ -8931,6 +8977,33 @@ void trace_init_global_iter(struct trace_iterator *iter)
|
|||
iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_QCOM_MINIDUMP_FTRACE
|
||||
static void trace_check_size(struct trace_iterator iter, int cpu)
|
||||
{
|
||||
unsigned long buffer_size;
|
||||
|
||||
if (!minidump_ftrace_dump)
|
||||
return;
|
||||
buffer_size = ring_buffer_size(iter.tr->trace_buffer.buffer, cpu);
|
||||
if (buffer_size > (SZ_256K + PAGE_SIZE)) {
|
||||
printk(KERN_TRACE "Skip md ftrace buffer dump for: %#lx\n",
|
||||
buffer_size);
|
||||
minidump_ftrace_dump = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool trace_skip_ftrace_dump(void)
|
||||
{
|
||||
return !minidump_ftrace_dump;
|
||||
}
|
||||
#else
|
||||
static void trace_check_size(struct trace_iterator iter, int cpu) { }
|
||||
static bool trace_skip_ftrace_dump(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
|
||||
{
|
||||
/* use static because iter can be a bit big for the stack */
|
||||
|
|
@ -8965,6 +9038,7 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
|
|||
|
||||
for_each_tracing_cpu(cpu) {
|
||||
atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
|
||||
trace_check_size(iter, cpu);
|
||||
}
|
||||
|
||||
old_userobj = tr->trace_flags & TRACE_ITER_SYM_USEROBJ;
|
||||
|
|
@ -8972,6 +9046,8 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
|
|||
/* don't look at user memory in panic mode */
|
||||
tr->trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
|
||||
|
||||
if (trace_skip_ftrace_dump())
|
||||
goto out_enable;
|
||||
switch (oops_dump_mode) {
|
||||
case DUMP_ALL:
|
||||
iter.cpu_file = RING_BUFFER_ALL_CPUS;
|
||||
|
|
|
|||
Loading…
Reference in a new issue