1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <sys/queue.h> 6 #include <stdio.h> 7 #include <string.h> 8 9 #include <rte_eal.h> 10 #include <rte_eal_memconfig.h> 11 #include <rte_log.h> 12 #include <rte_string_fns.h> 13 14 #include "eal_private.h" 15 #include "eal_memcfg.h" 16 17 TAILQ_HEAD(rte_tailq_elem_head, rte_tailq_elem); 18 /* local tailq list */ 19 static struct rte_tailq_elem_head rte_tailq_elem_head = 20 TAILQ_HEAD_INITIALIZER(rte_tailq_elem_head); 21 22 /* number of tailqs registered, -1 before call to rte_eal_tailqs_init */ 23 static int rte_tailqs_count = -1; 24 25 struct rte_tailq_head * 26 rte_eal_tailq_lookup(const char *name) 27 { 28 unsigned i; 29 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 30 31 if (name == NULL) 32 return NULL; 33 34 for (i = 0; i < RTE_MAX_TAILQ; i++) { 35 if (!strncmp(name, mcfg->tailq_head[i].name, 36 RTE_TAILQ_NAMESIZE-1)) 37 return &mcfg->tailq_head[i]; 38 } 39 40 return NULL; 41 } 42 43 void 44 rte_dump_tailq(FILE *f) 45 { 46 struct rte_mem_config *mcfg; 47 unsigned i = 0; 48 49 mcfg = rte_eal_get_configuration()->mem_config; 50 51 rte_mcfg_tailq_read_lock(); 52 for (i = 0; i < RTE_MAX_TAILQ; i++) { 53 const struct rte_tailq_head *tailq = &mcfg->tailq_head[i]; 54 const struct rte_tailq_entry_head *head = &tailq->tailq_head; 55 56 fprintf(f, "Tailq %u: qname:<%s>, tqh_first:%p, tqh_last:%p\n", 57 i, tailq->name, head->tqh_first, head->tqh_last); 58 } 59 rte_mcfg_tailq_read_unlock(); 60 } 61 62 static struct rte_tailq_head * 63 rte_eal_tailq_create(const char *name) 64 { 65 struct rte_tailq_head *head = NULL; 66 67 if (!rte_eal_tailq_lookup(name) && 68 (rte_tailqs_count + 1 < RTE_MAX_TAILQ)) { 69 struct rte_mem_config *mcfg; 70 71 mcfg = rte_eal_get_configuration()->mem_config; 72 head = &mcfg->tailq_head[rte_tailqs_count]; 73 strlcpy(head->name, name, sizeof(head->name) - 1); 74 TAILQ_INIT(&head->tailq_head); 75 rte_tailqs_count++; 76 } 77 78 return head; 79 } 80 81 /* local register, used to store "early" tailqs before rte_eal_init() and to 82 * ensure secondary process only registers tailqs once. */ 83 static int 84 rte_eal_tailq_local_register(struct rte_tailq_elem *t) 85 { 86 struct rte_tailq_elem *temp; 87 88 TAILQ_FOREACH(temp, &rte_tailq_elem_head, next) { 89 if (!strncmp(t->name, temp->name, sizeof(temp->name))) 90 return -1; 91 } 92 93 TAILQ_INSERT_TAIL(&rte_tailq_elem_head, t, next); 94 return 0; 95 } 96 97 static void 98 rte_eal_tailq_update(struct rte_tailq_elem *t) 99 { 100 if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 101 /* primary process is the only one that creates */ 102 t->head = rte_eal_tailq_create(t->name); 103 } else { 104 t->head = rte_eal_tailq_lookup(t->name); 105 } 106 } 107 108 int 109 rte_eal_tailq_register(struct rte_tailq_elem *t) 110 { 111 if (rte_eal_tailq_local_register(t) < 0) { 112 EAL_LOG(ERR, 113 "%s tailq is already registered", t->name); 114 goto error; 115 } 116 117 /* if a register happens after rte_eal_tailqs_init(), then we can update 118 * tailq head */ 119 if (rte_tailqs_count >= 0) { 120 rte_eal_tailq_update(t); 121 if (t->head == NULL) { 122 EAL_LOG(ERR, 123 "Cannot initialize tailq: %s", t->name); 124 TAILQ_REMOVE(&rte_tailq_elem_head, t, next); 125 goto error; 126 } 127 } 128 129 return 0; 130 131 error: 132 t->head = NULL; 133 return -1; 134 } 135 136 int 137 rte_eal_tailqs_init(void) 138 { 139 struct rte_tailq_elem *t; 140 141 rte_tailqs_count = 0; 142 143 TAILQ_FOREACH(t, &rte_tailq_elem_head, next) { 144 /* second part of register job for "early" tailqs, see 145 * rte_eal_tailq_register and EAL_REGISTER_TAILQ */ 146 rte_eal_tailq_update(t); 147 if (t->head == NULL) { 148 EAL_LOG(ERR, 149 "Cannot initialize tailq: %s", t->name); 150 /* TAILQ_REMOVE not needed, error is already fatal */ 151 goto fail; 152 } 153 } 154 155 return 0; 156 157 fail: 158 rte_dump_tailq(stderr); 159 return -1; 160 } 161