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