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 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 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 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 */ 58*61438453SGabriele Monaco static void attach_vector_irq(void) { } 59*61438453SGabriele Monaco static void detach_vector_irq(void) { } 60*61438453SGabriele Monaco #endif 61*61438453SGabriele Monaco 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 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 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 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 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 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 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 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 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 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 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