diff options
Diffstat (limited to 'zephyr/shim/src/hooks.c')
-rw-r--r-- | zephyr/shim/src/hooks.c | 148 |
1 files changed, 79 insertions, 69 deletions
diff --git a/zephyr/shim/src/hooks.c b/zephyr/shim/src/hooks.c index 79a611812f..57a0b7965b 100644 --- a/zephyr/shim/src/hooks.c +++ b/zephyr/shim/src/hooks.c @@ -13,37 +13,68 @@ #include "task.h" #include "timer.h" -int hook_call_deferred(const struct deferred_data *data, int us) +static void hook_second_work(struct k_work *work); +static void hook_tick_work(struct k_work *work); + +static struct zephyr_shim_hook_list *hook_registry[HOOK_TYPE_COUNT]; + +static K_WORK_DELAYABLE_DEFINE(hook_seconds_work_data, hook_second_work); +static K_WORK_DELAYABLE_DEFINE(hook_ticks_work_data, hook_tick_work); + +static void work_queue_error(const void *data, int rv) { - struct k_work_delayable *work = data->work; - int rv = 0; + cprints(CC_HOOK, + "Warning: deferred call not submitted, " + "deferred_data=0x%pP, err=%d", + data, rv); +} - if (us == -1) { - k_work_cancel_delayable(work); - } else if (us >= 0) { - rv = k_work_reschedule(work, K_USEC(us)); - if (rv == -EINVAL) { - /* Already processing or completed. */ - return 0; - } else if (rv < 0) { - cprints(CC_HOOK, - "Warning: deferred call not submitted, " - "deferred_data=0x%pP, err=%d", - data, rv); - } - } else { - return EC_ERROR_PARAM2; - } +static void hook_second_work(struct k_work *work) +{ + int rv; - return rv; + hook_notify(HOOK_SECOND); + + rv = k_work_reschedule(&hook_seconds_work_data, K_SECONDS(1)); + if (rv < 0) + work_queue_error(&hook_seconds_work_data, rv); } -static struct zephyr_shim_hook_list *hook_registry[HOOK_TYPE_COUNT]; +static void hook_tick_work(struct k_work *work) +{ + int rv; + + hook_notify(HOOK_TICK); + + rv = k_work_reschedule(&hook_ticks_work_data, + K_USEC(HOOK_TICK_INTERVAL)); + if (rv < 0) + work_queue_error(&hook_ticks_work_data, rv); +} + +static void check_hook_task_priority(void) +{ + k_tid_t thread = &k_sys_work_q.thread; + + /* + * Numerically lower priorities take precedence, so verify the hook + * related threads cannot preempt any of the shimmed tasks. + */ + if (k_thread_priority_get(thread) < (TASK_ID_COUNT - 1)) + cprintf(CC_HOOK, + "ERROR: %s has priority %d but must be >= %d\n", + k_thread_name_get(thread), + k_thread_priority_get(thread), (TASK_ID_COUNT - 1)); +} +DECLARE_HOOK(HOOK_INIT, check_hook_task_priority, HOOK_PRIO_FIRST); static int zephyr_shim_setup_hooks(const struct device *unused) { + int rv; + STRUCT_SECTION_FOREACH(zephyr_shim_hook_list, entry) { - struct zephyr_shim_hook_list **loc = &hook_registry[entry->type]; + struct zephyr_shim_hook_list **loc = + &hook_registry[entry->type]; /* Find the correct place to put the entry in the registry. */ while (*loc && (*loc)->priority < entry->priority) @@ -55,6 +86,16 @@ static int zephyr_shim_setup_hooks(const struct device *unused) *loc = entry; } + /* Startup the HOOK_TICK and HOOK_SECOND recurring work */ + rv = k_work_reschedule(&hook_seconds_work_data, K_SECONDS(1)); + if (rv < 0) + work_queue_error(&hook_seconds_work_data, rv); + + rv = k_work_reschedule(&hook_ticks_work_data, + K_USEC(HOOK_TICK_INTERVAL)); + if (rv < 0) + work_queue_error(&hook_ticks_work_data, rv); + return 0; } @@ -68,55 +109,24 @@ void hook_notify(enum hook_type type) p->routine(); } -static void check_hook_task_priority(k_tid_t thread) -{ - /* - * Numerically lower priorities take precedence, so verify the hook - * related threads cannot preempt any of the shimmed tasks. - */ - if (k_thread_priority_get(thread) < (TASK_ID_COUNT - 1)) - cprintf(CC_HOOK, - "ERROR: %s has priority %d but must be >= %d\n", - k_thread_name_get(thread), - k_thread_priority_get(thread), (TASK_ID_COUNT - 1)); -} - -void hook_task(void *u) +int hook_call_deferred(const struct deferred_data *data, int us) { - /* Periodic hooks will be called first time through the loop */ - static uint64_t last_second = -SECOND; - static uint64_t last_tick = -HOOK_TICK_INTERVAL; - - /* - * Verify deferred routines are run at the lowest priority. - */ - check_hook_task_priority(&k_sys_work_q.thread); - check_hook_task_priority(k_current_get()); - - while (1) { - uint64_t t = get_time().val; - int next = 0; - - if (t - last_tick >= HOOK_TICK_INTERVAL) { - hook_notify(HOOK_TICK); - last_tick = t; - } + struct k_work_delayable *work = data->work; + int rv = 0; - if (t - last_second >= SECOND) { - hook_notify(HOOK_SECOND); - last_second = t; + if (us == -1) { + k_work_cancel_delayable(work); + } else if (us >= 0) { + rv = k_work_reschedule(work, K_USEC(us)); + if (rv == -EINVAL) { + /* Already processing or completed. */ + return 0; + } else if (rv < 0) { + work_queue_error(data, rv); } - - /* Calculate when next tick needs to occur */ - t = get_time().val; - if (last_tick + HOOK_TICK_INTERVAL > t) - next = last_tick + HOOK_TICK_INTERVAL - t; - - /* - * Sleep until next tick, unless we've already exceeded - * HOOK_TICK_INTERVAL. - */ - if (next > 0) - task_wait_event(next); + } else { + return EC_ERROR_PARAM2; } + + return rv; } |