xref: /dpdk/drivers/event/dlb2/dlb2.c (revision 10eaf41d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016-2020 Intel Corporation
3  */
4 
5 #include <assert.h>
6 #include <errno.h>
7 #include <nmmintrin.h>
8 #include <pthread.h>
9 #include <stdint.h>
10 #include <stdbool.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <sys/mman.h>
14 #include <fcntl.h>
15 
16 #include <rte_common.h>
17 #include <rte_config.h>
18 #include <rte_cycles.h>
19 #include <rte_debug.h>
20 #include <rte_dev.h>
21 #include <rte_errno.h>
22 #include <rte_eventdev.h>
23 #include <eventdev_pmd.h>
24 #include <rte_io.h>
25 #include <rte_kvargs.h>
26 #include <rte_log.h>
27 #include <rte_malloc.h>
28 #include <rte_mbuf.h>
29 #include <rte_power_intrinsics.h>
30 #include <rte_prefetch.h>
31 #include <rte_ring.h>
32 #include <rte_string_fns.h>
33 
34 #include "dlb2_priv.h"
35 #include "dlb2_iface.h"
36 #include "dlb2_inline_fns.h"
37 
38 /*
39  * Resources exposed to eventdev. Some values overridden at runtime using
40  * values returned by the DLB kernel driver.
41  */
42 #if (RTE_EVENT_MAX_QUEUES_PER_DEV > UINT8_MAX)
43 #error "RTE_EVENT_MAX_QUEUES_PER_DEV cannot fit in member max_event_queues"
44 #endif
45 static struct rte_event_dev_info evdev_dlb2_default_info = {
46 	.driver_name = "", /* probe will set */
47 	.min_dequeue_timeout_ns = DLB2_MIN_DEQUEUE_TIMEOUT_NS,
48 	.max_dequeue_timeout_ns = DLB2_MAX_DEQUEUE_TIMEOUT_NS,
49 #if (RTE_EVENT_MAX_QUEUES_PER_DEV < DLB2_MAX_NUM_LDB_QUEUES)
50 	.max_event_queues = RTE_EVENT_MAX_QUEUES_PER_DEV,
51 #else
52 	.max_event_queues = DLB2_MAX_NUM_LDB_QUEUES,
53 #endif
54 	.max_event_queue_flows = DLB2_MAX_NUM_FLOWS,
55 	.max_event_queue_priority_levels = DLB2_QID_PRIORITIES,
56 	.max_event_priority_levels = DLB2_QID_PRIORITIES,
57 	.max_event_ports = DLB2_MAX_NUM_LDB_PORTS,
58 	.max_event_port_dequeue_depth = DLB2_MAX_CQ_DEPTH,
59 	.max_event_port_enqueue_depth = DLB2_MAX_ENQUEUE_DEPTH,
60 	.max_event_port_links = DLB2_MAX_NUM_QIDS_PER_LDB_CQ,
61 	.max_num_events = DLB2_MAX_NUM_LDB_CREDITS,
62 	.max_single_link_event_port_queue_pairs =
63 		DLB2_MAX_NUM_DIR_PORTS(DLB2_HW_V2),
64 	.event_dev_cap = (RTE_EVENT_DEV_CAP_QUEUE_QOS |
65 			  RTE_EVENT_DEV_CAP_EVENT_QOS |
66 			  RTE_EVENT_DEV_CAP_BURST_MODE |
67 			  RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED |
68 			  RTE_EVENT_DEV_CAP_IMPLICIT_RELEASE_DISABLE |
69 			  RTE_EVENT_DEV_CAP_QUEUE_ALL_TYPES),
70 };
71 
72 struct process_local_port_data
73 dlb2_port[DLB2_MAX_NUM_PORTS_ALL][DLB2_NUM_PORT_TYPES];
74 
75 static void
76 dlb2_free_qe_mem(struct dlb2_port *qm_port)
77 {
78 	if (qm_port == NULL)
79 		return;
80 
81 	rte_free(qm_port->qe4);
82 	qm_port->qe4 = NULL;
83 
84 	rte_free(qm_port->int_arm_qe);
85 	qm_port->int_arm_qe = NULL;
86 
87 	rte_free(qm_port->consume_qe);
88 	qm_port->consume_qe = NULL;
89 
90 	rte_memzone_free(dlb2_port[qm_port->id][PORT_TYPE(qm_port)].mz);
91 	dlb2_port[qm_port->id][PORT_TYPE(qm_port)].mz = NULL;
92 }
93 
94 /* override defaults with value(s) provided on command line */
95 static void
96 dlb2_init_queue_depth_thresholds(struct dlb2_eventdev *dlb2,
97 				 int *qid_depth_thresholds)
98 {
99 	int q;
100 
101 	for (q = 0; q < DLB2_MAX_NUM_QUEUES(dlb2->version); q++) {
102 		if (qid_depth_thresholds[q] != 0)
103 			dlb2->ev_queues[q].depth_threshold =
104 				qid_depth_thresholds[q];
105 	}
106 }
107 
108 static int
109 dlb2_hw_query_resources(struct dlb2_eventdev *dlb2)
110 {
111 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
112 	struct dlb2_hw_resource_info *dlb2_info = &handle->info;
113 	int ret;
114 
115 	/* Query driver resources provisioned for this device */
116 
117 	ret = dlb2_iface_get_num_resources(handle,
118 					   &dlb2->hw_rsrc_query_results);
119 	if (ret) {
120 		DLB2_LOG_ERR("ioctl get dlb2 num resources, err=%d\n", ret);
121 		return ret;
122 	}
123 
124 	/* Complete filling in device resource info returned to evdev app,
125 	 * overriding any default values.
126 	 * The capabilities (CAPs) were set at compile time.
127 	 */
128 
129 	evdev_dlb2_default_info.max_event_queues =
130 		dlb2->hw_rsrc_query_results.num_ldb_queues;
131 
132 	evdev_dlb2_default_info.max_event_ports =
133 		dlb2->hw_rsrc_query_results.num_ldb_ports;
134 
135 	if (dlb2->version == DLB2_HW_V2_5) {
136 		evdev_dlb2_default_info.max_num_events =
137 			dlb2->hw_rsrc_query_results.num_credits;
138 	} else {
139 		evdev_dlb2_default_info.max_num_events =
140 			dlb2->hw_rsrc_query_results.num_ldb_credits;
141 	}
142 	/* Save off values used when creating the scheduling domain. */
143 
144 	handle->info.num_sched_domains =
145 		dlb2->hw_rsrc_query_results.num_sched_domains;
146 
147 	if (dlb2->version == DLB2_HW_V2_5) {
148 		handle->info.hw_rsrc_max.nb_events_limit =
149 			dlb2->hw_rsrc_query_results.num_credits;
150 	} else {
151 		handle->info.hw_rsrc_max.nb_events_limit =
152 			dlb2->hw_rsrc_query_results.num_ldb_credits;
153 	}
154 	handle->info.hw_rsrc_max.num_queues =
155 		dlb2->hw_rsrc_query_results.num_ldb_queues +
156 		dlb2->hw_rsrc_query_results.num_dir_ports;
157 
158 	handle->info.hw_rsrc_max.num_ldb_queues =
159 		dlb2->hw_rsrc_query_results.num_ldb_queues;
160 
161 	handle->info.hw_rsrc_max.num_ldb_ports =
162 		dlb2->hw_rsrc_query_results.num_ldb_ports;
163 
164 	handle->info.hw_rsrc_max.num_dir_ports =
165 		dlb2->hw_rsrc_query_results.num_dir_ports;
166 
167 	handle->info.hw_rsrc_max.reorder_window_size =
168 		dlb2->hw_rsrc_query_results.num_hist_list_entries;
169 
170 	rte_memcpy(dlb2_info, &handle->info.hw_rsrc_max, sizeof(*dlb2_info));
171 
172 	return 0;
173 }
174 
175 #define DLB2_BASE_10 10
176 
177 static int
178 dlb2_string_to_int(int *result, const char *str)
179 {
180 	long ret;
181 	char *endptr;
182 
183 	if (str == NULL || result == NULL)
184 		return -EINVAL;
185 
186 	errno = 0;
187 	ret = strtol(str, &endptr, DLB2_BASE_10);
188 	if (errno)
189 		return -errno;
190 
191 	/* long int and int may be different width for some architectures */
192 	if (ret < INT_MIN || ret > INT_MAX || endptr == str)
193 		return -EINVAL;
194 
195 	*result = ret;
196 	return 0;
197 }
198 
199 static int
200 set_numa_node(const char *key __rte_unused, const char *value, void *opaque)
201 {
202 	int *socket_id = opaque;
203 	int ret;
204 
205 	ret = dlb2_string_to_int(socket_id, value);
206 	if (ret < 0)
207 		return ret;
208 
209 	if (*socket_id > RTE_MAX_NUMA_NODES)
210 		return -EINVAL;
211 	return 0;
212 }
213 
214 static int
215 set_max_num_events(const char *key __rte_unused,
216 		   const char *value,
217 		   void *opaque)
218 {
219 	int *max_num_events = opaque;
220 	int ret;
221 
222 	if (value == NULL || opaque == NULL) {
223 		DLB2_LOG_ERR("NULL pointer\n");
224 		return -EINVAL;
225 	}
226 
227 	ret = dlb2_string_to_int(max_num_events, value);
228 	if (ret < 0)
229 		return ret;
230 
231 	if (*max_num_events < 0 || *max_num_events >
232 			DLB2_MAX_NUM_LDB_CREDITS) {
233 		DLB2_LOG_ERR("dlb2: max_num_events must be between 0 and %d\n",
234 			     DLB2_MAX_NUM_LDB_CREDITS);
235 		return -EINVAL;
236 	}
237 
238 	return 0;
239 }
240 
241 static int
242 set_num_dir_credits(const char *key __rte_unused,
243 		    const char *value,
244 		    void *opaque)
245 {
246 	int *num_dir_credits = opaque;
247 	int ret;
248 
249 	if (value == NULL || opaque == NULL) {
250 		DLB2_LOG_ERR("NULL pointer\n");
251 		return -EINVAL;
252 	}
253 
254 	ret = dlb2_string_to_int(num_dir_credits, value);
255 	if (ret < 0)
256 		return ret;
257 
258 	if (*num_dir_credits < 0 ||
259 	    *num_dir_credits > DLB2_MAX_NUM_DIR_CREDITS(DLB2_HW_V2)) {
260 		DLB2_LOG_ERR("dlb2: num_dir_credits must be between 0 and %d\n",
261 			     DLB2_MAX_NUM_DIR_CREDITS(DLB2_HW_V2));
262 		return -EINVAL;
263 	}
264 
265 	return 0;
266 }
267 
268 static int
269 set_dev_id(const char *key __rte_unused,
270 	   const char *value,
271 	   void *opaque)
272 {
273 	int *dev_id = opaque;
274 	int ret;
275 
276 	if (value == NULL || opaque == NULL) {
277 		DLB2_LOG_ERR("NULL pointer\n");
278 		return -EINVAL;
279 	}
280 
281 	ret = dlb2_string_to_int(dev_id, value);
282 	if (ret < 0)
283 		return ret;
284 
285 	return 0;
286 }
287 
288 static int
289 set_cos(const char *key __rte_unused,
290 	const char *value,
291 	void *opaque)
292 {
293 	enum dlb2_cos *cos_id = opaque;
294 	int x = 0;
295 	int ret;
296 
297 	if (value == NULL || opaque == NULL) {
298 		DLB2_LOG_ERR("NULL pointer\n");
299 		return -EINVAL;
300 	}
301 
302 	ret = dlb2_string_to_int(&x, value);
303 	if (ret < 0)
304 		return ret;
305 
306 	if (x != DLB2_COS_DEFAULT && (x < DLB2_COS_0 || x > DLB2_COS_3)) {
307 		DLB2_LOG_ERR(
308 			"COS %d out of range, must be DLB2_COS_DEFAULT or 0-3\n",
309 			x);
310 		return -EINVAL;
311 	}
312 
313 	*cos_id = x;
314 
315 	return 0;
316 }
317 
318 static int
319 set_poll_interval(const char *key __rte_unused,
320 	const char *value,
321 	void *opaque)
322 {
323 	int *poll_interval = opaque;
324 	int ret;
325 
326 	if (value == NULL || opaque == NULL) {
327 		DLB2_LOG_ERR("NULL pointer\n");
328 		return -EINVAL;
329 	}
330 
331 	ret = dlb2_string_to_int(poll_interval, value);
332 	if (ret < 0)
333 		return ret;
334 
335 	return 0;
336 }
337 
338 static int
339 set_sw_credit_quanta(const char *key __rte_unused,
340 	const char *value,
341 	void *opaque)
342 {
343 	int *sw_credit_quanta = opaque;
344 	int ret;
345 
346 	if (value == NULL || opaque == NULL) {
347 		DLB2_LOG_ERR("NULL pointer\n");
348 		return -EINVAL;
349 	}
350 
351 	ret = dlb2_string_to_int(sw_credit_quanta, value);
352 	if (ret < 0)
353 		return ret;
354 
355 	return 0;
356 }
357 
358 static int
359 set_default_depth_thresh(const char *key __rte_unused,
360 	const char *value,
361 	void *opaque)
362 {
363 	int *default_depth_thresh = opaque;
364 	int ret;
365 
366 	if (value == NULL || opaque == NULL) {
367 		DLB2_LOG_ERR("NULL pointer\n");
368 		return -EINVAL;
369 	}
370 
371 	ret = dlb2_string_to_int(default_depth_thresh, value);
372 	if (ret < 0)
373 		return ret;
374 
375 	return 0;
376 }
377 
378 static int
379 set_vector_opts_enab(const char *key __rte_unused,
380 	const char *value,
381 	void *opaque)
382 {
383 	bool *dlb2_vector_opts_enabled = opaque;
384 
385 	if (value == NULL || opaque == NULL) {
386 		DLB2_LOG_ERR("NULL pointer\n");
387 		return -EINVAL;
388 	}
389 
390 	if ((*value == 'y') || (*value == 'Y'))
391 		*dlb2_vector_opts_enabled = true;
392 	else
393 		*dlb2_vector_opts_enabled = false;
394 
395 	return 0;
396 }
397 
398 static int
399 set_qid_depth_thresh(const char *key __rte_unused,
400 		     const char *value,
401 		     void *opaque)
402 {
403 	struct dlb2_qid_depth_thresholds *qid_thresh = opaque;
404 	int first, last, thresh, i;
405 
406 	if (value == NULL || opaque == NULL) {
407 		DLB2_LOG_ERR("NULL pointer\n");
408 		return -EINVAL;
409 	}
410 
411 	/* command line override may take one of the following 3 forms:
412 	 * qid_depth_thresh=all:<threshold_value> ... all queues
413 	 * qid_depth_thresh=qidA-qidB:<threshold_value> ... a range of queues
414 	 * qid_depth_thresh=qid:<threshold_value> ... just one queue
415 	 */
416 	if (sscanf(value, "all:%d", &thresh) == 1) {
417 		first = 0;
418 		last = DLB2_MAX_NUM_QUEUES(DLB2_HW_V2) - 1;
419 	} else if (sscanf(value, "%d-%d:%d", &first, &last, &thresh) == 3) {
420 		/* we have everything we need */
421 	} else if (sscanf(value, "%d:%d", &first, &thresh) == 2) {
422 		last = first;
423 	} else {
424 		DLB2_LOG_ERR("Error parsing qid depth devarg. Should be all:val, qid-qid:val, or qid:val\n");
425 		return -EINVAL;
426 	}
427 
428 	if (first > last || first < 0 ||
429 		last >= DLB2_MAX_NUM_QUEUES(DLB2_HW_V2)) {
430 		DLB2_LOG_ERR("Error parsing qid depth devarg, invalid qid value\n");
431 		return -EINVAL;
432 	}
433 
434 	if (thresh < 0 || thresh > DLB2_MAX_QUEUE_DEPTH_THRESHOLD) {
435 		DLB2_LOG_ERR("Error parsing qid depth devarg, threshold > %d\n",
436 			     DLB2_MAX_QUEUE_DEPTH_THRESHOLD);
437 		return -EINVAL;
438 	}
439 
440 	for (i = first; i <= last; i++)
441 		qid_thresh->val[i] = thresh; /* indexed by qid */
442 
443 	return 0;
444 }
445 
446 static int
447 set_qid_depth_thresh_v2_5(const char *key __rte_unused,
448 			  const char *value,
449 			  void *opaque)
450 {
451 	struct dlb2_qid_depth_thresholds *qid_thresh = opaque;
452 	int first, last, thresh, i;
453 
454 	if (value == NULL || opaque == NULL) {
455 		DLB2_LOG_ERR("NULL pointer\n");
456 		return -EINVAL;
457 	}
458 
459 	/* command line override may take one of the following 3 forms:
460 	 * qid_depth_thresh=all:<threshold_value> ... all queues
461 	 * qid_depth_thresh=qidA-qidB:<threshold_value> ... a range of queues
462 	 * qid_depth_thresh=qid:<threshold_value> ... just one queue
463 	 */
464 	if (sscanf(value, "all:%d", &thresh) == 1) {
465 		first = 0;
466 		last = DLB2_MAX_NUM_QUEUES(DLB2_HW_V2_5) - 1;
467 	} else if (sscanf(value, "%d-%d:%d", &first, &last, &thresh) == 3) {
468 		/* we have everything we need */
469 	} else if (sscanf(value, "%d:%d", &first, &thresh) == 2) {
470 		last = first;
471 	} else {
472 		DLB2_LOG_ERR("Error parsing qid depth devarg. Should be all:val, qid-qid:val, or qid:val\n");
473 		return -EINVAL;
474 	}
475 
476 	if (first > last || first < 0 ||
477 		last >= DLB2_MAX_NUM_QUEUES(DLB2_HW_V2_5)) {
478 		DLB2_LOG_ERR("Error parsing qid depth devarg, invalid qid value\n");
479 		return -EINVAL;
480 	}
481 
482 	if (thresh < 0 || thresh > DLB2_MAX_QUEUE_DEPTH_THRESHOLD) {
483 		DLB2_LOG_ERR("Error parsing qid depth devarg, threshold > %d\n",
484 			     DLB2_MAX_QUEUE_DEPTH_THRESHOLD);
485 		return -EINVAL;
486 	}
487 
488 	for (i = first; i <= last; i++)
489 		qid_thresh->val[i] = thresh; /* indexed by qid */
490 
491 	return 0;
492 }
493 
494 static void
495 dlb2_eventdev_info_get(struct rte_eventdev *dev,
496 		       struct rte_event_dev_info *dev_info)
497 {
498 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
499 	int ret;
500 
501 	ret = dlb2_hw_query_resources(dlb2);
502 	if (ret) {
503 		const struct rte_eventdev_data *data = dev->data;
504 
505 		DLB2_LOG_ERR("get resources err=%d, devid=%d\n",
506 			     ret, data->dev_id);
507 		/* fn is void, so fall through and return values set up in
508 		 * probe
509 		 */
510 	}
511 
512 	/* Add num resources currently owned by this domain.
513 	 * These would become available if the scheduling domain were reset due
514 	 * to the application recalling eventdev_configure to *reconfigure* the
515 	 * domain.
516 	 */
517 	evdev_dlb2_default_info.max_event_ports += dlb2->num_ldb_ports;
518 	evdev_dlb2_default_info.max_event_queues += dlb2->num_ldb_queues;
519 	if (dlb2->version == DLB2_HW_V2_5) {
520 		evdev_dlb2_default_info.max_num_events +=
521 			dlb2->max_credits;
522 	} else {
523 		evdev_dlb2_default_info.max_num_events +=
524 			dlb2->max_ldb_credits;
525 	}
526 	evdev_dlb2_default_info.max_event_queues =
527 		RTE_MIN(evdev_dlb2_default_info.max_event_queues,
528 			RTE_EVENT_MAX_QUEUES_PER_DEV);
529 
530 	evdev_dlb2_default_info.max_num_events =
531 		RTE_MIN(evdev_dlb2_default_info.max_num_events,
532 			dlb2->max_num_events_override);
533 
534 	*dev_info = evdev_dlb2_default_info;
535 }
536 
537 static int
538 dlb2_hw_create_sched_domain(struct dlb2_hw_dev *handle,
539 			    const struct dlb2_hw_rsrcs *resources_asked,
540 			    uint8_t device_version)
541 {
542 	int ret = 0;
543 	struct dlb2_create_sched_domain_args *cfg;
544 
545 	if (resources_asked == NULL) {
546 		DLB2_LOG_ERR("dlb2: dlb2_create NULL parameter\n");
547 		ret = EINVAL;
548 		goto error_exit;
549 	}
550 
551 	/* Map generic qm resources to dlb2 resources */
552 	cfg = &handle->cfg.resources;
553 
554 	/* DIR ports and queues */
555 
556 	cfg->num_dir_ports = resources_asked->num_dir_ports;
557 	if (device_version == DLB2_HW_V2_5)
558 		cfg->num_credits = resources_asked->num_credits;
559 	else
560 		cfg->num_dir_credits = resources_asked->num_dir_credits;
561 
562 	/* LDB queues */
563 
564 	cfg->num_ldb_queues = resources_asked->num_ldb_queues;
565 
566 	/* LDB ports */
567 
568 	cfg->cos_strict = 0; /* Best effort */
569 	cfg->num_cos_ldb_ports[0] = 0;
570 	cfg->num_cos_ldb_ports[1] = 0;
571 	cfg->num_cos_ldb_ports[2] = 0;
572 	cfg->num_cos_ldb_ports[3] = 0;
573 
574 	switch (handle->cos_id) {
575 	case DLB2_COS_0:
576 		cfg->num_ldb_ports = 0; /* no don't care ports */
577 		cfg->num_cos_ldb_ports[0] =
578 			resources_asked->num_ldb_ports;
579 		break;
580 	case DLB2_COS_1:
581 		cfg->num_ldb_ports = 0; /* no don't care ports */
582 		cfg->num_cos_ldb_ports[1] = resources_asked->num_ldb_ports;
583 		break;
584 	case DLB2_COS_2:
585 		cfg->num_ldb_ports = 0; /* no don't care ports */
586 		cfg->num_cos_ldb_ports[2] = resources_asked->num_ldb_ports;
587 		break;
588 	case DLB2_COS_3:
589 		cfg->num_ldb_ports = 0; /* no don't care ports */
590 		cfg->num_cos_ldb_ports[3] =
591 			resources_asked->num_ldb_ports;
592 		break;
593 	case DLB2_COS_DEFAULT:
594 		/* all ldb ports are don't care ports from a cos perspective */
595 		cfg->num_ldb_ports =
596 			resources_asked->num_ldb_ports;
597 		break;
598 	}
599 
600 	if (device_version == DLB2_HW_V2)
601 		cfg->num_ldb_credits = resources_asked->num_ldb_credits;
602 
603 	cfg->num_atomic_inflights =
604 		DLB2_NUM_ATOMIC_INFLIGHTS_PER_QUEUE *
605 		cfg->num_ldb_queues;
606 
607 	cfg->num_hist_list_entries = resources_asked->num_ldb_ports *
608 		DLB2_NUM_HIST_LIST_ENTRIES_PER_LDB_PORT;
609 
610 	if (device_version == DLB2_HW_V2_5) {
611 		DLB2_LOG_DBG("sched domain create - ldb_qs=%d, ldb_ports=%d, dir_ports=%d, atomic_inflights=%d, hist_list_entries=%d, credits=%d\n",
612 			     cfg->num_ldb_queues,
613 			     resources_asked->num_ldb_ports,
614 			     cfg->num_dir_ports,
615 			     cfg->num_atomic_inflights,
616 			     cfg->num_hist_list_entries,
617 			     cfg->num_credits);
618 	} else {
619 		DLB2_LOG_DBG("sched domain create - ldb_qs=%d, ldb_ports=%d, dir_ports=%d, atomic_inflights=%d, hist_list_entries=%d, ldb_credits=%d, dir_credits=%d\n",
620 			     cfg->num_ldb_queues,
621 			     resources_asked->num_ldb_ports,
622 			     cfg->num_dir_ports,
623 			     cfg->num_atomic_inflights,
624 			     cfg->num_hist_list_entries,
625 			     cfg->num_ldb_credits,
626 			     cfg->num_dir_credits);
627 	}
628 
629 	/* Configure the QM */
630 
631 	ret = dlb2_iface_sched_domain_create(handle, cfg);
632 	if (ret < 0) {
633 		DLB2_LOG_ERR("dlb2: domain create failed, ret = %d, extra status: %s\n",
634 			     ret,
635 			     dlb2_error_strings[cfg->response.status]);
636 
637 		goto error_exit;
638 	}
639 
640 	handle->domain_id = cfg->response.id;
641 	handle->cfg.configured = true;
642 
643 error_exit:
644 
645 	return ret;
646 }
647 
648 static void
649 dlb2_hw_reset_sched_domain(const struct rte_eventdev *dev, bool reconfig)
650 {
651 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
652 	enum dlb2_configuration_state config_state;
653 	int i, j;
654 
655 	dlb2_iface_domain_reset(dlb2);
656 
657 	/* Free all dynamically allocated port memory */
658 	for (i = 0; i < dlb2->num_ports; i++)
659 		dlb2_free_qe_mem(&dlb2->ev_ports[i].qm_port);
660 
661 	/* If reconfiguring, mark the device's queues and ports as "previously
662 	 * configured." If the user doesn't reconfigure them, the PMD will
663 	 * reapply their previous configuration when the device is started.
664 	 */
665 	config_state = (reconfig) ? DLB2_PREV_CONFIGURED :
666 		DLB2_NOT_CONFIGURED;
667 
668 	for (i = 0; i < dlb2->num_ports; i++) {
669 		dlb2->ev_ports[i].qm_port.config_state = config_state;
670 		/* Reset setup_done so ports can be reconfigured */
671 		dlb2->ev_ports[i].setup_done = false;
672 		for (j = 0; j < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; j++)
673 			dlb2->ev_ports[i].link[j].mapped = false;
674 	}
675 
676 	for (i = 0; i < dlb2->num_queues; i++)
677 		dlb2->ev_queues[i].qm_queue.config_state = config_state;
678 
679 	for (i = 0; i < DLB2_MAX_NUM_QUEUES(DLB2_HW_V2_5); i++)
680 		dlb2->ev_queues[i].setup_done = false;
681 
682 	dlb2->num_ports = 0;
683 	dlb2->num_ldb_ports = 0;
684 	dlb2->num_dir_ports = 0;
685 	dlb2->num_queues = 0;
686 	dlb2->num_ldb_queues = 0;
687 	dlb2->num_dir_queues = 0;
688 	dlb2->configured = false;
689 }
690 
691 /* Note: 1 QM instance per QM device, QM instance/device == event device */
692 static int
693 dlb2_eventdev_configure(const struct rte_eventdev *dev)
694 {
695 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
696 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
697 	struct dlb2_hw_rsrcs *rsrcs = &handle->info.hw_rsrc_max;
698 	const struct rte_eventdev_data *data = dev->data;
699 	const struct rte_event_dev_config *config = &data->dev_conf;
700 	int ret;
701 
702 	/* If this eventdev is already configured, we must release the current
703 	 * scheduling domain before attempting to configure a new one.
704 	 */
705 	if (dlb2->configured) {
706 		dlb2_hw_reset_sched_domain(dev, true);
707 		ret = dlb2_hw_query_resources(dlb2);
708 		if (ret) {
709 			DLB2_LOG_ERR("get resources err=%d, devid=%d\n",
710 				     ret, data->dev_id);
711 			return ret;
712 		}
713 	}
714 
715 	if (config->nb_event_queues > rsrcs->num_queues) {
716 		DLB2_LOG_ERR("nb_event_queues parameter (%d) exceeds the QM device's capabilities (%d).\n",
717 			     config->nb_event_queues,
718 			     rsrcs->num_queues);
719 		return -EINVAL;
720 	}
721 	if (config->nb_event_ports > (rsrcs->num_ldb_ports
722 			+ rsrcs->num_dir_ports)) {
723 		DLB2_LOG_ERR("nb_event_ports parameter (%d) exceeds the QM device's capabilities (%d).\n",
724 			     config->nb_event_ports,
725 			     (rsrcs->num_ldb_ports + rsrcs->num_dir_ports));
726 		return -EINVAL;
727 	}
728 	if (config->nb_events_limit > rsrcs->nb_events_limit) {
729 		DLB2_LOG_ERR("nb_events_limit parameter (%d) exceeds the QM device's capabilities (%d).\n",
730 			     config->nb_events_limit,
731 			     rsrcs->nb_events_limit);
732 		return -EINVAL;
733 	}
734 
735 	if (config->event_dev_cfg & RTE_EVENT_DEV_CFG_PER_DEQUEUE_TIMEOUT)
736 		dlb2->global_dequeue_wait = false;
737 	else {
738 		uint32_t timeout32;
739 
740 		dlb2->global_dequeue_wait = true;
741 
742 		/* note size mismatch of timeout vals in eventdev lib. */
743 		timeout32 = config->dequeue_timeout_ns;
744 
745 		dlb2->global_dequeue_wait_ticks =
746 			timeout32 * (rte_get_timer_hz() / 1E9);
747 	}
748 
749 	/* Does this platform support umonitor/umwait? */
750 	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG))
751 		dlb2->umwait_allowed = true;
752 
753 	rsrcs->num_dir_ports = config->nb_single_link_event_port_queues;
754 	rsrcs->num_ldb_ports  = config->nb_event_ports - rsrcs->num_dir_ports;
755 	/* 1 dir queue per dir port */
756 	rsrcs->num_ldb_queues = config->nb_event_queues - rsrcs->num_dir_ports;
757 
758 	if (dlb2->version == DLB2_HW_V2_5) {
759 		rsrcs->num_credits = 0;
760 		if (rsrcs->num_ldb_queues || rsrcs->num_dir_ports)
761 			rsrcs->num_credits = config->nb_events_limit;
762 	} else {
763 		/* Scale down nb_events_limit by 4 for directed credits,
764 		 * since there are 4x as many load-balanced credits.
765 		 */
766 		rsrcs->num_ldb_credits = 0;
767 		rsrcs->num_dir_credits = 0;
768 
769 		if (rsrcs->num_ldb_queues)
770 			rsrcs->num_ldb_credits = config->nb_events_limit;
771 		if (rsrcs->num_dir_ports)
772 			rsrcs->num_dir_credits = config->nb_events_limit / 4;
773 		if (dlb2->num_dir_credits_override != -1)
774 			rsrcs->num_dir_credits = dlb2->num_dir_credits_override;
775 	}
776 
777 	if (dlb2_hw_create_sched_domain(handle, rsrcs, dlb2->version) < 0) {
778 		DLB2_LOG_ERR("dlb2_hw_create_sched_domain failed\n");
779 		return -ENODEV;
780 	}
781 
782 	dlb2->new_event_limit = config->nb_events_limit;
783 	__atomic_store_n(&dlb2->inflights, 0, __ATOMIC_SEQ_CST);
784 
785 	/* Save number of ports/queues for this event dev */
786 	dlb2->num_ports = config->nb_event_ports;
787 	dlb2->num_queues = config->nb_event_queues;
788 	dlb2->num_dir_ports = rsrcs->num_dir_ports;
789 	dlb2->num_ldb_ports = dlb2->num_ports - dlb2->num_dir_ports;
790 	dlb2->num_ldb_queues = dlb2->num_queues - dlb2->num_dir_ports;
791 	dlb2->num_dir_queues = dlb2->num_dir_ports;
792 	if (dlb2->version == DLB2_HW_V2_5) {
793 		dlb2->credit_pool = rsrcs->num_credits;
794 		dlb2->max_credits = rsrcs->num_credits;
795 	} else {
796 		dlb2->ldb_credit_pool = rsrcs->num_ldb_credits;
797 		dlb2->max_ldb_credits = rsrcs->num_ldb_credits;
798 		dlb2->dir_credit_pool = rsrcs->num_dir_credits;
799 		dlb2->max_dir_credits = rsrcs->num_dir_credits;
800 	}
801 
802 	dlb2->configured = true;
803 
804 	return 0;
805 }
806 
807 static void
808 dlb2_eventdev_port_default_conf_get(struct rte_eventdev *dev,
809 				    uint8_t port_id,
810 				    struct rte_event_port_conf *port_conf)
811 {
812 	RTE_SET_USED(port_id);
813 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
814 
815 	port_conf->new_event_threshold = dlb2->new_event_limit;
816 	port_conf->dequeue_depth = 32;
817 	port_conf->enqueue_depth = DLB2_MAX_ENQUEUE_DEPTH;
818 	port_conf->event_port_cfg = 0;
819 }
820 
821 static void
822 dlb2_eventdev_queue_default_conf_get(struct rte_eventdev *dev,
823 				     uint8_t queue_id,
824 				     struct rte_event_queue_conf *queue_conf)
825 {
826 	RTE_SET_USED(dev);
827 	RTE_SET_USED(queue_id);
828 
829 	queue_conf->nb_atomic_flows = 1024;
830 	queue_conf->nb_atomic_order_sequences = 64;
831 	queue_conf->event_queue_cfg = 0;
832 	queue_conf->priority = 0;
833 }
834 
835 static int32_t
836 dlb2_get_sn_allocation(struct dlb2_eventdev *dlb2, int group)
837 {
838 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
839 	struct dlb2_get_sn_allocation_args cfg;
840 	int ret;
841 
842 	cfg.group = group;
843 
844 	ret = dlb2_iface_get_sn_allocation(handle, &cfg);
845 	if (ret < 0) {
846 		DLB2_LOG_ERR("dlb2: get_sn_allocation ret=%d (driver status: %s)\n",
847 			     ret, dlb2_error_strings[cfg.response.status]);
848 		return ret;
849 	}
850 
851 	return cfg.response.id;
852 }
853 
854 static int
855 dlb2_set_sn_allocation(struct dlb2_eventdev *dlb2, int group, int num)
856 {
857 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
858 	struct dlb2_set_sn_allocation_args cfg;
859 	int ret;
860 
861 	cfg.num = num;
862 	cfg.group = group;
863 
864 	ret = dlb2_iface_set_sn_allocation(handle, &cfg);
865 	if (ret < 0) {
866 		DLB2_LOG_ERR("dlb2: set_sn_allocation ret=%d (driver status: %s)\n",
867 			     ret, dlb2_error_strings[cfg.response.status]);
868 		return ret;
869 	}
870 
871 	return ret;
872 }
873 
874 static int32_t
875 dlb2_get_sn_occupancy(struct dlb2_eventdev *dlb2, int group)
876 {
877 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
878 	struct dlb2_get_sn_occupancy_args cfg;
879 	int ret;
880 
881 	cfg.group = group;
882 
883 	ret = dlb2_iface_get_sn_occupancy(handle, &cfg);
884 	if (ret < 0) {
885 		DLB2_LOG_ERR("dlb2: get_sn_occupancy ret=%d (driver status: %s)\n",
886 			     ret, dlb2_error_strings[cfg.response.status]);
887 		return ret;
888 	}
889 
890 	return cfg.response.id;
891 }
892 
893 /* Query the current sequence number allocations and, if they conflict with the
894  * requested LDB queue configuration, attempt to re-allocate sequence numbers.
895  * This is best-effort; if it fails, the PMD will attempt to configure the
896  * load-balanced queue and return an error.
897  */
898 static void
899 dlb2_program_sn_allocation(struct dlb2_eventdev *dlb2,
900 			   const struct rte_event_queue_conf *queue_conf)
901 {
902 	int grp_occupancy[DLB2_NUM_SN_GROUPS];
903 	int grp_alloc[DLB2_NUM_SN_GROUPS];
904 	int i, sequence_numbers;
905 
906 	sequence_numbers = (int)queue_conf->nb_atomic_order_sequences;
907 
908 	for (i = 0; i < DLB2_NUM_SN_GROUPS; i++) {
909 		int total_slots;
910 
911 		grp_alloc[i] = dlb2_get_sn_allocation(dlb2, i);
912 		if (grp_alloc[i] < 0)
913 			return;
914 
915 		total_slots = DLB2_MAX_LDB_SN_ALLOC / grp_alloc[i];
916 
917 		grp_occupancy[i] = dlb2_get_sn_occupancy(dlb2, i);
918 		if (grp_occupancy[i] < 0)
919 			return;
920 
921 		/* DLB has at least one available slot for the requested
922 		 * sequence numbers, so no further configuration required.
923 		 */
924 		if (grp_alloc[i] == sequence_numbers &&
925 		    grp_occupancy[i] < total_slots)
926 			return;
927 	}
928 
929 	/* None of the sequence number groups are configured for the requested
930 	 * sequence numbers, so we have to reconfigure one of them. This is
931 	 * only possible if a group is not in use.
932 	 */
933 	for (i = 0; i < DLB2_NUM_SN_GROUPS; i++) {
934 		if (grp_occupancy[i] == 0)
935 			break;
936 	}
937 
938 	if (i == DLB2_NUM_SN_GROUPS) {
939 		DLB2_LOG_ERR("[%s()] No groups with %d sequence_numbers are available or have free slots\n",
940 		       __func__, sequence_numbers);
941 		return;
942 	}
943 
944 	/* Attempt to configure slot i with the requested number of sequence
945 	 * numbers. Ignore the return value -- if this fails, the error will be
946 	 * caught during subsequent queue configuration.
947 	 */
948 	dlb2_set_sn_allocation(dlb2, i, sequence_numbers);
949 }
950 
951 static int32_t
952 dlb2_hw_create_ldb_queue(struct dlb2_eventdev *dlb2,
953 			 struct dlb2_eventdev_queue *ev_queue,
954 			 const struct rte_event_queue_conf *evq_conf)
955 {
956 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
957 	struct dlb2_queue *queue = &ev_queue->qm_queue;
958 	struct dlb2_create_ldb_queue_args cfg;
959 	int32_t ret;
960 	uint32_t qm_qid;
961 	int sched_type = -1;
962 
963 	if (evq_conf == NULL)
964 		return -EINVAL;
965 
966 	if (evq_conf->event_queue_cfg & RTE_EVENT_QUEUE_CFG_ALL_TYPES) {
967 		if (evq_conf->nb_atomic_order_sequences != 0)
968 			sched_type = RTE_SCHED_TYPE_ORDERED;
969 		else
970 			sched_type = RTE_SCHED_TYPE_PARALLEL;
971 	} else
972 		sched_type = evq_conf->schedule_type;
973 
974 	cfg.num_atomic_inflights = DLB2_NUM_ATOMIC_INFLIGHTS_PER_QUEUE;
975 	cfg.num_sequence_numbers = evq_conf->nb_atomic_order_sequences;
976 	cfg.num_qid_inflights = evq_conf->nb_atomic_order_sequences;
977 
978 	if (sched_type != RTE_SCHED_TYPE_ORDERED) {
979 		cfg.num_sequence_numbers = 0;
980 		cfg.num_qid_inflights = 2048;
981 	}
982 
983 	/* App should set this to the number of hardware flows they want, not
984 	 * the overall number of flows they're going to use. E.g. if app is
985 	 * using 64 flows and sets compression to 64, best-case they'll get
986 	 * 64 unique hashed flows in hardware.
987 	 */
988 	switch (evq_conf->nb_atomic_flows) {
989 	/* Valid DLB2 compression levels */
990 	case 64:
991 	case 128:
992 	case 256:
993 	case 512:
994 	case (1 * 1024): /* 1K */
995 	case (2 * 1024): /* 2K */
996 	case (4 * 1024): /* 4K */
997 	case (64 * 1024): /* 64K */
998 		cfg.lock_id_comp_level = evq_conf->nb_atomic_flows;
999 		break;
1000 	default:
1001 		/* Invalid compression level */
1002 		cfg.lock_id_comp_level = 0; /* no compression */
1003 	}
1004 
1005 	if (ev_queue->depth_threshold == 0) {
1006 		cfg.depth_threshold = dlb2->default_depth_thresh;
1007 		ev_queue->depth_threshold =
1008 			dlb2->default_depth_thresh;
1009 	} else
1010 		cfg.depth_threshold = ev_queue->depth_threshold;
1011 
1012 	ret = dlb2_iface_ldb_queue_create(handle, &cfg);
1013 	if (ret < 0) {
1014 		DLB2_LOG_ERR("dlb2: create LB event queue error, ret=%d (driver status: %s)\n",
1015 			     ret, dlb2_error_strings[cfg.response.status]);
1016 		return -EINVAL;
1017 	}
1018 
1019 	qm_qid = cfg.response.id;
1020 
1021 	/* Save off queue config for debug, resource lookups, and reconfig */
1022 	queue->num_qid_inflights = cfg.num_qid_inflights;
1023 	queue->num_atm_inflights = cfg.num_atomic_inflights;
1024 
1025 	queue->sched_type = sched_type;
1026 	queue->config_state = DLB2_CONFIGURED;
1027 
1028 	DLB2_LOG_DBG("Created LB event queue %d, nb_inflights=%d, nb_seq=%d, qid inflights=%d\n",
1029 		     qm_qid,
1030 		     cfg.num_atomic_inflights,
1031 		     cfg.num_sequence_numbers,
1032 		     cfg.num_qid_inflights);
1033 
1034 	return qm_qid;
1035 }
1036 
1037 static int
1038 dlb2_eventdev_ldb_queue_setup(struct rte_eventdev *dev,
1039 			      struct dlb2_eventdev_queue *ev_queue,
1040 			      const struct rte_event_queue_conf *queue_conf)
1041 {
1042 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
1043 	int32_t qm_qid;
1044 
1045 	if (queue_conf->nb_atomic_order_sequences)
1046 		dlb2_program_sn_allocation(dlb2, queue_conf);
1047 
1048 	qm_qid = dlb2_hw_create_ldb_queue(dlb2, ev_queue, queue_conf);
1049 	if (qm_qid < 0) {
1050 		DLB2_LOG_ERR("Failed to create the load-balanced queue\n");
1051 
1052 		return qm_qid;
1053 	}
1054 
1055 	dlb2->qm_ldb_to_ev_queue_id[qm_qid] = ev_queue->id;
1056 
1057 	ev_queue->qm_queue.id = qm_qid;
1058 
1059 	return 0;
1060 }
1061 
1062 static int dlb2_num_dir_queues_setup(struct dlb2_eventdev *dlb2)
1063 {
1064 	int i, num = 0;
1065 
1066 	for (i = 0; i < dlb2->num_queues; i++) {
1067 		if (dlb2->ev_queues[i].setup_done &&
1068 		    dlb2->ev_queues[i].qm_queue.is_directed)
1069 			num++;
1070 	}
1071 
1072 	return num;
1073 }
1074 
1075 static void
1076 dlb2_queue_link_teardown(struct dlb2_eventdev *dlb2,
1077 			 struct dlb2_eventdev_queue *ev_queue)
1078 {
1079 	struct dlb2_eventdev_port *ev_port;
1080 	int i, j;
1081 
1082 	for (i = 0; i < dlb2->num_ports; i++) {
1083 		ev_port = &dlb2->ev_ports[i];
1084 
1085 		for (j = 0; j < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; j++) {
1086 			if (!ev_port->link[j].valid ||
1087 			    ev_port->link[j].queue_id != ev_queue->id)
1088 				continue;
1089 
1090 			ev_port->link[j].valid = false;
1091 			ev_port->num_links--;
1092 		}
1093 	}
1094 
1095 	ev_queue->num_links = 0;
1096 }
1097 
1098 static int
1099 dlb2_eventdev_queue_setup(struct rte_eventdev *dev,
1100 			  uint8_t ev_qid,
1101 			  const struct rte_event_queue_conf *queue_conf)
1102 {
1103 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
1104 	struct dlb2_eventdev_queue *ev_queue;
1105 	int ret;
1106 
1107 	if (queue_conf == NULL)
1108 		return -EINVAL;
1109 
1110 	if (ev_qid >= dlb2->num_queues)
1111 		return -EINVAL;
1112 
1113 	ev_queue = &dlb2->ev_queues[ev_qid];
1114 
1115 	ev_queue->qm_queue.is_directed = queue_conf->event_queue_cfg &
1116 		RTE_EVENT_QUEUE_CFG_SINGLE_LINK;
1117 	ev_queue->id = ev_qid;
1118 	ev_queue->conf = *queue_conf;
1119 
1120 	if (!ev_queue->qm_queue.is_directed) {
1121 		ret = dlb2_eventdev_ldb_queue_setup(dev, ev_queue, queue_conf);
1122 	} else {
1123 		/* The directed queue isn't setup until link time, at which
1124 		 * point we know its directed port ID. Directed queue setup
1125 		 * will only fail if this queue is already setup or there are
1126 		 * no directed queues left to configure.
1127 		 */
1128 		ret = 0;
1129 
1130 		ev_queue->qm_queue.config_state = DLB2_NOT_CONFIGURED;
1131 
1132 		if (ev_queue->setup_done ||
1133 		    dlb2_num_dir_queues_setup(dlb2) == dlb2->num_dir_queues)
1134 			ret = -EINVAL;
1135 	}
1136 
1137 	/* Tear down pre-existing port->queue links */
1138 	if (!ret && dlb2->run_state == DLB2_RUN_STATE_STOPPED)
1139 		dlb2_queue_link_teardown(dlb2, ev_queue);
1140 
1141 	if (!ret)
1142 		ev_queue->setup_done = true;
1143 
1144 	return ret;
1145 }
1146 
1147 static int
1148 dlb2_init_consume_qe(struct dlb2_port *qm_port, char *mz_name)
1149 {
1150 	struct dlb2_cq_pop_qe *qe;
1151 
1152 	qe = rte_zmalloc(mz_name,
1153 			DLB2_NUM_QES_PER_CACHE_LINE *
1154 				sizeof(struct dlb2_cq_pop_qe),
1155 			RTE_CACHE_LINE_SIZE);
1156 
1157 	if (qe == NULL)	{
1158 		DLB2_LOG_ERR("dlb2: no memory for consume_qe\n");
1159 		return -ENOMEM;
1160 	}
1161 	qm_port->consume_qe = qe;
1162 
1163 	qe->qe_valid = 0;
1164 	qe->qe_frag = 0;
1165 	qe->qe_comp = 0;
1166 	qe->cq_token = 1;
1167 	/* Tokens value is 0-based; i.e. '0' returns 1 token, '1' returns 2,
1168 	 * and so on.
1169 	 */
1170 	qe->tokens = 0;	/* set at run time */
1171 	qe->meas_lat = 0;
1172 	qe->no_dec = 0;
1173 	/* Completion IDs are disabled */
1174 	qe->cmp_id = 0;
1175 
1176 	return 0;
1177 }
1178 
1179 static int
1180 dlb2_init_int_arm_qe(struct dlb2_port *qm_port, char *mz_name)
1181 {
1182 	struct dlb2_enqueue_qe *qe;
1183 
1184 	qe = rte_zmalloc(mz_name,
1185 			DLB2_NUM_QES_PER_CACHE_LINE *
1186 				sizeof(struct dlb2_enqueue_qe),
1187 			RTE_CACHE_LINE_SIZE);
1188 
1189 	if (qe == NULL) {
1190 		DLB2_LOG_ERR("dlb2: no memory for complete_qe\n");
1191 		return -ENOMEM;
1192 	}
1193 	qm_port->int_arm_qe = qe;
1194 
1195 	/* V2 - INT ARM is CQ_TOKEN + FRAG */
1196 	qe->qe_valid = 0;
1197 	qe->qe_frag = 1;
1198 	qe->qe_comp = 0;
1199 	qe->cq_token = 1;
1200 	qe->meas_lat = 0;
1201 	qe->no_dec = 0;
1202 	/* Completion IDs are disabled */
1203 	qe->cmp_id = 0;
1204 
1205 	return 0;
1206 }
1207 
1208 static int
1209 dlb2_init_qe_mem(struct dlb2_port *qm_port, char *mz_name)
1210 {
1211 	int ret, sz;
1212 
1213 	sz = DLB2_NUM_QES_PER_CACHE_LINE * sizeof(struct dlb2_enqueue_qe);
1214 
1215 	qm_port->qe4 = rte_zmalloc(mz_name, sz, RTE_CACHE_LINE_SIZE);
1216 
1217 	if (qm_port->qe4 == NULL) {
1218 		DLB2_LOG_ERR("dlb2: no qe4 memory\n");
1219 		ret = -ENOMEM;
1220 		goto error_exit;
1221 	}
1222 
1223 	ret = dlb2_init_int_arm_qe(qm_port, mz_name);
1224 	if (ret < 0) {
1225 		DLB2_LOG_ERR("dlb2: dlb2_init_int_arm_qe ret=%d\n", ret);
1226 		goto error_exit;
1227 	}
1228 
1229 	ret = dlb2_init_consume_qe(qm_port, mz_name);
1230 	if (ret < 0) {
1231 		DLB2_LOG_ERR("dlb2: dlb2_init_consume_qe ret=%d\n", ret);
1232 		goto error_exit;
1233 	}
1234 
1235 	return 0;
1236 
1237 error_exit:
1238 
1239 	dlb2_free_qe_mem(qm_port);
1240 
1241 	return ret;
1242 }
1243 
1244 static inline uint16_t
1245 dlb2_event_enqueue_delayed(void *event_port,
1246 			   const struct rte_event events[]);
1247 
1248 static inline uint16_t
1249 dlb2_event_enqueue_burst_delayed(void *event_port,
1250 				 const struct rte_event events[],
1251 				 uint16_t num);
1252 
1253 static inline uint16_t
1254 dlb2_event_enqueue_new_burst_delayed(void *event_port,
1255 				     const struct rte_event events[],
1256 				     uint16_t num);
1257 
1258 static inline uint16_t
1259 dlb2_event_enqueue_forward_burst_delayed(void *event_port,
1260 					 const struct rte_event events[],
1261 					 uint16_t num);
1262 
1263 /* Generate the required bitmask for rotate-style expected QE gen bits.
1264  * This requires a pattern of 1's and zeros, starting with expected as
1265  * 1 bits, so when hardware writes 0's they're "new". This requires the
1266  * ring size to be powers of 2 to wrap correctly.
1267  */
1268 static void
1269 dlb2_hw_cq_bitmask_init(struct dlb2_port *qm_port, uint32_t cq_depth)
1270 {
1271 	uint64_t cq_build_mask = 0;
1272 	uint32_t i;
1273 
1274 	if (cq_depth > 64)
1275 		return; /* need to fall back to scalar code */
1276 
1277 	/*
1278 	 * all 1's in first u64, all zeros in second is correct bit pattern to
1279 	 * start. Special casing == 64 easier than adapting complex loop logic.
1280 	 */
1281 	if (cq_depth == 64) {
1282 		qm_port->cq_rolling_mask = 0;
1283 		qm_port->cq_rolling_mask_2 = -1;
1284 		return;
1285 	}
1286 
1287 	for (i = 0; i < 64; i += (cq_depth * 2))
1288 		cq_build_mask |= ((1ULL << cq_depth) - 1) << (i + cq_depth);
1289 
1290 	qm_port->cq_rolling_mask = cq_build_mask;
1291 	qm_port->cq_rolling_mask_2 = cq_build_mask;
1292 }
1293 
1294 static int
1295 dlb2_hw_create_ldb_port(struct dlb2_eventdev *dlb2,
1296 			struct dlb2_eventdev_port *ev_port,
1297 			uint32_t dequeue_depth,
1298 			uint32_t enqueue_depth)
1299 {
1300 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
1301 	struct dlb2_create_ldb_port_args cfg = { {0} };
1302 	int ret;
1303 	struct dlb2_port *qm_port = NULL;
1304 	char mz_name[RTE_MEMZONE_NAMESIZE];
1305 	uint32_t qm_port_id;
1306 	uint16_t ldb_credit_high_watermark = 0;
1307 	uint16_t dir_credit_high_watermark = 0;
1308 	uint16_t credit_high_watermark = 0;
1309 
1310 	if (handle == NULL)
1311 		return -EINVAL;
1312 
1313 	if (dequeue_depth < DLB2_MIN_CQ_DEPTH) {
1314 		DLB2_LOG_ERR("dlb2: invalid enqueue_depth, must be at least %d\n",
1315 			     DLB2_MIN_CQ_DEPTH);
1316 		return -EINVAL;
1317 	}
1318 
1319 	if (enqueue_depth < DLB2_MIN_ENQUEUE_DEPTH) {
1320 		DLB2_LOG_ERR("dlb2: invalid enqueue_depth, must be at least %d\n",
1321 			     DLB2_MIN_ENQUEUE_DEPTH);
1322 		return -EINVAL;
1323 	}
1324 
1325 	rte_spinlock_lock(&handle->resource_lock);
1326 
1327 	/* We round up to the next power of 2 if necessary */
1328 	cfg.cq_depth = rte_align32pow2(dequeue_depth);
1329 	cfg.cq_depth_threshold = 1;
1330 
1331 	cfg.cq_history_list_size = DLB2_NUM_HIST_LIST_ENTRIES_PER_LDB_PORT;
1332 
1333 	if (handle->cos_id == DLB2_COS_DEFAULT)
1334 		cfg.cos_id = 0;
1335 	else
1336 		cfg.cos_id = handle->cos_id;
1337 
1338 	cfg.cos_strict = 0;
1339 
1340 	/* User controls the LDB high watermark via enqueue depth. The DIR high
1341 	 * watermark is equal, unless the directed credit pool is too small.
1342 	 */
1343 	if (dlb2->version == DLB2_HW_V2) {
1344 		ldb_credit_high_watermark = enqueue_depth;
1345 		/* If there are no directed ports, the kernel driver will
1346 		 * ignore this port's directed credit settings. Don't use
1347 		 * enqueue_depth if it would require more directed credits
1348 		 * than are available.
1349 		 */
1350 		dir_credit_high_watermark =
1351 			RTE_MIN(enqueue_depth,
1352 				handle->cfg.num_dir_credits / dlb2->num_ports);
1353 	} else
1354 		credit_high_watermark = enqueue_depth;
1355 
1356 	/* Per QM values */
1357 
1358 	ret = dlb2_iface_ldb_port_create(handle, &cfg,  dlb2->poll_mode);
1359 	if (ret < 0) {
1360 		DLB2_LOG_ERR("dlb2: dlb2_ldb_port_create error, ret=%d (driver status: %s)\n",
1361 			     ret, dlb2_error_strings[cfg.response.status]);
1362 		goto error_exit;
1363 	}
1364 
1365 	qm_port_id = cfg.response.id;
1366 
1367 	DLB2_LOG_DBG("dlb2: ev_port %d uses qm LB port %d <<<<<\n",
1368 		     ev_port->id, qm_port_id);
1369 
1370 	qm_port = &ev_port->qm_port;
1371 	qm_port->ev_port = ev_port; /* back ptr */
1372 	qm_port->dlb2 = dlb2; /* back ptr */
1373 	/*
1374 	 * Allocate and init local qe struct(s).
1375 	 * Note: MOVDIR64 requires the enqueue QE (qe4) to be aligned.
1376 	 */
1377 
1378 	snprintf(mz_name, sizeof(mz_name), "dlb2_ldb_port%d",
1379 		 ev_port->id);
1380 
1381 	ret = dlb2_init_qe_mem(qm_port, mz_name);
1382 	if (ret < 0) {
1383 		DLB2_LOG_ERR("dlb2: init_qe_mem failed, ret=%d\n", ret);
1384 		goto error_exit;
1385 	}
1386 
1387 	qm_port->id = qm_port_id;
1388 
1389 	if (dlb2->version == DLB2_HW_V2) {
1390 		qm_port->cached_ldb_credits = 0;
1391 		qm_port->cached_dir_credits = 0;
1392 	} else
1393 		qm_port->cached_credits = 0;
1394 
1395 	/* CQs with depth < 8 use an 8-entry queue, but withhold credits so
1396 	 * the effective depth is smaller.
1397 	 */
1398 	qm_port->cq_depth = cfg.cq_depth <= 8 ? 8 : cfg.cq_depth;
1399 	qm_port->cq_idx = 0;
1400 	qm_port->cq_idx_unmasked = 0;
1401 
1402 	if (dlb2->poll_mode == DLB2_CQ_POLL_MODE_SPARSE)
1403 		qm_port->cq_depth_mask = (qm_port->cq_depth * 4) - 1;
1404 	else
1405 		qm_port->cq_depth_mask = qm_port->cq_depth - 1;
1406 
1407 	qm_port->gen_bit_shift = __builtin_popcount(qm_port->cq_depth_mask);
1408 	/* starting value of gen bit - it toggles at wrap time */
1409 	qm_port->gen_bit = 1;
1410 
1411 	dlb2_hw_cq_bitmask_init(qm_port, qm_port->cq_depth);
1412 
1413 	qm_port->int_armed = false;
1414 
1415 	/* Save off for later use in info and lookup APIs. */
1416 	qm_port->qid_mappings = &dlb2->qm_ldb_to_ev_queue_id[0];
1417 
1418 	qm_port->dequeue_depth = dequeue_depth;
1419 	qm_port->token_pop_thresh = dequeue_depth;
1420 
1421 	/* The default enqueue functions do not include delayed-pop support for
1422 	 * performance reasons.
1423 	 */
1424 	if (qm_port->token_pop_mode == DELAYED_POP) {
1425 		dlb2->event_dev->enqueue = dlb2_event_enqueue_delayed;
1426 		dlb2->event_dev->enqueue_burst =
1427 			dlb2_event_enqueue_burst_delayed;
1428 		dlb2->event_dev->enqueue_new_burst =
1429 			dlb2_event_enqueue_new_burst_delayed;
1430 		dlb2->event_dev->enqueue_forward_burst =
1431 			dlb2_event_enqueue_forward_burst_delayed;
1432 	}
1433 
1434 	qm_port->owed_tokens = 0;
1435 	qm_port->issued_releases = 0;
1436 
1437 	/* Save config message too. */
1438 	rte_memcpy(&qm_port->cfg.ldb, &cfg, sizeof(qm_port->cfg.ldb));
1439 
1440 	/* update state */
1441 	qm_port->state = PORT_STARTED; /* enabled at create time */
1442 	qm_port->config_state = DLB2_CONFIGURED;
1443 
1444 	if (dlb2->version == DLB2_HW_V2) {
1445 		qm_port->dir_credits = dir_credit_high_watermark;
1446 		qm_port->ldb_credits = ldb_credit_high_watermark;
1447 		qm_port->credit_pool[DLB2_DIR_QUEUE] = &dlb2->dir_credit_pool;
1448 		qm_port->credit_pool[DLB2_LDB_QUEUE] = &dlb2->ldb_credit_pool;
1449 
1450 		DLB2_LOG_DBG("dlb2: created ldb port %d, depth = %d, ldb credits=%d, dir credits=%d\n",
1451 			     qm_port_id,
1452 			     dequeue_depth,
1453 			     qm_port->ldb_credits,
1454 			     qm_port->dir_credits);
1455 	} else {
1456 		qm_port->credits = credit_high_watermark;
1457 		qm_port->credit_pool[DLB2_COMBINED_POOL] = &dlb2->credit_pool;
1458 
1459 		DLB2_LOG_DBG("dlb2: created ldb port %d, depth = %d, credits=%d\n",
1460 			     qm_port_id,
1461 			     dequeue_depth,
1462 			     qm_port->credits);
1463 	}
1464 
1465 	qm_port->use_scalar = false;
1466 
1467 #if (!defined RTE_ARCH_X86_64)
1468 	qm_port->use_scalar = true;
1469 #else
1470 	if ((qm_port->cq_depth > 64) ||
1471 	    (!rte_is_power_of_2(qm_port->cq_depth)) ||
1472 	    (dlb2->vector_opts_enabled == false))
1473 		qm_port->use_scalar = true;
1474 #endif
1475 
1476 	rte_spinlock_unlock(&handle->resource_lock);
1477 
1478 	return 0;
1479 
1480 error_exit:
1481 
1482 	if (qm_port)
1483 		dlb2_free_qe_mem(qm_port);
1484 
1485 	rte_spinlock_unlock(&handle->resource_lock);
1486 
1487 	DLB2_LOG_ERR("dlb2: create ldb port failed!\n");
1488 
1489 	return ret;
1490 }
1491 
1492 static void
1493 dlb2_port_link_teardown(struct dlb2_eventdev *dlb2,
1494 			struct dlb2_eventdev_port *ev_port)
1495 {
1496 	struct dlb2_eventdev_queue *ev_queue;
1497 	int i;
1498 
1499 	for (i = 0; i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; i++) {
1500 		if (!ev_port->link[i].valid)
1501 			continue;
1502 
1503 		ev_queue = &dlb2->ev_queues[ev_port->link[i].queue_id];
1504 
1505 		ev_port->link[i].valid = false;
1506 		ev_port->num_links--;
1507 		ev_queue->num_links--;
1508 	}
1509 }
1510 
1511 static int
1512 dlb2_hw_create_dir_port(struct dlb2_eventdev *dlb2,
1513 			struct dlb2_eventdev_port *ev_port,
1514 			uint32_t dequeue_depth,
1515 			uint32_t enqueue_depth)
1516 {
1517 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
1518 	struct dlb2_create_dir_port_args cfg = { {0} };
1519 	int ret;
1520 	struct dlb2_port *qm_port = NULL;
1521 	char mz_name[RTE_MEMZONE_NAMESIZE];
1522 	uint32_t qm_port_id;
1523 	uint16_t ldb_credit_high_watermark = 0;
1524 	uint16_t dir_credit_high_watermark = 0;
1525 	uint16_t credit_high_watermark = 0;
1526 
1527 	if (dlb2 == NULL || handle == NULL)
1528 		return -EINVAL;
1529 
1530 	if (dequeue_depth < DLB2_MIN_CQ_DEPTH) {
1531 		DLB2_LOG_ERR("dlb2: invalid dequeue_depth, must be %d-%d\n",
1532 			     DLB2_MIN_CQ_DEPTH, DLB2_MAX_INPUT_QUEUE_DEPTH);
1533 		return -EINVAL;
1534 	}
1535 
1536 	if (enqueue_depth < DLB2_MIN_ENQUEUE_DEPTH) {
1537 		DLB2_LOG_ERR("dlb2: invalid enqueue_depth, must be at least %d\n",
1538 			     DLB2_MIN_ENQUEUE_DEPTH);
1539 		return -EINVAL;
1540 	}
1541 
1542 	rte_spinlock_lock(&handle->resource_lock);
1543 
1544 	/* Directed queues are configured at link time. */
1545 	cfg.queue_id = -1;
1546 
1547 	/* We round up to the next power of 2 if necessary */
1548 	cfg.cq_depth = rte_align32pow2(dequeue_depth);
1549 	cfg.cq_depth_threshold = 1;
1550 
1551 	/* User controls the LDB high watermark via enqueue depth. The DIR high
1552 	 * watermark is equal, unless the directed credit pool is too small.
1553 	 */
1554 	if (dlb2->version == DLB2_HW_V2) {
1555 		ldb_credit_high_watermark = enqueue_depth;
1556 		/* Don't use enqueue_depth if it would require more directed
1557 		 * credits than are available.
1558 		 */
1559 		dir_credit_high_watermark =
1560 			RTE_MIN(enqueue_depth,
1561 				handle->cfg.num_dir_credits / dlb2->num_ports);
1562 	} else
1563 		credit_high_watermark = enqueue_depth;
1564 
1565 	/* Per QM values */
1566 
1567 	ret = dlb2_iface_dir_port_create(handle, &cfg,  dlb2->poll_mode);
1568 	if (ret < 0) {
1569 		DLB2_LOG_ERR("dlb2: dlb2_dir_port_create error, ret=%d (driver status: %s)\n",
1570 			     ret, dlb2_error_strings[cfg.response.status]);
1571 		goto error_exit;
1572 	}
1573 
1574 	qm_port_id = cfg.response.id;
1575 
1576 	DLB2_LOG_DBG("dlb2: ev_port %d uses qm DIR port %d <<<<<\n",
1577 		     ev_port->id, qm_port_id);
1578 
1579 	qm_port = &ev_port->qm_port;
1580 	qm_port->ev_port = ev_port; /* back ptr */
1581 	qm_port->dlb2 = dlb2;  /* back ptr */
1582 
1583 	/*
1584 	 * Init local qe struct(s).
1585 	 * Note: MOVDIR64 requires the enqueue QE to be aligned
1586 	 */
1587 
1588 	snprintf(mz_name, sizeof(mz_name), "dlb2_dir_port%d",
1589 		 ev_port->id);
1590 
1591 	ret = dlb2_init_qe_mem(qm_port, mz_name);
1592 
1593 	if (ret < 0) {
1594 		DLB2_LOG_ERR("dlb2: init_qe_mem failed, ret=%d\n", ret);
1595 		goto error_exit;
1596 	}
1597 
1598 	qm_port->id = qm_port_id;
1599 
1600 	if (dlb2->version == DLB2_HW_V2) {
1601 		qm_port->cached_ldb_credits = 0;
1602 		qm_port->cached_dir_credits = 0;
1603 	} else
1604 		qm_port->cached_credits = 0;
1605 
1606 	/* CQs with depth < 8 use an 8-entry queue, but withhold credits so
1607 	 * the effective depth is smaller.
1608 	 */
1609 	qm_port->cq_depth = cfg.cq_depth <= 8 ? 8 : cfg.cq_depth;
1610 	qm_port->cq_idx = 0;
1611 	qm_port->cq_idx_unmasked = 0;
1612 
1613 	if (dlb2->poll_mode == DLB2_CQ_POLL_MODE_SPARSE)
1614 		qm_port->cq_depth_mask = (cfg.cq_depth * 4) - 1;
1615 	else
1616 		qm_port->cq_depth_mask = cfg.cq_depth - 1;
1617 
1618 	qm_port->gen_bit_shift = __builtin_popcount(qm_port->cq_depth_mask);
1619 	/* starting value of gen bit - it toggles at wrap time */
1620 	qm_port->gen_bit = 1;
1621 	dlb2_hw_cq_bitmask_init(qm_port, qm_port->cq_depth);
1622 
1623 	qm_port->int_armed = false;
1624 
1625 	/* Save off for later use in info and lookup APIs. */
1626 	qm_port->qid_mappings = &dlb2->qm_dir_to_ev_queue_id[0];
1627 
1628 	qm_port->dequeue_depth = dequeue_depth;
1629 
1630 	/* Directed ports are auto-pop, by default. */
1631 	qm_port->token_pop_mode = AUTO_POP;
1632 	qm_port->owed_tokens = 0;
1633 	qm_port->issued_releases = 0;
1634 
1635 	/* Save config message too. */
1636 	rte_memcpy(&qm_port->cfg.dir, &cfg, sizeof(qm_port->cfg.dir));
1637 
1638 	/* update state */
1639 	qm_port->state = PORT_STARTED; /* enabled at create time */
1640 	qm_port->config_state = DLB2_CONFIGURED;
1641 
1642 	if (dlb2->version == DLB2_HW_V2) {
1643 		qm_port->dir_credits = dir_credit_high_watermark;
1644 		qm_port->ldb_credits = ldb_credit_high_watermark;
1645 		qm_port->credit_pool[DLB2_DIR_QUEUE] = &dlb2->dir_credit_pool;
1646 		qm_port->credit_pool[DLB2_LDB_QUEUE] = &dlb2->ldb_credit_pool;
1647 
1648 		DLB2_LOG_DBG("dlb2: created dir port %d, depth = %d cr=%d,%d\n",
1649 			     qm_port_id,
1650 			     dequeue_depth,
1651 			     dir_credit_high_watermark,
1652 			     ldb_credit_high_watermark);
1653 	} else {
1654 		qm_port->credits = credit_high_watermark;
1655 		qm_port->credit_pool[DLB2_COMBINED_POOL] = &dlb2->credit_pool;
1656 
1657 		DLB2_LOG_DBG("dlb2: created dir port %d, depth = %d cr=%d\n",
1658 			     qm_port_id,
1659 			     dequeue_depth,
1660 			     credit_high_watermark);
1661 	}
1662 
1663 #if (!defined RTE_ARCH_X86_64)
1664 	qm_port->use_scalar = true;
1665 #else
1666 	if ((qm_port->cq_depth > 64) ||
1667 	    (!rte_is_power_of_2(qm_port->cq_depth)) ||
1668 	    (dlb2->vector_opts_enabled == false))
1669 		qm_port->use_scalar = true;
1670 #endif
1671 
1672 	rte_spinlock_unlock(&handle->resource_lock);
1673 
1674 	return 0;
1675 
1676 error_exit:
1677 
1678 	if (qm_port)
1679 		dlb2_free_qe_mem(qm_port);
1680 
1681 	rte_spinlock_unlock(&handle->resource_lock);
1682 
1683 	DLB2_LOG_ERR("dlb2: create dir port failed!\n");
1684 
1685 	return ret;
1686 }
1687 
1688 static int
1689 dlb2_eventdev_port_setup(struct rte_eventdev *dev,
1690 			 uint8_t ev_port_id,
1691 			 const struct rte_event_port_conf *port_conf)
1692 {
1693 	struct dlb2_eventdev *dlb2;
1694 	struct dlb2_eventdev_port *ev_port;
1695 	int ret;
1696 
1697 	if (dev == NULL || port_conf == NULL) {
1698 		DLB2_LOG_ERR("Null parameter\n");
1699 		return -EINVAL;
1700 	}
1701 
1702 	dlb2 = dlb2_pmd_priv(dev);
1703 
1704 	if (ev_port_id >= DLB2_MAX_NUM_PORTS(dlb2->version))
1705 		return -EINVAL;
1706 
1707 	if (port_conf->dequeue_depth >
1708 		evdev_dlb2_default_info.max_event_port_dequeue_depth ||
1709 	    port_conf->enqueue_depth >
1710 		evdev_dlb2_default_info.max_event_port_enqueue_depth)
1711 		return -EINVAL;
1712 
1713 	ev_port = &dlb2->ev_ports[ev_port_id];
1714 	/* configured? */
1715 	if (ev_port->setup_done) {
1716 		DLB2_LOG_ERR("evport %d is already configured\n", ev_port_id);
1717 		return -EINVAL;
1718 	}
1719 
1720 	ev_port->qm_port.is_directed = port_conf->event_port_cfg &
1721 		RTE_EVENT_PORT_CFG_SINGLE_LINK;
1722 
1723 	if (!ev_port->qm_port.is_directed) {
1724 		ret = dlb2_hw_create_ldb_port(dlb2,
1725 					      ev_port,
1726 					      port_conf->dequeue_depth,
1727 					      port_conf->enqueue_depth);
1728 		if (ret < 0) {
1729 			DLB2_LOG_ERR("Failed to create the lB port ve portId=%d\n",
1730 				     ev_port_id);
1731 
1732 			return ret;
1733 		}
1734 	} else {
1735 		ret = dlb2_hw_create_dir_port(dlb2,
1736 					      ev_port,
1737 					      port_conf->dequeue_depth,
1738 					      port_conf->enqueue_depth);
1739 		if (ret < 0) {
1740 			DLB2_LOG_ERR("Failed to create the DIR port\n");
1741 			return ret;
1742 		}
1743 	}
1744 
1745 	/* Save off port config for reconfig */
1746 	ev_port->conf = *port_conf;
1747 
1748 	ev_port->id = ev_port_id;
1749 	ev_port->enq_configured = true;
1750 	ev_port->setup_done = true;
1751 	ev_port->inflight_max = port_conf->new_event_threshold;
1752 	ev_port->implicit_release = !(port_conf->event_port_cfg &
1753 		  RTE_EVENT_PORT_CFG_DISABLE_IMPL_REL);
1754 	ev_port->outstanding_releases = 0;
1755 	ev_port->inflight_credits = 0;
1756 	ev_port->credit_update_quanta = dlb2->sw_credit_quanta;
1757 	ev_port->dlb2 = dlb2; /* reverse link */
1758 
1759 	/* Tear down pre-existing port->queue links */
1760 	if (dlb2->run_state == DLB2_RUN_STATE_STOPPED)
1761 		dlb2_port_link_teardown(dlb2, &dlb2->ev_ports[ev_port_id]);
1762 
1763 	dev->data->ports[ev_port_id] = &dlb2->ev_ports[ev_port_id];
1764 
1765 	return 0;
1766 }
1767 
1768 static int16_t
1769 dlb2_hw_map_ldb_qid_to_port(struct dlb2_hw_dev *handle,
1770 			    uint32_t qm_port_id,
1771 			    uint16_t qm_qid,
1772 			    uint8_t priority)
1773 {
1774 	struct dlb2_map_qid_args cfg;
1775 	int32_t ret;
1776 
1777 	if (handle == NULL)
1778 		return -EINVAL;
1779 
1780 	/* Build message */
1781 	cfg.port_id = qm_port_id;
1782 	cfg.qid = qm_qid;
1783 	cfg.priority = EV_TO_DLB2_PRIO(priority);
1784 
1785 	ret = dlb2_iface_map_qid(handle, &cfg);
1786 	if (ret < 0) {
1787 		DLB2_LOG_ERR("dlb2: map qid error, ret=%d (driver status: %s)\n",
1788 			     ret, dlb2_error_strings[cfg.response.status]);
1789 		DLB2_LOG_ERR("dlb2: grp=%d, qm_port=%d, qm_qid=%d prio=%d\n",
1790 			     handle->domain_id, cfg.port_id,
1791 			     cfg.qid,
1792 			     cfg.priority);
1793 	} else {
1794 		DLB2_LOG_DBG("dlb2: mapped queue %d to qm_port %d\n",
1795 			     qm_qid, qm_port_id);
1796 	}
1797 
1798 	return ret;
1799 }
1800 
1801 static int
1802 dlb2_event_queue_join_ldb(struct dlb2_eventdev *dlb2,
1803 			  struct dlb2_eventdev_port *ev_port,
1804 			  struct dlb2_eventdev_queue *ev_queue,
1805 			  uint8_t priority)
1806 {
1807 	int first_avail = -1;
1808 	int ret, i;
1809 
1810 	for (i = 0; i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; i++) {
1811 		if (ev_port->link[i].valid) {
1812 			if (ev_port->link[i].queue_id == ev_queue->id &&
1813 			    ev_port->link[i].priority == priority) {
1814 				if (ev_port->link[i].mapped)
1815 					return 0; /* already mapped */
1816 				first_avail = i;
1817 			}
1818 		} else if (first_avail == -1)
1819 			first_avail = i;
1820 	}
1821 	if (first_avail == -1) {
1822 		DLB2_LOG_ERR("dlb2: qm_port %d has no available QID slots.\n",
1823 			     ev_port->qm_port.id);
1824 		return -EINVAL;
1825 	}
1826 
1827 	ret = dlb2_hw_map_ldb_qid_to_port(&dlb2->qm_instance,
1828 					  ev_port->qm_port.id,
1829 					  ev_queue->qm_queue.id,
1830 					  priority);
1831 
1832 	if (!ret)
1833 		ev_port->link[first_avail].mapped = true;
1834 
1835 	return ret;
1836 }
1837 
1838 static int32_t
1839 dlb2_hw_create_dir_queue(struct dlb2_eventdev *dlb2,
1840 			 struct dlb2_eventdev_queue *ev_queue,
1841 			 int32_t qm_port_id)
1842 {
1843 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
1844 	struct dlb2_create_dir_queue_args cfg;
1845 	int32_t ret;
1846 
1847 	/* The directed port is always configured before its queue */
1848 	cfg.port_id = qm_port_id;
1849 
1850 	if (ev_queue->depth_threshold == 0) {
1851 		cfg.depth_threshold = dlb2->default_depth_thresh;
1852 		ev_queue->depth_threshold =
1853 			dlb2->default_depth_thresh;
1854 	} else
1855 		cfg.depth_threshold = ev_queue->depth_threshold;
1856 
1857 	ret = dlb2_iface_dir_queue_create(handle, &cfg);
1858 	if (ret < 0) {
1859 		DLB2_LOG_ERR("dlb2: create DIR event queue error, ret=%d (driver status: %s)\n",
1860 			     ret, dlb2_error_strings[cfg.response.status]);
1861 		return -EINVAL;
1862 	}
1863 
1864 	return cfg.response.id;
1865 }
1866 
1867 static int
1868 dlb2_eventdev_dir_queue_setup(struct dlb2_eventdev *dlb2,
1869 			      struct dlb2_eventdev_queue *ev_queue,
1870 			      struct dlb2_eventdev_port *ev_port)
1871 {
1872 	int32_t qm_qid;
1873 
1874 	qm_qid = dlb2_hw_create_dir_queue(dlb2, ev_queue, ev_port->qm_port.id);
1875 
1876 	if (qm_qid < 0) {
1877 		DLB2_LOG_ERR("Failed to create the DIR queue\n");
1878 		return qm_qid;
1879 	}
1880 
1881 	dlb2->qm_dir_to_ev_queue_id[qm_qid] = ev_queue->id;
1882 
1883 	ev_queue->qm_queue.id = qm_qid;
1884 
1885 	return 0;
1886 }
1887 
1888 static int
1889 dlb2_do_port_link(struct rte_eventdev *dev,
1890 		  struct dlb2_eventdev_queue *ev_queue,
1891 		  struct dlb2_eventdev_port *ev_port,
1892 		  uint8_t prio)
1893 {
1894 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
1895 	int err;
1896 
1897 	/* Don't link until start time. */
1898 	if (dlb2->run_state == DLB2_RUN_STATE_STOPPED)
1899 		return 0;
1900 
1901 	if (ev_queue->qm_queue.is_directed)
1902 		err = dlb2_eventdev_dir_queue_setup(dlb2, ev_queue, ev_port);
1903 	else
1904 		err = dlb2_event_queue_join_ldb(dlb2, ev_port, ev_queue, prio);
1905 
1906 	if (err) {
1907 		DLB2_LOG_ERR("port link failure for %s ev_q %d, ev_port %d\n",
1908 			     ev_queue->qm_queue.is_directed ? "DIR" : "LDB",
1909 			     ev_queue->id, ev_port->id);
1910 
1911 		rte_errno = err;
1912 		return -1;
1913 	}
1914 
1915 	return 0;
1916 }
1917 
1918 static int
1919 dlb2_validate_port_link(struct dlb2_eventdev_port *ev_port,
1920 			uint8_t queue_id,
1921 			bool link_exists,
1922 			int index)
1923 {
1924 	struct dlb2_eventdev *dlb2 = ev_port->dlb2;
1925 	struct dlb2_eventdev_queue *ev_queue;
1926 	bool port_is_dir, queue_is_dir;
1927 
1928 	if (queue_id > dlb2->num_queues) {
1929 		rte_errno = -EINVAL;
1930 		return -1;
1931 	}
1932 
1933 	ev_queue = &dlb2->ev_queues[queue_id];
1934 
1935 	if (!ev_queue->setup_done &&
1936 	    ev_queue->qm_queue.config_state != DLB2_PREV_CONFIGURED) {
1937 		rte_errno = -EINVAL;
1938 		return -1;
1939 	}
1940 
1941 	port_is_dir = ev_port->qm_port.is_directed;
1942 	queue_is_dir = ev_queue->qm_queue.is_directed;
1943 
1944 	if (port_is_dir != queue_is_dir) {
1945 		DLB2_LOG_ERR("%s queue %u can't link to %s port %u\n",
1946 			     queue_is_dir ? "DIR" : "LDB", ev_queue->id,
1947 			     port_is_dir ? "DIR" : "LDB", ev_port->id);
1948 
1949 		rte_errno = -EINVAL;
1950 		return -1;
1951 	}
1952 
1953 	/* Check if there is space for the requested link */
1954 	if (!link_exists && index == -1) {
1955 		DLB2_LOG_ERR("no space for new link\n");
1956 		rte_errno = -ENOSPC;
1957 		return -1;
1958 	}
1959 
1960 	/* Check if the directed port is already linked */
1961 	if (ev_port->qm_port.is_directed && ev_port->num_links > 0 &&
1962 	    !link_exists) {
1963 		DLB2_LOG_ERR("Can't link DIR port %d to >1 queues\n",
1964 			     ev_port->id);
1965 		rte_errno = -EINVAL;
1966 		return -1;
1967 	}
1968 
1969 	/* Check if the directed queue is already linked */
1970 	if (ev_queue->qm_queue.is_directed && ev_queue->num_links > 0 &&
1971 	    !link_exists) {
1972 		DLB2_LOG_ERR("Can't link DIR queue %d to >1 ports\n",
1973 			     ev_queue->id);
1974 		rte_errno = -EINVAL;
1975 		return -1;
1976 	}
1977 
1978 	return 0;
1979 }
1980 
1981 static int
1982 dlb2_eventdev_port_link(struct rte_eventdev *dev, void *event_port,
1983 			const uint8_t queues[], const uint8_t priorities[],
1984 			uint16_t nb_links)
1985 
1986 {
1987 	struct dlb2_eventdev_port *ev_port = event_port;
1988 	struct dlb2_eventdev *dlb2;
1989 	int i, j;
1990 
1991 	RTE_SET_USED(dev);
1992 
1993 	if (ev_port == NULL) {
1994 		DLB2_LOG_ERR("dlb2: evport not setup\n");
1995 		rte_errno = -EINVAL;
1996 		return 0;
1997 	}
1998 
1999 	if (!ev_port->setup_done &&
2000 	    ev_port->qm_port.config_state != DLB2_PREV_CONFIGURED) {
2001 		DLB2_LOG_ERR("dlb2: evport not setup\n");
2002 		rte_errno = -EINVAL;
2003 		return 0;
2004 	}
2005 
2006 	/* Note: rte_event_port_link() ensures the PMD won't receive a NULL
2007 	 * queues pointer.
2008 	 */
2009 	if (nb_links == 0) {
2010 		DLB2_LOG_DBG("dlb2: nb_links is 0\n");
2011 		return 0; /* Ignore and return success */
2012 	}
2013 
2014 	dlb2 = ev_port->dlb2;
2015 
2016 	DLB2_LOG_DBG("Linking %u queues to %s port %d\n",
2017 		     nb_links,
2018 		     ev_port->qm_port.is_directed ? "DIR" : "LDB",
2019 		     ev_port->id);
2020 
2021 	for (i = 0; i < nb_links; i++) {
2022 		struct dlb2_eventdev_queue *ev_queue;
2023 		uint8_t queue_id, prio;
2024 		bool found = false;
2025 		int index = -1;
2026 
2027 		queue_id = queues[i];
2028 		prio = priorities[i];
2029 
2030 		/* Check if the link already exists. */
2031 		for (j = 0; j < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; j++)
2032 			if (ev_port->link[j].valid) {
2033 				if (ev_port->link[j].queue_id == queue_id) {
2034 					found = true;
2035 					index = j;
2036 					break;
2037 				}
2038 			} else if (index == -1) {
2039 				index = j;
2040 			}
2041 
2042 		/* could not link */
2043 		if (index == -1)
2044 			break;
2045 
2046 		/* Check if already linked at the requested priority */
2047 		if (found && ev_port->link[j].priority == prio)
2048 			continue;
2049 
2050 		if (dlb2_validate_port_link(ev_port, queue_id, found, index))
2051 			break; /* return index of offending queue */
2052 
2053 		ev_queue = &dlb2->ev_queues[queue_id];
2054 
2055 		if (dlb2_do_port_link(dev, ev_queue, ev_port, prio))
2056 			break; /* return index of offending queue */
2057 
2058 		ev_queue->num_links++;
2059 
2060 		ev_port->link[index].queue_id = queue_id;
2061 		ev_port->link[index].priority = prio;
2062 		ev_port->link[index].valid = true;
2063 		/* Entry already exists?  If so, then must be prio change */
2064 		if (!found)
2065 			ev_port->num_links++;
2066 	}
2067 	return i;
2068 }
2069 
2070 static int16_t
2071 dlb2_hw_unmap_ldb_qid_from_port(struct dlb2_hw_dev *handle,
2072 				uint32_t qm_port_id,
2073 				uint16_t qm_qid)
2074 {
2075 	struct dlb2_unmap_qid_args cfg;
2076 	int32_t ret;
2077 
2078 	if (handle == NULL)
2079 		return -EINVAL;
2080 
2081 	cfg.port_id = qm_port_id;
2082 	cfg.qid = qm_qid;
2083 
2084 	ret = dlb2_iface_unmap_qid(handle, &cfg);
2085 	if (ret < 0)
2086 		DLB2_LOG_ERR("dlb2: unmap qid error, ret=%d (driver status: %s)\n",
2087 			     ret, dlb2_error_strings[cfg.response.status]);
2088 
2089 	return ret;
2090 }
2091 
2092 static int
2093 dlb2_event_queue_detach_ldb(struct dlb2_eventdev *dlb2,
2094 			    struct dlb2_eventdev_port *ev_port,
2095 			    struct dlb2_eventdev_queue *ev_queue)
2096 {
2097 	int ret, i;
2098 
2099 	/* Don't unlink until start time. */
2100 	if (dlb2->run_state == DLB2_RUN_STATE_STOPPED)
2101 		return 0;
2102 
2103 	for (i = 0; i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; i++) {
2104 		if (ev_port->link[i].valid &&
2105 		    ev_port->link[i].queue_id == ev_queue->id)
2106 			break; /* found */
2107 	}
2108 
2109 	/* This is expected with eventdev API!
2110 	 * It blindly attemmpts to unmap all queues.
2111 	 */
2112 	if (i == DLB2_MAX_NUM_QIDS_PER_LDB_CQ) {
2113 		DLB2_LOG_DBG("dlb2: ignoring LB QID %d not mapped for qm_port %d.\n",
2114 			     ev_queue->qm_queue.id,
2115 			     ev_port->qm_port.id);
2116 		return 0;
2117 	}
2118 
2119 	ret = dlb2_hw_unmap_ldb_qid_from_port(&dlb2->qm_instance,
2120 					      ev_port->qm_port.id,
2121 					      ev_queue->qm_queue.id);
2122 	if (!ret)
2123 		ev_port->link[i].mapped = false;
2124 
2125 	return ret;
2126 }
2127 
2128 static int
2129 dlb2_eventdev_port_unlink(struct rte_eventdev *dev, void *event_port,
2130 			  uint8_t queues[], uint16_t nb_unlinks)
2131 {
2132 	struct dlb2_eventdev_port *ev_port = event_port;
2133 	struct dlb2_eventdev *dlb2;
2134 	int i;
2135 
2136 	RTE_SET_USED(dev);
2137 
2138 	if (!ev_port->setup_done) {
2139 		DLB2_LOG_ERR("dlb2: evport %d is not configured\n",
2140 			     ev_port->id);
2141 		rte_errno = -EINVAL;
2142 		return 0;
2143 	}
2144 
2145 	if (queues == NULL || nb_unlinks == 0) {
2146 		DLB2_LOG_DBG("dlb2: queues is NULL or nb_unlinks is 0\n");
2147 		return 0; /* Ignore and return success */
2148 	}
2149 
2150 	if (ev_port->qm_port.is_directed) {
2151 		DLB2_LOG_DBG("dlb2: ignore unlink from dir port %d\n",
2152 			     ev_port->id);
2153 		rte_errno = 0;
2154 		return nb_unlinks; /* as if success */
2155 	}
2156 
2157 	dlb2 = ev_port->dlb2;
2158 
2159 	for (i = 0; i < nb_unlinks; i++) {
2160 		struct dlb2_eventdev_queue *ev_queue;
2161 		int ret, j;
2162 
2163 		if (queues[i] >= dlb2->num_queues) {
2164 			DLB2_LOG_ERR("dlb2: invalid queue id %d\n", queues[i]);
2165 			rte_errno = -EINVAL;
2166 			return i; /* return index of offending queue */
2167 		}
2168 
2169 		ev_queue = &dlb2->ev_queues[queues[i]];
2170 
2171 		/* Does a link exist? */
2172 		for (j = 0; j < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; j++)
2173 			if (ev_port->link[j].queue_id == queues[i] &&
2174 			    ev_port->link[j].valid)
2175 				break;
2176 
2177 		if (j == DLB2_MAX_NUM_QIDS_PER_LDB_CQ)
2178 			continue;
2179 
2180 		ret = dlb2_event_queue_detach_ldb(dlb2, ev_port, ev_queue);
2181 		if (ret) {
2182 			DLB2_LOG_ERR("unlink err=%d for port %d queue %d\n",
2183 				     ret, ev_port->id, queues[i]);
2184 			rte_errno = -ENOENT;
2185 			return i; /* return index of offending queue */
2186 		}
2187 
2188 		ev_port->link[j].valid = false;
2189 		ev_port->num_links--;
2190 		ev_queue->num_links--;
2191 	}
2192 
2193 	return nb_unlinks;
2194 }
2195 
2196 static int
2197 dlb2_eventdev_port_unlinks_in_progress(struct rte_eventdev *dev,
2198 				       void *event_port)
2199 {
2200 	struct dlb2_eventdev_port *ev_port = event_port;
2201 	struct dlb2_eventdev *dlb2;
2202 	struct dlb2_hw_dev *handle;
2203 	struct dlb2_pending_port_unmaps_args cfg;
2204 	int ret;
2205 
2206 	RTE_SET_USED(dev);
2207 
2208 	if (!ev_port->setup_done) {
2209 		DLB2_LOG_ERR("dlb2: evport %d is not configured\n",
2210 			     ev_port->id);
2211 		rte_errno = -EINVAL;
2212 		return 0;
2213 	}
2214 
2215 	cfg.port_id = ev_port->qm_port.id;
2216 	dlb2 = ev_port->dlb2;
2217 	handle = &dlb2->qm_instance;
2218 	ret = dlb2_iface_pending_port_unmaps(handle, &cfg);
2219 
2220 	if (ret < 0) {
2221 		DLB2_LOG_ERR("dlb2: num_unlinks_in_progress ret=%d (driver status: %s)\n",
2222 			     ret, dlb2_error_strings[cfg.response.status]);
2223 		return ret;
2224 	}
2225 
2226 	return cfg.response.id;
2227 }
2228 
2229 static int
2230 dlb2_eventdev_reapply_configuration(struct rte_eventdev *dev)
2231 {
2232 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
2233 	int ret, i;
2234 
2235 	/* If an event queue or port was previously configured, but hasn't been
2236 	 * reconfigured, reapply its original configuration.
2237 	 */
2238 	for (i = 0; i < dlb2->num_queues; i++) {
2239 		struct dlb2_eventdev_queue *ev_queue;
2240 
2241 		ev_queue = &dlb2->ev_queues[i];
2242 
2243 		if (ev_queue->qm_queue.config_state != DLB2_PREV_CONFIGURED)
2244 			continue;
2245 
2246 		ret = dlb2_eventdev_queue_setup(dev, i, &ev_queue->conf);
2247 		if (ret < 0) {
2248 			DLB2_LOG_ERR("dlb2: failed to reconfigure queue %d", i);
2249 			return ret;
2250 		}
2251 	}
2252 
2253 	for (i = 0; i < dlb2->num_ports; i++) {
2254 		struct dlb2_eventdev_port *ev_port = &dlb2->ev_ports[i];
2255 
2256 		if (ev_port->qm_port.config_state != DLB2_PREV_CONFIGURED)
2257 			continue;
2258 
2259 		ret = dlb2_eventdev_port_setup(dev, i, &ev_port->conf);
2260 		if (ret < 0) {
2261 			DLB2_LOG_ERR("dlb2: failed to reconfigure ev_port %d",
2262 				     i);
2263 			return ret;
2264 		}
2265 	}
2266 
2267 	return 0;
2268 }
2269 
2270 static int
2271 dlb2_eventdev_apply_port_links(struct rte_eventdev *dev)
2272 {
2273 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
2274 	int i;
2275 
2276 	/* Perform requested port->queue links */
2277 	for (i = 0; i < dlb2->num_ports; i++) {
2278 		struct dlb2_eventdev_port *ev_port = &dlb2->ev_ports[i];
2279 		int j;
2280 
2281 		for (j = 0; j < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; j++) {
2282 			struct dlb2_eventdev_queue *ev_queue;
2283 			uint8_t prio, queue_id;
2284 
2285 			if (!ev_port->link[j].valid)
2286 				continue;
2287 
2288 			prio = ev_port->link[j].priority;
2289 			queue_id = ev_port->link[j].queue_id;
2290 
2291 			if (dlb2_validate_port_link(ev_port, queue_id, true, j))
2292 				return -EINVAL;
2293 
2294 			ev_queue = &dlb2->ev_queues[queue_id];
2295 
2296 			if (dlb2_do_port_link(dev, ev_queue, ev_port, prio))
2297 				return -EINVAL;
2298 		}
2299 	}
2300 
2301 	return 0;
2302 }
2303 
2304 static int
2305 dlb2_eventdev_start(struct rte_eventdev *dev)
2306 {
2307 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
2308 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
2309 	struct dlb2_start_domain_args cfg;
2310 	int ret, i;
2311 
2312 	rte_spinlock_lock(&dlb2->qm_instance.resource_lock);
2313 	if (dlb2->run_state != DLB2_RUN_STATE_STOPPED) {
2314 		DLB2_LOG_ERR("bad state %d for dev_start\n",
2315 			     (int)dlb2->run_state);
2316 		rte_spinlock_unlock(&dlb2->qm_instance.resource_lock);
2317 		return -EINVAL;
2318 	}
2319 	dlb2->run_state = DLB2_RUN_STATE_STARTING;
2320 	rte_spinlock_unlock(&dlb2->qm_instance.resource_lock);
2321 
2322 	/* If the device was configured more than once, some event ports and/or
2323 	 * queues may need to be reconfigured.
2324 	 */
2325 	ret = dlb2_eventdev_reapply_configuration(dev);
2326 	if (ret)
2327 		return ret;
2328 
2329 	/* The DLB PMD delays port links until the device is started. */
2330 	ret = dlb2_eventdev_apply_port_links(dev);
2331 	if (ret)
2332 		return ret;
2333 
2334 	for (i = 0; i < dlb2->num_ports; i++) {
2335 		if (!dlb2->ev_ports[i].setup_done) {
2336 			DLB2_LOG_ERR("dlb2: port %d not setup", i);
2337 			return -ESTALE;
2338 		}
2339 	}
2340 
2341 	for (i = 0; i < dlb2->num_queues; i++) {
2342 		if (dlb2->ev_queues[i].num_links == 0) {
2343 			DLB2_LOG_ERR("dlb2: queue %d is not linked", i);
2344 			return -ENOLINK;
2345 		}
2346 	}
2347 
2348 	ret = dlb2_iface_sched_domain_start(handle, &cfg);
2349 	if (ret < 0) {
2350 		DLB2_LOG_ERR("dlb2: sched_domain_start ret=%d (driver status: %s)\n",
2351 			     ret, dlb2_error_strings[cfg.response.status]);
2352 		return ret;
2353 	}
2354 
2355 	dlb2->run_state = DLB2_RUN_STATE_STARTED;
2356 	DLB2_LOG_DBG("dlb2: sched_domain_start completed OK\n");
2357 
2358 	return 0;
2359 }
2360 
2361 static uint8_t cmd_byte_map[DLB2_NUM_PORT_TYPES][DLB2_NUM_HW_SCHED_TYPES] = {
2362 	{
2363 		/* Load-balanced cmd bytes */
2364 		[RTE_EVENT_OP_NEW] = DLB2_NEW_CMD_BYTE,
2365 		[RTE_EVENT_OP_FORWARD] = DLB2_FWD_CMD_BYTE,
2366 		[RTE_EVENT_OP_RELEASE] = DLB2_COMP_CMD_BYTE,
2367 	},
2368 	{
2369 		/* Directed cmd bytes */
2370 		[RTE_EVENT_OP_NEW] = DLB2_NEW_CMD_BYTE,
2371 		[RTE_EVENT_OP_FORWARD] = DLB2_NEW_CMD_BYTE,
2372 		[RTE_EVENT_OP_RELEASE] = DLB2_NOOP_CMD_BYTE,
2373 	},
2374 };
2375 
2376 static inline uint32_t
2377 dlb2_port_credits_get(struct dlb2_port *qm_port,
2378 		      enum dlb2_hw_queue_types type)
2379 {
2380 	uint32_t credits = *qm_port->credit_pool[type];
2381 	uint32_t batch_size = DLB2_SW_CREDIT_BATCH_SZ;
2382 
2383 	if (unlikely(credits < batch_size))
2384 		batch_size = credits;
2385 
2386 	if (likely(credits &&
2387 		   __atomic_compare_exchange_n(
2388 			qm_port->credit_pool[type],
2389 			&credits, credits - batch_size, false,
2390 			__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)))
2391 		return batch_size;
2392 	else
2393 		return 0;
2394 }
2395 
2396 static inline void
2397 dlb2_replenish_sw_credits(struct dlb2_eventdev *dlb2,
2398 			  struct dlb2_eventdev_port *ev_port)
2399 {
2400 	uint16_t quanta = ev_port->credit_update_quanta;
2401 
2402 	if (ev_port->inflight_credits >= quanta * 2) {
2403 		/* Replenish credits, saving one quanta for enqueues */
2404 		uint16_t val = ev_port->inflight_credits - quanta;
2405 
2406 		__atomic_fetch_sub(&dlb2->inflights, val, __ATOMIC_SEQ_CST);
2407 		ev_port->inflight_credits -= val;
2408 	}
2409 }
2410 
2411 static inline int
2412 dlb2_check_enqueue_sw_credits(struct dlb2_eventdev *dlb2,
2413 			      struct dlb2_eventdev_port *ev_port)
2414 {
2415 	uint32_t sw_inflights = __atomic_load_n(&dlb2->inflights,
2416 						__ATOMIC_SEQ_CST);
2417 	const int num = 1;
2418 
2419 	if (unlikely(ev_port->inflight_max < sw_inflights)) {
2420 		DLB2_INC_STAT(ev_port->stats.traffic.tx_nospc_inflight_max, 1);
2421 		rte_errno = -ENOSPC;
2422 		return 1;
2423 	}
2424 
2425 	if (ev_port->inflight_credits < num) {
2426 		/* check if event enqueue brings ev_port over max threshold */
2427 		uint32_t credit_update_quanta = ev_port->credit_update_quanta;
2428 
2429 		if (sw_inflights + credit_update_quanta >
2430 				dlb2->new_event_limit) {
2431 			DLB2_INC_STAT(
2432 			ev_port->stats.traffic.tx_nospc_new_event_limit,
2433 			1);
2434 			rte_errno = -ENOSPC;
2435 			return 1;
2436 		}
2437 
2438 		__atomic_fetch_add(&dlb2->inflights, credit_update_quanta,
2439 				   __ATOMIC_SEQ_CST);
2440 		ev_port->inflight_credits += (credit_update_quanta);
2441 
2442 		if (ev_port->inflight_credits < num) {
2443 			DLB2_INC_STAT(
2444 			ev_port->stats.traffic.tx_nospc_inflight_credits,
2445 			1);
2446 			rte_errno = -ENOSPC;
2447 			return 1;
2448 		}
2449 	}
2450 
2451 	return 0;
2452 }
2453 
2454 static inline int
2455 dlb2_check_enqueue_hw_ldb_credits(struct dlb2_port *qm_port)
2456 {
2457 	if (unlikely(qm_port->cached_ldb_credits == 0)) {
2458 		qm_port->cached_ldb_credits =
2459 			dlb2_port_credits_get(qm_port,
2460 					      DLB2_LDB_QUEUE);
2461 		if (unlikely(qm_port->cached_ldb_credits == 0)) {
2462 			DLB2_INC_STAT(
2463 			qm_port->ev_port->stats.traffic.tx_nospc_ldb_hw_credits,
2464 			1);
2465 			DLB2_LOG_DBG("ldb credits exhausted\n");
2466 			return 1; /* credits exhausted */
2467 		}
2468 	}
2469 
2470 	return 0;
2471 }
2472 
2473 static inline int
2474 dlb2_check_enqueue_hw_dir_credits(struct dlb2_port *qm_port)
2475 {
2476 	if (unlikely(qm_port->cached_dir_credits == 0)) {
2477 		qm_port->cached_dir_credits =
2478 			dlb2_port_credits_get(qm_port,
2479 					      DLB2_DIR_QUEUE);
2480 		if (unlikely(qm_port->cached_dir_credits == 0)) {
2481 			DLB2_INC_STAT(
2482 			qm_port->ev_port->stats.traffic.tx_nospc_dir_hw_credits,
2483 			1);
2484 			DLB2_LOG_DBG("dir credits exhausted\n");
2485 			return 1; /* credits exhausted */
2486 		}
2487 	}
2488 
2489 	return 0;
2490 }
2491 
2492 static inline int
2493 dlb2_check_enqueue_hw_credits(struct dlb2_port *qm_port)
2494 {
2495 	if (unlikely(qm_port->cached_credits == 0)) {
2496 		qm_port->cached_credits =
2497 			dlb2_port_credits_get(qm_port,
2498 					      DLB2_COMBINED_POOL);
2499 		if (unlikely(qm_port->cached_credits == 0)) {
2500 			DLB2_INC_STAT(
2501 			qm_port->ev_port->stats.traffic.tx_nospc_hw_credits, 1);
2502 			DLB2_LOG_DBG("credits exhausted\n");
2503 			return 1; /* credits exhausted */
2504 		}
2505 	}
2506 
2507 	return 0;
2508 }
2509 
2510 static __rte_always_inline void
2511 dlb2_pp_write(struct dlb2_enqueue_qe *qe4,
2512 	      struct process_local_port_data *port_data)
2513 {
2514 	dlb2_movdir64b(port_data->pp_addr, qe4);
2515 }
2516 
2517 static inline int
2518 dlb2_consume_qe_immediate(struct dlb2_port *qm_port, int num)
2519 {
2520 	struct process_local_port_data *port_data;
2521 	struct dlb2_cq_pop_qe *qe;
2522 
2523 	RTE_ASSERT(qm_port->config_state == DLB2_CONFIGURED);
2524 
2525 	qe = qm_port->consume_qe;
2526 
2527 	qe->tokens = num - 1;
2528 
2529 	/* No store fence needed since no pointer is being sent, and CQ token
2530 	 * pops can be safely reordered with other HCWs.
2531 	 */
2532 	port_data = &dlb2_port[qm_port->id][PORT_TYPE(qm_port)];
2533 
2534 	dlb2_movntdq_single(port_data->pp_addr, qe);
2535 
2536 	DLB2_LOG_DBG("dlb2: consume immediate - %d QEs\n", num);
2537 
2538 	qm_port->owed_tokens = 0;
2539 
2540 	return 0;
2541 }
2542 
2543 static inline void
2544 dlb2_hw_do_enqueue(struct dlb2_port *qm_port,
2545 		   bool do_sfence,
2546 		   struct process_local_port_data *port_data)
2547 {
2548 	/* Since MOVDIR64B is weakly-ordered, use an SFENCE to ensure that
2549 	 * application writes complete before enqueueing the QE.
2550 	 */
2551 	if (do_sfence)
2552 		rte_wmb();
2553 
2554 	dlb2_pp_write(qm_port->qe4, port_data);
2555 }
2556 
2557 static inline void
2558 dlb2_construct_token_pop_qe(struct dlb2_port *qm_port, int idx)
2559 {
2560 	struct dlb2_cq_pop_qe *qe = (void *)qm_port->qe4;
2561 	int num = qm_port->owed_tokens;
2562 
2563 	qe[idx].cmd_byte = DLB2_POP_CMD_BYTE;
2564 	qe[idx].tokens = num - 1;
2565 
2566 	qm_port->owed_tokens = 0;
2567 }
2568 
2569 static inline void
2570 dlb2_event_build_hcws(struct dlb2_port *qm_port,
2571 		      const struct rte_event ev[],
2572 		      int num,
2573 		      uint8_t *sched_type,
2574 		      uint8_t *queue_id)
2575 {
2576 	struct dlb2_enqueue_qe *qe;
2577 	uint16_t sched_word[4];
2578 	__m128i sse_qe[2];
2579 	int i;
2580 
2581 	qe = qm_port->qe4;
2582 
2583 	sse_qe[0] = _mm_setzero_si128();
2584 	sse_qe[1] = _mm_setzero_si128();
2585 
2586 	switch (num) {
2587 	case 4:
2588 		/* Construct the metadata portion of two HCWs in one 128b SSE
2589 		 * register. HCW metadata is constructed in the SSE registers
2590 		 * like so:
2591 		 * sse_qe[0][63:0]:   qe[0]'s metadata
2592 		 * sse_qe[0][127:64]: qe[1]'s metadata
2593 		 * sse_qe[1][63:0]:   qe[2]'s metadata
2594 		 * sse_qe[1][127:64]: qe[3]'s metadata
2595 		 */
2596 
2597 		/* Convert the event operation into a command byte and store it
2598 		 * in the metadata:
2599 		 * sse_qe[0][63:56]   = cmd_byte_map[is_directed][ev[0].op]
2600 		 * sse_qe[0][127:120] = cmd_byte_map[is_directed][ev[1].op]
2601 		 * sse_qe[1][63:56]   = cmd_byte_map[is_directed][ev[2].op]
2602 		 * sse_qe[1][127:120] = cmd_byte_map[is_directed][ev[3].op]
2603 		 */
2604 #define DLB2_QE_CMD_BYTE 7
2605 		sse_qe[0] = _mm_insert_epi8(sse_qe[0],
2606 				cmd_byte_map[qm_port->is_directed][ev[0].op],
2607 				DLB2_QE_CMD_BYTE);
2608 		sse_qe[0] = _mm_insert_epi8(sse_qe[0],
2609 				cmd_byte_map[qm_port->is_directed][ev[1].op],
2610 				DLB2_QE_CMD_BYTE + 8);
2611 		sse_qe[1] = _mm_insert_epi8(sse_qe[1],
2612 				cmd_byte_map[qm_port->is_directed][ev[2].op],
2613 				DLB2_QE_CMD_BYTE);
2614 		sse_qe[1] = _mm_insert_epi8(sse_qe[1],
2615 				cmd_byte_map[qm_port->is_directed][ev[3].op],
2616 				DLB2_QE_CMD_BYTE + 8);
2617 
2618 		/* Store priority, scheduling type, and queue ID in the sched
2619 		 * word array because these values are re-used when the
2620 		 * destination is a directed queue.
2621 		 */
2622 		sched_word[0] = EV_TO_DLB2_PRIO(ev[0].priority) << 10 |
2623 				sched_type[0] << 8 |
2624 				queue_id[0];
2625 		sched_word[1] = EV_TO_DLB2_PRIO(ev[1].priority) << 10 |
2626 				sched_type[1] << 8 |
2627 				queue_id[1];
2628 		sched_word[2] = EV_TO_DLB2_PRIO(ev[2].priority) << 10 |
2629 				sched_type[2] << 8 |
2630 				queue_id[2];
2631 		sched_word[3] = EV_TO_DLB2_PRIO(ev[3].priority) << 10 |
2632 				sched_type[3] << 8 |
2633 				queue_id[3];
2634 
2635 		/* Store the event priority, scheduling type, and queue ID in
2636 		 * the metadata:
2637 		 * sse_qe[0][31:16] = sched_word[0]
2638 		 * sse_qe[0][95:80] = sched_word[1]
2639 		 * sse_qe[1][31:16] = sched_word[2]
2640 		 * sse_qe[1][95:80] = sched_word[3]
2641 		 */
2642 #define DLB2_QE_QID_SCHED_WORD 1
2643 		sse_qe[0] = _mm_insert_epi16(sse_qe[0],
2644 					     sched_word[0],
2645 					     DLB2_QE_QID_SCHED_WORD);
2646 		sse_qe[0] = _mm_insert_epi16(sse_qe[0],
2647 					     sched_word[1],
2648 					     DLB2_QE_QID_SCHED_WORD + 4);
2649 		sse_qe[1] = _mm_insert_epi16(sse_qe[1],
2650 					     sched_word[2],
2651 					     DLB2_QE_QID_SCHED_WORD);
2652 		sse_qe[1] = _mm_insert_epi16(sse_qe[1],
2653 					     sched_word[3],
2654 					     DLB2_QE_QID_SCHED_WORD + 4);
2655 
2656 		/* If the destination is a load-balanced queue, store the lock
2657 		 * ID. If it is a directed queue, DLB places this field in
2658 		 * bytes 10-11 of the received QE, so we format it accordingly:
2659 		 * sse_qe[0][47:32]  = dir queue ? sched_word[0] : flow_id[0]
2660 		 * sse_qe[0][111:96] = dir queue ? sched_word[1] : flow_id[1]
2661 		 * sse_qe[1][47:32]  = dir queue ? sched_word[2] : flow_id[2]
2662 		 * sse_qe[1][111:96] = dir queue ? sched_word[3] : flow_id[3]
2663 		 */
2664 #define DLB2_QE_LOCK_ID_WORD 2
2665 		sse_qe[0] = _mm_insert_epi16(sse_qe[0],
2666 				(sched_type[0] == DLB2_SCHED_DIRECTED) ?
2667 					sched_word[0] : ev[0].flow_id,
2668 				DLB2_QE_LOCK_ID_WORD);
2669 		sse_qe[0] = _mm_insert_epi16(sse_qe[0],
2670 				(sched_type[1] == DLB2_SCHED_DIRECTED) ?
2671 					sched_word[1] : ev[1].flow_id,
2672 				DLB2_QE_LOCK_ID_WORD + 4);
2673 		sse_qe[1] = _mm_insert_epi16(sse_qe[1],
2674 				(sched_type[2] == DLB2_SCHED_DIRECTED) ?
2675 					sched_word[2] : ev[2].flow_id,
2676 				DLB2_QE_LOCK_ID_WORD);
2677 		sse_qe[1] = _mm_insert_epi16(sse_qe[1],
2678 				(sched_type[3] == DLB2_SCHED_DIRECTED) ?
2679 					sched_word[3] : ev[3].flow_id,
2680 				DLB2_QE_LOCK_ID_WORD + 4);
2681 
2682 		/* Store the event type and sub event type in the metadata:
2683 		 * sse_qe[0][15:0]  = flow_id[0]
2684 		 * sse_qe[0][79:64] = flow_id[1]
2685 		 * sse_qe[1][15:0]  = flow_id[2]
2686 		 * sse_qe[1][79:64] = flow_id[3]
2687 		 */
2688 #define DLB2_QE_EV_TYPE_WORD 0
2689 		sse_qe[0] = _mm_insert_epi16(sse_qe[0],
2690 					     ev[0].sub_event_type << 8 |
2691 						ev[0].event_type,
2692 					     DLB2_QE_EV_TYPE_WORD);
2693 		sse_qe[0] = _mm_insert_epi16(sse_qe[0],
2694 					     ev[1].sub_event_type << 8 |
2695 						ev[1].event_type,
2696 					     DLB2_QE_EV_TYPE_WORD + 4);
2697 		sse_qe[1] = _mm_insert_epi16(sse_qe[1],
2698 					     ev[2].sub_event_type << 8 |
2699 						ev[2].event_type,
2700 					     DLB2_QE_EV_TYPE_WORD);
2701 		sse_qe[1] = _mm_insert_epi16(sse_qe[1],
2702 					     ev[3].sub_event_type << 8 |
2703 						ev[3].event_type,
2704 					     DLB2_QE_EV_TYPE_WORD + 4);
2705 
2706 		/* Store the metadata to memory (use the double-precision
2707 		 * _mm_storeh_pd because there is no integer function for
2708 		 * storing the upper 64b):
2709 		 * qe[0] metadata = sse_qe[0][63:0]
2710 		 * qe[1] metadata = sse_qe[0][127:64]
2711 		 * qe[2] metadata = sse_qe[1][63:0]
2712 		 * qe[3] metadata = sse_qe[1][127:64]
2713 		 */
2714 		_mm_storel_epi64((__m128i *)&qe[0].u.opaque_data, sse_qe[0]);
2715 		_mm_storeh_pd((double *)&qe[1].u.opaque_data,
2716 			      (__m128d)sse_qe[0]);
2717 		_mm_storel_epi64((__m128i *)&qe[2].u.opaque_data, sse_qe[1]);
2718 		_mm_storeh_pd((double *)&qe[3].u.opaque_data,
2719 			      (__m128d)sse_qe[1]);
2720 
2721 		qe[0].data = ev[0].u64;
2722 		qe[1].data = ev[1].u64;
2723 		qe[2].data = ev[2].u64;
2724 		qe[3].data = ev[3].u64;
2725 
2726 		break;
2727 	case 3:
2728 	case 2:
2729 	case 1:
2730 		for (i = 0; i < num; i++) {
2731 			qe[i].cmd_byte =
2732 				cmd_byte_map[qm_port->is_directed][ev[i].op];
2733 			qe[i].sched_type = sched_type[i];
2734 			qe[i].data = ev[i].u64;
2735 			qe[i].qid = queue_id[i];
2736 			qe[i].priority = EV_TO_DLB2_PRIO(ev[i].priority);
2737 			qe[i].lock_id = ev[i].flow_id;
2738 			if (sched_type[i] == DLB2_SCHED_DIRECTED) {
2739 				struct dlb2_msg_info *info =
2740 					(struct dlb2_msg_info *)&qe[i].lock_id;
2741 
2742 				info->qid = queue_id[i];
2743 				info->sched_type = DLB2_SCHED_DIRECTED;
2744 				info->priority = qe[i].priority;
2745 			}
2746 			qe[i].u.event_type.major = ev[i].event_type;
2747 			qe[i].u.event_type.sub = ev[i].sub_event_type;
2748 		}
2749 		break;
2750 	case 0:
2751 		break;
2752 	}
2753 }
2754 
2755 static inline int
2756 dlb2_event_enqueue_prep(struct dlb2_eventdev_port *ev_port,
2757 			struct dlb2_port *qm_port,
2758 			const struct rte_event ev[],
2759 			uint8_t *sched_type,
2760 			uint8_t *queue_id)
2761 {
2762 	struct dlb2_eventdev *dlb2 = ev_port->dlb2;
2763 	struct dlb2_eventdev_queue *ev_queue;
2764 	uint16_t *cached_credits = NULL;
2765 	struct dlb2_queue *qm_queue;
2766 
2767 	ev_queue = &dlb2->ev_queues[ev->queue_id];
2768 	qm_queue = &ev_queue->qm_queue;
2769 	*queue_id = qm_queue->id;
2770 
2771 	/* Ignore sched_type and hardware credits on release events */
2772 	if (ev->op == RTE_EVENT_OP_RELEASE)
2773 		goto op_check;
2774 
2775 	if (!qm_queue->is_directed) {
2776 		/* Load balanced destination queue */
2777 
2778 		if (dlb2->version == DLB2_HW_V2) {
2779 			if (dlb2_check_enqueue_hw_ldb_credits(qm_port)) {
2780 				rte_errno = -ENOSPC;
2781 				return 1;
2782 			}
2783 			cached_credits = &qm_port->cached_ldb_credits;
2784 		} else {
2785 			if (dlb2_check_enqueue_hw_credits(qm_port)) {
2786 				rte_errno = -ENOSPC;
2787 				return 1;
2788 			}
2789 			cached_credits = &qm_port->cached_credits;
2790 		}
2791 		switch (ev->sched_type) {
2792 		case RTE_SCHED_TYPE_ORDERED:
2793 			DLB2_LOG_DBG("dlb2: put_qe: RTE_SCHED_TYPE_ORDERED\n");
2794 			if (qm_queue->sched_type != RTE_SCHED_TYPE_ORDERED) {
2795 				DLB2_LOG_ERR("dlb2: tried to send ordered event to unordered queue %d\n",
2796 					     *queue_id);
2797 				rte_errno = -EINVAL;
2798 				return 1;
2799 			}
2800 			*sched_type = DLB2_SCHED_ORDERED;
2801 			break;
2802 		case RTE_SCHED_TYPE_ATOMIC:
2803 			DLB2_LOG_DBG("dlb2: put_qe: RTE_SCHED_TYPE_ATOMIC\n");
2804 			*sched_type = DLB2_SCHED_ATOMIC;
2805 			break;
2806 		case RTE_SCHED_TYPE_PARALLEL:
2807 			DLB2_LOG_DBG("dlb2: put_qe: RTE_SCHED_TYPE_PARALLEL\n");
2808 			if (qm_queue->sched_type == RTE_SCHED_TYPE_ORDERED)
2809 				*sched_type = DLB2_SCHED_ORDERED;
2810 			else
2811 				*sched_type = DLB2_SCHED_UNORDERED;
2812 			break;
2813 		default:
2814 			DLB2_LOG_ERR("Unsupported LDB sched type in put_qe\n");
2815 			DLB2_INC_STAT(ev_port->stats.tx_invalid, 1);
2816 			rte_errno = -EINVAL;
2817 			return 1;
2818 		}
2819 	} else {
2820 		/* Directed destination queue */
2821 
2822 		if (dlb2->version == DLB2_HW_V2) {
2823 			if (dlb2_check_enqueue_hw_dir_credits(qm_port)) {
2824 				rte_errno = -ENOSPC;
2825 				return 1;
2826 			}
2827 			cached_credits = &qm_port->cached_dir_credits;
2828 		} else {
2829 			if (dlb2_check_enqueue_hw_credits(qm_port)) {
2830 				rte_errno = -ENOSPC;
2831 				return 1;
2832 			}
2833 			cached_credits = &qm_port->cached_credits;
2834 		}
2835 		DLB2_LOG_DBG("dlb2: put_qe: RTE_SCHED_TYPE_DIRECTED\n");
2836 
2837 		*sched_type = DLB2_SCHED_DIRECTED;
2838 	}
2839 
2840 op_check:
2841 	switch (ev->op) {
2842 	case RTE_EVENT_OP_NEW:
2843 		/* Check that a sw credit is available */
2844 		if (dlb2_check_enqueue_sw_credits(dlb2, ev_port)) {
2845 			rte_errno = -ENOSPC;
2846 			return 1;
2847 		}
2848 		ev_port->inflight_credits--;
2849 		(*cached_credits)--;
2850 		break;
2851 	case RTE_EVENT_OP_FORWARD:
2852 		/* Check for outstanding_releases underflow. If this occurs,
2853 		 * the application is not using the EVENT_OPs correctly; for
2854 		 * example, forwarding or releasing events that were not
2855 		 * dequeued.
2856 		 */
2857 		RTE_ASSERT(ev_port->outstanding_releases > 0);
2858 		ev_port->outstanding_releases--;
2859 		qm_port->issued_releases++;
2860 		(*cached_credits)--;
2861 		break;
2862 	case RTE_EVENT_OP_RELEASE:
2863 		ev_port->inflight_credits++;
2864 		/* Check for outstanding_releases underflow. If this occurs,
2865 		 * the application is not using the EVENT_OPs correctly; for
2866 		 * example, forwarding or releasing events that were not
2867 		 * dequeued.
2868 		 */
2869 		RTE_ASSERT(ev_port->outstanding_releases > 0);
2870 		ev_port->outstanding_releases--;
2871 		qm_port->issued_releases++;
2872 
2873 		/* Replenish s/w credits if enough are cached */
2874 		dlb2_replenish_sw_credits(dlb2, ev_port);
2875 		break;
2876 	}
2877 
2878 	DLB2_INC_STAT(ev_port->stats.tx_op_cnt[ev->op], 1);
2879 	DLB2_INC_STAT(ev_port->stats.traffic.tx_ok, 1);
2880 
2881 #ifndef RTE_LIBRTE_PMD_DLB_QUELL_STATS
2882 	if (ev->op != RTE_EVENT_OP_RELEASE) {
2883 		DLB2_INC_STAT(ev_port->stats.queue[ev->queue_id].enq_ok, 1);
2884 		DLB2_INC_STAT(ev_port->stats.tx_sched_cnt[*sched_type], 1);
2885 	}
2886 #endif
2887 
2888 	return 0;
2889 }
2890 
2891 static inline uint16_t
2892 __dlb2_event_enqueue_burst(void *event_port,
2893 			   const struct rte_event events[],
2894 			   uint16_t num,
2895 			   bool use_delayed)
2896 {
2897 	struct dlb2_eventdev_port *ev_port = event_port;
2898 	struct dlb2_port *qm_port = &ev_port->qm_port;
2899 	struct process_local_port_data *port_data;
2900 	int i;
2901 
2902 	RTE_ASSERT(ev_port->enq_configured);
2903 	RTE_ASSERT(events != NULL);
2904 
2905 	i = 0;
2906 
2907 	port_data = &dlb2_port[qm_port->id][PORT_TYPE(qm_port)];
2908 
2909 	while (i < num) {
2910 		uint8_t sched_types[DLB2_NUM_QES_PER_CACHE_LINE];
2911 		uint8_t queue_ids[DLB2_NUM_QES_PER_CACHE_LINE];
2912 		int pop_offs = 0;
2913 		int j = 0;
2914 
2915 		memset(qm_port->qe4,
2916 		       0,
2917 		       DLB2_NUM_QES_PER_CACHE_LINE *
2918 		       sizeof(struct dlb2_enqueue_qe));
2919 
2920 		for (; j < DLB2_NUM_QES_PER_CACHE_LINE && (i + j) < num; j++) {
2921 			const struct rte_event *ev = &events[i + j];
2922 			int16_t thresh = qm_port->token_pop_thresh;
2923 
2924 			if (use_delayed &&
2925 			    qm_port->token_pop_mode == DELAYED_POP &&
2926 			    (ev->op == RTE_EVENT_OP_FORWARD ||
2927 			     ev->op == RTE_EVENT_OP_RELEASE) &&
2928 			    qm_port->issued_releases >= thresh - 1) {
2929 				/* Insert the token pop QE and break out. This
2930 				 * may result in a partial HCW, but that is
2931 				 * simpler than supporting arbitrary QE
2932 				 * insertion.
2933 				 */
2934 				dlb2_construct_token_pop_qe(qm_port, j);
2935 
2936 				/* Reset the releases for the next QE batch */
2937 				qm_port->issued_releases -= thresh;
2938 
2939 				pop_offs = 1;
2940 				j++;
2941 				break;
2942 			}
2943 
2944 			if (dlb2_event_enqueue_prep(ev_port, qm_port, ev,
2945 						    &sched_types[j],
2946 						    &queue_ids[j]))
2947 				break;
2948 		}
2949 
2950 		if (j == 0)
2951 			break;
2952 
2953 		dlb2_event_build_hcws(qm_port, &events[i], j - pop_offs,
2954 				      sched_types, queue_ids);
2955 
2956 		dlb2_hw_do_enqueue(qm_port, i == 0, port_data);
2957 
2958 		/* Don't include the token pop QE in the enqueue count */
2959 		i += j - pop_offs;
2960 
2961 		/* Don't interpret j < DLB2_NUM_... as out-of-credits if
2962 		 * pop_offs != 0
2963 		 */
2964 		if (j < DLB2_NUM_QES_PER_CACHE_LINE && pop_offs == 0)
2965 			break;
2966 	}
2967 
2968 	return i;
2969 }
2970 
2971 static uint16_t
2972 dlb2_event_enqueue_burst(void *event_port,
2973 			     const struct rte_event events[],
2974 			     uint16_t num)
2975 {
2976 	return __dlb2_event_enqueue_burst(event_port, events, num, false);
2977 }
2978 
2979 static uint16_t
2980 dlb2_event_enqueue_burst_delayed(void *event_port,
2981 				     const struct rte_event events[],
2982 				     uint16_t num)
2983 {
2984 	return __dlb2_event_enqueue_burst(event_port, events, num, true);
2985 }
2986 
2987 static inline uint16_t
2988 dlb2_event_enqueue(void *event_port,
2989 		   const struct rte_event events[])
2990 {
2991 	return __dlb2_event_enqueue_burst(event_port, events, 1, false);
2992 }
2993 
2994 static inline uint16_t
2995 dlb2_event_enqueue_delayed(void *event_port,
2996 			   const struct rte_event events[])
2997 {
2998 	return __dlb2_event_enqueue_burst(event_port, events, 1, true);
2999 }
3000 
3001 static uint16_t
3002 dlb2_event_enqueue_new_burst(void *event_port,
3003 			     const struct rte_event events[],
3004 			     uint16_t num)
3005 {
3006 	return __dlb2_event_enqueue_burst(event_port, events, num, false);
3007 }
3008 
3009 static uint16_t
3010 dlb2_event_enqueue_new_burst_delayed(void *event_port,
3011 				     const struct rte_event events[],
3012 				     uint16_t num)
3013 {
3014 	return __dlb2_event_enqueue_burst(event_port, events, num, true);
3015 }
3016 
3017 static uint16_t
3018 dlb2_event_enqueue_forward_burst(void *event_port,
3019 				 const struct rte_event events[],
3020 				 uint16_t num)
3021 {
3022 	return __dlb2_event_enqueue_burst(event_port, events, num, false);
3023 }
3024 
3025 static uint16_t
3026 dlb2_event_enqueue_forward_burst_delayed(void *event_port,
3027 					 const struct rte_event events[],
3028 					 uint16_t num)
3029 {
3030 	return __dlb2_event_enqueue_burst(event_port, events, num, true);
3031 }
3032 
3033 static void
3034 dlb2_event_release(struct dlb2_eventdev *dlb2,
3035 		   uint8_t port_id,
3036 		   int n)
3037 {
3038 	struct process_local_port_data *port_data;
3039 	struct dlb2_eventdev_port *ev_port;
3040 	struct dlb2_port *qm_port;
3041 	int i;
3042 
3043 	if (port_id > dlb2->num_ports) {
3044 		DLB2_LOG_ERR("Invalid port id %d in dlb2-event_release\n",
3045 			     port_id);
3046 		rte_errno = -EINVAL;
3047 		return;
3048 	}
3049 
3050 	ev_port = &dlb2->ev_ports[port_id];
3051 	qm_port = &ev_port->qm_port;
3052 	port_data = &dlb2_port[qm_port->id][PORT_TYPE(qm_port)];
3053 
3054 	i = 0;
3055 
3056 	if (qm_port->is_directed) {
3057 		i = n;
3058 		goto sw_credit_update;
3059 	}
3060 
3061 	while (i < n) {
3062 		int pop_offs = 0;
3063 		int j = 0;
3064 
3065 		/* Zero-out QEs */
3066 		_mm_storeu_si128((void *)&qm_port->qe4[0], _mm_setzero_si128());
3067 		_mm_storeu_si128((void *)&qm_port->qe4[1], _mm_setzero_si128());
3068 		_mm_storeu_si128((void *)&qm_port->qe4[2], _mm_setzero_si128());
3069 		_mm_storeu_si128((void *)&qm_port->qe4[3], _mm_setzero_si128());
3070 
3071 
3072 		for (; j < DLB2_NUM_QES_PER_CACHE_LINE && (i + j) < n; j++) {
3073 			int16_t thresh = qm_port->token_pop_thresh;
3074 
3075 			if (qm_port->token_pop_mode == DELAYED_POP &&
3076 			    qm_port->issued_releases >= thresh - 1) {
3077 				/* Insert the token pop QE */
3078 				dlb2_construct_token_pop_qe(qm_port, j);
3079 
3080 				/* Reset the releases for the next QE batch */
3081 				qm_port->issued_releases -= thresh;
3082 
3083 				pop_offs = 1;
3084 				j++;
3085 				break;
3086 			}
3087 
3088 			qm_port->qe4[j].cmd_byte = DLB2_COMP_CMD_BYTE;
3089 			qm_port->issued_releases++;
3090 		}
3091 
3092 		dlb2_hw_do_enqueue(qm_port, i == 0, port_data);
3093 
3094 		/* Don't include the token pop QE in the release count */
3095 		i += j - pop_offs;
3096 	}
3097 
3098 sw_credit_update:
3099 	/* each release returns one credit */
3100 	if (unlikely(!ev_port->outstanding_releases)) {
3101 		DLB2_LOG_ERR("%s: Outstanding releases underflowed.\n",
3102 			     __func__);
3103 		return;
3104 	}
3105 	ev_port->outstanding_releases -= i;
3106 	ev_port->inflight_credits += i;
3107 
3108 	/* Replenish s/w credits if enough releases are performed */
3109 	dlb2_replenish_sw_credits(dlb2, ev_port);
3110 }
3111 
3112 static inline void
3113 dlb2_port_credits_inc(struct dlb2_port *qm_port, int num)
3114 {
3115 	uint32_t batch_size = DLB2_SW_CREDIT_BATCH_SZ;
3116 
3117 	/* increment port credits, and return to pool if exceeds threshold */
3118 	if (!qm_port->is_directed) {
3119 		if (qm_port->dlb2->version == DLB2_HW_V2) {
3120 			qm_port->cached_ldb_credits += num;
3121 			if (qm_port->cached_ldb_credits >= 2 * batch_size) {
3122 				__atomic_fetch_add(
3123 					qm_port->credit_pool[DLB2_LDB_QUEUE],
3124 					batch_size, __ATOMIC_SEQ_CST);
3125 				qm_port->cached_ldb_credits -= batch_size;
3126 			}
3127 		} else {
3128 			qm_port->cached_credits += num;
3129 			if (qm_port->cached_credits >= 2 * batch_size) {
3130 				__atomic_fetch_add(
3131 				      qm_port->credit_pool[DLB2_COMBINED_POOL],
3132 				      batch_size, __ATOMIC_SEQ_CST);
3133 				qm_port->cached_credits -= batch_size;
3134 			}
3135 		}
3136 	} else {
3137 		if (qm_port->dlb2->version == DLB2_HW_V2) {
3138 			qm_port->cached_dir_credits += num;
3139 			if (qm_port->cached_dir_credits >= 2 * batch_size) {
3140 				__atomic_fetch_add(
3141 					qm_port->credit_pool[DLB2_DIR_QUEUE],
3142 					batch_size, __ATOMIC_SEQ_CST);
3143 				qm_port->cached_dir_credits -= batch_size;
3144 			}
3145 		} else {
3146 			qm_port->cached_credits += num;
3147 			if (qm_port->cached_credits >= 2 * batch_size) {
3148 				__atomic_fetch_add(
3149 				      qm_port->credit_pool[DLB2_COMBINED_POOL],
3150 				      batch_size, __ATOMIC_SEQ_CST);
3151 				qm_port->cached_credits -= batch_size;
3152 			}
3153 		}
3154 	}
3155 }
3156 
3157 #define CLB_MASK_IDX 0
3158 #define CLB_VAL_IDX 1
3159 static int
3160 dlb2_monitor_callback(const uint64_t val,
3161 		const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ])
3162 {
3163 	/* abort if the value matches */
3164 	return (val & opaque[CLB_MASK_IDX]) == opaque[CLB_VAL_IDX] ? -1 : 0;
3165 }
3166 
3167 static inline int
3168 dlb2_dequeue_wait(struct dlb2_eventdev *dlb2,
3169 		  struct dlb2_eventdev_port *ev_port,
3170 		  struct dlb2_port *qm_port,
3171 		  uint64_t timeout,
3172 		  uint64_t start_ticks)
3173 {
3174 	struct process_local_port_data *port_data;
3175 	uint64_t elapsed_ticks;
3176 
3177 	port_data = &dlb2_port[qm_port->id][PORT_TYPE(qm_port)];
3178 
3179 	elapsed_ticks = rte_get_timer_cycles() - start_ticks;
3180 
3181 	/* Wait/poll time expired */
3182 	if (elapsed_ticks >= timeout) {
3183 		return 1;
3184 	} else if (dlb2->umwait_allowed) {
3185 		struct rte_power_monitor_cond pmc;
3186 		volatile struct dlb2_dequeue_qe *cq_base;
3187 		union {
3188 			uint64_t raw_qe[2];
3189 			struct dlb2_dequeue_qe qe;
3190 		} qe_mask;
3191 		uint64_t expected_value;
3192 		volatile uint64_t *monitor_addr;
3193 
3194 		qe_mask.qe.cq_gen = 1; /* set mask */
3195 
3196 		cq_base = port_data->cq_base;
3197 		monitor_addr = (volatile uint64_t *)(volatile void *)
3198 			&cq_base[qm_port->cq_idx];
3199 		monitor_addr++; /* cq_gen bit is in second 64bit location */
3200 
3201 		if (qm_port->gen_bit)
3202 			expected_value = qe_mask.raw_qe[1];
3203 		else
3204 			expected_value = 0;
3205 
3206 		pmc.addr = monitor_addr;
3207 		/* store expected value and comparison mask in opaque data */
3208 		pmc.opaque[CLB_VAL_IDX] = expected_value;
3209 		pmc.opaque[CLB_MASK_IDX] = qe_mask.raw_qe[1];
3210 		/* set up callback */
3211 		pmc.fn = dlb2_monitor_callback;
3212 		pmc.size = sizeof(uint64_t);
3213 
3214 		rte_power_monitor(&pmc, timeout + start_ticks);
3215 
3216 		DLB2_INC_STAT(ev_port->stats.traffic.rx_umonitor_umwait, 1);
3217 	} else {
3218 		uint64_t poll_interval = dlb2->poll_interval;
3219 		uint64_t curr_ticks = rte_get_timer_cycles();
3220 		uint64_t init_ticks = curr_ticks;
3221 
3222 		while ((curr_ticks - start_ticks < timeout) &&
3223 		       (curr_ticks - init_ticks < poll_interval))
3224 			curr_ticks = rte_get_timer_cycles();
3225 	}
3226 
3227 	return 0;
3228 }
3229 
3230 static __rte_noinline int
3231 dlb2_process_dequeue_qes(struct dlb2_eventdev_port *ev_port,
3232 			 struct dlb2_port *qm_port,
3233 			 struct rte_event *events,
3234 			 struct dlb2_dequeue_qe *qes,
3235 			 int cnt)
3236 {
3237 	uint8_t *qid_mappings = qm_port->qid_mappings;
3238 	int i, num, evq_id;
3239 
3240 	for (i = 0, num = 0; i < cnt; i++) {
3241 		struct dlb2_dequeue_qe *qe = &qes[i];
3242 		int sched_type_map[DLB2_NUM_HW_SCHED_TYPES] = {
3243 			[DLB2_SCHED_ATOMIC] = RTE_SCHED_TYPE_ATOMIC,
3244 			[DLB2_SCHED_UNORDERED] = RTE_SCHED_TYPE_PARALLEL,
3245 			[DLB2_SCHED_ORDERED] = RTE_SCHED_TYPE_ORDERED,
3246 			[DLB2_SCHED_DIRECTED] = RTE_SCHED_TYPE_ATOMIC,
3247 		};
3248 
3249 		/* Fill in event information.
3250 		 * Note that flow_id must be embedded in the data by
3251 		 * the app, such as the mbuf RSS hash field if the data
3252 		 * buffer is a mbuf.
3253 		 */
3254 		if (unlikely(qe->error)) {
3255 			DLB2_LOG_ERR("QE error bit ON\n");
3256 			DLB2_INC_STAT(ev_port->stats.traffic.rx_drop, 1);
3257 			dlb2_consume_qe_immediate(qm_port, 1);
3258 			continue; /* Ignore */
3259 		}
3260 
3261 		events[num].u64 = qe->data;
3262 		events[num].flow_id = qe->flow_id;
3263 		events[num].priority = DLB2_TO_EV_PRIO((uint8_t)qe->priority);
3264 		events[num].event_type = qe->u.event_type.major;
3265 		events[num].sub_event_type = qe->u.event_type.sub;
3266 		events[num].sched_type = sched_type_map[qe->sched_type];
3267 		events[num].impl_opaque = qe->qid_depth;
3268 
3269 		/* qid not preserved for directed queues */
3270 		if (qm_port->is_directed)
3271 			evq_id = ev_port->link[0].queue_id;
3272 		else
3273 			evq_id = qid_mappings[qe->qid];
3274 
3275 		events[num].queue_id = evq_id;
3276 		DLB2_INC_STAT(
3277 			ev_port->stats.queue[evq_id].qid_depth[qe->qid_depth],
3278 			1);
3279 		DLB2_INC_STAT(ev_port->stats.rx_sched_cnt[qe->sched_type], 1);
3280 		num++;
3281 	}
3282 
3283 	DLB2_INC_STAT(ev_port->stats.traffic.rx_ok, num);
3284 
3285 	return num;
3286 }
3287 
3288 static inline int
3289 dlb2_process_dequeue_four_qes(struct dlb2_eventdev_port *ev_port,
3290 			      struct dlb2_port *qm_port,
3291 			      struct rte_event *events,
3292 			      struct dlb2_dequeue_qe *qes)
3293 {
3294 	int sched_type_map[] = {
3295 		[DLB2_SCHED_ATOMIC] = RTE_SCHED_TYPE_ATOMIC,
3296 		[DLB2_SCHED_UNORDERED] = RTE_SCHED_TYPE_PARALLEL,
3297 		[DLB2_SCHED_ORDERED] = RTE_SCHED_TYPE_ORDERED,
3298 		[DLB2_SCHED_DIRECTED] = RTE_SCHED_TYPE_ATOMIC,
3299 	};
3300 	const int num_events = DLB2_NUM_QES_PER_CACHE_LINE;
3301 	uint8_t *qid_mappings = qm_port->qid_mappings;
3302 	__m128i sse_evt[2];
3303 
3304 	/* In the unlikely case that any of the QE error bits are set, process
3305 	 * them one at a time.
3306 	 */
3307 	if (unlikely(qes[0].error || qes[1].error ||
3308 		     qes[2].error || qes[3].error))
3309 		return dlb2_process_dequeue_qes(ev_port, qm_port, events,
3310 						 qes, num_events);
3311 
3312 	events[0].u64 = qes[0].data;
3313 	events[1].u64 = qes[1].data;
3314 	events[2].u64 = qes[2].data;
3315 	events[3].u64 = qes[3].data;
3316 
3317 	/* Construct the metadata portion of two struct rte_events
3318 	 * in one 128b SSE register. Event metadata is constructed in the SSE
3319 	 * registers like so:
3320 	 * sse_evt[0][63:0]:   event[0]'s metadata
3321 	 * sse_evt[0][127:64]: event[1]'s metadata
3322 	 * sse_evt[1][63:0]:   event[2]'s metadata
3323 	 * sse_evt[1][127:64]: event[3]'s metadata
3324 	 */
3325 	sse_evt[0] = _mm_setzero_si128();
3326 	sse_evt[1] = _mm_setzero_si128();
3327 
3328 	/* Convert the hardware queue ID to an event queue ID and store it in
3329 	 * the metadata:
3330 	 * sse_evt[0][47:40]   = qid_mappings[qes[0].qid]
3331 	 * sse_evt[0][111:104] = qid_mappings[qes[1].qid]
3332 	 * sse_evt[1][47:40]   = qid_mappings[qes[2].qid]
3333 	 * sse_evt[1][111:104] = qid_mappings[qes[3].qid]
3334 	 */
3335 #define DLB_EVENT_QUEUE_ID_BYTE 5
3336 	sse_evt[0] = _mm_insert_epi8(sse_evt[0],
3337 				     qid_mappings[qes[0].qid],
3338 				     DLB_EVENT_QUEUE_ID_BYTE);
3339 	sse_evt[0] = _mm_insert_epi8(sse_evt[0],
3340 				     qid_mappings[qes[1].qid],
3341 				     DLB_EVENT_QUEUE_ID_BYTE + 8);
3342 	sse_evt[1] = _mm_insert_epi8(sse_evt[1],
3343 				     qid_mappings[qes[2].qid],
3344 				     DLB_EVENT_QUEUE_ID_BYTE);
3345 	sse_evt[1] = _mm_insert_epi8(sse_evt[1],
3346 				     qid_mappings[qes[3].qid],
3347 				     DLB_EVENT_QUEUE_ID_BYTE + 8);
3348 
3349 	/* Convert the hardware priority to an event priority and store it in
3350 	 * the metadata, while also returning the queue depth status
3351 	 * value captured by the hardware, storing it in impl_opaque, which can
3352 	 * be read by the application but not modified
3353 	 * sse_evt[0][55:48]   = DLB2_TO_EV_PRIO(qes[0].priority)
3354 	 * sse_evt[0][63:56]   = qes[0].qid_depth
3355 	 * sse_evt[0][119:112] = DLB2_TO_EV_PRIO(qes[1].priority)
3356 	 * sse_evt[0][127:120] = qes[1].qid_depth
3357 	 * sse_evt[1][55:48]   = DLB2_TO_EV_PRIO(qes[2].priority)
3358 	 * sse_evt[1][63:56]   = qes[2].qid_depth
3359 	 * sse_evt[1][119:112] = DLB2_TO_EV_PRIO(qes[3].priority)
3360 	 * sse_evt[1][127:120] = qes[3].qid_depth
3361 	 */
3362 #define DLB_EVENT_PRIO_IMPL_OPAQUE_WORD 3
3363 #define DLB_BYTE_SHIFT 8
3364 	sse_evt[0] =
3365 		_mm_insert_epi16(sse_evt[0],
3366 			DLB2_TO_EV_PRIO((uint8_t)qes[0].priority) |
3367 			(qes[0].qid_depth << DLB_BYTE_SHIFT),
3368 			DLB_EVENT_PRIO_IMPL_OPAQUE_WORD);
3369 	sse_evt[0] =
3370 		_mm_insert_epi16(sse_evt[0],
3371 			DLB2_TO_EV_PRIO((uint8_t)qes[1].priority) |
3372 			(qes[1].qid_depth << DLB_BYTE_SHIFT),
3373 			DLB_EVENT_PRIO_IMPL_OPAQUE_WORD + 4);
3374 	sse_evt[1] =
3375 		_mm_insert_epi16(sse_evt[1],
3376 			DLB2_TO_EV_PRIO((uint8_t)qes[2].priority) |
3377 			(qes[2].qid_depth << DLB_BYTE_SHIFT),
3378 			DLB_EVENT_PRIO_IMPL_OPAQUE_WORD);
3379 	sse_evt[1] =
3380 		_mm_insert_epi16(sse_evt[1],
3381 			DLB2_TO_EV_PRIO((uint8_t)qes[3].priority) |
3382 			(qes[3].qid_depth << DLB_BYTE_SHIFT),
3383 			DLB_EVENT_PRIO_IMPL_OPAQUE_WORD + 4);
3384 
3385 	/* Write the event type, sub event type, and flow_id to the event
3386 	 * metadata.
3387 	 * sse_evt[0][31:0]   = qes[0].flow_id |
3388 	 *			qes[0].u.event_type.major << 28 |
3389 	 *			qes[0].u.event_type.sub << 20;
3390 	 * sse_evt[0][95:64]  = qes[1].flow_id |
3391 	 *			qes[1].u.event_type.major << 28 |
3392 	 *			qes[1].u.event_type.sub << 20;
3393 	 * sse_evt[1][31:0]   = qes[2].flow_id |
3394 	 *			qes[2].u.event_type.major << 28 |
3395 	 *			qes[2].u.event_type.sub << 20;
3396 	 * sse_evt[1][95:64]  = qes[3].flow_id |
3397 	 *			qes[3].u.event_type.major << 28 |
3398 	 *			qes[3].u.event_type.sub << 20;
3399 	 */
3400 #define DLB_EVENT_EV_TYPE_DW 0
3401 #define DLB_EVENT_EV_TYPE_SHIFT 28
3402 #define DLB_EVENT_SUB_EV_TYPE_SHIFT 20
3403 	sse_evt[0] = _mm_insert_epi32(sse_evt[0],
3404 			qes[0].flow_id |
3405 			qes[0].u.event_type.major << DLB_EVENT_EV_TYPE_SHIFT |
3406 			qes[0].u.event_type.sub <<  DLB_EVENT_SUB_EV_TYPE_SHIFT,
3407 			DLB_EVENT_EV_TYPE_DW);
3408 	sse_evt[0] = _mm_insert_epi32(sse_evt[0],
3409 			qes[1].flow_id |
3410 			qes[1].u.event_type.major << DLB_EVENT_EV_TYPE_SHIFT |
3411 			qes[1].u.event_type.sub <<  DLB_EVENT_SUB_EV_TYPE_SHIFT,
3412 			DLB_EVENT_EV_TYPE_DW + 2);
3413 	sse_evt[1] = _mm_insert_epi32(sse_evt[1],
3414 			qes[2].flow_id |
3415 			qes[2].u.event_type.major << DLB_EVENT_EV_TYPE_SHIFT |
3416 			qes[2].u.event_type.sub <<  DLB_EVENT_SUB_EV_TYPE_SHIFT,
3417 			DLB_EVENT_EV_TYPE_DW);
3418 	sse_evt[1] = _mm_insert_epi32(sse_evt[1],
3419 			qes[3].flow_id |
3420 			qes[3].u.event_type.major << DLB_EVENT_EV_TYPE_SHIFT  |
3421 			qes[3].u.event_type.sub << DLB_EVENT_SUB_EV_TYPE_SHIFT,
3422 			DLB_EVENT_EV_TYPE_DW + 2);
3423 
3424 	/* Write the sched type to the event metadata. 'op' and 'rsvd' are not
3425 	 * set:
3426 	 * sse_evt[0][39:32]  = sched_type_map[qes[0].sched_type] << 6
3427 	 * sse_evt[0][103:96] = sched_type_map[qes[1].sched_type] << 6
3428 	 * sse_evt[1][39:32]  = sched_type_map[qes[2].sched_type] << 6
3429 	 * sse_evt[1][103:96] = sched_type_map[qes[3].sched_type] << 6
3430 	 */
3431 #define DLB_EVENT_SCHED_TYPE_BYTE 4
3432 #define DLB_EVENT_SCHED_TYPE_SHIFT 6
3433 	sse_evt[0] = _mm_insert_epi8(sse_evt[0],
3434 		sched_type_map[qes[0].sched_type] << DLB_EVENT_SCHED_TYPE_SHIFT,
3435 		DLB_EVENT_SCHED_TYPE_BYTE);
3436 	sse_evt[0] = _mm_insert_epi8(sse_evt[0],
3437 		sched_type_map[qes[1].sched_type] << DLB_EVENT_SCHED_TYPE_SHIFT,
3438 		DLB_EVENT_SCHED_TYPE_BYTE + 8);
3439 	sse_evt[1] = _mm_insert_epi8(sse_evt[1],
3440 		sched_type_map[qes[2].sched_type] << DLB_EVENT_SCHED_TYPE_SHIFT,
3441 		DLB_EVENT_SCHED_TYPE_BYTE);
3442 	sse_evt[1] = _mm_insert_epi8(sse_evt[1],
3443 		sched_type_map[qes[3].sched_type] << DLB_EVENT_SCHED_TYPE_SHIFT,
3444 		DLB_EVENT_SCHED_TYPE_BYTE + 8);
3445 
3446 	/* Store the metadata to the event (use the double-precision
3447 	 * _mm_storeh_pd because there is no integer function for storing the
3448 	 * upper 64b):
3449 	 * events[0].event = sse_evt[0][63:0]
3450 	 * events[1].event = sse_evt[0][127:64]
3451 	 * events[2].event = sse_evt[1][63:0]
3452 	 * events[3].event = sse_evt[1][127:64]
3453 	 */
3454 	_mm_storel_epi64((__m128i *)&events[0].event, sse_evt[0]);
3455 	_mm_storeh_pd((double *)&events[1].event, (__m128d) sse_evt[0]);
3456 	_mm_storel_epi64((__m128i *)&events[2].event, sse_evt[1]);
3457 	_mm_storeh_pd((double *)&events[3].event, (__m128d) sse_evt[1]);
3458 
3459 	DLB2_INC_STAT(ev_port->stats.rx_sched_cnt[qes[0].sched_type], 1);
3460 	DLB2_INC_STAT(ev_port->stats.rx_sched_cnt[qes[1].sched_type], 1);
3461 	DLB2_INC_STAT(ev_port->stats.rx_sched_cnt[qes[2].sched_type], 1);
3462 	DLB2_INC_STAT(ev_port->stats.rx_sched_cnt[qes[3].sched_type], 1);
3463 
3464 	DLB2_INC_STAT(
3465 		ev_port->stats.queue[events[0].queue_id].
3466 			qid_depth[qes[0].qid_depth],
3467 		1);
3468 	DLB2_INC_STAT(
3469 		ev_port->stats.queue[events[1].queue_id].
3470 			qid_depth[qes[1].qid_depth],
3471 		1);
3472 	DLB2_INC_STAT(
3473 		ev_port->stats.queue[events[2].queue_id].
3474 			qid_depth[qes[2].qid_depth],
3475 		1);
3476 	DLB2_INC_STAT(
3477 		ev_port->stats.queue[events[3].queue_id].
3478 			qid_depth[qes[3].qid_depth],
3479 		1);
3480 
3481 	DLB2_INC_STAT(ev_port->stats.traffic.rx_ok, num_events);
3482 
3483 	return num_events;
3484 }
3485 
3486 static __rte_always_inline int
3487 dlb2_recv_qe_sparse(struct dlb2_port *qm_port, struct dlb2_dequeue_qe *qe)
3488 {
3489 	volatile struct dlb2_dequeue_qe *cq_addr;
3490 	uint8_t xor_mask[2] = {0x0F, 0x00};
3491 	const uint8_t and_mask = 0x0F;
3492 	__m128i *qes = (__m128i *)qe;
3493 	uint8_t gen_bits, gen_bit;
3494 	uintptr_t addr[4];
3495 	uint16_t idx;
3496 
3497 	cq_addr = dlb2_port[qm_port->id][PORT_TYPE(qm_port)].cq_base;
3498 
3499 	idx = qm_port->cq_idx_unmasked & qm_port->cq_depth_mask;
3500 	/* Load the next 4 QEs */
3501 	addr[0] = (uintptr_t)&cq_addr[idx];
3502 	addr[1] = (uintptr_t)&cq_addr[(idx +  4) & qm_port->cq_depth_mask];
3503 	addr[2] = (uintptr_t)&cq_addr[(idx +  8) & qm_port->cq_depth_mask];
3504 	addr[3] = (uintptr_t)&cq_addr[(idx + 12) & qm_port->cq_depth_mask];
3505 
3506 	/* Prefetch next batch of QEs (all CQs occupy minimum 8 cache lines) */
3507 	rte_prefetch0(&cq_addr[(idx + 16) & qm_port->cq_depth_mask]);
3508 	rte_prefetch0(&cq_addr[(idx + 20) & qm_port->cq_depth_mask]);
3509 	rte_prefetch0(&cq_addr[(idx + 24) & qm_port->cq_depth_mask]);
3510 	rte_prefetch0(&cq_addr[(idx + 28) & qm_port->cq_depth_mask]);
3511 
3512 	/* Correct the xor_mask for wrap-around QEs */
3513 	gen_bit = qm_port->gen_bit;
3514 	xor_mask[gen_bit] ^= !!((idx +  4) > qm_port->cq_depth_mask) << 1;
3515 	xor_mask[gen_bit] ^= !!((idx +  8) > qm_port->cq_depth_mask) << 2;
3516 	xor_mask[gen_bit] ^= !!((idx + 12) > qm_port->cq_depth_mask) << 3;
3517 
3518 	/* Read the cache lines backwards to ensure that if QE[N] (N > 0) is
3519 	 * valid, then QEs[0:N-1] are too.
3520 	 */
3521 	qes[3] = _mm_load_si128((__m128i *)(void *)addr[3]);
3522 	rte_compiler_barrier();
3523 	qes[2] = _mm_load_si128((__m128i *)(void *)addr[2]);
3524 	rte_compiler_barrier();
3525 	qes[1] = _mm_load_si128((__m128i *)(void *)addr[1]);
3526 	rte_compiler_barrier();
3527 	qes[0] = _mm_load_si128((__m128i *)(void *)addr[0]);
3528 
3529 	/* Extract and combine the gen bits */
3530 	gen_bits = ((_mm_extract_epi8(qes[0], 15) & 0x1) << 0) |
3531 		   ((_mm_extract_epi8(qes[1], 15) & 0x1) << 1) |
3532 		   ((_mm_extract_epi8(qes[2], 15) & 0x1) << 2) |
3533 		   ((_mm_extract_epi8(qes[3], 15) & 0x1) << 3);
3534 
3535 	/* XOR the combined bits such that a 1 represents a valid QE */
3536 	gen_bits ^= xor_mask[gen_bit];
3537 
3538 	/* Mask off gen bits we don't care about */
3539 	gen_bits &= and_mask;
3540 
3541 	return __builtin_popcount(gen_bits);
3542 }
3543 
3544 static inline void
3545 _process_deq_qes_vec_impl(struct dlb2_port *qm_port,
3546 			  struct rte_event *events,
3547 			  __m128i v_qe_3,
3548 			  __m128i v_qe_2,
3549 			  __m128i v_qe_1,
3550 			  __m128i v_qe_0,
3551 			  __m128i v_qe_meta,
3552 			  __m128i v_qe_status,
3553 			  uint32_t valid_events)
3554 {
3555 	/* Look up the event QIDs, using the hardware QIDs to index the
3556 	 * port's QID mapping.
3557 	 *
3558 	 * Each v_qe_[0-4] is just a 16-byte load of the whole QE. It is
3559 	 * passed along in registers as the QE data is required later.
3560 	 *
3561 	 * v_qe_meta is an u32 unpack of all 4x QEs. A.k.a, it contains one
3562 	 * 32-bit slice of each QE, so makes up a full SSE register. This
3563 	 * allows parallel processing of 4x QEs in a single register.
3564 	 */
3565 
3566 	__m128i v_qid_done = {0};
3567 	int hw_qid0 = _mm_extract_epi8(v_qe_meta, 2);
3568 	int hw_qid1 = _mm_extract_epi8(v_qe_meta, 6);
3569 	int hw_qid2 = _mm_extract_epi8(v_qe_meta, 10);
3570 	int hw_qid3 = _mm_extract_epi8(v_qe_meta, 14);
3571 
3572 	int ev_qid0 = qm_port->qid_mappings[hw_qid0];
3573 	int ev_qid1 = qm_port->qid_mappings[hw_qid1];
3574 	int ev_qid2 = qm_port->qid_mappings[hw_qid2];
3575 	int ev_qid3 = qm_port->qid_mappings[hw_qid3];
3576 
3577 	int hw_sched0 = _mm_extract_epi8(v_qe_meta, 3) & 3ul;
3578 	int hw_sched1 = _mm_extract_epi8(v_qe_meta, 7) & 3ul;
3579 	int hw_sched2 = _mm_extract_epi8(v_qe_meta, 11) & 3ul;
3580 	int hw_sched3 = _mm_extract_epi8(v_qe_meta, 15) & 3ul;
3581 
3582 	v_qid_done = _mm_insert_epi8(v_qid_done, ev_qid0, 2);
3583 	v_qid_done = _mm_insert_epi8(v_qid_done, ev_qid1, 6);
3584 	v_qid_done = _mm_insert_epi8(v_qid_done, ev_qid2, 10);
3585 	v_qid_done = _mm_insert_epi8(v_qid_done, ev_qid3, 14);
3586 
3587 	/* Schedule field remapping using byte shuffle
3588 	 * - Full byte containing sched field handled here (op, rsvd are zero)
3589 	 * - Note sanitizing the register requires two masking ANDs:
3590 	 *   1) to strip prio/msg_type from byte for correct shuffle lookup
3591 	 *   2) to strip any non-sched-field lanes from any results to OR later
3592 	 * - Final byte result is >> 10 to another byte-lane inside the u32.
3593 	 *   This makes the final combination OR easier to make the rte_event.
3594 	 */
3595 	__m128i v_sched_done;
3596 	__m128i v_sched_bits;
3597 	{
3598 		static const uint8_t sched_type_map[16] = {
3599 			[DLB2_SCHED_ATOMIC] = RTE_SCHED_TYPE_ATOMIC,
3600 			[DLB2_SCHED_UNORDERED] = RTE_SCHED_TYPE_PARALLEL,
3601 			[DLB2_SCHED_ORDERED] = RTE_SCHED_TYPE_ORDERED,
3602 			[DLB2_SCHED_DIRECTED] = RTE_SCHED_TYPE_ATOMIC,
3603 		};
3604 		static const uint8_t sched_and_mask[16] = {
3605 			0x00, 0x00, 0x00, 0x03,
3606 			0x00, 0x00, 0x00, 0x03,
3607 			0x00, 0x00, 0x00, 0x03,
3608 			0x00, 0x00, 0x00, 0x03,
3609 		};
3610 		const __m128i v_sched_map = _mm_loadu_si128(
3611 					     (const __m128i *)sched_type_map);
3612 		__m128i v_sched_mask = _mm_loadu_si128(
3613 					     (const __m128i *)&sched_and_mask);
3614 		v_sched_bits = _mm_and_si128(v_qe_meta, v_sched_mask);
3615 		__m128i v_sched_remapped = _mm_shuffle_epi8(v_sched_map,
3616 							    v_sched_bits);
3617 		__m128i v_preshift = _mm_and_si128(v_sched_remapped,
3618 						   v_sched_mask);
3619 		v_sched_done = _mm_srli_epi32(v_preshift, 10);
3620 	}
3621 
3622 	/* Priority handling
3623 	 * - QE provides 3 bits of priority
3624 	 * - Shift << 3 to move to MSBs for byte-prio in rte_event
3625 	 * - Mask bits to avoid pollution, leaving only 3 prio MSBs in reg
3626 	 */
3627 	__m128i v_prio_done;
3628 	{
3629 		static const uint8_t prio_mask[16] = {
3630 			0x00, 0x00, 0x00, 0x07 << 5,
3631 			0x00, 0x00, 0x00, 0x07 << 5,
3632 			0x00, 0x00, 0x00, 0x07 << 5,
3633 			0x00, 0x00, 0x00, 0x07 << 5,
3634 		};
3635 		__m128i v_prio_mask  = _mm_loadu_si128(
3636 						(const __m128i *)prio_mask);
3637 		__m128i v_prio_shifted = _mm_slli_epi32(v_qe_meta, 3);
3638 		v_prio_done = _mm_and_si128(v_prio_shifted, v_prio_mask);
3639 	}
3640 
3641 	/* Event Sub/Type handling:
3642 	 * we want to keep the lower 12 bits of each QE. Shift up by 20 bits
3643 	 * to get the sub/ev type data into rte_event location, clearing the
3644 	 * lower 20 bits in the process.
3645 	 */
3646 	__m128i v_types_done;
3647 	{
3648 		static const uint8_t event_mask[16] = {
3649 			0x0f, 0x00, 0x00, 0x00,
3650 			0x0f, 0x00, 0x00, 0x00,
3651 			0x0f, 0x00, 0x00, 0x00,
3652 			0x0f, 0x00, 0x00, 0x00,
3653 		};
3654 		static const uint8_t sub_event_mask[16] = {
3655 			0xff, 0x00, 0x00, 0x00,
3656 			0xff, 0x00, 0x00, 0x00,
3657 			0xff, 0x00, 0x00, 0x00,
3658 			0xff, 0x00, 0x00, 0x00,
3659 		};
3660 		static const uint8_t flow_mask[16] = {
3661 			0xff, 0xff, 0x00, 0x00,
3662 			0xff, 0xff, 0x00, 0x00,
3663 			0xff, 0xff, 0x00, 0x00,
3664 			0xff, 0xff, 0x00, 0x00,
3665 		};
3666 		__m128i v_event_mask  = _mm_loadu_si128(
3667 					(const __m128i *)event_mask);
3668 		__m128i v_sub_event_mask  = _mm_loadu_si128(
3669 					(const __m128i *)sub_event_mask);
3670 		__m128i v_flow_mask  = _mm_loadu_si128(
3671 				       (const __m128i *)flow_mask);
3672 		__m128i v_sub = _mm_srli_epi32(v_qe_meta, 8);
3673 		v_sub = _mm_and_si128(v_sub, v_sub_event_mask);
3674 		__m128i v_type = _mm_and_si128(v_qe_meta, v_event_mask);
3675 		v_type = _mm_slli_epi32(v_type, 8);
3676 		v_types_done = _mm_or_si128(v_type, v_sub);
3677 		v_types_done = _mm_slli_epi32(v_types_done, 20);
3678 		__m128i v_flow = _mm_and_si128(v_qe_status, v_flow_mask);
3679 		v_types_done = _mm_or_si128(v_types_done, v_flow);
3680 	}
3681 
3682 	/* Combine QID, Sched and Prio fields, then Shift >> 8 bits to align
3683 	 * with the rte_event, allowing unpacks to move/blend with payload.
3684 	 */
3685 	__m128i v_q_s_p_done;
3686 	{
3687 		__m128i v_qid_sched = _mm_or_si128(v_qid_done, v_sched_done);
3688 		__m128i v_q_s_prio = _mm_or_si128(v_qid_sched, v_prio_done);
3689 		v_q_s_p_done = _mm_srli_epi32(v_q_s_prio, 8);
3690 	}
3691 
3692 	__m128i v_unpk_ev_23, v_unpk_ev_01, v_ev_2, v_ev_3, v_ev_0, v_ev_1;
3693 
3694 	/* Unpack evs into u64 metadata, then indiv events */
3695 	v_unpk_ev_23 = _mm_unpackhi_epi32(v_types_done, v_q_s_p_done);
3696 	v_unpk_ev_01 = _mm_unpacklo_epi32(v_types_done, v_q_s_p_done);
3697 
3698 	switch (valid_events) {
3699 	case 4:
3700 		v_ev_3 = _mm_blend_epi16(v_unpk_ev_23, v_qe_3, 0x0F);
3701 		v_ev_3 = _mm_alignr_epi8(v_ev_3, v_ev_3, 8);
3702 		_mm_storeu_si128((__m128i *)&events[3], v_ev_3);
3703 		DLB2_INC_STAT(qm_port->ev_port->stats.rx_sched_cnt[hw_sched3],
3704 			      1);
3705 		/* fallthrough */
3706 	case 3:
3707 		v_ev_2 = _mm_unpacklo_epi64(v_unpk_ev_23, v_qe_2);
3708 		_mm_storeu_si128((__m128i *)&events[2], v_ev_2);
3709 		DLB2_INC_STAT(qm_port->ev_port->stats.rx_sched_cnt[hw_sched2],
3710 			      1);
3711 		/* fallthrough */
3712 	case 2:
3713 		v_ev_1 = _mm_blend_epi16(v_unpk_ev_01, v_qe_1, 0x0F);
3714 		v_ev_1 = _mm_alignr_epi8(v_ev_1, v_ev_1, 8);
3715 		_mm_storeu_si128((__m128i *)&events[1], v_ev_1);
3716 		DLB2_INC_STAT(qm_port->ev_port->stats.rx_sched_cnt[hw_sched1],
3717 			      1);
3718 		/* fallthrough */
3719 	case 1:
3720 		v_ev_0 = _mm_unpacklo_epi64(v_unpk_ev_01, v_qe_0);
3721 		_mm_storeu_si128((__m128i *)&events[0], v_ev_0);
3722 		DLB2_INC_STAT(qm_port->ev_port->stats.rx_sched_cnt[hw_sched0],
3723 			      1);
3724 	}
3725 }
3726 
3727 static __rte_always_inline int
3728 dlb2_recv_qe_sparse_vec(struct dlb2_port *qm_port, void *events,
3729 			uint32_t max_events)
3730 {
3731 	/* Using unmasked idx for perf, and masking manually */
3732 	uint16_t idx = qm_port->cq_idx_unmasked;
3733 	volatile struct dlb2_dequeue_qe *cq_addr;
3734 
3735 	cq_addr = dlb2_port[qm_port->id][PORT_TYPE(qm_port)].cq_base;
3736 
3737 	uintptr_t qe_ptr_3 = (uintptr_t)&cq_addr[(idx + 12) &
3738 						 qm_port->cq_depth_mask];
3739 	uintptr_t qe_ptr_2 = (uintptr_t)&cq_addr[(idx +  8) &
3740 						 qm_port->cq_depth_mask];
3741 	uintptr_t qe_ptr_1 = (uintptr_t)&cq_addr[(idx +  4) &
3742 						 qm_port->cq_depth_mask];
3743 	uintptr_t qe_ptr_0 = (uintptr_t)&cq_addr[(idx +  0) &
3744 						 qm_port->cq_depth_mask];
3745 
3746 	/* Load QEs from CQ: use compiler barriers to avoid load reordering */
3747 	__m128i v_qe_3 = _mm_loadu_si128((const __m128i *)qe_ptr_3);
3748 	rte_compiler_barrier();
3749 	__m128i v_qe_2 = _mm_loadu_si128((const __m128i *)qe_ptr_2);
3750 	rte_compiler_barrier();
3751 	__m128i v_qe_1 = _mm_loadu_si128((const __m128i *)qe_ptr_1);
3752 	rte_compiler_barrier();
3753 	__m128i v_qe_0 = _mm_loadu_si128((const __m128i *)qe_ptr_0);
3754 
3755 	/* Generate the pkt_shuffle mask;
3756 	 * - Avoids load in otherwise load-heavy section of code
3757 	 * - Moves bytes 3,7,11,15 (gen bit bytes) to LSB bytes in XMM
3758 	 */
3759 	const uint32_t stat_shuf_bytes = (15 << 24) | (11 << 16) | (7 << 8) | 3;
3760 	__m128i v_zeros = _mm_setzero_si128();
3761 	__m128i v_ffff = _mm_cmpeq_epi8(v_zeros, v_zeros);
3762 	__m128i v_stat_shuf_mask = _mm_insert_epi32(v_ffff, stat_shuf_bytes, 0);
3763 
3764 	/* Extract u32 components required from the QE
3765 	 * - QE[64 to 95 ] for metadata (qid, sched, prio, event type, ...)
3766 	 * - QE[96 to 127] for status (cq gen bit, error)
3767 	 *
3768 	 * Note that stage 1 of the unpacking is re-used for both u32 extracts
3769 	 */
3770 	__m128i v_qe_02 = _mm_unpackhi_epi32(v_qe_0, v_qe_2);
3771 	__m128i v_qe_13 = _mm_unpackhi_epi32(v_qe_1, v_qe_3);
3772 	__m128i v_qe_status = _mm_unpackhi_epi32(v_qe_02, v_qe_13);
3773 	__m128i v_qe_meta   = _mm_unpacklo_epi32(v_qe_02, v_qe_13);
3774 
3775 	/* Status byte (gen_bit, error) handling:
3776 	 * - Shuffle to lanes 0,1,2,3, clear all others
3777 	 * - Shift right by 7 for gen bit to MSB, movemask to scalar
3778 	 * - Shift right by 2 for error bit to MSB, movemask to scalar
3779 	 */
3780 	__m128i v_qe_shuffled = _mm_shuffle_epi8(v_qe_status, v_stat_shuf_mask);
3781 	__m128i v_qes_shift_gen_bit = _mm_slli_epi32(v_qe_shuffled, 7);
3782 	int32_t qe_gen_bits = _mm_movemask_epi8(v_qes_shift_gen_bit) & 0xf;
3783 
3784 	/* Expected vs Reality of QE Gen bits
3785 	 * - cq_rolling_mask provides expected bits
3786 	 * - QE loads, unpacks/shuffle and movemask provides reality
3787 	 * - XOR of the two gives bitmask of new packets
3788 	 * - POPCNT to get the number of new events
3789 	 */
3790 	uint64_t rolling = qm_port->cq_rolling_mask & 0xF;
3791 	uint64_t qe_xor_bits = (qe_gen_bits ^ rolling);
3792 	uint32_t count_new = __builtin_popcount(qe_xor_bits);
3793 	count_new = RTE_MIN(count_new, max_events);
3794 	if (!count_new)
3795 		return 0;
3796 
3797 	/* emulate a 128 bit rotate using 2x 64-bit numbers and bit-shifts */
3798 
3799 	uint64_t m_rshift = qm_port->cq_rolling_mask >> count_new;
3800 	uint64_t m_lshift = qm_port->cq_rolling_mask << (64 - count_new);
3801 	uint64_t m2_rshift = qm_port->cq_rolling_mask_2 >> count_new;
3802 	uint64_t m2_lshift = qm_port->cq_rolling_mask_2 << (64 - count_new);
3803 
3804 	/* shifted out of m2 into MSB of m */
3805 	qm_port->cq_rolling_mask = (m_rshift | m2_lshift);
3806 
3807 	/* shifted out of m "looped back" into MSB of m2 */
3808 	qm_port->cq_rolling_mask_2 = (m2_rshift | m_lshift);
3809 
3810 	/* Prefetch the next QEs - should run as IPC instead of cycles */
3811 	rte_prefetch0(&cq_addr[(idx + 16) & qm_port->cq_depth_mask]);
3812 	rte_prefetch0(&cq_addr[(idx + 20) & qm_port->cq_depth_mask]);
3813 	rte_prefetch0(&cq_addr[(idx + 24) & qm_port->cq_depth_mask]);
3814 	rte_prefetch0(&cq_addr[(idx + 28) & qm_port->cq_depth_mask]);
3815 
3816 	/* Convert QEs from XMM regs to events and store events directly */
3817 	_process_deq_qes_vec_impl(qm_port, events, v_qe_3, v_qe_2, v_qe_1,
3818 				  v_qe_0, v_qe_meta, v_qe_status, count_new);
3819 
3820 	return count_new;
3821 }
3822 
3823 static inline void
3824 dlb2_inc_cq_idx(struct dlb2_port *qm_port, int cnt)
3825 {
3826 	uint16_t idx = qm_port->cq_idx_unmasked + cnt;
3827 
3828 	qm_port->cq_idx_unmasked = idx;
3829 	qm_port->cq_idx = idx & qm_port->cq_depth_mask;
3830 	qm_port->gen_bit = (~(idx >> qm_port->gen_bit_shift)) & 0x1;
3831 }
3832 
3833 static inline int16_t
3834 dlb2_hw_dequeue_sparse(struct dlb2_eventdev *dlb2,
3835 		       struct dlb2_eventdev_port *ev_port,
3836 		       struct rte_event *events,
3837 		       uint16_t max_num,
3838 		       uint64_t dequeue_timeout_ticks)
3839 {
3840 	uint64_t start_ticks = 0ULL;
3841 	struct dlb2_port *qm_port;
3842 	int num = 0;
3843 	bool use_scalar;
3844 	uint64_t timeout;
3845 
3846 	qm_port = &ev_port->qm_port;
3847 	use_scalar = qm_port->use_scalar;
3848 
3849 	if (!dlb2->global_dequeue_wait)
3850 		timeout = dequeue_timeout_ticks;
3851 	else
3852 		timeout = dlb2->global_dequeue_wait_ticks;
3853 
3854 	start_ticks = rte_get_timer_cycles();
3855 
3856 	use_scalar = use_scalar || (max_num & 0x3);
3857 
3858 	while (num < max_num) {
3859 		struct dlb2_dequeue_qe qes[DLB2_NUM_QES_PER_CACHE_LINE];
3860 		int num_avail;
3861 		if (use_scalar) {
3862 			num_avail = dlb2_recv_qe_sparse(qm_port, qes);
3863 			num_avail = RTE_MIN(num_avail, max_num - num);
3864 			dlb2_inc_cq_idx(qm_port, num_avail << 2);
3865 			if (num_avail == DLB2_NUM_QES_PER_CACHE_LINE)
3866 				num += dlb2_process_dequeue_four_qes(ev_port,
3867 								  qm_port,
3868 								  &events[num],
3869 								  &qes[0]);
3870 			else if (num_avail)
3871 				num += dlb2_process_dequeue_qes(ev_port,
3872 								qm_port,
3873 								&events[num],
3874 								&qes[0],
3875 								num_avail);
3876 		} else { /* !use_scalar */
3877 			num_avail = dlb2_recv_qe_sparse_vec(qm_port,
3878 							    &events[num],
3879 							    max_num - num);
3880 			num += num_avail;
3881 			dlb2_inc_cq_idx(qm_port, num_avail << 2);
3882 			DLB2_INC_STAT(ev_port->stats.traffic.rx_ok, num_avail);
3883 		}
3884 		if (!num_avail) {
3885 			if (num > 0)
3886 				break;
3887 			else if (dlb2_dequeue_wait(dlb2, ev_port, qm_port,
3888 						   timeout, start_ticks))
3889 				break;
3890 		}
3891 	}
3892 
3893 	qm_port->owed_tokens += num;
3894 
3895 	if (num) {
3896 		if (qm_port->token_pop_mode == AUTO_POP)
3897 			dlb2_consume_qe_immediate(qm_port, num);
3898 
3899 		ev_port->outstanding_releases += num;
3900 
3901 		dlb2_port_credits_inc(qm_port, num);
3902 	}
3903 
3904 	return num;
3905 }
3906 
3907 static __rte_always_inline int
3908 dlb2_recv_qe(struct dlb2_port *qm_port, struct dlb2_dequeue_qe *qe,
3909 	     uint8_t *offset)
3910 {
3911 	uint8_t xor_mask[2][4] = { {0x0F, 0x0E, 0x0C, 0x08},
3912 				   {0x00, 0x01, 0x03, 0x07} };
3913 	uint8_t and_mask[4] = {0x0F, 0x0E, 0x0C, 0x08};
3914 	volatile struct dlb2_dequeue_qe *cq_addr;
3915 	__m128i *qes = (__m128i *)qe;
3916 	uint64_t *cache_line_base;
3917 	uint8_t gen_bits;
3918 
3919 	cq_addr = dlb2_port[qm_port->id][PORT_TYPE(qm_port)].cq_base;
3920 	cq_addr = &cq_addr[qm_port->cq_idx];
3921 
3922 	cache_line_base = (void *)(((uintptr_t)cq_addr) & ~0x3F);
3923 	*offset = ((uintptr_t)cq_addr & 0x30) >> 4;
3924 
3925 	/* Load the next CQ cache line from memory. Pack these reads as tight
3926 	 * as possible to reduce the chance that DLB invalidates the line while
3927 	 * the CPU is reading it. Read the cache line backwards to ensure that
3928 	 * if QE[N] (N > 0) is valid, then QEs[0:N-1] are too.
3929 	 *
3930 	 * (Valid QEs start at &qe[offset])
3931 	 */
3932 	qes[3] = _mm_load_si128((__m128i *)&cache_line_base[6]);
3933 	qes[2] = _mm_load_si128((__m128i *)&cache_line_base[4]);
3934 	qes[1] = _mm_load_si128((__m128i *)&cache_line_base[2]);
3935 	qes[0] = _mm_load_si128((__m128i *)&cache_line_base[0]);
3936 
3937 	/* Evict the cache line ASAP */
3938 	rte_cldemote(cache_line_base);
3939 
3940 	/* Extract and combine the gen bits */
3941 	gen_bits = ((_mm_extract_epi8(qes[0], 15) & 0x1) << 0) |
3942 		   ((_mm_extract_epi8(qes[1], 15) & 0x1) << 1) |
3943 		   ((_mm_extract_epi8(qes[2], 15) & 0x1) << 2) |
3944 		   ((_mm_extract_epi8(qes[3], 15) & 0x1) << 3);
3945 
3946 	/* XOR the combined bits such that a 1 represents a valid QE */
3947 	gen_bits ^= xor_mask[qm_port->gen_bit][*offset];
3948 
3949 	/* Mask off gen bits we don't care about */
3950 	gen_bits &= and_mask[*offset];
3951 
3952 	return __builtin_popcount(gen_bits);
3953 }
3954 
3955 static inline int16_t
3956 dlb2_hw_dequeue(struct dlb2_eventdev *dlb2,
3957 		struct dlb2_eventdev_port *ev_port,
3958 		struct rte_event *events,
3959 		uint16_t max_num,
3960 		uint64_t dequeue_timeout_ticks)
3961 {
3962 	uint64_t timeout;
3963 	uint64_t start_ticks = 0ULL;
3964 	struct dlb2_port *qm_port;
3965 	int num = 0;
3966 
3967 	qm_port = &ev_port->qm_port;
3968 
3969 	/* We have a special implementation for waiting. Wait can be:
3970 	 * 1) no waiting at all
3971 	 * 2) busy poll only
3972 	 * 3) wait for interrupt. If wakeup and poll time
3973 	 * has expired, then return to caller
3974 	 * 4) umonitor/umwait repeatedly up to poll time
3975 	 */
3976 
3977 	/* If configured for per dequeue wait, then use wait value provided
3978 	 * to this API. Otherwise we must use the global
3979 	 * value from eventdev config time.
3980 	 */
3981 	if (!dlb2->global_dequeue_wait)
3982 		timeout = dequeue_timeout_ticks;
3983 	else
3984 		timeout = dlb2->global_dequeue_wait_ticks;
3985 
3986 	start_ticks = rte_get_timer_cycles();
3987 
3988 	while (num < max_num) {
3989 		struct dlb2_dequeue_qe qes[DLB2_NUM_QES_PER_CACHE_LINE];
3990 		uint8_t offset;
3991 		int num_avail;
3992 
3993 		/* Copy up to 4 QEs from the current cache line into qes */
3994 		num_avail = dlb2_recv_qe(qm_port, qes, &offset);
3995 
3996 		/* But don't process more than the user requested */
3997 		num_avail = RTE_MIN(num_avail, max_num - num);
3998 
3999 		dlb2_inc_cq_idx(qm_port, num_avail);
4000 
4001 		if (num_avail == DLB2_NUM_QES_PER_CACHE_LINE)
4002 			num += dlb2_process_dequeue_four_qes(ev_port,
4003 							     qm_port,
4004 							     &events[num],
4005 							     &qes[offset]);
4006 		else if (num_avail)
4007 			num += dlb2_process_dequeue_qes(ev_port,
4008 							qm_port,
4009 							&events[num],
4010 							&qes[offset],
4011 							num_avail);
4012 		else if ((timeout == 0) || (num > 0))
4013 			/* Not waiting in any form, or 1+ events received? */
4014 			break;
4015 		else if (dlb2_dequeue_wait(dlb2, ev_port, qm_port,
4016 					   timeout, start_ticks))
4017 			break;
4018 	}
4019 
4020 	qm_port->owed_tokens += num;
4021 
4022 	if (num) {
4023 		if (qm_port->token_pop_mode == AUTO_POP)
4024 			dlb2_consume_qe_immediate(qm_port, num);
4025 
4026 		ev_port->outstanding_releases += num;
4027 
4028 		dlb2_port_credits_inc(qm_port, num);
4029 	}
4030 
4031 	return num;
4032 }
4033 
4034 static uint16_t
4035 dlb2_event_dequeue_burst(void *event_port, struct rte_event *ev, uint16_t num,
4036 			 uint64_t wait)
4037 {
4038 	struct dlb2_eventdev_port *ev_port = event_port;
4039 	struct dlb2_port *qm_port = &ev_port->qm_port;
4040 	struct dlb2_eventdev *dlb2 = ev_port->dlb2;
4041 	uint16_t cnt;
4042 
4043 	RTE_ASSERT(ev_port->setup_done);
4044 	RTE_ASSERT(ev != NULL);
4045 
4046 	if (ev_port->implicit_release && ev_port->outstanding_releases > 0) {
4047 		uint16_t out_rels = ev_port->outstanding_releases;
4048 
4049 		dlb2_event_release(dlb2, ev_port->id, out_rels);
4050 
4051 		DLB2_INC_STAT(ev_port->stats.tx_implicit_rel, out_rels);
4052 	}
4053 
4054 	if (qm_port->token_pop_mode == DEFERRED_POP && qm_port->owed_tokens)
4055 		dlb2_consume_qe_immediate(qm_port, qm_port->owed_tokens);
4056 
4057 	cnt = dlb2_hw_dequeue(dlb2, ev_port, ev, num, wait);
4058 
4059 	DLB2_INC_STAT(ev_port->stats.traffic.total_polls, 1);
4060 	DLB2_INC_STAT(ev_port->stats.traffic.zero_polls, ((cnt == 0) ? 1 : 0));
4061 
4062 	return cnt;
4063 }
4064 
4065 static uint16_t
4066 dlb2_event_dequeue(void *event_port, struct rte_event *ev, uint64_t wait)
4067 {
4068 	return dlb2_event_dequeue_burst(event_port, ev, 1, wait);
4069 }
4070 
4071 static uint16_t
4072 dlb2_event_dequeue_burst_sparse(void *event_port, struct rte_event *ev,
4073 				uint16_t num, uint64_t wait)
4074 {
4075 	struct dlb2_eventdev_port *ev_port = event_port;
4076 	struct dlb2_port *qm_port = &ev_port->qm_port;
4077 	struct dlb2_eventdev *dlb2 = ev_port->dlb2;
4078 	uint16_t cnt;
4079 
4080 	RTE_ASSERT(ev_port->setup_done);
4081 	RTE_ASSERT(ev != NULL);
4082 
4083 	if (ev_port->implicit_release && ev_port->outstanding_releases > 0) {
4084 		uint16_t out_rels = ev_port->outstanding_releases;
4085 
4086 		dlb2_event_release(dlb2, ev_port->id, out_rels);
4087 
4088 		DLB2_INC_STAT(ev_port->stats.tx_implicit_rel, out_rels);
4089 	}
4090 
4091 	if (qm_port->token_pop_mode == DEFERRED_POP && qm_port->owed_tokens)
4092 		dlb2_consume_qe_immediate(qm_port, qm_port->owed_tokens);
4093 
4094 	cnt = dlb2_hw_dequeue_sparse(dlb2, ev_port, ev, num, wait);
4095 
4096 	DLB2_INC_STAT(ev_port->stats.traffic.total_polls, 1);
4097 	DLB2_INC_STAT(ev_port->stats.traffic.zero_polls, ((cnt == 0) ? 1 : 0));
4098 	return cnt;
4099 }
4100 
4101 static uint16_t
4102 dlb2_event_dequeue_sparse(void *event_port, struct rte_event *ev,
4103 			  uint64_t wait)
4104 {
4105 	return dlb2_event_dequeue_burst_sparse(event_port, ev, 1, wait);
4106 }
4107 
4108 static void
4109 dlb2_flush_port(struct rte_eventdev *dev, int port_id)
4110 {
4111 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
4112 	eventdev_stop_flush_t flush;
4113 	struct rte_event ev;
4114 	uint8_t dev_id;
4115 	void *arg;
4116 	int i;
4117 
4118 	flush = dev->dev_ops->dev_stop_flush;
4119 	dev_id = dev->data->dev_id;
4120 	arg = dev->data->dev_stop_flush_arg;
4121 
4122 	while (rte_event_dequeue_burst(dev_id, port_id, &ev, 1, 0)) {
4123 		if (flush)
4124 			flush(dev_id, ev, arg);
4125 
4126 		if (dlb2->ev_ports[port_id].qm_port.is_directed)
4127 			continue;
4128 
4129 		ev.op = RTE_EVENT_OP_RELEASE;
4130 
4131 		rte_event_enqueue_burst(dev_id, port_id, &ev, 1);
4132 	}
4133 
4134 	/* Enqueue any additional outstanding releases */
4135 	ev.op = RTE_EVENT_OP_RELEASE;
4136 
4137 	for (i = dlb2->ev_ports[port_id].outstanding_releases; i > 0; i--)
4138 		rte_event_enqueue_burst(dev_id, port_id, &ev, 1);
4139 }
4140 
4141 static uint32_t
4142 dlb2_get_ldb_queue_depth(struct dlb2_eventdev *dlb2,
4143 			 struct dlb2_eventdev_queue *queue)
4144 {
4145 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
4146 	struct dlb2_get_ldb_queue_depth_args cfg;
4147 	int ret;
4148 
4149 	cfg.queue_id = queue->qm_queue.id;
4150 
4151 	ret = dlb2_iface_get_ldb_queue_depth(handle, &cfg);
4152 	if (ret < 0) {
4153 		DLB2_LOG_ERR("dlb2: get_ldb_queue_depth ret=%d (driver status: %s)\n",
4154 			     ret, dlb2_error_strings[cfg.response.status]);
4155 		return ret;
4156 	}
4157 
4158 	return cfg.response.id;
4159 }
4160 
4161 static uint32_t
4162 dlb2_get_dir_queue_depth(struct dlb2_eventdev *dlb2,
4163 			 struct dlb2_eventdev_queue *queue)
4164 {
4165 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
4166 	struct dlb2_get_dir_queue_depth_args cfg;
4167 	int ret;
4168 
4169 	cfg.queue_id = queue->qm_queue.id;
4170 
4171 	ret = dlb2_iface_get_dir_queue_depth(handle, &cfg);
4172 	if (ret < 0) {
4173 		DLB2_LOG_ERR("dlb2: get_dir_queue_depth ret=%d (driver status: %s)\n",
4174 			     ret, dlb2_error_strings[cfg.response.status]);
4175 		return ret;
4176 	}
4177 
4178 	return cfg.response.id;
4179 }
4180 
4181 uint32_t
4182 dlb2_get_queue_depth(struct dlb2_eventdev *dlb2,
4183 		     struct dlb2_eventdev_queue *queue)
4184 {
4185 	if (queue->qm_queue.is_directed)
4186 		return dlb2_get_dir_queue_depth(dlb2, queue);
4187 	else
4188 		return dlb2_get_ldb_queue_depth(dlb2, queue);
4189 }
4190 
4191 static bool
4192 dlb2_queue_is_empty(struct dlb2_eventdev *dlb2,
4193 		    struct dlb2_eventdev_queue *queue)
4194 {
4195 	return dlb2_get_queue_depth(dlb2, queue) == 0;
4196 }
4197 
4198 static bool
4199 dlb2_linked_queues_empty(struct dlb2_eventdev *dlb2)
4200 {
4201 	int i;
4202 
4203 	for (i = 0; i < dlb2->num_queues; i++) {
4204 		if (dlb2->ev_queues[i].num_links == 0)
4205 			continue;
4206 		if (!dlb2_queue_is_empty(dlb2, &dlb2->ev_queues[i]))
4207 			return false;
4208 	}
4209 
4210 	return true;
4211 }
4212 
4213 static bool
4214 dlb2_queues_empty(struct dlb2_eventdev *dlb2)
4215 {
4216 	int i;
4217 
4218 	for (i = 0; i < dlb2->num_queues; i++) {
4219 		if (!dlb2_queue_is_empty(dlb2, &dlb2->ev_queues[i]))
4220 			return false;
4221 	}
4222 
4223 	return true;
4224 }
4225 
4226 static void
4227 dlb2_drain(struct rte_eventdev *dev)
4228 {
4229 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
4230 	struct dlb2_eventdev_port *ev_port = NULL;
4231 	uint8_t dev_id;
4232 	int i;
4233 
4234 	dev_id = dev->data->dev_id;
4235 
4236 	while (!dlb2_linked_queues_empty(dlb2)) {
4237 		/* Flush all the ev_ports, which will drain all their connected
4238 		 * queues.
4239 		 */
4240 		for (i = 0; i < dlb2->num_ports; i++)
4241 			dlb2_flush_port(dev, i);
4242 	}
4243 
4244 	/* The queues are empty, but there may be events left in the ports. */
4245 	for (i = 0; i < dlb2->num_ports; i++)
4246 		dlb2_flush_port(dev, i);
4247 
4248 	/* If the domain's queues are empty, we're done. */
4249 	if (dlb2_queues_empty(dlb2))
4250 		return;
4251 
4252 	/* Else, there must be at least one unlinked load-balanced queue.
4253 	 * Select a load-balanced port with which to drain the unlinked
4254 	 * queue(s).
4255 	 */
4256 	for (i = 0; i < dlb2->num_ports; i++) {
4257 		ev_port = &dlb2->ev_ports[i];
4258 
4259 		if (!ev_port->qm_port.is_directed)
4260 			break;
4261 	}
4262 
4263 	if (i == dlb2->num_ports) {
4264 		DLB2_LOG_ERR("internal error: no LDB ev_ports\n");
4265 		return;
4266 	}
4267 
4268 	rte_errno = 0;
4269 	rte_event_port_unlink(dev_id, ev_port->id, NULL, 0);
4270 
4271 	if (rte_errno) {
4272 		DLB2_LOG_ERR("internal error: failed to unlink ev_port %d\n",
4273 			     ev_port->id);
4274 		return;
4275 	}
4276 
4277 	for (i = 0; i < dlb2->num_queues; i++) {
4278 		uint8_t qid, prio;
4279 		int ret;
4280 
4281 		if (dlb2_queue_is_empty(dlb2, &dlb2->ev_queues[i]))
4282 			continue;
4283 
4284 		qid = i;
4285 		prio = 0;
4286 
4287 		/* Link the ev_port to the queue */
4288 		ret = rte_event_port_link(dev_id, ev_port->id, &qid, &prio, 1);
4289 		if (ret != 1) {
4290 			DLB2_LOG_ERR("internal error: failed to link ev_port %d to queue %d\n",
4291 				     ev_port->id, qid);
4292 			return;
4293 		}
4294 
4295 		/* Flush the queue */
4296 		while (!dlb2_queue_is_empty(dlb2, &dlb2->ev_queues[i]))
4297 			dlb2_flush_port(dev, ev_port->id);
4298 
4299 		/* Drain any extant events in the ev_port. */
4300 		dlb2_flush_port(dev, ev_port->id);
4301 
4302 		/* Unlink the ev_port from the queue */
4303 		ret = rte_event_port_unlink(dev_id, ev_port->id, &qid, 1);
4304 		if (ret != 1) {
4305 			DLB2_LOG_ERR("internal error: failed to unlink ev_port %d to queue %d\n",
4306 				     ev_port->id, qid);
4307 			return;
4308 		}
4309 	}
4310 }
4311 
4312 static void
4313 dlb2_eventdev_stop(struct rte_eventdev *dev)
4314 {
4315 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
4316 
4317 	rte_spinlock_lock(&dlb2->qm_instance.resource_lock);
4318 
4319 	if (dlb2->run_state == DLB2_RUN_STATE_STOPPED) {
4320 		DLB2_LOG_DBG("Internal error: already stopped\n");
4321 		rte_spinlock_unlock(&dlb2->qm_instance.resource_lock);
4322 		return;
4323 	} else if (dlb2->run_state != DLB2_RUN_STATE_STARTED) {
4324 		DLB2_LOG_ERR("Internal error: bad state %d for dev_stop\n",
4325 			     (int)dlb2->run_state);
4326 		rte_spinlock_unlock(&dlb2->qm_instance.resource_lock);
4327 		return;
4328 	}
4329 
4330 	dlb2->run_state = DLB2_RUN_STATE_STOPPING;
4331 
4332 	rte_spinlock_unlock(&dlb2->qm_instance.resource_lock);
4333 
4334 	dlb2_drain(dev);
4335 
4336 	dlb2->run_state = DLB2_RUN_STATE_STOPPED;
4337 }
4338 
4339 static int
4340 dlb2_eventdev_close(struct rte_eventdev *dev)
4341 {
4342 	dlb2_hw_reset_sched_domain(dev, false);
4343 
4344 	return 0;
4345 }
4346 
4347 static void
4348 dlb2_eventdev_queue_release(struct rte_eventdev *dev, uint8_t id)
4349 {
4350 	RTE_SET_USED(dev);
4351 	RTE_SET_USED(id);
4352 
4353 	/* This function intentionally left blank. */
4354 }
4355 
4356 static void
4357 dlb2_eventdev_port_release(void *port)
4358 {
4359 	struct dlb2_eventdev_port *ev_port = port;
4360 	struct dlb2_port *qm_port;
4361 
4362 	if (ev_port) {
4363 		qm_port = &ev_port->qm_port;
4364 		if (qm_port->config_state == DLB2_CONFIGURED)
4365 			dlb2_free_qe_mem(qm_port);
4366 	}
4367 }
4368 
4369 static int
4370 dlb2_eventdev_timeout_ticks(struct rte_eventdev *dev, uint64_t ns,
4371 			    uint64_t *timeout_ticks)
4372 {
4373 	RTE_SET_USED(dev);
4374 	uint64_t cycles_per_ns = rte_get_timer_hz() / 1E9;
4375 
4376 	*timeout_ticks = ns * cycles_per_ns;
4377 
4378 	return 0;
4379 }
4380 
4381 static void
4382 dlb2_entry_points_init(struct rte_eventdev *dev)
4383 {
4384 	struct dlb2_eventdev *dlb2;
4385 
4386 	/* Expose PMD's eventdev interface */
4387 	static struct rte_eventdev_ops dlb2_eventdev_entry_ops = {
4388 		.dev_infos_get    = dlb2_eventdev_info_get,
4389 		.dev_configure    = dlb2_eventdev_configure,
4390 		.dev_start        = dlb2_eventdev_start,
4391 		.dev_stop         = dlb2_eventdev_stop,
4392 		.dev_close        = dlb2_eventdev_close,
4393 		.queue_def_conf   = dlb2_eventdev_queue_default_conf_get,
4394 		.queue_setup      = dlb2_eventdev_queue_setup,
4395 		.queue_release    = dlb2_eventdev_queue_release,
4396 		.port_def_conf    = dlb2_eventdev_port_default_conf_get,
4397 		.port_setup       = dlb2_eventdev_port_setup,
4398 		.port_release     = dlb2_eventdev_port_release,
4399 		.port_link        = dlb2_eventdev_port_link,
4400 		.port_unlink      = dlb2_eventdev_port_unlink,
4401 		.port_unlinks_in_progress =
4402 				    dlb2_eventdev_port_unlinks_in_progress,
4403 		.timeout_ticks    = dlb2_eventdev_timeout_ticks,
4404 		.dump             = dlb2_eventdev_dump,
4405 		.xstats_get       = dlb2_eventdev_xstats_get,
4406 		.xstats_get_names = dlb2_eventdev_xstats_get_names,
4407 		.xstats_get_by_name = dlb2_eventdev_xstats_get_by_name,
4408 		.xstats_reset	    = dlb2_eventdev_xstats_reset,
4409 		.dev_selftest     = test_dlb2_eventdev,
4410 	};
4411 
4412 	/* Expose PMD's eventdev interface */
4413 
4414 	dev->dev_ops = &dlb2_eventdev_entry_ops;
4415 	dev->enqueue = dlb2_event_enqueue;
4416 	dev->enqueue_burst = dlb2_event_enqueue_burst;
4417 	dev->enqueue_new_burst = dlb2_event_enqueue_new_burst;
4418 	dev->enqueue_forward_burst = dlb2_event_enqueue_forward_burst;
4419 
4420 	dlb2 = dev->data->dev_private;
4421 	if (dlb2->poll_mode == DLB2_CQ_POLL_MODE_SPARSE) {
4422 		dev->dequeue = dlb2_event_dequeue_sparse;
4423 		dev->dequeue_burst = dlb2_event_dequeue_burst_sparse;
4424 	} else {
4425 		dev->dequeue = dlb2_event_dequeue;
4426 		dev->dequeue_burst = dlb2_event_dequeue_burst;
4427 	}
4428 }
4429 
4430 int
4431 dlb2_primary_eventdev_probe(struct rte_eventdev *dev,
4432 			    const char *name,
4433 			    struct dlb2_devargs *dlb2_args)
4434 {
4435 	struct dlb2_eventdev *dlb2;
4436 	int err, i;
4437 
4438 	dlb2 = dev->data->dev_private;
4439 
4440 	dlb2->event_dev = dev; /* backlink */
4441 
4442 	evdev_dlb2_default_info.driver_name = name;
4443 
4444 	dlb2->max_num_events_override = dlb2_args->max_num_events;
4445 	dlb2->num_dir_credits_override = dlb2_args->num_dir_credits_override;
4446 	dlb2->qm_instance.cos_id = dlb2_args->cos_id;
4447 	dlb2->poll_interval = dlb2_args->poll_interval;
4448 	dlb2->sw_credit_quanta = dlb2_args->sw_credit_quanta;
4449 	dlb2->default_depth_thresh = dlb2_args->default_depth_thresh;
4450 	dlb2->vector_opts_enabled = dlb2_args->vector_opts_enabled;
4451 
4452 	err = dlb2_iface_open(&dlb2->qm_instance, name);
4453 	if (err < 0) {
4454 		DLB2_LOG_ERR("could not open event hardware device, err=%d\n",
4455 			     err);
4456 		return err;
4457 	}
4458 
4459 	err = dlb2_iface_get_device_version(&dlb2->qm_instance,
4460 					    &dlb2->revision);
4461 	if (err < 0) {
4462 		DLB2_LOG_ERR("dlb2: failed to get the device version, err=%d\n",
4463 			     err);
4464 		return err;
4465 	}
4466 
4467 	err = dlb2_hw_query_resources(dlb2);
4468 	if (err) {
4469 		DLB2_LOG_ERR("get resources err=%d for %s\n",
4470 			     err, name);
4471 		return err;
4472 	}
4473 
4474 	dlb2_iface_hardware_init(&dlb2->qm_instance);
4475 
4476 	err = dlb2_iface_get_cq_poll_mode(&dlb2->qm_instance, &dlb2->poll_mode);
4477 	if (err < 0) {
4478 		DLB2_LOG_ERR("dlb2: failed to get the poll mode, err=%d\n",
4479 			     err);
4480 		return err;
4481 	}
4482 
4483 	/* Complete xtstats runtime initialization */
4484 	err = dlb2_xstats_init(dlb2);
4485 	if (err) {
4486 		DLB2_LOG_ERR("dlb2: failed to init xstats, err=%d\n", err);
4487 		return err;
4488 	}
4489 
4490 	/* Initialize each port's token pop mode */
4491 	for (i = 0; i < DLB2_MAX_NUM_PORTS(dlb2->version); i++)
4492 		dlb2->ev_ports[i].qm_port.token_pop_mode = AUTO_POP;
4493 
4494 	rte_spinlock_init(&dlb2->qm_instance.resource_lock);
4495 
4496 	dlb2_iface_low_level_io_init();
4497 
4498 	dlb2_entry_points_init(dev);
4499 
4500 	dlb2_init_queue_depth_thresholds(dlb2,
4501 					 dlb2_args->qid_depth_thresholds.val);
4502 
4503 	return 0;
4504 }
4505 
4506 int
4507 dlb2_secondary_eventdev_probe(struct rte_eventdev *dev,
4508 			      const char *name)
4509 {
4510 	struct dlb2_eventdev *dlb2;
4511 	int err;
4512 
4513 	dlb2 = dev->data->dev_private;
4514 
4515 	evdev_dlb2_default_info.driver_name = name;
4516 
4517 	err = dlb2_iface_open(&dlb2->qm_instance, name);
4518 	if (err < 0) {
4519 		DLB2_LOG_ERR("could not open event hardware device, err=%d\n",
4520 			     err);
4521 		return err;
4522 	}
4523 
4524 	err = dlb2_hw_query_resources(dlb2);
4525 	if (err) {
4526 		DLB2_LOG_ERR("get resources err=%d for %s\n",
4527 			     err, name);
4528 		return err;
4529 	}
4530 
4531 	dlb2_iface_low_level_io_init();
4532 
4533 	dlb2_entry_points_init(dev);
4534 
4535 	return 0;
4536 }
4537 
4538 int
4539 dlb2_parse_params(const char *params,
4540 		  const char *name,
4541 		  struct dlb2_devargs *dlb2_args,
4542 		  uint8_t version)
4543 {
4544 	int ret = 0;
4545 	static const char * const args[] = { NUMA_NODE_ARG,
4546 					     DLB2_MAX_NUM_EVENTS,
4547 					     DLB2_NUM_DIR_CREDITS,
4548 					     DEV_ID_ARG,
4549 					     DLB2_QID_DEPTH_THRESH_ARG,
4550 					     DLB2_COS_ARG,
4551 					     DLB2_POLL_INTERVAL_ARG,
4552 					     DLB2_SW_CREDIT_QUANTA_ARG,
4553 					     DLB2_DEPTH_THRESH_ARG,
4554 					     DLB2_VECTOR_OPTS_ENAB_ARG,
4555 					     NULL };
4556 
4557 	if (params != NULL && params[0] != '\0') {
4558 		struct rte_kvargs *kvlist = rte_kvargs_parse(params, args);
4559 
4560 		if (kvlist == NULL) {
4561 			RTE_LOG(INFO, PMD,
4562 				"Ignoring unsupported parameters when creating device '%s'\n",
4563 				name);
4564 		} else {
4565 			int ret = rte_kvargs_process(kvlist, NUMA_NODE_ARG,
4566 						     set_numa_node,
4567 						     &dlb2_args->socket_id);
4568 			if (ret != 0) {
4569 				DLB2_LOG_ERR("%s: Error parsing numa node parameter",
4570 					     name);
4571 				rte_kvargs_free(kvlist);
4572 				return ret;
4573 			}
4574 
4575 			ret = rte_kvargs_process(kvlist, DLB2_MAX_NUM_EVENTS,
4576 						 set_max_num_events,
4577 						 &dlb2_args->max_num_events);
4578 			if (ret != 0) {
4579 				DLB2_LOG_ERR("%s: Error parsing max_num_events parameter",
4580 					     name);
4581 				rte_kvargs_free(kvlist);
4582 				return ret;
4583 			}
4584 
4585 			if (version == DLB2_HW_V2) {
4586 				ret = rte_kvargs_process(kvlist,
4587 					DLB2_NUM_DIR_CREDITS,
4588 					set_num_dir_credits,
4589 					&dlb2_args->num_dir_credits_override);
4590 				if (ret != 0) {
4591 					DLB2_LOG_ERR("%s: Error parsing num_dir_credits parameter",
4592 						     name);
4593 					rte_kvargs_free(kvlist);
4594 					return ret;
4595 				}
4596 			}
4597 			ret = rte_kvargs_process(kvlist, DEV_ID_ARG,
4598 						 set_dev_id,
4599 						 &dlb2_args->dev_id);
4600 			if (ret != 0) {
4601 				DLB2_LOG_ERR("%s: Error parsing dev_id parameter",
4602 					     name);
4603 				rte_kvargs_free(kvlist);
4604 				return ret;
4605 			}
4606 
4607 			if (version == DLB2_HW_V2) {
4608 				ret = rte_kvargs_process(
4609 					kvlist,
4610 					DLB2_QID_DEPTH_THRESH_ARG,
4611 					set_qid_depth_thresh,
4612 					&dlb2_args->qid_depth_thresholds);
4613 			} else {
4614 				ret = rte_kvargs_process(
4615 					kvlist,
4616 					DLB2_QID_DEPTH_THRESH_ARG,
4617 					set_qid_depth_thresh_v2_5,
4618 					&dlb2_args->qid_depth_thresholds);
4619 			}
4620 			if (ret != 0) {
4621 				DLB2_LOG_ERR("%s: Error parsing qid_depth_thresh parameter",
4622 					     name);
4623 				rte_kvargs_free(kvlist);
4624 				return ret;
4625 			}
4626 
4627 			ret = rte_kvargs_process(kvlist, DLB2_COS_ARG,
4628 						 set_cos,
4629 						 &dlb2_args->cos_id);
4630 			if (ret != 0) {
4631 				DLB2_LOG_ERR("%s: Error parsing cos parameter",
4632 					     name);
4633 				rte_kvargs_free(kvlist);
4634 				return ret;
4635 			}
4636 
4637 			ret = rte_kvargs_process(kvlist, DLB2_POLL_INTERVAL_ARG,
4638 						 set_poll_interval,
4639 						 &dlb2_args->poll_interval);
4640 			if (ret != 0) {
4641 				DLB2_LOG_ERR("%s: Error parsing poll interval parameter",
4642 					     name);
4643 				rte_kvargs_free(kvlist);
4644 				return ret;
4645 			}
4646 
4647 			ret = rte_kvargs_process(kvlist,
4648 						 DLB2_SW_CREDIT_QUANTA_ARG,
4649 						 set_sw_credit_quanta,
4650 						 &dlb2_args->sw_credit_quanta);
4651 			if (ret != 0) {
4652 				DLB2_LOG_ERR("%s: Error parsing sw xredit quanta parameter",
4653 					     name);
4654 				rte_kvargs_free(kvlist);
4655 				return ret;
4656 			}
4657 
4658 			ret = rte_kvargs_process(kvlist, DLB2_DEPTH_THRESH_ARG,
4659 					set_default_depth_thresh,
4660 					&dlb2_args->default_depth_thresh);
4661 			if (ret != 0) {
4662 				DLB2_LOG_ERR("%s: Error parsing set depth thresh parameter",
4663 					     name);
4664 				rte_kvargs_free(kvlist);
4665 				return ret;
4666 			}
4667 
4668 			ret = rte_kvargs_process(kvlist,
4669 					DLB2_VECTOR_OPTS_ENAB_ARG,
4670 					set_vector_opts_enab,
4671 					&dlb2_args->vector_opts_enabled);
4672 			if (ret != 0) {
4673 				DLB2_LOG_ERR("%s: Error parsing vector opts enabled",
4674 					     name);
4675 				rte_kvargs_free(kvlist);
4676 				return ret;
4677 			}
4678 
4679 			rte_kvargs_free(kvlist);
4680 		}
4681 	}
4682 	return ret;
4683 }
4684 RTE_LOG_REGISTER_DEFAULT(eventdev_dlb2_log_level, NOTICE);
4685