blob: 0402a1b850f61c46b08117b5db4f6aeb396515f8 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/pinctrl/consumer.h>
#include <linux/trace_events.h>
#include <trace/hooks/printk.h>
#include <linux/irqflags.h>
static bool print_task_name_bool;
/* notice: this param only used by build module */
module_param(print_task_name_bool, bool, 0664);
MODULE_PARM_DESC(print_task_name_bool, "\n statistical log printing\n");
void printk_caller_id(void *data, u32 *caller_id)
{
unsigned long irqflags;
unsigned long preempt_value = preempt_count();
u8 cpu = raw_smp_processor_id();
u8 irq_trace;
#ifdef CONFIG_AMLOGIC_APU
if (apu_enable && cpu == apu_id)
cpu = 0;
#endif
local_save_flags(irqflags);
irq_trace =
(irqs_disabled_flags(irqflags) ? TRACE_FLAG_IRQS_OFF : 0) |
((preempt_value & NMI_MASK) ? TRACE_FLAG_NMI : 0) |
((preempt_value & HARDIRQ_MASK) ? TRACE_FLAG_HARDIRQ : 0) |
((preempt_value & SOFTIRQ_OFFSET) ? TRACE_FLAG_SOFTIRQ : 0) |
(tif_need_resched() ? TRACE_FLAG_NEED_RESCHED : 0) |
(test_preempt_need_resched() ? TRACE_FLAG_PREEMPT_RESCHED : 0);
*caller_id = (cpu << 28 | irq_trace << 20 | current->pid);
}
void printk_caller(void *data, char *caller, size_t size, u32 id, int *ret)
{
struct task_struct *task = NULL;
char task_name[TASK_COMM_LEN] = "";
u8 cpu = id >> 28;
u8 irq_trace = (id >> 20) & 0xff;
pid_t pid = id & 0xfffff;
char hardsoft_irq;
char irqs_off;
int hardirq;
int softirq;
int nmi;
nmi = irq_trace & TRACE_FLAG_NMI;
hardirq = irq_trace & TRACE_FLAG_HARDIRQ;
softirq = irq_trace & TRACE_FLAG_SOFTIRQ;
irqs_off =
(irq_trace & TRACE_FLAG_IRQS_OFF) ? 'd' :
(irq_trace & TRACE_FLAG_IRQS_NOSUPPORT) ? 'X' :
'.';
hardsoft_irq =
(nmi && hardirq) ? 'Z' :
nmi ? 'z' :
(hardirq && softirq) ? 'H' :
hardirq ? 'h' :
softirq ? 's' :
'.';
if (print_task_name_bool) {
rcu_read_lock();
task = find_task_by_vpid(pid);
rcu_read_unlock();
if (task)
__get_task_comm(task_name, TASK_COMM_LEN, task);
} else {
sprintf(task_name, "T%u", pid);
}
*ret = snprintf(caller, size, "%d %-6.6s %c%c",
cpu,
task_name,
irqs_off, hardsoft_irq);
}
#if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS)
int printk_vendor_hook_init(void)
{
int ret;
ret = register_trace_android_vh_printk_caller_id(printk_caller_id, NULL);
if (ret)
pr_err("register_trace_android_vh_printk_caller_id fail ret=%d\n", ret);
ret = register_trace_android_vh_printk_caller(printk_caller, NULL);
if (ret)
pr_err("register_trace_android_vh_printk_caller fail ret=%d\n", ret);
return ret;
}
void printk_vendor_hook_exit(void)
{
int ret;
ret = unregister_trace_android_vh_printk_caller_id(printk_caller_id, NULL);
if (ret)
pr_err("unregister_trace_android_vh_printk_caller_id fail ret=%d\n", ret);
ret = unregister_trace_android_vh_printk_caller(printk_caller, NULL);
if (ret)
pr_err("unregister_trace_android_vh_printk_caller fail ret=%d\n", ret);
}
#else
int printk_vendor_hook_init(void)
{
return 0;
}
void printk_vendor_hook_exit(void)
{
}
void trace_android_vh_printk_caller_id(u32 *caller_id)
{
printk_caller_id(NULL, caller_id);
}
EXPORT_SYMBOL(trace_android_vh_printk_caller_id);
void trace_android_vh_printk_caller(char *caller, size_t size, u32 id, int *ret)
{
printk_caller(NULL, caller, size, id, ret);
}
EXPORT_SYMBOL(trace_android_vh_printk_caller);
#endif /* END CONFIG_ANDROID_VENDOR_HOOKS */
#if IS_BUILTIN(CONFIG_AMLOGIC_DEBUG_PRINTK)
early_initcall(printk_vendor_hook_init);
module_exit(printk_vendor_hook_exit);
#endif