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