1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2015-2016 Intel Corporation 3 */ 4 5 #include <inttypes.h> 6 7 #include <rte_common.h> 8 #include <rte_cycles.h> 9 #include <rte_lcore.h> 10 #include <rte_log.h> 11 #include <rte_keepalive.h> 12 #include <rte_malloc.h> 13 14 #include "eal_private.h" 15 16 struct rte_keepalive { 17 /** Core Liveness. */ 18 struct { 19 /* 20 * Each element must be cache aligned to prevent false sharing. 21 */ 22 enum rte_keepalive_state core_state __rte_cache_aligned; 23 } live_data[RTE_KEEPALIVE_MAXCORES]; 24 25 /** Last-seen-alive timestamps */ 26 uint64_t last_alive[RTE_KEEPALIVE_MAXCORES]; 27 28 /** 29 * Cores to check. 30 * Indexed by core id, non-zero if the core should be checked. 31 */ 32 uint8_t active_cores[RTE_KEEPALIVE_MAXCORES]; 33 34 /** Dead core handler. */ 35 rte_keepalive_failure_callback_t callback; 36 37 /** 38 * Dead core handler app data. 39 * Pointer is passed to dead core handler. 40 */ 41 void *callback_data; 42 uint64_t tsc_initial; 43 uint64_t tsc_mhz; 44 45 /** Core state relay handler. */ 46 rte_keepalive_relay_callback_t relay_callback; 47 48 /** 49 * Core state relay handler app data. 50 * Pointer is passed to live core handler. 51 */ 52 void *relay_callback_data; 53 }; 54 55 static void 56 print_trace(const char *msg, struct rte_keepalive *keepcfg, int idx_core) 57 { 58 EAL_LOG(INFO, "%sLast seen %" PRId64 "ms ago.", 59 msg, 60 ((rte_rdtsc() - keepcfg->last_alive[idx_core])*1000) 61 / rte_get_tsc_hz() 62 ); 63 } 64 65 void 66 rte_keepalive_dispatch_pings(__rte_unused void *ptr_timer, 67 void *ptr_data) 68 { 69 struct rte_keepalive *keepcfg = ptr_data; 70 int idx_core; 71 72 for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES; idx_core++) { 73 if (keepcfg->active_cores[idx_core] == 0) 74 continue; 75 76 switch (keepcfg->live_data[idx_core].core_state) { 77 case RTE_KA_STATE_UNUSED: 78 break; 79 case RTE_KA_STATE_ALIVE: /* Alive */ 80 keepcfg->live_data[idx_core].core_state = 81 RTE_KA_STATE_MISSING; 82 keepcfg->last_alive[idx_core] = rte_rdtsc(); 83 break; 84 case RTE_KA_STATE_MISSING: /* MIA */ 85 print_trace("Core MIA. ", keepcfg, idx_core); 86 keepcfg->live_data[idx_core].core_state = 87 RTE_KA_STATE_DEAD; 88 break; 89 case RTE_KA_STATE_DEAD: /* Dead */ 90 keepcfg->live_data[idx_core].core_state = 91 RTE_KA_STATE_GONE; 92 print_trace("Core died. ", keepcfg, idx_core); 93 if (keepcfg->callback) 94 keepcfg->callback( 95 keepcfg->callback_data, 96 idx_core 97 ); 98 break; 99 case RTE_KA_STATE_GONE: /* Buried */ 100 break; 101 case RTE_KA_STATE_DOZING: /* Core going idle */ 102 keepcfg->live_data[idx_core].core_state = 103 RTE_KA_STATE_SLEEP; 104 keepcfg->last_alive[idx_core] = rte_rdtsc(); 105 break; 106 case RTE_KA_STATE_SLEEP: /* Idled core */ 107 break; 108 } 109 if (keepcfg->relay_callback) 110 keepcfg->relay_callback( 111 keepcfg->relay_callback_data, 112 idx_core, 113 keepcfg->live_data[idx_core].core_state, 114 keepcfg->last_alive[idx_core] 115 ); 116 } 117 } 118 119 struct rte_keepalive * 120 rte_keepalive_create(rte_keepalive_failure_callback_t callback, 121 void *data) 122 { 123 struct rte_keepalive *keepcfg; 124 125 keepcfg = rte_zmalloc("RTE_EAL_KEEPALIVE", 126 sizeof(struct rte_keepalive), 127 RTE_CACHE_LINE_SIZE); 128 if (keepcfg != NULL) { 129 keepcfg->callback = callback; 130 keepcfg->callback_data = data; 131 keepcfg->tsc_initial = rte_rdtsc(); 132 keepcfg->tsc_mhz = rte_get_tsc_hz() / 1000; 133 } 134 return keepcfg; 135 } 136 137 void rte_keepalive_register_relay_callback(struct rte_keepalive *keepcfg, 138 rte_keepalive_relay_callback_t callback, 139 void *data) 140 { 141 keepcfg->relay_callback = callback; 142 keepcfg->relay_callback_data = data; 143 } 144 145 void 146 rte_keepalive_register_core(struct rte_keepalive *keepcfg, const int id_core) 147 { 148 if (id_core < RTE_KEEPALIVE_MAXCORES) { 149 keepcfg->active_cores[id_core] = RTE_KA_STATE_ALIVE; 150 keepcfg->last_alive[id_core] = rte_rdtsc(); 151 } 152 } 153 154 void 155 rte_keepalive_mark_alive(struct rte_keepalive *keepcfg) 156 { 157 keepcfg->live_data[rte_lcore_id()].core_state = RTE_KA_STATE_ALIVE; 158 } 159 160 void 161 rte_keepalive_mark_sleep(struct rte_keepalive *keepcfg) 162 { 163 keepcfg->live_data[rte_lcore_id()].core_state = RTE_KA_STATE_DOZING; 164 } 165