1*61438453SGabriele Monaco // SPDX-License-Identifier: GPL-2.0
2*61438453SGabriele Monaco #include <linux/ftrace.h>
3*61438453SGabriele Monaco #include <linux/tracepoint.h>
4*61438453SGabriele Monaco #include <linux/kernel.h>
5*61438453SGabriele Monaco #include <linux/module.h>
6*61438453SGabriele Monaco #include <linux/init.h>
7*61438453SGabriele Monaco #include <linux/rv.h>
8*61438453SGabriele Monaco #include <rv/instrumentation.h>
9*61438453SGabriele Monaco #include <rv/da_monitor.h>
10*61438453SGabriele Monaco
11*61438453SGabriele Monaco #define MODULE_NAME "opid"
12*61438453SGabriele Monaco
13*61438453SGabriele Monaco #include <trace/events/sched.h>
14*61438453SGabriele Monaco #include <trace/events/irq.h>
15*61438453SGabriele Monaco #include <trace/events/preemptirq.h>
16*61438453SGabriele Monaco #include <rv_trace.h>
17*61438453SGabriele Monaco #include <monitors/sched/sched.h>
18*61438453SGabriele Monaco
19*61438453SGabriele Monaco #include "opid.h"
20*61438453SGabriele Monaco
21*61438453SGabriele Monaco static struct rv_monitor rv_opid;
22*61438453SGabriele Monaco DECLARE_DA_MON_PER_CPU(opid, unsigned char);
23*61438453SGabriele Monaco
24*61438453SGabriele Monaco #ifdef CONFIG_X86_LOCAL_APIC
25*61438453SGabriele Monaco #include <asm/trace/irq_vectors.h>
26*61438453SGabriele Monaco
handle_vector_irq_entry(void * data,int vector)27*61438453SGabriele Monaco static void handle_vector_irq_entry(void *data, int vector)
28*61438453SGabriele Monaco {
29*61438453SGabriele Monaco da_handle_event_opid(irq_entry_opid);
30*61438453SGabriele Monaco }
31*61438453SGabriele Monaco
attach_vector_irq(void)32*61438453SGabriele Monaco static void attach_vector_irq(void)
33*61438453SGabriele Monaco {
34*61438453SGabriele Monaco rv_attach_trace_probe("opid", local_timer_entry, handle_vector_irq_entry);
35*61438453SGabriele Monaco if (IS_ENABLED(CONFIG_IRQ_WORK))
36*61438453SGabriele Monaco rv_attach_trace_probe("opid", irq_work_entry, handle_vector_irq_entry);
37*61438453SGabriele Monaco if (IS_ENABLED(CONFIG_SMP)) {
38*61438453SGabriele Monaco rv_attach_trace_probe("opid", reschedule_entry, handle_vector_irq_entry);
39*61438453SGabriele Monaco rv_attach_trace_probe("opid", call_function_entry, handle_vector_irq_entry);
40*61438453SGabriele Monaco rv_attach_trace_probe("opid", call_function_single_entry, handle_vector_irq_entry);
41*61438453SGabriele Monaco }
42*61438453SGabriele Monaco }
43*61438453SGabriele Monaco
detach_vector_irq(void)44*61438453SGabriele Monaco static void detach_vector_irq(void)
45*61438453SGabriele Monaco {
46*61438453SGabriele Monaco rv_detach_trace_probe("opid", local_timer_entry, handle_vector_irq_entry);
47*61438453SGabriele Monaco if (IS_ENABLED(CONFIG_IRQ_WORK))
48*61438453SGabriele Monaco rv_detach_trace_probe("opid", irq_work_entry, handle_vector_irq_entry);
49*61438453SGabriele Monaco if (IS_ENABLED(CONFIG_SMP)) {
50*61438453SGabriele Monaco rv_detach_trace_probe("opid", reschedule_entry, handle_vector_irq_entry);
51*61438453SGabriele Monaco rv_detach_trace_probe("opid", call_function_entry, handle_vector_irq_entry);
52*61438453SGabriele Monaco rv_detach_trace_probe("opid", call_function_single_entry, handle_vector_irq_entry);
53*61438453SGabriele Monaco }
54*61438453SGabriele Monaco }
55*61438453SGabriele Monaco
56*61438453SGabriele Monaco #else
57*61438453SGabriele Monaco /* We assume irq_entry tracepoints are sufficient on other architectures */
attach_vector_irq(void)58*61438453SGabriele Monaco static void attach_vector_irq(void) { }
detach_vector_irq(void)59*61438453SGabriele Monaco static void detach_vector_irq(void) { }
60*61438453SGabriele Monaco #endif
61*61438453SGabriele Monaco
handle_irq_disable(void * data,unsigned long ip,unsigned long parent_ip)62*61438453SGabriele Monaco static void handle_irq_disable(void *data, unsigned long ip, unsigned long parent_ip)
63*61438453SGabriele Monaco {
64*61438453SGabriele Monaco da_handle_event_opid(irq_disable_opid);
65*61438453SGabriele Monaco }
66*61438453SGabriele Monaco
handle_irq_enable(void * data,unsigned long ip,unsigned long parent_ip)67*61438453SGabriele Monaco static void handle_irq_enable(void *data, unsigned long ip, unsigned long parent_ip)
68*61438453SGabriele Monaco {
69*61438453SGabriele Monaco da_handle_event_opid(irq_enable_opid);
70*61438453SGabriele Monaco }
71*61438453SGabriele Monaco
handle_irq_entry(void * data,int irq,struct irqaction * action)72*61438453SGabriele Monaco static void handle_irq_entry(void *data, int irq, struct irqaction *action)
73*61438453SGabriele Monaco {
74*61438453SGabriele Monaco da_handle_event_opid(irq_entry_opid);
75*61438453SGabriele Monaco }
76*61438453SGabriele Monaco
handle_preempt_disable(void * data,unsigned long ip,unsigned long parent_ip)77*61438453SGabriele Monaco static void handle_preempt_disable(void *data, unsigned long ip, unsigned long parent_ip)
78*61438453SGabriele Monaco {
79*61438453SGabriele Monaco da_handle_event_opid(preempt_disable_opid);
80*61438453SGabriele Monaco }
81*61438453SGabriele Monaco
handle_preempt_enable(void * data,unsigned long ip,unsigned long parent_ip)82*61438453SGabriele Monaco static void handle_preempt_enable(void *data, unsigned long ip, unsigned long parent_ip)
83*61438453SGabriele Monaco {
84*61438453SGabriele Monaco da_handle_event_opid(preempt_enable_opid);
85*61438453SGabriele Monaco }
86*61438453SGabriele Monaco
handle_sched_need_resched(void * data,struct task_struct * tsk,int cpu,int tif)87*61438453SGabriele Monaco static void handle_sched_need_resched(void *data, struct task_struct *tsk, int cpu, int tif)
88*61438453SGabriele Monaco {
89*61438453SGabriele Monaco /* The monitor's intitial state is not in_irq */
90*61438453SGabriele Monaco if (this_cpu_read(hardirq_context))
91*61438453SGabriele Monaco da_handle_event_opid(sched_need_resched_opid);
92*61438453SGabriele Monaco else
93*61438453SGabriele Monaco da_handle_start_event_opid(sched_need_resched_opid);
94*61438453SGabriele Monaco }
95*61438453SGabriele Monaco
handle_sched_waking(void * data,struct task_struct * p)96*61438453SGabriele Monaco static void handle_sched_waking(void *data, struct task_struct *p)
97*61438453SGabriele Monaco {
98*61438453SGabriele Monaco /* The monitor's intitial state is not in_irq */
99*61438453SGabriele Monaco if (this_cpu_read(hardirq_context))
100*61438453SGabriele Monaco da_handle_event_opid(sched_waking_opid);
101*61438453SGabriele Monaco else
102*61438453SGabriele Monaco da_handle_start_event_opid(sched_waking_opid);
103*61438453SGabriele Monaco }
104*61438453SGabriele Monaco
enable_opid(void)105*61438453SGabriele Monaco static int enable_opid(void)
106*61438453SGabriele Monaco {
107*61438453SGabriele Monaco int retval;
108*61438453SGabriele Monaco
109*61438453SGabriele Monaco retval = da_monitor_init_opid();
110*61438453SGabriele Monaco if (retval)
111*61438453SGabriele Monaco return retval;
112*61438453SGabriele Monaco
113*61438453SGabriele Monaco rv_attach_trace_probe("opid", irq_disable, handle_irq_disable);
114*61438453SGabriele Monaco rv_attach_trace_probe("opid", irq_enable, handle_irq_enable);
115*61438453SGabriele Monaco rv_attach_trace_probe("opid", irq_handler_entry, handle_irq_entry);
116*61438453SGabriele Monaco rv_attach_trace_probe("opid", preempt_disable, handle_preempt_disable);
117*61438453SGabriele Monaco rv_attach_trace_probe("opid", preempt_enable, handle_preempt_enable);
118*61438453SGabriele Monaco rv_attach_trace_probe("opid", sched_set_need_resched_tp, handle_sched_need_resched);
119*61438453SGabriele Monaco rv_attach_trace_probe("opid", sched_waking, handle_sched_waking);
120*61438453SGabriele Monaco attach_vector_irq();
121*61438453SGabriele Monaco
122*61438453SGabriele Monaco return 0;
123*61438453SGabriele Monaco }
124*61438453SGabriele Monaco
disable_opid(void)125*61438453SGabriele Monaco static void disable_opid(void)
126*61438453SGabriele Monaco {
127*61438453SGabriele Monaco rv_opid.enabled = 0;
128*61438453SGabriele Monaco
129*61438453SGabriele Monaco rv_detach_trace_probe("opid", irq_disable, handle_irq_disable);
130*61438453SGabriele Monaco rv_detach_trace_probe("opid", irq_enable, handle_irq_enable);
131*61438453SGabriele Monaco rv_detach_trace_probe("opid", irq_handler_entry, handle_irq_entry);
132*61438453SGabriele Monaco rv_detach_trace_probe("opid", preempt_disable, handle_preempt_disable);
133*61438453SGabriele Monaco rv_detach_trace_probe("opid", preempt_enable, handle_preempt_enable);
134*61438453SGabriele Monaco rv_detach_trace_probe("opid", sched_set_need_resched_tp, handle_sched_need_resched);
135*61438453SGabriele Monaco rv_detach_trace_probe("opid", sched_waking, handle_sched_waking);
136*61438453SGabriele Monaco detach_vector_irq();
137*61438453SGabriele Monaco
138*61438453SGabriele Monaco da_monitor_destroy_opid();
139*61438453SGabriele Monaco }
140*61438453SGabriele Monaco
141*61438453SGabriele Monaco /*
142*61438453SGabriele Monaco * This is the monitor register section.
143*61438453SGabriele Monaco */
144*61438453SGabriele Monaco static struct rv_monitor rv_opid = {
145*61438453SGabriele Monaco .name = "opid",
146*61438453SGabriele Monaco .description = "operations with preemption and irq disabled.",
147*61438453SGabriele Monaco .enable = enable_opid,
148*61438453SGabriele Monaco .disable = disable_opid,
149*61438453SGabriele Monaco .reset = da_monitor_reset_all_opid,
150*61438453SGabriele Monaco .enabled = 0,
151*61438453SGabriele Monaco };
152*61438453SGabriele Monaco
register_opid(void)153*61438453SGabriele Monaco static int __init register_opid(void)
154*61438453SGabriele Monaco {
155*61438453SGabriele Monaco return rv_register_monitor(&rv_opid, &rv_sched);
156*61438453SGabriele Monaco }
157*61438453SGabriele Monaco
unregister_opid(void)158*61438453SGabriele Monaco static void __exit unregister_opid(void)
159*61438453SGabriele Monaco {
160*61438453SGabriele Monaco rv_unregister_monitor(&rv_opid);
161*61438453SGabriele Monaco }
162*61438453SGabriele Monaco
163*61438453SGabriele Monaco module_init(register_opid);
164*61438453SGabriele Monaco module_exit(unregister_opid);
165*61438453SGabriele Monaco
166*61438453SGabriele Monaco MODULE_LICENSE("GPL");
167*61438453SGabriele Monaco MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
168*61438453SGabriele Monaco MODULE_DESCRIPTION("opid: operations with preemption and irq disabled.");
169