xref: /linux/kernel/trace/rv/monitors/wakeup/wakeup.c (revision 55ee4b931a7ffedc886175d265dd6e6d08fd4151)
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