"Das U-Boot" Source Tree
at master 114 lines 2.9 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * A general-purpose cyclic execution infrastructure, to allow "small" 4 * (run-time wise) functions to be executed at a specified frequency. 5 * Things like LED blinking or watchdog triggering are examples for such 6 * tasks. 7 * 8 * Copyright (C) 2022 Stefan Roese <sr@denx.de> 9 */ 10 11#include <cyclic.h> 12#include <log.h> 13#include <malloc.h> 14#include <time.h> 15#include <linux/errno.h> 16#include <linux/list.h> 17#include <asm/global_data.h> 18#include <u-boot/schedule.h> 19 20DECLARE_GLOBAL_DATA_PTR; 21 22void hw_watchdog_reset(void); 23 24struct hlist_head *cyclic_get_list(void) 25{ 26 /* Silence "discards 'volatile' qualifier" warning. */ 27 return (struct hlist_head *)&gd->cyclic_list; 28} 29 30void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func, 31 uint64_t delay_us, const char *name) 32{ 33 memset(cyclic, 0, sizeof(*cyclic)); 34 35 /* Store values in struct */ 36 cyclic->func = func; 37 cyclic->name = name; 38 cyclic->delay_us = delay_us; 39 cyclic->start_time_us = get_timer_us(0); 40 hlist_add_head(&cyclic->list, cyclic_get_list()); 41} 42 43void cyclic_unregister(struct cyclic_info *cyclic) 44{ 45 hlist_del(&cyclic->list); 46} 47 48static void cyclic_run(void) 49{ 50 struct cyclic_info *cyclic; 51 struct hlist_node *tmp; 52 uint64_t now, cpu_time; 53 54 /* Prevent recursion */ 55 if (gd->flags & GD_FLG_CYCLIC_RUNNING) 56 return; 57 58 gd->flags |= GD_FLG_CYCLIC_RUNNING; 59 hlist_for_each_entry_safe(cyclic, tmp, cyclic_get_list(), list) { 60 /* 61 * Check if this cyclic function needs to get called, e.g. 62 * do not call the cyclic func too often 63 */ 64 now = get_timer_us(0); 65 if (time_after_eq64(now, cyclic->next_call)) { 66 /* Call cyclic function and account it's cpu-time */ 67 cyclic->next_call = now + cyclic->delay_us; 68 cyclic->func(cyclic); 69 cyclic->run_cnt++; 70 cpu_time = get_timer_us(0) - now; 71 cyclic->cpu_time_us += cpu_time; 72 73 /* Check if cpu-time exceeds max allowed time */ 74 if ((cpu_time > CONFIG_CYCLIC_MAX_CPU_TIME_US) && 75 (!cyclic->already_warned)) { 76 pr_err("cyclic function %s took too long: %lldus vs %dus max\n", 77 cyclic->name, cpu_time, 78 CONFIG_CYCLIC_MAX_CPU_TIME_US); 79 80 /* 81 * Don't disable this function, just warn once 82 * about this exceeding CPU time usage 83 */ 84 cyclic->already_warned = true; 85 } 86 } 87 } 88 gd->flags &= ~GD_FLG_CYCLIC_RUNNING; 89} 90 91void schedule(void) 92{ 93 /* The HW watchdog is not integrated into the cyclic IF (yet) */ 94 if (IS_ENABLED(CONFIG_HW_WATCHDOG)) 95 hw_watchdog_reset(); 96 97 /* 98 * schedule() might get called very early before the cyclic IF is 99 * ready. Make sure to only call cyclic_run() when it's initalized. 100 */ 101 if (gd) 102 cyclic_run(); 103} 104 105int cyclic_unregister_all(void) 106{ 107 struct cyclic_info *cyclic; 108 struct hlist_node *tmp; 109 110 hlist_for_each_entry_safe(cyclic, tmp, cyclic_get_list(), list) 111 cyclic_unregister(cyclic); 112 113 return 0; 114}