1*9ef64711SSamuel Wu // SPDX-License-Identifier: GPL-2.0 2*9ef64711SSamuel Wu /* Copyright 2026 Google LLC */ 3*9ef64711SSamuel Wu 4*9ef64711SSamuel Wu #include "vmlinux.h" 5*9ef64711SSamuel Wu #include <bpf/bpf_helpers.h> 6*9ef64711SSamuel Wu #include <bpf/bpf_core_read.h> 7*9ef64711SSamuel Wu #include "bpf_experimental.h" 8*9ef64711SSamuel Wu #include "bpf_misc.h" 9*9ef64711SSamuel Wu #include "wakeup_source.h" 10*9ef64711SSamuel Wu 11*9ef64711SSamuel Wu #define MAX_LOOP_ITER 1000 12*9ef64711SSamuel Wu #define RB_SIZE (16384 * 4) 13*9ef64711SSamuel Wu 14*9ef64711SSamuel Wu struct { 15*9ef64711SSamuel Wu __uint(type, BPF_MAP_TYPE_RINGBUF); 16*9ef64711SSamuel Wu __uint(max_entries, RB_SIZE); 17*9ef64711SSamuel Wu } rb SEC(".maps"); 18*9ef64711SSamuel Wu 19*9ef64711SSamuel Wu struct bpf_ws_lock; 20*9ef64711SSamuel Wu struct bpf_ws_lock *bpf_wakeup_sources_read_lock(void) __ksym; 21*9ef64711SSamuel Wu void bpf_wakeup_sources_read_unlock(struct bpf_ws_lock *lock) __ksym; 22*9ef64711SSamuel Wu void *bpf_wakeup_sources_get_head(void) __ksym; 23*9ef64711SSamuel Wu 24*9ef64711SSamuel Wu SEC("syscall") 25*9ef64711SSamuel Wu __success __retval(0) 26*9ef64711SSamuel Wu int iterate_wakeupsources(void *ctx) 27*9ef64711SSamuel Wu { 28*9ef64711SSamuel Wu struct list_head *head = bpf_wakeup_sources_get_head(); 29*9ef64711SSamuel Wu struct list_head *pos = head; 30*9ef64711SSamuel Wu struct bpf_ws_lock *lock; 31*9ef64711SSamuel Wu int i; 32*9ef64711SSamuel Wu 33*9ef64711SSamuel Wu lock = bpf_wakeup_sources_read_lock(); 34*9ef64711SSamuel Wu if (!lock) 35*9ef64711SSamuel Wu return 0; 36*9ef64711SSamuel Wu 37*9ef64711SSamuel Wu bpf_for(i, 0, MAX_LOOP_ITER) { 38*9ef64711SSamuel Wu if (bpf_core_read(&pos, sizeof(pos), &pos->next) || !pos || pos == head) 39*9ef64711SSamuel Wu break; 40*9ef64711SSamuel Wu 41*9ef64711SSamuel Wu struct wakeup_event_t *e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); 42*9ef64711SSamuel Wu 43*9ef64711SSamuel Wu if (!e) 44*9ef64711SSamuel Wu break; 45*9ef64711SSamuel Wu 46*9ef64711SSamuel Wu struct wakeup_source *ws = bpf_core_cast( 47*9ef64711SSamuel Wu (void *)pos - bpf_core_field_offset(struct wakeup_source, entry), 48*9ef64711SSamuel Wu struct wakeup_source); 49*9ef64711SSamuel Wu s64 active_time = 0; 50*9ef64711SSamuel Wu bool active = BPF_CORE_READ_BITFIELD(ws, active); 51*9ef64711SSamuel Wu bool autosleep_enable = BPF_CORE_READ_BITFIELD(ws, autosleep_enabled); 52*9ef64711SSamuel Wu s64 last_time = ws->last_time; 53*9ef64711SSamuel Wu s64 max_time = ws->max_time; 54*9ef64711SSamuel Wu s64 prevent_sleep_time = ws->prevent_sleep_time; 55*9ef64711SSamuel Wu s64 total_time = ws->total_time; 56*9ef64711SSamuel Wu 57*9ef64711SSamuel Wu if (active) { 58*9ef64711SSamuel Wu s64 curr_time = bpf_ktime_get_ns(); 59*9ef64711SSamuel Wu s64 prevent_time = ws->start_prevent_time; 60*9ef64711SSamuel Wu 61*9ef64711SSamuel Wu if (curr_time > last_time) 62*9ef64711SSamuel Wu active_time = curr_time - last_time; 63*9ef64711SSamuel Wu 64*9ef64711SSamuel Wu total_time += active_time; 65*9ef64711SSamuel Wu if (active_time > max_time) 66*9ef64711SSamuel Wu max_time = active_time; 67*9ef64711SSamuel Wu if (autosleep_enable && curr_time > prevent_time) 68*9ef64711SSamuel Wu prevent_sleep_time += curr_time - prevent_time; 69*9ef64711SSamuel Wu } 70*9ef64711SSamuel Wu 71*9ef64711SSamuel Wu e->active_count = ws->active_count; 72*9ef64711SSamuel Wu e->active_time_ns = active_time; 73*9ef64711SSamuel Wu e->event_count = ws->event_count; 74*9ef64711SSamuel Wu e->expire_count = ws->expire_count; 75*9ef64711SSamuel Wu e->last_time_ns = last_time; 76*9ef64711SSamuel Wu e->max_time_ns = max_time; 77*9ef64711SSamuel Wu e->prevent_sleep_time_ns = prevent_sleep_time; 78*9ef64711SSamuel Wu e->total_time_ns = total_time; 79*9ef64711SSamuel Wu e->wakeup_count = ws->wakeup_count; 80*9ef64711SSamuel Wu 81*9ef64711SSamuel Wu if (bpf_probe_read_kernel_str( 82*9ef64711SSamuel Wu e->name, WAKEUP_NAME_LEN, ws->name) < 0) 83*9ef64711SSamuel Wu e->name[0] = '\0'; 84*9ef64711SSamuel Wu 85*9ef64711SSamuel Wu bpf_ringbuf_submit(e, 0); 86*9ef64711SSamuel Wu } 87*9ef64711SSamuel Wu 88*9ef64711SSamuel Wu bpf_wakeup_sources_read_unlock(lock); 89*9ef64711SSamuel Wu return 0; 90*9ef64711SSamuel Wu } 91*9ef64711SSamuel Wu 92*9ef64711SSamuel Wu char _license[] SEC("license") = "GPL"; 93