1b77f6600SCristian Dumitrescu /* SPDX-License-Identifier: BSD-3-Clause 2b77f6600SCristian Dumitrescu * Copyright(c) 2020 Intel Corporation 3b77f6600SCristian Dumitrescu */ 4b77f6600SCristian Dumitrescu 5b77f6600SCristian Dumitrescu #include <stdlib.h> 6b77f6600SCristian Dumitrescu 7b77f6600SCristian Dumitrescu #include <rte_common.h> 8b77f6600SCristian Dumitrescu #include <rte_cycles.h> 9b77f6600SCristian Dumitrescu #include <rte_lcore.h> 10b77f6600SCristian Dumitrescu #include <rte_ring.h> 11b77f6600SCristian Dumitrescu 12b77f6600SCristian Dumitrescu #include <rte_table_acl.h> 13b77f6600SCristian Dumitrescu #include <rte_table_array.h> 14b77f6600SCristian Dumitrescu #include <rte_table_hash.h> 15b77f6600SCristian Dumitrescu #include <rte_table_lpm.h> 16b77f6600SCristian Dumitrescu #include <rte_table_lpm_ipv6.h> 17b77f6600SCristian Dumitrescu 18b77f6600SCristian Dumitrescu #include "obj.h" 19b77f6600SCristian Dumitrescu #include "thread.h" 20b77f6600SCristian Dumitrescu 21b77f6600SCristian Dumitrescu #ifndef THREAD_PIPELINES_MAX 22b77f6600SCristian Dumitrescu #define THREAD_PIPELINES_MAX 256 23b77f6600SCristian Dumitrescu #endif 24b77f6600SCristian Dumitrescu 25b77f6600SCristian Dumitrescu #ifndef THREAD_MSGQ_SIZE 26b77f6600SCristian Dumitrescu #define THREAD_MSGQ_SIZE 64 27b77f6600SCristian Dumitrescu #endif 28b77f6600SCristian Dumitrescu 29b77f6600SCristian Dumitrescu #ifndef THREAD_TIMER_PERIOD_MS 30b77f6600SCristian Dumitrescu #define THREAD_TIMER_PERIOD_MS 100 31b77f6600SCristian Dumitrescu #endif 32b77f6600SCristian Dumitrescu 33*0b50ea60SCristian Dumitrescu /* Pipeline instruction quanta: Needs to be big enough to do some meaningful 34*0b50ea60SCristian Dumitrescu * work, but not too big to avoid starving any other pipelines mapped to the 35*0b50ea60SCristian Dumitrescu * same thread. For a pipeline that executes 10 instructions per packet, a 36*0b50ea60SCristian Dumitrescu * quanta of 1000 instructions equates to processing 100 packets. 37*0b50ea60SCristian Dumitrescu */ 38*0b50ea60SCristian Dumitrescu #ifndef PIPELINE_INSTR_QUANTA 39*0b50ea60SCristian Dumitrescu #define PIPELINE_INSTR_QUANTA 1000 40*0b50ea60SCristian Dumitrescu #endif 41*0b50ea60SCristian Dumitrescu 42b77f6600SCristian Dumitrescu /** 43b77f6600SCristian Dumitrescu * Control thread: data plane thread context 44b77f6600SCristian Dumitrescu */ 45b77f6600SCristian Dumitrescu struct thread { 46b77f6600SCristian Dumitrescu struct rte_ring *msgq_req; 47b77f6600SCristian Dumitrescu struct rte_ring *msgq_rsp; 48b77f6600SCristian Dumitrescu 49b77f6600SCristian Dumitrescu uint32_t enabled; 50b77f6600SCristian Dumitrescu }; 51b77f6600SCristian Dumitrescu 52b77f6600SCristian Dumitrescu static struct thread thread[RTE_MAX_LCORE]; 53b77f6600SCristian Dumitrescu 54b77f6600SCristian Dumitrescu /** 55b77f6600SCristian Dumitrescu * Data plane threads: context 56b77f6600SCristian Dumitrescu */ 57b77f6600SCristian Dumitrescu struct pipeline_data { 58b77f6600SCristian Dumitrescu struct rte_swx_pipeline *p; 59b77f6600SCristian Dumitrescu uint64_t timer_period; /* Measured in CPU cycles. */ 60b77f6600SCristian Dumitrescu uint64_t time_next; 61b77f6600SCristian Dumitrescu }; 62b77f6600SCristian Dumitrescu 63b77f6600SCristian Dumitrescu struct thread_data { 64b77f6600SCristian Dumitrescu struct rte_swx_pipeline *p[THREAD_PIPELINES_MAX]; 65b77f6600SCristian Dumitrescu uint32_t n_pipelines; 66b77f6600SCristian Dumitrescu 67b77f6600SCristian Dumitrescu struct pipeline_data pipeline_data[THREAD_PIPELINES_MAX]; 68b77f6600SCristian Dumitrescu struct rte_ring *msgq_req; 69b77f6600SCristian Dumitrescu struct rte_ring *msgq_rsp; 70b77f6600SCristian Dumitrescu uint64_t timer_period; /* Measured in CPU cycles. */ 71b77f6600SCristian Dumitrescu uint64_t time_next; 72b77f6600SCristian Dumitrescu uint64_t time_next_min; 73b77f6600SCristian Dumitrescu } __rte_cache_aligned; 74b77f6600SCristian Dumitrescu 75b77f6600SCristian Dumitrescu static struct thread_data thread_data[RTE_MAX_LCORE]; 76b77f6600SCristian Dumitrescu 77b77f6600SCristian Dumitrescu /** 78b77f6600SCristian Dumitrescu * Control thread: data plane thread init 79b77f6600SCristian Dumitrescu */ 80b77f6600SCristian Dumitrescu static void 81b77f6600SCristian Dumitrescu thread_free(void) 82b77f6600SCristian Dumitrescu { 83b77f6600SCristian Dumitrescu uint32_t i; 84b77f6600SCristian Dumitrescu 85b77f6600SCristian Dumitrescu for (i = 0; i < RTE_MAX_LCORE; i++) { 86b77f6600SCristian Dumitrescu struct thread *t = &thread[i]; 87b77f6600SCristian Dumitrescu 88b77f6600SCristian Dumitrescu if (!rte_lcore_is_enabled(i)) 89b77f6600SCristian Dumitrescu continue; 90b77f6600SCristian Dumitrescu 91b77f6600SCristian Dumitrescu /* MSGQs */ 92b77f6600SCristian Dumitrescu if (t->msgq_req) 93b77f6600SCristian Dumitrescu rte_ring_free(t->msgq_req); 94b77f6600SCristian Dumitrescu 95b77f6600SCristian Dumitrescu if (t->msgq_rsp) 96b77f6600SCristian Dumitrescu rte_ring_free(t->msgq_rsp); 97b77f6600SCristian Dumitrescu } 98b77f6600SCristian Dumitrescu } 99b77f6600SCristian Dumitrescu 100b77f6600SCristian Dumitrescu int 101b77f6600SCristian Dumitrescu thread_init(void) 102b77f6600SCristian Dumitrescu { 103b77f6600SCristian Dumitrescu uint32_t i; 104b77f6600SCristian Dumitrescu 105cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(i) { 106b77f6600SCristian Dumitrescu char name[NAME_MAX]; 107b77f6600SCristian Dumitrescu struct rte_ring *msgq_req, *msgq_rsp; 108b77f6600SCristian Dumitrescu struct thread *t = &thread[i]; 109b77f6600SCristian Dumitrescu struct thread_data *t_data = &thread_data[i]; 110b77f6600SCristian Dumitrescu uint32_t cpu_id = rte_lcore_to_socket_id(i); 111b77f6600SCristian Dumitrescu 112b77f6600SCristian Dumitrescu /* MSGQs */ 113b77f6600SCristian Dumitrescu snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-REQ", i); 114b77f6600SCristian Dumitrescu 115b77f6600SCristian Dumitrescu msgq_req = rte_ring_create(name, 116b77f6600SCristian Dumitrescu THREAD_MSGQ_SIZE, 117b77f6600SCristian Dumitrescu cpu_id, 118b77f6600SCristian Dumitrescu RING_F_SP_ENQ | RING_F_SC_DEQ); 119b77f6600SCristian Dumitrescu 120b77f6600SCristian Dumitrescu if (msgq_req == NULL) { 121b77f6600SCristian Dumitrescu thread_free(); 122b77f6600SCristian Dumitrescu return -1; 123b77f6600SCristian Dumitrescu } 124b77f6600SCristian Dumitrescu 125b77f6600SCristian Dumitrescu snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-RSP", i); 126b77f6600SCristian Dumitrescu 127b77f6600SCristian Dumitrescu msgq_rsp = rte_ring_create(name, 128b77f6600SCristian Dumitrescu THREAD_MSGQ_SIZE, 129b77f6600SCristian Dumitrescu cpu_id, 130b77f6600SCristian Dumitrescu RING_F_SP_ENQ | RING_F_SC_DEQ); 131b77f6600SCristian Dumitrescu 132b77f6600SCristian Dumitrescu if (msgq_rsp == NULL) { 133b77f6600SCristian Dumitrescu thread_free(); 134b77f6600SCristian Dumitrescu return -1; 135b77f6600SCristian Dumitrescu } 136b77f6600SCristian Dumitrescu 137b77f6600SCristian Dumitrescu /* Control thread records */ 138b77f6600SCristian Dumitrescu t->msgq_req = msgq_req; 139b77f6600SCristian Dumitrescu t->msgq_rsp = msgq_rsp; 140b77f6600SCristian Dumitrescu t->enabled = 1; 141b77f6600SCristian Dumitrescu 142b77f6600SCristian Dumitrescu /* Data plane thread records */ 143b77f6600SCristian Dumitrescu t_data->n_pipelines = 0; 144b77f6600SCristian Dumitrescu t_data->msgq_req = msgq_req; 145b77f6600SCristian Dumitrescu t_data->msgq_rsp = msgq_rsp; 146b77f6600SCristian Dumitrescu t_data->timer_period = 147b77f6600SCristian Dumitrescu (rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000; 148b77f6600SCristian Dumitrescu t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period; 149b77f6600SCristian Dumitrescu t_data->time_next_min = t_data->time_next; 150b77f6600SCristian Dumitrescu } 151b77f6600SCristian Dumitrescu 152b77f6600SCristian Dumitrescu return 0; 153b77f6600SCristian Dumitrescu } 154b77f6600SCristian Dumitrescu 155b77f6600SCristian Dumitrescu static inline int 156b77f6600SCristian Dumitrescu thread_is_running(uint32_t thread_id) 157b77f6600SCristian Dumitrescu { 158b77f6600SCristian Dumitrescu enum rte_lcore_state_t thread_state; 159b77f6600SCristian Dumitrescu 160b77f6600SCristian Dumitrescu thread_state = rte_eal_get_lcore_state(thread_id); 161b77f6600SCristian Dumitrescu return (thread_state == RUNNING) ? 1 : 0; 162b77f6600SCristian Dumitrescu } 163b77f6600SCristian Dumitrescu 164b77f6600SCristian Dumitrescu /** 165b77f6600SCristian Dumitrescu * Control thread & data plane threads: message passing 166b77f6600SCristian Dumitrescu */ 167b77f6600SCristian Dumitrescu enum thread_req_type { 168b77f6600SCristian Dumitrescu THREAD_REQ_PIPELINE_ENABLE = 0, 169b77f6600SCristian Dumitrescu THREAD_REQ_PIPELINE_DISABLE, 170b77f6600SCristian Dumitrescu THREAD_REQ_MAX 171b77f6600SCristian Dumitrescu }; 172b77f6600SCristian Dumitrescu 173b77f6600SCristian Dumitrescu struct thread_msg_req { 174b77f6600SCristian Dumitrescu enum thread_req_type type; 175b77f6600SCristian Dumitrescu 176b77f6600SCristian Dumitrescu union { 177b77f6600SCristian Dumitrescu struct { 178b77f6600SCristian Dumitrescu struct rte_swx_pipeline *p; 179b77f6600SCristian Dumitrescu uint32_t timer_period_ms; 180b77f6600SCristian Dumitrescu } pipeline_enable; 181b77f6600SCristian Dumitrescu 182b77f6600SCristian Dumitrescu struct { 183b77f6600SCristian Dumitrescu struct rte_swx_pipeline *p; 184b77f6600SCristian Dumitrescu } pipeline_disable; 185b77f6600SCristian Dumitrescu }; 186b77f6600SCristian Dumitrescu }; 187b77f6600SCristian Dumitrescu 188b77f6600SCristian Dumitrescu struct thread_msg_rsp { 189b77f6600SCristian Dumitrescu int status; 190b77f6600SCristian Dumitrescu }; 191b77f6600SCristian Dumitrescu 192b77f6600SCristian Dumitrescu /** 193b77f6600SCristian Dumitrescu * Control thread 194b77f6600SCristian Dumitrescu */ 195b77f6600SCristian Dumitrescu static struct thread_msg_req * 196b77f6600SCristian Dumitrescu thread_msg_alloc(void) 197b77f6600SCristian Dumitrescu { 198b77f6600SCristian Dumitrescu size_t size = RTE_MAX(sizeof(struct thread_msg_req), 199b77f6600SCristian Dumitrescu sizeof(struct thread_msg_rsp)); 200b77f6600SCristian Dumitrescu 201b77f6600SCristian Dumitrescu return calloc(1, size); 202b77f6600SCristian Dumitrescu } 203b77f6600SCristian Dumitrescu 204b77f6600SCristian Dumitrescu static void 205b77f6600SCristian Dumitrescu thread_msg_free(struct thread_msg_rsp *rsp) 206b77f6600SCristian Dumitrescu { 207b77f6600SCristian Dumitrescu free(rsp); 208b77f6600SCristian Dumitrescu } 209b77f6600SCristian Dumitrescu 210b77f6600SCristian Dumitrescu static struct thread_msg_rsp * 211b77f6600SCristian Dumitrescu thread_msg_send_recv(uint32_t thread_id, 212b77f6600SCristian Dumitrescu struct thread_msg_req *req) 213b77f6600SCristian Dumitrescu { 214b77f6600SCristian Dumitrescu struct thread *t = &thread[thread_id]; 215b77f6600SCristian Dumitrescu struct rte_ring *msgq_req = t->msgq_req; 216b77f6600SCristian Dumitrescu struct rte_ring *msgq_rsp = t->msgq_rsp; 217b77f6600SCristian Dumitrescu struct thread_msg_rsp *rsp; 218b77f6600SCristian Dumitrescu int status; 219b77f6600SCristian Dumitrescu 220b77f6600SCristian Dumitrescu /* send */ 221b77f6600SCristian Dumitrescu do { 222b77f6600SCristian Dumitrescu status = rte_ring_sp_enqueue(msgq_req, req); 223b77f6600SCristian Dumitrescu } while (status == -ENOBUFS); 224b77f6600SCristian Dumitrescu 225b77f6600SCristian Dumitrescu /* recv */ 226b77f6600SCristian Dumitrescu do { 227b77f6600SCristian Dumitrescu status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp); 228b77f6600SCristian Dumitrescu } while (status != 0); 229b77f6600SCristian Dumitrescu 230b77f6600SCristian Dumitrescu return rsp; 231b77f6600SCristian Dumitrescu } 232b77f6600SCristian Dumitrescu 233b77f6600SCristian Dumitrescu int 234b77f6600SCristian Dumitrescu thread_pipeline_enable(uint32_t thread_id, 235b77f6600SCristian Dumitrescu struct obj *obj, 236b77f6600SCristian Dumitrescu const char *pipeline_name) 237b77f6600SCristian Dumitrescu { 238b77f6600SCristian Dumitrescu struct pipeline *p = pipeline_find(obj, pipeline_name); 239b77f6600SCristian Dumitrescu struct thread *t; 240b77f6600SCristian Dumitrescu struct thread_msg_req *req; 241b77f6600SCristian Dumitrescu struct thread_msg_rsp *rsp; 242b77f6600SCristian Dumitrescu int status; 243b77f6600SCristian Dumitrescu 244b77f6600SCristian Dumitrescu /* Check input params */ 245b77f6600SCristian Dumitrescu if ((thread_id >= RTE_MAX_LCORE) || 246b77f6600SCristian Dumitrescu (p == NULL)) 247b77f6600SCristian Dumitrescu return -1; 248b77f6600SCristian Dumitrescu 249b77f6600SCristian Dumitrescu t = &thread[thread_id]; 250b77f6600SCristian Dumitrescu if (t->enabled == 0) 251b77f6600SCristian Dumitrescu return -1; 252b77f6600SCristian Dumitrescu 253b77f6600SCristian Dumitrescu if (!thread_is_running(thread_id)) { 254b77f6600SCristian Dumitrescu struct thread_data *td = &thread_data[thread_id]; 255b77f6600SCristian Dumitrescu struct pipeline_data *tdp = &td->pipeline_data[td->n_pipelines]; 256b77f6600SCristian Dumitrescu 257b77f6600SCristian Dumitrescu if (td->n_pipelines >= THREAD_PIPELINES_MAX) 258b77f6600SCristian Dumitrescu return -1; 259b77f6600SCristian Dumitrescu 260b77f6600SCristian Dumitrescu /* Data plane thread */ 261b77f6600SCristian Dumitrescu td->p[td->n_pipelines] = p->p; 262b77f6600SCristian Dumitrescu 263b77f6600SCristian Dumitrescu tdp->p = p->p; 264b77f6600SCristian Dumitrescu tdp->timer_period = 265b77f6600SCristian Dumitrescu (rte_get_tsc_hz() * p->timer_period_ms) / 1000; 266b77f6600SCristian Dumitrescu tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period; 267b77f6600SCristian Dumitrescu 268b77f6600SCristian Dumitrescu td->n_pipelines++; 269b77f6600SCristian Dumitrescu 270b77f6600SCristian Dumitrescu /* Pipeline */ 271b77f6600SCristian Dumitrescu p->thread_id = thread_id; 272b77f6600SCristian Dumitrescu p->enabled = 1; 273b77f6600SCristian Dumitrescu 274b77f6600SCristian Dumitrescu return 0; 275b77f6600SCristian Dumitrescu } 276b77f6600SCristian Dumitrescu 277b77f6600SCristian Dumitrescu /* Allocate request */ 278b77f6600SCristian Dumitrescu req = thread_msg_alloc(); 279b77f6600SCristian Dumitrescu if (req == NULL) 280b77f6600SCristian Dumitrescu return -1; 281b77f6600SCristian Dumitrescu 282b77f6600SCristian Dumitrescu /* Write request */ 283b77f6600SCristian Dumitrescu req->type = THREAD_REQ_PIPELINE_ENABLE; 284b77f6600SCristian Dumitrescu req->pipeline_enable.p = p->p; 285b77f6600SCristian Dumitrescu req->pipeline_enable.timer_period_ms = p->timer_period_ms; 286b77f6600SCristian Dumitrescu 287b77f6600SCristian Dumitrescu /* Send request and wait for response */ 288b77f6600SCristian Dumitrescu rsp = thread_msg_send_recv(thread_id, req); 289b77f6600SCristian Dumitrescu 290b77f6600SCristian Dumitrescu /* Read response */ 291b77f6600SCristian Dumitrescu status = rsp->status; 292b77f6600SCristian Dumitrescu 293b77f6600SCristian Dumitrescu /* Free response */ 294b77f6600SCristian Dumitrescu thread_msg_free(rsp); 295b77f6600SCristian Dumitrescu 296b77f6600SCristian Dumitrescu /* Request completion */ 297b77f6600SCristian Dumitrescu if (status) 298b77f6600SCristian Dumitrescu return status; 299b77f6600SCristian Dumitrescu 300b77f6600SCristian Dumitrescu p->thread_id = thread_id; 301b77f6600SCristian Dumitrescu p->enabled = 1; 302b77f6600SCristian Dumitrescu 303b77f6600SCristian Dumitrescu return 0; 304b77f6600SCristian Dumitrescu } 305b77f6600SCristian Dumitrescu 306b77f6600SCristian Dumitrescu int 307b77f6600SCristian Dumitrescu thread_pipeline_disable(uint32_t thread_id, 308b77f6600SCristian Dumitrescu struct obj *obj, 309b77f6600SCristian Dumitrescu const char *pipeline_name) 310b77f6600SCristian Dumitrescu { 311b77f6600SCristian Dumitrescu struct pipeline *p = pipeline_find(obj, pipeline_name); 312b77f6600SCristian Dumitrescu struct thread *t; 313b77f6600SCristian Dumitrescu struct thread_msg_req *req; 314b77f6600SCristian Dumitrescu struct thread_msg_rsp *rsp; 315b77f6600SCristian Dumitrescu int status; 316b77f6600SCristian Dumitrescu 317b77f6600SCristian Dumitrescu /* Check input params */ 318b77f6600SCristian Dumitrescu if ((thread_id >= RTE_MAX_LCORE) || 319b77f6600SCristian Dumitrescu (p == NULL)) 320b77f6600SCristian Dumitrescu return -1; 321b77f6600SCristian Dumitrescu 322b77f6600SCristian Dumitrescu t = &thread[thread_id]; 323b77f6600SCristian Dumitrescu if (t->enabled == 0) 324b77f6600SCristian Dumitrescu return -1; 325b77f6600SCristian Dumitrescu 326b77f6600SCristian Dumitrescu if (p->enabled == 0) 327b77f6600SCristian Dumitrescu return 0; 328b77f6600SCristian Dumitrescu 329b77f6600SCristian Dumitrescu if (p->thread_id != thread_id) 330b77f6600SCristian Dumitrescu return -1; 331b77f6600SCristian Dumitrescu 332b77f6600SCristian Dumitrescu if (!thread_is_running(thread_id)) { 333b77f6600SCristian Dumitrescu struct thread_data *td = &thread_data[thread_id]; 334b77f6600SCristian Dumitrescu uint32_t i; 335b77f6600SCristian Dumitrescu 336b77f6600SCristian Dumitrescu for (i = 0; i < td->n_pipelines; i++) { 337b77f6600SCristian Dumitrescu struct pipeline_data *tdp = &td->pipeline_data[i]; 338b77f6600SCristian Dumitrescu 339b77f6600SCristian Dumitrescu if (tdp->p != p->p) 340b77f6600SCristian Dumitrescu continue; 341b77f6600SCristian Dumitrescu 342b77f6600SCristian Dumitrescu /* Data plane thread */ 343b77f6600SCristian Dumitrescu if (i < td->n_pipelines - 1) { 344b77f6600SCristian Dumitrescu struct rte_swx_pipeline *pipeline_last = 345b77f6600SCristian Dumitrescu td->p[td->n_pipelines - 1]; 346b77f6600SCristian Dumitrescu struct pipeline_data *tdp_last = 347b77f6600SCristian Dumitrescu &td->pipeline_data[td->n_pipelines - 1]; 348b77f6600SCristian Dumitrescu 349b77f6600SCristian Dumitrescu td->p[i] = pipeline_last; 350b77f6600SCristian Dumitrescu memcpy(tdp, tdp_last, sizeof(*tdp)); 351b77f6600SCristian Dumitrescu } 352b77f6600SCristian Dumitrescu 353b77f6600SCristian Dumitrescu td->n_pipelines--; 354b77f6600SCristian Dumitrescu 355b77f6600SCristian Dumitrescu /* Pipeline */ 356b77f6600SCristian Dumitrescu p->enabled = 0; 357b77f6600SCristian Dumitrescu 358b77f6600SCristian Dumitrescu break; 359b77f6600SCristian Dumitrescu } 360b77f6600SCristian Dumitrescu 361b77f6600SCristian Dumitrescu return 0; 362b77f6600SCristian Dumitrescu } 363b77f6600SCristian Dumitrescu 364b77f6600SCristian Dumitrescu /* Allocate request */ 365b77f6600SCristian Dumitrescu req = thread_msg_alloc(); 366b77f6600SCristian Dumitrescu if (req == NULL) 367b77f6600SCristian Dumitrescu return -1; 368b77f6600SCristian Dumitrescu 369b77f6600SCristian Dumitrescu /* Write request */ 370b77f6600SCristian Dumitrescu req->type = THREAD_REQ_PIPELINE_DISABLE; 371b77f6600SCristian Dumitrescu req->pipeline_disable.p = p->p; 372b77f6600SCristian Dumitrescu 373b77f6600SCristian Dumitrescu /* Send request and wait for response */ 374b77f6600SCristian Dumitrescu rsp = thread_msg_send_recv(thread_id, req); 375b77f6600SCristian Dumitrescu 376b77f6600SCristian Dumitrescu /* Read response */ 377b77f6600SCristian Dumitrescu status = rsp->status; 378b77f6600SCristian Dumitrescu 379b77f6600SCristian Dumitrescu /* Free response */ 380b77f6600SCristian Dumitrescu thread_msg_free(rsp); 381b77f6600SCristian Dumitrescu 382b77f6600SCristian Dumitrescu /* Request completion */ 383b77f6600SCristian Dumitrescu if (status) 384b77f6600SCristian Dumitrescu return status; 385b77f6600SCristian Dumitrescu 386b77f6600SCristian Dumitrescu p->enabled = 0; 387b77f6600SCristian Dumitrescu 388b77f6600SCristian Dumitrescu return 0; 389b77f6600SCristian Dumitrescu } 390b77f6600SCristian Dumitrescu 391b77f6600SCristian Dumitrescu /** 392b77f6600SCristian Dumitrescu * Data plane threads: message handling 393b77f6600SCristian Dumitrescu */ 394b77f6600SCristian Dumitrescu static inline struct thread_msg_req * 395b77f6600SCristian Dumitrescu thread_msg_recv(struct rte_ring *msgq_req) 396b77f6600SCristian Dumitrescu { 397b77f6600SCristian Dumitrescu struct thread_msg_req *req; 398b77f6600SCristian Dumitrescu 399b77f6600SCristian Dumitrescu int status = rte_ring_sc_dequeue(msgq_req, (void **) &req); 400b77f6600SCristian Dumitrescu 401b77f6600SCristian Dumitrescu if (status != 0) 402b77f6600SCristian Dumitrescu return NULL; 403b77f6600SCristian Dumitrescu 404b77f6600SCristian Dumitrescu return req; 405b77f6600SCristian Dumitrescu } 406b77f6600SCristian Dumitrescu 407b77f6600SCristian Dumitrescu static inline void 408b77f6600SCristian Dumitrescu thread_msg_send(struct rte_ring *msgq_rsp, 409b77f6600SCristian Dumitrescu struct thread_msg_rsp *rsp) 410b77f6600SCristian Dumitrescu { 411b77f6600SCristian Dumitrescu int status; 412b77f6600SCristian Dumitrescu 413b77f6600SCristian Dumitrescu do { 414b77f6600SCristian Dumitrescu status = rte_ring_sp_enqueue(msgq_rsp, rsp); 415b77f6600SCristian Dumitrescu } while (status == -ENOBUFS); 416b77f6600SCristian Dumitrescu } 417b77f6600SCristian Dumitrescu 418b77f6600SCristian Dumitrescu static struct thread_msg_rsp * 419b77f6600SCristian Dumitrescu thread_msg_handle_pipeline_enable(struct thread_data *t, 420b77f6600SCristian Dumitrescu struct thread_msg_req *req) 421b77f6600SCristian Dumitrescu { 422b77f6600SCristian Dumitrescu struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req; 423b77f6600SCristian Dumitrescu struct pipeline_data *p = &t->pipeline_data[t->n_pipelines]; 424b77f6600SCristian Dumitrescu 425b77f6600SCristian Dumitrescu /* Request */ 426b77f6600SCristian Dumitrescu if (t->n_pipelines >= THREAD_PIPELINES_MAX) { 427b77f6600SCristian Dumitrescu rsp->status = -1; 428b77f6600SCristian Dumitrescu return rsp; 429b77f6600SCristian Dumitrescu } 430b77f6600SCristian Dumitrescu 431b77f6600SCristian Dumitrescu t->p[t->n_pipelines] = req->pipeline_enable.p; 432b77f6600SCristian Dumitrescu 433b77f6600SCristian Dumitrescu p->p = req->pipeline_enable.p; 434b77f6600SCristian Dumitrescu p->timer_period = (rte_get_tsc_hz() * 435b77f6600SCristian Dumitrescu req->pipeline_enable.timer_period_ms) / 1000; 436b77f6600SCristian Dumitrescu p->time_next = rte_get_tsc_cycles() + p->timer_period; 437b77f6600SCristian Dumitrescu 438b77f6600SCristian Dumitrescu t->n_pipelines++; 439b77f6600SCristian Dumitrescu 440b77f6600SCristian Dumitrescu /* Response */ 441b77f6600SCristian Dumitrescu rsp->status = 0; 442b77f6600SCristian Dumitrescu return rsp; 443b77f6600SCristian Dumitrescu } 444b77f6600SCristian Dumitrescu 445b77f6600SCristian Dumitrescu static struct thread_msg_rsp * 446b77f6600SCristian Dumitrescu thread_msg_handle_pipeline_disable(struct thread_data *t, 447b77f6600SCristian Dumitrescu struct thread_msg_req *req) 448b77f6600SCristian Dumitrescu { 449b77f6600SCristian Dumitrescu struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req; 450b77f6600SCristian Dumitrescu uint32_t n_pipelines = t->n_pipelines; 451b77f6600SCristian Dumitrescu struct rte_swx_pipeline *pipeline = req->pipeline_disable.p; 452b77f6600SCristian Dumitrescu uint32_t i; 453b77f6600SCristian Dumitrescu 454b77f6600SCristian Dumitrescu /* find pipeline */ 455b77f6600SCristian Dumitrescu for (i = 0; i < n_pipelines; i++) { 456b77f6600SCristian Dumitrescu struct pipeline_data *p = &t->pipeline_data[i]; 457b77f6600SCristian Dumitrescu 458b77f6600SCristian Dumitrescu if (p->p != pipeline) 459b77f6600SCristian Dumitrescu continue; 460b77f6600SCristian Dumitrescu 461b77f6600SCristian Dumitrescu if (i < n_pipelines - 1) { 462b77f6600SCristian Dumitrescu struct rte_swx_pipeline *pipeline_last = 463b77f6600SCristian Dumitrescu t->p[n_pipelines - 1]; 464b77f6600SCristian Dumitrescu struct pipeline_data *p_last = 465b77f6600SCristian Dumitrescu &t->pipeline_data[n_pipelines - 1]; 466b77f6600SCristian Dumitrescu 467b77f6600SCristian Dumitrescu t->p[i] = pipeline_last; 468b77f6600SCristian Dumitrescu memcpy(p, p_last, sizeof(*p)); 469b77f6600SCristian Dumitrescu } 470b77f6600SCristian Dumitrescu 471b77f6600SCristian Dumitrescu t->n_pipelines--; 472b77f6600SCristian Dumitrescu 473b77f6600SCristian Dumitrescu rsp->status = 0; 474b77f6600SCristian Dumitrescu return rsp; 475b77f6600SCristian Dumitrescu } 476b77f6600SCristian Dumitrescu 477b77f6600SCristian Dumitrescu /* should not get here */ 478b77f6600SCristian Dumitrescu rsp->status = 0; 479b77f6600SCristian Dumitrescu return rsp; 480b77f6600SCristian Dumitrescu } 481b77f6600SCristian Dumitrescu 482b77f6600SCristian Dumitrescu static void 483b77f6600SCristian Dumitrescu thread_msg_handle(struct thread_data *t) 484b77f6600SCristian Dumitrescu { 485b77f6600SCristian Dumitrescu for ( ; ; ) { 486b77f6600SCristian Dumitrescu struct thread_msg_req *req; 487b77f6600SCristian Dumitrescu struct thread_msg_rsp *rsp; 488b77f6600SCristian Dumitrescu 489b77f6600SCristian Dumitrescu req = thread_msg_recv(t->msgq_req); 490b77f6600SCristian Dumitrescu if (req == NULL) 491b77f6600SCristian Dumitrescu break; 492b77f6600SCristian Dumitrescu 493b77f6600SCristian Dumitrescu switch (req->type) { 494b77f6600SCristian Dumitrescu case THREAD_REQ_PIPELINE_ENABLE: 495b77f6600SCristian Dumitrescu rsp = thread_msg_handle_pipeline_enable(t, req); 496b77f6600SCristian Dumitrescu break; 497b77f6600SCristian Dumitrescu 498b77f6600SCristian Dumitrescu case THREAD_REQ_PIPELINE_DISABLE: 499b77f6600SCristian Dumitrescu rsp = thread_msg_handle_pipeline_disable(t, req); 500b77f6600SCristian Dumitrescu break; 501b77f6600SCristian Dumitrescu 502b77f6600SCristian Dumitrescu default: 503b77f6600SCristian Dumitrescu rsp = (struct thread_msg_rsp *) req; 504b77f6600SCristian Dumitrescu rsp->status = -1; 505b77f6600SCristian Dumitrescu } 506b77f6600SCristian Dumitrescu 507b77f6600SCristian Dumitrescu thread_msg_send(t->msgq_rsp, rsp); 508b77f6600SCristian Dumitrescu } 509b77f6600SCristian Dumitrescu } 510b77f6600SCristian Dumitrescu 511b77f6600SCristian Dumitrescu /** 512b77f6600SCristian Dumitrescu * Data plane threads: main 513b77f6600SCristian Dumitrescu */ 514b77f6600SCristian Dumitrescu int 515b77f6600SCristian Dumitrescu thread_main(void *arg __rte_unused) 516b77f6600SCristian Dumitrescu { 517b77f6600SCristian Dumitrescu struct thread_data *t; 518b77f6600SCristian Dumitrescu uint32_t thread_id, i; 519b77f6600SCristian Dumitrescu 520b77f6600SCristian Dumitrescu thread_id = rte_lcore_id(); 521b77f6600SCristian Dumitrescu t = &thread_data[thread_id]; 522b77f6600SCristian Dumitrescu 523b77f6600SCristian Dumitrescu /* Dispatch loop */ 524b77f6600SCristian Dumitrescu for (i = 0; ; i++) { 525b77f6600SCristian Dumitrescu uint32_t j; 526b77f6600SCristian Dumitrescu 527b77f6600SCristian Dumitrescu /* Data Plane */ 528b77f6600SCristian Dumitrescu for (j = 0; j < t->n_pipelines; j++) 529*0b50ea60SCristian Dumitrescu rte_swx_pipeline_run(t->p[j], PIPELINE_INSTR_QUANTA); 530b77f6600SCristian Dumitrescu 531b77f6600SCristian Dumitrescu /* Control Plane */ 532b77f6600SCristian Dumitrescu if ((i & 0xF) == 0) { 533b77f6600SCristian Dumitrescu uint64_t time = rte_get_tsc_cycles(); 534b77f6600SCristian Dumitrescu uint64_t time_next_min = UINT64_MAX; 535b77f6600SCristian Dumitrescu 536b77f6600SCristian Dumitrescu if (time < t->time_next_min) 537b77f6600SCristian Dumitrescu continue; 538b77f6600SCristian Dumitrescu 539b77f6600SCristian Dumitrescu /* Thread message queues */ 540b77f6600SCristian Dumitrescu { 541b77f6600SCristian Dumitrescu uint64_t time_next = t->time_next; 542b77f6600SCristian Dumitrescu 543b77f6600SCristian Dumitrescu if (time_next <= time) { 544b77f6600SCristian Dumitrescu thread_msg_handle(t); 545b77f6600SCristian Dumitrescu time_next = time + t->timer_period; 546b77f6600SCristian Dumitrescu t->time_next = time_next; 547b77f6600SCristian Dumitrescu } 548b77f6600SCristian Dumitrescu 549b77f6600SCristian Dumitrescu if (time_next < time_next_min) 550b77f6600SCristian Dumitrescu time_next_min = time_next; 551b77f6600SCristian Dumitrescu } 552b77f6600SCristian Dumitrescu 553b77f6600SCristian Dumitrescu t->time_next_min = time_next_min; 554b77f6600SCristian Dumitrescu } 555b77f6600SCristian Dumitrescu } 556b77f6600SCristian Dumitrescu 557b77f6600SCristian Dumitrescu return 0; 558b77f6600SCristian Dumitrescu } 559