1*13578a08SGabriele Monaco // SPDX-License-Identifier: GPL-2.0 2*13578a08SGabriele Monaco #include <linux/ftrace.h> 3*13578a08SGabriele Monaco #include <linux/tracepoint.h> 4*13578a08SGabriele Monaco #include <linux/kernel.h> 5*13578a08SGabriele Monaco #include <linux/module.h> 6*13578a08SGabriele Monaco #include <linux/init.h> 7*13578a08SGabriele Monaco #include <linux/rv.h> 8*13578a08SGabriele Monaco #include <rv/instrumentation.h> 9*13578a08SGabriele Monaco 10*13578a08SGabriele Monaco #define MODULE_NAME "stall" 11*13578a08SGabriele Monaco 12*13578a08SGabriele Monaco #include <trace/events/sched.h> 13*13578a08SGabriele Monaco #include <rv_trace.h> 14*13578a08SGabriele Monaco 15*13578a08SGabriele Monaco #define RV_MON_TYPE RV_MON_PER_TASK 16*13578a08SGabriele Monaco #define HA_TIMER_TYPE HA_TIMER_WHEEL 17*13578a08SGabriele Monaco #include "stall.h" 18*13578a08SGabriele Monaco #include <rv/ha_monitor.h> 19*13578a08SGabriele Monaco 20*13578a08SGabriele Monaco static u64 threshold_jiffies = 1000; 21*13578a08SGabriele Monaco module_param(threshold_jiffies, ullong, 0644); 22*13578a08SGabriele Monaco 23*13578a08SGabriele Monaco static u64 ha_get_env(struct ha_monitor *ha_mon, enum envs_stall env, u64 time_ns) 24*13578a08SGabriele Monaco { 25*13578a08SGabriele Monaco if (env == clk_stall) 26*13578a08SGabriele Monaco return ha_get_clk_jiffy(ha_mon, env); 27*13578a08SGabriele Monaco return ENV_INVALID_VALUE; 28*13578a08SGabriele Monaco } 29*13578a08SGabriele Monaco 30*13578a08SGabriele Monaco static void ha_reset_env(struct ha_monitor *ha_mon, enum envs_stall env, u64 time_ns) 31*13578a08SGabriele Monaco { 32*13578a08SGabriele Monaco if (env == clk_stall) 33*13578a08SGabriele Monaco ha_reset_clk_jiffy(ha_mon, env); 34*13578a08SGabriele Monaco } 35*13578a08SGabriele Monaco 36*13578a08SGabriele Monaco static inline bool ha_verify_invariants(struct ha_monitor *ha_mon, 37*13578a08SGabriele Monaco enum states curr_state, enum events event, 38*13578a08SGabriele Monaco enum states next_state, u64 time_ns) 39*13578a08SGabriele Monaco { 40*13578a08SGabriele Monaco if (curr_state == enqueued_stall) 41*13578a08SGabriele Monaco return ha_check_invariant_jiffy(ha_mon, clk_stall, time_ns); 42*13578a08SGabriele Monaco return true; 43*13578a08SGabriele Monaco } 44*13578a08SGabriele Monaco 45*13578a08SGabriele Monaco static inline bool ha_verify_guards(struct ha_monitor *ha_mon, 46*13578a08SGabriele Monaco enum states curr_state, enum events event, 47*13578a08SGabriele Monaco enum states next_state, u64 time_ns) 48*13578a08SGabriele Monaco { 49*13578a08SGabriele Monaco bool res = true; 50*13578a08SGabriele Monaco 51*13578a08SGabriele Monaco if (curr_state == dequeued_stall && event == sched_wakeup_stall) 52*13578a08SGabriele Monaco ha_reset_env(ha_mon, clk_stall, time_ns); 53*13578a08SGabriele Monaco else if (curr_state == running_stall && event == sched_switch_preempt_stall) 54*13578a08SGabriele Monaco ha_reset_env(ha_mon, clk_stall, time_ns); 55*13578a08SGabriele Monaco return res; 56*13578a08SGabriele Monaco } 57*13578a08SGabriele Monaco 58*13578a08SGabriele Monaco static inline void ha_setup_invariants(struct ha_monitor *ha_mon, 59*13578a08SGabriele Monaco enum states curr_state, enum events event, 60*13578a08SGabriele Monaco enum states next_state, u64 time_ns) 61*13578a08SGabriele Monaco { 62*13578a08SGabriele Monaco if (next_state == curr_state) 63*13578a08SGabriele Monaco return; 64*13578a08SGabriele Monaco if (next_state == enqueued_stall) 65*13578a08SGabriele Monaco ha_start_timer_jiffy(ha_mon, clk_stall, threshold_jiffies, time_ns); 66*13578a08SGabriele Monaco else if (curr_state == enqueued_stall) 67*13578a08SGabriele Monaco ha_cancel_timer(ha_mon); 68*13578a08SGabriele Monaco } 69*13578a08SGabriele Monaco 70*13578a08SGabriele Monaco static bool ha_verify_constraint(struct ha_monitor *ha_mon, 71*13578a08SGabriele Monaco enum states curr_state, enum events event, 72*13578a08SGabriele Monaco enum states next_state, u64 time_ns) 73*13578a08SGabriele Monaco { 74*13578a08SGabriele Monaco if (!ha_verify_invariants(ha_mon, curr_state, event, next_state, time_ns)) 75*13578a08SGabriele Monaco return false; 76*13578a08SGabriele Monaco 77*13578a08SGabriele Monaco if (!ha_verify_guards(ha_mon, curr_state, event, next_state, time_ns)) 78*13578a08SGabriele Monaco return false; 79*13578a08SGabriele Monaco 80*13578a08SGabriele Monaco ha_setup_invariants(ha_mon, curr_state, event, next_state, time_ns); 81*13578a08SGabriele Monaco 82*13578a08SGabriele Monaco return true; 83*13578a08SGabriele Monaco } 84*13578a08SGabriele Monaco 85*13578a08SGabriele Monaco static void handle_sched_switch(void *data, bool preempt, 86*13578a08SGabriele Monaco struct task_struct *prev, 87*13578a08SGabriele Monaco struct task_struct *next, 88*13578a08SGabriele Monaco unsigned int prev_state) 89*13578a08SGabriele Monaco { 90*13578a08SGabriele Monaco if (!preempt && prev_state != TASK_RUNNING) 91*13578a08SGabriele Monaco da_handle_start_event(prev, sched_switch_wait_stall); 92*13578a08SGabriele Monaco else 93*13578a08SGabriele Monaco da_handle_event(prev, sched_switch_preempt_stall); 94*13578a08SGabriele Monaco da_handle_event(next, sched_switch_in_stall); 95*13578a08SGabriele Monaco } 96*13578a08SGabriele Monaco 97*13578a08SGabriele Monaco static void handle_sched_wakeup(void *data, struct task_struct *p) 98*13578a08SGabriele Monaco { 99*13578a08SGabriele Monaco da_handle_event(p, sched_wakeup_stall); 100*13578a08SGabriele Monaco } 101*13578a08SGabriele Monaco 102*13578a08SGabriele Monaco static int enable_stall(void) 103*13578a08SGabriele Monaco { 104*13578a08SGabriele Monaco int retval; 105*13578a08SGabriele Monaco 106*13578a08SGabriele Monaco retval = da_monitor_init(); 107*13578a08SGabriele Monaco if (retval) 108*13578a08SGabriele Monaco return retval; 109*13578a08SGabriele Monaco 110*13578a08SGabriele Monaco rv_attach_trace_probe("stall", sched_switch, handle_sched_switch); 111*13578a08SGabriele Monaco rv_attach_trace_probe("stall", sched_wakeup, handle_sched_wakeup); 112*13578a08SGabriele Monaco 113*13578a08SGabriele Monaco return 0; 114*13578a08SGabriele Monaco } 115*13578a08SGabriele Monaco 116*13578a08SGabriele Monaco static void disable_stall(void) 117*13578a08SGabriele Monaco { 118*13578a08SGabriele Monaco rv_this.enabled = 0; 119*13578a08SGabriele Monaco 120*13578a08SGabriele Monaco rv_detach_trace_probe("stall", sched_switch, handle_sched_switch); 121*13578a08SGabriele Monaco rv_detach_trace_probe("stall", sched_wakeup, handle_sched_wakeup); 122*13578a08SGabriele Monaco 123*13578a08SGabriele Monaco da_monitor_destroy(); 124*13578a08SGabriele Monaco } 125*13578a08SGabriele Monaco 126*13578a08SGabriele Monaco static struct rv_monitor rv_this = { 127*13578a08SGabriele Monaco .name = "stall", 128*13578a08SGabriele Monaco .description = "identify tasks stalled for longer than a threshold.", 129*13578a08SGabriele Monaco .enable = enable_stall, 130*13578a08SGabriele Monaco .disable = disable_stall, 131*13578a08SGabriele Monaco .reset = da_monitor_reset_all, 132*13578a08SGabriele Monaco .enabled = 0, 133*13578a08SGabriele Monaco }; 134*13578a08SGabriele Monaco 135*13578a08SGabriele Monaco static int __init register_stall(void) 136*13578a08SGabriele Monaco { 137*13578a08SGabriele Monaco return rv_register_monitor(&rv_this, NULL); 138*13578a08SGabriele Monaco } 139*13578a08SGabriele Monaco 140*13578a08SGabriele Monaco static void __exit unregister_stall(void) 141*13578a08SGabriele Monaco { 142*13578a08SGabriele Monaco rv_unregister_monitor(&rv_this); 143*13578a08SGabriele Monaco } 144*13578a08SGabriele Monaco 145*13578a08SGabriele Monaco module_init(register_stall); 146*13578a08SGabriele Monaco module_exit(unregister_stall); 147*13578a08SGabriele Monaco 148*13578a08SGabriele Monaco MODULE_LICENSE("GPL"); 149*13578a08SGabriele Monaco MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 150*13578a08SGabriele Monaco MODULE_DESCRIPTION("stall: identify tasks stalled for longer than a threshold."); 151