Rasmus Villemoes 4457e5c61d cyclic: introduce u-boot/schedule.h
I noticed an "unnecessary" include of <cyclic.h> in
global_data.h, in the sense that nothing in cyclic.h is needed in
order to define 'struct global_data'.

Well, it's not unnecessary, as it implicitly ensures that everybody
gets a declaration of schedule(), and schedule() is (obviously) called
all over the tree. Almost none of those places directly include
<cyclic.h>, but for historical reasons, many do include
<watchdog.h> (most schedule() instances are replacements of
WATCHDOG_RESET()).

However, very few TUs actually need the declarations of the
cyclic_register() and struct cyclic_info, and they also don't really
need anything from the watchdog.h header.

So introduce a new header which just contains a declaration of
schedule(), which can then be included from all the places that do
call schedule(). I removed the direct reference to cyclic_run(),
because we shouldn't have two public functions for doing roughly the
same without being very explicit about when one should call one or the
other.

Testing of later patches that explicitly include <schedule.h> when
schedule() is used revealed a problem with host tool build on win32,
which apparently picked up a host <schedule.h>. To avoid that problem,
put the new header in include/u-boot/ and hence make the include
statements say <u-boot/schedule.h>.

Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Stefan Roese <sr@denx.de>
2024-10-23 06:52:38 +02:00

115 lines
2.8 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* A general-purpose cyclic execution infrastructure, to allow "small"
* (run-time wise) functions to be executed at a specified frequency.
* Things like LED blinking or watchdog triggering are examples for such
* tasks.
*
* Copyright (C) 2022 Stefan Roese <sr@denx.de>
*/
#include <cyclic.h>
#include <log.h>
#include <malloc.h>
#include <time.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <asm/global_data.h>
#include <u-boot/schedule.h>
DECLARE_GLOBAL_DATA_PTR;
void hw_watchdog_reset(void);
struct hlist_head *cyclic_get_list(void)
{
/* Silence "discards 'volatile' qualifier" warning. */
return (struct hlist_head *)&gd->cyclic_list;
}
void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
uint64_t delay_us, const char *name)
{
memset(cyclic, 0, sizeof(*cyclic));
/* Store values in struct */
cyclic->func = func;
cyclic->name = name;
cyclic->delay_us = delay_us;
cyclic->start_time_us = timer_get_us();
hlist_add_head(&cyclic->list, cyclic_get_list());
}
void cyclic_unregister(struct cyclic_info *cyclic)
{
hlist_del(&cyclic->list);
}
void cyclic_run(void)
{
struct cyclic_info *cyclic;
struct hlist_node *tmp;
uint64_t now, cpu_time;
/* Prevent recursion */
if (gd->flags & GD_FLG_CYCLIC_RUNNING)
return;
gd->flags |= GD_FLG_CYCLIC_RUNNING;
hlist_for_each_entry_safe(cyclic, tmp, cyclic_get_list(), list) {
/*
* Check if this cyclic function needs to get called, e.g.
* do not call the cyclic func too often
*/
now = timer_get_us();
if (time_after_eq64(now, cyclic->next_call)) {
/* Call cyclic function and account it's cpu-time */
cyclic->next_call = now + cyclic->delay_us;
cyclic->func(cyclic);
cyclic->run_cnt++;
cpu_time = timer_get_us() - now;
cyclic->cpu_time_us += cpu_time;
/* Check if cpu-time exceeds max allowed time */
if ((cpu_time > CONFIG_CYCLIC_MAX_CPU_TIME_US) &&
(!cyclic->already_warned)) {
pr_err("cyclic function %s took too long: %lldus vs %dus max\n",
cyclic->name, cpu_time,
CONFIG_CYCLIC_MAX_CPU_TIME_US);
/*
* Don't disable this function, just warn once
* about this exceeding CPU time usage
*/
cyclic->already_warned = true;
}
}
}
gd->flags &= ~GD_FLG_CYCLIC_RUNNING;
}
void schedule(void)
{
/* The HW watchdog is not integrated into the cyclic IF (yet) */
if (IS_ENABLED(CONFIG_HW_WATCHDOG))
hw_watchdog_reset();
/*
* schedule() might get called very early before the cyclic IF is
* ready. Make sure to only call cyclic_run() when it's initalized.
*/
if (gd)
cyclic_run();
}
int cyclic_unregister_all(void)
{
struct cyclic_info *cyclic;
struct hlist_node *tmp;
hlist_for_each_entry_safe(cyclic, tmp, cyclic_get_list(), list)
cyclic_unregister(cyclic);
return 0;
}