1*6fdaab4eSNam Cao // SPDX-License-Identifier: GPL-2.0 2*6fdaab4eSNam Cao #include <linux/ftrace.h> 3*6fdaab4eSNam Cao #include <linux/tracepoint.h> 4*6fdaab4eSNam Cao #include <linux/kernel.h> 5*6fdaab4eSNam Cao #include <linux/module.h> 6*6fdaab4eSNam Cao #include <linux/init.h> 7*6fdaab4eSNam Cao #include <linux/rv.h> 8*6fdaab4eSNam Cao #include <rv/instrumentation.h> 9*6fdaab4eSNam Cao 10*6fdaab4eSNam Cao #define MODULE_NAME "wakeup" 11*6fdaab4eSNam Cao 12*6fdaab4eSNam Cao #include <trace/events/syscalls.h> 13*6fdaab4eSNam Cao #include <trace/events/sched.h> 14*6fdaab4eSNam Cao #include <trace/events/lock.h> 15*6fdaab4eSNam Cao #include <uapi/linux/futex.h> 16*6fdaab4eSNam Cao 17*6fdaab4eSNam Cao #include <rv_trace.h> 18*6fdaab4eSNam Cao #include <monitors/rtapp/rtapp.h> 19*6fdaab4eSNam Cao 20*6fdaab4eSNam Cao 21*6fdaab4eSNam Cao #ifndef __NR_futex 22*6fdaab4eSNam Cao #define __NR_futex (-__COUNTER__) 23*6fdaab4eSNam Cao #endif 24*6fdaab4eSNam Cao #ifndef __NR_futex_time64 25*6fdaab4eSNam Cao #define __NR_futex_time64 (-__COUNTER__) 26*6fdaab4eSNam Cao #endif 27*6fdaab4eSNam Cao 28*6fdaab4eSNam Cao #include "wakeup.h" 29*6fdaab4eSNam Cao #include <rv/ltl_monitor.h> 30*6fdaab4eSNam Cao 31*6fdaab4eSNam Cao static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *mon) 32*6fdaab4eSNam Cao { 33*6fdaab4eSNam Cao /* 34*6fdaab4eSNam Cao * This includes "actual" real-time tasks and also PI-boosted 35*6fdaab4eSNam Cao * tasks. A task being PI-boosted means it is blocking an "actual" 36*6fdaab4eSNam Cao * real-task, therefore it should also obey the monitor's rule, 37*6fdaab4eSNam Cao * otherwise the "actual" real-task may be delayed. 38*6fdaab4eSNam Cao */ 39*6fdaab4eSNam Cao ltl_atom_set(mon, LTL_RT, rt_or_dl_task(task)); 40*6fdaab4eSNam Cao } 41*6fdaab4eSNam Cao 42*6fdaab4eSNam Cao static void ltl_atoms_init(struct task_struct *task, struct ltl_monitor *mon, bool task_creation) 43*6fdaab4eSNam Cao { 44*6fdaab4eSNam Cao ltl_atom_set(mon, LTL_WOKEN_BY_LOWER_PRIO, false); 45*6fdaab4eSNam Cao ltl_atom_set(mon, LTL_WOKEN_BY_SOFTIRQ, false); 46*6fdaab4eSNam Cao 47*6fdaab4eSNam Cao if (task_creation) { 48*6fdaab4eSNam Cao ltl_atom_set(mon, LTL_BLOCK_ON_RT_MUTEX, false); 49*6fdaab4eSNam Cao ltl_atom_set(mon, LTL_FUTEX_LOCK_PI, false); 50*6fdaab4eSNam Cao } 51*6fdaab4eSNam Cao 52*6fdaab4eSNam Cao ltl_atom_set(mon, LTL_USER_THREAD, !(task->flags & PF_KTHREAD)); 53*6fdaab4eSNam Cao } 54*6fdaab4eSNam Cao 55*6fdaab4eSNam Cao static void handle_sched_waking(void *data, struct task_struct *task) 56*6fdaab4eSNam Cao { 57*6fdaab4eSNam Cao if (in_task()) { 58*6fdaab4eSNam Cao if (current->prio > task->prio) 59*6fdaab4eSNam Cao ltl_atom_pulse(task, LTL_WOKEN_BY_LOWER_PRIO, true); 60*6fdaab4eSNam Cao } else if (in_serving_softirq()) { 61*6fdaab4eSNam Cao ltl_atom_pulse(task, LTL_WOKEN_BY_SOFTIRQ, true); 62*6fdaab4eSNam Cao } 63*6fdaab4eSNam Cao } 64*6fdaab4eSNam Cao 65*6fdaab4eSNam Cao static void handle_contention_begin(void *data, void *lock, unsigned int flags) 66*6fdaab4eSNam Cao { 67*6fdaab4eSNam Cao if (flags & LCB_F_RT) 68*6fdaab4eSNam Cao ltl_atom_update(current, LTL_BLOCK_ON_RT_MUTEX, true); 69*6fdaab4eSNam Cao } 70*6fdaab4eSNam Cao 71*6fdaab4eSNam Cao static void handle_contention_end(void *data, void *lock, int ret) 72*6fdaab4eSNam Cao { 73*6fdaab4eSNam Cao ltl_atom_update(current, LTL_BLOCK_ON_RT_MUTEX, false); 74*6fdaab4eSNam Cao } 75*6fdaab4eSNam Cao 76*6fdaab4eSNam Cao static void handle_sys_enter(void *data, struct pt_regs *regs, long id) 77*6fdaab4eSNam Cao { 78*6fdaab4eSNam Cao unsigned long args[6]; 79*6fdaab4eSNam Cao int op, cmd; 80*6fdaab4eSNam Cao 81*6fdaab4eSNam Cao switch (id) { 82*6fdaab4eSNam Cao case __NR_futex: 83*6fdaab4eSNam Cao case __NR_futex_time64: 84*6fdaab4eSNam Cao syscall_get_arguments(current, regs, args); 85*6fdaab4eSNam Cao op = args[1]; 86*6fdaab4eSNam Cao cmd = op & FUTEX_CMD_MASK; 87*6fdaab4eSNam Cao 88*6fdaab4eSNam Cao switch (cmd) { 89*6fdaab4eSNam Cao case FUTEX_LOCK_PI: 90*6fdaab4eSNam Cao case FUTEX_LOCK_PI2: 91*6fdaab4eSNam Cao ltl_atom_update(current, LTL_FUTEX_LOCK_PI, true); 92*6fdaab4eSNam Cao break; 93*6fdaab4eSNam Cao } 94*6fdaab4eSNam Cao break; 95*6fdaab4eSNam Cao } 96*6fdaab4eSNam Cao } 97*6fdaab4eSNam Cao 98*6fdaab4eSNam Cao static void handle_sys_exit(void *data, struct pt_regs *regs, long ret) 99*6fdaab4eSNam Cao { 100*6fdaab4eSNam Cao ltl_atom_update(current, LTL_FUTEX_LOCK_PI, false); 101*6fdaab4eSNam Cao } 102*6fdaab4eSNam Cao 103*6fdaab4eSNam Cao static int enable_wakeup(void) 104*6fdaab4eSNam Cao { 105*6fdaab4eSNam Cao int retval; 106*6fdaab4eSNam Cao 107*6fdaab4eSNam Cao retval = ltl_monitor_init(); 108*6fdaab4eSNam Cao if (retval) 109*6fdaab4eSNam Cao return retval; 110*6fdaab4eSNam Cao 111*6fdaab4eSNam Cao rv_attach_trace_probe("rtapp_wakeup", sched_waking, handle_sched_waking); 112*6fdaab4eSNam Cao rv_attach_trace_probe("rtapp_wakeup", contention_begin, handle_contention_begin); 113*6fdaab4eSNam Cao rv_attach_trace_probe("rtapp_wakeup", contention_end, handle_contention_end); 114*6fdaab4eSNam Cao rv_attach_trace_probe("rtapp_wakeup", sys_enter, handle_sys_enter); 115*6fdaab4eSNam Cao rv_attach_trace_probe("rtapp_wakeup", sys_exit, handle_sys_exit); 116*6fdaab4eSNam Cao 117*6fdaab4eSNam Cao return 0; 118*6fdaab4eSNam Cao } 119*6fdaab4eSNam Cao 120*6fdaab4eSNam Cao static void disable_wakeup(void) 121*6fdaab4eSNam Cao { 122*6fdaab4eSNam Cao rv_detach_trace_probe("rtapp_wakeup", sched_waking, handle_sched_waking); 123*6fdaab4eSNam Cao rv_detach_trace_probe("rtapp_wakeup", contention_begin, handle_contention_begin); 124*6fdaab4eSNam Cao rv_detach_trace_probe("rtapp_wakeup", contention_end, handle_contention_end); 125*6fdaab4eSNam Cao rv_detach_trace_probe("rtapp_wakeup", sys_enter, handle_sys_enter); 126*6fdaab4eSNam Cao rv_detach_trace_probe("rtapp_wakeup", sys_exit, handle_sys_exit); 127*6fdaab4eSNam Cao 128*6fdaab4eSNam Cao ltl_monitor_destroy(); 129*6fdaab4eSNam Cao } 130*6fdaab4eSNam Cao 131*6fdaab4eSNam Cao static struct rv_monitor rv_wakeup = { 132*6fdaab4eSNam Cao .name = "wakeup", 133*6fdaab4eSNam Cao .description = "Monitor that real-time tasks are not woken by lower-priority tasks", 134*6fdaab4eSNam Cao .enable = enable_wakeup, 135*6fdaab4eSNam Cao .disable = disable_wakeup, 136*6fdaab4eSNam Cao }; 137*6fdaab4eSNam Cao 138*6fdaab4eSNam Cao static int __init register_wakeup(void) 139*6fdaab4eSNam Cao { 140*6fdaab4eSNam Cao return rv_register_monitor(&rv_wakeup, &rv_rtapp); 141*6fdaab4eSNam Cao } 142*6fdaab4eSNam Cao 143*6fdaab4eSNam Cao static void __exit unregister_wakeup(void) 144*6fdaab4eSNam Cao { 145*6fdaab4eSNam Cao rv_unregister_monitor(&rv_wakeup); 146*6fdaab4eSNam Cao } 147*6fdaab4eSNam Cao 148*6fdaab4eSNam Cao module_init(register_wakeup); 149*6fdaab4eSNam Cao module_exit(unregister_wakeup); 150*6fdaab4eSNam Cao 151*6fdaab4eSNam Cao MODULE_LICENSE("GPL"); 152*6fdaab4eSNam Cao MODULE_AUTHOR("Nam Cao <namcao@linutronix.de>"); 153*6fdaab4eSNam Cao MODULE_DESCRIPTION("Monitor that real-time tasks are not woken by lower-priority tasks"); 154