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