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