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