xref: /dpdk/drivers/event/dlb2/dlb2.c (revision b19f366c)
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_disab(const char *key __rte_unused,
380 	const char *value,
381 	void *opaque)
382 {
383 	bool *dlb2_vector_opts_disabled = 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_disabled = true;
392 	else
393 		*dlb2_vector_opts_disabled = 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_disabled == true))
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_disabled == true))
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 static inline int
3158 dlb2_dequeue_wait(struct dlb2_eventdev *dlb2,
3159 		  struct dlb2_eventdev_port *ev_port,
3160 		  struct dlb2_port *qm_port,
3161 		  uint64_t timeout,
3162 		  uint64_t start_ticks)
3163 {
3164 	struct process_local_port_data *port_data;
3165 	uint64_t elapsed_ticks;
3166 
3167 	port_data = &dlb2_port[qm_port->id][PORT_TYPE(qm_port)];
3168 
3169 	elapsed_ticks = rte_get_timer_cycles() - start_ticks;
3170 
3171 	/* Wait/poll time expired */
3172 	if (elapsed_ticks >= timeout) {
3173 		return 1;
3174 	} else if (dlb2->umwait_allowed) {
3175 		struct rte_power_monitor_cond pmc;
3176 		volatile struct dlb2_dequeue_qe *cq_base;
3177 		union {
3178 			uint64_t raw_qe[2];
3179 			struct dlb2_dequeue_qe qe;
3180 		} qe_mask;
3181 		uint64_t expected_value;
3182 		volatile uint64_t *monitor_addr;
3183 
3184 		qe_mask.qe.cq_gen = 1; /* set mask */
3185 
3186 		cq_base = port_data->cq_base;
3187 		monitor_addr = (volatile uint64_t *)(volatile void *)
3188 			&cq_base[qm_port->cq_idx];
3189 		monitor_addr++; /* cq_gen bit is in second 64bit location */
3190 
3191 		if (qm_port->gen_bit)
3192 			expected_value = qe_mask.raw_qe[1];
3193 		else
3194 			expected_value = 0;
3195 
3196 		pmc.addr = monitor_addr;
3197 		pmc.val = expected_value;
3198 		pmc.mask = qe_mask.raw_qe[1];
3199 		pmc.size = sizeof(uint64_t);
3200 
3201 		rte_power_monitor(&pmc, timeout + start_ticks);
3202 
3203 		DLB2_INC_STAT(ev_port->stats.traffic.rx_umonitor_umwait, 1);
3204 	} else {
3205 		uint64_t poll_interval = dlb2->poll_interval;
3206 		uint64_t curr_ticks = rte_get_timer_cycles();
3207 		uint64_t init_ticks = curr_ticks;
3208 
3209 		while ((curr_ticks - start_ticks < timeout) &&
3210 		       (curr_ticks - init_ticks < poll_interval))
3211 			curr_ticks = rte_get_timer_cycles();
3212 	}
3213 
3214 	return 0;
3215 }
3216 
3217 static __rte_noinline int
3218 dlb2_process_dequeue_qes(struct dlb2_eventdev_port *ev_port,
3219 			 struct dlb2_port *qm_port,
3220 			 struct rte_event *events,
3221 			 struct dlb2_dequeue_qe *qes,
3222 			 int cnt)
3223 {
3224 	uint8_t *qid_mappings = qm_port->qid_mappings;
3225 	int i, num, evq_id;
3226 
3227 	for (i = 0, num = 0; i < cnt; i++) {
3228 		struct dlb2_dequeue_qe *qe = &qes[i];
3229 		int sched_type_map[DLB2_NUM_HW_SCHED_TYPES] = {
3230 			[DLB2_SCHED_ATOMIC] = RTE_SCHED_TYPE_ATOMIC,
3231 			[DLB2_SCHED_UNORDERED] = RTE_SCHED_TYPE_PARALLEL,
3232 			[DLB2_SCHED_ORDERED] = RTE_SCHED_TYPE_ORDERED,
3233 			[DLB2_SCHED_DIRECTED] = RTE_SCHED_TYPE_ATOMIC,
3234 		};
3235 
3236 		/* Fill in event information.
3237 		 * Note that flow_id must be embedded in the data by
3238 		 * the app, such as the mbuf RSS hash field if the data
3239 		 * buffer is a mbuf.
3240 		 */
3241 		if (unlikely(qe->error)) {
3242 			DLB2_LOG_ERR("QE error bit ON\n");
3243 			DLB2_INC_STAT(ev_port->stats.traffic.rx_drop, 1);
3244 			dlb2_consume_qe_immediate(qm_port, 1);
3245 			continue; /* Ignore */
3246 		}
3247 
3248 		events[num].u64 = qe->data;
3249 		events[num].flow_id = qe->flow_id;
3250 		events[num].priority = DLB2_TO_EV_PRIO((uint8_t)qe->priority);
3251 		events[num].event_type = qe->u.event_type.major;
3252 		events[num].sub_event_type = qe->u.event_type.sub;
3253 		events[num].sched_type = sched_type_map[qe->sched_type];
3254 		events[num].impl_opaque = qe->qid_depth;
3255 
3256 		/* qid not preserved for directed queues */
3257 		if (qm_port->is_directed)
3258 			evq_id = ev_port->link[0].queue_id;
3259 		else
3260 			evq_id = qid_mappings[qe->qid];
3261 
3262 		events[num].queue_id = evq_id;
3263 		DLB2_INC_STAT(
3264 			ev_port->stats.queue[evq_id].qid_depth[qe->qid_depth],
3265 			1);
3266 		DLB2_INC_STAT(ev_port->stats.rx_sched_cnt[qe->sched_type], 1);
3267 		num++;
3268 	}
3269 
3270 	DLB2_INC_STAT(ev_port->stats.traffic.rx_ok, num);
3271 
3272 	return num;
3273 }
3274 
3275 static inline int
3276 dlb2_process_dequeue_four_qes(struct dlb2_eventdev_port *ev_port,
3277 			      struct dlb2_port *qm_port,
3278 			      struct rte_event *events,
3279 			      struct dlb2_dequeue_qe *qes)
3280 {
3281 	int sched_type_map[] = {
3282 		[DLB2_SCHED_ATOMIC] = RTE_SCHED_TYPE_ATOMIC,
3283 		[DLB2_SCHED_UNORDERED] = RTE_SCHED_TYPE_PARALLEL,
3284 		[DLB2_SCHED_ORDERED] = RTE_SCHED_TYPE_ORDERED,
3285 		[DLB2_SCHED_DIRECTED] = RTE_SCHED_TYPE_ATOMIC,
3286 	};
3287 	const int num_events = DLB2_NUM_QES_PER_CACHE_LINE;
3288 	uint8_t *qid_mappings = qm_port->qid_mappings;
3289 	__m128i sse_evt[2];
3290 
3291 	/* In the unlikely case that any of the QE error bits are set, process
3292 	 * them one at a time.
3293 	 */
3294 	if (unlikely(qes[0].error || qes[1].error ||
3295 		     qes[2].error || qes[3].error))
3296 		return dlb2_process_dequeue_qes(ev_port, qm_port, events,
3297 						 qes, num_events);
3298 
3299 	events[0].u64 = qes[0].data;
3300 	events[1].u64 = qes[1].data;
3301 	events[2].u64 = qes[2].data;
3302 	events[3].u64 = qes[3].data;
3303 
3304 	/* Construct the metadata portion of two struct rte_events
3305 	 * in one 128b SSE register. Event metadata is constructed in the SSE
3306 	 * registers like so:
3307 	 * sse_evt[0][63:0]:   event[0]'s metadata
3308 	 * sse_evt[0][127:64]: event[1]'s metadata
3309 	 * sse_evt[1][63:0]:   event[2]'s metadata
3310 	 * sse_evt[1][127:64]: event[3]'s metadata
3311 	 */
3312 	sse_evt[0] = _mm_setzero_si128();
3313 	sse_evt[1] = _mm_setzero_si128();
3314 
3315 	/* Convert the hardware queue ID to an event queue ID and store it in
3316 	 * the metadata:
3317 	 * sse_evt[0][47:40]   = qid_mappings[qes[0].qid]
3318 	 * sse_evt[0][111:104] = qid_mappings[qes[1].qid]
3319 	 * sse_evt[1][47:40]   = qid_mappings[qes[2].qid]
3320 	 * sse_evt[1][111:104] = qid_mappings[qes[3].qid]
3321 	 */
3322 #define DLB_EVENT_QUEUE_ID_BYTE 5
3323 	sse_evt[0] = _mm_insert_epi8(sse_evt[0],
3324 				     qid_mappings[qes[0].qid],
3325 				     DLB_EVENT_QUEUE_ID_BYTE);
3326 	sse_evt[0] = _mm_insert_epi8(sse_evt[0],
3327 				     qid_mappings[qes[1].qid],
3328 				     DLB_EVENT_QUEUE_ID_BYTE + 8);
3329 	sse_evt[1] = _mm_insert_epi8(sse_evt[1],
3330 				     qid_mappings[qes[2].qid],
3331 				     DLB_EVENT_QUEUE_ID_BYTE);
3332 	sse_evt[1] = _mm_insert_epi8(sse_evt[1],
3333 				     qid_mappings[qes[3].qid],
3334 				     DLB_EVENT_QUEUE_ID_BYTE + 8);
3335 
3336 	/* Convert the hardware priority to an event priority and store it in
3337 	 * the metadata, while also returning the queue depth status
3338 	 * value captured by the hardware, storing it in impl_opaque, which can
3339 	 * be read by the application but not modified
3340 	 * sse_evt[0][55:48]   = DLB2_TO_EV_PRIO(qes[0].priority)
3341 	 * sse_evt[0][63:56]   = qes[0].qid_depth
3342 	 * sse_evt[0][119:112] = DLB2_TO_EV_PRIO(qes[1].priority)
3343 	 * sse_evt[0][127:120] = qes[1].qid_depth
3344 	 * sse_evt[1][55:48]   = DLB2_TO_EV_PRIO(qes[2].priority)
3345 	 * sse_evt[1][63:56]   = qes[2].qid_depth
3346 	 * sse_evt[1][119:112] = DLB2_TO_EV_PRIO(qes[3].priority)
3347 	 * sse_evt[1][127:120] = qes[3].qid_depth
3348 	 */
3349 #define DLB_EVENT_PRIO_IMPL_OPAQUE_WORD 3
3350 #define DLB_BYTE_SHIFT 8
3351 	sse_evt[0] =
3352 		_mm_insert_epi16(sse_evt[0],
3353 			DLB2_TO_EV_PRIO((uint8_t)qes[0].priority) |
3354 			(qes[0].qid_depth << DLB_BYTE_SHIFT),
3355 			DLB_EVENT_PRIO_IMPL_OPAQUE_WORD);
3356 	sse_evt[0] =
3357 		_mm_insert_epi16(sse_evt[0],
3358 			DLB2_TO_EV_PRIO((uint8_t)qes[1].priority) |
3359 			(qes[1].qid_depth << DLB_BYTE_SHIFT),
3360 			DLB_EVENT_PRIO_IMPL_OPAQUE_WORD + 4);
3361 	sse_evt[1] =
3362 		_mm_insert_epi16(sse_evt[1],
3363 			DLB2_TO_EV_PRIO((uint8_t)qes[2].priority) |
3364 			(qes[2].qid_depth << DLB_BYTE_SHIFT),
3365 			DLB_EVENT_PRIO_IMPL_OPAQUE_WORD);
3366 	sse_evt[1] =
3367 		_mm_insert_epi16(sse_evt[1],
3368 			DLB2_TO_EV_PRIO((uint8_t)qes[3].priority) |
3369 			(qes[3].qid_depth << DLB_BYTE_SHIFT),
3370 			DLB_EVENT_PRIO_IMPL_OPAQUE_WORD + 4);
3371 
3372 	/* Write the event type, sub event type, and flow_id to the event
3373 	 * metadata.
3374 	 * sse_evt[0][31:0]   = qes[0].flow_id |
3375 	 *			qes[0].u.event_type.major << 28 |
3376 	 *			qes[0].u.event_type.sub << 20;
3377 	 * sse_evt[0][95:64]  = qes[1].flow_id |
3378 	 *			qes[1].u.event_type.major << 28 |
3379 	 *			qes[1].u.event_type.sub << 20;
3380 	 * sse_evt[1][31:0]   = qes[2].flow_id |
3381 	 *			qes[2].u.event_type.major << 28 |
3382 	 *			qes[2].u.event_type.sub << 20;
3383 	 * sse_evt[1][95:64]  = qes[3].flow_id |
3384 	 *			qes[3].u.event_type.major << 28 |
3385 	 *			qes[3].u.event_type.sub << 20;
3386 	 */
3387 #define DLB_EVENT_EV_TYPE_DW 0
3388 #define DLB_EVENT_EV_TYPE_SHIFT 28
3389 #define DLB_EVENT_SUB_EV_TYPE_SHIFT 20
3390 	sse_evt[0] = _mm_insert_epi32(sse_evt[0],
3391 			qes[0].flow_id |
3392 			qes[0].u.event_type.major << DLB_EVENT_EV_TYPE_SHIFT |
3393 			qes[0].u.event_type.sub <<  DLB_EVENT_SUB_EV_TYPE_SHIFT,
3394 			DLB_EVENT_EV_TYPE_DW);
3395 	sse_evt[0] = _mm_insert_epi32(sse_evt[0],
3396 			qes[1].flow_id |
3397 			qes[1].u.event_type.major << DLB_EVENT_EV_TYPE_SHIFT |
3398 			qes[1].u.event_type.sub <<  DLB_EVENT_SUB_EV_TYPE_SHIFT,
3399 			DLB_EVENT_EV_TYPE_DW + 2);
3400 	sse_evt[1] = _mm_insert_epi32(sse_evt[1],
3401 			qes[2].flow_id |
3402 			qes[2].u.event_type.major << DLB_EVENT_EV_TYPE_SHIFT |
3403 			qes[2].u.event_type.sub <<  DLB_EVENT_SUB_EV_TYPE_SHIFT,
3404 			DLB_EVENT_EV_TYPE_DW);
3405 	sse_evt[1] = _mm_insert_epi32(sse_evt[1],
3406 			qes[3].flow_id |
3407 			qes[3].u.event_type.major << DLB_EVENT_EV_TYPE_SHIFT  |
3408 			qes[3].u.event_type.sub << DLB_EVENT_SUB_EV_TYPE_SHIFT,
3409 			DLB_EVENT_EV_TYPE_DW + 2);
3410 
3411 	/* Write the sched type to the event metadata. 'op' and 'rsvd' are not
3412 	 * set:
3413 	 * sse_evt[0][39:32]  = sched_type_map[qes[0].sched_type] << 6
3414 	 * sse_evt[0][103:96] = sched_type_map[qes[1].sched_type] << 6
3415 	 * sse_evt[1][39:32]  = sched_type_map[qes[2].sched_type] << 6
3416 	 * sse_evt[1][103:96] = sched_type_map[qes[3].sched_type] << 6
3417 	 */
3418 #define DLB_EVENT_SCHED_TYPE_BYTE 4
3419 #define DLB_EVENT_SCHED_TYPE_SHIFT 6
3420 	sse_evt[0] = _mm_insert_epi8(sse_evt[0],
3421 		sched_type_map[qes[0].sched_type] << DLB_EVENT_SCHED_TYPE_SHIFT,
3422 		DLB_EVENT_SCHED_TYPE_BYTE);
3423 	sse_evt[0] = _mm_insert_epi8(sse_evt[0],
3424 		sched_type_map[qes[1].sched_type] << DLB_EVENT_SCHED_TYPE_SHIFT,
3425 		DLB_EVENT_SCHED_TYPE_BYTE + 8);
3426 	sse_evt[1] = _mm_insert_epi8(sse_evt[1],
3427 		sched_type_map[qes[2].sched_type] << DLB_EVENT_SCHED_TYPE_SHIFT,
3428 		DLB_EVENT_SCHED_TYPE_BYTE);
3429 	sse_evt[1] = _mm_insert_epi8(sse_evt[1],
3430 		sched_type_map[qes[3].sched_type] << DLB_EVENT_SCHED_TYPE_SHIFT,
3431 		DLB_EVENT_SCHED_TYPE_BYTE + 8);
3432 
3433 	/* Store the metadata to the event (use the double-precision
3434 	 * _mm_storeh_pd because there is no integer function for storing the
3435 	 * upper 64b):
3436 	 * events[0].event = sse_evt[0][63:0]
3437 	 * events[1].event = sse_evt[0][127:64]
3438 	 * events[2].event = sse_evt[1][63:0]
3439 	 * events[3].event = sse_evt[1][127:64]
3440 	 */
3441 	_mm_storel_epi64((__m128i *)&events[0].event, sse_evt[0]);
3442 	_mm_storeh_pd((double *)&events[1].event, (__m128d) sse_evt[0]);
3443 	_mm_storel_epi64((__m128i *)&events[2].event, sse_evt[1]);
3444 	_mm_storeh_pd((double *)&events[3].event, (__m128d) sse_evt[1]);
3445 
3446 	DLB2_INC_STAT(ev_port->stats.rx_sched_cnt[qes[0].sched_type], 1);
3447 	DLB2_INC_STAT(ev_port->stats.rx_sched_cnt[qes[1].sched_type], 1);
3448 	DLB2_INC_STAT(ev_port->stats.rx_sched_cnt[qes[2].sched_type], 1);
3449 	DLB2_INC_STAT(ev_port->stats.rx_sched_cnt[qes[3].sched_type], 1);
3450 
3451 	DLB2_INC_STAT(
3452 		ev_port->stats.queue[events[0].queue_id].
3453 			qid_depth[qes[0].qid_depth],
3454 		1);
3455 	DLB2_INC_STAT(
3456 		ev_port->stats.queue[events[1].queue_id].
3457 			qid_depth[qes[1].qid_depth],
3458 		1);
3459 	DLB2_INC_STAT(
3460 		ev_port->stats.queue[events[2].queue_id].
3461 			qid_depth[qes[2].qid_depth],
3462 		1);
3463 	DLB2_INC_STAT(
3464 		ev_port->stats.queue[events[3].queue_id].
3465 			qid_depth[qes[3].qid_depth],
3466 		1);
3467 
3468 	DLB2_INC_STAT(ev_port->stats.traffic.rx_ok, num_events);
3469 
3470 	return num_events;
3471 }
3472 
3473 static __rte_always_inline int
3474 dlb2_recv_qe_sparse(struct dlb2_port *qm_port, struct dlb2_dequeue_qe *qe)
3475 {
3476 	volatile struct dlb2_dequeue_qe *cq_addr;
3477 	uint8_t xor_mask[2] = {0x0F, 0x00};
3478 	const uint8_t and_mask = 0x0F;
3479 	__m128i *qes = (__m128i *)qe;
3480 	uint8_t gen_bits, gen_bit;
3481 	uintptr_t addr[4];
3482 	uint16_t idx;
3483 
3484 	cq_addr = dlb2_port[qm_port->id][PORT_TYPE(qm_port)].cq_base;
3485 
3486 	idx = qm_port->cq_idx_unmasked & qm_port->cq_depth_mask;
3487 	/* Load the next 4 QEs */
3488 	addr[0] = (uintptr_t)&cq_addr[idx];
3489 	addr[1] = (uintptr_t)&cq_addr[(idx +  4) & qm_port->cq_depth_mask];
3490 	addr[2] = (uintptr_t)&cq_addr[(idx +  8) & qm_port->cq_depth_mask];
3491 	addr[3] = (uintptr_t)&cq_addr[(idx + 12) & qm_port->cq_depth_mask];
3492 
3493 	/* Prefetch next batch of QEs (all CQs occupy minimum 8 cache lines) */
3494 	rte_prefetch0(&cq_addr[(idx + 16) & qm_port->cq_depth_mask]);
3495 	rte_prefetch0(&cq_addr[(idx + 20) & qm_port->cq_depth_mask]);
3496 	rte_prefetch0(&cq_addr[(idx + 24) & qm_port->cq_depth_mask]);
3497 	rte_prefetch0(&cq_addr[(idx + 28) & qm_port->cq_depth_mask]);
3498 
3499 	/* Correct the xor_mask for wrap-around QEs */
3500 	gen_bit = qm_port->gen_bit;
3501 	xor_mask[gen_bit] ^= !!((idx +  4) > qm_port->cq_depth_mask) << 1;
3502 	xor_mask[gen_bit] ^= !!((idx +  8) > qm_port->cq_depth_mask) << 2;
3503 	xor_mask[gen_bit] ^= !!((idx + 12) > qm_port->cq_depth_mask) << 3;
3504 
3505 	/* Read the cache lines backwards to ensure that if QE[N] (N > 0) is
3506 	 * valid, then QEs[0:N-1] are too.
3507 	 */
3508 	qes[3] = _mm_load_si128((__m128i *)(void *)addr[3]);
3509 	rte_compiler_barrier();
3510 	qes[2] = _mm_load_si128((__m128i *)(void *)addr[2]);
3511 	rte_compiler_barrier();
3512 	qes[1] = _mm_load_si128((__m128i *)(void *)addr[1]);
3513 	rte_compiler_barrier();
3514 	qes[0] = _mm_load_si128((__m128i *)(void *)addr[0]);
3515 
3516 	/* Extract and combine the gen bits */
3517 	gen_bits = ((_mm_extract_epi8(qes[0], 15) & 0x1) << 0) |
3518 		   ((_mm_extract_epi8(qes[1], 15) & 0x1) << 1) |
3519 		   ((_mm_extract_epi8(qes[2], 15) & 0x1) << 2) |
3520 		   ((_mm_extract_epi8(qes[3], 15) & 0x1) << 3);
3521 
3522 	/* XOR the combined bits such that a 1 represents a valid QE */
3523 	gen_bits ^= xor_mask[gen_bit];
3524 
3525 	/* Mask off gen bits we don't care about */
3526 	gen_bits &= and_mask;
3527 
3528 	return __builtin_popcount(gen_bits);
3529 }
3530 
3531 static inline void
3532 _process_deq_qes_vec_impl(struct dlb2_port *qm_port,
3533 			  struct rte_event *events,
3534 			  __m128i v_qe_3,
3535 			  __m128i v_qe_2,
3536 			  __m128i v_qe_1,
3537 			  __m128i v_qe_0,
3538 			  __m128i v_qe_meta,
3539 			  __m128i v_qe_status,
3540 			  uint32_t valid_events)
3541 {
3542 	/* Look up the event QIDs, using the hardware QIDs to index the
3543 	 * port's QID mapping.
3544 	 *
3545 	 * Each v_qe_[0-4] is just a 16-byte load of the whole QE. It is
3546 	 * passed along in registers as the QE data is required later.
3547 	 *
3548 	 * v_qe_meta is an u32 unpack of all 4x QEs. A.k.a, it contains one
3549 	 * 32-bit slice of each QE, so makes up a full SSE register. This
3550 	 * allows parallel processing of 4x QEs in a single register.
3551 	 */
3552 
3553 	__m128i v_qid_done = {0};
3554 	int hw_qid0 = _mm_extract_epi8(v_qe_meta, 2);
3555 	int hw_qid1 = _mm_extract_epi8(v_qe_meta, 6);
3556 	int hw_qid2 = _mm_extract_epi8(v_qe_meta, 10);
3557 	int hw_qid3 = _mm_extract_epi8(v_qe_meta, 14);
3558 
3559 	int ev_qid0 = qm_port->qid_mappings[hw_qid0];
3560 	int ev_qid1 = qm_port->qid_mappings[hw_qid1];
3561 	int ev_qid2 = qm_port->qid_mappings[hw_qid2];
3562 	int ev_qid3 = qm_port->qid_mappings[hw_qid3];
3563 
3564 	v_qid_done = _mm_insert_epi8(v_qid_done, ev_qid0, 2);
3565 	v_qid_done = _mm_insert_epi8(v_qid_done, ev_qid1, 6);
3566 	v_qid_done = _mm_insert_epi8(v_qid_done, ev_qid2, 10);
3567 	v_qid_done = _mm_insert_epi8(v_qid_done, ev_qid3, 14);
3568 
3569 	/* Schedule field remapping using byte shuffle
3570 	 * - Full byte containing sched field handled here (op, rsvd are zero)
3571 	 * - Note sanitizing the register requires two masking ANDs:
3572 	 *   1) to strip prio/msg_type from byte for correct shuffle lookup
3573 	 *   2) to strip any non-sched-field lanes from any results to OR later
3574 	 * - Final byte result is >> 10 to another byte-lane inside the u32.
3575 	 *   This makes the final combination OR easier to make the rte_event.
3576 	 */
3577 	__m128i v_sched_done;
3578 	__m128i v_sched_bits;
3579 	{
3580 		static const uint8_t sched_type_map[16] = {
3581 			[DLB2_SCHED_ATOMIC] = RTE_SCHED_TYPE_ATOMIC,
3582 			[DLB2_SCHED_UNORDERED] = RTE_SCHED_TYPE_PARALLEL,
3583 			[DLB2_SCHED_ORDERED] = RTE_SCHED_TYPE_ORDERED,
3584 			[DLB2_SCHED_DIRECTED] = RTE_SCHED_TYPE_ATOMIC,
3585 		};
3586 		static const uint8_t sched_and_mask[16] = {
3587 			0x00, 0x00, 0x00, 0x03,
3588 			0x00, 0x00, 0x00, 0x03,
3589 			0x00, 0x00, 0x00, 0x03,
3590 			0x00, 0x00, 0x00, 0x03,
3591 		};
3592 		const __m128i v_sched_map = _mm_loadu_si128(
3593 					     (const __m128i *)sched_type_map);
3594 		__m128i v_sched_mask = _mm_loadu_si128(
3595 					     (const __m128i *)&sched_and_mask);
3596 		v_sched_bits = _mm_and_si128(v_qe_meta, v_sched_mask);
3597 		__m128i v_sched_remapped = _mm_shuffle_epi8(v_sched_map,
3598 							    v_sched_bits);
3599 		__m128i v_preshift = _mm_and_si128(v_sched_remapped,
3600 						   v_sched_mask);
3601 		v_sched_done = _mm_srli_epi32(v_preshift, 10);
3602 	}
3603 
3604 	/* Priority handling
3605 	 * - QE provides 3 bits of priority
3606 	 * - Shift << 3 to move to MSBs for byte-prio in rte_event
3607 	 * - Mask bits to avoid pollution, leaving only 3 prio MSBs in reg
3608 	 */
3609 	__m128i v_prio_done;
3610 	{
3611 		static const uint8_t prio_mask[16] = {
3612 			0x00, 0x00, 0x00, 0x07 << 5,
3613 			0x00, 0x00, 0x00, 0x07 << 5,
3614 			0x00, 0x00, 0x00, 0x07 << 5,
3615 			0x00, 0x00, 0x00, 0x07 << 5,
3616 		};
3617 		__m128i v_prio_mask  = _mm_loadu_si128(
3618 						(const __m128i *)prio_mask);
3619 		__m128i v_prio_shifted = _mm_slli_epi32(v_qe_meta, 3);
3620 		v_prio_done = _mm_and_si128(v_prio_shifted, v_prio_mask);
3621 	}
3622 
3623 	/* Event Sub/Type handling:
3624 	 * we want to keep the lower 12 bits of each QE. Shift up by 20 bits
3625 	 * to get the sub/ev type data into rte_event location, clearing the
3626 	 * lower 20 bits in the process.
3627 	 */
3628 	__m128i v_types_done;
3629 	{
3630 		static const uint8_t event_mask[16] = {
3631 			0x0f, 0x00, 0x00, 0x00,
3632 			0x0f, 0x00, 0x00, 0x00,
3633 			0x0f, 0x00, 0x00, 0x00,
3634 			0x0f, 0x00, 0x00, 0x00,
3635 		};
3636 		static const uint8_t sub_event_mask[16] = {
3637 			0xff, 0x00, 0x00, 0x00,
3638 			0xff, 0x00, 0x00, 0x00,
3639 			0xff, 0x00, 0x00, 0x00,
3640 			0xff, 0x00, 0x00, 0x00,
3641 		};
3642 		static const uint8_t flow_mask[16] = {
3643 			0xff, 0xff, 0x00, 0x00,
3644 			0xff, 0xff, 0x00, 0x00,
3645 			0xff, 0xff, 0x00, 0x00,
3646 			0xff, 0xff, 0x00, 0x00,
3647 		};
3648 		__m128i v_event_mask  = _mm_loadu_si128(
3649 					(const __m128i *)event_mask);
3650 		__m128i v_sub_event_mask  = _mm_loadu_si128(
3651 					(const __m128i *)sub_event_mask);
3652 		__m128i v_flow_mask  = _mm_loadu_si128(
3653 				       (const __m128i *)flow_mask);
3654 		__m128i v_sub = _mm_srli_epi32(v_qe_meta, 8);
3655 		v_sub = _mm_and_si128(v_sub, v_sub_event_mask);
3656 		__m128i v_type = _mm_and_si128(v_qe_meta, v_event_mask);
3657 		v_type = _mm_slli_epi32(v_type, 8);
3658 		v_types_done = _mm_or_si128(v_type, v_sub);
3659 		v_types_done = _mm_slli_epi32(v_types_done, 20);
3660 		__m128i v_flow = _mm_and_si128(v_qe_status, v_flow_mask);
3661 		v_types_done = _mm_or_si128(v_types_done, v_flow);
3662 	}
3663 
3664 	/* Combine QID, Sched and Prio fields, then Shift >> 8 bits to align
3665 	 * with the rte_event, allowing unpacks to move/blend with payload.
3666 	 */
3667 	__m128i v_q_s_p_done;
3668 	{
3669 		__m128i v_qid_sched = _mm_or_si128(v_qid_done, v_sched_done);
3670 		__m128i v_q_s_prio = _mm_or_si128(v_qid_sched, v_prio_done);
3671 		v_q_s_p_done = _mm_srli_epi32(v_q_s_prio, 8);
3672 	}
3673 
3674 	__m128i v_unpk_ev_23, v_unpk_ev_01, v_ev_2, v_ev_3, v_ev_0, v_ev_1;
3675 
3676 	/* Unpack evs into u64 metadata, then indiv events */
3677 	v_unpk_ev_23 = _mm_unpackhi_epi32(v_types_done, v_q_s_p_done);
3678 	v_unpk_ev_01 = _mm_unpacklo_epi32(v_types_done, v_q_s_p_done);
3679 
3680 	switch (valid_events) {
3681 	case 4:
3682 		v_ev_3 = _mm_blend_epi16(v_unpk_ev_23, v_qe_3, 0x0F);
3683 		v_ev_3 = _mm_alignr_epi8(v_ev_3, v_ev_3, 8);
3684 		_mm_storeu_si128((__m128i *)&events[3], v_ev_3);
3685 		/* fallthrough */
3686 	case 3:
3687 		v_ev_2 = _mm_unpacklo_epi64(v_unpk_ev_23, v_qe_2);
3688 		_mm_storeu_si128((__m128i *)&events[2], v_ev_2);
3689 		/* fallthrough */
3690 	case 2:
3691 		v_ev_1 = _mm_blend_epi16(v_unpk_ev_01, v_qe_1, 0x0F);
3692 		v_ev_1 = _mm_alignr_epi8(v_ev_1, v_ev_1, 8);
3693 		_mm_storeu_si128((__m128i *)&events[1], v_ev_1);
3694 		/* fallthrough */
3695 	case 1:
3696 		v_ev_0 = _mm_unpacklo_epi64(v_unpk_ev_01, v_qe_0);
3697 		_mm_storeu_si128((__m128i *)&events[0], v_ev_0);
3698 	}
3699 }
3700 
3701 static __rte_always_inline int
3702 dlb2_recv_qe_sparse_vec(struct dlb2_port *qm_port, void *events,
3703 			uint32_t max_events)
3704 {
3705 	/* Using unmasked idx for perf, and masking manually */
3706 	uint16_t idx = qm_port->cq_idx_unmasked;
3707 	volatile struct dlb2_dequeue_qe *cq_addr;
3708 
3709 	cq_addr = dlb2_port[qm_port->id][PORT_TYPE(qm_port)].cq_base;
3710 
3711 	uintptr_t qe_ptr_3 = (uintptr_t)&cq_addr[(idx + 12) &
3712 						 qm_port->cq_depth_mask];
3713 	uintptr_t qe_ptr_2 = (uintptr_t)&cq_addr[(idx +  8) &
3714 						 qm_port->cq_depth_mask];
3715 	uintptr_t qe_ptr_1 = (uintptr_t)&cq_addr[(idx +  4) &
3716 						 qm_port->cq_depth_mask];
3717 	uintptr_t qe_ptr_0 = (uintptr_t)&cq_addr[(idx +  0) &
3718 						 qm_port->cq_depth_mask];
3719 
3720 	/* Load QEs from CQ: use compiler barriers to avoid load reordering */
3721 	__m128i v_qe_3 = _mm_loadu_si128((const __m128i *)qe_ptr_3);
3722 	rte_compiler_barrier();
3723 	__m128i v_qe_2 = _mm_loadu_si128((const __m128i *)qe_ptr_2);
3724 	rte_compiler_barrier();
3725 	__m128i v_qe_1 = _mm_loadu_si128((const __m128i *)qe_ptr_1);
3726 	rte_compiler_barrier();
3727 	__m128i v_qe_0 = _mm_loadu_si128((const __m128i *)qe_ptr_0);
3728 
3729 	/* Generate the pkt_shuffle mask;
3730 	 * - Avoids load in otherwise load-heavy section of code
3731 	 * - Moves bytes 3,7,11,15 (gen bit bytes) to LSB bytes in XMM
3732 	 */
3733 	const uint32_t stat_shuf_bytes = (15 << 24) | (11 << 16) | (7 << 8) | 3;
3734 	__m128i v_zeros = _mm_setzero_si128();
3735 	__m128i v_ffff = _mm_cmpeq_epi8(v_zeros, v_zeros);
3736 	__m128i v_stat_shuf_mask = _mm_insert_epi32(v_ffff, stat_shuf_bytes, 0);
3737 
3738 	/* Extract u32 components required from the QE
3739 	 * - QE[64 to 95 ] for metadata (qid, sched, prio, event type, ...)
3740 	 * - QE[96 to 127] for status (cq gen bit, error)
3741 	 *
3742 	 * Note that stage 1 of the unpacking is re-used for both u32 extracts
3743 	 */
3744 	__m128i v_qe_02 = _mm_unpackhi_epi32(v_qe_0, v_qe_2);
3745 	__m128i v_qe_13 = _mm_unpackhi_epi32(v_qe_1, v_qe_3);
3746 	__m128i v_qe_status = _mm_unpackhi_epi32(v_qe_02, v_qe_13);
3747 	__m128i v_qe_meta   = _mm_unpacklo_epi32(v_qe_02, v_qe_13);
3748 
3749 	/* Status byte (gen_bit, error) handling:
3750 	 * - Shuffle to lanes 0,1,2,3, clear all others
3751 	 * - Shift right by 7 for gen bit to MSB, movemask to scalar
3752 	 * - Shift right by 2 for error bit to MSB, movemask to scalar
3753 	 */
3754 	__m128i v_qe_shuffled = _mm_shuffle_epi8(v_qe_status, v_stat_shuf_mask);
3755 	__m128i v_qes_shift_gen_bit = _mm_slli_epi32(v_qe_shuffled, 7);
3756 	int32_t qe_gen_bits = _mm_movemask_epi8(v_qes_shift_gen_bit) & 0xf;
3757 
3758 	/* Expected vs Reality of QE Gen bits
3759 	 * - cq_rolling_mask provides expected bits
3760 	 * - QE loads, unpacks/shuffle and movemask provides reality
3761 	 * - XOR of the two gives bitmask of new packets
3762 	 * - POPCNT to get the number of new events
3763 	 */
3764 	uint64_t rolling = qm_port->cq_rolling_mask & 0xF;
3765 	uint64_t qe_xor_bits = (qe_gen_bits ^ rolling);
3766 	uint32_t count_new = __builtin_popcount(qe_xor_bits);
3767 	count_new = RTE_MIN(count_new, max_events);
3768 	if (!count_new)
3769 		return 0;
3770 
3771 	/* emulate a 128 bit rotate using 2x 64-bit numbers and bit-shifts */
3772 
3773 	uint64_t m_rshift = qm_port->cq_rolling_mask >> count_new;
3774 	uint64_t m_lshift = qm_port->cq_rolling_mask << (64 - count_new);
3775 	uint64_t m2_rshift = qm_port->cq_rolling_mask_2 >> count_new;
3776 	uint64_t m2_lshift = qm_port->cq_rolling_mask_2 << (64 - count_new);
3777 
3778 	/* shifted out of m2 into MSB of m */
3779 	qm_port->cq_rolling_mask = (m_rshift | m2_lshift);
3780 
3781 	/* shifted out of m "looped back" into MSB of m2 */
3782 	qm_port->cq_rolling_mask_2 = (m2_rshift | m_lshift);
3783 
3784 	/* Prefetch the next QEs - should run as IPC instead of cycles */
3785 	rte_prefetch0(&cq_addr[(idx + 16) & qm_port->cq_depth_mask]);
3786 	rte_prefetch0(&cq_addr[(idx + 20) & qm_port->cq_depth_mask]);
3787 	rte_prefetch0(&cq_addr[(idx + 24) & qm_port->cq_depth_mask]);
3788 	rte_prefetch0(&cq_addr[(idx + 28) & qm_port->cq_depth_mask]);
3789 
3790 	/* Convert QEs from XMM regs to events and store events directly */
3791 	_process_deq_qes_vec_impl(qm_port, events, v_qe_3, v_qe_2, v_qe_1,
3792 				  v_qe_0, v_qe_meta, v_qe_status, count_new);
3793 
3794 	return count_new;
3795 }
3796 
3797 static inline void
3798 dlb2_inc_cq_idx(struct dlb2_port *qm_port, int cnt)
3799 {
3800 	uint16_t idx = qm_port->cq_idx_unmasked + cnt;
3801 
3802 	qm_port->cq_idx_unmasked = idx;
3803 	qm_port->cq_idx = idx & qm_port->cq_depth_mask;
3804 	qm_port->gen_bit = (~(idx >> qm_port->gen_bit_shift)) & 0x1;
3805 }
3806 
3807 static inline int16_t
3808 dlb2_hw_dequeue_sparse(struct dlb2_eventdev *dlb2,
3809 		       struct dlb2_eventdev_port *ev_port,
3810 		       struct rte_event *events,
3811 		       uint16_t max_num,
3812 		       uint64_t dequeue_timeout_ticks)
3813 {
3814 	uint64_t start_ticks = 0ULL;
3815 	struct dlb2_port *qm_port;
3816 	int num = 0;
3817 	bool use_scalar;
3818 	uint64_t timeout;
3819 
3820 	qm_port = &ev_port->qm_port;
3821 	use_scalar = qm_port->use_scalar;
3822 
3823 	if (!dlb2->global_dequeue_wait)
3824 		timeout = dequeue_timeout_ticks;
3825 	else
3826 		timeout = dlb2->global_dequeue_wait_ticks;
3827 
3828 	start_ticks = rte_get_timer_cycles();
3829 
3830 	use_scalar = use_scalar || (max_num & 0x3);
3831 
3832 	while (num < max_num) {
3833 		struct dlb2_dequeue_qe qes[DLB2_NUM_QES_PER_CACHE_LINE];
3834 		int num_avail;
3835 		if (use_scalar) {
3836 			num_avail = dlb2_recv_qe_sparse(qm_port, qes);
3837 			num_avail = RTE_MIN(num_avail, max_num - num);
3838 			dlb2_inc_cq_idx(qm_port, num_avail << 2);
3839 			if (num_avail == DLB2_NUM_QES_PER_CACHE_LINE)
3840 				num += dlb2_process_dequeue_four_qes(ev_port,
3841 								  qm_port,
3842 								  &events[num],
3843 								  &qes[0]);
3844 			else if (num_avail)
3845 				num += dlb2_process_dequeue_qes(ev_port,
3846 								qm_port,
3847 								&events[num],
3848 								&qes[0],
3849 								num_avail);
3850 		} else { /* !use_scalar */
3851 			num_avail = dlb2_recv_qe_sparse_vec(qm_port,
3852 							    &events[num],
3853 							    max_num - num);
3854 			num += num_avail;
3855 			dlb2_inc_cq_idx(qm_port, num_avail << 2);
3856 			DLB2_INC_STAT(ev_port->stats.traffic.rx_ok, num_avail);
3857 		}
3858 		if (!num_avail) {
3859 			if (num > 0)
3860 				break;
3861 			else if (dlb2_dequeue_wait(dlb2, ev_port, qm_port,
3862 						   timeout, start_ticks))
3863 				break;
3864 		}
3865 	}
3866 
3867 	qm_port->owed_tokens += num;
3868 
3869 	if (num) {
3870 		if (qm_port->token_pop_mode == AUTO_POP)
3871 			dlb2_consume_qe_immediate(qm_port, num);
3872 
3873 		ev_port->outstanding_releases += num;
3874 
3875 		dlb2_port_credits_inc(qm_port, num);
3876 	}
3877 
3878 	return num;
3879 }
3880 
3881 static __rte_always_inline int
3882 dlb2_recv_qe(struct dlb2_port *qm_port, struct dlb2_dequeue_qe *qe,
3883 	     uint8_t *offset)
3884 {
3885 	uint8_t xor_mask[2][4] = { {0x0F, 0x0E, 0x0C, 0x08},
3886 				   {0x00, 0x01, 0x03, 0x07} };
3887 	uint8_t and_mask[4] = {0x0F, 0x0E, 0x0C, 0x08};
3888 	volatile struct dlb2_dequeue_qe *cq_addr;
3889 	__m128i *qes = (__m128i *)qe;
3890 	uint64_t *cache_line_base;
3891 	uint8_t gen_bits;
3892 
3893 	cq_addr = dlb2_port[qm_port->id][PORT_TYPE(qm_port)].cq_base;
3894 	cq_addr = &cq_addr[qm_port->cq_idx];
3895 
3896 	cache_line_base = (void *)(((uintptr_t)cq_addr) & ~0x3F);
3897 	*offset = ((uintptr_t)cq_addr & 0x30) >> 4;
3898 
3899 	/* Load the next CQ cache line from memory. Pack these reads as tight
3900 	 * as possible to reduce the chance that DLB invalidates the line while
3901 	 * the CPU is reading it. Read the cache line backwards to ensure that
3902 	 * if QE[N] (N > 0) is valid, then QEs[0:N-1] are too.
3903 	 *
3904 	 * (Valid QEs start at &qe[offset])
3905 	 */
3906 	qes[3] = _mm_load_si128((__m128i *)&cache_line_base[6]);
3907 	qes[2] = _mm_load_si128((__m128i *)&cache_line_base[4]);
3908 	qes[1] = _mm_load_si128((__m128i *)&cache_line_base[2]);
3909 	qes[0] = _mm_load_si128((__m128i *)&cache_line_base[0]);
3910 
3911 	/* Evict the cache line ASAP */
3912 	rte_cldemote(cache_line_base);
3913 
3914 	/* Extract and combine the gen bits */
3915 	gen_bits = ((_mm_extract_epi8(qes[0], 15) & 0x1) << 0) |
3916 		   ((_mm_extract_epi8(qes[1], 15) & 0x1) << 1) |
3917 		   ((_mm_extract_epi8(qes[2], 15) & 0x1) << 2) |
3918 		   ((_mm_extract_epi8(qes[3], 15) & 0x1) << 3);
3919 
3920 	/* XOR the combined bits such that a 1 represents a valid QE */
3921 	gen_bits ^= xor_mask[qm_port->gen_bit][*offset];
3922 
3923 	/* Mask off gen bits we don't care about */
3924 	gen_bits &= and_mask[*offset];
3925 
3926 	return __builtin_popcount(gen_bits);
3927 }
3928 
3929 static inline int16_t
3930 dlb2_hw_dequeue(struct dlb2_eventdev *dlb2,
3931 		struct dlb2_eventdev_port *ev_port,
3932 		struct rte_event *events,
3933 		uint16_t max_num,
3934 		uint64_t dequeue_timeout_ticks)
3935 {
3936 	uint64_t timeout;
3937 	uint64_t start_ticks = 0ULL;
3938 	struct dlb2_port *qm_port;
3939 	int num = 0;
3940 
3941 	qm_port = &ev_port->qm_port;
3942 
3943 	/* We have a special implementation for waiting. Wait can be:
3944 	 * 1) no waiting at all
3945 	 * 2) busy poll only
3946 	 * 3) wait for interrupt. If wakeup and poll time
3947 	 * has expired, then return to caller
3948 	 * 4) umonitor/umwait repeatedly up to poll time
3949 	 */
3950 
3951 	/* If configured for per dequeue wait, then use wait value provided
3952 	 * to this API. Otherwise we must use the global
3953 	 * value from eventdev config time.
3954 	 */
3955 	if (!dlb2->global_dequeue_wait)
3956 		timeout = dequeue_timeout_ticks;
3957 	else
3958 		timeout = dlb2->global_dequeue_wait_ticks;
3959 
3960 	start_ticks = rte_get_timer_cycles();
3961 
3962 	while (num < max_num) {
3963 		struct dlb2_dequeue_qe qes[DLB2_NUM_QES_PER_CACHE_LINE];
3964 		uint8_t offset;
3965 		int num_avail;
3966 
3967 		/* Copy up to 4 QEs from the current cache line into qes */
3968 		num_avail = dlb2_recv_qe(qm_port, qes, &offset);
3969 
3970 		/* But don't process more than the user requested */
3971 		num_avail = RTE_MIN(num_avail, max_num - num);
3972 
3973 		dlb2_inc_cq_idx(qm_port, num_avail);
3974 
3975 		if (num_avail == DLB2_NUM_QES_PER_CACHE_LINE)
3976 			num += dlb2_process_dequeue_four_qes(ev_port,
3977 							     qm_port,
3978 							     &events[num],
3979 							     &qes[offset]);
3980 		else if (num_avail)
3981 			num += dlb2_process_dequeue_qes(ev_port,
3982 							qm_port,
3983 							&events[num],
3984 							&qes[offset],
3985 							num_avail);
3986 		else if ((timeout == 0) || (num > 0))
3987 			/* Not waiting in any form, or 1+ events received? */
3988 			break;
3989 		else if (dlb2_dequeue_wait(dlb2, ev_port, qm_port,
3990 					   timeout, start_ticks))
3991 			break;
3992 	}
3993 
3994 	qm_port->owed_tokens += num;
3995 
3996 	if (num) {
3997 		if (qm_port->token_pop_mode == AUTO_POP)
3998 			dlb2_consume_qe_immediate(qm_port, num);
3999 
4000 		ev_port->outstanding_releases += num;
4001 
4002 		dlb2_port_credits_inc(qm_port, num);
4003 	}
4004 
4005 	return num;
4006 }
4007 
4008 static uint16_t
4009 dlb2_event_dequeue_burst(void *event_port, struct rte_event *ev, uint16_t num,
4010 			 uint64_t wait)
4011 {
4012 	struct dlb2_eventdev_port *ev_port = event_port;
4013 	struct dlb2_port *qm_port = &ev_port->qm_port;
4014 	struct dlb2_eventdev *dlb2 = ev_port->dlb2;
4015 	uint16_t cnt;
4016 
4017 	RTE_ASSERT(ev_port->setup_done);
4018 	RTE_ASSERT(ev != NULL);
4019 
4020 	if (ev_port->implicit_release && ev_port->outstanding_releases > 0) {
4021 		uint16_t out_rels = ev_port->outstanding_releases;
4022 
4023 		dlb2_event_release(dlb2, ev_port->id, out_rels);
4024 
4025 		DLB2_INC_STAT(ev_port->stats.tx_implicit_rel, out_rels);
4026 	}
4027 
4028 	if (qm_port->token_pop_mode == DEFERRED_POP && qm_port->owed_tokens)
4029 		dlb2_consume_qe_immediate(qm_port, qm_port->owed_tokens);
4030 
4031 	cnt = dlb2_hw_dequeue(dlb2, ev_port, ev, num, wait);
4032 
4033 	DLB2_INC_STAT(ev_port->stats.traffic.total_polls, 1);
4034 	DLB2_INC_STAT(ev_port->stats.traffic.zero_polls, ((cnt == 0) ? 1 : 0));
4035 
4036 	return cnt;
4037 }
4038 
4039 static uint16_t
4040 dlb2_event_dequeue(void *event_port, struct rte_event *ev, uint64_t wait)
4041 {
4042 	return dlb2_event_dequeue_burst(event_port, ev, 1, wait);
4043 }
4044 
4045 static uint16_t
4046 dlb2_event_dequeue_burst_sparse(void *event_port, struct rte_event *ev,
4047 				uint16_t num, uint64_t wait)
4048 {
4049 	struct dlb2_eventdev_port *ev_port = event_port;
4050 	struct dlb2_port *qm_port = &ev_port->qm_port;
4051 	struct dlb2_eventdev *dlb2 = ev_port->dlb2;
4052 	uint16_t cnt;
4053 
4054 	RTE_ASSERT(ev_port->setup_done);
4055 	RTE_ASSERT(ev != NULL);
4056 
4057 	if (ev_port->implicit_release && ev_port->outstanding_releases > 0) {
4058 		uint16_t out_rels = ev_port->outstanding_releases;
4059 
4060 		dlb2_event_release(dlb2, ev_port->id, out_rels);
4061 
4062 		DLB2_INC_STAT(ev_port->stats.tx_implicit_rel, out_rels);
4063 	}
4064 
4065 	if (qm_port->token_pop_mode == DEFERRED_POP && qm_port->owed_tokens)
4066 		dlb2_consume_qe_immediate(qm_port, qm_port->owed_tokens);
4067 
4068 	cnt = dlb2_hw_dequeue_sparse(dlb2, ev_port, ev, num, wait);
4069 
4070 	DLB2_INC_STAT(ev_port->stats.traffic.total_polls, 1);
4071 	DLB2_INC_STAT(ev_port->stats.traffic.zero_polls, ((cnt == 0) ? 1 : 0));
4072 	return cnt;
4073 }
4074 
4075 static uint16_t
4076 dlb2_event_dequeue_sparse(void *event_port, struct rte_event *ev,
4077 			  uint64_t wait)
4078 {
4079 	return dlb2_event_dequeue_burst_sparse(event_port, ev, 1, wait);
4080 }
4081 
4082 static void
4083 dlb2_flush_port(struct rte_eventdev *dev, int port_id)
4084 {
4085 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
4086 	eventdev_stop_flush_t flush;
4087 	struct rte_event ev;
4088 	uint8_t dev_id;
4089 	void *arg;
4090 	int i;
4091 
4092 	flush = dev->dev_ops->dev_stop_flush;
4093 	dev_id = dev->data->dev_id;
4094 	arg = dev->data->dev_stop_flush_arg;
4095 
4096 	while (rte_event_dequeue_burst(dev_id, port_id, &ev, 1, 0)) {
4097 		if (flush)
4098 			flush(dev_id, ev, arg);
4099 
4100 		if (dlb2->ev_ports[port_id].qm_port.is_directed)
4101 			continue;
4102 
4103 		ev.op = RTE_EVENT_OP_RELEASE;
4104 
4105 		rte_event_enqueue_burst(dev_id, port_id, &ev, 1);
4106 	}
4107 
4108 	/* Enqueue any additional outstanding releases */
4109 	ev.op = RTE_EVENT_OP_RELEASE;
4110 
4111 	for (i = dlb2->ev_ports[port_id].outstanding_releases; i > 0; i--)
4112 		rte_event_enqueue_burst(dev_id, port_id, &ev, 1);
4113 }
4114 
4115 static uint32_t
4116 dlb2_get_ldb_queue_depth(struct dlb2_eventdev *dlb2,
4117 			 struct dlb2_eventdev_queue *queue)
4118 {
4119 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
4120 	struct dlb2_get_ldb_queue_depth_args cfg;
4121 	int ret;
4122 
4123 	cfg.queue_id = queue->qm_queue.id;
4124 
4125 	ret = dlb2_iface_get_ldb_queue_depth(handle, &cfg);
4126 	if (ret < 0) {
4127 		DLB2_LOG_ERR("dlb2: get_ldb_queue_depth ret=%d (driver status: %s)\n",
4128 			     ret, dlb2_error_strings[cfg.response.status]);
4129 		return ret;
4130 	}
4131 
4132 	return cfg.response.id;
4133 }
4134 
4135 static uint32_t
4136 dlb2_get_dir_queue_depth(struct dlb2_eventdev *dlb2,
4137 			 struct dlb2_eventdev_queue *queue)
4138 {
4139 	struct dlb2_hw_dev *handle = &dlb2->qm_instance;
4140 	struct dlb2_get_dir_queue_depth_args cfg;
4141 	int ret;
4142 
4143 	cfg.queue_id = queue->qm_queue.id;
4144 
4145 	ret = dlb2_iface_get_dir_queue_depth(handle, &cfg);
4146 	if (ret < 0) {
4147 		DLB2_LOG_ERR("dlb2: get_dir_queue_depth ret=%d (driver status: %s)\n",
4148 			     ret, dlb2_error_strings[cfg.response.status]);
4149 		return ret;
4150 	}
4151 
4152 	return cfg.response.id;
4153 }
4154 
4155 uint32_t
4156 dlb2_get_queue_depth(struct dlb2_eventdev *dlb2,
4157 		     struct dlb2_eventdev_queue *queue)
4158 {
4159 	if (queue->qm_queue.is_directed)
4160 		return dlb2_get_dir_queue_depth(dlb2, queue);
4161 	else
4162 		return dlb2_get_ldb_queue_depth(dlb2, queue);
4163 }
4164 
4165 static bool
4166 dlb2_queue_is_empty(struct dlb2_eventdev *dlb2,
4167 		    struct dlb2_eventdev_queue *queue)
4168 {
4169 	return dlb2_get_queue_depth(dlb2, queue) == 0;
4170 }
4171 
4172 static bool
4173 dlb2_linked_queues_empty(struct dlb2_eventdev *dlb2)
4174 {
4175 	int i;
4176 
4177 	for (i = 0; i < dlb2->num_queues; i++) {
4178 		if (dlb2->ev_queues[i].num_links == 0)
4179 			continue;
4180 		if (!dlb2_queue_is_empty(dlb2, &dlb2->ev_queues[i]))
4181 			return false;
4182 	}
4183 
4184 	return true;
4185 }
4186 
4187 static bool
4188 dlb2_queues_empty(struct dlb2_eventdev *dlb2)
4189 {
4190 	int i;
4191 
4192 	for (i = 0; i < dlb2->num_queues; i++) {
4193 		if (!dlb2_queue_is_empty(dlb2, &dlb2->ev_queues[i]))
4194 			return false;
4195 	}
4196 
4197 	return true;
4198 }
4199 
4200 static void
4201 dlb2_drain(struct rte_eventdev *dev)
4202 {
4203 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
4204 	struct dlb2_eventdev_port *ev_port = NULL;
4205 	uint8_t dev_id;
4206 	int i;
4207 
4208 	dev_id = dev->data->dev_id;
4209 
4210 	while (!dlb2_linked_queues_empty(dlb2)) {
4211 		/* Flush all the ev_ports, which will drain all their connected
4212 		 * queues.
4213 		 */
4214 		for (i = 0; i < dlb2->num_ports; i++)
4215 			dlb2_flush_port(dev, i);
4216 	}
4217 
4218 	/* The queues are empty, but there may be events left in the ports. */
4219 	for (i = 0; i < dlb2->num_ports; i++)
4220 		dlb2_flush_port(dev, i);
4221 
4222 	/* If the domain's queues are empty, we're done. */
4223 	if (dlb2_queues_empty(dlb2))
4224 		return;
4225 
4226 	/* Else, there must be at least one unlinked load-balanced queue.
4227 	 * Select a load-balanced port with which to drain the unlinked
4228 	 * queue(s).
4229 	 */
4230 	for (i = 0; i < dlb2->num_ports; i++) {
4231 		ev_port = &dlb2->ev_ports[i];
4232 
4233 		if (!ev_port->qm_port.is_directed)
4234 			break;
4235 	}
4236 
4237 	if (i == dlb2->num_ports) {
4238 		DLB2_LOG_ERR("internal error: no LDB ev_ports\n");
4239 		return;
4240 	}
4241 
4242 	rte_errno = 0;
4243 	rte_event_port_unlink(dev_id, ev_port->id, NULL, 0);
4244 
4245 	if (rte_errno) {
4246 		DLB2_LOG_ERR("internal error: failed to unlink ev_port %d\n",
4247 			     ev_port->id);
4248 		return;
4249 	}
4250 
4251 	for (i = 0; i < dlb2->num_queues; i++) {
4252 		uint8_t qid, prio;
4253 		int ret;
4254 
4255 		if (dlb2_queue_is_empty(dlb2, &dlb2->ev_queues[i]))
4256 			continue;
4257 
4258 		qid = i;
4259 		prio = 0;
4260 
4261 		/* Link the ev_port to the queue */
4262 		ret = rte_event_port_link(dev_id, ev_port->id, &qid, &prio, 1);
4263 		if (ret != 1) {
4264 			DLB2_LOG_ERR("internal error: failed to link ev_port %d to queue %d\n",
4265 				     ev_port->id, qid);
4266 			return;
4267 		}
4268 
4269 		/* Flush the queue */
4270 		while (!dlb2_queue_is_empty(dlb2, &dlb2->ev_queues[i]))
4271 			dlb2_flush_port(dev, ev_port->id);
4272 
4273 		/* Drain any extant events in the ev_port. */
4274 		dlb2_flush_port(dev, ev_port->id);
4275 
4276 		/* Unlink the ev_port from the queue */
4277 		ret = rte_event_port_unlink(dev_id, ev_port->id, &qid, 1);
4278 		if (ret != 1) {
4279 			DLB2_LOG_ERR("internal error: failed to unlink ev_port %d to queue %d\n",
4280 				     ev_port->id, qid);
4281 			return;
4282 		}
4283 	}
4284 }
4285 
4286 static void
4287 dlb2_eventdev_stop(struct rte_eventdev *dev)
4288 {
4289 	struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev);
4290 
4291 	rte_spinlock_lock(&dlb2->qm_instance.resource_lock);
4292 
4293 	if (dlb2->run_state == DLB2_RUN_STATE_STOPPED) {
4294 		DLB2_LOG_DBG("Internal error: already stopped\n");
4295 		rte_spinlock_unlock(&dlb2->qm_instance.resource_lock);
4296 		return;
4297 	} else if (dlb2->run_state != DLB2_RUN_STATE_STARTED) {
4298 		DLB2_LOG_ERR("Internal error: bad state %d for dev_stop\n",
4299 			     (int)dlb2->run_state);
4300 		rte_spinlock_unlock(&dlb2->qm_instance.resource_lock);
4301 		return;
4302 	}
4303 
4304 	dlb2->run_state = DLB2_RUN_STATE_STOPPING;
4305 
4306 	rte_spinlock_unlock(&dlb2->qm_instance.resource_lock);
4307 
4308 	dlb2_drain(dev);
4309 
4310 	dlb2->run_state = DLB2_RUN_STATE_STOPPED;
4311 }
4312 
4313 static int
4314 dlb2_eventdev_close(struct rte_eventdev *dev)
4315 {
4316 	dlb2_hw_reset_sched_domain(dev, false);
4317 
4318 	return 0;
4319 }
4320 
4321 static void
4322 dlb2_eventdev_queue_release(struct rte_eventdev *dev, uint8_t id)
4323 {
4324 	RTE_SET_USED(dev);
4325 	RTE_SET_USED(id);
4326 
4327 	/* This function intentionally left blank. */
4328 }
4329 
4330 static void
4331 dlb2_eventdev_port_release(void *port)
4332 {
4333 	struct dlb2_eventdev_port *ev_port = port;
4334 	struct dlb2_port *qm_port;
4335 
4336 	if (ev_port) {
4337 		qm_port = &ev_port->qm_port;
4338 		if (qm_port->config_state == DLB2_CONFIGURED)
4339 			dlb2_free_qe_mem(qm_port);
4340 	}
4341 }
4342 
4343 static int
4344 dlb2_eventdev_timeout_ticks(struct rte_eventdev *dev, uint64_t ns,
4345 			    uint64_t *timeout_ticks)
4346 {
4347 	RTE_SET_USED(dev);
4348 	uint64_t cycles_per_ns = rte_get_timer_hz() / 1E9;
4349 
4350 	*timeout_ticks = ns * cycles_per_ns;
4351 
4352 	return 0;
4353 }
4354 
4355 static void
4356 dlb2_entry_points_init(struct rte_eventdev *dev)
4357 {
4358 	struct dlb2_eventdev *dlb2;
4359 
4360 	/* Expose PMD's eventdev interface */
4361 	static struct rte_eventdev_ops dlb2_eventdev_entry_ops = {
4362 		.dev_infos_get    = dlb2_eventdev_info_get,
4363 		.dev_configure    = dlb2_eventdev_configure,
4364 		.dev_start        = dlb2_eventdev_start,
4365 		.dev_stop         = dlb2_eventdev_stop,
4366 		.dev_close        = dlb2_eventdev_close,
4367 		.queue_def_conf   = dlb2_eventdev_queue_default_conf_get,
4368 		.queue_setup      = dlb2_eventdev_queue_setup,
4369 		.queue_release    = dlb2_eventdev_queue_release,
4370 		.port_def_conf    = dlb2_eventdev_port_default_conf_get,
4371 		.port_setup       = dlb2_eventdev_port_setup,
4372 		.port_release     = dlb2_eventdev_port_release,
4373 		.port_link        = dlb2_eventdev_port_link,
4374 		.port_unlink      = dlb2_eventdev_port_unlink,
4375 		.port_unlinks_in_progress =
4376 				    dlb2_eventdev_port_unlinks_in_progress,
4377 		.timeout_ticks    = dlb2_eventdev_timeout_ticks,
4378 		.dump             = dlb2_eventdev_dump,
4379 		.xstats_get       = dlb2_eventdev_xstats_get,
4380 		.xstats_get_names = dlb2_eventdev_xstats_get_names,
4381 		.xstats_get_by_name = dlb2_eventdev_xstats_get_by_name,
4382 		.xstats_reset	    = dlb2_eventdev_xstats_reset,
4383 		.dev_selftest     = test_dlb2_eventdev,
4384 	};
4385 
4386 	/* Expose PMD's eventdev interface */
4387 
4388 	dev->dev_ops = &dlb2_eventdev_entry_ops;
4389 	dev->enqueue = dlb2_event_enqueue;
4390 	dev->enqueue_burst = dlb2_event_enqueue_burst;
4391 	dev->enqueue_new_burst = dlb2_event_enqueue_new_burst;
4392 	dev->enqueue_forward_burst = dlb2_event_enqueue_forward_burst;
4393 
4394 	dlb2 = dev->data->dev_private;
4395 	if (dlb2->poll_mode == DLB2_CQ_POLL_MODE_SPARSE) {
4396 		dev->dequeue = dlb2_event_dequeue_sparse;
4397 		dev->dequeue_burst = dlb2_event_dequeue_burst_sparse;
4398 	} else {
4399 		dev->dequeue = dlb2_event_dequeue;
4400 		dev->dequeue_burst = dlb2_event_dequeue_burst;
4401 	}
4402 }
4403 
4404 int
4405 dlb2_primary_eventdev_probe(struct rte_eventdev *dev,
4406 			    const char *name,
4407 			    struct dlb2_devargs *dlb2_args)
4408 {
4409 	struct dlb2_eventdev *dlb2;
4410 	int err, i;
4411 
4412 	dlb2 = dev->data->dev_private;
4413 
4414 	dlb2->event_dev = dev; /* backlink */
4415 
4416 	evdev_dlb2_default_info.driver_name = name;
4417 
4418 	dlb2->max_num_events_override = dlb2_args->max_num_events;
4419 	dlb2->num_dir_credits_override = dlb2_args->num_dir_credits_override;
4420 	dlb2->qm_instance.cos_id = dlb2_args->cos_id;
4421 	dlb2->poll_interval = dlb2_args->poll_interval;
4422 	dlb2->sw_credit_quanta = dlb2_args->sw_credit_quanta;
4423 	dlb2->default_depth_thresh = dlb2_args->default_depth_thresh;
4424 	dlb2->vector_opts_disabled = dlb2_args->vector_opts_disabled;
4425 
4426 	err = dlb2_iface_open(&dlb2->qm_instance, name);
4427 	if (err < 0) {
4428 		DLB2_LOG_ERR("could not open event hardware device, err=%d\n",
4429 			     err);
4430 		return err;
4431 	}
4432 
4433 	err = dlb2_iface_get_device_version(&dlb2->qm_instance,
4434 					    &dlb2->revision);
4435 	if (err < 0) {
4436 		DLB2_LOG_ERR("dlb2: failed to get the device version, err=%d\n",
4437 			     err);
4438 		return err;
4439 	}
4440 
4441 	err = dlb2_hw_query_resources(dlb2);
4442 	if (err) {
4443 		DLB2_LOG_ERR("get resources err=%d for %s\n",
4444 			     err, name);
4445 		return err;
4446 	}
4447 
4448 	dlb2_iface_hardware_init(&dlb2->qm_instance);
4449 
4450 	err = dlb2_iface_get_cq_poll_mode(&dlb2->qm_instance, &dlb2->poll_mode);
4451 	if (err < 0) {
4452 		DLB2_LOG_ERR("dlb2: failed to get the poll mode, err=%d\n",
4453 			     err);
4454 		return err;
4455 	}
4456 
4457 	/* Complete xtstats runtime initialization */
4458 	err = dlb2_xstats_init(dlb2);
4459 	if (err) {
4460 		DLB2_LOG_ERR("dlb2: failed to init xstats, err=%d\n", err);
4461 		return err;
4462 	}
4463 
4464 	/* Initialize each port's token pop mode */
4465 	for (i = 0; i < DLB2_MAX_NUM_PORTS(dlb2->version); i++)
4466 		dlb2->ev_ports[i].qm_port.token_pop_mode = AUTO_POP;
4467 
4468 	rte_spinlock_init(&dlb2->qm_instance.resource_lock);
4469 
4470 	dlb2_iface_low_level_io_init();
4471 
4472 	dlb2_entry_points_init(dev);
4473 
4474 	dlb2_init_queue_depth_thresholds(dlb2,
4475 					 dlb2_args->qid_depth_thresholds.val);
4476 
4477 	return 0;
4478 }
4479 
4480 int
4481 dlb2_secondary_eventdev_probe(struct rte_eventdev *dev,
4482 			      const char *name)
4483 {
4484 	struct dlb2_eventdev *dlb2;
4485 	int err;
4486 
4487 	dlb2 = dev->data->dev_private;
4488 
4489 	evdev_dlb2_default_info.driver_name = name;
4490 
4491 	err = dlb2_iface_open(&dlb2->qm_instance, name);
4492 	if (err < 0) {
4493 		DLB2_LOG_ERR("could not open event hardware device, err=%d\n",
4494 			     err);
4495 		return err;
4496 	}
4497 
4498 	err = dlb2_hw_query_resources(dlb2);
4499 	if (err) {
4500 		DLB2_LOG_ERR("get resources err=%d for %s\n",
4501 			     err, name);
4502 		return err;
4503 	}
4504 
4505 	dlb2_iface_low_level_io_init();
4506 
4507 	dlb2_entry_points_init(dev);
4508 
4509 	return 0;
4510 }
4511 
4512 int
4513 dlb2_parse_params(const char *params,
4514 		  const char *name,
4515 		  struct dlb2_devargs *dlb2_args,
4516 		  uint8_t version)
4517 {
4518 	int ret = 0;
4519 	static const char * const args[] = { NUMA_NODE_ARG,
4520 					     DLB2_MAX_NUM_EVENTS,
4521 					     DLB2_NUM_DIR_CREDITS,
4522 					     DEV_ID_ARG,
4523 					     DLB2_QID_DEPTH_THRESH_ARG,
4524 					     DLB2_COS_ARG,
4525 					     DLB2_POLL_INTERVAL_ARG,
4526 					     DLB2_SW_CREDIT_QUANTA_ARG,
4527 					     DLB2_DEPTH_THRESH_ARG,
4528 					     DLB2_VECTOR_OPTS_DISAB_ARG,
4529 					     NULL };
4530 
4531 	if (params != NULL && params[0] != '\0') {
4532 		struct rte_kvargs *kvlist = rte_kvargs_parse(params, args);
4533 
4534 		if (kvlist == NULL) {
4535 			RTE_LOG(INFO, PMD,
4536 				"Ignoring unsupported parameters when creating device '%s'\n",
4537 				name);
4538 		} else {
4539 			int ret = rte_kvargs_process(kvlist, NUMA_NODE_ARG,
4540 						     set_numa_node,
4541 						     &dlb2_args->socket_id);
4542 			if (ret != 0) {
4543 				DLB2_LOG_ERR("%s: Error parsing numa node parameter",
4544 					     name);
4545 				rte_kvargs_free(kvlist);
4546 				return ret;
4547 			}
4548 
4549 			ret = rte_kvargs_process(kvlist, DLB2_MAX_NUM_EVENTS,
4550 						 set_max_num_events,
4551 						 &dlb2_args->max_num_events);
4552 			if (ret != 0) {
4553 				DLB2_LOG_ERR("%s: Error parsing max_num_events parameter",
4554 					     name);
4555 				rte_kvargs_free(kvlist);
4556 				return ret;
4557 			}
4558 
4559 			if (version == DLB2_HW_V2) {
4560 				ret = rte_kvargs_process(kvlist,
4561 					DLB2_NUM_DIR_CREDITS,
4562 					set_num_dir_credits,
4563 					&dlb2_args->num_dir_credits_override);
4564 				if (ret != 0) {
4565 					DLB2_LOG_ERR("%s: Error parsing num_dir_credits parameter",
4566 						     name);
4567 					rte_kvargs_free(kvlist);
4568 					return ret;
4569 				}
4570 			}
4571 			ret = rte_kvargs_process(kvlist, DEV_ID_ARG,
4572 						 set_dev_id,
4573 						 &dlb2_args->dev_id);
4574 			if (ret != 0) {
4575 				DLB2_LOG_ERR("%s: Error parsing dev_id parameter",
4576 					     name);
4577 				rte_kvargs_free(kvlist);
4578 				return ret;
4579 			}
4580 
4581 			if (version == DLB2_HW_V2) {
4582 				ret = rte_kvargs_process(
4583 					kvlist,
4584 					DLB2_QID_DEPTH_THRESH_ARG,
4585 					set_qid_depth_thresh,
4586 					&dlb2_args->qid_depth_thresholds);
4587 			} else {
4588 				ret = rte_kvargs_process(
4589 					kvlist,
4590 					DLB2_QID_DEPTH_THRESH_ARG,
4591 					set_qid_depth_thresh_v2_5,
4592 					&dlb2_args->qid_depth_thresholds);
4593 			}
4594 			if (ret != 0) {
4595 				DLB2_LOG_ERR("%s: Error parsing qid_depth_thresh parameter",
4596 					     name);
4597 				rte_kvargs_free(kvlist);
4598 				return ret;
4599 			}
4600 
4601 			ret = rte_kvargs_process(kvlist, DLB2_COS_ARG,
4602 						 set_cos,
4603 						 &dlb2_args->cos_id);
4604 			if (ret != 0) {
4605 				DLB2_LOG_ERR("%s: Error parsing cos parameter",
4606 					     name);
4607 				rte_kvargs_free(kvlist);
4608 				return ret;
4609 			}
4610 
4611 			ret = rte_kvargs_process(kvlist, DLB2_POLL_INTERVAL_ARG,
4612 						 set_poll_interval,
4613 						 &dlb2_args->poll_interval);
4614 			if (ret != 0) {
4615 				DLB2_LOG_ERR("%s: Error parsing poll interval parameter",
4616 					     name);
4617 				rte_kvargs_free(kvlist);
4618 				return ret;
4619 			}
4620 
4621 			ret = rte_kvargs_process(kvlist,
4622 						 DLB2_SW_CREDIT_QUANTA_ARG,
4623 						 set_sw_credit_quanta,
4624 						 &dlb2_args->sw_credit_quanta);
4625 			if (ret != 0) {
4626 				DLB2_LOG_ERR("%s: Error parsing sw xredit quanta parameter",
4627 					     name);
4628 				rte_kvargs_free(kvlist);
4629 				return ret;
4630 			}
4631 
4632 			ret = rte_kvargs_process(kvlist, DLB2_DEPTH_THRESH_ARG,
4633 					set_default_depth_thresh,
4634 					&dlb2_args->default_depth_thresh);
4635 			if (ret != 0) {
4636 				DLB2_LOG_ERR("%s: Error parsing set depth thresh parameter",
4637 					     name);
4638 				rte_kvargs_free(kvlist);
4639 				return ret;
4640 			}
4641 
4642 			ret = rte_kvargs_process(kvlist,
4643 					DLB2_VECTOR_OPTS_DISAB_ARG,
4644 					set_vector_opts_disab,
4645 					&dlb2_args->vector_opts_disabled);
4646 			if (ret != 0) {
4647 				DLB2_LOG_ERR("%s: Error parsing vector opts disabled",
4648 					     name);
4649 				rte_kvargs_free(kvlist);
4650 				return ret;
4651 			}
4652 
4653 			rte_kvargs_free(kvlist);
4654 		}
4655 	}
4656 	return ret;
4657 }
4658 RTE_LOG_REGISTER_DEFAULT(eventdev_dlb2_log_level, NOTICE);
4659