blob: 194a9dd997acb8fd1aac570507d1760caff0791a [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/stacktrace.h>
#include <linux/export.h>
#include <linux/types.h>
#include <linux/smp.h>
#include <linux/irqflags.h>
#include <linux/sched.h>
#include <linux/moduleparam.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/sched/clock.h>
#include <linux/sched/debug.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/stacktrace.h>
#include <linux/arm-smccc.h>
#include <linux/kprobes.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <sched.h>
#define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_ALL
#include <trace/events/meson_atrace.h>
#include "lockup.h"
static unsigned int load_hrtimer_sleepus;
module_param(load_hrtimer_sleepus, int, 0644);
static unsigned int load_hrtimer_delayms;
module_param(load_hrtimer_delayms, int, 0644);
static int load_hrtimer_print;
static struct hrtimer load_hrtimer;
static enum hrtimer_restart do_load_hrtimer(struct hrtimer *timer)
{
if (load_hrtimer_print)
pr_info("++ %s() load_hrtimer_delayms=%d\n", __func__, load_hrtimer_delayms);
mdelay(load_hrtimer_delayms);
if (load_hrtimer_print)
pr_info("-- %s()\n", __func__);
if (load_hrtimer_sleepus) {
hrtimer_forward(timer, ktime_get(), ktime_set(0, load_hrtimer_sleepus * 1000));
return HRTIMER_RESTART;
}
return HRTIMER_NORESTART;
}
static void load_hrtimer_start(void *info)
{
hrtimer_start(&load_hrtimer, ktime_set(0, load_hrtimer_sleepus * 1000), HRTIMER_MODE_REL);
}
void load_hrtimer_test(u64 sleepus, u64 delayus, int cpu, int print)
{
load_hrtimer_sleepus = sleepus;
load_hrtimer_delayms = delayus;
load_hrtimer_print = print;
pr_emerg("%s: (%px) sleepus=%d delayms=%d cpu=%d print=%d\n",
__func__,
&load_hrtimer,
load_hrtimer_sleepus,
load_hrtimer_delayms,
cpu,
print);
hrtimer_init(&load_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
load_hrtimer.function = do_load_hrtimer;
smp_call_function_single(cpu, load_hrtimer_start, NULL, 1);
}
static int load_timer_sleepms;
static int load_timer_delayus;
static int load_timer_print;
static struct timer_list load_timer;
static void do_load_timer(struct timer_list *timer)
{
if (load_timer_print)
pr_info("++ %s()\n", __func__);
udelay(load_timer_delayus);
if (load_timer_print)
pr_info("-- %s()\n", __func__);
if (load_timer_sleepms)
mod_timer(timer, jiffies + msecs_to_jiffies(load_timer_sleepms));
}
void load_timer_start(void *info)
{
mod_timer(&load_timer, jiffies + msecs_to_jiffies(load_timer_sleepms));
}
void load_timer_test(int sleepms, int delayus, int cpu, int print)
{
load_timer_sleepms = sleepms;
load_timer_delayus = delayus;
load_timer_print = print;
pr_emerg("%s(%px) sleepms=%d delayus=%d cpu=%d print=%d\n",
__func__,
&load_timer,
load_timer_sleepms,
load_timer_delayus,
cpu,
print);
timer_setup(&load_timer, do_load_timer, 0);
smp_call_function_single(cpu, load_timer_start, NULL, 1);
}
void isr_long_test(void)
{
pr_emerg("+++ %s() start\n", __func__);
load_hrtimer_test(0, 600, 3, 1);
msleep(2000);
pr_emerg("--- %s() end\n", __func__);
}
void isr_ratio_test(void)
{
pr_emerg("+++ %s() start\n", __func__);
load_hrtimer_test(20, 0, 3, 0);
msleep(3000);
load_hrtimer_sleepus = 1000000;
pr_emerg("--- %s() end\n", __func__);
}
void sirq_long_test(void)
{
pr_emerg("+++ %s() start\n", __func__);
load_timer_test(0, 800000, 3, 0);
msleep(2000);
pr_emerg("--- %s() end\n", __func__);
}
static void idle_long_test(void)
{
pr_emerg("+++ %s() start\n", __func__);
idle_long_debug = 1;
msleep(10000);
pr_emerg("--- %s() end\n", __func__);
}
static void irq_disable_test1(void)
{
pr_emerg("+++ %s() start\n", __func__);
local_irq_disable();
mdelay(1000);
local_irq_disable();
mdelay(1000);
local_irq_enable();
mdelay(1000);
local_irq_enable();
pr_emerg("--- %s() end\n", __func__);
}
static void irq_disable_test2(void)
{
unsigned long flags, flags2;
pr_emerg("+++ %s() start\n", __func__);
local_irq_save(flags);
mdelay(1000);
local_irq_save(flags2);
mdelay(1000);
local_irq_restore(flags2);
mdelay(1000);
local_irq_restore(flags);
pr_emerg("--- %s() end\n", __func__);
}
static DEFINE_SPINLOCK(test_lock);
static void irq_disable_test3(void)
{
unsigned long flags;
spin_lock_init(&test_lock);
pr_emerg("+++ %s() start\n", __func__);
spin_lock_irqsave(&test_lock, flags);
mdelay(1000);
spin_unlock_irqrestore(&test_lock, flags);
pr_emerg("--- %s() end\n", __func__);
}
static int trace_test_thread(void *data)
{
int i;
pr_emerg("+++ %s() start\n", __func__);
for (i = 0; ; i++) {
ATRACE_COUNTER("atrace_test", i);
msleep(1000);
}
pr_emerg("--- %s() end\n", __func__);
}
static void atrace_test(void)
{
pr_emerg("+++ %s() start, please confirm with ftrace cmds\n", __func__);
kthread_run(trace_test_thread, NULL, "atrace_test");
pr_emerg("--- %s() end\n", __func__);
}
static void smc_long_test(void)
{
struct arm_smccc_res res;
pr_emerg("+++ %s() start\n", __func__);
smc_long_debug = 1;
arm_smccc_smc(0x1234, 1, 2, 3, 4, 5, 6, 7, &res);
msleep(2000);
pr_emerg("--- %s() end\n", __func__);
}
static int rt_throttle_debug;
static int rt_throttle_thread(void *data)
{
int ret;
struct sched_attr attr = {
.size = sizeof(struct sched_attr),
.sched_policy = SCHED_FIFO,
.sched_nice = 0,
.sched_priority = 50,
};
pr_emerg("==== %s() start\n", __func__);
ret = sched_setattr_nocheck(current, &attr);
if (ret) {
pr_warn("%s: failed to set SCHED_FIFO\n", __func__);
return ret;
}
while (true) {
if (rt_throttle_debug)
mdelay(1000);
else
msleep(1000);
}
return 0;
}
static void rt_throttle_test(void)
{
pr_emerg("+++ %s() start\n", __func__);
rt_throttle_debug = 1;
kthread_run(rt_throttle_thread, NULL, "rt_throttle_test");
msleep(10000);
rt_throttle_debug = 0;
pr_emerg("--- %s() end\n", __func__);
}
static int debug_test_init(void)
{
pr_emerg("++++++++++++++++++++++++ %s() start\n", __func__);
isr_long_test();
isr_ratio_test();
sirq_long_test();
idle_long_test();
irq_disable_test1();
irq_disable_test2();
irq_disable_test3();
smc_long_test();
rt_throttle_test();
atrace_test();
pr_emerg("------------------------ %s() end\n", __func__);
return 0;
}
static void debug_test_exit(void)
{
}
module_init(debug_test_init);
module_exit(debug_test_exit);
MODULE_LICENSE("GPL v2");