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