1*e8440a88SGabriele Monaco // SPDX-License-Identifier: GPL-2.0 2*e8440a88SGabriele Monaco #include <linux/ftrace.h> 3*e8440a88SGabriele Monaco #include <linux/tracepoint.h> 4*e8440a88SGabriele Monaco #include <linux/kernel.h> 5*e8440a88SGabriele Monaco #include <linux/module.h> 6*e8440a88SGabriele Monaco #include <linux/init.h> 7*e8440a88SGabriele Monaco #include <linux/rv.h> 8*e8440a88SGabriele Monaco #include <rv/instrumentation.h> 9*e8440a88SGabriele Monaco #include <rv/da_monitor.h> 10*e8440a88SGabriele Monaco 11*e8440a88SGabriele Monaco #define MODULE_NAME "nrp" 12*e8440a88SGabriele Monaco 13*e8440a88SGabriele Monaco #include <trace/events/irq.h> 14*e8440a88SGabriele Monaco #include <trace/events/sched.h> 15*e8440a88SGabriele Monaco #include <rv_trace.h> 16*e8440a88SGabriele Monaco #include <monitors/sched/sched.h> 17*e8440a88SGabriele Monaco 18*e8440a88SGabriele Monaco #include "nrp.h" 19*e8440a88SGabriele Monaco 20*e8440a88SGabriele Monaco static struct rv_monitor rv_nrp; 21*e8440a88SGabriele Monaco DECLARE_DA_MON_PER_TASK(nrp, unsigned char); 22*e8440a88SGabriele Monaco 23*e8440a88SGabriele Monaco #ifdef CONFIG_X86_LOCAL_APIC 24*e8440a88SGabriele Monaco #include <asm/trace/irq_vectors.h> 25*e8440a88SGabriele Monaco 26*e8440a88SGabriele Monaco static void handle_vector_irq_entry(void *data, int vector) 27*e8440a88SGabriele Monaco { 28*e8440a88SGabriele Monaco da_handle_event_nrp(current, irq_entry_nrp); 29*e8440a88SGabriele Monaco } 30*e8440a88SGabriele Monaco 31*e8440a88SGabriele Monaco static void attach_vector_irq(void) 32*e8440a88SGabriele Monaco { 33*e8440a88SGabriele Monaco rv_attach_trace_probe("nrp", local_timer_entry, handle_vector_irq_entry); 34*e8440a88SGabriele Monaco if (IS_ENABLED(CONFIG_IRQ_WORK)) 35*e8440a88SGabriele Monaco rv_attach_trace_probe("nrp", irq_work_entry, handle_vector_irq_entry); 36*e8440a88SGabriele Monaco if (IS_ENABLED(CONFIG_SMP)) { 37*e8440a88SGabriele Monaco rv_attach_trace_probe("nrp", reschedule_entry, handle_vector_irq_entry); 38*e8440a88SGabriele Monaco rv_attach_trace_probe("nrp", call_function_entry, handle_vector_irq_entry); 39*e8440a88SGabriele Monaco rv_attach_trace_probe("nrp", call_function_single_entry, handle_vector_irq_entry); 40*e8440a88SGabriele Monaco } 41*e8440a88SGabriele Monaco } 42*e8440a88SGabriele Monaco 43*e8440a88SGabriele Monaco static void detach_vector_irq(void) 44*e8440a88SGabriele Monaco { 45*e8440a88SGabriele Monaco rv_detach_trace_probe("nrp", local_timer_entry, handle_vector_irq_entry); 46*e8440a88SGabriele Monaco if (IS_ENABLED(CONFIG_IRQ_WORK)) 47*e8440a88SGabriele Monaco rv_detach_trace_probe("nrp", irq_work_entry, handle_vector_irq_entry); 48*e8440a88SGabriele Monaco if (IS_ENABLED(CONFIG_SMP)) { 49*e8440a88SGabriele Monaco rv_detach_trace_probe("nrp", reschedule_entry, handle_vector_irq_entry); 50*e8440a88SGabriele Monaco rv_detach_trace_probe("nrp", call_function_entry, handle_vector_irq_entry); 51*e8440a88SGabriele Monaco rv_detach_trace_probe("nrp", call_function_single_entry, handle_vector_irq_entry); 52*e8440a88SGabriele Monaco } 53*e8440a88SGabriele Monaco } 54*e8440a88SGabriele Monaco 55*e8440a88SGabriele Monaco #else 56*e8440a88SGabriele Monaco /* We assume irq_entry tracepoints are sufficient on other architectures */ 57*e8440a88SGabriele Monaco static void attach_vector_irq(void) { } 58*e8440a88SGabriele Monaco static void detach_vector_irq(void) { } 59*e8440a88SGabriele Monaco #endif 60*e8440a88SGabriele Monaco 61*e8440a88SGabriele Monaco static void handle_irq_entry(void *data, int irq, struct irqaction *action) 62*e8440a88SGabriele Monaco { 63*e8440a88SGabriele Monaco da_handle_event_nrp(current, irq_entry_nrp); 64*e8440a88SGabriele Monaco } 65*e8440a88SGabriele Monaco 66*e8440a88SGabriele Monaco static void handle_sched_need_resched(void *data, struct task_struct *tsk, 67*e8440a88SGabriele Monaco int cpu, int tif) 68*e8440a88SGabriele Monaco { 69*e8440a88SGabriele Monaco /* 70*e8440a88SGabriele Monaco * Although need_resched leads to both the rescheduling and preempt_irq 71*e8440a88SGabriele Monaco * states, it is safer to start the monitor always in preempt_irq, 72*e8440a88SGabriele Monaco * which may not mirror the system state but makes the monitor simpler, 73*e8440a88SGabriele Monaco */ 74*e8440a88SGabriele Monaco if (tif == TIF_NEED_RESCHED) 75*e8440a88SGabriele Monaco da_handle_start_event_nrp(tsk, sched_need_resched_nrp); 76*e8440a88SGabriele Monaco } 77*e8440a88SGabriele Monaco 78*e8440a88SGabriele Monaco static void handle_schedule_entry(void *data, bool preempt) 79*e8440a88SGabriele Monaco { 80*e8440a88SGabriele Monaco if (preempt) 81*e8440a88SGabriele Monaco da_handle_event_nrp(current, schedule_entry_preempt_nrp); 82*e8440a88SGabriele Monaco else 83*e8440a88SGabriele Monaco da_handle_event_nrp(current, schedule_entry_nrp); 84*e8440a88SGabriele Monaco } 85*e8440a88SGabriele Monaco 86*e8440a88SGabriele Monaco static int enable_nrp(void) 87*e8440a88SGabriele Monaco { 88*e8440a88SGabriele Monaco int retval; 89*e8440a88SGabriele Monaco 90*e8440a88SGabriele Monaco retval = da_monitor_init_nrp(); 91*e8440a88SGabriele Monaco if (retval) 92*e8440a88SGabriele Monaco return retval; 93*e8440a88SGabriele Monaco 94*e8440a88SGabriele Monaco rv_attach_trace_probe("nrp", irq_handler_entry, handle_irq_entry); 95*e8440a88SGabriele Monaco rv_attach_trace_probe("nrp", sched_set_need_resched_tp, handle_sched_need_resched); 96*e8440a88SGabriele Monaco rv_attach_trace_probe("nrp", sched_entry_tp, handle_schedule_entry); 97*e8440a88SGabriele Monaco attach_vector_irq(); 98*e8440a88SGabriele Monaco 99*e8440a88SGabriele Monaco return 0; 100*e8440a88SGabriele Monaco } 101*e8440a88SGabriele Monaco 102*e8440a88SGabriele Monaco static void disable_nrp(void) 103*e8440a88SGabriele Monaco { 104*e8440a88SGabriele Monaco rv_nrp.enabled = 0; 105*e8440a88SGabriele Monaco 106*e8440a88SGabriele Monaco rv_detach_trace_probe("nrp", irq_handler_entry, handle_irq_entry); 107*e8440a88SGabriele Monaco rv_detach_trace_probe("nrp", sched_set_need_resched_tp, handle_sched_need_resched); 108*e8440a88SGabriele Monaco rv_detach_trace_probe("nrp", sched_entry_tp, handle_schedule_entry); 109*e8440a88SGabriele Monaco detach_vector_irq(); 110*e8440a88SGabriele Monaco 111*e8440a88SGabriele Monaco da_monitor_destroy_nrp(); 112*e8440a88SGabriele Monaco } 113*e8440a88SGabriele Monaco 114*e8440a88SGabriele Monaco static struct rv_monitor rv_nrp = { 115*e8440a88SGabriele Monaco .name = "nrp", 116*e8440a88SGabriele Monaco .description = "need resched preempts.", 117*e8440a88SGabriele Monaco .enable = enable_nrp, 118*e8440a88SGabriele Monaco .disable = disable_nrp, 119*e8440a88SGabriele Monaco .reset = da_monitor_reset_all_nrp, 120*e8440a88SGabriele Monaco .enabled = 0, 121*e8440a88SGabriele Monaco }; 122*e8440a88SGabriele Monaco 123*e8440a88SGabriele Monaco static int __init register_nrp(void) 124*e8440a88SGabriele Monaco { 125*e8440a88SGabriele Monaco return rv_register_monitor(&rv_nrp, &rv_sched); 126*e8440a88SGabriele Monaco } 127*e8440a88SGabriele Monaco 128*e8440a88SGabriele Monaco static void __exit unregister_nrp(void) 129*e8440a88SGabriele Monaco { 130*e8440a88SGabriele Monaco rv_unregister_monitor(&rv_nrp); 131*e8440a88SGabriele Monaco } 132*e8440a88SGabriele Monaco 133*e8440a88SGabriele Monaco module_init(register_nrp); 134*e8440a88SGabriele Monaco module_exit(unregister_nrp); 135*e8440a88SGabriele Monaco 136*e8440a88SGabriele Monaco MODULE_LICENSE("GPL"); 137*e8440a88SGabriele Monaco MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 138*e8440a88SGabriele Monaco MODULE_DESCRIPTION("nrp: need resched preempts."); 139