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 "sts" 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 "sts.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_sts); 28 } 29 30 static void attach_vector_irq(void) 31 { 32 rv_attach_trace_probe("sts", local_timer_entry, handle_vector_irq_entry); 33 if (IS_ENABLED(CONFIG_IRQ_WORK)) 34 rv_attach_trace_probe("sts", irq_work_entry, handle_vector_irq_entry); 35 if (IS_ENABLED(CONFIG_SMP)) { 36 rv_attach_trace_probe("sts", reschedule_entry, handle_vector_irq_entry); 37 rv_attach_trace_probe("sts", call_function_entry, handle_vector_irq_entry); 38 rv_attach_trace_probe("sts", call_function_single_entry, handle_vector_irq_entry); 39 } 40 } 41 42 static void detach_vector_irq(void) 43 { 44 rv_detach_trace_probe("sts", local_timer_entry, handle_vector_irq_entry); 45 if (IS_ENABLED(CONFIG_IRQ_WORK)) 46 rv_detach_trace_probe("sts", irq_work_entry, handle_vector_irq_entry); 47 if (IS_ENABLED(CONFIG_SMP)) { 48 rv_detach_trace_probe("sts", reschedule_entry, handle_vector_irq_entry); 49 rv_detach_trace_probe("sts", call_function_entry, handle_vector_irq_entry); 50 rv_detach_trace_probe("sts", 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_sts); 63 } 64 65 static void handle_irq_enable(void *data, unsigned long ip, unsigned long parent_ip) 66 { 67 da_handle_event(irq_enable_sts); 68 } 69 70 static void handle_irq_entry(void *data, int irq, struct irqaction *action) 71 { 72 da_handle_event(irq_entry_sts); 73 } 74 75 static void handle_sched_switch(void *data, bool preempt, 76 struct task_struct *prev, 77 struct task_struct *next, 78 unsigned int prev_state) 79 { 80 da_handle_event(sched_switch_sts); 81 } 82 83 static void handle_schedule_entry(void *data, bool preempt) 84 { 85 da_handle_event(schedule_entry_sts); 86 } 87 88 static void handle_schedule_exit(void *data, bool is_switch) 89 { 90 da_handle_start_event(schedule_exit_sts); 91 } 92 93 static int enable_sts(void) 94 { 95 int retval; 96 97 retval = da_monitor_init(); 98 if (retval) 99 return retval; 100 101 rv_attach_trace_probe("sts", irq_disable, handle_irq_disable); 102 rv_attach_trace_probe("sts", irq_enable, handle_irq_enable); 103 rv_attach_trace_probe("sts", irq_handler_entry, handle_irq_entry); 104 rv_attach_trace_probe("sts", sched_switch, handle_sched_switch); 105 rv_attach_trace_probe("sts", sched_entry_tp, handle_schedule_entry); 106 rv_attach_trace_probe("sts", sched_exit_tp, handle_schedule_exit); 107 attach_vector_irq(); 108 109 return 0; 110 } 111 112 static void disable_sts(void) 113 { 114 rv_this.enabled = 0; 115 116 rv_detach_trace_probe("sts", irq_disable, handle_irq_disable); 117 rv_detach_trace_probe("sts", irq_enable, handle_irq_enable); 118 rv_detach_trace_probe("sts", irq_handler_entry, handle_irq_entry); 119 rv_detach_trace_probe("sts", sched_switch, handle_sched_switch); 120 rv_detach_trace_probe("sts", sched_entry_tp, handle_schedule_entry); 121 rv_detach_trace_probe("sts", sched_exit_tp, handle_schedule_exit); 122 detach_vector_irq(); 123 124 da_monitor_destroy(); 125 } 126 127 /* 128 * This is the monitor register section. 129 */ 130 static struct rv_monitor rv_this = { 131 .name = "sts", 132 .description = "schedule implies task switch.", 133 .enable = enable_sts, 134 .disable = disable_sts, 135 .reset = da_monitor_reset_all, 136 .enabled = 0, 137 }; 138 139 static int __init register_sts(void) 140 { 141 return rv_register_monitor(&rv_this, &rv_sched); 142 } 143 144 static void __exit unregister_sts(void) 145 { 146 rv_unregister_monitor(&rv_this); 147 } 148 149 module_init(register_sts); 150 module_exit(unregister_sts); 151 152 MODULE_LICENSE("GPL"); 153 MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 154 MODULE_DESCRIPTION("sts: schedule implies task switch."); 155