199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2015-2016 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
599a2dd95SBruce Richardson #include <inttypes.h>
6*e9fd1ebfSTyler Retzlaff #include <stdalign.h>
799a2dd95SBruce Richardson
899a2dd95SBruce Richardson #include <rte_common.h>
999a2dd95SBruce Richardson #include <rte_cycles.h>
1099a2dd95SBruce Richardson #include <rte_lcore.h>
1199a2dd95SBruce Richardson #include <rte_log.h>
1299a2dd95SBruce Richardson #include <rte_keepalive.h>
1399a2dd95SBruce Richardson #include <rte_malloc.h>
1499a2dd95SBruce Richardson
15ae67895bSDavid Marchand #include "eal_private.h"
16ae67895bSDavid Marchand
1799a2dd95SBruce Richardson struct rte_keepalive {
1899a2dd95SBruce Richardson /** Core Liveness. */
1999a2dd95SBruce Richardson struct {
2099a2dd95SBruce Richardson /*
2199a2dd95SBruce Richardson * Each element must be cache aligned to prevent false sharing.
2299a2dd95SBruce Richardson */
23*e9fd1ebfSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) enum rte_keepalive_state core_state;
2499a2dd95SBruce Richardson } live_data[RTE_KEEPALIVE_MAXCORES];
2599a2dd95SBruce Richardson
2699a2dd95SBruce Richardson /** Last-seen-alive timestamps */
2799a2dd95SBruce Richardson uint64_t last_alive[RTE_KEEPALIVE_MAXCORES];
2899a2dd95SBruce Richardson
2999a2dd95SBruce Richardson /**
3099a2dd95SBruce Richardson * Cores to check.
3199a2dd95SBruce Richardson * Indexed by core id, non-zero if the core should be checked.
3299a2dd95SBruce Richardson */
3399a2dd95SBruce Richardson uint8_t active_cores[RTE_KEEPALIVE_MAXCORES];
3499a2dd95SBruce Richardson
3599a2dd95SBruce Richardson /** Dead core handler. */
3699a2dd95SBruce Richardson rte_keepalive_failure_callback_t callback;
3799a2dd95SBruce Richardson
3899a2dd95SBruce Richardson /**
3999a2dd95SBruce Richardson * Dead core handler app data.
4099a2dd95SBruce Richardson * Pointer is passed to dead core handler.
4199a2dd95SBruce Richardson */
4299a2dd95SBruce Richardson void *callback_data;
4399a2dd95SBruce Richardson uint64_t tsc_initial;
4499a2dd95SBruce Richardson uint64_t tsc_mhz;
4599a2dd95SBruce Richardson
4699a2dd95SBruce Richardson /** Core state relay handler. */
4799a2dd95SBruce Richardson rte_keepalive_relay_callback_t relay_callback;
4899a2dd95SBruce Richardson
4999a2dd95SBruce Richardson /**
5099a2dd95SBruce Richardson * Core state relay handler app data.
5199a2dd95SBruce Richardson * Pointer is passed to live core handler.
5299a2dd95SBruce Richardson */
5399a2dd95SBruce Richardson void *relay_callback_data;
5499a2dd95SBruce Richardson };
5599a2dd95SBruce Richardson
5699a2dd95SBruce Richardson static void
print_trace(const char * msg,struct rte_keepalive * keepcfg,int idx_core)5799a2dd95SBruce Richardson print_trace(const char *msg, struct rte_keepalive *keepcfg, int idx_core)
5899a2dd95SBruce Richardson {
59ae67895bSDavid Marchand EAL_LOG(INFO, "%sLast seen %" PRId64 "ms ago.",
6099a2dd95SBruce Richardson msg,
6199a2dd95SBruce Richardson ((rte_rdtsc() - keepcfg->last_alive[idx_core])*1000)
6299a2dd95SBruce Richardson / rte_get_tsc_hz()
6399a2dd95SBruce Richardson );
6499a2dd95SBruce Richardson }
6599a2dd95SBruce Richardson
6699a2dd95SBruce Richardson void
rte_keepalive_dispatch_pings(__rte_unused void * ptr_timer,void * ptr_data)6799a2dd95SBruce Richardson rte_keepalive_dispatch_pings(__rte_unused void *ptr_timer,
6899a2dd95SBruce Richardson void *ptr_data)
6999a2dd95SBruce Richardson {
7099a2dd95SBruce Richardson struct rte_keepalive *keepcfg = ptr_data;
7199a2dd95SBruce Richardson int idx_core;
7299a2dd95SBruce Richardson
7399a2dd95SBruce Richardson for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES; idx_core++) {
7499a2dd95SBruce Richardson if (keepcfg->active_cores[idx_core] == 0)
7599a2dd95SBruce Richardson continue;
7699a2dd95SBruce Richardson
7799a2dd95SBruce Richardson switch (keepcfg->live_data[idx_core].core_state) {
7899a2dd95SBruce Richardson case RTE_KA_STATE_UNUSED:
7999a2dd95SBruce Richardson break;
8099a2dd95SBruce Richardson case RTE_KA_STATE_ALIVE: /* Alive */
8199a2dd95SBruce Richardson keepcfg->live_data[idx_core].core_state =
8299a2dd95SBruce Richardson RTE_KA_STATE_MISSING;
8399a2dd95SBruce Richardson keepcfg->last_alive[idx_core] = rte_rdtsc();
8499a2dd95SBruce Richardson break;
8599a2dd95SBruce Richardson case RTE_KA_STATE_MISSING: /* MIA */
8699a2dd95SBruce Richardson print_trace("Core MIA. ", keepcfg, idx_core);
8799a2dd95SBruce Richardson keepcfg->live_data[idx_core].core_state =
8899a2dd95SBruce Richardson RTE_KA_STATE_DEAD;
8999a2dd95SBruce Richardson break;
9099a2dd95SBruce Richardson case RTE_KA_STATE_DEAD: /* Dead */
9199a2dd95SBruce Richardson keepcfg->live_data[idx_core].core_state =
9299a2dd95SBruce Richardson RTE_KA_STATE_GONE;
9399a2dd95SBruce Richardson print_trace("Core died. ", keepcfg, idx_core);
9499a2dd95SBruce Richardson if (keepcfg->callback)
9599a2dd95SBruce Richardson keepcfg->callback(
9699a2dd95SBruce Richardson keepcfg->callback_data,
9799a2dd95SBruce Richardson idx_core
9899a2dd95SBruce Richardson );
9999a2dd95SBruce Richardson break;
10099a2dd95SBruce Richardson case RTE_KA_STATE_GONE: /* Buried */
10199a2dd95SBruce Richardson break;
10299a2dd95SBruce Richardson case RTE_KA_STATE_DOZING: /* Core going idle */
10399a2dd95SBruce Richardson keepcfg->live_data[idx_core].core_state =
10499a2dd95SBruce Richardson RTE_KA_STATE_SLEEP;
10599a2dd95SBruce Richardson keepcfg->last_alive[idx_core] = rte_rdtsc();
10699a2dd95SBruce Richardson break;
10799a2dd95SBruce Richardson case RTE_KA_STATE_SLEEP: /* Idled core */
10899a2dd95SBruce Richardson break;
10999a2dd95SBruce Richardson }
11099a2dd95SBruce Richardson if (keepcfg->relay_callback)
11199a2dd95SBruce Richardson keepcfg->relay_callback(
11299a2dd95SBruce Richardson keepcfg->relay_callback_data,
11399a2dd95SBruce Richardson idx_core,
11499a2dd95SBruce Richardson keepcfg->live_data[idx_core].core_state,
11599a2dd95SBruce Richardson keepcfg->last_alive[idx_core]
11699a2dd95SBruce Richardson );
11799a2dd95SBruce Richardson }
11899a2dd95SBruce Richardson }
11999a2dd95SBruce Richardson
12099a2dd95SBruce Richardson struct rte_keepalive *
rte_keepalive_create(rte_keepalive_failure_callback_t callback,void * data)12199a2dd95SBruce Richardson rte_keepalive_create(rte_keepalive_failure_callback_t callback,
12299a2dd95SBruce Richardson void *data)
12399a2dd95SBruce Richardson {
12499a2dd95SBruce Richardson struct rte_keepalive *keepcfg;
12599a2dd95SBruce Richardson
12699a2dd95SBruce Richardson keepcfg = rte_zmalloc("RTE_EAL_KEEPALIVE",
12799a2dd95SBruce Richardson sizeof(struct rte_keepalive),
12899a2dd95SBruce Richardson RTE_CACHE_LINE_SIZE);
12999a2dd95SBruce Richardson if (keepcfg != NULL) {
13099a2dd95SBruce Richardson keepcfg->callback = callback;
13199a2dd95SBruce Richardson keepcfg->callback_data = data;
13299a2dd95SBruce Richardson keepcfg->tsc_initial = rte_rdtsc();
13399a2dd95SBruce Richardson keepcfg->tsc_mhz = rte_get_tsc_hz() / 1000;
13499a2dd95SBruce Richardson }
13599a2dd95SBruce Richardson return keepcfg;
13699a2dd95SBruce Richardson }
13799a2dd95SBruce Richardson
rte_keepalive_register_relay_callback(struct rte_keepalive * keepcfg,rte_keepalive_relay_callback_t callback,void * data)13899a2dd95SBruce Richardson void rte_keepalive_register_relay_callback(struct rte_keepalive *keepcfg,
13999a2dd95SBruce Richardson rte_keepalive_relay_callback_t callback,
14099a2dd95SBruce Richardson void *data)
14199a2dd95SBruce Richardson {
14299a2dd95SBruce Richardson keepcfg->relay_callback = callback;
14399a2dd95SBruce Richardson keepcfg->relay_callback_data = data;
14499a2dd95SBruce Richardson }
14599a2dd95SBruce Richardson
14699a2dd95SBruce Richardson void
rte_keepalive_register_core(struct rte_keepalive * keepcfg,const int id_core)14799a2dd95SBruce Richardson rte_keepalive_register_core(struct rte_keepalive *keepcfg, const int id_core)
14899a2dd95SBruce Richardson {
14999a2dd95SBruce Richardson if (id_core < RTE_KEEPALIVE_MAXCORES) {
15099a2dd95SBruce Richardson keepcfg->active_cores[id_core] = RTE_KA_STATE_ALIVE;
15199a2dd95SBruce Richardson keepcfg->last_alive[id_core] = rte_rdtsc();
15299a2dd95SBruce Richardson }
15399a2dd95SBruce Richardson }
15499a2dd95SBruce Richardson
15599a2dd95SBruce Richardson void
rte_keepalive_mark_alive(struct rte_keepalive * keepcfg)15699a2dd95SBruce Richardson rte_keepalive_mark_alive(struct rte_keepalive *keepcfg)
15799a2dd95SBruce Richardson {
15899a2dd95SBruce Richardson keepcfg->live_data[rte_lcore_id()].core_state = RTE_KA_STATE_ALIVE;
15999a2dd95SBruce Richardson }
16099a2dd95SBruce Richardson
16199a2dd95SBruce Richardson void
rte_keepalive_mark_sleep(struct rte_keepalive * keepcfg)16299a2dd95SBruce Richardson rte_keepalive_mark_sleep(struct rte_keepalive *keepcfg)
16399a2dd95SBruce Richardson {
16499a2dd95SBruce Richardson keepcfg->live_data[rte_lcore_id()].core_state = RTE_KA_STATE_DOZING;
16599a2dd95SBruce Richardson }
166