xref: /dpdk/drivers/event/dlb2/pf/base/dlb2_resource.c (revision f6ed136a)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016-2020 Intel Corporation
3  */
4 
5 #include "dlb2_user.h"
6 
7 #include "dlb2_hw_types.h"
8 #include "dlb2_osdep.h"
9 #include "dlb2_osdep_bitmap.h"
10 #include "dlb2_osdep_types.h"
11 #include "dlb2_regs.h"
12 #include "dlb2_resource.h"
13 
14 #include "../../dlb2_priv.h"
15 #include "../../dlb2_inline_fns.h"
16 
17 #define DLB2_DOM_LIST_HEAD(head, type) \
18 	DLB2_LIST_HEAD((head), type, domain_list)
19 
20 #define DLB2_FUNC_LIST_HEAD(head, type) \
21 	DLB2_LIST_HEAD((head), type, func_list)
22 
23 #define DLB2_DOM_LIST_FOR(head, ptr, iter) \
24 	DLB2_LIST_FOR_EACH(head, ptr, domain_list, iter)
25 
26 #define DLB2_FUNC_LIST_FOR(head, ptr, iter) \
27 	DLB2_LIST_FOR_EACH(head, ptr, func_list, iter)
28 
29 #define DLB2_DOM_LIST_FOR_SAFE(head, ptr, ptr_tmp, it, it_tmp) \
30 	DLB2_LIST_FOR_EACH_SAFE((head), ptr, ptr_tmp, domain_list, it, it_tmp)
31 
32 #define DLB2_FUNC_LIST_FOR_SAFE(head, ptr, ptr_tmp, it, it_tmp) \
33 	DLB2_LIST_FOR_EACH_SAFE((head), ptr, ptr_tmp, func_list, it, it_tmp)
34 
35 /*
36  * The PF driver cannot assume that a register write will affect subsequent HCW
37  * writes. To ensure a write completes, the driver must read back a CSR. This
38  * function only need be called for configuration that can occur after the
39  * domain has started; prior to starting, applications can't send HCWs.
40  */
dlb2_flush_csr(struct dlb2_hw * hw)41 static inline void dlb2_flush_csr(struct dlb2_hw *hw)
42 {
43 	DLB2_CSR_RD(hw, DLB2_SYS_TOTAL_VAS(hw->ver));
44 }
45 
dlb2_init_domain_rsrc_lists(struct dlb2_hw_domain * domain)46 static void dlb2_init_domain_rsrc_lists(struct dlb2_hw_domain *domain)
47 {
48 	int i;
49 
50 	dlb2_list_init_head(&domain->used_ldb_queues);
51 	dlb2_list_init_head(&domain->used_dir_pq_pairs);
52 	dlb2_list_init_head(&domain->avail_ldb_queues);
53 	dlb2_list_init_head(&domain->avail_dir_pq_pairs);
54 
55 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++)
56 		dlb2_list_init_head(&domain->used_ldb_ports[i]);
57 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++)
58 		dlb2_list_init_head(&domain->avail_ldb_ports[i]);
59 }
60 
dlb2_init_fn_rsrc_lists(struct dlb2_function_resources * rsrc)61 static void dlb2_init_fn_rsrc_lists(struct dlb2_function_resources *rsrc)
62 {
63 	int i;
64 	dlb2_list_init_head(&rsrc->avail_domains);
65 	dlb2_list_init_head(&rsrc->used_domains);
66 	dlb2_list_init_head(&rsrc->avail_ldb_queues);
67 	dlb2_list_init_head(&rsrc->avail_dir_pq_pairs);
68 
69 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++)
70 		dlb2_list_init_head(&rsrc->avail_ldb_ports[i]);
71 }
72 
73 /**
74  * dlb2_resource_free() - free device state memory
75  * @hw: dlb2_hw handle for a particular device.
76  *
77  * This function frees software state pointed to by dlb2_hw. This function
78  * should be called when resetting the device or unloading the driver.
79  */
dlb2_resource_free(struct dlb2_hw * hw)80 void dlb2_resource_free(struct dlb2_hw *hw)
81 {
82 	int i;
83 
84 	if (hw->pf.avail_hist_list_entries)
85 		dlb2_bitmap_free(hw->pf.avail_hist_list_entries);
86 
87 	for (i = 0; i < DLB2_MAX_NUM_VDEVS; i++) {
88 		if (hw->vdev[i].avail_hist_list_entries)
89 			dlb2_bitmap_free(hw->vdev[i].avail_hist_list_entries);
90 	}
91 }
92 
93 /**
94  * dlb2_resource_init() - initialize the device
95  * @hw: pointer to struct dlb2_hw.
96  * @ver: device version.
97  *
98  * This function initializes the device's software state (pointed to by the hw
99  * argument) and programs global scheduling QoS registers. This function should
100  * be called during driver initialization, and the dlb2_hw structure should
101  * be zero-initialized before calling the function.
102  *
103  * The dlb2_hw struct must be unique per DLB 2.0 device and persist until the
104  * device is reset.
105  *
106  * Return:
107  * Returns 0 upon success, <0 otherwise.
108  */
dlb2_resource_init(struct dlb2_hw * hw,enum dlb2_hw_ver ver)109 int dlb2_resource_init(struct dlb2_hw *hw, enum dlb2_hw_ver ver)
110 {
111 	struct dlb2_list_entry *list;
112 	unsigned int i;
113 	int ret;
114 
115 	/*
116 	 * For optimal load-balancing, ports that map to one or more QIDs in
117 	 * common should not be in numerical sequence. The port->QID mapping is
118 	 * application dependent, but the driver interleaves port IDs as much
119 	 * as possible to reduce the likelihood of sequential ports mapping to
120 	 * the same QID(s). This initial allocation of port IDs maximizes the
121 	 * average distance between an ID and its immediate neighbors (i.e.
122 	 * the distance from 1 to 0 and to 2, the distance from 2 to 1 and to
123 	 * 3, etc.).
124 	 */
125 	const u8 init_ldb_port_allocation[DLB2_MAX_NUM_LDB_PORTS] = {
126 		0,  7,  14,  5, 12,  3, 10,  1,  8, 15,  6, 13,  4, 11,  2,  9,
127 		16, 23, 30, 21, 28, 19, 26, 17, 24, 31, 22, 29, 20, 27, 18, 25,
128 		32, 39, 46, 37, 44, 35, 42, 33, 40, 47, 38, 45, 36, 43, 34, 41,
129 		48, 55, 62, 53, 60, 51, 58, 49, 56, 63, 54, 61, 52, 59, 50, 57,
130 	};
131 
132 	hw->ver = ver;
133 
134 	dlb2_init_fn_rsrc_lists(&hw->pf);
135 
136 	for (i = 0; i < DLB2_MAX_NUM_VDEVS; i++)
137 		dlb2_init_fn_rsrc_lists(&hw->vdev[i]);
138 
139 	for (i = 0; i < DLB2_MAX_NUM_DOMAINS; i++) {
140 		dlb2_init_domain_rsrc_lists(&hw->domains[i]);
141 		hw->domains[i].parent_func = &hw->pf;
142 	}
143 
144 	/* Give all resources to the PF driver */
145 	hw->pf.num_avail_domains = DLB2_MAX_NUM_DOMAINS;
146 	for (i = 0; i < hw->pf.num_avail_domains; i++) {
147 		list = &hw->domains[i].func_list;
148 
149 		dlb2_list_add(&hw->pf.avail_domains, list);
150 	}
151 
152 	hw->pf.num_avail_ldb_queues = DLB2_MAX_NUM_LDB_QUEUES;
153 	for (i = 0; i < hw->pf.num_avail_ldb_queues; i++) {
154 		list = &hw->rsrcs.ldb_queues[i].func_list;
155 
156 		dlb2_list_add(&hw->pf.avail_ldb_queues, list);
157 	}
158 
159 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++)
160 		hw->pf.num_avail_ldb_ports[i] =
161 			DLB2_MAX_NUM_LDB_PORTS / DLB2_NUM_COS_DOMAINS;
162 
163 	for (i = 0; i < DLB2_MAX_NUM_LDB_PORTS; i++) {
164 		int cos_id = i >> DLB2_NUM_COS_DOMAINS;
165 		struct dlb2_ldb_port *port;
166 
167 		port = &hw->rsrcs.ldb_ports[init_ldb_port_allocation[i]];
168 
169 		dlb2_list_add(&hw->pf.avail_ldb_ports[cos_id],
170 			      &port->func_list);
171 	}
172 
173 	hw->pf.num_avail_dir_pq_pairs = DLB2_MAX_NUM_DIR_PORTS(hw->ver);
174 	for (i = 0; i < hw->pf.num_avail_dir_pq_pairs; i++) {
175 		list = &hw->rsrcs.dir_pq_pairs[i].func_list;
176 
177 		dlb2_list_add(&hw->pf.avail_dir_pq_pairs, list);
178 	}
179 
180 	if (hw->ver == DLB2_HW_V2) {
181 		hw->pf.num_avail_qed_entries = DLB2_MAX_NUM_LDB_CREDITS;
182 		hw->pf.num_avail_dqed_entries =
183 			DLB2_MAX_NUM_DIR_CREDITS(hw->ver);
184 	} else {
185 		hw->pf.num_avail_entries = DLB2_MAX_NUM_CREDITS(hw->ver);
186 	}
187 
188 	hw->pf.num_avail_aqed_entries = DLB2_MAX_NUM_AQED_ENTRIES;
189 
190 	ret = dlb2_bitmap_alloc(&hw->pf.avail_hist_list_entries,
191 				DLB2_MAX_NUM_HIST_LIST_ENTRIES);
192 	if (ret)
193 		goto unwind;
194 
195 	ret = dlb2_bitmap_fill(hw->pf.avail_hist_list_entries);
196 	if (ret)
197 		goto unwind;
198 
199 	for (i = 0; i < DLB2_MAX_NUM_VDEVS; i++) {
200 		ret = dlb2_bitmap_alloc(&hw->vdev[i].avail_hist_list_entries,
201 					DLB2_MAX_NUM_HIST_LIST_ENTRIES);
202 		if (ret)
203 			goto unwind;
204 
205 		ret = dlb2_bitmap_zero(hw->vdev[i].avail_hist_list_entries);
206 		if (ret)
207 			goto unwind;
208 	}
209 
210 	/* Initialize the hardware resource IDs */
211 	for (i = 0; i < DLB2_MAX_NUM_DOMAINS; i++) {
212 		hw->domains[i].id.phys_id = i;
213 		hw->domains[i].id.vdev_owned = false;
214 	}
215 
216 	for (i = 0; i < DLB2_MAX_NUM_LDB_QUEUES; i++) {
217 		hw->rsrcs.ldb_queues[i].id.phys_id = i;
218 		hw->rsrcs.ldb_queues[i].id.vdev_owned = false;
219 	}
220 
221 	for (i = 0; i < DLB2_MAX_NUM_LDB_PORTS; i++) {
222 		hw->rsrcs.ldb_ports[i].id.phys_id = i;
223 		hw->rsrcs.ldb_ports[i].id.vdev_owned = false;
224 	}
225 
226 	for (i = 0; i < DLB2_MAX_NUM_DIR_PORTS(hw->ver); i++) {
227 		hw->rsrcs.dir_pq_pairs[i].id.phys_id = i;
228 		hw->rsrcs.dir_pq_pairs[i].id.vdev_owned = false;
229 	}
230 
231 	for (i = 0; i < DLB2_MAX_NUM_SEQUENCE_NUMBER_GROUPS; i++) {
232 		hw->rsrcs.sn_groups[i].id = i;
233 		/* Default mode (0) is 64 sequence numbers per queue */
234 		hw->rsrcs.sn_groups[i].mode = 0;
235 		hw->rsrcs.sn_groups[i].sequence_numbers_per_queue = 64;
236 		hw->rsrcs.sn_groups[i].slot_use_bitmap = 0;
237 	}
238 
239 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++)
240 		hw->cos_reservation[i] = 100 / DLB2_NUM_COS_DOMAINS;
241 
242 	return 0;
243 
244 unwind:
245 	dlb2_resource_free(hw);
246 
247 	return ret;
248 }
249 
250 /**
251  * dlb2_clr_pmcsr_disable() - power on bulk of DLB 2.0 logic
252  * @hw: dlb2_hw handle for a particular device.
253  * @ver: device version.
254  *
255  * Clearing the PMCSR must be done at initialization to make the device fully
256  * operational.
257  */
dlb2_clr_pmcsr_disable(struct dlb2_hw * hw,enum dlb2_hw_ver ver)258 void dlb2_clr_pmcsr_disable(struct dlb2_hw *hw, enum dlb2_hw_ver ver)
259 {
260 	u32 pmcsr_dis;
261 
262 	pmcsr_dis = DLB2_CSR_RD(hw, DLB2_CM_CFG_PM_PMCSR_DISABLE(ver));
263 
264 	DLB2_BITS_CLR(pmcsr_dis, DLB2_CM_CFG_PM_PMCSR_DISABLE_DISABLE);
265 
266 	DLB2_CSR_WR(hw, DLB2_CM_CFG_PM_PMCSR_DISABLE(ver), pmcsr_dis);
267 }
268 
269 /**
270  * dlb2_hw_get_num_resources() - query the PCI function's available resources
271  * @hw: dlb2_hw handle for a particular device.
272  * @arg: pointer to resource counts.
273  * @vdev_req: indicates whether this request came from a vdev.
274  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
275  *
276  * This function returns the number of available resources for the PF or for a
277  * VF.
278  *
279  * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual
280  * device.
281  *
282  * Return:
283  * Returns 0 upon success, -EINVAL if vdev_req is true and vdev_id is
284  * invalid.
285  */
dlb2_hw_get_num_resources(struct dlb2_hw * hw,struct dlb2_get_num_resources_args * arg,bool vdev_req,unsigned int vdev_id)286 int dlb2_hw_get_num_resources(struct dlb2_hw *hw,
287 			      struct dlb2_get_num_resources_args *arg,
288 			      bool vdev_req,
289 			      unsigned int vdev_id)
290 {
291 	struct dlb2_function_resources *rsrcs;
292 	struct dlb2_bitmap *map;
293 	int i;
294 
295 	if (vdev_req && vdev_id >= DLB2_MAX_NUM_VDEVS)
296 		return -EINVAL;
297 
298 	if (vdev_req)
299 		rsrcs = &hw->vdev[vdev_id];
300 	else
301 		rsrcs = &hw->pf;
302 
303 	arg->num_sched_domains = rsrcs->num_avail_domains;
304 
305 	arg->num_ldb_queues = rsrcs->num_avail_ldb_queues;
306 
307 	arg->num_ldb_ports = 0;
308 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++)
309 		arg->num_ldb_ports += rsrcs->num_avail_ldb_ports[i];
310 
311 	arg->num_cos_ldb_ports[0] = rsrcs->num_avail_ldb_ports[0];
312 	arg->num_cos_ldb_ports[1] = rsrcs->num_avail_ldb_ports[1];
313 	arg->num_cos_ldb_ports[2] = rsrcs->num_avail_ldb_ports[2];
314 	arg->num_cos_ldb_ports[3] = rsrcs->num_avail_ldb_ports[3];
315 
316 	arg->num_dir_ports = rsrcs->num_avail_dir_pq_pairs;
317 
318 	arg->num_atomic_inflights = rsrcs->num_avail_aqed_entries;
319 
320 	map = rsrcs->avail_hist_list_entries;
321 
322 	arg->num_hist_list_entries = dlb2_bitmap_count(map);
323 
324 	arg->max_contiguous_hist_list_entries =
325 		dlb2_bitmap_longest_set_range(map);
326 
327 	if (hw->ver == DLB2_HW_V2) {
328 		arg->num_ldb_credits = rsrcs->num_avail_qed_entries;
329 		arg->num_dir_credits = rsrcs->num_avail_dqed_entries;
330 	} else {
331 		arg->num_credits = rsrcs->num_avail_entries;
332 	}
333 	return 0;
334 }
335 
dlb2_configure_domain_credits_v2_5(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)336 static void dlb2_configure_domain_credits_v2_5(struct dlb2_hw *hw,
337 					       struct dlb2_hw_domain *domain)
338 {
339 	u32 reg = 0;
340 
341 	DLB2_BITS_SET(reg, domain->num_credits, DLB2_CHP_CFG_LDB_VAS_CRD_COUNT);
342 	DLB2_CSR_WR(hw, DLB2_CHP_CFG_VAS_CRD(domain->id.phys_id), reg);
343 }
344 
dlb2_configure_domain_credits_v2(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)345 static void dlb2_configure_domain_credits_v2(struct dlb2_hw *hw,
346 					     struct dlb2_hw_domain *domain)
347 {
348 	u32 reg = 0;
349 
350 	DLB2_BITS_SET(reg, domain->num_ldb_credits,
351 		      DLB2_CHP_CFG_LDB_VAS_CRD_COUNT);
352 	DLB2_CSR_WR(hw, DLB2_CHP_CFG_LDB_VAS_CRD(domain->id.phys_id), reg);
353 
354 	reg = 0;
355 	DLB2_BITS_SET(reg, domain->num_dir_credits,
356 		      DLB2_CHP_CFG_DIR_VAS_CRD_COUNT);
357 	DLB2_CSR_WR(hw, DLB2_CHP_CFG_DIR_VAS_CRD(domain->id.phys_id), reg);
358 }
359 
dlb2_configure_domain_credits(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)360 static void dlb2_configure_domain_credits(struct dlb2_hw *hw,
361 					  struct dlb2_hw_domain *domain)
362 {
363 	if (hw->ver == DLB2_HW_V2)
364 		dlb2_configure_domain_credits_v2(hw, domain);
365 	else
366 		dlb2_configure_domain_credits_v2_5(hw, domain);
367 }
368 
dlb2_attach_credits(struct dlb2_function_resources * rsrcs,struct dlb2_hw_domain * domain,u32 num_credits,struct dlb2_cmd_response * resp)369 static int dlb2_attach_credits(struct dlb2_function_resources *rsrcs,
370 			       struct dlb2_hw_domain *domain,
371 			       u32 num_credits,
372 			       struct dlb2_cmd_response *resp)
373 {
374 	if (rsrcs->num_avail_entries < num_credits) {
375 		resp->status = DLB2_ST_CREDITS_UNAVAILABLE;
376 		return -EINVAL;
377 	}
378 
379 	rsrcs->num_avail_entries -= num_credits;
380 	domain->num_credits += num_credits;
381 	return 0;
382 }
383 
384 static struct dlb2_ldb_port *
dlb2_get_next_ldb_port(struct dlb2_hw * hw,struct dlb2_function_resources * rsrcs,u32 domain_id,u32 cos_id)385 dlb2_get_next_ldb_port(struct dlb2_hw *hw,
386 		       struct dlb2_function_resources *rsrcs,
387 		       u32 domain_id,
388 		       u32 cos_id)
389 {
390 	struct dlb2_list_entry *iter;
391 	struct dlb2_ldb_port *port;
392 	RTE_SET_USED(iter);
393 
394 	/*
395 	 * To reduce the odds of consecutive load-balanced ports mapping to the
396 	 * same queue(s), the driver attempts to allocate ports whose neighbors
397 	 * are owned by a different domain.
398 	 */
399 	DLB2_FUNC_LIST_FOR(rsrcs->avail_ldb_ports[cos_id], port, iter) {
400 		u32 next, prev;
401 		u32 phys_id;
402 
403 		phys_id = port->id.phys_id;
404 		next = phys_id + 1;
405 		prev = phys_id - 1;
406 
407 		if (phys_id == DLB2_MAX_NUM_LDB_PORTS - 1)
408 			next = 0;
409 		if (phys_id == 0)
410 			prev = DLB2_MAX_NUM_LDB_PORTS - 1;
411 
412 		if (!hw->rsrcs.ldb_ports[next].owned ||
413 		    hw->rsrcs.ldb_ports[next].domain_id.phys_id == domain_id)
414 			continue;
415 
416 		if (!hw->rsrcs.ldb_ports[prev].owned ||
417 		    hw->rsrcs.ldb_ports[prev].domain_id.phys_id == domain_id)
418 			continue;
419 
420 		return port;
421 	}
422 
423 	/*
424 	 * Failing that, the driver looks for a port with one neighbor owned by
425 	 * a different domain and the other unallocated.
426 	 */
427 	DLB2_FUNC_LIST_FOR(rsrcs->avail_ldb_ports[cos_id], port, iter) {
428 		u32 next, prev;
429 		u32 phys_id;
430 
431 		phys_id = port->id.phys_id;
432 		next = phys_id + 1;
433 		prev = phys_id - 1;
434 
435 		if (phys_id == DLB2_MAX_NUM_LDB_PORTS - 1)
436 			next = 0;
437 		if (phys_id == 0)
438 			prev = DLB2_MAX_NUM_LDB_PORTS - 1;
439 
440 		if (!hw->rsrcs.ldb_ports[prev].owned &&
441 		    hw->rsrcs.ldb_ports[next].owned &&
442 		    hw->rsrcs.ldb_ports[next].domain_id.phys_id != domain_id)
443 			return port;
444 
445 		if (!hw->rsrcs.ldb_ports[next].owned &&
446 		    hw->rsrcs.ldb_ports[prev].owned &&
447 		    hw->rsrcs.ldb_ports[prev].domain_id.phys_id != domain_id)
448 			return port;
449 	}
450 
451 	/*
452 	 * Failing that, the driver looks for a port with both neighbors
453 	 * unallocated.
454 	 */
455 	DLB2_FUNC_LIST_FOR(rsrcs->avail_ldb_ports[cos_id], port, iter) {
456 		u32 next, prev;
457 		u32 phys_id;
458 
459 		phys_id = port->id.phys_id;
460 		next = phys_id + 1;
461 		prev = phys_id - 1;
462 
463 		if (phys_id == DLB2_MAX_NUM_LDB_PORTS - 1)
464 			next = 0;
465 		if (phys_id == 0)
466 			prev = DLB2_MAX_NUM_LDB_PORTS - 1;
467 
468 		if (!hw->rsrcs.ldb_ports[prev].owned &&
469 		    !hw->rsrcs.ldb_ports[next].owned)
470 			return port;
471 	}
472 
473 	/* If all else fails, the driver returns the next available port. */
474 	return DLB2_FUNC_LIST_HEAD(rsrcs->avail_ldb_ports[cos_id],
475 				   typeof(*port));
476 }
477 
__dlb2_attach_ldb_ports(struct dlb2_hw * hw,struct dlb2_function_resources * rsrcs,struct dlb2_hw_domain * domain,u32 num_ports,u32 cos_id,struct dlb2_cmd_response * resp)478 static int __dlb2_attach_ldb_ports(struct dlb2_hw *hw,
479 				   struct dlb2_function_resources *rsrcs,
480 				   struct dlb2_hw_domain *domain,
481 				   u32 num_ports,
482 				   u32 cos_id,
483 				   struct dlb2_cmd_response *resp)
484 {
485 	unsigned int i;
486 
487 	if (rsrcs->num_avail_ldb_ports[cos_id] < num_ports) {
488 		resp->status = DLB2_ST_LDB_PORTS_UNAVAILABLE;
489 		return -EINVAL;
490 	}
491 
492 	for (i = 0; i < num_ports; i++) {
493 		struct dlb2_ldb_port *port;
494 
495 		port = dlb2_get_next_ldb_port(hw, rsrcs,
496 					      domain->id.phys_id, cos_id);
497 		if (port == NULL) {
498 			DLB2_HW_ERR(hw,
499 				    "[%s()] Internal error: domain validation failed\n",
500 				    __func__);
501 			return -EFAULT;
502 		}
503 
504 		dlb2_list_del(&rsrcs->avail_ldb_ports[cos_id],
505 			      &port->func_list);
506 
507 		port->domain_id = domain->id;
508 		port->owned = true;
509 
510 		dlb2_list_add(&domain->avail_ldb_ports[cos_id],
511 			      &port->domain_list);
512 	}
513 
514 	rsrcs->num_avail_ldb_ports[cos_id] -= num_ports;
515 
516 	return 0;
517 }
518 
519 
dlb2_attach_ldb_ports(struct dlb2_hw * hw,struct dlb2_function_resources * rsrcs,struct dlb2_hw_domain * domain,struct dlb2_create_sched_domain_args * args,struct dlb2_cmd_response * resp)520 static int dlb2_attach_ldb_ports(struct dlb2_hw *hw,
521 				 struct dlb2_function_resources *rsrcs,
522 				 struct dlb2_hw_domain *domain,
523 				 struct dlb2_create_sched_domain_args *args,
524 				 struct dlb2_cmd_response *resp)
525 {
526 	unsigned int i, j;
527 	int ret;
528 
529 	if (args->cos_strict) {
530 		for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
531 			u32 num = args->num_cos_ldb_ports[i];
532 
533 			/* Allocate ports from specific classes-of-service */
534 			ret = __dlb2_attach_ldb_ports(hw,
535 						      rsrcs,
536 						      domain,
537 						      num,
538 						      i,
539 						      resp);
540 			if (ret)
541 				return ret;
542 		}
543 	} else {
544 		unsigned int k;
545 		u32 cos_id;
546 
547 		/*
548 		 * Attempt to allocate from specific class-of-service, but
549 		 * fallback to the other classes if that fails.
550 		 */
551 		for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
552 			for (j = 0; j < args->num_cos_ldb_ports[i]; j++) {
553 				for (k = 0; k < DLB2_NUM_COS_DOMAINS; k++) {
554 					cos_id = (i + k) % DLB2_NUM_COS_DOMAINS;
555 
556 					ret = __dlb2_attach_ldb_ports(hw,
557 								      rsrcs,
558 								      domain,
559 								      1,
560 								      cos_id,
561 								      resp);
562 					if (ret == 0)
563 						break;
564 				}
565 
566 				if (ret)
567 					return ret;
568 			}
569 		}
570 	}
571 
572 	/* Allocate num_ldb_ports from any class-of-service */
573 	for (i = 0; i < args->num_ldb_ports; i++) {
574 		for (j = 0; j < DLB2_NUM_COS_DOMAINS; j++) {
575 			ret = __dlb2_attach_ldb_ports(hw,
576 						      rsrcs,
577 						      domain,
578 						      1,
579 						      j,
580 						      resp);
581 			if (ret == 0)
582 				break;
583 		}
584 
585 		if (ret)
586 			return ret;
587 	}
588 
589 	return 0;
590 }
591 
dlb2_attach_dir_ports(struct dlb2_hw * hw,struct dlb2_function_resources * rsrcs,struct dlb2_hw_domain * domain,u32 num_ports,struct dlb2_cmd_response * resp)592 static int dlb2_attach_dir_ports(struct dlb2_hw *hw,
593 				 struct dlb2_function_resources *rsrcs,
594 				 struct dlb2_hw_domain *domain,
595 				 u32 num_ports,
596 				 struct dlb2_cmd_response *resp)
597 {
598 	unsigned int i;
599 
600 	if (rsrcs->num_avail_dir_pq_pairs < num_ports) {
601 		resp->status = DLB2_ST_DIR_PORTS_UNAVAILABLE;
602 		return -EINVAL;
603 	}
604 
605 	for (i = 0; i < num_ports; i++) {
606 		struct dlb2_dir_pq_pair *port;
607 
608 		port = DLB2_FUNC_LIST_HEAD(rsrcs->avail_dir_pq_pairs,
609 					   typeof(*port));
610 		if (port == NULL) {
611 			DLB2_HW_ERR(hw,
612 				    "[%s()] Internal error: domain validation failed\n",
613 				    __func__);
614 			return -EFAULT;
615 		}
616 
617 		dlb2_list_del(&rsrcs->avail_dir_pq_pairs, &port->func_list);
618 
619 		port->domain_id = domain->id;
620 		port->owned = true;
621 
622 		dlb2_list_add(&domain->avail_dir_pq_pairs, &port->domain_list);
623 	}
624 
625 	rsrcs->num_avail_dir_pq_pairs -= num_ports;
626 
627 	return 0;
628 }
629 
dlb2_attach_ldb_credits(struct dlb2_function_resources * rsrcs,struct dlb2_hw_domain * domain,u32 num_credits,struct dlb2_cmd_response * resp)630 static int dlb2_attach_ldb_credits(struct dlb2_function_resources *rsrcs,
631 				   struct dlb2_hw_domain *domain,
632 				   u32 num_credits,
633 				   struct dlb2_cmd_response *resp)
634 {
635 	if (rsrcs->num_avail_qed_entries < num_credits) {
636 		resp->status = DLB2_ST_LDB_CREDITS_UNAVAILABLE;
637 		return -EINVAL;
638 	}
639 
640 	rsrcs->num_avail_qed_entries -= num_credits;
641 	domain->num_ldb_credits += num_credits;
642 	return 0;
643 }
644 
dlb2_attach_dir_credits(struct dlb2_function_resources * rsrcs,struct dlb2_hw_domain * domain,u32 num_credits,struct dlb2_cmd_response * resp)645 static int dlb2_attach_dir_credits(struct dlb2_function_resources *rsrcs,
646 				   struct dlb2_hw_domain *domain,
647 				   u32 num_credits,
648 				   struct dlb2_cmd_response *resp)
649 {
650 	if (rsrcs->num_avail_dqed_entries < num_credits) {
651 		resp->status = DLB2_ST_DIR_CREDITS_UNAVAILABLE;
652 		return -EINVAL;
653 	}
654 
655 	rsrcs->num_avail_dqed_entries -= num_credits;
656 	domain->num_dir_credits += num_credits;
657 	return 0;
658 }
659 
660 
dlb2_attach_atomic_inflights(struct dlb2_function_resources * rsrcs,struct dlb2_hw_domain * domain,u32 num_atomic_inflights,struct dlb2_cmd_response * resp)661 static int dlb2_attach_atomic_inflights(struct dlb2_function_resources *rsrcs,
662 					struct dlb2_hw_domain *domain,
663 					u32 num_atomic_inflights,
664 					struct dlb2_cmd_response *resp)
665 {
666 	if (rsrcs->num_avail_aqed_entries < num_atomic_inflights) {
667 		resp->status = DLB2_ST_ATOMIC_INFLIGHTS_UNAVAILABLE;
668 		return -EINVAL;
669 	}
670 
671 	rsrcs->num_avail_aqed_entries -= num_atomic_inflights;
672 	domain->num_avail_aqed_entries += num_atomic_inflights;
673 	return 0;
674 }
675 
676 static int
dlb2_attach_domain_hist_list_entries(struct dlb2_function_resources * rsrcs,struct dlb2_hw_domain * domain,u32 num_hist_list_entries,struct dlb2_cmd_response * resp)677 dlb2_attach_domain_hist_list_entries(struct dlb2_function_resources *rsrcs,
678 				     struct dlb2_hw_domain *domain,
679 				     u32 num_hist_list_entries,
680 				     struct dlb2_cmd_response *resp)
681 {
682 	struct dlb2_bitmap *bitmap;
683 	int base;
684 
685 	if (num_hist_list_entries) {
686 		bitmap = rsrcs->avail_hist_list_entries;
687 
688 		base = dlb2_bitmap_find_set_bit_range(bitmap,
689 						      num_hist_list_entries);
690 		if (base < 0)
691 			goto error;
692 
693 		domain->total_hist_list_entries = num_hist_list_entries;
694 		domain->avail_hist_list_entries = num_hist_list_entries;
695 		domain->hist_list_entry_base = base;
696 		domain->hist_list_entry_offset = 0;
697 
698 		dlb2_bitmap_clear_range(bitmap, base, num_hist_list_entries);
699 	}
700 	return 0;
701 
702 error:
703 	resp->status = DLB2_ST_HIST_LIST_ENTRIES_UNAVAILABLE;
704 	return -EINVAL;
705 }
706 
dlb2_attach_ldb_queues(struct dlb2_hw * hw,struct dlb2_function_resources * rsrcs,struct dlb2_hw_domain * domain,u32 num_queues,struct dlb2_cmd_response * resp)707 static int dlb2_attach_ldb_queues(struct dlb2_hw *hw,
708 				  struct dlb2_function_resources *rsrcs,
709 				  struct dlb2_hw_domain *domain,
710 				  u32 num_queues,
711 				  struct dlb2_cmd_response *resp)
712 {
713 	unsigned int i;
714 
715 	if (rsrcs->num_avail_ldb_queues < num_queues) {
716 		resp->status = DLB2_ST_LDB_QUEUES_UNAVAILABLE;
717 		return -EINVAL;
718 	}
719 
720 	for (i = 0; i < num_queues; i++) {
721 		struct dlb2_ldb_queue *queue;
722 
723 		queue = DLB2_FUNC_LIST_HEAD(rsrcs->avail_ldb_queues,
724 					    typeof(*queue));
725 		if (queue == NULL) {
726 			DLB2_HW_ERR(hw,
727 				    "[%s()] Internal error: domain validation failed\n",
728 				    __func__);
729 			return -EFAULT;
730 		}
731 
732 		dlb2_list_del(&rsrcs->avail_ldb_queues, &queue->func_list);
733 
734 		queue->domain_id = domain->id;
735 		queue->owned = true;
736 
737 		dlb2_list_add(&domain->avail_ldb_queues, &queue->domain_list);
738 	}
739 
740 	rsrcs->num_avail_ldb_queues -= num_queues;
741 
742 	return 0;
743 }
744 
745 static int
dlb2_domain_attach_resources(struct dlb2_hw * hw,struct dlb2_function_resources * rsrcs,struct dlb2_hw_domain * domain,struct dlb2_create_sched_domain_args * args,struct dlb2_cmd_response * resp)746 dlb2_domain_attach_resources(struct dlb2_hw *hw,
747 			     struct dlb2_function_resources *rsrcs,
748 			     struct dlb2_hw_domain *domain,
749 			     struct dlb2_create_sched_domain_args *args,
750 			     struct dlb2_cmd_response *resp)
751 {
752 	int ret;
753 
754 	ret = dlb2_attach_ldb_queues(hw,
755 				     rsrcs,
756 				     domain,
757 				     args->num_ldb_queues,
758 				     resp);
759 	if (ret)
760 		return ret;
761 
762 	ret = dlb2_attach_ldb_ports(hw,
763 				    rsrcs,
764 				    domain,
765 				    args,
766 				    resp);
767 	if (ret)
768 		return ret;
769 
770 	ret = dlb2_attach_dir_ports(hw,
771 				    rsrcs,
772 				    domain,
773 				    args->num_dir_ports,
774 				    resp);
775 	if (ret)
776 		return ret;
777 
778 	if (hw->ver == DLB2_HW_V2) {
779 		ret = dlb2_attach_ldb_credits(rsrcs,
780 					      domain,
781 					      args->num_ldb_credits,
782 					      resp);
783 		if (ret)
784 			return ret;
785 
786 		ret = dlb2_attach_dir_credits(rsrcs,
787 					      domain,
788 					      args->num_dir_credits,
789 					      resp);
790 		if (ret)
791 			return ret;
792 	} else {  /* DLB 2.5 */
793 		ret = dlb2_attach_credits(rsrcs,
794 					  domain,
795 					  args->num_credits,
796 					  resp);
797 		if (ret)
798 			return ret;
799 	}
800 
801 	ret = dlb2_attach_domain_hist_list_entries(rsrcs,
802 						   domain,
803 						   args->num_hist_list_entries,
804 						   resp);
805 	if (ret)
806 		return ret;
807 
808 	ret = dlb2_attach_atomic_inflights(rsrcs,
809 					   domain,
810 					   args->num_atomic_inflights,
811 					   resp);
812 	if (ret)
813 		return ret;
814 
815 	dlb2_configure_domain_credits(hw, domain);
816 
817 	domain->configured = true;
818 
819 	domain->started = false;
820 
821 	rsrcs->num_avail_domains--;
822 
823 	return 0;
824 }
825 
826 static int
dlb2_verify_create_sched_dom_args(struct dlb2_function_resources * rsrcs,struct dlb2_create_sched_domain_args * args,struct dlb2_cmd_response * resp,struct dlb2_hw * hw,struct dlb2_hw_domain ** out_domain)827 dlb2_verify_create_sched_dom_args(struct dlb2_function_resources *rsrcs,
828 				  struct dlb2_create_sched_domain_args *args,
829 				  struct dlb2_cmd_response *resp,
830 				  struct dlb2_hw *hw,
831 				  struct dlb2_hw_domain **out_domain)
832 {
833 	u32 num_avail_ldb_ports, req_ldb_ports;
834 	struct dlb2_bitmap *avail_hl_entries;
835 	unsigned int max_contig_hl_range;
836 	struct dlb2_hw_domain *domain;
837 	int i;
838 
839 	avail_hl_entries = rsrcs->avail_hist_list_entries;
840 
841 	max_contig_hl_range = dlb2_bitmap_longest_set_range(avail_hl_entries);
842 
843 	num_avail_ldb_ports = 0;
844 	req_ldb_ports = 0;
845 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
846 		num_avail_ldb_ports += rsrcs->num_avail_ldb_ports[i];
847 
848 		req_ldb_ports += args->num_cos_ldb_ports[i];
849 	}
850 
851 	req_ldb_ports += args->num_ldb_ports;
852 
853 	if (rsrcs->num_avail_domains < 1) {
854 		resp->status = DLB2_ST_DOMAIN_UNAVAILABLE;
855 		return -EINVAL;
856 	}
857 
858 	domain = DLB2_FUNC_LIST_HEAD(rsrcs->avail_domains, typeof(*domain));
859 	if (domain == NULL) {
860 		resp->status = DLB2_ST_DOMAIN_UNAVAILABLE;
861 		return -EFAULT;
862 	}
863 
864 	if (rsrcs->num_avail_ldb_queues < args->num_ldb_queues) {
865 		resp->status = DLB2_ST_LDB_QUEUES_UNAVAILABLE;
866 		return -EINVAL;
867 	}
868 
869 	if (req_ldb_ports > num_avail_ldb_ports) {
870 		resp->status = DLB2_ST_LDB_PORTS_UNAVAILABLE;
871 		return -EINVAL;
872 	}
873 
874 	for (i = 0; args->cos_strict && i < DLB2_NUM_COS_DOMAINS; i++) {
875 		if (args->num_cos_ldb_ports[i] >
876 		    rsrcs->num_avail_ldb_ports[i]) {
877 			resp->status = DLB2_ST_LDB_PORTS_UNAVAILABLE;
878 			return -EINVAL;
879 		}
880 	}
881 
882 	if (args->num_ldb_queues > 0 && req_ldb_ports == 0) {
883 		resp->status = DLB2_ST_LDB_PORT_REQUIRED_FOR_LDB_QUEUES;
884 		return -EINVAL;
885 	}
886 
887 	if (rsrcs->num_avail_dir_pq_pairs < args->num_dir_ports) {
888 		resp->status = DLB2_ST_DIR_PORTS_UNAVAILABLE;
889 		return -EINVAL;
890 	}
891 	if (hw->ver == DLB2_HW_V2_5) {
892 		if (rsrcs->num_avail_entries < args->num_credits) {
893 			resp->status = DLB2_ST_CREDITS_UNAVAILABLE;
894 			return -EINVAL;
895 		}
896 	} else {
897 		if (rsrcs->num_avail_qed_entries < args->num_ldb_credits) {
898 			resp->status = DLB2_ST_LDB_CREDITS_UNAVAILABLE;
899 			return -EINVAL;
900 		}
901 		if (rsrcs->num_avail_dqed_entries < args->num_dir_credits) {
902 			resp->status = DLB2_ST_DIR_CREDITS_UNAVAILABLE;
903 			return -EINVAL;
904 		}
905 	}
906 
907 	if (rsrcs->num_avail_aqed_entries < args->num_atomic_inflights) {
908 		resp->status = DLB2_ST_ATOMIC_INFLIGHTS_UNAVAILABLE;
909 		return -EINVAL;
910 	}
911 
912 	if (max_contig_hl_range < args->num_hist_list_entries) {
913 		resp->status = DLB2_ST_HIST_LIST_ENTRIES_UNAVAILABLE;
914 		return -EINVAL;
915 	}
916 
917 	*out_domain = domain;
918 
919 	return 0;
920 }
921 
922 static void
dlb2_log_create_sched_domain_args(struct dlb2_hw * hw,struct dlb2_create_sched_domain_args * args,bool vdev_req,unsigned int vdev_id)923 dlb2_log_create_sched_domain_args(struct dlb2_hw *hw,
924 				  struct dlb2_create_sched_domain_args *args,
925 				  bool vdev_req,
926 				  unsigned int vdev_id)
927 {
928 	DLB2_HW_DBG(hw, "DLB2 create sched domain arguments:\n");
929 	if (vdev_req)
930 		DLB2_HW_DBG(hw, "(Request from vdev %d)\n", vdev_id);
931 	DLB2_HW_DBG(hw, "\tNumber of LDB queues:          %d\n",
932 		    args->num_ldb_queues);
933 	DLB2_HW_DBG(hw, "\tNumber of LDB ports (any CoS): %d\n",
934 		    args->num_ldb_ports);
935 	DLB2_HW_DBG(hw, "\tNumber of LDB ports (CoS 0):   %d\n",
936 		    args->num_cos_ldb_ports[0]);
937 	DLB2_HW_DBG(hw, "\tNumber of LDB ports (CoS 1):   %d\n",
938 		    args->num_cos_ldb_ports[1]);
939 	DLB2_HW_DBG(hw, "\tNumber of LDB ports (CoS 2):   %d\n",
940 		    args->num_cos_ldb_ports[2]);
941 	DLB2_HW_DBG(hw, "\tNumber of LDB ports (CoS 3):   %d\n",
942 		    args->num_cos_ldb_ports[3]);
943 	DLB2_HW_DBG(hw, "\tStrict CoS allocation:         %d\n",
944 		    args->cos_strict);
945 	DLB2_HW_DBG(hw, "\tNumber of DIR ports:           %d\n",
946 		    args->num_dir_ports);
947 	DLB2_HW_DBG(hw, "\tNumber of ATM inflights:       %d\n",
948 		    args->num_atomic_inflights);
949 	DLB2_HW_DBG(hw, "\tNumber of hist list entries:   %d\n",
950 		    args->num_hist_list_entries);
951 	if (hw->ver == DLB2_HW_V2) {
952 		DLB2_HW_DBG(hw, "\tNumber of LDB credits:         %d\n",
953 			    args->num_ldb_credits);
954 		DLB2_HW_DBG(hw, "\tNumber of DIR credits:         %d\n",
955 			    args->num_dir_credits);
956 	} else {
957 		DLB2_HW_DBG(hw, "\tNumber of credits:         %d\n",
958 			    args->num_credits);
959 	}
960 }
961 
962 /**
963  * dlb2_hw_create_sched_domain() - create a scheduling domain
964  * @hw: dlb2_hw handle for a particular device.
965  * @args: scheduling domain creation arguments.
966  * @resp: response structure.
967  * @vdev_req: indicates whether this request came from a vdev.
968  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
969  *
970  * This function creates a scheduling domain containing the resources specified
971  * in args. The individual resources (queues, ports, credits) can be configured
972  * after creating a scheduling domain.
973  *
974  * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual
975  * device.
976  *
977  * Return:
978  * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
979  * assigned a detailed error code from enum dlb2_error. If successful, resp->id
980  * contains the domain ID.
981  *
982  * resp->id contains a virtual ID if vdev_req is true.
983  *
984  * Errors:
985  * EINVAL - A requested resource is unavailable, or the requested domain name
986  *	    is already in use.
987  * EFAULT - Internal error (resp->status not set).
988  */
dlb2_hw_create_sched_domain(struct dlb2_hw * hw,struct dlb2_create_sched_domain_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id)989 int dlb2_hw_create_sched_domain(struct dlb2_hw *hw,
990 				struct dlb2_create_sched_domain_args *args,
991 				struct dlb2_cmd_response *resp,
992 				bool vdev_req,
993 				unsigned int vdev_id)
994 {
995 	struct dlb2_function_resources *rsrcs;
996 	struct dlb2_hw_domain *domain;
997 	int ret;
998 
999 	rsrcs = (vdev_req) ? &hw->vdev[vdev_id] : &hw->pf;
1000 
1001 	dlb2_log_create_sched_domain_args(hw, args, vdev_req, vdev_id);
1002 
1003 	/*
1004 	 * Verify that hardware resources are available before attempting to
1005 	 * satisfy the request. This simplifies the error unwinding code.
1006 	 */
1007 	ret = dlb2_verify_create_sched_dom_args(rsrcs, args, resp, hw, &domain);
1008 	if (ret)
1009 		return ret;
1010 
1011 	dlb2_init_domain_rsrc_lists(domain);
1012 
1013 	ret = dlb2_domain_attach_resources(hw, rsrcs, domain, args, resp);
1014 	if (ret) {
1015 		DLB2_HW_ERR(hw,
1016 			    "[%s()] Internal error: failed to verify args.\n",
1017 			    __func__);
1018 
1019 		return ret;
1020 	}
1021 
1022 	dlb2_list_del(&rsrcs->avail_domains, &domain->func_list);
1023 
1024 	dlb2_list_add(&rsrcs->used_domains, &domain->func_list);
1025 
1026 	resp->id = (vdev_req) ? domain->id.virt_id : domain->id.phys_id;
1027 	resp->status = 0;
1028 
1029 	return 0;
1030 }
1031 
dlb2_dir_port_cq_disable(struct dlb2_hw * hw,struct dlb2_dir_pq_pair * port)1032 static void dlb2_dir_port_cq_disable(struct dlb2_hw *hw,
1033 				     struct dlb2_dir_pq_pair *port)
1034 {
1035 	u32 reg = 0;
1036 
1037 	DLB2_BIT_SET(reg, DLB2_LSP_CQ_DIR_DSBL_DISABLED);
1038 	DLB2_CSR_WR(hw, DLB2_LSP_CQ_DIR_DSBL(hw->ver, port->id.phys_id), reg);
1039 
1040 	dlb2_flush_csr(hw);
1041 }
1042 
dlb2_dir_cq_token_count(struct dlb2_hw * hw,struct dlb2_dir_pq_pair * port)1043 static u32 dlb2_dir_cq_token_count(struct dlb2_hw *hw,
1044 				   struct dlb2_dir_pq_pair *port)
1045 {
1046 	u32 cnt;
1047 
1048 	cnt = DLB2_CSR_RD(hw,
1049 			  DLB2_LSP_CQ_DIR_TKN_CNT(hw->ver, port->id.phys_id));
1050 
1051 	/*
1052 	 * Account for the initial token count, which is used in order to
1053 	 * provide a CQ with depth less than 8.
1054 	 */
1055 
1056 	return DLB2_BITS_GET(cnt, DLB2_LSP_CQ_DIR_TKN_CNT_COUNT) -
1057 	       port->init_tkn_cnt;
1058 }
1059 
dlb2_drain_dir_cq(struct dlb2_hw * hw,struct dlb2_dir_pq_pair * port)1060 static void dlb2_drain_dir_cq(struct dlb2_hw *hw,
1061 			      struct dlb2_dir_pq_pair *port)
1062 {
1063 	unsigned int port_id = port->id.phys_id;
1064 	u32 cnt;
1065 
1066 	/* Return any outstanding tokens */
1067 	cnt = dlb2_dir_cq_token_count(hw, port);
1068 
1069 	if (cnt != 0) {
1070 		struct dlb2_hcw hcw_mem[8], *hcw;
1071 		void __iomem *pp_addr;
1072 
1073 		pp_addr = os_map_producer_port(hw, port_id, false);
1074 
1075 		/* Point hcw to a 64B-aligned location */
1076 		hcw = (struct dlb2_hcw *)((uintptr_t)&hcw_mem[4] & ~0x3F);
1077 
1078 		/*
1079 		 * Program the first HCW for a batch token return and
1080 		 * the rest as NOOPS
1081 		 */
1082 		memset(hcw, 0, 4 * sizeof(*hcw));
1083 		hcw->cq_token = 1;
1084 		hcw->lock_id = cnt - 1;
1085 
1086 		dlb2_movdir64b(pp_addr, hcw);
1087 
1088 		os_fence_hcw(hw, pp_addr);
1089 
1090 		os_unmap_producer_port(hw, pp_addr);
1091 	}
1092 }
1093 
dlb2_dir_port_cq_enable(struct dlb2_hw * hw,struct dlb2_dir_pq_pair * port)1094 static void dlb2_dir_port_cq_enable(struct dlb2_hw *hw,
1095 				    struct dlb2_dir_pq_pair *port)
1096 {
1097 	u32 reg = 0;
1098 
1099 	DLB2_CSR_WR(hw, DLB2_LSP_CQ_DIR_DSBL(hw->ver, port->id.phys_id), reg);
1100 
1101 	dlb2_flush_csr(hw);
1102 }
1103 
dlb2_domain_drain_dir_cqs(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,bool toggle_port)1104 static int dlb2_domain_drain_dir_cqs(struct dlb2_hw *hw,
1105 				     struct dlb2_hw_domain *domain,
1106 				     bool toggle_port)
1107 {
1108 	struct dlb2_list_entry *iter;
1109 	struct dlb2_dir_pq_pair *port;
1110 	RTE_SET_USED(iter);
1111 
1112 	DLB2_DOM_LIST_FOR(domain->used_dir_pq_pairs, port, iter) {
1113 		/*
1114 		 * Can't drain a port if it's not configured, and there's
1115 		 * nothing to drain if its queue is unconfigured.
1116 		 */
1117 		if (!port->port_configured || !port->queue_configured)
1118 			continue;
1119 
1120 		if (toggle_port)
1121 			dlb2_dir_port_cq_disable(hw, port);
1122 
1123 		dlb2_drain_dir_cq(hw, port);
1124 
1125 		if (toggle_port)
1126 			dlb2_dir_port_cq_enable(hw, port);
1127 	}
1128 
1129 	return 0;
1130 }
1131 
dlb2_dir_queue_depth(struct dlb2_hw * hw,struct dlb2_dir_pq_pair * queue)1132 static u32 dlb2_dir_queue_depth(struct dlb2_hw *hw,
1133 				struct dlb2_dir_pq_pair *queue)
1134 {
1135 	u32 cnt;
1136 
1137 	cnt = DLB2_CSR_RD(hw, DLB2_LSP_QID_DIR_ENQUEUE_CNT(hw->ver,
1138 						      queue->id.phys_id));
1139 
1140 	return DLB2_BITS_GET(cnt, DLB2_LSP_QID_DIR_ENQUEUE_CNT_COUNT);
1141 }
1142 
dlb2_dir_queue_is_empty(struct dlb2_hw * hw,struct dlb2_dir_pq_pair * queue)1143 static bool dlb2_dir_queue_is_empty(struct dlb2_hw *hw,
1144 				    struct dlb2_dir_pq_pair *queue)
1145 {
1146 	return dlb2_dir_queue_depth(hw, queue) == 0;
1147 }
1148 
dlb2_domain_dir_queues_empty(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)1149 static bool dlb2_domain_dir_queues_empty(struct dlb2_hw *hw,
1150 					 struct dlb2_hw_domain *domain)
1151 {
1152 	struct dlb2_list_entry *iter;
1153 	struct dlb2_dir_pq_pair *queue;
1154 	RTE_SET_USED(iter);
1155 
1156 	DLB2_DOM_LIST_FOR(domain->used_dir_pq_pairs, queue, iter) {
1157 		if (!dlb2_dir_queue_is_empty(hw, queue))
1158 			return false;
1159 	}
1160 
1161 	return true;
1162 }
dlb2_domain_drain_dir_queues(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)1163 static int dlb2_domain_drain_dir_queues(struct dlb2_hw *hw,
1164 					struct dlb2_hw_domain *domain)
1165 {
1166 	int i;
1167 
1168 	/* If the domain hasn't been started, there's no traffic to drain */
1169 	if (!domain->started)
1170 		return 0;
1171 
1172 	for (i = 0; i < DLB2_MAX_QID_EMPTY_CHECK_LOOPS; i++) {
1173 		dlb2_domain_drain_dir_cqs(hw, domain, true);
1174 
1175 		if (dlb2_domain_dir_queues_empty(hw, domain))
1176 			break;
1177 	}
1178 
1179 	if (i == DLB2_MAX_QID_EMPTY_CHECK_LOOPS) {
1180 		DLB2_HW_ERR(hw,
1181 			    "[%s()] Internal error: failed to empty queues\n",
1182 			    __func__);
1183 		return -EFAULT;
1184 	}
1185 
1186 	/*
1187 	 * Drain the CQs one more time. For the queues to go empty, they would
1188 	 * have scheduled one or more QEs.
1189 	 */
1190 	dlb2_domain_drain_dir_cqs(hw, domain, true);
1191 
1192 	return 0;
1193 }
1194 
dlb2_ldb_port_cq_enable(struct dlb2_hw * hw,struct dlb2_ldb_port * port)1195 static void dlb2_ldb_port_cq_enable(struct dlb2_hw *hw,
1196 				    struct dlb2_ldb_port *port)
1197 {
1198 	u32 reg = 0;
1199 
1200 	/*
1201 	 * Don't re-enable the port if a removal is pending. The caller should
1202 	 * mark this port as enabled (if it isn't already), and when the
1203 	 * removal completes the port will be enabled.
1204 	 */
1205 	if (port->num_pending_removals)
1206 		return;
1207 
1208 	DLB2_CSR_WR(hw, DLB2_LSP_CQ_LDB_DSBL(hw->ver, port->id.phys_id), reg);
1209 
1210 	dlb2_flush_csr(hw);
1211 }
1212 
dlb2_ldb_port_cq_disable(struct dlb2_hw * hw,struct dlb2_ldb_port * port)1213 static void dlb2_ldb_port_cq_disable(struct dlb2_hw *hw,
1214 				     struct dlb2_ldb_port *port)
1215 {
1216 	u32 reg = 0;
1217 
1218 	DLB2_BIT_SET(reg, DLB2_LSP_CQ_LDB_DSBL_DISABLED);
1219 	DLB2_CSR_WR(hw, DLB2_LSP_CQ_LDB_DSBL(hw->ver, port->id.phys_id), reg);
1220 
1221 	dlb2_flush_csr(hw);
1222 }
1223 
dlb2_ldb_cq_inflight_count(struct dlb2_hw * hw,struct dlb2_ldb_port * port)1224 static u32 dlb2_ldb_cq_inflight_count(struct dlb2_hw *hw,
1225 				      struct dlb2_ldb_port *port)
1226 {
1227 	u32 cnt;
1228 
1229 	cnt = DLB2_CSR_RD(hw,
1230 			  DLB2_LSP_CQ_LDB_INFL_CNT(hw->ver, port->id.phys_id));
1231 
1232 	return DLB2_BITS_GET(cnt, DLB2_LSP_CQ_LDB_INFL_CNT_COUNT);
1233 }
1234 
dlb2_ldb_cq_token_count(struct dlb2_hw * hw,struct dlb2_ldb_port * port)1235 static u32 dlb2_ldb_cq_token_count(struct dlb2_hw *hw,
1236 				   struct dlb2_ldb_port *port)
1237 {
1238 	u32 cnt;
1239 
1240 	cnt = DLB2_CSR_RD(hw,
1241 			  DLB2_LSP_CQ_LDB_TKN_CNT(hw->ver, port->id.phys_id));
1242 
1243 	/*
1244 	 * Account for the initial token count, which is used in order to
1245 	 * provide a CQ with depth less than 8.
1246 	 */
1247 
1248 	return DLB2_BITS_GET(cnt, DLB2_LSP_CQ_LDB_TKN_CNT_TOKEN_COUNT) -
1249 		port->init_tkn_cnt;
1250 }
1251 
dlb2_drain_ldb_cq(struct dlb2_hw * hw,struct dlb2_ldb_port * port)1252 static void dlb2_drain_ldb_cq(struct dlb2_hw *hw, struct dlb2_ldb_port *port)
1253 {
1254 	u32 infl_cnt, tkn_cnt;
1255 	unsigned int i;
1256 
1257 	infl_cnt = dlb2_ldb_cq_inflight_count(hw, port);
1258 	tkn_cnt = dlb2_ldb_cq_token_count(hw, port);
1259 
1260 	if (infl_cnt || tkn_cnt) {
1261 		struct dlb2_hcw hcw_mem[8], *hcw;
1262 		void __iomem *pp_addr;
1263 
1264 		pp_addr = os_map_producer_port(hw, port->id.phys_id, true);
1265 
1266 		/* Point hcw to a 64B-aligned location */
1267 		hcw = (struct dlb2_hcw *)((uintptr_t)&hcw_mem[4] & ~0x3F);
1268 
1269 		/*
1270 		 * Program the first HCW for a completion and token return and
1271 		 * the other HCWs as NOOPS
1272 		 */
1273 
1274 		memset(hcw, 0, 4 * sizeof(*hcw));
1275 		hcw->qe_comp = (infl_cnt > 0);
1276 		hcw->cq_token = (tkn_cnt > 0);
1277 		hcw->lock_id = tkn_cnt - 1;
1278 
1279 		/* Return tokens in the first HCW */
1280 		dlb2_movdir64b(pp_addr, hcw);
1281 
1282 		hcw->cq_token = 0;
1283 
1284 		/* Issue remaining completions (if any) */
1285 		for (i = 1; i < infl_cnt; i++)
1286 			dlb2_movdir64b(pp_addr, hcw);
1287 
1288 		os_fence_hcw(hw, pp_addr);
1289 
1290 		os_unmap_producer_port(hw, pp_addr);
1291 	}
1292 }
1293 
dlb2_domain_drain_ldb_cqs(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,bool toggle_port)1294 static void dlb2_domain_drain_ldb_cqs(struct dlb2_hw *hw,
1295 				      struct dlb2_hw_domain *domain,
1296 				      bool toggle_port)
1297 {
1298 	struct dlb2_list_entry *iter;
1299 	struct dlb2_ldb_port *port;
1300 	int i;
1301 	RTE_SET_USED(iter);
1302 
1303 	/* If the domain hasn't been started, there's no traffic to drain */
1304 	if (!domain->started)
1305 		return;
1306 
1307 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
1308 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) {
1309 			if (toggle_port)
1310 				dlb2_ldb_port_cq_disable(hw, port);
1311 
1312 			dlb2_drain_ldb_cq(hw, port);
1313 
1314 			if (toggle_port)
1315 				dlb2_ldb_port_cq_enable(hw, port);
1316 		}
1317 	}
1318 }
1319 
dlb2_ldb_queue_depth(struct dlb2_hw * hw,struct dlb2_ldb_queue * queue)1320 static u32 dlb2_ldb_queue_depth(struct dlb2_hw *hw,
1321 				struct dlb2_ldb_queue *queue)
1322 {
1323 	u32 aqed, ldb, atm;
1324 
1325 	aqed = DLB2_CSR_RD(hw, DLB2_LSP_QID_AQED_ACTIVE_CNT(hw->ver,
1326 						       queue->id.phys_id));
1327 	ldb = DLB2_CSR_RD(hw, DLB2_LSP_QID_LDB_ENQUEUE_CNT(hw->ver,
1328 						      queue->id.phys_id));
1329 	atm = DLB2_CSR_RD(hw,
1330 			  DLB2_LSP_QID_ATM_ACTIVE(hw->ver, queue->id.phys_id));
1331 
1332 	return DLB2_BITS_GET(aqed, DLB2_LSP_QID_AQED_ACTIVE_CNT_COUNT)
1333 	       + DLB2_BITS_GET(ldb, DLB2_LSP_QID_LDB_ENQUEUE_CNT_COUNT)
1334 	       + DLB2_BITS_GET(atm, DLB2_LSP_QID_ATM_ACTIVE_COUNT);
1335 }
1336 
dlb2_ldb_queue_is_empty(struct dlb2_hw * hw,struct dlb2_ldb_queue * queue)1337 static bool dlb2_ldb_queue_is_empty(struct dlb2_hw *hw,
1338 				    struct dlb2_ldb_queue *queue)
1339 {
1340 	return dlb2_ldb_queue_depth(hw, queue) == 0;
1341 }
1342 
dlb2_domain_mapped_queues_empty(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)1343 static bool dlb2_domain_mapped_queues_empty(struct dlb2_hw *hw,
1344 					    struct dlb2_hw_domain *domain)
1345 {
1346 	struct dlb2_list_entry *iter;
1347 	struct dlb2_ldb_queue *queue;
1348 	RTE_SET_USED(iter);
1349 
1350 	DLB2_DOM_LIST_FOR(domain->used_ldb_queues, queue, iter) {
1351 		if (queue->num_mappings == 0)
1352 			continue;
1353 
1354 		if (!dlb2_ldb_queue_is_empty(hw, queue))
1355 			return false;
1356 	}
1357 
1358 	return true;
1359 }
1360 
dlb2_domain_drain_mapped_queues(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)1361 static int dlb2_domain_drain_mapped_queues(struct dlb2_hw *hw,
1362 					   struct dlb2_hw_domain *domain)
1363 {
1364 	int i;
1365 
1366 	/* If the domain hasn't been started, there's no traffic to drain */
1367 	if (!domain->started)
1368 		return 0;
1369 
1370 	if (domain->num_pending_removals > 0) {
1371 		DLB2_HW_ERR(hw,
1372 			    "[%s()] Internal error: failed to unmap domain queues\n",
1373 			    __func__);
1374 		return -EFAULT;
1375 	}
1376 
1377 	for (i = 0; i < DLB2_MAX_QID_EMPTY_CHECK_LOOPS; i++) {
1378 		dlb2_domain_drain_ldb_cqs(hw, domain, true);
1379 
1380 		if (dlb2_domain_mapped_queues_empty(hw, domain))
1381 			break;
1382 	}
1383 
1384 	if (i == DLB2_MAX_QID_EMPTY_CHECK_LOOPS) {
1385 		DLB2_HW_ERR(hw,
1386 			    "[%s()] Internal error: failed to empty queues\n",
1387 			    __func__);
1388 		return -EFAULT;
1389 	}
1390 
1391 	/*
1392 	 * Drain the CQs one more time. For the queues to go empty, they would
1393 	 * have scheduled one or more QEs.
1394 	 */
1395 	dlb2_domain_drain_ldb_cqs(hw, domain, true);
1396 
1397 	return 0;
1398 }
1399 
dlb2_domain_enable_ldb_cqs(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)1400 static void dlb2_domain_enable_ldb_cqs(struct dlb2_hw *hw,
1401 				       struct dlb2_hw_domain *domain)
1402 {
1403 	struct dlb2_list_entry *iter;
1404 	struct dlb2_ldb_port *port;
1405 	int i;
1406 	RTE_SET_USED(iter);
1407 
1408 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
1409 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) {
1410 			port->enabled = true;
1411 
1412 			dlb2_ldb_port_cq_enable(hw, port);
1413 		}
1414 	}
1415 }
1416 
1417 static struct dlb2_ldb_queue *
dlb2_get_ldb_queue_from_id(struct dlb2_hw * hw,u32 id,bool vdev_req,unsigned int vdev_id)1418 dlb2_get_ldb_queue_from_id(struct dlb2_hw *hw,
1419 			   u32 id,
1420 			   bool vdev_req,
1421 			   unsigned int vdev_id)
1422 {
1423 	struct dlb2_list_entry *iter1;
1424 	struct dlb2_list_entry *iter2;
1425 	struct dlb2_function_resources *rsrcs;
1426 	struct dlb2_hw_domain *domain;
1427 	struct dlb2_ldb_queue *queue;
1428 	RTE_SET_USED(iter1);
1429 	RTE_SET_USED(iter2);
1430 
1431 	if (id >= DLB2_MAX_NUM_LDB_QUEUES)
1432 		return NULL;
1433 
1434 	rsrcs = (vdev_req) ? &hw->vdev[vdev_id] : &hw->pf;
1435 
1436 	if (!vdev_req)
1437 		return &hw->rsrcs.ldb_queues[id];
1438 
1439 	DLB2_FUNC_LIST_FOR(rsrcs->used_domains, domain, iter1) {
1440 		DLB2_DOM_LIST_FOR(domain->used_ldb_queues, queue, iter2) {
1441 			if (queue->id.virt_id == id)
1442 				return queue;
1443 		}
1444 	}
1445 
1446 	DLB2_FUNC_LIST_FOR(rsrcs->avail_ldb_queues, queue, iter1) {
1447 		if (queue->id.virt_id == id)
1448 			return queue;
1449 	}
1450 
1451 	return NULL;
1452 }
1453 
dlb2_get_domain_from_id(struct dlb2_hw * hw,u32 id,bool vdev_req,unsigned int vdev_id)1454 static struct dlb2_hw_domain *dlb2_get_domain_from_id(struct dlb2_hw *hw,
1455 						      u32 id,
1456 						      bool vdev_req,
1457 						      unsigned int vdev_id)
1458 {
1459 	struct dlb2_list_entry *iteration;
1460 	struct dlb2_function_resources *rsrcs;
1461 	struct dlb2_hw_domain *domain;
1462 	RTE_SET_USED(iteration);
1463 
1464 	if (id >= DLB2_MAX_NUM_DOMAINS)
1465 		return NULL;
1466 
1467 	if (!vdev_req)
1468 		return &hw->domains[id];
1469 
1470 	rsrcs = &hw->vdev[vdev_id];
1471 
1472 	DLB2_FUNC_LIST_FOR(rsrcs->used_domains, domain, iteration) {
1473 		if (domain->id.virt_id == id)
1474 			return domain;
1475 	}
1476 
1477 	return NULL;
1478 }
1479 
dlb2_port_slot_state_transition(struct dlb2_hw * hw,struct dlb2_ldb_port * port,struct dlb2_ldb_queue * queue,int slot,enum dlb2_qid_map_state new_state)1480 static int dlb2_port_slot_state_transition(struct dlb2_hw *hw,
1481 					   struct dlb2_ldb_port *port,
1482 					   struct dlb2_ldb_queue *queue,
1483 					   int slot,
1484 					   enum dlb2_qid_map_state new_state)
1485 {
1486 	enum dlb2_qid_map_state curr_state = port->qid_map[slot].state;
1487 	struct dlb2_hw_domain *domain;
1488 	int domain_id;
1489 
1490 	domain_id = port->domain_id.phys_id;
1491 
1492 	domain = dlb2_get_domain_from_id(hw, domain_id, false, 0);
1493 	if (domain == NULL) {
1494 		DLB2_HW_ERR(hw,
1495 			    "[%s()] Internal error: unable to find domain %d\n",
1496 			    __func__, domain_id);
1497 		return -EINVAL;
1498 	}
1499 
1500 	switch (curr_state) {
1501 	case DLB2_QUEUE_UNMAPPED:
1502 		switch (new_state) {
1503 		case DLB2_QUEUE_MAPPED:
1504 			queue->num_mappings++;
1505 			port->num_mappings++;
1506 			break;
1507 		case DLB2_QUEUE_MAP_IN_PROG:
1508 			queue->num_pending_additions++;
1509 			domain->num_pending_additions++;
1510 			break;
1511 		default:
1512 			goto error;
1513 		}
1514 		break;
1515 	case DLB2_QUEUE_MAPPED:
1516 		switch (new_state) {
1517 		case DLB2_QUEUE_UNMAPPED:
1518 			queue->num_mappings--;
1519 			port->num_mappings--;
1520 			break;
1521 		case DLB2_QUEUE_UNMAP_IN_PROG:
1522 			port->num_pending_removals++;
1523 			domain->num_pending_removals++;
1524 			break;
1525 		case DLB2_QUEUE_MAPPED:
1526 			/* Priority change, nothing to update */
1527 			break;
1528 		default:
1529 			goto error;
1530 		}
1531 		break;
1532 	case DLB2_QUEUE_MAP_IN_PROG:
1533 		switch (new_state) {
1534 		case DLB2_QUEUE_UNMAPPED:
1535 			queue->num_pending_additions--;
1536 			domain->num_pending_additions--;
1537 			break;
1538 		case DLB2_QUEUE_MAPPED:
1539 			queue->num_mappings++;
1540 			port->num_mappings++;
1541 			queue->num_pending_additions--;
1542 			domain->num_pending_additions--;
1543 			break;
1544 		default:
1545 			goto error;
1546 		}
1547 		break;
1548 	case DLB2_QUEUE_UNMAP_IN_PROG:
1549 		switch (new_state) {
1550 		case DLB2_QUEUE_UNMAPPED:
1551 			port->num_pending_removals--;
1552 			domain->num_pending_removals--;
1553 			queue->num_mappings--;
1554 			port->num_mappings--;
1555 			break;
1556 		case DLB2_QUEUE_MAPPED:
1557 			port->num_pending_removals--;
1558 			domain->num_pending_removals--;
1559 			break;
1560 		case DLB2_QUEUE_UNMAP_IN_PROG_PENDING_MAP:
1561 			/* Nothing to update */
1562 			break;
1563 		default:
1564 			goto error;
1565 		}
1566 		break;
1567 	case DLB2_QUEUE_UNMAP_IN_PROG_PENDING_MAP:
1568 		switch (new_state) {
1569 		case DLB2_QUEUE_UNMAP_IN_PROG:
1570 			/* Nothing to update */
1571 			break;
1572 		case DLB2_QUEUE_UNMAPPED:
1573 			/*
1574 			 * An UNMAP_IN_PROG_PENDING_MAP slot briefly
1575 			 * becomes UNMAPPED before it transitions to
1576 			 * MAP_IN_PROG.
1577 			 */
1578 			queue->num_mappings--;
1579 			port->num_mappings--;
1580 			port->num_pending_removals--;
1581 			domain->num_pending_removals--;
1582 			break;
1583 		default:
1584 			goto error;
1585 		}
1586 		break;
1587 	default:
1588 		goto error;
1589 	}
1590 
1591 	port->qid_map[slot].state = new_state;
1592 
1593 	DLB2_HW_DBG(hw,
1594 		    "[%s()] queue %d -> port %d state transition (%d -> %d)\n",
1595 		    __func__, queue->id.phys_id, port->id.phys_id,
1596 		    curr_state, new_state);
1597 	return 0;
1598 
1599 error:
1600 	DLB2_HW_ERR(hw,
1601 		    "[%s()] Internal error: invalid queue %d -> port %d state transition (%d -> %d)\n",
1602 		    __func__, queue->id.phys_id, port->id.phys_id,
1603 		    curr_state, new_state);
1604 	return -EFAULT;
1605 }
1606 
dlb2_port_find_slot(struct dlb2_ldb_port * port,enum dlb2_qid_map_state state,int * slot)1607 static bool dlb2_port_find_slot(struct dlb2_ldb_port *port,
1608 				enum dlb2_qid_map_state state,
1609 				int *slot)
1610 {
1611 	int i;
1612 
1613 	for (i = 0; i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; i++) {
1614 		if (port->qid_map[i].state == state)
1615 			break;
1616 	}
1617 
1618 	*slot = i;
1619 
1620 	return (i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ);
1621 }
1622 
dlb2_port_find_slot_queue(struct dlb2_ldb_port * port,enum dlb2_qid_map_state state,struct dlb2_ldb_queue * queue,int * slot)1623 static bool dlb2_port_find_slot_queue(struct dlb2_ldb_port *port,
1624 				      enum dlb2_qid_map_state state,
1625 				      struct dlb2_ldb_queue *queue,
1626 				      int *slot)
1627 {
1628 	int i;
1629 
1630 	for (i = 0; i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; i++) {
1631 		if (port->qid_map[i].state == state &&
1632 		    port->qid_map[i].qid == queue->id.phys_id)
1633 			break;
1634 	}
1635 
1636 	*slot = i;
1637 
1638 	return (i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ);
1639 }
1640 
1641 /*
1642  * dlb2_ldb_queue_{enable, disable}_mapped_cqs() don't operate exactly as
1643  * their function names imply, and should only be called by the dynamic CQ
1644  * mapping code.
1645  */
dlb2_ldb_queue_disable_mapped_cqs(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_queue * queue)1646 static void dlb2_ldb_queue_disable_mapped_cqs(struct dlb2_hw *hw,
1647 					      struct dlb2_hw_domain *domain,
1648 					      struct dlb2_ldb_queue *queue)
1649 {
1650 	struct dlb2_list_entry *iter;
1651 	struct dlb2_ldb_port *port;
1652 	int slot, i;
1653 	RTE_SET_USED(iter);
1654 
1655 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
1656 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) {
1657 			enum dlb2_qid_map_state state = DLB2_QUEUE_MAPPED;
1658 
1659 			if (!dlb2_port_find_slot_queue(port, state,
1660 						       queue, &slot))
1661 				continue;
1662 
1663 			if (port->enabled)
1664 				dlb2_ldb_port_cq_disable(hw, port);
1665 		}
1666 	}
1667 }
1668 
dlb2_ldb_queue_enable_mapped_cqs(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_queue * queue)1669 static void dlb2_ldb_queue_enable_mapped_cqs(struct dlb2_hw *hw,
1670 					     struct dlb2_hw_domain *domain,
1671 					     struct dlb2_ldb_queue *queue)
1672 {
1673 	struct dlb2_list_entry *iter;
1674 	struct dlb2_ldb_port *port;
1675 	int slot, i;
1676 	RTE_SET_USED(iter);
1677 
1678 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
1679 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) {
1680 			enum dlb2_qid_map_state state = DLB2_QUEUE_MAPPED;
1681 
1682 			if (!dlb2_port_find_slot_queue(port, state,
1683 						       queue, &slot))
1684 				continue;
1685 
1686 			if (port->enabled)
1687 				dlb2_ldb_port_cq_enable(hw, port);
1688 		}
1689 	}
1690 }
1691 
dlb2_ldb_port_clear_queue_if_status(struct dlb2_hw * hw,struct dlb2_ldb_port * port,int slot)1692 static void dlb2_ldb_port_clear_queue_if_status(struct dlb2_hw *hw,
1693 						struct dlb2_ldb_port *port,
1694 						int slot)
1695 {
1696 	u32 ctrl = 0;
1697 
1698 	DLB2_BITS_SET(ctrl, port->id.phys_id, DLB2_LSP_LDB_SCHED_CTRL_CQ);
1699 	DLB2_BITS_SET(ctrl, slot, DLB2_LSP_LDB_SCHED_CTRL_QIDIX);
1700 	DLB2_BIT_SET(ctrl, DLB2_LSP_LDB_SCHED_CTRL_INFLIGHT_OK_V);
1701 
1702 	DLB2_CSR_WR(hw, DLB2_LSP_LDB_SCHED_CTRL(hw->ver), ctrl);
1703 
1704 	dlb2_flush_csr(hw);
1705 }
1706 
dlb2_ldb_port_set_queue_if_status(struct dlb2_hw * hw,struct dlb2_ldb_port * port,int slot)1707 static void dlb2_ldb_port_set_queue_if_status(struct dlb2_hw *hw,
1708 					      struct dlb2_ldb_port *port,
1709 					      int slot)
1710 {
1711 	u32 ctrl = 0;
1712 
1713 	DLB2_BITS_SET(ctrl, port->id.phys_id, DLB2_LSP_LDB_SCHED_CTRL_CQ);
1714 	DLB2_BITS_SET(ctrl, slot, DLB2_LSP_LDB_SCHED_CTRL_QIDIX);
1715 	DLB2_BIT_SET(ctrl, DLB2_LSP_LDB_SCHED_CTRL_VALUE);
1716 	DLB2_BIT_SET(ctrl, DLB2_LSP_LDB_SCHED_CTRL_INFLIGHT_OK_V);
1717 
1718 	DLB2_CSR_WR(hw, DLB2_LSP_LDB_SCHED_CTRL(hw->ver), ctrl);
1719 
1720 	dlb2_flush_csr(hw);
1721 }
1722 
dlb2_ldb_port_map_qid_static(struct dlb2_hw * hw,struct dlb2_ldb_port * p,struct dlb2_ldb_queue * q,u8 priority)1723 static int dlb2_ldb_port_map_qid_static(struct dlb2_hw *hw,
1724 					struct dlb2_ldb_port *p,
1725 					struct dlb2_ldb_queue *q,
1726 					u8 priority)
1727 {
1728 	enum dlb2_qid_map_state state;
1729 	u32 lsp_qid2cq2;
1730 	u32 lsp_qid2cq;
1731 	u32 atm_qid2cq;
1732 	u32 cq2priov;
1733 	u32 cq2qid;
1734 	int i;
1735 
1736 	/* Look for a pending or already mapped slot, else an unused slot */
1737 	if (!dlb2_port_find_slot_queue(p, DLB2_QUEUE_MAP_IN_PROG, q, &i) &&
1738 	    !dlb2_port_find_slot_queue(p, DLB2_QUEUE_MAPPED, q, &i) &&
1739 	    !dlb2_port_find_slot(p, DLB2_QUEUE_UNMAPPED, &i)) {
1740 		DLB2_HW_ERR(hw,
1741 			    "[%s():%d] Internal error: CQ has no available QID mapping slots\n",
1742 			    __func__, __LINE__);
1743 		return -EFAULT;
1744 	}
1745 
1746 	/* Read-modify-write the priority and valid bit register */
1747 	cq2priov = DLB2_CSR_RD(hw, DLB2_LSP_CQ2PRIOV(hw->ver, p->id.phys_id));
1748 
1749 	cq2priov |= (1 << (i + DLB2_LSP_CQ2PRIOV_V_LOC)) & DLB2_LSP_CQ2PRIOV_V;
1750 	cq2priov |= ((priority & 0x7) << (i + DLB2_LSP_CQ2PRIOV_PRIO_LOC) * 3)
1751 		    & DLB2_LSP_CQ2PRIOV_PRIO;
1752 
1753 	DLB2_CSR_WR(hw, DLB2_LSP_CQ2PRIOV(hw->ver, p->id.phys_id), cq2priov);
1754 
1755 	/* Read-modify-write the QID map register */
1756 	if (i < 4)
1757 		cq2qid = DLB2_CSR_RD(hw, DLB2_LSP_CQ2QID0(hw->ver,
1758 							  p->id.phys_id));
1759 	else
1760 		cq2qid = DLB2_CSR_RD(hw, DLB2_LSP_CQ2QID1(hw->ver,
1761 							  p->id.phys_id));
1762 
1763 	if (i == 0 || i == 4)
1764 		DLB2_BITS_SET(cq2qid, q->id.phys_id, DLB2_LSP_CQ2QID0_QID_P0);
1765 	if (i == 1 || i == 5)
1766 		DLB2_BITS_SET(cq2qid, q->id.phys_id, DLB2_LSP_CQ2QID0_QID_P1);
1767 	if (i == 2 || i == 6)
1768 		DLB2_BITS_SET(cq2qid, q->id.phys_id, DLB2_LSP_CQ2QID0_QID_P2);
1769 	if (i == 3 || i == 7)
1770 		DLB2_BITS_SET(cq2qid, q->id.phys_id, DLB2_LSP_CQ2QID0_QID_P3);
1771 
1772 	if (i < 4)
1773 		DLB2_CSR_WR(hw,
1774 			    DLB2_LSP_CQ2QID0(hw->ver, p->id.phys_id), cq2qid);
1775 	else
1776 		DLB2_CSR_WR(hw,
1777 			    DLB2_LSP_CQ2QID1(hw->ver, p->id.phys_id), cq2qid);
1778 
1779 	atm_qid2cq = DLB2_CSR_RD(hw,
1780 				 DLB2_ATM_QID2CQIDIX(q->id.phys_id,
1781 						p->id.phys_id / 4));
1782 
1783 	lsp_qid2cq = DLB2_CSR_RD(hw,
1784 				 DLB2_LSP_QID2CQIDIX(hw->ver, q->id.phys_id,
1785 						p->id.phys_id / 4));
1786 
1787 	lsp_qid2cq2 = DLB2_CSR_RD(hw,
1788 				  DLB2_LSP_QID2CQIDIX2(hw->ver, q->id.phys_id,
1789 						  p->id.phys_id / 4));
1790 
1791 	switch (p->id.phys_id % 4) {
1792 	case 0:
1793 		DLB2_BIT_SET(atm_qid2cq,
1794 			     1 << (i + DLB2_ATM_QID2CQIDIX_00_CQ_P0_LOC));
1795 		DLB2_BIT_SET(lsp_qid2cq,
1796 			     1 << (i + DLB2_LSP_QID2CQIDIX_00_CQ_P0_LOC));
1797 		DLB2_BIT_SET(lsp_qid2cq2,
1798 			     1 << (i + DLB2_LSP_QID2CQIDIX2_00_CQ_P0_LOC));
1799 		break;
1800 
1801 	case 1:
1802 		DLB2_BIT_SET(atm_qid2cq,
1803 			     1 << (i + DLB2_ATM_QID2CQIDIX_00_CQ_P1_LOC));
1804 		DLB2_BIT_SET(lsp_qid2cq,
1805 			     1 << (i + DLB2_LSP_QID2CQIDIX_00_CQ_P1_LOC));
1806 		DLB2_BIT_SET(lsp_qid2cq2,
1807 			     1 << (i + DLB2_LSP_QID2CQIDIX2_00_CQ_P1_LOC));
1808 		break;
1809 
1810 	case 2:
1811 		DLB2_BIT_SET(atm_qid2cq,
1812 			     1 << (i + DLB2_ATM_QID2CQIDIX_00_CQ_P2_LOC));
1813 		DLB2_BIT_SET(lsp_qid2cq,
1814 			     1 << (i + DLB2_LSP_QID2CQIDIX_00_CQ_P2_LOC));
1815 		DLB2_BIT_SET(lsp_qid2cq2,
1816 			     1 << (i + DLB2_LSP_QID2CQIDIX2_00_CQ_P2_LOC));
1817 		break;
1818 
1819 	case 3:
1820 		DLB2_BIT_SET(atm_qid2cq,
1821 			     1 << (i + DLB2_ATM_QID2CQIDIX_00_CQ_P3_LOC));
1822 		DLB2_BIT_SET(lsp_qid2cq,
1823 			     1 << (i + DLB2_LSP_QID2CQIDIX_00_CQ_P3_LOC));
1824 		DLB2_BIT_SET(lsp_qid2cq2,
1825 			     1 << (i + DLB2_LSP_QID2CQIDIX2_00_CQ_P3_LOC));
1826 		break;
1827 	}
1828 
1829 	DLB2_CSR_WR(hw,
1830 		    DLB2_ATM_QID2CQIDIX(q->id.phys_id, p->id.phys_id / 4),
1831 		    atm_qid2cq);
1832 
1833 	DLB2_CSR_WR(hw,
1834 		    DLB2_LSP_QID2CQIDIX(hw->ver,
1835 					q->id.phys_id, p->id.phys_id / 4),
1836 		    lsp_qid2cq);
1837 
1838 	DLB2_CSR_WR(hw,
1839 		    DLB2_LSP_QID2CQIDIX2(hw->ver,
1840 					 q->id.phys_id, p->id.phys_id / 4),
1841 		    lsp_qid2cq2);
1842 
1843 	dlb2_flush_csr(hw);
1844 
1845 	p->qid_map[i].qid = q->id.phys_id;
1846 	p->qid_map[i].priority = priority;
1847 
1848 	state = DLB2_QUEUE_MAPPED;
1849 
1850 	return dlb2_port_slot_state_transition(hw, p, q, i, state);
1851 }
1852 
dlb2_ldb_port_set_has_work_bits(struct dlb2_hw * hw,struct dlb2_ldb_port * port,struct dlb2_ldb_queue * queue,int slot)1853 static int dlb2_ldb_port_set_has_work_bits(struct dlb2_hw *hw,
1854 					   struct dlb2_ldb_port *port,
1855 					   struct dlb2_ldb_queue *queue,
1856 					   int slot)
1857 {
1858 	u32 ctrl = 0;
1859 	u32 active;
1860 	u32 enq;
1861 
1862 	/* Set the atomic scheduling haswork bit */
1863 	active = DLB2_CSR_RD(hw, DLB2_LSP_QID_AQED_ACTIVE_CNT(hw->ver,
1864 							 queue->id.phys_id));
1865 
1866 	DLB2_BITS_SET(ctrl, port->id.phys_id, DLB2_LSP_LDB_SCHED_CTRL_CQ);
1867 	DLB2_BITS_SET(ctrl, slot, DLB2_LSP_LDB_SCHED_CTRL_QIDIX);
1868 	DLB2_BIT_SET(ctrl, DLB2_LSP_LDB_SCHED_CTRL_VALUE);
1869 	DLB2_BITS_SET(ctrl,
1870 		      DLB2_BITS_GET(active,
1871 				    DLB2_LSP_QID_AQED_ACTIVE_CNT_COUNT) > 0,
1872 				    DLB2_LSP_LDB_SCHED_CTRL_RLIST_HASWORK_V);
1873 
1874 	/* Set the non-atomic scheduling haswork bit */
1875 	DLB2_CSR_WR(hw, DLB2_LSP_LDB_SCHED_CTRL(hw->ver), ctrl);
1876 
1877 	enq = DLB2_CSR_RD(hw,
1878 			  DLB2_LSP_QID_LDB_ENQUEUE_CNT(hw->ver,
1879 						       queue->id.phys_id));
1880 
1881 	memset(&ctrl, 0, sizeof(ctrl));
1882 
1883 	DLB2_BITS_SET(ctrl, port->id.phys_id, DLB2_LSP_LDB_SCHED_CTRL_CQ);
1884 	DLB2_BITS_SET(ctrl, slot, DLB2_LSP_LDB_SCHED_CTRL_QIDIX);
1885 	DLB2_BIT_SET(ctrl, DLB2_LSP_LDB_SCHED_CTRL_VALUE);
1886 	DLB2_BITS_SET(ctrl,
1887 		      DLB2_BITS_GET(enq,
1888 				    DLB2_LSP_QID_LDB_ENQUEUE_CNT_COUNT) > 0,
1889 		      DLB2_LSP_LDB_SCHED_CTRL_NALB_HASWORK_V);
1890 
1891 	DLB2_CSR_WR(hw, DLB2_LSP_LDB_SCHED_CTRL(hw->ver), ctrl);
1892 
1893 	dlb2_flush_csr(hw);
1894 
1895 	return 0;
1896 }
1897 
dlb2_ldb_port_clear_has_work_bits(struct dlb2_hw * hw,struct dlb2_ldb_port * port,u8 slot)1898 static void dlb2_ldb_port_clear_has_work_bits(struct dlb2_hw *hw,
1899 					      struct dlb2_ldb_port *port,
1900 					      u8 slot)
1901 {
1902 	u32 ctrl = 0;
1903 
1904 	DLB2_BITS_SET(ctrl, port->id.phys_id, DLB2_LSP_LDB_SCHED_CTRL_CQ);
1905 	DLB2_BITS_SET(ctrl, slot, DLB2_LSP_LDB_SCHED_CTRL_QIDIX);
1906 	DLB2_BIT_SET(ctrl, DLB2_LSP_LDB_SCHED_CTRL_RLIST_HASWORK_V);
1907 
1908 	DLB2_CSR_WR(hw, DLB2_LSP_LDB_SCHED_CTRL(hw->ver), ctrl);
1909 
1910 	memset(&ctrl, 0, sizeof(ctrl));
1911 
1912 	DLB2_BITS_SET(ctrl, port->id.phys_id, DLB2_LSP_LDB_SCHED_CTRL_CQ);
1913 	DLB2_BITS_SET(ctrl, slot, DLB2_LSP_LDB_SCHED_CTRL_QIDIX);
1914 	DLB2_BIT_SET(ctrl, DLB2_LSP_LDB_SCHED_CTRL_NALB_HASWORK_V);
1915 
1916 	DLB2_CSR_WR(hw, DLB2_LSP_LDB_SCHED_CTRL(hw->ver), ctrl);
1917 
1918 	dlb2_flush_csr(hw);
1919 }
1920 
1921 
dlb2_ldb_queue_set_inflight_limit(struct dlb2_hw * hw,struct dlb2_ldb_queue * queue)1922 static void dlb2_ldb_queue_set_inflight_limit(struct dlb2_hw *hw,
1923 					      struct dlb2_ldb_queue *queue)
1924 {
1925 	u32 infl_lim = 0;
1926 
1927 	DLB2_BITS_SET(infl_lim, queue->num_qid_inflights,
1928 		 DLB2_LSP_QID_LDB_INFL_LIM_LIMIT);
1929 
1930 	DLB2_CSR_WR(hw, DLB2_LSP_QID_LDB_INFL_LIM(hw->ver, queue->id.phys_id),
1931 		    infl_lim);
1932 }
1933 
dlb2_ldb_queue_clear_inflight_limit(struct dlb2_hw * hw,struct dlb2_ldb_queue * queue)1934 static void dlb2_ldb_queue_clear_inflight_limit(struct dlb2_hw *hw,
1935 						struct dlb2_ldb_queue *queue)
1936 {
1937 	DLB2_CSR_WR(hw,
1938 		    DLB2_LSP_QID_LDB_INFL_LIM(hw->ver, queue->id.phys_id),
1939 		    DLB2_LSP_QID_LDB_INFL_LIM_RST);
1940 }
1941 
dlb2_ldb_port_finish_map_qid_dynamic(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_port * port,struct dlb2_ldb_queue * queue)1942 static int dlb2_ldb_port_finish_map_qid_dynamic(struct dlb2_hw *hw,
1943 						struct dlb2_hw_domain *domain,
1944 						struct dlb2_ldb_port *port,
1945 						struct dlb2_ldb_queue *queue)
1946 {
1947 	struct dlb2_list_entry *iter;
1948 	enum dlb2_qid_map_state state;
1949 	int slot, ret, i;
1950 	u32 infl_cnt;
1951 	u8 prio;
1952 	RTE_SET_USED(iter);
1953 
1954 	infl_cnt = DLB2_CSR_RD(hw,
1955 			       DLB2_LSP_QID_LDB_INFL_CNT(hw->ver,
1956 						    queue->id.phys_id));
1957 
1958 	if (DLB2_BITS_GET(infl_cnt, DLB2_LSP_QID_LDB_INFL_CNT_COUNT)) {
1959 		DLB2_HW_ERR(hw,
1960 			    "[%s()] Internal error: non-zero QID inflight count\n",
1961 			    __func__);
1962 		return -EINVAL;
1963 	}
1964 
1965 	/*
1966 	 * Static map the port and set its corresponding has_work bits.
1967 	 */
1968 	state = DLB2_QUEUE_MAP_IN_PROG;
1969 	if (!dlb2_port_find_slot_queue(port, state, queue, &slot))
1970 		return -EINVAL;
1971 
1972 	prio = port->qid_map[slot].priority;
1973 
1974 	/*
1975 	 * Update the CQ2QID, CQ2PRIOV, and QID2CQIDX registers, and
1976 	 * the port's qid_map state.
1977 	 */
1978 	ret = dlb2_ldb_port_map_qid_static(hw, port, queue, prio);
1979 	if (ret)
1980 		return ret;
1981 
1982 	ret = dlb2_ldb_port_set_has_work_bits(hw, port, queue, slot);
1983 	if (ret)
1984 		return ret;
1985 
1986 	/*
1987 	 * Ensure IF_status(cq,qid) is 0 before enabling the port to
1988 	 * prevent spurious schedules to cause the queue's inflight
1989 	 * count to increase.
1990 	 */
1991 	dlb2_ldb_port_clear_queue_if_status(hw, port, slot);
1992 
1993 	/* Reset the queue's inflight status */
1994 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
1995 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) {
1996 			state = DLB2_QUEUE_MAPPED;
1997 			if (!dlb2_port_find_slot_queue(port, state,
1998 						       queue, &slot))
1999 				continue;
2000 
2001 			dlb2_ldb_port_set_queue_if_status(hw, port, slot);
2002 		}
2003 	}
2004 
2005 	dlb2_ldb_queue_set_inflight_limit(hw, queue);
2006 
2007 	/* Re-enable CQs mapped to this queue */
2008 	dlb2_ldb_queue_enable_mapped_cqs(hw, domain, queue);
2009 
2010 	/* If this queue has other mappings pending, clear its inflight limit */
2011 	if (queue->num_pending_additions > 0)
2012 		dlb2_ldb_queue_clear_inflight_limit(hw, queue);
2013 
2014 	return 0;
2015 }
2016 
2017 /**
2018  * dlb2_ldb_port_map_qid_dynamic() - perform a "dynamic" QID->CQ mapping
2019  * @hw: dlb2_hw handle for a particular device.
2020  * @port: load-balanced port
2021  * @queue: load-balanced queue
2022  * @priority: queue servicing priority
2023  *
2024  * Returns 0 if the queue was mapped, 1 if the mapping is scheduled to occur
2025  * at a later point, and <0 if an error occurred.
2026  */
dlb2_ldb_port_map_qid_dynamic(struct dlb2_hw * hw,struct dlb2_ldb_port * port,struct dlb2_ldb_queue * queue,u8 priority)2027 static int dlb2_ldb_port_map_qid_dynamic(struct dlb2_hw *hw,
2028 					 struct dlb2_ldb_port *port,
2029 					 struct dlb2_ldb_queue *queue,
2030 					 u8 priority)
2031 {
2032 	enum dlb2_qid_map_state state;
2033 	struct dlb2_hw_domain *domain;
2034 	int domain_id, slot, ret;
2035 	u32 infl_cnt;
2036 
2037 	domain_id = port->domain_id.phys_id;
2038 
2039 	domain = dlb2_get_domain_from_id(hw, domain_id, false, 0);
2040 	if (domain == NULL) {
2041 		DLB2_HW_ERR(hw,
2042 			    "[%s()] Internal error: unable to find domain %d\n",
2043 			    __func__, port->domain_id.phys_id);
2044 		return -EINVAL;
2045 	}
2046 
2047 	/*
2048 	 * Set the QID inflight limit to 0 to prevent further scheduling of the
2049 	 * queue.
2050 	 */
2051 	DLB2_CSR_WR(hw, DLB2_LSP_QID_LDB_INFL_LIM(hw->ver,
2052 						  queue->id.phys_id), 0);
2053 
2054 	if (!dlb2_port_find_slot(port, DLB2_QUEUE_UNMAPPED, &slot)) {
2055 		DLB2_HW_ERR(hw,
2056 			    "Internal error: No available unmapped slots\n");
2057 		return -EFAULT;
2058 	}
2059 
2060 	port->qid_map[slot].qid = queue->id.phys_id;
2061 	port->qid_map[slot].priority = priority;
2062 
2063 	state = DLB2_QUEUE_MAP_IN_PROG;
2064 	ret = dlb2_port_slot_state_transition(hw, port, queue, slot, state);
2065 	if (ret)
2066 		return ret;
2067 
2068 	infl_cnt = DLB2_CSR_RD(hw,
2069 			       DLB2_LSP_QID_LDB_INFL_CNT(hw->ver,
2070 						    queue->id.phys_id));
2071 
2072 	if (DLB2_BITS_GET(infl_cnt, DLB2_LSP_QID_LDB_INFL_CNT_COUNT)) {
2073 		/*
2074 		 * The queue is owed completions so it's not safe to map it
2075 		 * yet. Schedule a kernel thread to complete the mapping later,
2076 		 * once software has completed all the queue's inflight events.
2077 		 */
2078 		if (!os_worker_active(hw))
2079 			os_schedule_work(hw);
2080 
2081 		return 1;
2082 	}
2083 
2084 	/*
2085 	 * Disable the affected CQ, and the CQs already mapped to the QID,
2086 	 * before reading the QID's inflight count a second time. There is an
2087 	 * unlikely race in which the QID may schedule one more QE after we
2088 	 * read an inflight count of 0, and disabling the CQs guarantees that
2089 	 * the race will not occur after a re-read of the inflight count
2090 	 * register.
2091 	 */
2092 	if (port->enabled)
2093 		dlb2_ldb_port_cq_disable(hw, port);
2094 
2095 	dlb2_ldb_queue_disable_mapped_cqs(hw, domain, queue);
2096 
2097 	infl_cnt = DLB2_CSR_RD(hw,
2098 			       DLB2_LSP_QID_LDB_INFL_CNT(hw->ver,
2099 						    queue->id.phys_id));
2100 
2101 	if (DLB2_BITS_GET(infl_cnt, DLB2_LSP_QID_LDB_INFL_CNT_COUNT)) {
2102 		if (port->enabled)
2103 			dlb2_ldb_port_cq_enable(hw, port);
2104 
2105 		dlb2_ldb_queue_enable_mapped_cqs(hw, domain, queue);
2106 
2107 		/*
2108 		 * The queue is owed completions so it's not safe to map it
2109 		 * yet. Schedule a kernel thread to complete the mapping later,
2110 		 * once software has completed all the queue's inflight events.
2111 		 */
2112 		if (!os_worker_active(hw))
2113 			os_schedule_work(hw);
2114 
2115 		return 1;
2116 	}
2117 
2118 	return dlb2_ldb_port_finish_map_qid_dynamic(hw, domain, port, queue);
2119 }
2120 
dlb2_domain_finish_map_port(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_port * port)2121 static void dlb2_domain_finish_map_port(struct dlb2_hw *hw,
2122 					struct dlb2_hw_domain *domain,
2123 					struct dlb2_ldb_port *port)
2124 {
2125 	int i;
2126 
2127 	for (i = 0; i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; i++) {
2128 		u32 infl_cnt;
2129 		struct dlb2_ldb_queue *queue;
2130 		int qid;
2131 
2132 		if (port->qid_map[i].state != DLB2_QUEUE_MAP_IN_PROG)
2133 			continue;
2134 
2135 		qid = port->qid_map[i].qid;
2136 
2137 		queue = dlb2_get_ldb_queue_from_id(hw, qid, false, 0);
2138 
2139 		if (queue == NULL) {
2140 			DLB2_HW_ERR(hw,
2141 				    "[%s()] Internal error: unable to find queue %d\n",
2142 				    __func__, qid);
2143 			continue;
2144 		}
2145 
2146 		infl_cnt = DLB2_CSR_RD(hw,
2147 				       DLB2_LSP_QID_LDB_INFL_CNT(hw->ver, qid));
2148 
2149 		if (DLB2_BITS_GET(infl_cnt, DLB2_LSP_QID_LDB_INFL_CNT_COUNT))
2150 			continue;
2151 
2152 		/*
2153 		 * Disable the affected CQ, and the CQs already mapped to the
2154 		 * QID, before reading the QID's inflight count a second time.
2155 		 * There is an unlikely race in which the QID may schedule one
2156 		 * more QE after we read an inflight count of 0, and disabling
2157 		 * the CQs guarantees that the race will not occur after a
2158 		 * re-read of the inflight count register.
2159 		 */
2160 		if (port->enabled)
2161 			dlb2_ldb_port_cq_disable(hw, port);
2162 
2163 		dlb2_ldb_queue_disable_mapped_cqs(hw, domain, queue);
2164 
2165 		infl_cnt = DLB2_CSR_RD(hw,
2166 				       DLB2_LSP_QID_LDB_INFL_CNT(hw->ver, qid));
2167 
2168 		if (DLB2_BITS_GET(infl_cnt, DLB2_LSP_QID_LDB_INFL_CNT_COUNT)) {
2169 			if (port->enabled)
2170 				dlb2_ldb_port_cq_enable(hw, port);
2171 
2172 			dlb2_ldb_queue_enable_mapped_cqs(hw, domain, queue);
2173 
2174 			continue;
2175 		}
2176 
2177 		dlb2_ldb_port_finish_map_qid_dynamic(hw, domain, port, queue);
2178 	}
2179 }
2180 
2181 static unsigned int
dlb2_domain_finish_map_qid_procedures(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2182 dlb2_domain_finish_map_qid_procedures(struct dlb2_hw *hw,
2183 				      struct dlb2_hw_domain *domain)
2184 {
2185 	struct dlb2_list_entry *iter;
2186 	struct dlb2_ldb_port *port;
2187 	int i;
2188 	RTE_SET_USED(iter);
2189 
2190 	if (!domain->configured || domain->num_pending_additions == 0)
2191 		return 0;
2192 
2193 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
2194 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter)
2195 			dlb2_domain_finish_map_port(hw, domain, port);
2196 	}
2197 
2198 	return domain->num_pending_additions;
2199 }
2200 
dlb2_ldb_port_unmap_qid(struct dlb2_hw * hw,struct dlb2_ldb_port * port,struct dlb2_ldb_queue * queue)2201 static int dlb2_ldb_port_unmap_qid(struct dlb2_hw *hw,
2202 				   struct dlb2_ldb_port *port,
2203 				   struct dlb2_ldb_queue *queue)
2204 {
2205 	enum dlb2_qid_map_state mapped, in_progress, pending_map, unmapped;
2206 	u32 lsp_qid2cq2;
2207 	u32 lsp_qid2cq;
2208 	u32 atm_qid2cq;
2209 	u32 cq2priov;
2210 	u32 queue_id;
2211 	u32 port_id;
2212 	int i;
2213 
2214 	/* Find the queue's slot */
2215 	mapped = DLB2_QUEUE_MAPPED;
2216 	in_progress = DLB2_QUEUE_UNMAP_IN_PROG;
2217 	pending_map = DLB2_QUEUE_UNMAP_IN_PROG_PENDING_MAP;
2218 
2219 	if (!dlb2_port_find_slot_queue(port, mapped, queue, &i) &&
2220 	    !dlb2_port_find_slot_queue(port, in_progress, queue, &i) &&
2221 	    !dlb2_port_find_slot_queue(port, pending_map, queue, &i)) {
2222 		DLB2_HW_ERR(hw,
2223 			    "[%s():%d] Internal error: QID %d isn't mapped\n",
2224 			    __func__, __LINE__, queue->id.phys_id);
2225 		return -EFAULT;
2226 	}
2227 
2228 	port_id = port->id.phys_id;
2229 	queue_id = queue->id.phys_id;
2230 
2231 	/* Read-modify-write the priority and valid bit register */
2232 	cq2priov = DLB2_CSR_RD(hw, DLB2_LSP_CQ2PRIOV(hw->ver, port_id));
2233 
2234 	cq2priov &= ~(1 << (i + DLB2_LSP_CQ2PRIOV_V_LOC));
2235 
2236 	DLB2_CSR_WR(hw, DLB2_LSP_CQ2PRIOV(hw->ver, port_id), cq2priov);
2237 
2238 	atm_qid2cq = DLB2_CSR_RD(hw, DLB2_ATM_QID2CQIDIX(queue_id,
2239 							 port_id / 4));
2240 
2241 	lsp_qid2cq = DLB2_CSR_RD(hw,
2242 				 DLB2_LSP_QID2CQIDIX(hw->ver,
2243 						queue_id, port_id / 4));
2244 
2245 	lsp_qid2cq2 = DLB2_CSR_RD(hw,
2246 				  DLB2_LSP_QID2CQIDIX2(hw->ver,
2247 						  queue_id, port_id / 4));
2248 
2249 	switch (port_id % 4) {
2250 	case 0:
2251 		atm_qid2cq &= ~(1 << (i + DLB2_ATM_QID2CQIDIX_00_CQ_P0_LOC));
2252 		lsp_qid2cq &= ~(1 << (i + DLB2_LSP_QID2CQIDIX_00_CQ_P0_LOC));
2253 		lsp_qid2cq2 &= ~(1 << (i + DLB2_LSP_QID2CQIDIX2_00_CQ_P0_LOC));
2254 		break;
2255 
2256 	case 1:
2257 		atm_qid2cq &= ~(1 << (i + DLB2_ATM_QID2CQIDIX_00_CQ_P1_LOC));
2258 		lsp_qid2cq &= ~(1 << (i + DLB2_LSP_QID2CQIDIX_00_CQ_P1_LOC));
2259 		lsp_qid2cq2 &= ~(1 << (i + DLB2_LSP_QID2CQIDIX2_00_CQ_P1_LOC));
2260 		break;
2261 
2262 	case 2:
2263 		atm_qid2cq &= ~(1 << (i + DLB2_ATM_QID2CQIDIX_00_CQ_P2_LOC));
2264 		lsp_qid2cq &= ~(1 << (i + DLB2_LSP_QID2CQIDIX_00_CQ_P2_LOC));
2265 		lsp_qid2cq2 &= ~(1 << (i + DLB2_LSP_QID2CQIDIX2_00_CQ_P2_LOC));
2266 		break;
2267 
2268 	case 3:
2269 		atm_qid2cq &= ~(1 << (i + DLB2_ATM_QID2CQIDIX_00_CQ_P3_LOC));
2270 		lsp_qid2cq &= ~(1 << (i + DLB2_LSP_QID2CQIDIX_00_CQ_P3_LOC));
2271 		lsp_qid2cq2 &= ~(1 << (i + DLB2_LSP_QID2CQIDIX2_00_CQ_P3_LOC));
2272 		break;
2273 	}
2274 
2275 	DLB2_CSR_WR(hw, DLB2_ATM_QID2CQIDIX(queue_id, port_id / 4), atm_qid2cq);
2276 
2277 	DLB2_CSR_WR(hw, DLB2_LSP_QID2CQIDIX(hw->ver, queue_id, port_id / 4),
2278 		    lsp_qid2cq);
2279 
2280 	DLB2_CSR_WR(hw, DLB2_LSP_QID2CQIDIX2(hw->ver, queue_id, port_id / 4),
2281 		    lsp_qid2cq2);
2282 
2283 	dlb2_flush_csr(hw);
2284 
2285 	unmapped = DLB2_QUEUE_UNMAPPED;
2286 
2287 	return dlb2_port_slot_state_transition(hw, port, queue, i, unmapped);
2288 }
2289 
dlb2_ldb_port_map_qid(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_port * port,struct dlb2_ldb_queue * queue,u8 prio)2290 static int dlb2_ldb_port_map_qid(struct dlb2_hw *hw,
2291 				 struct dlb2_hw_domain *domain,
2292 				 struct dlb2_ldb_port *port,
2293 				 struct dlb2_ldb_queue *queue,
2294 				 u8 prio)
2295 {
2296 	if (domain->started)
2297 		return dlb2_ldb_port_map_qid_dynamic(hw, port, queue, prio);
2298 	else
2299 		return dlb2_ldb_port_map_qid_static(hw, port, queue, prio);
2300 }
2301 
2302 static void
dlb2_domain_finish_unmap_port_slot(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_port * port,int slot)2303 dlb2_domain_finish_unmap_port_slot(struct dlb2_hw *hw,
2304 				   struct dlb2_hw_domain *domain,
2305 				   struct dlb2_ldb_port *port,
2306 				   int slot)
2307 {
2308 	enum dlb2_qid_map_state state;
2309 	struct dlb2_ldb_queue *queue;
2310 
2311 	queue = &hw->rsrcs.ldb_queues[port->qid_map[slot].qid];
2312 
2313 	state = port->qid_map[slot].state;
2314 
2315 	/* Update the QID2CQIDX and CQ2QID vectors */
2316 	dlb2_ldb_port_unmap_qid(hw, port, queue);
2317 
2318 	/*
2319 	 * Ensure the QID will not be serviced by this {CQ, slot} by clearing
2320 	 * the has_work bits
2321 	 */
2322 	dlb2_ldb_port_clear_has_work_bits(hw, port, slot);
2323 
2324 	/* Reset the {CQ, slot} to its default state */
2325 	dlb2_ldb_port_set_queue_if_status(hw, port, slot);
2326 
2327 	/* Re-enable the CQ if it was not manually disabled by the user */
2328 	if (port->enabled)
2329 		dlb2_ldb_port_cq_enable(hw, port);
2330 
2331 	/*
2332 	 * If there is a mapping that is pending this slot's removal, perform
2333 	 * the mapping now.
2334 	 */
2335 	if (state == DLB2_QUEUE_UNMAP_IN_PROG_PENDING_MAP) {
2336 		struct dlb2_ldb_port_qid_map *map;
2337 		struct dlb2_ldb_queue *map_queue;
2338 		u8 prio;
2339 
2340 		map = &port->qid_map[slot];
2341 
2342 		map->qid = map->pending_qid;
2343 		map->priority = map->pending_priority;
2344 
2345 		map_queue = &hw->rsrcs.ldb_queues[map->qid];
2346 		prio = map->priority;
2347 
2348 		dlb2_ldb_port_map_qid(hw, domain, port, map_queue, prio);
2349 	}
2350 }
2351 
2352 
dlb2_domain_finish_unmap_port(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_port * port)2353 static bool dlb2_domain_finish_unmap_port(struct dlb2_hw *hw,
2354 					  struct dlb2_hw_domain *domain,
2355 					  struct dlb2_ldb_port *port)
2356 {
2357 	u32 infl_cnt;
2358 	int i;
2359 	const int max_iters = 1000;
2360 	const int iter_poll_us = 100;
2361 
2362 	if (port->num_pending_removals == 0)
2363 		return false;
2364 
2365 	/*
2366 	 * The unmap requires all the CQ's outstanding inflights to be
2367 	 * completed. Poll up to 100ms.
2368 	 */
2369 	for (i = 0; i < max_iters; i++) {
2370 		infl_cnt = DLB2_CSR_RD(hw, DLB2_LSP_CQ_LDB_INFL_CNT(hw->ver,
2371 						       port->id.phys_id));
2372 
2373 		if (DLB2_BITS_GET(infl_cnt,
2374 				  DLB2_LSP_CQ_LDB_INFL_CNT_COUNT) == 0)
2375 			break;
2376 		rte_delay_us_sleep(iter_poll_us);
2377 	}
2378 
2379 	if (DLB2_BITS_GET(infl_cnt, DLB2_LSP_CQ_LDB_INFL_CNT_COUNT) > 0)
2380 		return false;
2381 
2382 	for (i = 0; i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; i++) {
2383 		struct dlb2_ldb_port_qid_map *map;
2384 
2385 		map = &port->qid_map[i];
2386 
2387 		if (map->state != DLB2_QUEUE_UNMAP_IN_PROG &&
2388 		    map->state != DLB2_QUEUE_UNMAP_IN_PROG_PENDING_MAP)
2389 			continue;
2390 
2391 		dlb2_domain_finish_unmap_port_slot(hw, domain, port, i);
2392 	}
2393 
2394 	return true;
2395 }
2396 
2397 static unsigned int
dlb2_domain_finish_unmap_qid_procedures(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2398 dlb2_domain_finish_unmap_qid_procedures(struct dlb2_hw *hw,
2399 					struct dlb2_hw_domain *domain)
2400 {
2401 	struct dlb2_list_entry *iter;
2402 	struct dlb2_ldb_port *port;
2403 	int i;
2404 	RTE_SET_USED(iter);
2405 
2406 	if (!domain->configured || domain->num_pending_removals == 0)
2407 		return 0;
2408 
2409 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
2410 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter)
2411 			dlb2_domain_finish_unmap_port(hw, domain, port);
2412 	}
2413 
2414 	return domain->num_pending_removals;
2415 }
2416 
dlb2_domain_disable_ldb_cqs(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2417 static void dlb2_domain_disable_ldb_cqs(struct dlb2_hw *hw,
2418 					struct dlb2_hw_domain *domain)
2419 {
2420 	struct dlb2_list_entry *iter;
2421 	struct dlb2_ldb_port *port;
2422 	int i;
2423 	RTE_SET_USED(iter);
2424 
2425 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
2426 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) {
2427 			port->enabled = false;
2428 
2429 			dlb2_ldb_port_cq_disable(hw, port);
2430 		}
2431 	}
2432 }
2433 
2434 
dlb2_log_reset_domain(struct dlb2_hw * hw,u32 domain_id,bool vdev_req,unsigned int vdev_id)2435 static void dlb2_log_reset_domain(struct dlb2_hw *hw,
2436 				  u32 domain_id,
2437 				  bool vdev_req,
2438 				  unsigned int vdev_id)
2439 {
2440 	DLB2_HW_DBG(hw, "DLB2 reset domain:\n");
2441 	if (vdev_req)
2442 		DLB2_HW_DBG(hw, "(Request from vdev %d)\n", vdev_id);
2443 	DLB2_HW_DBG(hw, "\tDomain ID: %d\n", domain_id);
2444 }
2445 
dlb2_domain_disable_dir_vpps(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,unsigned int vdev_id)2446 static void dlb2_domain_disable_dir_vpps(struct dlb2_hw *hw,
2447 					 struct dlb2_hw_domain *domain,
2448 					 unsigned int vdev_id)
2449 {
2450 	struct dlb2_list_entry *iter;
2451 	struct dlb2_dir_pq_pair *port;
2452 	u32 vpp_v = 0;
2453 	RTE_SET_USED(iter);
2454 
2455 	DLB2_DOM_LIST_FOR(domain->used_dir_pq_pairs, port, iter) {
2456 		unsigned int offs;
2457 		u32 virt_id;
2458 
2459 		if (hw->virt_mode == DLB2_VIRT_SRIOV)
2460 			virt_id = port->id.virt_id;
2461 		else
2462 			virt_id = port->id.phys_id;
2463 
2464 		offs = vdev_id * DLB2_MAX_NUM_DIR_PORTS(hw->ver) + virt_id;
2465 
2466 		DLB2_CSR_WR(hw, DLB2_SYS_VF_DIR_VPP_V(offs), vpp_v);
2467 	}
2468 }
2469 
dlb2_domain_disable_ldb_vpps(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,unsigned int vdev_id)2470 static void dlb2_domain_disable_ldb_vpps(struct dlb2_hw *hw,
2471 					 struct dlb2_hw_domain *domain,
2472 					 unsigned int vdev_id)
2473 {
2474 	struct dlb2_list_entry *iter;
2475 	struct dlb2_ldb_port *port;
2476 	u32 vpp_v = 0;
2477 	int i;
2478 	RTE_SET_USED(iter);
2479 
2480 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
2481 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) {
2482 			unsigned int offs;
2483 			u32 virt_id;
2484 
2485 			if (hw->virt_mode == DLB2_VIRT_SRIOV)
2486 				virt_id = port->id.virt_id;
2487 			else
2488 				virt_id = port->id.phys_id;
2489 
2490 			offs = vdev_id * DLB2_MAX_NUM_LDB_PORTS + virt_id;
2491 
2492 			DLB2_CSR_WR(hw, DLB2_SYS_VF_LDB_VPP_V(offs), vpp_v);
2493 		}
2494 	}
2495 }
2496 
2497 static void
dlb2_domain_disable_ldb_port_interrupts(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2498 dlb2_domain_disable_ldb_port_interrupts(struct dlb2_hw *hw,
2499 					struct dlb2_hw_domain *domain)
2500 {
2501 	struct dlb2_list_entry *iter;
2502 	struct dlb2_ldb_port *port;
2503 	u32 int_en = 0;
2504 	u32 wd_en = 0;
2505 	int i;
2506 	RTE_SET_USED(iter);
2507 
2508 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
2509 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) {
2510 			DLB2_CSR_WR(hw,
2511 				    DLB2_CHP_LDB_CQ_INT_ENB(hw->ver,
2512 						       port->id.phys_id),
2513 				    int_en);
2514 
2515 			DLB2_CSR_WR(hw,
2516 				    DLB2_CHP_LDB_CQ_WD_ENB(hw->ver,
2517 						      port->id.phys_id),
2518 				    wd_en);
2519 		}
2520 	}
2521 }
2522 
2523 static void
dlb2_domain_disable_dir_port_interrupts(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2524 dlb2_domain_disable_dir_port_interrupts(struct dlb2_hw *hw,
2525 					struct dlb2_hw_domain *domain)
2526 {
2527 	struct dlb2_list_entry *iter;
2528 	struct dlb2_dir_pq_pair *port;
2529 	u32 int_en = 0;
2530 	u32 wd_en = 0;
2531 	RTE_SET_USED(iter);
2532 
2533 	DLB2_DOM_LIST_FOR(domain->used_dir_pq_pairs, port, iter) {
2534 		DLB2_CSR_WR(hw,
2535 			    DLB2_CHP_DIR_CQ_INT_ENB(hw->ver, port->id.phys_id),
2536 			    int_en);
2537 
2538 		DLB2_CSR_WR(hw,
2539 			    DLB2_CHP_DIR_CQ_WD_ENB(hw->ver, port->id.phys_id),
2540 			    wd_en);
2541 	}
2542 }
2543 
2544 static void
dlb2_domain_disable_ldb_queue_write_perms(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2545 dlb2_domain_disable_ldb_queue_write_perms(struct dlb2_hw *hw,
2546 					  struct dlb2_hw_domain *domain)
2547 {
2548 	int domain_offset = domain->id.phys_id * DLB2_MAX_NUM_LDB_QUEUES;
2549 	struct dlb2_list_entry *iter;
2550 	struct dlb2_ldb_queue *queue;
2551 	RTE_SET_USED(iter);
2552 
2553 	DLB2_DOM_LIST_FOR(domain->used_ldb_queues, queue, iter) {
2554 		int idx = domain_offset + queue->id.phys_id;
2555 
2556 		DLB2_CSR_WR(hw, DLB2_SYS_LDB_VASQID_V(idx), 0);
2557 
2558 		if (queue->id.vdev_owned) {
2559 			DLB2_CSR_WR(hw,
2560 				    DLB2_SYS_LDB_QID2VQID(queue->id.phys_id),
2561 				    0);
2562 
2563 			idx = queue->id.vdev_id * DLB2_MAX_NUM_LDB_QUEUES +
2564 				queue->id.virt_id;
2565 
2566 			DLB2_CSR_WR(hw, DLB2_SYS_VF_LDB_VQID_V(idx), 0);
2567 
2568 			DLB2_CSR_WR(hw, DLB2_SYS_VF_LDB_VQID2QID(idx), 0);
2569 		}
2570 	}
2571 }
2572 
2573 static void
dlb2_domain_disable_dir_queue_write_perms(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2574 dlb2_domain_disable_dir_queue_write_perms(struct dlb2_hw *hw,
2575 					  struct dlb2_hw_domain *domain)
2576 {
2577 	struct dlb2_list_entry *iter;
2578 	struct dlb2_dir_pq_pair *queue;
2579 	unsigned long max_ports;
2580 	int domain_offset;
2581 	RTE_SET_USED(iter);
2582 
2583 	max_ports = DLB2_MAX_NUM_DIR_PORTS(hw->ver);
2584 
2585 	domain_offset = domain->id.phys_id * max_ports;
2586 
2587 	DLB2_DOM_LIST_FOR(domain->used_dir_pq_pairs, queue, iter) {
2588 		int idx = domain_offset + queue->id.phys_id;
2589 
2590 		DLB2_CSR_WR(hw, DLB2_SYS_DIR_VASQID_V(idx), 0);
2591 
2592 		if (queue->id.vdev_owned) {
2593 			idx = queue->id.vdev_id * max_ports + queue->id.virt_id;
2594 
2595 			DLB2_CSR_WR(hw, DLB2_SYS_VF_DIR_VQID_V(idx), 0);
2596 
2597 			DLB2_CSR_WR(hw, DLB2_SYS_VF_DIR_VQID2QID(idx), 0);
2598 		}
2599 	}
2600 }
2601 
dlb2_domain_disable_ldb_seq_checks(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2602 static void dlb2_domain_disable_ldb_seq_checks(struct dlb2_hw *hw,
2603 					       struct dlb2_hw_domain *domain)
2604 {
2605 	struct dlb2_list_entry *iter;
2606 	struct dlb2_ldb_port *port;
2607 	u32 chk_en = 0;
2608 	int i;
2609 	RTE_SET_USED(iter);
2610 
2611 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
2612 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) {
2613 			DLB2_CSR_WR(hw,
2614 				    DLB2_CHP_SN_CHK_ENBL(hw->ver,
2615 							 port->id.phys_id),
2616 				    chk_en);
2617 		}
2618 	}
2619 }
2620 
dlb2_domain_wait_for_ldb_cqs_to_empty(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2621 static int dlb2_domain_wait_for_ldb_cqs_to_empty(struct dlb2_hw *hw,
2622 						 struct dlb2_hw_domain *domain)
2623 {
2624 	struct dlb2_list_entry *iter;
2625 	struct dlb2_ldb_port *port;
2626 	int i;
2627 	RTE_SET_USED(iter);
2628 
2629 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
2630 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) {
2631 			int j;
2632 
2633 			for (j = 0; j < DLB2_MAX_CQ_COMP_CHECK_LOOPS; j++) {
2634 				if (dlb2_ldb_cq_inflight_count(hw, port) == 0)
2635 					break;
2636 			}
2637 
2638 			if (j == DLB2_MAX_CQ_COMP_CHECK_LOOPS) {
2639 				DLB2_HW_ERR(hw,
2640 					    "[%s()] Internal error: failed to flush load-balanced port %d's completions.\n",
2641 					    __func__, port->id.phys_id);
2642 				return -EFAULT;
2643 			}
2644 		}
2645 	}
2646 
2647 	return 0;
2648 }
2649 
dlb2_domain_disable_dir_cqs(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2650 static void dlb2_domain_disable_dir_cqs(struct dlb2_hw *hw,
2651 					struct dlb2_hw_domain *domain)
2652 {
2653 	struct dlb2_list_entry *iter;
2654 	struct dlb2_dir_pq_pair *port;
2655 	RTE_SET_USED(iter);
2656 
2657 	DLB2_DOM_LIST_FOR(domain->used_dir_pq_pairs, port, iter) {
2658 		port->enabled = false;
2659 
2660 		dlb2_dir_port_cq_disable(hw, port);
2661 	}
2662 }
2663 
2664 static void
dlb2_domain_disable_dir_producer_ports(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2665 dlb2_domain_disable_dir_producer_ports(struct dlb2_hw *hw,
2666 				       struct dlb2_hw_domain *domain)
2667 {
2668 	struct dlb2_list_entry *iter;
2669 	struct dlb2_dir_pq_pair *port;
2670 	u32 pp_v = 0;
2671 	RTE_SET_USED(iter);
2672 
2673 	DLB2_DOM_LIST_FOR(domain->used_dir_pq_pairs, port, iter) {
2674 		DLB2_CSR_WR(hw,
2675 			    DLB2_SYS_DIR_PP_V(port->id.phys_id),
2676 			    pp_v);
2677 	}
2678 }
2679 
2680 static void
dlb2_domain_disable_ldb_producer_ports(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2681 dlb2_domain_disable_ldb_producer_ports(struct dlb2_hw *hw,
2682 				       struct dlb2_hw_domain *domain)
2683 {
2684 	struct dlb2_list_entry *iter;
2685 	struct dlb2_ldb_port *port;
2686 	u32 pp_v = 0;
2687 	int i;
2688 	RTE_SET_USED(iter);
2689 
2690 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
2691 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) {
2692 			DLB2_CSR_WR(hw,
2693 				    DLB2_SYS_LDB_PP_V(port->id.phys_id),
2694 				    pp_v);
2695 		}
2696 	}
2697 }
2698 
dlb2_domain_verify_reset_success(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2699 static int dlb2_domain_verify_reset_success(struct dlb2_hw *hw,
2700 					    struct dlb2_hw_domain *domain)
2701 {
2702 	struct dlb2_list_entry *iter;
2703 	struct dlb2_dir_pq_pair *dir_port;
2704 	struct dlb2_ldb_port *ldb_port;
2705 	struct dlb2_ldb_queue *queue;
2706 	int i;
2707 	RTE_SET_USED(iter);
2708 
2709 	/*
2710 	 * Confirm that all the domain's queue's inflight counts and AQED
2711 	 * active counts are 0.
2712 	 */
2713 	DLB2_DOM_LIST_FOR(domain->used_ldb_queues, queue, iter) {
2714 		if (!dlb2_ldb_queue_is_empty(hw, queue)) {
2715 			DLB2_HW_ERR(hw,
2716 				    "[%s()] Internal error: failed to empty ldb queue %d\n",
2717 				    __func__, queue->id.phys_id);
2718 			return -EFAULT;
2719 		}
2720 	}
2721 
2722 	/* Confirm that all the domain's CQs inflight and token counts are 0. */
2723 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
2724 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], ldb_port, iter) {
2725 			if (dlb2_ldb_cq_inflight_count(hw, ldb_port) ||
2726 			    dlb2_ldb_cq_token_count(hw, ldb_port)) {
2727 				DLB2_HW_ERR(hw,
2728 					    "[%s()] Internal error: failed to empty ldb port %d\n",
2729 					    __func__, ldb_port->id.phys_id);
2730 				return -EFAULT;
2731 			}
2732 		}
2733 	}
2734 
2735 	DLB2_DOM_LIST_FOR(domain->used_dir_pq_pairs, dir_port, iter) {
2736 		if (!dlb2_dir_queue_is_empty(hw, dir_port)) {
2737 			DLB2_HW_ERR(hw,
2738 				    "[%s()] Internal error: failed to empty dir queue %d\n",
2739 				    __func__, dir_port->id.phys_id);
2740 			return -EFAULT;
2741 		}
2742 
2743 		if (dlb2_dir_cq_token_count(hw, dir_port)) {
2744 			DLB2_HW_ERR(hw,
2745 				    "[%s()] Internal error: failed to empty dir port %d\n",
2746 				    __func__, dir_port->id.phys_id);
2747 			return -EFAULT;
2748 		}
2749 	}
2750 
2751 	return 0;
2752 }
2753 
__dlb2_domain_reset_ldb_port_registers(struct dlb2_hw * hw,struct dlb2_ldb_port * port)2754 static void __dlb2_domain_reset_ldb_port_registers(struct dlb2_hw *hw,
2755 						   struct dlb2_ldb_port *port)
2756 {
2757 	DLB2_CSR_WR(hw,
2758 		    DLB2_SYS_LDB_PP2VAS(port->id.phys_id),
2759 		    DLB2_SYS_LDB_PP2VAS_RST);
2760 
2761 	DLB2_CSR_WR(hw,
2762 		    DLB2_CHP_LDB_CQ2VAS(hw->ver, port->id.phys_id),
2763 		    DLB2_CHP_LDB_CQ2VAS_RST);
2764 
2765 	DLB2_CSR_WR(hw,
2766 		    DLB2_SYS_LDB_PP2VDEV(port->id.phys_id),
2767 		    DLB2_SYS_LDB_PP2VDEV_RST);
2768 
2769 	if (port->id.vdev_owned) {
2770 		unsigned int offs;
2771 		u32 virt_id;
2772 
2773 		/*
2774 		 * DLB uses producer port address bits 17:12 to determine the
2775 		 * producer port ID. In Scalable IOV mode, PP accesses come
2776 		 * through the PF MMIO window for the physical producer port,
2777 		 * so for translation purposes the virtual and physical port
2778 		 * IDs are equal.
2779 		 */
2780 		if (hw->virt_mode == DLB2_VIRT_SRIOV)
2781 			virt_id = port->id.virt_id;
2782 		else
2783 			virt_id = port->id.phys_id;
2784 
2785 		offs = port->id.vdev_id * DLB2_MAX_NUM_LDB_PORTS + virt_id;
2786 
2787 		DLB2_CSR_WR(hw,
2788 			    DLB2_SYS_VF_LDB_VPP2PP(offs),
2789 			    DLB2_SYS_VF_LDB_VPP2PP_RST);
2790 
2791 		DLB2_CSR_WR(hw,
2792 			    DLB2_SYS_VF_LDB_VPP_V(offs),
2793 			    DLB2_SYS_VF_LDB_VPP_V_RST);
2794 	}
2795 
2796 	DLB2_CSR_WR(hw,
2797 		    DLB2_SYS_LDB_PP_V(port->id.phys_id),
2798 		    DLB2_SYS_LDB_PP_V_RST);
2799 
2800 	DLB2_CSR_WR(hw,
2801 		    DLB2_LSP_CQ_LDB_DSBL(hw->ver, port->id.phys_id),
2802 		    DLB2_LSP_CQ_LDB_DSBL_RST);
2803 
2804 	DLB2_CSR_WR(hw,
2805 		    DLB2_CHP_LDB_CQ_DEPTH(hw->ver, port->id.phys_id),
2806 		    DLB2_CHP_LDB_CQ_DEPTH_RST);
2807 
2808 	if (hw->ver != DLB2_HW_V2)
2809 		DLB2_CSR_WR(hw,
2810 			    DLB2_LSP_CFG_CQ_LDB_WU_LIMIT(port->id.phys_id),
2811 			    DLB2_LSP_CFG_CQ_LDB_WU_LIMIT_RST);
2812 
2813 	DLB2_CSR_WR(hw,
2814 		    DLB2_LSP_CQ_LDB_INFL_LIM(hw->ver, port->id.phys_id),
2815 		    DLB2_LSP_CQ_LDB_INFL_LIM_RST);
2816 
2817 	DLB2_CSR_WR(hw,
2818 		    DLB2_CHP_HIST_LIST_LIM(hw->ver, port->id.phys_id),
2819 		    DLB2_CHP_HIST_LIST_LIM_RST);
2820 
2821 	DLB2_CSR_WR(hw,
2822 		    DLB2_CHP_HIST_LIST_BASE(hw->ver, port->id.phys_id),
2823 		    DLB2_CHP_HIST_LIST_BASE_RST);
2824 
2825 	DLB2_CSR_WR(hw,
2826 		    DLB2_CHP_HIST_LIST_POP_PTR(hw->ver, port->id.phys_id),
2827 		    DLB2_CHP_HIST_LIST_POP_PTR_RST);
2828 
2829 	DLB2_CSR_WR(hw,
2830 		    DLB2_CHP_HIST_LIST_PUSH_PTR(hw->ver, port->id.phys_id),
2831 		    DLB2_CHP_HIST_LIST_PUSH_PTR_RST);
2832 
2833 	DLB2_CSR_WR(hw,
2834 		    DLB2_CHP_LDB_CQ_INT_DEPTH_THRSH(hw->ver, port->id.phys_id),
2835 		    DLB2_CHP_LDB_CQ_INT_DEPTH_THRSH_RST);
2836 
2837 	DLB2_CSR_WR(hw,
2838 		    DLB2_CHP_LDB_CQ_TMR_THRSH(hw->ver, port->id.phys_id),
2839 		    DLB2_CHP_LDB_CQ_TMR_THRSH_RST);
2840 
2841 	DLB2_CSR_WR(hw,
2842 		    DLB2_CHP_LDB_CQ_INT_ENB(hw->ver, port->id.phys_id),
2843 		    DLB2_CHP_LDB_CQ_INT_ENB_RST);
2844 
2845 	DLB2_CSR_WR(hw,
2846 		    DLB2_SYS_LDB_CQ_ISR(port->id.phys_id),
2847 		    DLB2_SYS_LDB_CQ_ISR_RST);
2848 
2849 	DLB2_CSR_WR(hw,
2850 		    DLB2_LSP_CQ_LDB_TKN_DEPTH_SEL(hw->ver, port->id.phys_id),
2851 		    DLB2_LSP_CQ_LDB_TKN_DEPTH_SEL_RST);
2852 
2853 	DLB2_CSR_WR(hw,
2854 		    DLB2_CHP_LDB_CQ_TKN_DEPTH_SEL(hw->ver, port->id.phys_id),
2855 		    DLB2_CHP_LDB_CQ_TKN_DEPTH_SEL_RST);
2856 
2857 	DLB2_CSR_WR(hw,
2858 		    DLB2_CHP_LDB_CQ_WPTR(hw->ver, port->id.phys_id),
2859 		    DLB2_CHP_LDB_CQ_WPTR_RST);
2860 
2861 	DLB2_CSR_WR(hw,
2862 		    DLB2_LSP_CQ_LDB_TKN_CNT(hw->ver, port->id.phys_id),
2863 		    DLB2_LSP_CQ_LDB_TKN_CNT_RST);
2864 
2865 	DLB2_CSR_WR(hw,
2866 		    DLB2_SYS_LDB_CQ_ADDR_L(port->id.phys_id),
2867 		    DLB2_SYS_LDB_CQ_ADDR_L_RST);
2868 
2869 	DLB2_CSR_WR(hw,
2870 		    DLB2_SYS_LDB_CQ_ADDR_U(port->id.phys_id),
2871 		    DLB2_SYS_LDB_CQ_ADDR_U_RST);
2872 
2873 	if (hw->ver == DLB2_HW_V2)
2874 		DLB2_CSR_WR(hw,
2875 			    DLB2_SYS_LDB_CQ_AT(port->id.phys_id),
2876 			    DLB2_SYS_LDB_CQ_AT_RST);
2877 
2878 	DLB2_CSR_WR(hw,
2879 		    DLB2_SYS_LDB_CQ_PASID(hw->ver, port->id.phys_id),
2880 		    DLB2_SYS_LDB_CQ_PASID_RST);
2881 
2882 	DLB2_CSR_WR(hw,
2883 		    DLB2_SYS_LDB_CQ2VF_PF_RO(port->id.phys_id),
2884 		    DLB2_SYS_LDB_CQ2VF_PF_RO_RST);
2885 
2886 	DLB2_CSR_WR(hw,
2887 		    DLB2_LSP_CQ_LDB_TOT_SCH_CNTL(hw->ver, port->id.phys_id),
2888 		    DLB2_LSP_CQ_LDB_TOT_SCH_CNTL_RST);
2889 
2890 	DLB2_CSR_WR(hw,
2891 		    DLB2_LSP_CQ_LDB_TOT_SCH_CNTH(hw->ver, port->id.phys_id),
2892 		    DLB2_LSP_CQ_LDB_TOT_SCH_CNTH_RST);
2893 
2894 	DLB2_CSR_WR(hw,
2895 		    DLB2_LSP_CQ2QID0(hw->ver, port->id.phys_id),
2896 		    DLB2_LSP_CQ2QID0_RST);
2897 
2898 	DLB2_CSR_WR(hw,
2899 		    DLB2_LSP_CQ2QID1(hw->ver, port->id.phys_id),
2900 		    DLB2_LSP_CQ2QID1_RST);
2901 
2902 	DLB2_CSR_WR(hw,
2903 		    DLB2_LSP_CQ2PRIOV(hw->ver, port->id.phys_id),
2904 		    DLB2_LSP_CQ2PRIOV_RST);
2905 }
2906 
dlb2_domain_reset_ldb_port_registers(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)2907 static void dlb2_domain_reset_ldb_port_registers(struct dlb2_hw *hw,
2908 						 struct dlb2_hw_domain *domain)
2909 {
2910 	struct dlb2_list_entry *iter;
2911 	struct dlb2_ldb_port *port;
2912 	int i;
2913 	RTE_SET_USED(iter);
2914 
2915 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
2916 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter)
2917 			__dlb2_domain_reset_ldb_port_registers(hw, port);
2918 	}
2919 }
2920 
2921 static void
__dlb2_domain_reset_dir_port_registers(struct dlb2_hw * hw,struct dlb2_dir_pq_pair * port)2922 __dlb2_domain_reset_dir_port_registers(struct dlb2_hw *hw,
2923 				       struct dlb2_dir_pq_pair *port)
2924 {
2925 	u32 reg = 0;
2926 
2927 	DLB2_CSR_WR(hw,
2928 		    DLB2_CHP_DIR_CQ2VAS(hw->ver, port->id.phys_id),
2929 		    DLB2_CHP_DIR_CQ2VAS_RST);
2930 
2931 	DLB2_CSR_WR(hw,
2932 		    DLB2_LSP_CQ_DIR_DSBL(hw->ver, port->id.phys_id),
2933 		    DLB2_LSP_CQ_DIR_DSBL_RST);
2934 
2935 	DLB2_BIT_SET(reg, DLB2_SYS_WB_DIR_CQ_STATE_CQ_OPT_CLR);
2936 
2937 	if (hw->ver == DLB2_HW_V2)
2938 		DLB2_CSR_WR(hw, DLB2_SYS_DIR_CQ_OPT_CLR, port->id.phys_id);
2939 	else
2940 		DLB2_CSR_WR(hw,
2941 			    DLB2_SYS_WB_DIR_CQ_STATE(port->id.phys_id), reg);
2942 
2943 	DLB2_CSR_WR(hw,
2944 		    DLB2_CHP_DIR_CQ_DEPTH(hw->ver, port->id.phys_id),
2945 		    DLB2_CHP_DIR_CQ_DEPTH_RST);
2946 
2947 	DLB2_CSR_WR(hw,
2948 		    DLB2_CHP_DIR_CQ_INT_DEPTH_THRSH(hw->ver, port->id.phys_id),
2949 		    DLB2_CHP_DIR_CQ_INT_DEPTH_THRSH_RST);
2950 
2951 	DLB2_CSR_WR(hw,
2952 		    DLB2_CHP_DIR_CQ_TMR_THRSH(hw->ver, port->id.phys_id),
2953 		    DLB2_CHP_DIR_CQ_TMR_THRSH_RST);
2954 
2955 	DLB2_CSR_WR(hw,
2956 		    DLB2_CHP_DIR_CQ_INT_ENB(hw->ver, port->id.phys_id),
2957 		    DLB2_CHP_DIR_CQ_INT_ENB_RST);
2958 
2959 	DLB2_CSR_WR(hw,
2960 		    DLB2_SYS_DIR_CQ_ISR(port->id.phys_id),
2961 		    DLB2_SYS_DIR_CQ_ISR_RST);
2962 
2963 	DLB2_CSR_WR(hw,
2964 		    DLB2_LSP_CQ_DIR_TKN_DEPTH_SEL_DSI(hw->ver,
2965 						      port->id.phys_id),
2966 		    DLB2_LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_RST);
2967 
2968 	DLB2_CSR_WR(hw,
2969 		    DLB2_CHP_DIR_CQ_TKN_DEPTH_SEL(hw->ver, port->id.phys_id),
2970 		    DLB2_CHP_DIR_CQ_TKN_DEPTH_SEL_RST);
2971 
2972 	DLB2_CSR_WR(hw,
2973 		    DLB2_CHP_DIR_CQ_WPTR(hw->ver, port->id.phys_id),
2974 		    DLB2_CHP_DIR_CQ_WPTR_RST);
2975 
2976 	DLB2_CSR_WR(hw,
2977 		    DLB2_LSP_CQ_DIR_TKN_CNT(hw->ver, port->id.phys_id),
2978 		    DLB2_LSP_CQ_DIR_TKN_CNT_RST);
2979 
2980 	DLB2_CSR_WR(hw,
2981 		    DLB2_SYS_DIR_CQ_ADDR_L(port->id.phys_id),
2982 		    DLB2_SYS_DIR_CQ_ADDR_L_RST);
2983 
2984 	DLB2_CSR_WR(hw,
2985 		    DLB2_SYS_DIR_CQ_ADDR_U(port->id.phys_id),
2986 		    DLB2_SYS_DIR_CQ_ADDR_U_RST);
2987 
2988 	DLB2_CSR_WR(hw,
2989 		    DLB2_SYS_DIR_CQ_AT(port->id.phys_id),
2990 		    DLB2_SYS_DIR_CQ_AT_RST);
2991 
2992 	if (hw->ver == DLB2_HW_V2)
2993 		DLB2_CSR_WR(hw,
2994 			    DLB2_SYS_DIR_CQ_AT(port->id.phys_id),
2995 			    DLB2_SYS_DIR_CQ_AT_RST);
2996 
2997 	DLB2_CSR_WR(hw,
2998 		    DLB2_SYS_DIR_CQ_PASID(hw->ver, port->id.phys_id),
2999 		    DLB2_SYS_DIR_CQ_PASID_RST);
3000 
3001 	DLB2_CSR_WR(hw,
3002 		    DLB2_SYS_DIR_CQ_FMT(port->id.phys_id),
3003 		    DLB2_SYS_DIR_CQ_FMT_RST);
3004 
3005 	DLB2_CSR_WR(hw,
3006 		    DLB2_SYS_DIR_CQ2VF_PF_RO(port->id.phys_id),
3007 		    DLB2_SYS_DIR_CQ2VF_PF_RO_RST);
3008 
3009 	DLB2_CSR_WR(hw,
3010 		    DLB2_LSP_CQ_DIR_TOT_SCH_CNTL(hw->ver, port->id.phys_id),
3011 		    DLB2_LSP_CQ_DIR_TOT_SCH_CNTL_RST);
3012 
3013 	DLB2_CSR_WR(hw,
3014 		    DLB2_LSP_CQ_DIR_TOT_SCH_CNTH(hw->ver, port->id.phys_id),
3015 		    DLB2_LSP_CQ_DIR_TOT_SCH_CNTH_RST);
3016 
3017 	DLB2_CSR_WR(hw,
3018 		    DLB2_SYS_DIR_PP2VAS(port->id.phys_id),
3019 		    DLB2_SYS_DIR_PP2VAS_RST);
3020 
3021 	DLB2_CSR_WR(hw,
3022 		    DLB2_CHP_DIR_CQ2VAS(hw->ver, port->id.phys_id),
3023 		    DLB2_CHP_DIR_CQ2VAS_RST);
3024 
3025 	DLB2_CSR_WR(hw,
3026 		    DLB2_SYS_DIR_PP2VDEV(port->id.phys_id),
3027 		    DLB2_SYS_DIR_PP2VDEV_RST);
3028 
3029 	if (port->id.vdev_owned) {
3030 		unsigned int offs;
3031 		u32 virt_id;
3032 
3033 		/*
3034 		 * DLB uses producer port address bits 17:12 to determine the
3035 		 * producer port ID. In Scalable IOV mode, PP accesses come
3036 		 * through the PF MMIO window for the physical producer port,
3037 		 * so for translation purposes the virtual and physical port
3038 		 * IDs are equal.
3039 		 */
3040 		if (hw->virt_mode == DLB2_VIRT_SRIOV)
3041 			virt_id = port->id.virt_id;
3042 		else
3043 			virt_id = port->id.phys_id;
3044 
3045 		offs = port->id.vdev_id * DLB2_MAX_NUM_DIR_PORTS(hw->ver) +
3046 			virt_id;
3047 
3048 		DLB2_CSR_WR(hw,
3049 			    DLB2_SYS_VF_DIR_VPP2PP(offs),
3050 			    DLB2_SYS_VF_DIR_VPP2PP_RST);
3051 
3052 		DLB2_CSR_WR(hw,
3053 			    DLB2_SYS_VF_DIR_VPP_V(offs),
3054 			    DLB2_SYS_VF_DIR_VPP_V_RST);
3055 	}
3056 
3057 	DLB2_CSR_WR(hw,
3058 		    DLB2_SYS_DIR_PP_V(port->id.phys_id),
3059 		    DLB2_SYS_DIR_PP_V_RST);
3060 }
3061 
dlb2_domain_reset_dir_port_registers(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)3062 static void dlb2_domain_reset_dir_port_registers(struct dlb2_hw *hw,
3063 						 struct dlb2_hw_domain *domain)
3064 {
3065 	struct dlb2_list_entry *iter;
3066 	struct dlb2_dir_pq_pair *port;
3067 	RTE_SET_USED(iter);
3068 
3069 	DLB2_DOM_LIST_FOR(domain->used_dir_pq_pairs, port, iter)
3070 		__dlb2_domain_reset_dir_port_registers(hw, port);
3071 }
3072 
dlb2_domain_reset_ldb_queue_registers(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)3073 static void dlb2_domain_reset_ldb_queue_registers(struct dlb2_hw *hw,
3074 						  struct dlb2_hw_domain *domain)
3075 {
3076 	struct dlb2_list_entry *iter;
3077 	struct dlb2_ldb_queue *queue;
3078 	RTE_SET_USED(iter);
3079 
3080 	DLB2_DOM_LIST_FOR(domain->used_ldb_queues, queue, iter) {
3081 		unsigned int queue_id = queue->id.phys_id;
3082 		int i;
3083 
3084 		DLB2_CSR_WR(hw,
3085 			    DLB2_LSP_QID_NALDB_TOT_ENQ_CNTL(hw->ver, queue_id),
3086 			    DLB2_LSP_QID_NALDB_TOT_ENQ_CNTL_RST);
3087 
3088 		DLB2_CSR_WR(hw,
3089 			    DLB2_LSP_QID_NALDB_TOT_ENQ_CNTH(hw->ver, queue_id),
3090 			    DLB2_LSP_QID_NALDB_TOT_ENQ_CNTH_RST);
3091 
3092 		DLB2_CSR_WR(hw,
3093 			    DLB2_LSP_QID_ATM_TOT_ENQ_CNTL(hw->ver, queue_id),
3094 			    DLB2_LSP_QID_ATM_TOT_ENQ_CNTL_RST);
3095 
3096 		DLB2_CSR_WR(hw,
3097 			    DLB2_LSP_QID_ATM_TOT_ENQ_CNTH(hw->ver, queue_id),
3098 			    DLB2_LSP_QID_ATM_TOT_ENQ_CNTH_RST);
3099 
3100 		DLB2_CSR_WR(hw,
3101 			    DLB2_LSP_QID_NALDB_MAX_DEPTH(hw->ver, queue_id),
3102 			    DLB2_LSP_QID_NALDB_MAX_DEPTH_RST);
3103 
3104 		DLB2_CSR_WR(hw,
3105 			    DLB2_LSP_QID_LDB_INFL_LIM(hw->ver, queue_id),
3106 			    DLB2_LSP_QID_LDB_INFL_LIM_RST);
3107 
3108 		DLB2_CSR_WR(hw,
3109 			    DLB2_LSP_QID_AQED_ACTIVE_LIM(hw->ver, queue_id),
3110 			    DLB2_LSP_QID_AQED_ACTIVE_LIM_RST);
3111 
3112 		DLB2_CSR_WR(hw,
3113 			    DLB2_LSP_QID_ATM_DEPTH_THRSH(hw->ver, queue_id),
3114 			    DLB2_LSP_QID_ATM_DEPTH_THRSH_RST);
3115 
3116 		DLB2_CSR_WR(hw,
3117 			    DLB2_LSP_QID_NALDB_DEPTH_THRSH(hw->ver, queue_id),
3118 			    DLB2_LSP_QID_NALDB_DEPTH_THRSH_RST);
3119 
3120 		DLB2_CSR_WR(hw,
3121 			    DLB2_SYS_LDB_QID_ITS(queue_id),
3122 			    DLB2_SYS_LDB_QID_ITS_RST);
3123 
3124 		DLB2_CSR_WR(hw,
3125 			    DLB2_CHP_ORD_QID_SN(hw->ver, queue_id),
3126 			    DLB2_CHP_ORD_QID_SN_RST);
3127 
3128 		DLB2_CSR_WR(hw,
3129 			    DLB2_CHP_ORD_QID_SN_MAP(hw->ver, queue_id),
3130 			    DLB2_CHP_ORD_QID_SN_MAP_RST);
3131 
3132 		DLB2_CSR_WR(hw,
3133 			    DLB2_SYS_LDB_QID_V(queue_id),
3134 			    DLB2_SYS_LDB_QID_V_RST);
3135 
3136 		DLB2_CSR_WR(hw,
3137 			    DLB2_SYS_LDB_QID_CFG_V(queue_id),
3138 			    DLB2_SYS_LDB_QID_CFG_V_RST);
3139 
3140 		if (queue->sn_cfg_valid) {
3141 			u32 offs[2];
3142 
3143 			offs[0] = DLB2_RO_GRP_0_SLT_SHFT(hw->ver,
3144 							 queue->sn_slot);
3145 			offs[1] = DLB2_RO_GRP_1_SLT_SHFT(hw->ver,
3146 							 queue->sn_slot);
3147 
3148 			DLB2_CSR_WR(hw,
3149 				    offs[queue->sn_group],
3150 				    DLB2_RO_GRP_0_SLT_SHFT_RST);
3151 		}
3152 
3153 		for (i = 0; i < DLB2_LSP_QID2CQIDIX_NUM; i++) {
3154 			DLB2_CSR_WR(hw,
3155 				    DLB2_LSP_QID2CQIDIX(hw->ver, queue_id, i),
3156 				    DLB2_LSP_QID2CQIDIX_00_RST);
3157 
3158 			DLB2_CSR_WR(hw,
3159 				    DLB2_LSP_QID2CQIDIX2(hw->ver, queue_id, i),
3160 				    DLB2_LSP_QID2CQIDIX2_00_RST);
3161 
3162 			DLB2_CSR_WR(hw,
3163 				    DLB2_ATM_QID2CQIDIX(queue_id, i),
3164 				    DLB2_ATM_QID2CQIDIX_00_RST);
3165 		}
3166 	}
3167 }
3168 
dlb2_domain_reset_dir_queue_registers(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)3169 static void dlb2_domain_reset_dir_queue_registers(struct dlb2_hw *hw,
3170 						  struct dlb2_hw_domain *domain)
3171 {
3172 	struct dlb2_list_entry *iter;
3173 	struct dlb2_dir_pq_pair *queue;
3174 	RTE_SET_USED(iter);
3175 
3176 	DLB2_DOM_LIST_FOR(domain->used_dir_pq_pairs, queue, iter) {
3177 		DLB2_CSR_WR(hw,
3178 			    DLB2_LSP_QID_DIR_MAX_DEPTH(hw->ver,
3179 						       queue->id.phys_id),
3180 			    DLB2_LSP_QID_DIR_MAX_DEPTH_RST);
3181 
3182 		DLB2_CSR_WR(hw,
3183 			    DLB2_LSP_QID_DIR_TOT_ENQ_CNTL(hw->ver,
3184 							  queue->id.phys_id),
3185 			    DLB2_LSP_QID_DIR_TOT_ENQ_CNTL_RST);
3186 
3187 		DLB2_CSR_WR(hw,
3188 			    DLB2_LSP_QID_DIR_TOT_ENQ_CNTH(hw->ver,
3189 							  queue->id.phys_id),
3190 			    DLB2_LSP_QID_DIR_TOT_ENQ_CNTH_RST);
3191 
3192 		DLB2_CSR_WR(hw,
3193 			    DLB2_LSP_QID_DIR_DEPTH_THRSH(hw->ver,
3194 							 queue->id.phys_id),
3195 			    DLB2_LSP_QID_DIR_DEPTH_THRSH_RST);
3196 
3197 		DLB2_CSR_WR(hw,
3198 			    DLB2_SYS_DIR_QID_ITS(queue->id.phys_id),
3199 			    DLB2_SYS_DIR_QID_ITS_RST);
3200 
3201 		DLB2_CSR_WR(hw,
3202 			    DLB2_SYS_DIR_QID_V(queue->id.phys_id),
3203 			    DLB2_SYS_DIR_QID_V_RST);
3204 	}
3205 }
3206 
3207 
3208 
3209 
3210 
dlb2_domain_reset_registers(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)3211 static void dlb2_domain_reset_registers(struct dlb2_hw *hw,
3212 					struct dlb2_hw_domain *domain)
3213 {
3214 	dlb2_domain_reset_ldb_port_registers(hw, domain);
3215 
3216 	dlb2_domain_reset_dir_port_registers(hw, domain);
3217 
3218 	dlb2_domain_reset_ldb_queue_registers(hw, domain);
3219 
3220 	dlb2_domain_reset_dir_queue_registers(hw, domain);
3221 
3222 	if (hw->ver == DLB2_HW_V2) {
3223 		DLB2_CSR_WR(hw,
3224 			    DLB2_CHP_CFG_LDB_VAS_CRD(domain->id.phys_id),
3225 			    DLB2_CHP_CFG_LDB_VAS_CRD_RST);
3226 
3227 		DLB2_CSR_WR(hw,
3228 			    DLB2_CHP_CFG_DIR_VAS_CRD(domain->id.phys_id),
3229 			    DLB2_CHP_CFG_DIR_VAS_CRD_RST);
3230 	} else
3231 		DLB2_CSR_WR(hw,
3232 			    DLB2_CHP_CFG_VAS_CRD(domain->id.phys_id),
3233 			    DLB2_CHP_CFG_VAS_CRD_RST);
3234 }
3235 
dlb2_domain_reset_software_state(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)3236 static int dlb2_domain_reset_software_state(struct dlb2_hw *hw,
3237 					    struct dlb2_hw_domain *domain)
3238 {
3239 	struct dlb2_dir_pq_pair *tmp_dir_port;
3240 	struct dlb2_ldb_queue *tmp_ldb_queue;
3241 	struct dlb2_ldb_port *tmp_ldb_port;
3242 	struct dlb2_list_entry *iter1;
3243 	struct dlb2_list_entry *iter2;
3244 	struct dlb2_function_resources *rsrcs;
3245 	struct dlb2_dir_pq_pair *dir_port;
3246 	struct dlb2_ldb_queue *ldb_queue;
3247 	struct dlb2_ldb_port *ldb_port;
3248 	struct dlb2_list_head *list;
3249 	int ret, i;
3250 	RTE_SET_USED(tmp_dir_port);
3251 	RTE_SET_USED(tmp_ldb_queue);
3252 	RTE_SET_USED(tmp_ldb_port);
3253 	RTE_SET_USED(iter1);
3254 	RTE_SET_USED(iter2);
3255 
3256 	rsrcs = domain->parent_func;
3257 
3258 	/* Move the domain's ldb queues to the function's avail list */
3259 	list = &domain->used_ldb_queues;
3260 	DLB2_DOM_LIST_FOR_SAFE(*list, ldb_queue, tmp_ldb_queue, iter1, iter2) {
3261 		if (ldb_queue->sn_cfg_valid) {
3262 			struct dlb2_sn_group *grp;
3263 
3264 			grp = &hw->rsrcs.sn_groups[ldb_queue->sn_group];
3265 
3266 			dlb2_sn_group_free_slot(grp, ldb_queue->sn_slot);
3267 			ldb_queue->sn_cfg_valid = false;
3268 		}
3269 
3270 		ldb_queue->owned = false;
3271 		ldb_queue->num_mappings = 0;
3272 		ldb_queue->num_pending_additions = 0;
3273 
3274 		dlb2_list_del(&domain->used_ldb_queues,
3275 			      &ldb_queue->domain_list);
3276 		dlb2_list_add(&rsrcs->avail_ldb_queues,
3277 			      &ldb_queue->func_list);
3278 		rsrcs->num_avail_ldb_queues++;
3279 	}
3280 
3281 	list = &domain->avail_ldb_queues;
3282 	DLB2_DOM_LIST_FOR_SAFE(*list, ldb_queue, tmp_ldb_queue, iter1, iter2) {
3283 		ldb_queue->owned = false;
3284 
3285 		dlb2_list_del(&domain->avail_ldb_queues,
3286 			      &ldb_queue->domain_list);
3287 		dlb2_list_add(&rsrcs->avail_ldb_queues,
3288 			      &ldb_queue->func_list);
3289 		rsrcs->num_avail_ldb_queues++;
3290 	}
3291 
3292 	/* Move the domain's ldb ports to the function's avail list */
3293 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
3294 		list = &domain->used_ldb_ports[i];
3295 		DLB2_DOM_LIST_FOR_SAFE(*list, ldb_port, tmp_ldb_port,
3296 				       iter1, iter2) {
3297 			int j;
3298 
3299 			ldb_port->owned = false;
3300 			ldb_port->configured = false;
3301 			ldb_port->num_pending_removals = 0;
3302 			ldb_port->num_mappings = 0;
3303 			ldb_port->init_tkn_cnt = 0;
3304 			ldb_port->cq_depth = 0;
3305 			for (j = 0; j < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; j++)
3306 				ldb_port->qid_map[j].state =
3307 					DLB2_QUEUE_UNMAPPED;
3308 
3309 			dlb2_list_del(&domain->used_ldb_ports[i],
3310 				      &ldb_port->domain_list);
3311 			dlb2_list_add(&rsrcs->avail_ldb_ports[i],
3312 				      &ldb_port->func_list);
3313 			rsrcs->num_avail_ldb_ports[i]++;
3314 		}
3315 
3316 		list = &domain->avail_ldb_ports[i];
3317 		DLB2_DOM_LIST_FOR_SAFE(*list, ldb_port, tmp_ldb_port,
3318 				       iter1, iter2) {
3319 			ldb_port->owned = false;
3320 
3321 			dlb2_list_del(&domain->avail_ldb_ports[i],
3322 				      &ldb_port->domain_list);
3323 			dlb2_list_add(&rsrcs->avail_ldb_ports[i],
3324 				      &ldb_port->func_list);
3325 			rsrcs->num_avail_ldb_ports[i]++;
3326 		}
3327 	}
3328 
3329 	/* Move the domain's dir ports to the function's avail list */
3330 	list = &domain->used_dir_pq_pairs;
3331 	DLB2_DOM_LIST_FOR_SAFE(*list, dir_port, tmp_dir_port, iter1, iter2) {
3332 		dir_port->owned = false;
3333 		dir_port->port_configured = false;
3334 		dir_port->init_tkn_cnt = 0;
3335 
3336 		dlb2_list_del(&domain->used_dir_pq_pairs,
3337 			      &dir_port->domain_list);
3338 
3339 		dlb2_list_add(&rsrcs->avail_dir_pq_pairs,
3340 			      &dir_port->func_list);
3341 		rsrcs->num_avail_dir_pq_pairs++;
3342 	}
3343 
3344 	list = &domain->avail_dir_pq_pairs;
3345 	DLB2_DOM_LIST_FOR_SAFE(*list, dir_port, tmp_dir_port, iter1, iter2) {
3346 		dir_port->owned = false;
3347 
3348 		dlb2_list_del(&domain->avail_dir_pq_pairs,
3349 			      &dir_port->domain_list);
3350 
3351 		dlb2_list_add(&rsrcs->avail_dir_pq_pairs,
3352 			      &dir_port->func_list);
3353 		rsrcs->num_avail_dir_pq_pairs++;
3354 	}
3355 
3356 	/* Return hist list entries to the function */
3357 	ret = dlb2_bitmap_set_range(rsrcs->avail_hist_list_entries,
3358 				    domain->hist_list_entry_base,
3359 				    domain->total_hist_list_entries);
3360 	if (ret) {
3361 		DLB2_HW_ERR(hw,
3362 			    "[%s()] Internal error: domain hist list base does not match the function's bitmap.\n",
3363 			    __func__);
3364 		return ret;
3365 	}
3366 
3367 	domain->total_hist_list_entries = 0;
3368 	domain->avail_hist_list_entries = 0;
3369 	domain->hist_list_entry_base = 0;
3370 	domain->hist_list_entry_offset = 0;
3371 
3372 	if (hw->ver == DLB2_HW_V2_5) {
3373 		rsrcs->num_avail_entries += domain->num_credits;
3374 		domain->num_credits = 0;
3375 	} else {
3376 		rsrcs->num_avail_qed_entries += domain->num_ldb_credits;
3377 		domain->num_ldb_credits = 0;
3378 
3379 		rsrcs->num_avail_dqed_entries += domain->num_dir_credits;
3380 		domain->num_dir_credits = 0;
3381 	}
3382 	rsrcs->num_avail_aqed_entries += domain->num_avail_aqed_entries;
3383 	rsrcs->num_avail_aqed_entries += domain->num_used_aqed_entries;
3384 	domain->num_avail_aqed_entries = 0;
3385 	domain->num_used_aqed_entries = 0;
3386 
3387 	domain->num_pending_removals = 0;
3388 	domain->num_pending_additions = 0;
3389 	domain->configured = false;
3390 	domain->started = false;
3391 
3392 	/*
3393 	 * Move the domain out of the used_domains list and back to the
3394 	 * function's avail_domains list.
3395 	 */
3396 	dlb2_list_del(&rsrcs->used_domains, &domain->func_list);
3397 	dlb2_list_add(&rsrcs->avail_domains, &domain->func_list);
3398 	rsrcs->num_avail_domains++;
3399 
3400 	return 0;
3401 }
3402 
dlb2_domain_drain_unmapped_queue(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_queue * queue)3403 static int dlb2_domain_drain_unmapped_queue(struct dlb2_hw *hw,
3404 					    struct dlb2_hw_domain *domain,
3405 					    struct dlb2_ldb_queue *queue)
3406 {
3407 	struct dlb2_ldb_port *port = NULL;
3408 	int ret, i;
3409 
3410 	/* If a domain has LDB queues, it must have LDB ports */
3411 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
3412 		port = DLB2_DOM_LIST_HEAD(domain->used_ldb_ports[i],
3413 					  typeof(*port));
3414 		if (port)
3415 			break;
3416 	}
3417 
3418 	if (port == NULL) {
3419 		DLB2_HW_ERR(hw,
3420 			    "[%s()] Internal error: No configured LDB ports\n",
3421 			    __func__);
3422 		return -EFAULT;
3423 	}
3424 
3425 	/* If necessary, free up a QID slot in this CQ */
3426 	if (port->num_mappings == DLB2_MAX_NUM_QIDS_PER_LDB_CQ) {
3427 		struct dlb2_ldb_queue *mapped_queue;
3428 
3429 		mapped_queue = &hw->rsrcs.ldb_queues[port->qid_map[0].qid];
3430 
3431 		ret = dlb2_ldb_port_unmap_qid(hw, port, mapped_queue);
3432 		if (ret)
3433 			return ret;
3434 	}
3435 
3436 	ret = dlb2_ldb_port_map_qid_dynamic(hw, port, queue, 0);
3437 	if (ret)
3438 		return ret;
3439 
3440 	return dlb2_domain_drain_mapped_queues(hw, domain);
3441 }
3442 
dlb2_domain_drain_unmapped_queues(struct dlb2_hw * hw,struct dlb2_hw_domain * domain)3443 static int dlb2_domain_drain_unmapped_queues(struct dlb2_hw *hw,
3444 					     struct dlb2_hw_domain *domain)
3445 {
3446 	struct dlb2_list_entry *iter;
3447 	struct dlb2_ldb_queue *queue;
3448 	int ret;
3449 	RTE_SET_USED(iter);
3450 
3451 	/* If the domain hasn't been started, there's no traffic to drain */
3452 	if (!domain->started)
3453 		return 0;
3454 
3455 	/*
3456 	 * Pre-condition: the unattached queue must not have any outstanding
3457 	 * completions. This is ensured by calling dlb2_domain_drain_ldb_cqs()
3458 	 * prior to this in dlb2_domain_drain_mapped_queues().
3459 	 */
3460 	DLB2_DOM_LIST_FOR(domain->used_ldb_queues, queue, iter) {
3461 		if (queue->num_mappings != 0 ||
3462 		    dlb2_ldb_queue_is_empty(hw, queue))
3463 			continue;
3464 
3465 		ret = dlb2_domain_drain_unmapped_queue(hw, domain, queue);
3466 		if (ret)
3467 			return ret;
3468 	}
3469 
3470 	return 0;
3471 }
3472 
3473 /**
3474  * dlb2_reset_domain() - reset a scheduling domain
3475  * @hw: dlb2_hw handle for a particular device.
3476  * @domain_id: domain ID.
3477  * @vdev_req: indicates whether this request came from a vdev.
3478  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
3479  *
3480  * This function resets and frees a DLB 2.0 scheduling domain and its associated
3481  * resources.
3482  *
3483  * Pre-condition: the driver must ensure software has stopped sending QEs
3484  * through this domain's producer ports before invoking this function, or
3485  * undefined behavior will result.
3486  *
3487  * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual
3488  * device.
3489  *
3490  * Return:
3491  * Returns 0 upon success, -1 otherwise.
3492  *
3493  * EINVAL - Invalid domain ID, or the domain is not configured.
3494  * EFAULT - Internal error. (Possibly caused if software is the pre-condition
3495  *	    is not met.)
3496  * ETIMEDOUT - Hardware component didn't reset in the expected time.
3497  */
dlb2_reset_domain(struct dlb2_hw * hw,u32 domain_id,bool vdev_req,unsigned int vdev_id)3498 int dlb2_reset_domain(struct dlb2_hw *hw,
3499 		      u32 domain_id,
3500 		      bool vdev_req,
3501 		      unsigned int vdev_id)
3502 {
3503 	struct dlb2_hw_domain *domain;
3504 	int ret;
3505 
3506 	dlb2_log_reset_domain(hw, domain_id, vdev_req, vdev_id);
3507 
3508 	domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id);
3509 
3510 	if (domain == NULL || !domain->configured)
3511 		return -EINVAL;
3512 
3513 	/* Disable VPPs */
3514 	if (vdev_req) {
3515 		dlb2_domain_disable_dir_vpps(hw, domain, vdev_id);
3516 
3517 		dlb2_domain_disable_ldb_vpps(hw, domain, vdev_id);
3518 	}
3519 
3520 	/* Disable CQ interrupts */
3521 	dlb2_domain_disable_dir_port_interrupts(hw, domain);
3522 
3523 	dlb2_domain_disable_ldb_port_interrupts(hw, domain);
3524 
3525 	/*
3526 	 * For each queue owned by this domain, disable its write permissions to
3527 	 * cause any traffic sent to it to be dropped. Well-behaved software
3528 	 * should not be sending QEs at this point.
3529 	 */
3530 	dlb2_domain_disable_dir_queue_write_perms(hw, domain);
3531 
3532 	dlb2_domain_disable_ldb_queue_write_perms(hw, domain);
3533 
3534 	/* Turn off completion tracking on all the domain's PPs. */
3535 	dlb2_domain_disable_ldb_seq_checks(hw, domain);
3536 
3537 	/*
3538 	 * Disable the LDB CQs and drain them in order to complete the map and
3539 	 * unmap procedures, which require zero CQ inflights and zero QID
3540 	 * inflights respectively.
3541 	 */
3542 	dlb2_domain_disable_ldb_cqs(hw, domain);
3543 
3544 	dlb2_domain_drain_ldb_cqs(hw, domain, false);
3545 
3546 	ret = dlb2_domain_wait_for_ldb_cqs_to_empty(hw, domain);
3547 	if (ret)
3548 		return ret;
3549 
3550 	ret = dlb2_domain_finish_unmap_qid_procedures(hw, domain);
3551 	if (ret)
3552 		return ret;
3553 
3554 	ret = dlb2_domain_finish_map_qid_procedures(hw, domain);
3555 	if (ret)
3556 		return ret;
3557 
3558 	/* Re-enable the CQs in order to drain the mapped queues. */
3559 	dlb2_domain_enable_ldb_cqs(hw, domain);
3560 
3561 	ret = dlb2_domain_drain_mapped_queues(hw, domain);
3562 	if (ret)
3563 		return ret;
3564 
3565 	ret = dlb2_domain_drain_unmapped_queues(hw, domain);
3566 	if (ret)
3567 		return ret;
3568 
3569 	/* Done draining LDB QEs, so disable the CQs. */
3570 	dlb2_domain_disable_ldb_cqs(hw, domain);
3571 
3572 	dlb2_domain_drain_dir_queues(hw, domain);
3573 
3574 	/* Done draining DIR QEs, so disable the CQs. */
3575 	dlb2_domain_disable_dir_cqs(hw, domain);
3576 
3577 	/* Disable PPs */
3578 	dlb2_domain_disable_dir_producer_ports(hw, domain);
3579 
3580 	dlb2_domain_disable_ldb_producer_ports(hw, domain);
3581 
3582 	ret = dlb2_domain_verify_reset_success(hw, domain);
3583 	if (ret)
3584 		return ret;
3585 
3586 	/* Reset the QID and port state. */
3587 	dlb2_domain_reset_registers(hw, domain);
3588 
3589 	/* Hardware reset complete. Reset the domain's software state */
3590 	return dlb2_domain_reset_software_state(hw, domain);
3591 }
3592 
3593 static void
dlb2_log_create_ldb_queue_args(struct dlb2_hw * hw,u32 domain_id,struct dlb2_create_ldb_queue_args * args,bool vdev_req,unsigned int vdev_id)3594 dlb2_log_create_ldb_queue_args(struct dlb2_hw *hw,
3595 			       u32 domain_id,
3596 			       struct dlb2_create_ldb_queue_args *args,
3597 			       bool vdev_req,
3598 			       unsigned int vdev_id)
3599 {
3600 	DLB2_HW_DBG(hw, "DLB2 create load-balanced queue arguments:\n");
3601 	if (vdev_req)
3602 		DLB2_HW_DBG(hw, "(Request from vdev %d)\n", vdev_id);
3603 	DLB2_HW_DBG(hw, "\tDomain ID:                  %d\n",
3604 		    domain_id);
3605 	DLB2_HW_DBG(hw, "\tNumber of sequence numbers: %d\n",
3606 		    args->num_sequence_numbers);
3607 	DLB2_HW_DBG(hw, "\tNumber of QID inflights:    %d\n",
3608 		    args->num_qid_inflights);
3609 	DLB2_HW_DBG(hw, "\tNumber of ATM inflights:    %d\n",
3610 		    args->num_atomic_inflights);
3611 }
3612 
3613 static int
dlb2_ldb_queue_attach_to_sn_group(struct dlb2_hw * hw,struct dlb2_ldb_queue * queue,struct dlb2_create_ldb_queue_args * args)3614 dlb2_ldb_queue_attach_to_sn_group(struct dlb2_hw *hw,
3615 				  struct dlb2_ldb_queue *queue,
3616 				  struct dlb2_create_ldb_queue_args *args)
3617 {
3618 	int slot = -1;
3619 	int i;
3620 
3621 	queue->sn_cfg_valid = false;
3622 
3623 	if (args->num_sequence_numbers == 0)
3624 		return 0;
3625 
3626 	for (i = 0; i < DLB2_MAX_NUM_SEQUENCE_NUMBER_GROUPS; i++) {
3627 		struct dlb2_sn_group *group = &hw->rsrcs.sn_groups[i];
3628 
3629 		if (group->sequence_numbers_per_queue ==
3630 		    args->num_sequence_numbers &&
3631 		    !dlb2_sn_group_full(group)) {
3632 			slot = dlb2_sn_group_alloc_slot(group);
3633 			if (slot >= 0)
3634 				break;
3635 		}
3636 	}
3637 
3638 	if (slot == -1) {
3639 		DLB2_HW_ERR(hw,
3640 			    "[%s():%d] Internal error: no sequence number slots available\n",
3641 			    __func__, __LINE__);
3642 		return -EFAULT;
3643 	}
3644 
3645 	queue->sn_cfg_valid = true;
3646 	queue->sn_group = i;
3647 	queue->sn_slot = slot;
3648 	return 0;
3649 }
3650 
3651 static int
dlb2_verify_create_ldb_queue_args(struct dlb2_hw * hw,u32 domain_id,struct dlb2_create_ldb_queue_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id,struct dlb2_hw_domain ** out_domain,struct dlb2_ldb_queue ** out_queue)3652 dlb2_verify_create_ldb_queue_args(struct dlb2_hw *hw,
3653 				  u32 domain_id,
3654 				  struct dlb2_create_ldb_queue_args *args,
3655 				  struct dlb2_cmd_response *resp,
3656 				  bool vdev_req,
3657 				  unsigned int vdev_id,
3658 				  struct dlb2_hw_domain **out_domain,
3659 				  struct dlb2_ldb_queue **out_queue)
3660 {
3661 	struct dlb2_hw_domain *domain;
3662 	struct dlb2_ldb_queue *queue;
3663 	int i;
3664 
3665 	domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id);
3666 
3667 	if (!domain) {
3668 		resp->status = DLB2_ST_INVALID_DOMAIN_ID;
3669 		return -EINVAL;
3670 	}
3671 
3672 	if (!domain->configured) {
3673 		resp->status = DLB2_ST_DOMAIN_NOT_CONFIGURED;
3674 		return -EINVAL;
3675 	}
3676 
3677 	if (domain->started) {
3678 		resp->status = DLB2_ST_DOMAIN_STARTED;
3679 		return -EINVAL;
3680 	}
3681 
3682 	queue = DLB2_DOM_LIST_HEAD(domain->avail_ldb_queues, typeof(*queue));
3683 	if (!queue) {
3684 		resp->status = DLB2_ST_LDB_QUEUES_UNAVAILABLE;
3685 		return -EINVAL;
3686 	}
3687 
3688 	if (args->num_sequence_numbers) {
3689 		for (i = 0; i < DLB2_MAX_NUM_SEQUENCE_NUMBER_GROUPS; i++) {
3690 			struct dlb2_sn_group *group = &hw->rsrcs.sn_groups[i];
3691 
3692 			if (group->sequence_numbers_per_queue ==
3693 			    args->num_sequence_numbers &&
3694 			    !dlb2_sn_group_full(group))
3695 				break;
3696 		}
3697 
3698 		if (i == DLB2_MAX_NUM_SEQUENCE_NUMBER_GROUPS) {
3699 			resp->status = DLB2_ST_SEQUENCE_NUMBERS_UNAVAILABLE;
3700 			return -EINVAL;
3701 		}
3702 	}
3703 
3704 	if (args->num_qid_inflights > 4096) {
3705 		resp->status = DLB2_ST_INVALID_QID_INFLIGHT_ALLOCATION;
3706 		return -EINVAL;
3707 	}
3708 
3709 	/* Inflights must be <= number of sequence numbers if ordered */
3710 	if (args->num_sequence_numbers != 0 &&
3711 	    args->num_qid_inflights > args->num_sequence_numbers) {
3712 		resp->status = DLB2_ST_INVALID_QID_INFLIGHT_ALLOCATION;
3713 		return -EINVAL;
3714 	}
3715 
3716 	if (domain->num_avail_aqed_entries < args->num_atomic_inflights) {
3717 		resp->status = DLB2_ST_ATOMIC_INFLIGHTS_UNAVAILABLE;
3718 		return -EINVAL;
3719 	}
3720 
3721 	if (args->num_atomic_inflights &&
3722 	    args->lock_id_comp_level != 0 &&
3723 	    args->lock_id_comp_level != 64 &&
3724 	    args->lock_id_comp_level != 128 &&
3725 	    args->lock_id_comp_level != 256 &&
3726 	    args->lock_id_comp_level != 512 &&
3727 	    args->lock_id_comp_level != 1024 &&
3728 	    args->lock_id_comp_level != 2048 &&
3729 	    args->lock_id_comp_level != 4096 &&
3730 	    args->lock_id_comp_level != 65536) {
3731 		resp->status = DLB2_ST_INVALID_LOCK_ID_COMP_LEVEL;
3732 		return -EINVAL;
3733 	}
3734 
3735 	*out_domain = domain;
3736 	*out_queue = queue;
3737 
3738 	return 0;
3739 }
3740 
3741 static int
dlb2_ldb_queue_attach_resources(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_queue * queue,struct dlb2_create_ldb_queue_args * args)3742 dlb2_ldb_queue_attach_resources(struct dlb2_hw *hw,
3743 				struct dlb2_hw_domain *domain,
3744 				struct dlb2_ldb_queue *queue,
3745 				struct dlb2_create_ldb_queue_args *args)
3746 {
3747 	int ret;
3748 	ret = dlb2_ldb_queue_attach_to_sn_group(hw, queue, args);
3749 	if (ret)
3750 		return ret;
3751 
3752 	/* Attach QID inflights */
3753 	queue->num_qid_inflights = args->num_qid_inflights;
3754 
3755 	/* Attach atomic inflights */
3756 	queue->aqed_limit = args->num_atomic_inflights;
3757 
3758 	domain->num_avail_aqed_entries -= args->num_atomic_inflights;
3759 	domain->num_used_aqed_entries += args->num_atomic_inflights;
3760 
3761 	return 0;
3762 }
3763 
dlb2_configure_ldb_queue(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_queue * queue,struct dlb2_create_ldb_queue_args * args,bool vdev_req,unsigned int vdev_id)3764 static void dlb2_configure_ldb_queue(struct dlb2_hw *hw,
3765 				     struct dlb2_hw_domain *domain,
3766 				     struct dlb2_ldb_queue *queue,
3767 				     struct dlb2_create_ldb_queue_args *args,
3768 				     bool vdev_req,
3769 				     unsigned int vdev_id)
3770 {
3771 	struct dlb2_sn_group *sn_group;
3772 	unsigned int offs;
3773 	u32 reg = 0;
3774 	u32 alimit;
3775 
3776 	/* QID write permissions are turned on when the domain is started */
3777 	offs = domain->id.phys_id * DLB2_MAX_NUM_LDB_QUEUES + queue->id.phys_id;
3778 
3779 	DLB2_CSR_WR(hw, DLB2_SYS_LDB_VASQID_V(offs), reg);
3780 
3781 	/*
3782 	 * Unordered QIDs get 4K inflights, ordered get as many as the number
3783 	 * of sequence numbers.
3784 	 */
3785 	DLB2_BITS_SET(reg, args->num_qid_inflights,
3786 		      DLB2_LSP_QID_LDB_INFL_LIM_LIMIT);
3787 	DLB2_CSR_WR(hw, DLB2_LSP_QID_LDB_INFL_LIM(hw->ver,
3788 						  queue->id.phys_id), reg);
3789 
3790 	alimit = queue->aqed_limit;
3791 
3792 	if (alimit > DLB2_MAX_NUM_AQED_ENTRIES)
3793 		alimit = DLB2_MAX_NUM_AQED_ENTRIES;
3794 
3795 	reg = 0;
3796 	DLB2_BITS_SET(reg, alimit, DLB2_LSP_QID_AQED_ACTIVE_LIM_LIMIT);
3797 	DLB2_CSR_WR(hw,
3798 		    DLB2_LSP_QID_AQED_ACTIVE_LIM(hw->ver,
3799 						 queue->id.phys_id), reg);
3800 
3801 	reg = 0;
3802 	switch (args->lock_id_comp_level) {
3803 	case 64:
3804 		DLB2_BITS_SET(reg, 1, DLB2_AQED_QID_HID_WIDTH_COMPRESS_CODE);
3805 		break;
3806 	case 128:
3807 		DLB2_BITS_SET(reg, 2, DLB2_AQED_QID_HID_WIDTH_COMPRESS_CODE);
3808 		break;
3809 	case 256:
3810 		DLB2_BITS_SET(reg, 3, DLB2_AQED_QID_HID_WIDTH_COMPRESS_CODE);
3811 		break;
3812 	case 512:
3813 		DLB2_BITS_SET(reg, 4, DLB2_AQED_QID_HID_WIDTH_COMPRESS_CODE);
3814 		break;
3815 	case 1024:
3816 		DLB2_BITS_SET(reg, 5, DLB2_AQED_QID_HID_WIDTH_COMPRESS_CODE);
3817 		break;
3818 	case 2048:
3819 		DLB2_BITS_SET(reg, 6, DLB2_AQED_QID_HID_WIDTH_COMPRESS_CODE);
3820 		break;
3821 	case 4096:
3822 		DLB2_BITS_SET(reg, 7, DLB2_AQED_QID_HID_WIDTH_COMPRESS_CODE);
3823 		break;
3824 	default:
3825 		/* No compression by default */
3826 		break;
3827 	}
3828 
3829 	DLB2_CSR_WR(hw, DLB2_AQED_QID_HID_WIDTH(queue->id.phys_id), reg);
3830 
3831 	reg = 0;
3832 	/* Don't timestamp QEs that pass through this queue */
3833 	DLB2_CSR_WR(hw, DLB2_SYS_LDB_QID_ITS(queue->id.phys_id), reg);
3834 
3835 	DLB2_BITS_SET(reg, args->depth_threshold,
3836 		      DLB2_LSP_QID_ATM_DEPTH_THRSH_THRESH);
3837 	DLB2_CSR_WR(hw,
3838 		    DLB2_LSP_QID_ATM_DEPTH_THRSH(hw->ver,
3839 						 queue->id.phys_id), reg);
3840 
3841 	reg = 0;
3842 	DLB2_BITS_SET(reg, args->depth_threshold,
3843 		      DLB2_LSP_QID_NALDB_DEPTH_THRSH_THRESH);
3844 	DLB2_CSR_WR(hw,
3845 		    DLB2_LSP_QID_NALDB_DEPTH_THRSH(hw->ver, queue->id.phys_id),
3846 		    reg);
3847 
3848 	/*
3849 	 * This register limits the number of inflight flows a queue can have
3850 	 * at one time.  It has an upper bound of 2048, but can be
3851 	 * over-subscribed. 512 is chosen so that a single queue does not use
3852 	 * the entire atomic storage, but can use a substantial portion if
3853 	 * needed.
3854 	 */
3855 	reg = 0;
3856 	DLB2_BITS_SET(reg, 512, DLB2_AQED_QID_FID_LIM_QID_FID_LIMIT);
3857 	DLB2_CSR_WR(hw, DLB2_AQED_QID_FID_LIM(queue->id.phys_id), reg);
3858 
3859 	/* Configure SNs */
3860 	reg = 0;
3861 	sn_group = &hw->rsrcs.sn_groups[queue->sn_group];
3862 	DLB2_BITS_SET(reg, sn_group->mode, DLB2_CHP_ORD_QID_SN_MAP_MODE);
3863 	DLB2_BITS_SET(reg, queue->sn_slot, DLB2_CHP_ORD_QID_SN_MAP_SLOT);
3864 	DLB2_BITS_SET(reg, sn_group->id, DLB2_CHP_ORD_QID_SN_MAP_GRP);
3865 
3866 	DLB2_CSR_WR(hw,
3867 		    DLB2_CHP_ORD_QID_SN_MAP(hw->ver, queue->id.phys_id), reg);
3868 
3869 	reg = 0;
3870 	DLB2_BITS_SET(reg, (args->num_sequence_numbers != 0),
3871 		 DLB2_SYS_LDB_QID_CFG_V_SN_CFG_V);
3872 	DLB2_BITS_SET(reg, (args->num_atomic_inflights != 0),
3873 		 DLB2_SYS_LDB_QID_CFG_V_FID_CFG_V);
3874 
3875 	DLB2_CSR_WR(hw, DLB2_SYS_LDB_QID_CFG_V(queue->id.phys_id), reg);
3876 
3877 	if (vdev_req) {
3878 		offs = vdev_id * DLB2_MAX_NUM_LDB_QUEUES + queue->id.virt_id;
3879 
3880 		reg = 0;
3881 		DLB2_BIT_SET(reg, DLB2_SYS_VF_LDB_VQID_V_VQID_V);
3882 		DLB2_CSR_WR(hw, DLB2_SYS_VF_LDB_VQID_V(offs), reg);
3883 
3884 		reg = 0;
3885 		DLB2_BITS_SET(reg, queue->id.phys_id,
3886 			      DLB2_SYS_VF_LDB_VQID2QID_QID);
3887 		DLB2_CSR_WR(hw, DLB2_SYS_VF_LDB_VQID2QID(offs), reg);
3888 
3889 		reg = 0;
3890 		DLB2_BITS_SET(reg, queue->id.virt_id,
3891 			      DLB2_SYS_LDB_QID2VQID_VQID);
3892 		DLB2_CSR_WR(hw, DLB2_SYS_LDB_QID2VQID(queue->id.phys_id), reg);
3893 	}
3894 
3895 	reg = 0;
3896 	DLB2_BIT_SET(reg, DLB2_SYS_LDB_QID_V_QID_V);
3897 	DLB2_CSR_WR(hw, DLB2_SYS_LDB_QID_V(queue->id.phys_id), reg);
3898 }
3899 
3900 /**
3901  * dlb2_hw_create_ldb_queue() - create a load-balanced queue
3902  * @hw: dlb2_hw handle for a particular device.
3903  * @domain_id: domain ID.
3904  * @args: queue creation arguments.
3905  * @resp: response structure.
3906  * @vdev_req: indicates whether this request came from a vdev.
3907  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
3908  *
3909  * This function creates a load-balanced queue.
3910  *
3911  * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual
3912  * device.
3913  *
3914  * Return:
3915  * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
3916  * assigned a detailed error code from enum dlb2_error. If successful, resp->id
3917  * contains the queue ID.
3918  *
3919  * resp->id contains a virtual ID if vdev_req is true.
3920  *
3921  * Errors:
3922  * EINVAL - A requested resource is unavailable, the domain is not configured,
3923  *	    the domain has already been started, or the requested queue name is
3924  *	    already in use.
3925  * EFAULT - Internal error (resp->status not set).
3926  */
dlb2_hw_create_ldb_queue(struct dlb2_hw * hw,u32 domain_id,struct dlb2_create_ldb_queue_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id)3927 int dlb2_hw_create_ldb_queue(struct dlb2_hw *hw,
3928 			     u32 domain_id,
3929 			     struct dlb2_create_ldb_queue_args *args,
3930 			     struct dlb2_cmd_response *resp,
3931 			     bool vdev_req,
3932 			     unsigned int vdev_id)
3933 {
3934 	struct dlb2_hw_domain *domain;
3935 	struct dlb2_ldb_queue *queue;
3936 	int ret;
3937 
3938 	dlb2_log_create_ldb_queue_args(hw, domain_id, args, vdev_req, vdev_id);
3939 
3940 	/*
3941 	 * Verify that hardware resources are available before attempting to
3942 	 * satisfy the request. This simplifies the error unwinding code.
3943 	 */
3944 	ret = dlb2_verify_create_ldb_queue_args(hw,
3945 						domain_id,
3946 						args,
3947 						resp,
3948 						vdev_req,
3949 						vdev_id,
3950 						&domain,
3951 						&queue);
3952 	if (ret)
3953 		return ret;
3954 
3955 	ret = dlb2_ldb_queue_attach_resources(hw, domain, queue, args);
3956 
3957 	if (ret) {
3958 		DLB2_HW_ERR(hw,
3959 			    "[%s():%d] Internal error: failed to attach the ldb queue resources\n",
3960 			    __func__, __LINE__);
3961 		return ret;
3962 	}
3963 
3964 	dlb2_configure_ldb_queue(hw, domain, queue, args, vdev_req, vdev_id);
3965 
3966 	queue->num_mappings = 0;
3967 
3968 	queue->configured = true;
3969 
3970 	/*
3971 	 * Configuration succeeded, so move the resource from the 'avail' to
3972 	 * the 'used' list.
3973 	 */
3974 	dlb2_list_del(&domain->avail_ldb_queues, &queue->domain_list);
3975 
3976 	dlb2_list_add(&domain->used_ldb_queues, &queue->domain_list);
3977 
3978 	resp->status = 0;
3979 	resp->id = (vdev_req) ? queue->id.virt_id : queue->id.phys_id;
3980 
3981 	return 0;
3982 }
3983 
dlb2_ldb_port_configure_pp(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_port * port,bool vdev_req,unsigned int vdev_id)3984 static void dlb2_ldb_port_configure_pp(struct dlb2_hw *hw,
3985 				       struct dlb2_hw_domain *domain,
3986 				       struct dlb2_ldb_port *port,
3987 				       bool vdev_req,
3988 				       unsigned int vdev_id)
3989 {
3990 	u32 reg = 0;
3991 
3992 	DLB2_BITS_SET(reg, domain->id.phys_id, DLB2_SYS_LDB_PP2VAS_VAS);
3993 	DLB2_CSR_WR(hw, DLB2_SYS_LDB_PP2VAS(port->id.phys_id), reg);
3994 
3995 	if (vdev_req) {
3996 		unsigned int offs;
3997 		u32 virt_id;
3998 
3999 		/*
4000 		 * DLB uses producer port address bits 17:12 to determine the
4001 		 * producer port ID. In Scalable IOV mode, PP accesses come
4002 		 * through the PF MMIO window for the physical producer port,
4003 		 * so for translation purposes the virtual and physical port
4004 		 * IDs are equal.
4005 		 */
4006 		if (hw->virt_mode == DLB2_VIRT_SRIOV)
4007 			virt_id = port->id.virt_id;
4008 		else
4009 			virt_id = port->id.phys_id;
4010 
4011 		reg = 0;
4012 		DLB2_BITS_SET(reg, port->id.phys_id, DLB2_SYS_VF_LDB_VPP2PP_PP);
4013 		offs = vdev_id * DLB2_MAX_NUM_LDB_PORTS + virt_id;
4014 		DLB2_CSR_WR(hw, DLB2_SYS_VF_LDB_VPP2PP(offs), reg);
4015 
4016 		reg = 0;
4017 		DLB2_BITS_SET(reg, vdev_id, DLB2_SYS_LDB_PP2VDEV_VDEV);
4018 		DLB2_CSR_WR(hw, DLB2_SYS_LDB_PP2VDEV(port->id.phys_id), reg);
4019 
4020 		reg = 0;
4021 		DLB2_BIT_SET(reg, DLB2_SYS_VF_LDB_VPP_V_VPP_V);
4022 		DLB2_CSR_WR(hw, DLB2_SYS_VF_LDB_VPP_V(offs), reg);
4023 	}
4024 
4025 	reg = 0;
4026 	DLB2_BIT_SET(reg, DLB2_SYS_LDB_PP_V_PP_V);
4027 	DLB2_CSR_WR(hw, DLB2_SYS_LDB_PP_V(port->id.phys_id), reg);
4028 }
4029 
dlb2_ldb_port_configure_cq(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_port * port,uintptr_t cq_dma_base,struct dlb2_create_ldb_port_args * args,bool vdev_req,unsigned int vdev_id)4030 static int dlb2_ldb_port_configure_cq(struct dlb2_hw *hw,
4031 				      struct dlb2_hw_domain *domain,
4032 				      struct dlb2_ldb_port *port,
4033 				      uintptr_t cq_dma_base,
4034 				      struct dlb2_create_ldb_port_args *args,
4035 				      bool vdev_req,
4036 				      unsigned int vdev_id)
4037 {
4038 	u32 hl_base = 0;
4039 	u32 reg = 0;
4040 	u32 ds = 0;
4041 
4042 	/* The CQ address is 64B-aligned, and the DLB only wants bits [63:6] */
4043 	DLB2_BITS_SET(reg, cq_dma_base >> 6, DLB2_SYS_LDB_CQ_ADDR_L_ADDR_L);
4044 	DLB2_CSR_WR(hw, DLB2_SYS_LDB_CQ_ADDR_L(port->id.phys_id), reg);
4045 
4046 	reg = cq_dma_base >> 32;
4047 	DLB2_CSR_WR(hw, DLB2_SYS_LDB_CQ_ADDR_U(port->id.phys_id), reg);
4048 
4049 	/*
4050 	 * 'ro' == relaxed ordering. This setting allows DLB2 to write
4051 	 * cache lines out-of-order (but QEs within a cache line are always
4052 	 * updated in-order).
4053 	 */
4054 	reg = 0;
4055 	DLB2_BITS_SET(reg, vdev_id, DLB2_SYS_LDB_CQ2VF_PF_RO_VF);
4056 	DLB2_BITS_SET(reg,
4057 		 !vdev_req && (hw->virt_mode != DLB2_VIRT_SIOV),
4058 		 DLB2_SYS_LDB_CQ2VF_PF_RO_IS_PF);
4059 	DLB2_BIT_SET(reg, DLB2_SYS_LDB_CQ2VF_PF_RO_RO);
4060 
4061 	DLB2_CSR_WR(hw, DLB2_SYS_LDB_CQ2VF_PF_RO(port->id.phys_id), reg);
4062 
4063 	port->cq_depth = args->cq_depth;
4064 
4065 	if (args->cq_depth <= 8) {
4066 		ds = 1;
4067 	} else if (args->cq_depth == 16) {
4068 		ds = 2;
4069 	} else if (args->cq_depth == 32) {
4070 		ds = 3;
4071 	} else if (args->cq_depth == 64) {
4072 		ds = 4;
4073 	} else if (args->cq_depth == 128) {
4074 		ds = 5;
4075 	} else if (args->cq_depth == 256) {
4076 		ds = 6;
4077 	} else if (args->cq_depth == 512) {
4078 		ds = 7;
4079 	} else if (args->cq_depth == 1024) {
4080 		ds = 8;
4081 	} else {
4082 		DLB2_HW_ERR(hw,
4083 			    "[%s():%d] Internal error: invalid CQ depth\n",
4084 			    __func__, __LINE__);
4085 		return -EFAULT;
4086 	}
4087 
4088 	reg = 0;
4089 	DLB2_BITS_SET(reg, ds,
4090 		      DLB2_CHP_LDB_CQ_TKN_DEPTH_SEL_TOKEN_DEPTH_SELECT);
4091 	DLB2_CSR_WR(hw,
4092 		    DLB2_CHP_LDB_CQ_TKN_DEPTH_SEL(hw->ver, port->id.phys_id),
4093 		    reg);
4094 
4095 	/*
4096 	 * To support CQs with depth less than 8, program the token count
4097 	 * register with a non-zero initial value. Operations such as domain
4098 	 * reset must take this initial value into account when quiescing the
4099 	 * CQ.
4100 	 */
4101 	port->init_tkn_cnt = 0;
4102 
4103 	if (args->cq_depth < 8) {
4104 		reg = 0;
4105 		port->init_tkn_cnt = 8 - args->cq_depth;
4106 
4107 		DLB2_BITS_SET(reg,
4108 			      port->init_tkn_cnt,
4109 			      DLB2_LSP_CQ_LDB_TKN_CNT_TOKEN_COUNT);
4110 		DLB2_CSR_WR(hw,
4111 			    DLB2_LSP_CQ_LDB_TKN_CNT(hw->ver, port->id.phys_id),
4112 			    reg);
4113 	} else {
4114 		DLB2_CSR_WR(hw,
4115 			    DLB2_LSP_CQ_LDB_TKN_CNT(hw->ver, port->id.phys_id),
4116 			    DLB2_LSP_CQ_LDB_TKN_CNT_RST);
4117 	}
4118 
4119 	reg = 0;
4120 	DLB2_BITS_SET(reg, ds,
4121 		      DLB2_LSP_CQ_LDB_TKN_DEPTH_SEL_TOKEN_DEPTH_SELECT_V2);
4122 	DLB2_CSR_WR(hw,
4123 		    DLB2_LSP_CQ_LDB_TKN_DEPTH_SEL(hw->ver, port->id.phys_id),
4124 		    reg);
4125 
4126 	/* Reset the CQ write pointer */
4127 	DLB2_CSR_WR(hw,
4128 		    DLB2_CHP_LDB_CQ_WPTR(hw->ver, port->id.phys_id),
4129 		    DLB2_CHP_LDB_CQ_WPTR_RST);
4130 
4131 	reg = 0;
4132 	DLB2_BITS_SET(reg,
4133 		      port->hist_list_entry_limit - 1,
4134 		      DLB2_CHP_HIST_LIST_LIM_LIMIT);
4135 	DLB2_CSR_WR(hw, DLB2_CHP_HIST_LIST_LIM(hw->ver, port->id.phys_id), reg);
4136 
4137 	DLB2_BITS_SET(hl_base, port->hist_list_entry_base,
4138 		      DLB2_CHP_HIST_LIST_BASE_BASE);
4139 	DLB2_CSR_WR(hw,
4140 		    DLB2_CHP_HIST_LIST_BASE(hw->ver, port->id.phys_id),
4141 		    hl_base);
4142 
4143 	/*
4144 	 * The inflight limit sets a cap on the number of QEs for which this CQ
4145 	 * can owe completions at one time.
4146 	 */
4147 	reg = 0;
4148 	DLB2_BITS_SET(reg, args->cq_history_list_size,
4149 		      DLB2_LSP_CQ_LDB_INFL_LIM_LIMIT);
4150 	DLB2_CSR_WR(hw, DLB2_LSP_CQ_LDB_INFL_LIM(hw->ver, port->id.phys_id),
4151 		    reg);
4152 
4153 	reg = 0;
4154 	DLB2_BITS_SET(reg, DLB2_BITS_GET(hl_base, DLB2_CHP_HIST_LIST_BASE_BASE),
4155 		      DLB2_CHP_HIST_LIST_PUSH_PTR_PUSH_PTR);
4156 	DLB2_CSR_WR(hw, DLB2_CHP_HIST_LIST_PUSH_PTR(hw->ver, port->id.phys_id),
4157 		    reg);
4158 
4159 	reg = 0;
4160 	DLB2_BITS_SET(reg, DLB2_BITS_GET(hl_base, DLB2_CHP_HIST_LIST_BASE_BASE),
4161 		      DLB2_CHP_HIST_LIST_POP_PTR_POP_PTR);
4162 	DLB2_CSR_WR(hw, DLB2_CHP_HIST_LIST_POP_PTR(hw->ver, port->id.phys_id),
4163 		    reg);
4164 
4165 	/*
4166 	 * Address translation (AT) settings: 0: untranslated, 2: translated
4167 	 * (see ATS spec regarding Address Type field for more details)
4168 	 */
4169 
4170 	if (hw->ver == DLB2_HW_V2) {
4171 		reg = 0;
4172 		DLB2_CSR_WR(hw, DLB2_SYS_LDB_CQ_AT(port->id.phys_id), reg);
4173 	}
4174 
4175 	if (vdev_req && hw->virt_mode == DLB2_VIRT_SIOV) {
4176 		reg = 0;
4177 		DLB2_BITS_SET(reg, hw->pasid[vdev_id],
4178 			      DLB2_SYS_LDB_CQ_PASID_PASID);
4179 		DLB2_BIT_SET(reg, DLB2_SYS_LDB_CQ_PASID_FMT2);
4180 	}
4181 
4182 	DLB2_CSR_WR(hw, DLB2_SYS_LDB_CQ_PASID(hw->ver, port->id.phys_id), reg);
4183 
4184 	reg = 0;
4185 	DLB2_BITS_SET(reg, domain->id.phys_id, DLB2_CHP_LDB_CQ2VAS_CQ2VAS);
4186 	DLB2_CSR_WR(hw, DLB2_CHP_LDB_CQ2VAS(hw->ver, port->id.phys_id), reg);
4187 
4188 	/* Disable the port's QID mappings */
4189 	reg = 0;
4190 	DLB2_CSR_WR(hw, DLB2_LSP_CQ2PRIOV(hw->ver, port->id.phys_id), reg);
4191 
4192 	return 0;
4193 }
4194 
4195 static bool
dlb2_cq_depth_is_valid(u32 depth)4196 dlb2_cq_depth_is_valid(u32 depth)
4197 {
4198 	if (depth != 1 && depth != 2 &&
4199 	    depth != 4 && depth != 8 &&
4200 	    depth != 16 && depth != 32 &&
4201 	    depth != 64 && depth != 128 &&
4202 	    depth != 256 && depth != 512 &&
4203 	    depth != 1024)
4204 		return false;
4205 
4206 	return true;
4207 }
4208 
dlb2_configure_ldb_port(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_ldb_port * port,uintptr_t cq_dma_base,struct dlb2_create_ldb_port_args * args,bool vdev_req,unsigned int vdev_id)4209 static int dlb2_configure_ldb_port(struct dlb2_hw *hw,
4210 				   struct dlb2_hw_domain *domain,
4211 				   struct dlb2_ldb_port *port,
4212 				   uintptr_t cq_dma_base,
4213 				   struct dlb2_create_ldb_port_args *args,
4214 				   bool vdev_req,
4215 				   unsigned int vdev_id)
4216 {
4217 	int ret, i;
4218 
4219 	port->hist_list_entry_base = domain->hist_list_entry_base +
4220 				     domain->hist_list_entry_offset;
4221 	port->hist_list_entry_limit = port->hist_list_entry_base +
4222 				      args->cq_history_list_size;
4223 
4224 	domain->hist_list_entry_offset += args->cq_history_list_size;
4225 	domain->avail_hist_list_entries -= args->cq_history_list_size;
4226 
4227 	ret = dlb2_ldb_port_configure_cq(hw,
4228 					 domain,
4229 					 port,
4230 					 cq_dma_base,
4231 					 args,
4232 					 vdev_req,
4233 					 vdev_id);
4234 	if (ret)
4235 		return ret;
4236 
4237 	dlb2_ldb_port_configure_pp(hw,
4238 				   domain,
4239 				   port,
4240 				   vdev_req,
4241 				   vdev_id);
4242 
4243 	dlb2_ldb_port_cq_enable(hw, port);
4244 
4245 	for (i = 0; i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; i++)
4246 		port->qid_map[i].state = DLB2_QUEUE_UNMAPPED;
4247 	port->num_mappings = 0;
4248 
4249 	port->enabled = true;
4250 
4251 	port->configured = true;
4252 
4253 	return 0;
4254 }
4255 
4256 static void
dlb2_log_create_ldb_port_args(struct dlb2_hw * hw,u32 domain_id,uintptr_t cq_dma_base,struct dlb2_create_ldb_port_args * args,bool vdev_req,unsigned int vdev_id)4257 dlb2_log_create_ldb_port_args(struct dlb2_hw *hw,
4258 			      u32 domain_id,
4259 			      uintptr_t cq_dma_base,
4260 			      struct dlb2_create_ldb_port_args *args,
4261 			      bool vdev_req,
4262 			      unsigned int vdev_id)
4263 {
4264 	DLB2_HW_DBG(hw, "DLB2 create load-balanced port arguments:\n");
4265 	if (vdev_req)
4266 		DLB2_HW_DBG(hw, "(Request from vdev %d)\n", vdev_id);
4267 	DLB2_HW_DBG(hw, "\tDomain ID:                 %d\n",
4268 		    domain_id);
4269 	DLB2_HW_DBG(hw, "\tCQ depth:                  %d\n",
4270 		    args->cq_depth);
4271 	DLB2_HW_DBG(hw, "\tCQ hist list size:         %d\n",
4272 		    args->cq_history_list_size);
4273 	DLB2_HW_DBG(hw, "\tCQ base address:           0x%lx\n",
4274 		    cq_dma_base);
4275 	DLB2_HW_DBG(hw, "\tCoS ID:                    %u\n", args->cos_id);
4276 	DLB2_HW_DBG(hw, "\tStrict CoS allocation:     %u\n",
4277 		    args->cos_strict);
4278 }
4279 
4280 static int
dlb2_verify_create_ldb_port_args(struct dlb2_hw * hw,u32 domain_id,uintptr_t cq_dma_base,struct dlb2_create_ldb_port_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id,struct dlb2_hw_domain ** out_domain,struct dlb2_ldb_port ** out_port,int * out_cos_id)4281 dlb2_verify_create_ldb_port_args(struct dlb2_hw *hw,
4282 				 u32 domain_id,
4283 				 uintptr_t cq_dma_base,
4284 				 struct dlb2_create_ldb_port_args *args,
4285 				 struct dlb2_cmd_response *resp,
4286 				 bool vdev_req,
4287 				 unsigned int vdev_id,
4288 				 struct dlb2_hw_domain **out_domain,
4289 				 struct dlb2_ldb_port **out_port,
4290 				 int *out_cos_id)
4291 {
4292 	struct dlb2_hw_domain *domain;
4293 	struct dlb2_ldb_port *port;
4294 	int i, id;
4295 
4296 	domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id);
4297 
4298 	if (!domain) {
4299 		resp->status = DLB2_ST_INVALID_DOMAIN_ID;
4300 		return -EINVAL;
4301 	}
4302 
4303 	if (!domain->configured) {
4304 		resp->status = DLB2_ST_DOMAIN_NOT_CONFIGURED;
4305 		return -EINVAL;
4306 	}
4307 
4308 	if (domain->started) {
4309 		resp->status = DLB2_ST_DOMAIN_STARTED;
4310 		return -EINVAL;
4311 	}
4312 
4313 	if (args->cos_id >= DLB2_NUM_COS_DOMAINS) {
4314 		resp->status = DLB2_ST_INVALID_COS_ID;
4315 		return -EINVAL;
4316 	}
4317 
4318 	if (args->cos_strict) {
4319 		id = args->cos_id;
4320 		port = DLB2_DOM_LIST_HEAD(domain->avail_ldb_ports[id],
4321 					  typeof(*port));
4322 	} else {
4323 		for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
4324 			id = (args->cos_id + i) % DLB2_NUM_COS_DOMAINS;
4325 
4326 			port = DLB2_DOM_LIST_HEAD(domain->avail_ldb_ports[id],
4327 						  typeof(*port));
4328 			if (port)
4329 				break;
4330 		}
4331 	}
4332 
4333 	if (!port) {
4334 		resp->status = DLB2_ST_LDB_PORTS_UNAVAILABLE;
4335 		return -EINVAL;
4336 	}
4337 
4338 	/* Check cache-line alignment */
4339 	if ((cq_dma_base & 0x3F) != 0) {
4340 		resp->status = DLB2_ST_INVALID_CQ_VIRT_ADDR;
4341 		return -EINVAL;
4342 	}
4343 
4344 	if (!dlb2_cq_depth_is_valid(args->cq_depth)) {
4345 		resp->status = DLB2_ST_INVALID_CQ_DEPTH;
4346 		return -EINVAL;
4347 	}
4348 
4349 	/* The history list size must be >= 1 */
4350 	if (!args->cq_history_list_size) {
4351 		resp->status = DLB2_ST_INVALID_HIST_LIST_DEPTH;
4352 		return -EINVAL;
4353 	}
4354 
4355 	if (args->cq_history_list_size > domain->avail_hist_list_entries) {
4356 		resp->status = DLB2_ST_HIST_LIST_ENTRIES_UNAVAILABLE;
4357 		return -EINVAL;
4358 	}
4359 
4360 	*out_domain = domain;
4361 	*out_port = port;
4362 	*out_cos_id = id;
4363 
4364 	return 0;
4365 }
4366 
4367 /**
4368  * dlb2_hw_create_ldb_port() - create a load-balanced port
4369  * @hw: dlb2_hw handle for a particular device.
4370  * @domain_id: domain ID.
4371  * @args: port creation arguments.
4372  * @cq_dma_base: base address of the CQ memory. This can be a PA or an IOVA.
4373  * @resp: response structure.
4374  * @vdev_req: indicates whether this request came from a vdev.
4375  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
4376  *
4377  * This function creates a load-balanced port.
4378  *
4379  * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual
4380  * device.
4381  *
4382  * Return:
4383  * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
4384  * assigned a detailed error code from enum dlb2_error. If successful, resp->id
4385  * contains the port ID.
4386  *
4387  * resp->id contains a virtual ID if vdev_req is true.
4388  *
4389  * Errors:
4390  * EINVAL - A requested resource is unavailable, a credit setting is invalid, a
4391  *	    pointer address is not properly aligned, the domain is not
4392  *	    configured, or the domain has already been started.
4393  * EFAULT - Internal error (resp->status not set).
4394  */
dlb2_hw_create_ldb_port(struct dlb2_hw * hw,u32 domain_id,struct dlb2_create_ldb_port_args * args,uintptr_t cq_dma_base,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id)4395 int dlb2_hw_create_ldb_port(struct dlb2_hw *hw,
4396 			    u32 domain_id,
4397 			    struct dlb2_create_ldb_port_args *args,
4398 			    uintptr_t cq_dma_base,
4399 			    struct dlb2_cmd_response *resp,
4400 			    bool vdev_req,
4401 			    unsigned int vdev_id)
4402 {
4403 	struct dlb2_hw_domain *domain;
4404 	struct dlb2_ldb_port *port;
4405 	int ret, cos_id;
4406 
4407 	dlb2_log_create_ldb_port_args(hw,
4408 				      domain_id,
4409 				      cq_dma_base,
4410 				      args,
4411 				      vdev_req,
4412 				      vdev_id);
4413 
4414 	/*
4415 	 * Verify that hardware resources are available before attempting to
4416 	 * satisfy the request. This simplifies the error unwinding code.
4417 	 */
4418 	ret = dlb2_verify_create_ldb_port_args(hw,
4419 					       domain_id,
4420 					       cq_dma_base,
4421 					       args,
4422 					       resp,
4423 					       vdev_req,
4424 					       vdev_id,
4425 					       &domain,
4426 					       &port,
4427 					       &cos_id);
4428 	if (ret)
4429 		return ret;
4430 
4431 	ret = dlb2_configure_ldb_port(hw,
4432 				      domain,
4433 				      port,
4434 				      cq_dma_base,
4435 				      args,
4436 				      vdev_req,
4437 				      vdev_id);
4438 	if (ret)
4439 		return ret;
4440 
4441 	/*
4442 	 * Configuration succeeded, so move the resource from the 'avail' to
4443 	 * the 'used' list.
4444 	 */
4445 	dlb2_list_del(&domain->avail_ldb_ports[cos_id], &port->domain_list);
4446 
4447 	dlb2_list_add(&domain->used_ldb_ports[cos_id], &port->domain_list);
4448 
4449 	resp->status = 0;
4450 	resp->id = (vdev_req) ? port->id.virt_id : port->id.phys_id;
4451 
4452 	return 0;
4453 }
4454 
4455 static void
dlb2_log_create_dir_port_args(struct dlb2_hw * hw,u32 domain_id,uintptr_t cq_dma_base,struct dlb2_create_dir_port_args * args,bool vdev_req,unsigned int vdev_id)4456 dlb2_log_create_dir_port_args(struct dlb2_hw *hw,
4457 			      u32 domain_id,
4458 			      uintptr_t cq_dma_base,
4459 			      struct dlb2_create_dir_port_args *args,
4460 			      bool vdev_req,
4461 			      unsigned int vdev_id)
4462 {
4463 	DLB2_HW_DBG(hw, "DLB2 create directed port arguments:\n");
4464 	if (vdev_req)
4465 		DLB2_HW_DBG(hw, "(Request from vdev %d)\n", vdev_id);
4466 	DLB2_HW_DBG(hw, "\tDomain ID:                 %d\n",
4467 		    domain_id);
4468 	DLB2_HW_DBG(hw, "\tCQ depth:                  %d\n",
4469 		    args->cq_depth);
4470 	DLB2_HW_DBG(hw, "\tCQ base address:           0x%lx\n",
4471 		    cq_dma_base);
4472 }
4473 
4474 static struct dlb2_dir_pq_pair *
dlb2_get_domain_used_dir_pq(struct dlb2_hw * hw,u32 id,bool vdev_req,struct dlb2_hw_domain * domain)4475 dlb2_get_domain_used_dir_pq(struct dlb2_hw *hw,
4476 			    u32 id,
4477 			    bool vdev_req,
4478 			    struct dlb2_hw_domain *domain)
4479 {
4480 	struct dlb2_list_entry *iter;
4481 	struct dlb2_dir_pq_pair *port;
4482 	RTE_SET_USED(iter);
4483 
4484 	if (id >= DLB2_MAX_NUM_DIR_PORTS(hw->ver))
4485 		return NULL;
4486 
4487 	DLB2_DOM_LIST_FOR(domain->used_dir_pq_pairs, port, iter) {
4488 		if ((!vdev_req && port->id.phys_id == id) ||
4489 		    (vdev_req && port->id.virt_id == id))
4490 			return port;
4491 	}
4492 
4493 	return NULL;
4494 }
4495 
4496 static int
dlb2_verify_create_dir_port_args(struct dlb2_hw * hw,u32 domain_id,uintptr_t cq_dma_base,struct dlb2_create_dir_port_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id,struct dlb2_hw_domain ** out_domain,struct dlb2_dir_pq_pair ** out_port)4497 dlb2_verify_create_dir_port_args(struct dlb2_hw *hw,
4498 				 u32 domain_id,
4499 				 uintptr_t cq_dma_base,
4500 				 struct dlb2_create_dir_port_args *args,
4501 				 struct dlb2_cmd_response *resp,
4502 				 bool vdev_req,
4503 				 unsigned int vdev_id,
4504 				 struct dlb2_hw_domain **out_domain,
4505 				 struct dlb2_dir_pq_pair **out_port)
4506 {
4507 	struct dlb2_hw_domain *domain;
4508 	struct dlb2_dir_pq_pair *pq;
4509 
4510 	domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id);
4511 
4512 	if (!domain) {
4513 		resp->status = DLB2_ST_INVALID_DOMAIN_ID;
4514 		return -EINVAL;
4515 	}
4516 
4517 	if (!domain->configured) {
4518 		resp->status = DLB2_ST_DOMAIN_NOT_CONFIGURED;
4519 		return -EINVAL;
4520 	}
4521 
4522 	if (domain->started) {
4523 		resp->status = DLB2_ST_DOMAIN_STARTED;
4524 		return -EINVAL;
4525 	}
4526 
4527 	if (args->queue_id != -1) {
4528 		/*
4529 		 * If the user claims the queue is already configured, validate
4530 		 * the queue ID, its domain, and whether the queue is
4531 		 * configured.
4532 		 */
4533 		pq = dlb2_get_domain_used_dir_pq(hw,
4534 						 args->queue_id,
4535 						 vdev_req,
4536 						 domain);
4537 
4538 		if (!pq || pq->domain_id.phys_id != domain->id.phys_id ||
4539 		    !pq->queue_configured) {
4540 			resp->status = DLB2_ST_INVALID_DIR_QUEUE_ID;
4541 			return -EINVAL;
4542 		}
4543 	} else {
4544 		/*
4545 		 * If the port's queue is not configured, validate that a free
4546 		 * port-queue pair is available.
4547 		 */
4548 		pq = DLB2_DOM_LIST_HEAD(domain->avail_dir_pq_pairs,
4549 					typeof(*pq));
4550 		if (!pq) {
4551 			resp->status = DLB2_ST_DIR_PORTS_UNAVAILABLE;
4552 			return -EINVAL;
4553 		}
4554 	}
4555 
4556 	/* Check cache-line alignment */
4557 	if ((cq_dma_base & 0x3F) != 0) {
4558 		resp->status = DLB2_ST_INVALID_CQ_VIRT_ADDR;
4559 		return -EINVAL;
4560 	}
4561 
4562 	if (!dlb2_cq_depth_is_valid(args->cq_depth)) {
4563 		resp->status = DLB2_ST_INVALID_CQ_DEPTH;
4564 		return -EINVAL;
4565 	}
4566 
4567 	*out_domain = domain;
4568 	*out_port = pq;
4569 
4570 	return 0;
4571 }
4572 
dlb2_dir_port_configure_pp(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_dir_pq_pair * port,bool vdev_req,unsigned int vdev_id)4573 static void dlb2_dir_port_configure_pp(struct dlb2_hw *hw,
4574 				       struct dlb2_hw_domain *domain,
4575 				       struct dlb2_dir_pq_pair *port,
4576 				       bool vdev_req,
4577 				       unsigned int vdev_id)
4578 {
4579 	u32 reg = 0;
4580 
4581 	DLB2_BITS_SET(reg, domain->id.phys_id, DLB2_SYS_DIR_PP2VAS_VAS);
4582 	DLB2_CSR_WR(hw, DLB2_SYS_DIR_PP2VAS(port->id.phys_id), reg);
4583 
4584 	if (vdev_req) {
4585 		unsigned int offs;
4586 		u32 virt_id;
4587 
4588 		/*
4589 		 * DLB uses producer port address bits 17:12 to determine the
4590 		 * producer port ID. In Scalable IOV mode, PP accesses come
4591 		 * through the PF MMIO window for the physical producer port,
4592 		 * so for translation purposes the virtual and physical port
4593 		 * IDs are equal.
4594 		 */
4595 		if (hw->virt_mode == DLB2_VIRT_SRIOV)
4596 			virt_id = port->id.virt_id;
4597 		else
4598 			virt_id = port->id.phys_id;
4599 
4600 		reg = 0;
4601 		DLB2_BITS_SET(reg, port->id.phys_id, DLB2_SYS_VF_DIR_VPP2PP_PP);
4602 		offs = vdev_id * DLB2_MAX_NUM_DIR_PORTS(hw->ver) + virt_id;
4603 		DLB2_CSR_WR(hw, DLB2_SYS_VF_DIR_VPP2PP(offs), reg);
4604 
4605 		reg = 0;
4606 		DLB2_BITS_SET(reg, vdev_id, DLB2_SYS_DIR_PP2VDEV_VDEV);
4607 		DLB2_CSR_WR(hw, DLB2_SYS_DIR_PP2VDEV(port->id.phys_id), reg);
4608 
4609 		reg = 0;
4610 		DLB2_BIT_SET(reg, DLB2_SYS_VF_DIR_VPP_V_VPP_V);
4611 		DLB2_CSR_WR(hw, DLB2_SYS_VF_DIR_VPP_V(offs), reg);
4612 	}
4613 
4614 	reg = 0;
4615 	DLB2_BIT_SET(reg, DLB2_SYS_DIR_PP_V_PP_V);
4616 	DLB2_CSR_WR(hw, DLB2_SYS_DIR_PP_V(port->id.phys_id), reg);
4617 }
4618 
dlb2_dir_port_configure_cq(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_dir_pq_pair * port,uintptr_t cq_dma_base,struct dlb2_create_dir_port_args * args,bool vdev_req,unsigned int vdev_id)4619 static int dlb2_dir_port_configure_cq(struct dlb2_hw *hw,
4620 				      struct dlb2_hw_domain *domain,
4621 				      struct dlb2_dir_pq_pair *port,
4622 				      uintptr_t cq_dma_base,
4623 				      struct dlb2_create_dir_port_args *args,
4624 				      bool vdev_req,
4625 				      unsigned int vdev_id)
4626 {
4627 	u32 reg = 0;
4628 	u32 ds = 0;
4629 
4630 	/* The CQ address is 64B-aligned, and the DLB only wants bits [63:6] */
4631 	DLB2_BITS_SET(reg, cq_dma_base >> 6, DLB2_SYS_DIR_CQ_ADDR_L_ADDR_L);
4632 	DLB2_CSR_WR(hw, DLB2_SYS_DIR_CQ_ADDR_L(port->id.phys_id), reg);
4633 
4634 	reg = cq_dma_base >> 32;
4635 	DLB2_CSR_WR(hw, DLB2_SYS_DIR_CQ_ADDR_U(port->id.phys_id), reg);
4636 
4637 	/*
4638 	 * 'ro' == relaxed ordering. This setting allows DLB2 to write
4639 	 * cache lines out-of-order (but QEs within a cache line are always
4640 	 * updated in-order).
4641 	 */
4642 	reg = 0;
4643 	DLB2_BITS_SET(reg, vdev_id, DLB2_SYS_DIR_CQ2VF_PF_RO_VF);
4644 	DLB2_BITS_SET(reg, !vdev_req && (hw->virt_mode != DLB2_VIRT_SIOV),
4645 		 DLB2_SYS_DIR_CQ2VF_PF_RO_IS_PF);
4646 	DLB2_BIT_SET(reg, DLB2_SYS_DIR_CQ2VF_PF_RO_RO);
4647 
4648 	DLB2_CSR_WR(hw, DLB2_SYS_DIR_CQ2VF_PF_RO(port->id.phys_id), reg);
4649 
4650 	if (args->cq_depth <= 8) {
4651 		ds = 1;
4652 	} else if (args->cq_depth == 16) {
4653 		ds = 2;
4654 	} else if (args->cq_depth == 32) {
4655 		ds = 3;
4656 	} else if (args->cq_depth == 64) {
4657 		ds = 4;
4658 	} else if (args->cq_depth == 128) {
4659 		ds = 5;
4660 	} else if (args->cq_depth == 256) {
4661 		ds = 6;
4662 	} else if (args->cq_depth == 512) {
4663 		ds = 7;
4664 	} else if (args->cq_depth == 1024) {
4665 		ds = 8;
4666 	} else {
4667 		DLB2_HW_ERR(hw,
4668 			    "[%s():%d] Internal error: invalid CQ depth\n",
4669 			    __func__, __LINE__);
4670 		return -EFAULT;
4671 	}
4672 
4673 	reg = 0;
4674 	DLB2_BITS_SET(reg, ds,
4675 		      DLB2_CHP_DIR_CQ_TKN_DEPTH_SEL_TOKEN_DEPTH_SELECT);
4676 	DLB2_CSR_WR(hw,
4677 		    DLB2_CHP_DIR_CQ_TKN_DEPTH_SEL(hw->ver, port->id.phys_id),
4678 		    reg);
4679 
4680 	/*
4681 	 * To support CQs with depth less than 8, program the token count
4682 	 * register with a non-zero initial value. Operations such as domain
4683 	 * reset must take this initial value into account when quiescing the
4684 	 * CQ.
4685 	 */
4686 	port->init_tkn_cnt = 0;
4687 
4688 	if (args->cq_depth < 8) {
4689 		reg = 0;
4690 		port->init_tkn_cnt = 8 - args->cq_depth;
4691 
4692 		DLB2_BITS_SET(reg, port->init_tkn_cnt,
4693 			      DLB2_LSP_CQ_DIR_TKN_CNT_COUNT);
4694 		DLB2_CSR_WR(hw,
4695 			    DLB2_LSP_CQ_DIR_TKN_CNT(hw->ver, port->id.phys_id),
4696 			    reg);
4697 	} else {
4698 		DLB2_CSR_WR(hw,
4699 			    DLB2_LSP_CQ_DIR_TKN_CNT(hw->ver, port->id.phys_id),
4700 			    DLB2_LSP_CQ_DIR_TKN_CNT_RST);
4701 	}
4702 
4703 	reg = 0;
4704 	DLB2_BITS_SET(reg, ds,
4705 		      DLB2_LSP_CQ_DIR_TKN_DEPTH_SEL_DSI_TOKEN_DEPTH_SELECT_V2);
4706 	DLB2_CSR_WR(hw,
4707 		    DLB2_LSP_CQ_DIR_TKN_DEPTH_SEL_DSI(hw->ver,
4708 						      port->id.phys_id),
4709 		    reg);
4710 
4711 	/* Reset the CQ write pointer */
4712 	DLB2_CSR_WR(hw,
4713 		    DLB2_CHP_DIR_CQ_WPTR(hw->ver, port->id.phys_id),
4714 		    DLB2_CHP_DIR_CQ_WPTR_RST);
4715 
4716 	/* Virtualize the PPID */
4717 	reg = 0;
4718 	DLB2_CSR_WR(hw, DLB2_SYS_DIR_CQ_FMT(port->id.phys_id), reg);
4719 
4720 	/*
4721 	 * Address translation (AT) settings: 0: untranslated, 2: translated
4722 	 * (see ATS spec regarding Address Type field for more details)
4723 	 */
4724 	if (hw->ver == DLB2_HW_V2) {
4725 		reg = 0;
4726 		DLB2_CSR_WR(hw, DLB2_SYS_DIR_CQ_AT(port->id.phys_id), reg);
4727 	}
4728 
4729 	if (vdev_req && hw->virt_mode == DLB2_VIRT_SIOV) {
4730 		DLB2_BITS_SET(reg, hw->pasid[vdev_id],
4731 			      DLB2_SYS_DIR_CQ_PASID_PASID);
4732 		DLB2_BIT_SET(reg, DLB2_SYS_DIR_CQ_PASID_FMT2);
4733 	}
4734 
4735 	DLB2_CSR_WR(hw, DLB2_SYS_DIR_CQ_PASID(hw->ver, port->id.phys_id), reg);
4736 
4737 	reg = 0;
4738 	DLB2_BITS_SET(reg, domain->id.phys_id, DLB2_CHP_DIR_CQ2VAS_CQ2VAS);
4739 	DLB2_CSR_WR(hw, DLB2_CHP_DIR_CQ2VAS(hw->ver, port->id.phys_id), reg);
4740 
4741 	return 0;
4742 }
4743 
dlb2_configure_dir_port(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_dir_pq_pair * port,uintptr_t cq_dma_base,struct dlb2_create_dir_port_args * args,bool vdev_req,unsigned int vdev_id)4744 static int dlb2_configure_dir_port(struct dlb2_hw *hw,
4745 				   struct dlb2_hw_domain *domain,
4746 				   struct dlb2_dir_pq_pair *port,
4747 				   uintptr_t cq_dma_base,
4748 				   struct dlb2_create_dir_port_args *args,
4749 				   bool vdev_req,
4750 				   unsigned int vdev_id)
4751 {
4752 	int ret;
4753 
4754 	ret = dlb2_dir_port_configure_cq(hw,
4755 					 domain,
4756 					 port,
4757 					 cq_dma_base,
4758 					 args,
4759 					 vdev_req,
4760 					 vdev_id);
4761 
4762 	if (ret)
4763 		return ret;
4764 
4765 	dlb2_dir_port_configure_pp(hw,
4766 				   domain,
4767 				   port,
4768 				   vdev_req,
4769 				   vdev_id);
4770 
4771 	dlb2_dir_port_cq_enable(hw, port);
4772 
4773 	port->enabled = true;
4774 
4775 	port->port_configured = true;
4776 
4777 	return 0;
4778 }
4779 
4780 /**
4781  * dlb2_hw_create_dir_port() - create a directed port
4782  * @hw: dlb2_hw handle for a particular device.
4783  * @domain_id: domain ID.
4784  * @args: port creation arguments.
4785  * @cq_dma_base: base address of the CQ memory. This can be a PA or an IOVA.
4786  * @resp: response structure.
4787  * @vdev_req: indicates whether this request came from a vdev.
4788  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
4789  *
4790  * This function creates a directed port.
4791  *
4792  * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual
4793  * device.
4794  *
4795  * Return:
4796  * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
4797  * assigned a detailed error code from enum dlb2_error. If successful, resp->id
4798  * contains the port ID.
4799  *
4800  * resp->id contains a virtual ID if vdev_req is true.
4801  *
4802  * Errors:
4803  * EINVAL - A requested resource is unavailable, a credit setting is invalid, a
4804  *	    pointer address is not properly aligned, the domain is not
4805  *	    configured, or the domain has already been started.
4806  * EFAULT - Internal error (resp->status not set).
4807  */
dlb2_hw_create_dir_port(struct dlb2_hw * hw,u32 domain_id,struct dlb2_create_dir_port_args * args,uintptr_t cq_dma_base,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id)4808 int dlb2_hw_create_dir_port(struct dlb2_hw *hw,
4809 			    u32 domain_id,
4810 			    struct dlb2_create_dir_port_args *args,
4811 			    uintptr_t cq_dma_base,
4812 			    struct dlb2_cmd_response *resp,
4813 			    bool vdev_req,
4814 			    unsigned int vdev_id)
4815 {
4816 	struct dlb2_dir_pq_pair *port;
4817 	struct dlb2_hw_domain *domain;
4818 	int ret;
4819 
4820 	dlb2_log_create_dir_port_args(hw,
4821 				      domain_id,
4822 				      cq_dma_base,
4823 				      args,
4824 				      vdev_req,
4825 				      vdev_id);
4826 
4827 	/*
4828 	 * Verify that hardware resources are available before attempting to
4829 	 * satisfy the request. This simplifies the error unwinding code.
4830 	 */
4831 	ret = dlb2_verify_create_dir_port_args(hw,
4832 					       domain_id,
4833 					       cq_dma_base,
4834 					       args,
4835 					       resp,
4836 					       vdev_req,
4837 					       vdev_id,
4838 					       &domain,
4839 					       &port);
4840 	if (ret)
4841 		return ret;
4842 
4843 	ret = dlb2_configure_dir_port(hw,
4844 				      domain,
4845 				      port,
4846 				      cq_dma_base,
4847 				      args,
4848 				      vdev_req,
4849 				      vdev_id);
4850 	if (ret)
4851 		return ret;
4852 
4853 	/*
4854 	 * Configuration succeeded, so move the resource from the 'avail' to
4855 	 * the 'used' list (if it's not already there).
4856 	 */
4857 	if (args->queue_id == -1) {
4858 		dlb2_list_del(&domain->avail_dir_pq_pairs, &port->domain_list);
4859 
4860 		dlb2_list_add(&domain->used_dir_pq_pairs, &port->domain_list);
4861 	}
4862 
4863 	resp->status = 0;
4864 	resp->id = (vdev_req) ? port->id.virt_id : port->id.phys_id;
4865 
4866 	return 0;
4867 }
4868 
dlb2_configure_dir_queue(struct dlb2_hw * hw,struct dlb2_hw_domain * domain,struct dlb2_dir_pq_pair * queue,struct dlb2_create_dir_queue_args * args,bool vdev_req,unsigned int vdev_id)4869 static void dlb2_configure_dir_queue(struct dlb2_hw *hw,
4870 				     struct dlb2_hw_domain *domain,
4871 				     struct dlb2_dir_pq_pair *queue,
4872 				     struct dlb2_create_dir_queue_args *args,
4873 				     bool vdev_req,
4874 				     unsigned int vdev_id)
4875 {
4876 	unsigned int offs;
4877 	u32 reg = 0;
4878 
4879 	/* QID write permissions are turned on when the domain is started */
4880 	offs = domain->id.phys_id * DLB2_MAX_NUM_DIR_QUEUES(hw->ver) +
4881 		queue->id.phys_id;
4882 
4883 	DLB2_CSR_WR(hw, DLB2_SYS_DIR_VASQID_V(offs), reg);
4884 
4885 	/* Don't timestamp QEs that pass through this queue */
4886 	DLB2_CSR_WR(hw, DLB2_SYS_DIR_QID_ITS(queue->id.phys_id), reg);
4887 
4888 	reg = 0;
4889 	DLB2_BITS_SET(reg, args->depth_threshold,
4890 		      DLB2_LSP_QID_DIR_DEPTH_THRSH_THRESH);
4891 	DLB2_CSR_WR(hw,
4892 		    DLB2_LSP_QID_DIR_DEPTH_THRSH(hw->ver, queue->id.phys_id),
4893 		    reg);
4894 
4895 	if (vdev_req) {
4896 		offs = vdev_id * DLB2_MAX_NUM_DIR_QUEUES(hw->ver) +
4897 			queue->id.virt_id;
4898 
4899 		reg = 0;
4900 		DLB2_BIT_SET(reg, DLB2_SYS_VF_DIR_VQID_V_VQID_V);
4901 		DLB2_CSR_WR(hw, DLB2_SYS_VF_DIR_VQID_V(offs), reg);
4902 
4903 		reg = 0;
4904 		DLB2_BITS_SET(reg, queue->id.phys_id,
4905 			      DLB2_SYS_VF_DIR_VQID2QID_QID);
4906 		DLB2_CSR_WR(hw, DLB2_SYS_VF_DIR_VQID2QID(offs), reg);
4907 	}
4908 
4909 	reg = 0;
4910 	DLB2_BIT_SET(reg, DLB2_SYS_DIR_QID_V_QID_V);
4911 	DLB2_CSR_WR(hw, DLB2_SYS_DIR_QID_V(queue->id.phys_id), reg);
4912 
4913 	queue->queue_configured = true;
4914 }
4915 
4916 static void
dlb2_log_create_dir_queue_args(struct dlb2_hw * hw,u32 domain_id,struct dlb2_create_dir_queue_args * args,bool vdev_req,unsigned int vdev_id)4917 dlb2_log_create_dir_queue_args(struct dlb2_hw *hw,
4918 			       u32 domain_id,
4919 			       struct dlb2_create_dir_queue_args *args,
4920 			       bool vdev_req,
4921 			       unsigned int vdev_id)
4922 {
4923 	DLB2_HW_DBG(hw, "DLB2 create directed queue arguments:\n");
4924 	if (vdev_req)
4925 		DLB2_HW_DBG(hw, "(Request from vdev %d)\n", vdev_id);
4926 	DLB2_HW_DBG(hw, "\tDomain ID: %d\n", domain_id);
4927 	DLB2_HW_DBG(hw, "\tPort ID:   %d\n", args->port_id);
4928 }
4929 
4930 static int
dlb2_verify_create_dir_queue_args(struct dlb2_hw * hw,u32 domain_id,struct dlb2_create_dir_queue_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id,struct dlb2_hw_domain ** out_domain,struct dlb2_dir_pq_pair ** out_queue)4931 dlb2_verify_create_dir_queue_args(struct dlb2_hw *hw,
4932 				  u32 domain_id,
4933 				  struct dlb2_create_dir_queue_args *args,
4934 				  struct dlb2_cmd_response *resp,
4935 				  bool vdev_req,
4936 				  unsigned int vdev_id,
4937 				  struct dlb2_hw_domain **out_domain,
4938 				  struct dlb2_dir_pq_pair **out_queue)
4939 {
4940 	struct dlb2_hw_domain *domain;
4941 	struct dlb2_dir_pq_pair *pq;
4942 
4943 	domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id);
4944 
4945 	if (!domain) {
4946 		resp->status = DLB2_ST_INVALID_DOMAIN_ID;
4947 		return -EINVAL;
4948 	}
4949 
4950 	if (!domain->configured) {
4951 		resp->status = DLB2_ST_DOMAIN_NOT_CONFIGURED;
4952 		return -EINVAL;
4953 	}
4954 
4955 	if (domain->started) {
4956 		resp->status = DLB2_ST_DOMAIN_STARTED;
4957 		return -EINVAL;
4958 	}
4959 
4960 	/*
4961 	 * If the user claims the port is already configured, validate the port
4962 	 * ID, its domain, and whether the port is configured.
4963 	 */
4964 	if (args->port_id != -1) {
4965 		pq = dlb2_get_domain_used_dir_pq(hw,
4966 						 args->port_id,
4967 						 vdev_req,
4968 						 domain);
4969 
4970 		if (!pq || pq->domain_id.phys_id != domain->id.phys_id ||
4971 		    !pq->port_configured) {
4972 			resp->status = DLB2_ST_INVALID_PORT_ID;
4973 			return -EINVAL;
4974 		}
4975 	} else {
4976 		/*
4977 		 * If the queue's port is not configured, validate that a free
4978 		 * port-queue pair is available.
4979 		 */
4980 		pq = DLB2_DOM_LIST_HEAD(domain->avail_dir_pq_pairs,
4981 					typeof(*pq));
4982 		if (!pq) {
4983 			resp->status = DLB2_ST_DIR_QUEUES_UNAVAILABLE;
4984 			return -EINVAL;
4985 		}
4986 	}
4987 
4988 	*out_domain = domain;
4989 	*out_queue = pq;
4990 
4991 	return 0;
4992 }
4993 
4994 /**
4995  * dlb2_hw_create_dir_queue() - create a directed queue
4996  * @hw: dlb2_hw handle for a particular device.
4997  * @domain_id: domain ID.
4998  * @args: queue creation arguments.
4999  * @resp: response structure.
5000  * @vdev_req: indicates whether this request came from a vdev.
5001  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
5002  *
5003  * This function creates a directed queue.
5004  *
5005  * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual
5006  * device.
5007  *
5008  * Return:
5009  * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
5010  * assigned a detailed error code from enum dlb2_error. If successful, resp->id
5011  * contains the queue ID.
5012  *
5013  * resp->id contains a virtual ID if vdev_req is true.
5014  *
5015  * Errors:
5016  * EINVAL - A requested resource is unavailable, the domain is not configured,
5017  *	    or the domain has already been started.
5018  * EFAULT - Internal error (resp->status not set).
5019  */
dlb2_hw_create_dir_queue(struct dlb2_hw * hw,u32 domain_id,struct dlb2_create_dir_queue_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id)5020 int dlb2_hw_create_dir_queue(struct dlb2_hw *hw,
5021 			     u32 domain_id,
5022 			     struct dlb2_create_dir_queue_args *args,
5023 			     struct dlb2_cmd_response *resp,
5024 			     bool vdev_req,
5025 			     unsigned int vdev_id)
5026 {
5027 	struct dlb2_dir_pq_pair *queue;
5028 	struct dlb2_hw_domain *domain;
5029 	int ret;
5030 
5031 	dlb2_log_create_dir_queue_args(hw, domain_id, args, vdev_req, vdev_id);
5032 
5033 	/*
5034 	 * Verify that hardware resources are available before attempting to
5035 	 * satisfy the request. This simplifies the error unwinding code.
5036 	 */
5037 	ret = dlb2_verify_create_dir_queue_args(hw,
5038 						domain_id,
5039 						args,
5040 						resp,
5041 						vdev_req,
5042 						vdev_id,
5043 						&domain,
5044 						&queue);
5045 	if (ret)
5046 		return ret;
5047 
5048 	dlb2_configure_dir_queue(hw, domain, queue, args, vdev_req, vdev_id);
5049 
5050 	/*
5051 	 * Configuration succeeded, so move the resource from the 'avail' to
5052 	 * the 'used' list (if it's not already there).
5053 	 */
5054 	if (args->port_id == -1) {
5055 		dlb2_list_del(&domain->avail_dir_pq_pairs,
5056 			      &queue->domain_list);
5057 
5058 		dlb2_list_add(&domain->used_dir_pq_pairs,
5059 			      &queue->domain_list);
5060 	}
5061 
5062 	resp->status = 0;
5063 
5064 	resp->id = (vdev_req) ? queue->id.virt_id : queue->id.phys_id;
5065 
5066 	return 0;
5067 }
5068 
5069 static bool
dlb2_port_find_slot_with_pending_map_queue(struct dlb2_ldb_port * port,struct dlb2_ldb_queue * queue,int * slot)5070 dlb2_port_find_slot_with_pending_map_queue(struct dlb2_ldb_port *port,
5071 					   struct dlb2_ldb_queue *queue,
5072 					   int *slot)
5073 {
5074 	int i;
5075 
5076 	for (i = 0; i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; i++) {
5077 		struct dlb2_ldb_port_qid_map *map = &port->qid_map[i];
5078 
5079 		if (map->state == DLB2_QUEUE_UNMAP_IN_PROG_PENDING_MAP &&
5080 		    map->pending_qid == queue->id.phys_id)
5081 			break;
5082 	}
5083 
5084 	*slot = i;
5085 
5086 	return (i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ);
5087 }
5088 
dlb2_verify_map_qid_slot_available(struct dlb2_ldb_port * port,struct dlb2_ldb_queue * queue,struct dlb2_cmd_response * resp)5089 static int dlb2_verify_map_qid_slot_available(struct dlb2_ldb_port *port,
5090 					      struct dlb2_ldb_queue *queue,
5091 					      struct dlb2_cmd_response *resp)
5092 {
5093 	enum dlb2_qid_map_state state;
5094 	int i;
5095 
5096 	/* Unused slot available? */
5097 	if (port->num_mappings < DLB2_MAX_NUM_QIDS_PER_LDB_CQ)
5098 		return 0;
5099 
5100 	/*
5101 	 * If the queue is already mapped (from the application's perspective),
5102 	 * this is simply a priority update.
5103 	 */
5104 	state = DLB2_QUEUE_MAPPED;
5105 	if (dlb2_port_find_slot_queue(port, state, queue, &i))
5106 		return 0;
5107 
5108 	state = DLB2_QUEUE_MAP_IN_PROG;
5109 	if (dlb2_port_find_slot_queue(port, state, queue, &i))
5110 		return 0;
5111 
5112 	if (dlb2_port_find_slot_with_pending_map_queue(port, queue, &i))
5113 		return 0;
5114 
5115 	/*
5116 	 * If the slot contains an unmap in progress, it's considered
5117 	 * available.
5118 	 */
5119 	state = DLB2_QUEUE_UNMAP_IN_PROG;
5120 	if (dlb2_port_find_slot(port, state, &i))
5121 		return 0;
5122 
5123 	state = DLB2_QUEUE_UNMAPPED;
5124 	if (dlb2_port_find_slot(port, state, &i))
5125 		return 0;
5126 
5127 	resp->status = DLB2_ST_NO_QID_SLOTS_AVAILABLE;
5128 	return -EINVAL;
5129 }
5130 
5131 static struct dlb2_ldb_queue *
dlb2_get_domain_ldb_queue(u32 id,bool vdev_req,struct dlb2_hw_domain * domain)5132 dlb2_get_domain_ldb_queue(u32 id,
5133 			  bool vdev_req,
5134 			  struct dlb2_hw_domain *domain)
5135 {
5136 	struct dlb2_list_entry *iter;
5137 	struct dlb2_ldb_queue *queue;
5138 	RTE_SET_USED(iter);
5139 
5140 	if (id >= DLB2_MAX_NUM_LDB_QUEUES)
5141 		return NULL;
5142 
5143 	DLB2_DOM_LIST_FOR(domain->used_ldb_queues, queue, iter) {
5144 		if ((!vdev_req && queue->id.phys_id == id) ||
5145 		    (vdev_req && queue->id.virt_id == id))
5146 			return queue;
5147 	}
5148 
5149 	return NULL;
5150 }
5151 
5152 static struct dlb2_ldb_port *
dlb2_get_domain_used_ldb_port(u32 id,bool vdev_req,struct dlb2_hw_domain * domain)5153 dlb2_get_domain_used_ldb_port(u32 id,
5154 			      bool vdev_req,
5155 			      struct dlb2_hw_domain *domain)
5156 {
5157 	struct dlb2_list_entry *iter;
5158 	struct dlb2_ldb_port *port;
5159 	int i;
5160 	RTE_SET_USED(iter);
5161 
5162 	if (id >= DLB2_MAX_NUM_LDB_PORTS)
5163 		return NULL;
5164 
5165 	for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) {
5166 		DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) {
5167 			if ((!vdev_req && port->id.phys_id == id) ||
5168 			    (vdev_req && port->id.virt_id == id))
5169 				return port;
5170 		}
5171 
5172 		DLB2_DOM_LIST_FOR(domain->avail_ldb_ports[i], port, iter) {
5173 			if ((!vdev_req && port->id.phys_id == id) ||
5174 			    (vdev_req && port->id.virt_id == id))
5175 				return port;
5176 		}
5177 	}
5178 
5179 	return NULL;
5180 }
5181 
dlb2_ldb_port_change_qid_priority(struct dlb2_hw * hw,struct dlb2_ldb_port * port,int slot,struct dlb2_map_qid_args * args)5182 static void dlb2_ldb_port_change_qid_priority(struct dlb2_hw *hw,
5183 					      struct dlb2_ldb_port *port,
5184 					      int slot,
5185 					      struct dlb2_map_qid_args *args)
5186 {
5187 	u32 cq2priov;
5188 
5189 	/* Read-modify-write the priority and valid bit register */
5190 	cq2priov = DLB2_CSR_RD(hw,
5191 			       DLB2_LSP_CQ2PRIOV(hw->ver, port->id.phys_id));
5192 
5193 	cq2priov |= (1 << (slot + DLB2_LSP_CQ2PRIOV_V_LOC)) &
5194 		    DLB2_LSP_CQ2PRIOV_V;
5195 	cq2priov |= ((args->priority & 0x7) << slot * 3) &
5196 		    DLB2_LSP_CQ2PRIOV_PRIO;
5197 
5198 	DLB2_CSR_WR(hw, DLB2_LSP_CQ2PRIOV(hw->ver, port->id.phys_id), cq2priov);
5199 
5200 	dlb2_flush_csr(hw);
5201 
5202 	port->qid_map[slot].priority = args->priority;
5203 }
5204 
dlb2_verify_map_qid_args(struct dlb2_hw * hw,u32 domain_id,struct dlb2_map_qid_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id,struct dlb2_hw_domain ** out_domain,struct dlb2_ldb_port ** out_port,struct dlb2_ldb_queue ** out_queue)5205 static int dlb2_verify_map_qid_args(struct dlb2_hw *hw,
5206 				    u32 domain_id,
5207 				    struct dlb2_map_qid_args *args,
5208 				    struct dlb2_cmd_response *resp,
5209 				    bool vdev_req,
5210 				    unsigned int vdev_id,
5211 				    struct dlb2_hw_domain **out_domain,
5212 				    struct dlb2_ldb_port **out_port,
5213 				    struct dlb2_ldb_queue **out_queue)
5214 {
5215 	struct dlb2_hw_domain *domain;
5216 	struct dlb2_ldb_queue *queue;
5217 	struct dlb2_ldb_port *port;
5218 	int id;
5219 
5220 	domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id);
5221 
5222 	if (!domain) {
5223 		resp->status = DLB2_ST_INVALID_DOMAIN_ID;
5224 		return -EINVAL;
5225 	}
5226 
5227 	if (!domain->configured) {
5228 		resp->status = DLB2_ST_DOMAIN_NOT_CONFIGURED;
5229 		return -EINVAL;
5230 	}
5231 
5232 	id = args->port_id;
5233 
5234 	port = dlb2_get_domain_used_ldb_port(id, vdev_req, domain);
5235 
5236 	if (!port || !port->configured) {
5237 		resp->status = DLB2_ST_INVALID_PORT_ID;
5238 		return -EINVAL;
5239 	}
5240 
5241 	if (args->priority >= DLB2_QID_PRIORITIES) {
5242 		resp->status = DLB2_ST_INVALID_PRIORITY;
5243 		return -EINVAL;
5244 	}
5245 
5246 	queue = dlb2_get_domain_ldb_queue(args->qid, vdev_req, domain);
5247 
5248 	if (!queue || !queue->configured) {
5249 		resp->status = DLB2_ST_INVALID_QID;
5250 		return -EINVAL;
5251 	}
5252 
5253 	if (queue->domain_id.phys_id != domain->id.phys_id) {
5254 		resp->status = DLB2_ST_INVALID_QID;
5255 		return -EINVAL;
5256 	}
5257 
5258 	if (port->domain_id.phys_id != domain->id.phys_id) {
5259 		resp->status = DLB2_ST_INVALID_PORT_ID;
5260 		return -EINVAL;
5261 	}
5262 
5263 	*out_domain = domain;
5264 	*out_queue = queue;
5265 	*out_port = port;
5266 
5267 	return 0;
5268 }
5269 
dlb2_log_map_qid(struct dlb2_hw * hw,u32 domain_id,struct dlb2_map_qid_args * args,bool vdev_req,unsigned int vdev_id)5270 static void dlb2_log_map_qid(struct dlb2_hw *hw,
5271 			     u32 domain_id,
5272 			     struct dlb2_map_qid_args *args,
5273 			     bool vdev_req,
5274 			     unsigned int vdev_id)
5275 {
5276 	DLB2_HW_DBG(hw, "DLB2 map QID arguments:\n");
5277 	if (vdev_req)
5278 		DLB2_HW_DBG(hw, "(Request from vdev %d)\n", vdev_id);
5279 	DLB2_HW_DBG(hw, "\tDomain ID: %d\n",
5280 		    domain_id);
5281 	DLB2_HW_DBG(hw, "\tPort ID:   %d\n",
5282 		    args->port_id);
5283 	DLB2_HW_DBG(hw, "\tQueue ID:  %d\n",
5284 		    args->qid);
5285 	DLB2_HW_DBG(hw, "\tPriority:  %d\n",
5286 		    args->priority);
5287 }
5288 
5289 /**
5290  * dlb2_hw_map_qid() - map a load-balanced queue to a load-balanced port
5291  * @hw: dlb2_hw handle for a particular device.
5292  * @domain_id: domain ID.
5293  * @args: map QID arguments.
5294  * @resp: response structure.
5295  * @vdev_req: indicates whether this request came from a vdev.
5296  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
5297  *
5298  * This function configures the DLB to schedule QEs from the specified queue
5299  * to the specified port. Each load-balanced port can be mapped to up to 8
5300  * queues; each load-balanced queue can potentially map to all the
5301  * load-balanced ports.
5302  *
5303  * A successful return does not necessarily mean the mapping was configured. If
5304  * this function is unable to immediately map the queue to the port, it will
5305  * add the requested operation to a per-port list of pending map/unmap
5306  * operations, and (if it's not already running) launch a kernel thread that
5307  * periodically attempts to process all pending operations. In a sense, this is
5308  * an asynchronous function.
5309  *
5310  * This asynchronicity creates two views of the state of hardware: the actual
5311  * hardware state and the requested state (as if every request completed
5312  * immediately). If there are any pending map/unmap operations, the requested
5313  * state will differ from the actual state. All validation is performed with
5314  * respect to the pending state; for instance, if there are 8 pending map
5315  * operations for port X, a request for a 9th will fail because a load-balanced
5316  * port can only map up to 8 queues.
5317  *
5318  * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual
5319  * device.
5320  *
5321  * Return:
5322  * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
5323  * assigned a detailed error code from enum dlb2_error.
5324  *
5325  * Errors:
5326  * EINVAL - A requested resource is unavailable, invalid port or queue ID, or
5327  *	    the domain is not configured.
5328  * EFAULT - Internal error (resp->status not set).
5329  * EBUSY  - The requested port has outstanding detach operations.
5330  */
dlb2_hw_map_qid(struct dlb2_hw * hw,u32 domain_id,struct dlb2_map_qid_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id)5331 int dlb2_hw_map_qid(struct dlb2_hw *hw,
5332 		    u32 domain_id,
5333 		    struct dlb2_map_qid_args *args,
5334 		    struct dlb2_cmd_response *resp,
5335 		    bool vdev_req,
5336 		    unsigned int vdev_id)
5337 {
5338 	struct dlb2_hw_domain *domain;
5339 	struct dlb2_ldb_queue *queue;
5340 	enum dlb2_qid_map_state st;
5341 	struct dlb2_ldb_port *port;
5342 	int ret, i;
5343 	u8 prio;
5344 
5345 	dlb2_log_map_qid(hw, domain_id, args, vdev_req, vdev_id);
5346 
5347 	/*
5348 	 * Verify that hardware resources are available before attempting to
5349 	 * satisfy the request. This simplifies the error unwinding code.
5350 	 */
5351 	ret = dlb2_verify_map_qid_args(hw,
5352 				       domain_id,
5353 				       args,
5354 				       resp,
5355 				       vdev_req,
5356 				       vdev_id,
5357 				       &domain,
5358 				       &port,
5359 				       &queue);
5360 	if (ret)
5361 		return ret;
5362 
5363 	prio = args->priority;
5364 
5365 	/*
5366 	 * If there are any outstanding detach operations for this port,
5367 	 * attempt to complete them. This may be necessary to free up a QID
5368 	 * slot for this requested mapping.
5369 	 */
5370 	if (port->num_pending_removals) {
5371 		bool bool_ret;
5372 		bool_ret = dlb2_domain_finish_unmap_port(hw, domain, port);
5373 		if (!bool_ret)
5374 			return -EBUSY;
5375 	}
5376 
5377 	ret = dlb2_verify_map_qid_slot_available(port, queue, resp);
5378 	if (ret)
5379 		return ret;
5380 
5381 	/* Hardware requires disabling the CQ before mapping QIDs. */
5382 	if (port->enabled)
5383 		dlb2_ldb_port_cq_disable(hw, port);
5384 
5385 	/*
5386 	 * If this is only a priority change, don't perform the full QID->CQ
5387 	 * mapping procedure
5388 	 */
5389 	st = DLB2_QUEUE_MAPPED;
5390 	if (dlb2_port_find_slot_queue(port, st, queue, &i)) {
5391 		if (prio != port->qid_map[i].priority) {
5392 			dlb2_ldb_port_change_qid_priority(hw, port, i, args);
5393 			DLB2_HW_DBG(hw, "DLB2 map: priority change\n");
5394 		}
5395 
5396 		st = DLB2_QUEUE_MAPPED;
5397 		ret = dlb2_port_slot_state_transition(hw, port, queue, i, st);
5398 		if (ret)
5399 			return ret;
5400 
5401 		goto map_qid_done;
5402 	}
5403 
5404 	st = DLB2_QUEUE_UNMAP_IN_PROG;
5405 	if (dlb2_port_find_slot_queue(port, st, queue, &i)) {
5406 		if (prio != port->qid_map[i].priority) {
5407 			dlb2_ldb_port_change_qid_priority(hw, port, i, args);
5408 			DLB2_HW_DBG(hw, "DLB2 map: priority change\n");
5409 		}
5410 
5411 		st = DLB2_QUEUE_MAPPED;
5412 		ret = dlb2_port_slot_state_transition(hw, port, queue, i, st);
5413 		if (ret)
5414 			return ret;
5415 
5416 		goto map_qid_done;
5417 	}
5418 
5419 	/*
5420 	 * If this is a priority change on an in-progress mapping, don't
5421 	 * perform the full QID->CQ mapping procedure.
5422 	 */
5423 	st = DLB2_QUEUE_MAP_IN_PROG;
5424 	if (dlb2_port_find_slot_queue(port, st, queue, &i)) {
5425 		port->qid_map[i].priority = prio;
5426 
5427 		DLB2_HW_DBG(hw, "DLB2 map: priority change only\n");
5428 
5429 		goto map_qid_done;
5430 	}
5431 
5432 	/*
5433 	 * If this is a priority change on a pending mapping, update the
5434 	 * pending priority
5435 	 */
5436 	if (dlb2_port_find_slot_with_pending_map_queue(port, queue, &i)) {
5437 		port->qid_map[i].pending_priority = prio;
5438 
5439 		DLB2_HW_DBG(hw, "DLB2 map: priority change only\n");
5440 
5441 		goto map_qid_done;
5442 	}
5443 
5444 	/*
5445 	 * If all the CQ's slots are in use, then there's an unmap in progress
5446 	 * (guaranteed by dlb2_verify_map_qid_slot_available()), so add this
5447 	 * mapping to pending_map and return. When the removal is completed for
5448 	 * the slot's current occupant, this mapping will be performed.
5449 	 */
5450 	if (!dlb2_port_find_slot(port, DLB2_QUEUE_UNMAPPED, &i)) {
5451 		if (dlb2_port_find_slot(port, DLB2_QUEUE_UNMAP_IN_PROG, &i)) {
5452 			enum dlb2_qid_map_state new_st;
5453 
5454 			port->qid_map[i].pending_qid = queue->id.phys_id;
5455 			port->qid_map[i].pending_priority = prio;
5456 
5457 			new_st = DLB2_QUEUE_UNMAP_IN_PROG_PENDING_MAP;
5458 
5459 			ret = dlb2_port_slot_state_transition(hw, port, queue,
5460 							      i, new_st);
5461 			if (ret)
5462 				return ret;
5463 
5464 			DLB2_HW_DBG(hw, "DLB2 map: map pending removal\n");
5465 
5466 			goto map_qid_done;
5467 		}
5468 	}
5469 
5470 	/*
5471 	 * If the domain has started, a special "dynamic" CQ->queue mapping
5472 	 * procedure is required in order to safely update the CQ<->QID tables.
5473 	 * The "static" procedure cannot be used when traffic is flowing,
5474 	 * because the CQ<->QID tables cannot be updated atomically and the
5475 	 * scheduler won't see the new mapping unless the queue's if_status
5476 	 * changes, which isn't guaranteed.
5477 	 */
5478 	ret = dlb2_ldb_port_map_qid(hw, domain, port, queue, prio);
5479 
5480 	/* If ret is less than zero, it's due to an internal error */
5481 	if (ret < 0)
5482 		return ret;
5483 
5484 map_qid_done:
5485 	if (port->enabled)
5486 		dlb2_ldb_port_cq_enable(hw, port);
5487 
5488 	resp->status = 0;
5489 
5490 	return 0;
5491 }
5492 
dlb2_log_unmap_qid(struct dlb2_hw * hw,u32 domain_id,struct dlb2_unmap_qid_args * args,bool vdev_req,unsigned int vdev_id)5493 static void dlb2_log_unmap_qid(struct dlb2_hw *hw,
5494 			       u32 domain_id,
5495 			       struct dlb2_unmap_qid_args *args,
5496 			       bool vdev_req,
5497 			       unsigned int vdev_id)
5498 {
5499 	DLB2_HW_DBG(hw, "DLB2 unmap QID arguments:\n");
5500 	if (vdev_req)
5501 		DLB2_HW_DBG(hw, "(Request from vdev %d)\n", vdev_id);
5502 	DLB2_HW_DBG(hw, "\tDomain ID: %d\n",
5503 		    domain_id);
5504 	DLB2_HW_DBG(hw, "\tPort ID:   %d\n",
5505 		    args->port_id);
5506 	DLB2_HW_DBG(hw, "\tQueue ID:  %d\n",
5507 		    args->qid);
5508 	if (args->qid < DLB2_MAX_NUM_LDB_QUEUES)
5509 		DLB2_HW_DBG(hw, "\tQueue's num mappings:  %d\n",
5510 			    hw->rsrcs.ldb_queues[args->qid].num_mappings);
5511 }
5512 
dlb2_verify_unmap_qid_args(struct dlb2_hw * hw,u32 domain_id,struct dlb2_unmap_qid_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id,struct dlb2_hw_domain ** out_domain,struct dlb2_ldb_port ** out_port,struct dlb2_ldb_queue ** out_queue)5513 static int dlb2_verify_unmap_qid_args(struct dlb2_hw *hw,
5514 				      u32 domain_id,
5515 				      struct dlb2_unmap_qid_args *args,
5516 				      struct dlb2_cmd_response *resp,
5517 				      bool vdev_req,
5518 				      unsigned int vdev_id,
5519 				      struct dlb2_hw_domain **out_domain,
5520 				      struct dlb2_ldb_port **out_port,
5521 				      struct dlb2_ldb_queue **out_queue)
5522 {
5523 	enum dlb2_qid_map_state state;
5524 	struct dlb2_hw_domain *domain;
5525 	struct dlb2_ldb_queue *queue;
5526 	struct dlb2_ldb_port *port;
5527 	int slot;
5528 	int id;
5529 
5530 	domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id);
5531 
5532 	if (!domain) {
5533 		resp->status = DLB2_ST_INVALID_DOMAIN_ID;
5534 		return -EINVAL;
5535 	}
5536 
5537 	if (!domain->configured) {
5538 		resp->status = DLB2_ST_DOMAIN_NOT_CONFIGURED;
5539 		return -EINVAL;
5540 	}
5541 
5542 	id = args->port_id;
5543 
5544 	port = dlb2_get_domain_used_ldb_port(id, vdev_req, domain);
5545 
5546 	if (!port || !port->configured) {
5547 		resp->status = DLB2_ST_INVALID_PORT_ID;
5548 		return -EINVAL;
5549 	}
5550 
5551 	if (port->domain_id.phys_id != domain->id.phys_id) {
5552 		resp->status = DLB2_ST_INVALID_PORT_ID;
5553 		return -EINVAL;
5554 	}
5555 
5556 	queue = dlb2_get_domain_ldb_queue(args->qid, vdev_req, domain);
5557 
5558 	if (!queue || !queue->configured) {
5559 		DLB2_HW_ERR(hw, "[%s()] Can't unmap unconfigured queue %d\n",
5560 			    __func__, args->qid);
5561 		resp->status = DLB2_ST_INVALID_QID;
5562 		return -EINVAL;
5563 	}
5564 
5565 	/*
5566 	 * Verify that the port has the queue mapped. From the application's
5567 	 * perspective a queue is mapped if it is actually mapped, the map is
5568 	 * in progress, or the map is blocked pending an unmap.
5569 	 */
5570 	state = DLB2_QUEUE_MAPPED;
5571 	if (dlb2_port_find_slot_queue(port, state, queue, &slot))
5572 		goto done;
5573 
5574 	state = DLB2_QUEUE_MAP_IN_PROG;
5575 	if (dlb2_port_find_slot_queue(port, state, queue, &slot))
5576 		goto done;
5577 
5578 	if (dlb2_port_find_slot_with_pending_map_queue(port, queue, &slot))
5579 		goto done;
5580 
5581 	resp->status = DLB2_ST_INVALID_QID;
5582 	return -EINVAL;
5583 
5584 done:
5585 	*out_domain = domain;
5586 	*out_port = port;
5587 	*out_queue = queue;
5588 
5589 	return 0;
5590 }
5591 
5592 /**
5593  * dlb2_hw_unmap_qid() - Unmap a load-balanced queue from a load-balanced port
5594  * @hw: dlb2_hw handle for a particular device.
5595  * @domain_id: domain ID.
5596  * @args: unmap QID arguments.
5597  * @resp: response structure.
5598  * @vdev_req: indicates whether this request came from a vdev.
5599  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
5600  *
5601  * This function configures the DLB to stop scheduling QEs from the specified
5602  * queue to the specified port.
5603  *
5604  * A successful return does not necessarily mean the mapping was removed. If
5605  * this function is unable to immediately unmap the queue from the port, it
5606  * will add the requested operation to a per-port list of pending map/unmap
5607  * operations, and (if it's not already running) launch a kernel thread that
5608  * periodically attempts to process all pending operations. See
5609  * dlb2_hw_map_qid() for more details.
5610  *
5611  * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual
5612  * device.
5613  *
5614  * Return:
5615  * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
5616  * assigned a detailed error code from enum dlb2_error.
5617  *
5618  * Errors:
5619  * EINVAL - A requested resource is unavailable, invalid port or queue ID, or
5620  *	    the domain is not configured.
5621  * EFAULT - Internal error (resp->status not set).
5622  */
dlb2_hw_unmap_qid(struct dlb2_hw * hw,u32 domain_id,struct dlb2_unmap_qid_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id)5623 int dlb2_hw_unmap_qid(struct dlb2_hw *hw,
5624 		      u32 domain_id,
5625 		      struct dlb2_unmap_qid_args *args,
5626 		      struct dlb2_cmd_response *resp,
5627 		      bool vdev_req,
5628 		      unsigned int vdev_id)
5629 {
5630 	struct dlb2_hw_domain *domain;
5631 	struct dlb2_ldb_queue *queue;
5632 	enum dlb2_qid_map_state st;
5633 	struct dlb2_ldb_port *port;
5634 	bool unmap_complete;
5635 	int i, ret;
5636 
5637 	dlb2_log_unmap_qid(hw, domain_id, args, vdev_req, vdev_id);
5638 
5639 	/*
5640 	 * Verify that hardware resources are available before attempting to
5641 	 * satisfy the request. This simplifies the error unwinding code.
5642 	 */
5643 	ret = dlb2_verify_unmap_qid_args(hw,
5644 					 domain_id,
5645 					 args,
5646 					 resp,
5647 					 vdev_req,
5648 					 vdev_id,
5649 					 &domain,
5650 					 &port,
5651 					 &queue);
5652 	if (ret)
5653 		return ret;
5654 
5655 	/*
5656 	 * If the queue hasn't been mapped yet, we need to update the slot's
5657 	 * state and re-enable the queue's inflights.
5658 	 */
5659 	st = DLB2_QUEUE_MAP_IN_PROG;
5660 	if (dlb2_port_find_slot_queue(port, st, queue, &i)) {
5661 		/*
5662 		 * Since the in-progress map was aborted, re-enable the QID's
5663 		 * inflights.
5664 		 */
5665 		if (queue->num_pending_additions == 0)
5666 			dlb2_ldb_queue_set_inflight_limit(hw, queue);
5667 
5668 		st = DLB2_QUEUE_UNMAPPED;
5669 		ret = dlb2_port_slot_state_transition(hw, port, queue, i, st);
5670 		if (ret)
5671 			return ret;
5672 
5673 		goto unmap_qid_done;
5674 	}
5675 
5676 	/*
5677 	 * If the queue mapping is on hold pending an unmap, we simply need to
5678 	 * update the slot's state.
5679 	 */
5680 	if (dlb2_port_find_slot_with_pending_map_queue(port, queue, &i)) {
5681 		st = DLB2_QUEUE_UNMAP_IN_PROG;
5682 		ret = dlb2_port_slot_state_transition(hw, port, queue, i, st);
5683 		if (ret)
5684 			return ret;
5685 
5686 		goto unmap_qid_done;
5687 	}
5688 
5689 	st = DLB2_QUEUE_MAPPED;
5690 	if (!dlb2_port_find_slot_queue(port, st, queue, &i)) {
5691 		DLB2_HW_ERR(hw,
5692 			    "[%s()] Internal error: no available CQ slots\n",
5693 			    __func__);
5694 		return -EFAULT;
5695 	}
5696 
5697 	/*
5698 	 * QID->CQ mapping removal is an asynchronous procedure. It requires
5699 	 * stopping the DLB2 from scheduling this CQ, draining all inflights
5700 	 * from the CQ, then unmapping the queue from the CQ. This function
5701 	 * simply marks the port as needing the queue unmapped, and (if
5702 	 * necessary) starts the unmapping worker thread.
5703 	 */
5704 	dlb2_ldb_port_cq_disable(hw, port);
5705 
5706 	st = DLB2_QUEUE_UNMAP_IN_PROG;
5707 	ret = dlb2_port_slot_state_transition(hw, port, queue, i, st);
5708 	if (ret)
5709 		return ret;
5710 
5711 	/*
5712 	 * Attempt to finish the unmapping now, in case the port has no
5713 	 * outstanding inflights. If that's not the case, this will fail and
5714 	 * the unmapping will be completed at a later time.
5715 	 */
5716 	unmap_complete = dlb2_domain_finish_unmap_port(hw, domain, port);
5717 
5718 	/*
5719 	 * If the unmapping couldn't complete immediately, launch the worker
5720 	 * thread (if it isn't already launched) to finish it later.
5721 	 */
5722 	if (!unmap_complete && !os_worker_active(hw))
5723 		os_schedule_work(hw);
5724 
5725 unmap_qid_done:
5726 	resp->status = 0;
5727 
5728 	return 0;
5729 }
5730 
5731 static void
dlb2_log_pending_port_unmaps_args(struct dlb2_hw * hw,struct dlb2_pending_port_unmaps_args * args,bool vdev_req,unsigned int vdev_id)5732 dlb2_log_pending_port_unmaps_args(struct dlb2_hw *hw,
5733 				  struct dlb2_pending_port_unmaps_args *args,
5734 				  bool vdev_req,
5735 				  unsigned int vdev_id)
5736 {
5737 	DLB2_HW_DBG(hw, "DLB unmaps in progress arguments:\n");
5738 	if (vdev_req)
5739 		DLB2_HW_DBG(hw, "(Request from VF %d)\n", vdev_id);
5740 	DLB2_HW_DBG(hw, "\tPort ID: %d\n", args->port_id);
5741 }
5742 
5743 /**
5744  * dlb2_hw_pending_port_unmaps() - returns the number of unmap operations in
5745  *	progress.
5746  * @hw: dlb2_hw handle for a particular device.
5747  * @domain_id: domain ID.
5748  * @args: number of unmaps in progress args
5749  * @resp: response structure.
5750  * @vdev_req: indicates whether this request came from a vdev.
5751  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
5752  *
5753  * Return:
5754  * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
5755  * assigned a detailed error code from enum dlb2_error. If successful, resp->id
5756  * contains the number of unmaps in progress.
5757  *
5758  * Errors:
5759  * EINVAL - Invalid port ID.
5760  */
dlb2_hw_pending_port_unmaps(struct dlb2_hw * hw,u32 domain_id,struct dlb2_pending_port_unmaps_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id)5761 int dlb2_hw_pending_port_unmaps(struct dlb2_hw *hw,
5762 				u32 domain_id,
5763 				struct dlb2_pending_port_unmaps_args *args,
5764 				struct dlb2_cmd_response *resp,
5765 				bool vdev_req,
5766 				unsigned int vdev_id)
5767 {
5768 	struct dlb2_hw_domain *domain;
5769 	struct dlb2_ldb_port *port;
5770 
5771 	dlb2_log_pending_port_unmaps_args(hw, args, vdev_req, vdev_id);
5772 
5773 	domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id);
5774 
5775 	if (!domain) {
5776 		resp->status = DLB2_ST_INVALID_DOMAIN_ID;
5777 		return -EINVAL;
5778 	}
5779 
5780 	port = dlb2_get_domain_used_ldb_port(args->port_id, vdev_req, domain);
5781 	if (!port || !port->configured) {
5782 		resp->status = DLB2_ST_INVALID_PORT_ID;
5783 		return -EINVAL;
5784 	}
5785 
5786 	resp->id = port->num_pending_removals;
5787 
5788 	return 0;
5789 }
5790 
dlb2_verify_start_domain_args(struct dlb2_hw * hw,u32 domain_id,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id,struct dlb2_hw_domain ** out_domain)5791 static int dlb2_verify_start_domain_args(struct dlb2_hw *hw,
5792 					 u32 domain_id,
5793 					 struct dlb2_cmd_response *resp,
5794 					 bool vdev_req,
5795 					 unsigned int vdev_id,
5796 					 struct dlb2_hw_domain **out_domain)
5797 {
5798 	struct dlb2_hw_domain *domain;
5799 
5800 	domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id);
5801 
5802 	if (!domain) {
5803 		resp->status = DLB2_ST_INVALID_DOMAIN_ID;
5804 		return -EINVAL;
5805 	}
5806 
5807 	if (!domain->configured) {
5808 		resp->status = DLB2_ST_DOMAIN_NOT_CONFIGURED;
5809 		return -EINVAL;
5810 	}
5811 
5812 	if (domain->started) {
5813 		resp->status = DLB2_ST_DOMAIN_STARTED;
5814 		return -EINVAL;
5815 	}
5816 
5817 	*out_domain = domain;
5818 
5819 	return 0;
5820 }
5821 
dlb2_log_start_domain(struct dlb2_hw * hw,u32 domain_id,bool vdev_req,unsigned int vdev_id)5822 static void dlb2_log_start_domain(struct dlb2_hw *hw,
5823 				  u32 domain_id,
5824 				  bool vdev_req,
5825 				  unsigned int vdev_id)
5826 {
5827 	DLB2_HW_DBG(hw, "DLB2 start domain arguments:\n");
5828 	if (vdev_req)
5829 		DLB2_HW_DBG(hw, "(Request from vdev %d)\n", vdev_id);
5830 	DLB2_HW_DBG(hw, "\tDomain ID: %d\n", domain_id);
5831 }
5832 
5833 /**
5834  * dlb2_hw_start_domain() - start a scheduling domain
5835  * @hw: dlb2_hw handle for a particular device.
5836  * @domain_id: domain ID.
5837  * @arg: start domain arguments.
5838  * @resp: response structure.
5839  * @vdev_req: indicates whether this request came from a vdev.
5840  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
5841  *
5842  * This function starts a scheduling domain, which allows applications to send
5843  * traffic through it. Once a domain is started, its resources can no longer be
5844  * configured (besides QID remapping and port enable/disable).
5845  *
5846  * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual
5847  * device.
5848  *
5849  * Return:
5850  * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
5851  * assigned a detailed error code from enum dlb2_error.
5852  *
5853  * Errors:
5854  * EINVAL - the domain is not configured, or the domain is already started.
5855  */
5856 int
dlb2_hw_start_domain(struct dlb2_hw * hw,u32 domain_id,struct dlb2_start_domain_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id)5857 dlb2_hw_start_domain(struct dlb2_hw *hw,
5858 		     u32 domain_id,
5859 		     struct dlb2_start_domain_args *args,
5860 		     struct dlb2_cmd_response *resp,
5861 		     bool vdev_req,
5862 		     unsigned int vdev_id)
5863 {
5864 	struct dlb2_list_entry *iter;
5865 	struct dlb2_dir_pq_pair *dir_queue;
5866 	struct dlb2_ldb_queue *ldb_queue;
5867 	struct dlb2_hw_domain *domain;
5868 	int ret;
5869 	RTE_SET_USED(args);
5870 	RTE_SET_USED(iter);
5871 
5872 	dlb2_log_start_domain(hw, domain_id, vdev_req, vdev_id);
5873 
5874 	ret = dlb2_verify_start_domain_args(hw,
5875 					    domain_id,
5876 					    resp,
5877 					    vdev_req,
5878 					    vdev_id,
5879 					    &domain);
5880 	if (ret)
5881 		return ret;
5882 
5883 	/*
5884 	 * Enable load-balanced and directed queue write permissions for the
5885 	 * queues this domain owns. Without this, the DLB2 will drop all
5886 	 * incoming traffic to those queues.
5887 	 */
5888 	DLB2_DOM_LIST_FOR(domain->used_ldb_queues, ldb_queue, iter) {
5889 		u32 vasqid_v = 0;
5890 		unsigned int offs;
5891 
5892 		DLB2_BIT_SET(vasqid_v, DLB2_SYS_LDB_VASQID_V_VASQID_V);
5893 
5894 		offs = domain->id.phys_id * DLB2_MAX_NUM_LDB_QUEUES +
5895 			ldb_queue->id.phys_id;
5896 
5897 		DLB2_CSR_WR(hw, DLB2_SYS_LDB_VASQID_V(offs), vasqid_v);
5898 	}
5899 
5900 	DLB2_DOM_LIST_FOR(domain->used_dir_pq_pairs, dir_queue, iter) {
5901 		u32 vasqid_v = 0;
5902 		unsigned int offs;
5903 
5904 		DLB2_BIT_SET(vasqid_v, DLB2_SYS_DIR_VASQID_V_VASQID_V);
5905 
5906 		offs = domain->id.phys_id * DLB2_MAX_NUM_DIR_PORTS(hw->ver) +
5907 			dir_queue->id.phys_id;
5908 
5909 		DLB2_CSR_WR(hw, DLB2_SYS_DIR_VASQID_V(offs), vasqid_v);
5910 	}
5911 
5912 	dlb2_flush_csr(hw);
5913 
5914 	domain->started = true;
5915 
5916 	resp->status = 0;
5917 
5918 	return 0;
5919 }
5920 
dlb2_log_get_dir_queue_depth(struct dlb2_hw * hw,u32 domain_id,u32 queue_id,bool vdev_req,unsigned int vf_id)5921 static void dlb2_log_get_dir_queue_depth(struct dlb2_hw *hw,
5922 					 u32 domain_id,
5923 					 u32 queue_id,
5924 					 bool vdev_req,
5925 					 unsigned int vf_id)
5926 {
5927 	DLB2_HW_DBG(hw, "DLB get directed queue depth:\n");
5928 	if (vdev_req)
5929 		DLB2_HW_DBG(hw, "(Request from VF %d)\n", vf_id);
5930 	DLB2_HW_DBG(hw, "\tDomain ID: %d\n", domain_id);
5931 	DLB2_HW_DBG(hw, "\tQueue ID: %d\n", queue_id);
5932 }
5933 
5934 /**
5935  * dlb2_hw_get_dir_queue_depth() - returns the depth of a directed queue
5936  * @hw: dlb2_hw handle for a particular device.
5937  * @domain_id: domain ID.
5938  * @args: queue depth args
5939  * @resp: response structure.
5940  * @vdev_req: indicates whether this request came from a vdev.
5941  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
5942  *
5943  * This function returns the depth of a directed queue.
5944  *
5945  * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual
5946  * device.
5947  *
5948  * Return:
5949  * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
5950  * assigned a detailed error code from enum dlb2_error. If successful, resp->id
5951  * contains the depth.
5952  *
5953  * Errors:
5954  * EINVAL - Invalid domain ID or queue ID.
5955  */
dlb2_hw_get_dir_queue_depth(struct dlb2_hw * hw,u32 domain_id,struct dlb2_get_dir_queue_depth_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id)5956 int dlb2_hw_get_dir_queue_depth(struct dlb2_hw *hw,
5957 				u32 domain_id,
5958 				struct dlb2_get_dir_queue_depth_args *args,
5959 				struct dlb2_cmd_response *resp,
5960 				bool vdev_req,
5961 				unsigned int vdev_id)
5962 {
5963 	struct dlb2_dir_pq_pair *queue;
5964 	struct dlb2_hw_domain *domain;
5965 	int id;
5966 
5967 	id = domain_id;
5968 
5969 	dlb2_log_get_dir_queue_depth(hw, domain_id, args->queue_id,
5970 				     vdev_req, vdev_id);
5971 
5972 	domain = dlb2_get_domain_from_id(hw, id, vdev_req, vdev_id);
5973 	if (!domain) {
5974 		resp->status = DLB2_ST_INVALID_DOMAIN_ID;
5975 		return -EINVAL;
5976 	}
5977 
5978 	id = args->queue_id;
5979 
5980 	queue = dlb2_get_domain_used_dir_pq(hw, id, vdev_req, domain);
5981 	if (!queue) {
5982 		resp->status = DLB2_ST_INVALID_QID;
5983 		return -EINVAL;
5984 	}
5985 
5986 	resp->id = dlb2_dir_queue_depth(hw, queue);
5987 
5988 	return 0;
5989 }
5990 
dlb2_log_get_ldb_queue_depth(struct dlb2_hw * hw,u32 domain_id,u32 queue_id,bool vdev_req,unsigned int vf_id)5991 static void dlb2_log_get_ldb_queue_depth(struct dlb2_hw *hw,
5992 					 u32 domain_id,
5993 					 u32 queue_id,
5994 					 bool vdev_req,
5995 					 unsigned int vf_id)
5996 {
5997 	DLB2_HW_DBG(hw, "DLB get load-balanced queue depth:\n");
5998 	if (vdev_req)
5999 		DLB2_HW_DBG(hw, "(Request from VF %d)\n", vf_id);
6000 	DLB2_HW_DBG(hw, "\tDomain ID: %d\n", domain_id);
6001 	DLB2_HW_DBG(hw, "\tQueue ID: %d\n", queue_id);
6002 }
6003 
6004 /**
6005  * dlb2_hw_get_ldb_queue_depth() - returns the depth of a load-balanced queue
6006  * @hw: dlb2_hw handle for a particular device.
6007  * @domain_id: domain ID.
6008  * @args: queue depth args
6009  * @resp: response structure.
6010  * @vdev_req: indicates whether this request came from a vdev.
6011  * @vdev_id: If vdev_req is true, this contains the vdev's ID.
6012  *
6013  * This function returns the depth of a load-balanced queue.
6014  *
6015  * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual
6016  * device.
6017  *
6018  * Return:
6019  * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is
6020  * assigned a detailed error code from enum dlb2_error. If successful, resp->id
6021  * contains the depth.
6022  *
6023  * Errors:
6024  * EINVAL - Invalid domain ID or queue ID.
6025  */
dlb2_hw_get_ldb_queue_depth(struct dlb2_hw * hw,u32 domain_id,struct dlb2_get_ldb_queue_depth_args * args,struct dlb2_cmd_response * resp,bool vdev_req,unsigned int vdev_id)6026 int dlb2_hw_get_ldb_queue_depth(struct dlb2_hw *hw,
6027 				u32 domain_id,
6028 				struct dlb2_get_ldb_queue_depth_args *args,
6029 				struct dlb2_cmd_response *resp,
6030 				bool vdev_req,
6031 				unsigned int vdev_id)
6032 {
6033 	struct dlb2_hw_domain *domain;
6034 	struct dlb2_ldb_queue *queue;
6035 
6036 	dlb2_log_get_ldb_queue_depth(hw, domain_id, args->queue_id,
6037 				     vdev_req, vdev_id);
6038 
6039 	domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id);
6040 	if (!domain) {
6041 		resp->status = DLB2_ST_INVALID_DOMAIN_ID;
6042 		return -EINVAL;
6043 	}
6044 
6045 	queue = dlb2_get_domain_ldb_queue(args->queue_id, vdev_req, domain);
6046 	if (!queue) {
6047 		resp->status = DLB2_ST_INVALID_QID;
6048 		return -EINVAL;
6049 	}
6050 
6051 	resp->id = dlb2_ldb_queue_depth(hw, queue);
6052 
6053 	return 0;
6054 }
6055 
6056 /**
6057  * dlb2_finish_unmap_qid_procedures() - finish any pending unmap procedures
6058  * @hw: dlb2_hw handle for a particular device.
6059  *
6060  * This function attempts to finish any outstanding unmap procedures.
6061  * This function should be called by the kernel thread responsible for
6062  * finishing map/unmap procedures.
6063  *
6064  * Return:
6065  * Returns the number of procedures that weren't completed.
6066  */
dlb2_finish_unmap_qid_procedures(struct dlb2_hw * hw)6067 unsigned int dlb2_finish_unmap_qid_procedures(struct dlb2_hw *hw)
6068 {
6069 	int i, num = 0;
6070 
6071 	/* Finish queue unmap jobs for any domain that needs it */
6072 	for (i = 0; i < DLB2_MAX_NUM_DOMAINS; i++) {
6073 		struct dlb2_hw_domain *domain = &hw->domains[i];
6074 
6075 		num += dlb2_domain_finish_unmap_qid_procedures(hw, domain);
6076 	}
6077 
6078 	return num;
6079 }
6080 
6081 /**
6082  * dlb2_finish_map_qid_procedures() - finish any pending map procedures
6083  * @hw: dlb2_hw handle for a particular device.
6084  *
6085  * This function attempts to finish any outstanding map procedures.
6086  * This function should be called by the kernel thread responsible for
6087  * finishing map/unmap procedures.
6088  *
6089  * Return:
6090  * Returns the number of procedures that weren't completed.
6091  */
dlb2_finish_map_qid_procedures(struct dlb2_hw * hw)6092 unsigned int dlb2_finish_map_qid_procedures(struct dlb2_hw *hw)
6093 {
6094 	int i, num = 0;
6095 
6096 	/* Finish queue map jobs for any domain that needs it */
6097 	for (i = 0; i < DLB2_MAX_NUM_DOMAINS; i++) {
6098 		struct dlb2_hw_domain *domain = &hw->domains[i];
6099 
6100 		num += dlb2_domain_finish_map_qid_procedures(hw, domain);
6101 	}
6102 
6103 	return num;
6104 }
6105 
6106 /**
6107  * dlb2_hw_enable_sparse_dir_cq_mode() - enable sparse mode for directed ports.
6108  * @hw: dlb2_hw handle for a particular device.
6109  *
6110  * This function must be called prior to configuring scheduling domains.
6111  */
6112 
dlb2_hw_enable_sparse_dir_cq_mode(struct dlb2_hw * hw)6113 void dlb2_hw_enable_sparse_dir_cq_mode(struct dlb2_hw *hw)
6114 {
6115 	u32 ctrl;
6116 
6117 	ctrl = DLB2_CSR_RD(hw, DLB2_CHP_CFG_CHP_CSR_CTRL);
6118 
6119 	DLB2_BIT_SET(ctrl,
6120 		     DLB2_CHP_CFG_CHP_CSR_CTRL_CFG_64BYTES_QE_DIR_CQ_MODE);
6121 
6122 	DLB2_CSR_WR(hw, DLB2_CHP_CFG_CHP_CSR_CTRL, ctrl);
6123 }
6124 
6125 /**
6126  * dlb2_hw_enable_sparse_ldb_cq_mode() - enable sparse mode for load-balanced
6127  *	ports.
6128  * @hw: dlb2_hw handle for a particular device.
6129  *
6130  * This function must be called prior to configuring scheduling domains.
6131  */
dlb2_hw_enable_sparse_ldb_cq_mode(struct dlb2_hw * hw)6132 void dlb2_hw_enable_sparse_ldb_cq_mode(struct dlb2_hw *hw)
6133 {
6134 	u32 ctrl;
6135 
6136 	ctrl = DLB2_CSR_RD(hw, DLB2_CHP_CFG_CHP_CSR_CTRL);
6137 
6138 	DLB2_BIT_SET(ctrl,
6139 		     DLB2_CHP_CFG_CHP_CSR_CTRL_CFG_64BYTES_QE_LDB_CQ_MODE);
6140 
6141 	DLB2_CSR_WR(hw, DLB2_CHP_CFG_CHP_CSR_CTRL, ctrl);
6142 }
6143 
6144 /**
6145  * dlb2_get_group_sequence_numbers() - return a group's number of SNs per queue
6146  * @hw: dlb2_hw handle for a particular device.
6147  * @group_id: sequence number group ID.
6148  *
6149  * This function returns the configured number of sequence numbers per queue
6150  * for the specified group.
6151  *
6152  * Return:
6153  * Returns -EINVAL if group_id is invalid, else the group's SNs per queue.
6154  */
dlb2_get_group_sequence_numbers(struct dlb2_hw * hw,u32 group_id)6155 int dlb2_get_group_sequence_numbers(struct dlb2_hw *hw, u32 group_id)
6156 {
6157 	if (group_id >= DLB2_MAX_NUM_SEQUENCE_NUMBER_GROUPS)
6158 		return -EINVAL;
6159 
6160 	return hw->rsrcs.sn_groups[group_id].sequence_numbers_per_queue;
6161 }
6162 
6163 /**
6164  * dlb2_get_group_sequence_number_occupancy() - return a group's in-use slots
6165  * @hw: dlb2_hw handle for a particular device.
6166  * @group_id: sequence number group ID.
6167  *
6168  * This function returns the group's number of in-use slots (i.e. load-balanced
6169  * queues using the specified group).
6170  *
6171  * Return:
6172  * Returns -EINVAL if group_id is invalid, else the group's SNs per queue.
6173  */
dlb2_get_group_sequence_number_occupancy(struct dlb2_hw * hw,u32 group_id)6174 int dlb2_get_group_sequence_number_occupancy(struct dlb2_hw *hw, u32 group_id)
6175 {
6176 	if (group_id >= DLB2_MAX_NUM_SEQUENCE_NUMBER_GROUPS)
6177 		return -EINVAL;
6178 
6179 	return dlb2_sn_group_used_slots(&hw->rsrcs.sn_groups[group_id]);
6180 }
6181 
dlb2_log_set_group_sequence_numbers(struct dlb2_hw * hw,u32 group_id,u32 val)6182 static void dlb2_log_set_group_sequence_numbers(struct dlb2_hw *hw,
6183 						u32 group_id,
6184 						u32 val)
6185 {
6186 	DLB2_HW_DBG(hw, "DLB2 set group sequence numbers:\n");
6187 	DLB2_HW_DBG(hw, "\tGroup ID: %u\n", group_id);
6188 	DLB2_HW_DBG(hw, "\tValue:    %u\n", val);
6189 }
6190 
6191 /**
6192  * dlb2_set_group_sequence_numbers() - assign a group's number of SNs per queue
6193  * @hw: dlb2_hw handle for a particular device.
6194  * @group_id: sequence number group ID.
6195  * @val: requested amount of sequence numbers per queue.
6196  *
6197  * This function configures the group's number of sequence numbers per queue.
6198  * val can be a power-of-two between 32 and 1024, inclusive. This setting can
6199  * be configured until the first ordered load-balanced queue is configured, at
6200  * which point the configuration is locked.
6201  *
6202  * Return:
6203  * Returns 0 upon success; -EINVAL if group_id or val is invalid, -EPERM if an
6204  * ordered queue is configured.
6205  */
dlb2_set_group_sequence_numbers(struct dlb2_hw * hw,u32 group_id,u32 val)6206 int dlb2_set_group_sequence_numbers(struct dlb2_hw *hw,
6207 				    u32 group_id,
6208 				    u32 val)
6209 {
6210 	const u32 valid_allocations[] = {64, 128, 256, 512, 1024};
6211 	struct dlb2_sn_group *group;
6212 	u32 sn_mode = 0;
6213 	int mode;
6214 
6215 	if (group_id >= DLB2_MAX_NUM_SEQUENCE_NUMBER_GROUPS)
6216 		return -EINVAL;
6217 
6218 	group = &hw->rsrcs.sn_groups[group_id];
6219 
6220 	/*
6221 	 * Once the first load-balanced queue using an SN group is configured,
6222 	 * the group cannot be changed.
6223 	 */
6224 	if (group->slot_use_bitmap != 0)
6225 		return -EPERM;
6226 
6227 	for (mode = 0; mode < DLB2_MAX_NUM_SEQUENCE_NUMBER_MODES; mode++)
6228 		if (val == valid_allocations[mode])
6229 			break;
6230 
6231 	if (mode == DLB2_MAX_NUM_SEQUENCE_NUMBER_MODES)
6232 		return -EINVAL;
6233 
6234 	group->mode = mode;
6235 	group->sequence_numbers_per_queue = val;
6236 
6237 	DLB2_BITS_SET(sn_mode, hw->rsrcs.sn_groups[0].mode,
6238 		 DLB2_RO_GRP_SN_MODE_SN_MODE_0);
6239 	DLB2_BITS_SET(sn_mode, hw->rsrcs.sn_groups[1].mode,
6240 		 DLB2_RO_GRP_SN_MODE_SN_MODE_1);
6241 
6242 	DLB2_CSR_WR(hw, DLB2_RO_GRP_SN_MODE(hw->ver), sn_mode);
6243 
6244 	dlb2_log_set_group_sequence_numbers(hw, group_id, val);
6245 
6246 	return 0;
6247 }
6248 
6249