197 lines
5.4 KiB
C
197 lines
5.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (C) 2015 MediaTek Inc.
|
|
*/
|
|
|
|
#ifndef _MTK_SCHED_MON_H
|
|
#define _MTK_SCHED_MON_H
|
|
|
|
#include <asm/hardirq.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/sched/clock.h>
|
|
#ifdef CONFIG_MTK_AEE_FEATURE
|
|
#include <mt-plat/aee.h>
|
|
#endif
|
|
#ifdef CONFIG_MTK_AEE_IPANIC
|
|
#include <mt-plat/mboot_params.h>
|
|
#endif
|
|
|
|
#ifndef TO_KERNEL_LOG
|
|
#define TO_KERNEL_LOG 0x1
|
|
#define TO_FTRACE 0x2
|
|
#define TO_DEFERRED 0x4
|
|
#define TO_SRAM 0x8
|
|
#define TO_BOTH (TO_KERNEL_LOG | TO_FTRACE)
|
|
#define TO_BOTH_SAVE (TO_DEFERRED | TO_FTRACE)
|
|
#endif
|
|
|
|
void sched_mon_msg(int out, char *buf, ...);
|
|
|
|
#ifdef CONFIG_MTK_SCHED_MONITOR
|
|
extern bool irq_time_tracer;
|
|
extern unsigned int irq_time_th1_ms;
|
|
extern unsigned int irq_time_th2_ms;
|
|
extern unsigned int irq_time_aee_limit;
|
|
|
|
struct irq_handle_status {
|
|
unsigned int irq;
|
|
unsigned long long start;
|
|
unsigned long long end;
|
|
};
|
|
|
|
DECLARE_PER_CPU(struct irq_handle_status, irq_note);
|
|
DECLARE_PER_CPU(struct irq_handle_status, ipi_note);
|
|
DECLARE_PER_CPU(struct irq_handle_status, softirq_note);
|
|
|
|
#ifdef CONFIG_MTK_AEE_FEATURE
|
|
#define schedule_monitor_aee(msg, item) do { \
|
|
char aee_str[64]; \
|
|
\
|
|
snprintf(aee_str, sizeof(aee_str), \
|
|
"SCHED MONITOR: %s", item); \
|
|
RCU_NONIDLE(aee_kernel_warning_api(__FILE__, __LINE__, \
|
|
DB_OPT_DUMMY_DUMP | DB_OPT_FTRACE, \
|
|
aee_str, "\n%s\n", msg)); \
|
|
} while (0)
|
|
#else
|
|
#define schedule_monitor_aee(msg_str, item) do {} while (0)
|
|
#endif
|
|
|
|
#define WARN_INFO ": process time %llums, from %ld.%06ld to %ld.%06ld"
|
|
|
|
#define check_start_time(time) do { \
|
|
if (irq_time_tracer) \
|
|
time = sched_clock(); \
|
|
} while (0)
|
|
|
|
#define __check_process_time(msg, ts, ...) do { \
|
|
unsigned long long te = sched_clock(); \
|
|
unsigned long long t_diff = te - ts; \
|
|
\
|
|
do_div(t_diff, 1000000); \
|
|
if (t_diff > irq_time_th1_ms) { \
|
|
struct timeval tv_start, tv_end; \
|
|
char msg_str[128]; \
|
|
\
|
|
tv_start = ns_to_timeval(ts); \
|
|
tv_end = ns_to_timeval(te); \
|
|
snprintf(msg_str, sizeof(msg_str), \
|
|
msg WARN_INFO, ##__VA_ARGS__, t_diff, \
|
|
tv_start.tv_sec, tv_start.tv_usec, \
|
|
tv_end.tv_sec, tv_end.tv_usec); \
|
|
sched_mon_msg(TO_BOTH, msg_str); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define check_process_time(msg, ts, ...) do { \
|
|
if (irq_time_tracer) \
|
|
__check_process_time(msg, ts, ##__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#define check_preempt_count(count, msg, ...) do { \
|
|
if (count != preempt_count()) { \
|
|
char msg_str[128]; \
|
|
\
|
|
snprintf(msg_str, sizeof(msg_str), "entered " msg \
|
|
" with preempt_count %08x, exited with %08x", \
|
|
##__VA_ARGS__, count, preempt_count()); \
|
|
sched_mon_msg(TO_BOTH, msg_str); \
|
|
schedule_monitor_aee(msg_str, "PREEMPT COUNT"); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define check_start_time_preempt(type, count, time, id) do { \
|
|
if (irq_time_tracer) { \
|
|
time = sched_clock(); \
|
|
this_cpu_write(type.irq, id); \
|
|
this_cpu_write(type.start, time); \
|
|
this_cpu_write(type.end, 0); \
|
|
count = preempt_count(); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define __check_process_time_preempt(type, count, msg, ts, ...) do { \
|
|
unsigned long long te = sched_clock(); \
|
|
unsigned long long t_diff = te - ts; \
|
|
\
|
|
do_div(t_diff, 1000000); \
|
|
if (t_diff > irq_time_th1_ms) { \
|
|
struct timeval tv_start, tv_end; \
|
|
char msg_str[128]; \
|
|
\
|
|
tv_start = ns_to_timeval(ts); \
|
|
tv_end = ns_to_timeval(te); \
|
|
snprintf(msg_str, sizeof(msg_str), \
|
|
msg WARN_INFO, ##__VA_ARGS__, t_diff, \
|
|
tv_start.tv_sec, tv_start.tv_usec, \
|
|
tv_end.tv_sec, tv_end.tv_usec); \
|
|
sched_mon_msg(TO_BOTH, msg_str); \
|
|
if (irq_time_th2_ms && irq_time_aee_limit && \
|
|
t_diff > irq_time_th2_ms) { \
|
|
irq_time_aee_limit--; \
|
|
schedule_monitor_aee(msg_str, \
|
|
"IRQ PROCESSING TIME"); \
|
|
} \
|
|
} \
|
|
this_cpu_write(type.end, te); \
|
|
check_preempt_count(count, msg, ##__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#define check_process_time_preempt(type, count, msg, ts, ...) do { \
|
|
if (irq_time_tracer) \
|
|
__check_process_time_preempt(type, count, msg, ts, \
|
|
##__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#ifdef CONFIG_MTK_AEE_IPANIC
|
|
#define pr_aee_sram(msg) aee_sram_fiq_log(msg)
|
|
#else
|
|
#define pr_aee_sram(msg) do {} while (0)
|
|
#endif
|
|
|
|
void show_irq_handle_info(int output);
|
|
#ifdef CONFIG_MTK_IRQ_COUNT_TRACER
|
|
void show_irq_count_info(int output);
|
|
#else
|
|
#define show_irq_count_info(output) do {} while (0)
|
|
#endif
|
|
|
|
#ifdef CONFIG_MTK_IRQ_OFF_TRACER
|
|
void trace_hardirqs_off_time(void);
|
|
void trace_hardirqs_on_time(void);
|
|
#else
|
|
#define trace_hardirqs_off_time() do {} while (0)
|
|
#define trace_hardirqs_on_time() do {} while (0)
|
|
#endif
|
|
|
|
#ifdef CONFIG_MTK_PREEMPT_TRACER
|
|
void trace_preempt_off_time(void);
|
|
void trace_preempt_on_time(void);
|
|
#else
|
|
#define trace_preempt_off_time() do {} while (0)
|
|
#define trace_preempt_on_time() do {} while (0)
|
|
#endif
|
|
|
|
void mt_aee_dump_sched_traces(void);
|
|
|
|
#else /* !CONFIG_MTK_SCHED_MONITOR */
|
|
#define check_start_time(time) ((void)time)
|
|
#define check_process_time(msg, ts, ...) do {} while (0)
|
|
#define check_start_time_preempt(type, count, time, irq_id) do { \
|
|
(void)time; \
|
|
(void)count; \
|
|
} while (0)
|
|
#define check_process_time_preempt(type, count, msg, ts, ...) do {} while (0)
|
|
#define trace_hardirqs_off_time() do {} while (0)
|
|
#define trace_hardirqs_on_time() do {} while (0)
|
|
#define trace_preempt_off_time() do {} while (0)
|
|
#define trace_preempt_on_time() do {} while (0)
|
|
#define show_irq_handle_info(output) do {} while (0)
|
|
#define show_irq_count_info(output) do {} while (0)
|
|
#define mt_aee_dump_sched_traces() do {} while (0)
|
|
#endif /* CONFIG_MTK_SCHED_MONITOR */
|
|
|
|
const char *irq_to_name(int irq);
|
|
|
|
#endif /* _MTK_SCHED_MON_H */
|