Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_hal_queues.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 /**
34  * @file
35  *
36  */
37 
38 #include "ocs_os.h"
39 #include "ocs_hal.h"
40 #include "ocs_hal_queues.h"
41 
42 #define HAL_QTOP_DEBUG 0
43 
44 /**
45  * @brief Initialize queues
46  *
47  * Given the parsed queue topology spec, the SLI queues are created and
48  * initialized
49  *
50  * @param hal pointer to HAL object
51  * @param qtop pointer to queue topology
52  *
53  * @return returns 0 for success, an error code value for failure.
54  */
56 ocs_hal_init_queues(ocs_hal_t *hal, ocs_hal_qtop_t *qtop)
57 {
58  uint32_t i, j;
59  uint32_t default_lengths[QTOP_LAST], len;
60  ocs_hal_qtop_entry_t *qt, *next_qt;
61  ocs_hal_rqs_info_t rqs_info;
63 
64  hal_eq_t *eq = NULL;
65  hal_cq_t *cq = NULL;
66  hal_wq_t *wq = NULL;
67  hal_rq_t *rq = NULL;
68  hal_mq_t *mq = NULL;
69 
70  rqs_info.num_pairs = 0;
71  for (i = 0; i < OCS_HAL_MAX_MRQ_SETS; i++) {
72  memset(&mrq_sets[i], 0, sizeof(ocs_hal_mrq_info_t));
73  }
74 
75  default_lengths[QTOP_EQ] = OCS_HAL_EQ_ENTRIES_DEF;
76  default_lengths[QTOP_CQ] = hal->num_qentries[SLI_QTYPE_CQ];
77  default_lengths[QTOP_WQ] = hal->num_qentries[SLI_QTYPE_WQ];
78  default_lengths[QTOP_RQ] = OCS_HAL_RQ_ENTRIES_DEF;
79  default_lengths[QTOP_MQ] = OCS_HAL_MQ_ENTRIES_DEF;
80 
82 
83  hal->eq_count = 0;
84  hal->cq_count = 0;
85  hal->mq_count = 0;
86  hal->wq_count = 0;
87  hal->rq_count = 0;
88  hal->hal_rq_count = 0;
89  ocs_list_init(&hal->eq_list, hal_eq_t, link);
90 
91  /* Allocate class WQ pools */
92  for (i = 0; i < ARRAY_SIZE(hal->wq_class_array); i++) {
93  hal->wq_class_array[i] = ocs_varray_alloc(hal->os, OCS_HAL_MAX_NUM_WQ);
94  if (hal->wq_class_array[i] == NULL) {
95  ocs_log_err(hal->os, "ocs_varray_alloc for wq_class failed\n");
96  return OCS_HAL_RTN_NO_MEMORY;
97  }
98  }
99 
100  /* Allocate per CPU WQ pools */
101  for (i = 0; i < ARRAY_SIZE(hal->wq_cpu_array); i++) {
102  hal->wq_cpu_array[i] = ocs_varray_alloc(hal->os, OCS_HAL_MAX_NUM_WQ);
103  if (hal->wq_cpu_array[i] == NULL) {
104  ocs_log_err(hal->os, "ocs_varray_alloc for wq_class failed\n");
105  return OCS_HAL_RTN_NO_MEMORY;
106  }
107  }
108 
109  ocs_hal_assert(qtop != NULL);
110 
111  for (i = 0, qt = qtop->entries; i < qtop->inuse_count; i++, qt++) {
112  if (i == qtop->inuse_count - 1)
113  next_qt = NULL;
114  else
115  next_qt = qt + 1;
116 
117  switch(qt->entry) {
118  case QTOP_EQ:
119  len = (qt->len) ? qt->len : OCS_HAL_EQ_ENTRIES_DEF;
120 
121  /* Modify the Q length if qtop EQ len is not a valid value */
122  if (!ocs_qlen_valid(len, OCS_HAL_EQ_ENTRIES_MIN, hal->num_qentries[SLI_QTYPE_EQ])) {
123  ocs_log_info(hal->os, "QTOP EQ len %d is invalid; using EQ len %d\n",
124  len, default_lengths[QTOP_EQ]);
125  len = default_lengths[QTOP_EQ];
126  }
127 
128  if (qt->set_default) {
129  default_lengths[QTOP_EQ] = len;
130  break;
131  }
132 
133  eq = hal_new_eq(hal, len);
134  if (eq == NULL) {
135  goto fail;
136  }
137  eq->nvmeq = qt->nvmeq;
138 
139  if (!eq->nvmeq) {
140  eq->cpu_core = ocs_sched_cpu(eq->instance);
141  }
142  break;
143 
144  case QTOP_CQ:
145  len = (qt->len) ? qt->len : OCS_HAL_CQ_ENTRIES_DEF;
146 
147  /* Modify the Q length if qtop CQ len is not a valid value */
148  if (!ocs_qlen_valid(len, OCS_HAL_CQ_ENTRIES_MIN, hal->num_qentries[SLI_QTYPE_CQ])) {
149  ocs_log_info(hal->os, "QTOP CQ len %d is invalid; using CQ len %d\n",
150  len, default_lengths[QTOP_CQ]);
151  len = default_lengths[QTOP_CQ];
152  }
153 
154  if (qt->set_default) {
155  default_lengths[QTOP_CQ] = len;
156  break;
157  }
158 
159  if (eq && next_qt) {
160  /* If this CQ is for RQ, then delay the creation */
161  if (next_qt->entry != QTOP_RQ) {
162  cq = hal_new_cq(eq, len);
163  if (cq == NULL) {
164  goto fail;
165  }
166  }
167  } else {
168  goto fail;
169  }
170  break;
171 
172  case QTOP_WQ: {
173  uint32_t max_wq_entries;
174 
175  len = (qt->len) ? qt->len : OCS_HAL_WQ_ENTRIES_DEF;
176 
177  /* Limit the max WQ length to half the corresponding CQ length */
178  max_wq_entries = OCS_MIN((cq->entry_count / 2), hal->num_qentries[SLI_QTYPE_WQ]);
179 
180  /* Modify the Q length if qtop WQ len is not a valid value */
181  if (!ocs_qlen_valid(len, OCS_HAL_WQ_ENTRIES_MIN, max_wq_entries)) {
182  ocs_log_info(hal->os, "QTOP WQ len %d is invalid; using WQ len %d\n",
183  len, max_wq_entries);
184  len = max_wq_entries;
185  }
186 
187  if (qt->set_default) {
188  default_lengths[QTOP_WQ] = len;
189  break;
190  }
191 
192  if ((hal->ulp_start + qt->ulp) > hal->ulp_max) {
193  ocs_log_err(hal->os, "invalid ULP %d for WQ\n", qt->ulp);
194  goto fail;
195  }
196 
197  if (cq) {
198  wq = hal_new_wq(cq, len, qt->class, hal->ulp_start + qt->ulp);
199  if (wq == NULL) {
200  goto fail;
201  }
202  } else {
203  goto fail;
204  }
205 
206  if (!eq->nvmeq) {
207  /* Place this WQ on the EQ WQ array */
208  if (ocs_varray_add(eq->wq_array, wq)) {
209  ocs_log_err(hal->os, "QTOP_WQ: EQ ocs_varray_add failed\n");
210  goto fail;
211  }
212 
213  /* Place this WQ on the HAL class array */
214  if (qt->class < ARRAY_SIZE(hal->wq_class_array)) {
215  if (ocs_varray_add(hal->wq_class_array[qt->class], wq)) {
216  ocs_log_err(hal->os, "HAL wq_class_array ocs_varray_add failed\n");
217  goto fail;
218  }
219  } else {
220  ocs_log_err(hal->os, "Invalid class value: %d\n", qt->class);
221  goto fail;
222  }
223 
224  /*
225  * Place this WQ on the per CPU list, asumming that EQs are mapped to cpu given
226  * by the EQ instance modulo number of CPUs
227  */
228  if (ocs_varray_add(hal->wq_cpu_array[eq->cpu_core], wq)) {
229  ocs_log_err(hal->os, "HAL wq_cpu_array ocs_varray_add failed\n");
230  hal_queue_teardown(hal);
231  return OCS_HAL_RTN_ERROR;
232  }
233  }
234 
235  break;
236  }
237  case QTOP_RQ: {
238  len = (qt->len) ? qt->len : OCS_HAL_RQ_ENTRIES_DEF;
239 
240  /* Modify the Q length if qtop RQ len is not a valid value */
241  if (!ocs_qlen_valid(len, OCS_HAL_RQ_ENTRIES_MIN, hal->num_qentries[SLI_QTYPE_RQ])) {
242  ocs_log_info(hal->os, "QTOP RQ len %d is invalid; using RQ len %d\n",
243  len, default_lengths[QTOP_RQ]);
244  len = default_lengths[QTOP_RQ];
245  }
246 
247  if (qt->set_default) {
248  default_lengths[QTOP_RQ] = len;
249  break;
250  }
251 
252  if ((hal->ulp_start + qt->ulp) > hal->ulp_max) {
253  ocs_log_err(hal->os, "invalid ULP %d for RQ\n", qt->ulp);
254  goto fail;
255  }
256 
257  rqs_info.rq_cfg[rqs_info.num_pairs].len = len;
258  rqs_info.rq_cfg[rqs_info.num_pairs].ulp = hal->ulp_start + qt->ulp;
259  rqs_info.rq_cfg[rqs_info.num_pairs].filter_mask = qt->filter_mask;
260  rqs_info.rq_cfg[rqs_info.num_pairs].policy = qt->policy;
261  rqs_info.rq_cfg[rqs_info.num_pairs].eq = eq;
262  rqs_info.rq_cfg[rqs_info.num_pairs].protocol_valid = qt->protocol_valid;
263  rqs_info.rq_cfg[rqs_info.num_pairs].protocol = qt->protocol;
264  rqs_info.num_pairs ++;
265 
266  break;
267  }
268 
269  case QTOP_MQ:
270  len = (qt->len) ? qt->len : OCS_HAL_MQ_ENTRIES_DEF;
271 
272  /* Modify the Q length if qtop MQ len is not a valid value */
273  if (!ocs_qlen_valid(len, OCS_HAL_MQ_ENTRIES_MIN, hal->num_qentries[SLI_QTYPE_MQ])) {
274  ocs_log_info(hal->os, "QTOP MQ len %d is invalid; using MQ len %d\n",
275  len, default_lengths[QTOP_MQ]);
276  len = default_lengths[QTOP_MQ];
277  }
278 
279  if (qt->set_default) {
280  default_lengths[QTOP_MQ] = len;
281  break;
282  }
283 
284  if (cq) {
285  mq = hal_new_mq(cq, len);
286  if (mq == NULL) {
287  goto fail;
288  }
289  } else {
290  goto fail;
291  }
292  break;
293 
294  default:
295  ocs_hal_assert(0);
296  break;
297  }
298  }
299 
300  /* Now create RQs.
301  * Note: If more than one RQ have same filter mask, Then they should be created
302  * using SET, Else we should create as a normal RQ pair.
303  */
304  for (i = 0; i < rqs_info.num_pairs; i++) {
305 
306  /* Check if any other RQ have same filter mask. */
307  for (j = 0; j < rqs_info.num_pairs; j++) {
308  if ((i != j) && (rqs_info.rq_cfg[i].filter_mask ==
309  rqs_info.rq_cfg[j].filter_mask)) {
310 
311  int id = -1, k;
312 
313  /* If we get here then it means this RQ belongs to a set. */
314 
315  /* Find out which set it should go to. */
316  for (k = 0; k < OCS_HAL_MAX_MRQ_SETS; k++) {
317  if (mrq_sets[k].filter_mask == rqs_info.rq_cfg[i].filter_mask) {
318  id = k;
319  break;
320  }
321  if ((id < 0) && !mrq_sets[k].num_pairs) {
322  /* First free slot */
323  id = k;
324  }
325  }
326 
327  if (id < 0) {
328  ocs_log_crit(hal->os, "Can't create more than %d RQ Sets\n",
329  OCS_HAL_MAX_MRQ_SETS);
330  goto fail;
331  }
332 
333  if (!mrq_sets[id].num_pairs) {
334  /* Just copy once for first RQ in the set. */
335  mrq_sets[id].len = rqs_info.rq_cfg[i].len;
336  mrq_sets[id].filter_mask = rqs_info.rq_cfg[i].filter_mask;
337  mrq_sets[id].ulp = rqs_info.rq_cfg[i].ulp;
338  mrq_sets[id].policy = rqs_info.rq_cfg[i].policy;
339  mrq_sets[id].protocol_valid = rqs_info.rq_cfg[i].protocol_valid;
340  mrq_sets[id].protocol = rqs_info.rq_cfg[i].protocol;
341  mrq_sets[id].nvmeq = rqs_info.rq_cfg[i].eq->nvmeq;
342  }
343 
344  /* This differs for each RQ in the set. */
345  mrq_sets[id].eqs[mrq_sets[id].num_pairs] = rqs_info.rq_cfg[i].eq;
346 
347  mrq_sets[id].num_pairs ++;
348  break;
349  }
350  }
351 
352  if (j == rqs_info.num_pairs) {
353  /* No other RQ has same filter mask. This means a normal RQ PAIR */
354  cq = hal_new_cq(rqs_info.rq_cfg[i].eq, default_lengths[QTOP_CQ]);
355  if (cq == NULL) {
356  goto fail;
357  }
358 
359  rq = hal_new_rq(cq, rqs_info.rq_cfg[i].len, rqs_info.rq_cfg[i].ulp);
360  if (rq == NULL) {
361  goto fail;
362  }
363  rq->filter_mask = rqs_info.rq_cfg[i].filter_mask;
364  rq->nvmeq = rqs_info.rq_cfg[i].eq->nvmeq;
365  }
366  }
367 
368  /* Now create RQ Set */
369  for (j = 0; j < OCS_HAL_MAX_MRQ_SETS; j++) {
370  hal_cq_t *cqs[OCE_HAL_MAX_NUM_MRQ_PAIRS] = { NULL };
371  hal_rq_t *rqs[OCE_HAL_MAX_NUM_MRQ_PAIRS] = { NULL };
372 
373  if (!mrq_sets[j].num_pairs) {
374  continue; /* Not used */
375  }
376 
377  if (mrq_sets[j].num_pairs > OCE_HAL_MAX_NUM_MRQ_PAIRS) {
378  ocs_log_crit(hal->os, "Max Supported MRQ pairs = %d\n",
380  goto fail;
381  }
382 
383  if (!hal->hal_mrq_used) {
384  if (!hal->sli.config.features.flag.mrqp) {
385  ocs_log_err(hal->os, "MRQ not supported by SLI4.\n");
386  goto fail;
387  }
388  hal->hal_mrq_used = TRUE;
389  }
390 
391  /* Create CQ set */
392  if (hal_new_cq_set(mrq_sets[j].eqs, cqs, mrq_sets[j].num_pairs,
393  default_lengths[QTOP_CQ])) {
394  goto fail;
395  }
396 
397  /* Create RQ set */
398  if (hal_new_rq_set(cqs, rqs, mrq_sets[j].num_pairs,
399  mrq_sets[j].len, mrq_sets[j].ulp)) {
400  goto fail;
401  }
402 
403  for (i = 0; i < mrq_sets[j].num_pairs; i++) {
404  rqs[i]->filter_mask = mrq_sets[j].filter_mask;
405  rqs[i]->policy = mrq_sets[j].policy;
406  rqs[i]->nvmeq = mrq_sets[j].nvmeq;
407  rqs[i]->is_mrq = TRUE;
408  rqs[i]->base_mrq_id = rqs[0]->hdr->id;
409  rqs[i]->mrq_set_count = mrq_sets[j].num_pairs;
410  rqs[i]->mrq_set_num = j;
411  rqs[i]->protocol_valid = mrq_sets[j].protocol_valid;
412  rqs[i]->protocol = mrq_sets[j].protocol;
413  }
414 
415  }
416  return OCS_HAL_RTN_SUCCESS;
417 fail:
418  hal_queue_teardown(hal);
419  return OCS_HAL_RTN_ERROR;
420 }
421 
422 /**
423  * @brief Allocate a new EQ object
424  *
425  * A new EQ object is instantiated
426  *
427  * @param hal pointer to HAL object
428  * @param entry_count number of entries in the EQ
429  *
430  * @return pointer to allocated EQ object
431  */
432 hal_eq_t*
433 hal_new_eq(ocs_hal_t *hal, uint32_t entry_count)
434 {
435  hal_eq_t *eq = ocs_malloc(hal->os, sizeof(*eq), OCS_M_ZERO | OCS_M_NOWAIT);
436 
437  if (eq != NULL) {
438  eq->type = SLI_QTYPE_EQ;
439  eq->hal = hal;
440  eq->entry_count = entry_count;
441  eq->instance = hal->eq_count++;
442  eq->queue = hal->eq[eq->instance];
443  ocs_list_init(&eq->cq_list, hal_cq_t, link);
444 
445  eq->wq_array = ocs_varray_alloc(hal->os, OCS_HAL_MAX_NUM_WQ);
446  if (eq->wq_array == NULL) {
447  ocs_free(hal->os, eq, sizeof(*eq));
448  eq = NULL;
449  } else {
450  if (sli_queue_alloc(&hal->sli, SLI_QTYPE_EQ, eq->queue, entry_count, NULL, 0)) {
451  ocs_log_err(hal->os, "EQ[%d] allocation failure\n", eq->instance);
452  ocs_free(hal->os, eq, sizeof(*eq));
453  eq = NULL;
454  } else {
455  sli_eq_modify_delay(&hal->sli, eq->queue, 1, 0, 8);
456  hal->hal_eq[eq->instance] = eq;
457  ocs_list_add_tail(&hal->eq_list, eq);
458  ocs_log_debug(hal->os, "create eq[%2d] id %3d len %4d\n", eq->instance, eq->queue->id,
459  eq->entry_count);
460  }
461  }
462  }
463  return eq;
464 }
465 
466 /**
467  * @brief Allocate a new CQ object
468  *
469  * A new CQ object is instantiated
470  *
471  * @param eq pointer to parent EQ object
472  * @param entry_count number of entries in the CQ
473  *
474  * @return pointer to allocated CQ object
475  */
476 hal_cq_t*
477 hal_new_cq(hal_eq_t *eq, uint32_t entry_count)
478 {
479  ocs_hal_t *hal = eq->hal;
480  hal_cq_t *cq = ocs_malloc(hal->os, sizeof(*cq), OCS_M_ZERO | OCS_M_NOWAIT);
481 
482  if (cq != NULL) {
483  cq->eq = eq;
484  cq->type = SLI_QTYPE_CQ;
485  cq->instance = eq->hal->cq_count++;
486  cq->entry_count = entry_count;
487  cq->queue = hal->cq[cq->instance];
488 
489  ocs_list_init(&cq->q_list, hal_q_t, link);
490 
491  if (sli_queue_alloc(&hal->sli, SLI_QTYPE_CQ, cq->queue, cq->entry_count, eq->queue, 0)) {
492  ocs_log_err(hal->os, "CQ[%d] allocation failure len=%d\n",
493  eq->instance,
494  eq->entry_count);
495  ocs_free(hal->os, cq, sizeof(*cq));
496  cq = NULL;
497  } else {
498  hal->hal_cq[cq->instance] = cq;
499  ocs_list_add_tail(&eq->cq_list, cq);
500  ocs_log_debug(hal->os, "create cq[%2d] id %3d len %4d\n", cq->instance, cq->queue->id,
501  cq->entry_count);
502  }
503  }
504  return cq;
505 }
506 
507 /**
508  * @brief Allocate a new CQ Set of objects.
509  *
510  * @param eqs pointer to a set of EQ objects.
511  * @param cqs pointer to a set of CQ objects to be returned.
512  * @param num_cqs number of CQ queues in the set.
513  * @param entry_count number of entries in the CQ.
514  *
515  * @return 0 on success and -1 on failure.
516  */
517 uint32_t
518 hal_new_cq_set(hal_eq_t *eqs[], hal_cq_t *cqs[], uint32_t num_cqs, uint32_t entry_count)
519 {
520  uint32_t i;
521  ocs_hal_t *hal = eqs[0]->hal;
522  sli4_t *sli4 = &hal->sli;
523  hal_cq_t *cq = NULL;
525 
526  /* Initialise CQS pointers to NULL */
527  for (i = 0; i < num_cqs; i++) {
528  cqs[i] = NULL;
529  }
530 
531  for (i = 0; i < num_cqs; i++) {
532  cq = ocs_malloc(hal->os, sizeof(*cq), OCS_M_ZERO | OCS_M_NOWAIT);
533  if (cq == NULL)
534  goto error;
535 
536  cqs[i] = cq;
537  cq->eq = eqs[i];
538  cq->type = SLI_QTYPE_CQ;
539  cq->instance = hal->cq_count++;
540  cq->entry_count = entry_count;
541  cq->queue = hal->cq[cq->instance];
542  qs[i] = cq->queue;
543  assocs[i] = eqs[i]->queue;
544  ocs_list_init(&cq->q_list, hal_q_t, link);
545  }
546 
547  if (sli_cq_alloc_set(sli4, qs, num_cqs, entry_count, assocs)) {
548  ocs_log_err(NULL, "Failed to create CQ Set. \n");
549  goto error;
550  }
551 
552  for (i = 0; i < num_cqs; i++) {
553  hal->hal_cq[cqs[i]->instance] = cqs[i];
554  ocs_list_add_tail(&cqs[i]->eq->cq_list, cqs[i]);
555  }
556 
557  return 0;
558 
559 error:
560  for (i = 0; i < num_cqs; i++) {
561  if (cqs[i]) {
562  ocs_free(hal->os, cqs[i], sizeof(*cqs[i]));
563  cqs[i] = NULL;
564  }
565  }
566  return -1;
567 }
568 
569 
570 /**
571  * @brief Allocate a new MQ object
572  *
573  * A new MQ object is instantiated
574  *
575  * @param cq pointer to parent CQ object
576  * @param entry_count number of entries in the MQ
577  *
578  * @return pointer to allocated MQ object
579  */
580 hal_mq_t*
581 hal_new_mq(hal_cq_t *cq, uint32_t entry_count)
582 {
583  ocs_hal_t *hal = cq->eq->hal;
584  hal_mq_t *mq = ocs_malloc(hal->os, sizeof(*mq), OCS_M_ZERO | OCS_M_NOWAIT);
585 
586  if (mq != NULL) {
587  mq->cq = cq;
588  mq->type = SLI_QTYPE_MQ;
589  mq->instance = cq->eq->hal->mq_count++;
590  mq->entry_count = entry_count;
591  mq->queue = hal->mq[mq->instance];
592 
593  if (sli_queue_alloc(&hal->sli, SLI_QTYPE_MQ,
594  mq->queue,
595  mq->entry_count,
596  cq->queue, 0)) {
597  ocs_log_err(hal->os, "MQ allocation failure\n");
598  ocs_free(hal->os, mq, sizeof(*mq));
599  mq = NULL;
600  } else {
601  hal->hal_mq[mq->instance] = mq;
602  ocs_list_add_tail(&cq->q_list, mq);
603  ocs_log_debug(hal->os, "create mq[%2d] id %3d len %4d\n", mq->instance, mq->queue->id,
604  mq->entry_count);
605  }
606  }
607  return mq;
608 }
609 
610 /**
611  * @brief Allocate a new WQ object
612  *
613  * A new WQ object is instantiated
614  *
615  * @param cq pointer to parent CQ object
616  * @param entry_count number of entries in the WQ
617  * @param class WQ class
618  * @param ulp index of chute
619  *
620  * @return pointer to allocated WQ object
621  */
622 hal_wq_t*
623 hal_new_wq(hal_cq_t *cq, uint32_t entry_count, uint32_t class, uint32_t ulp)
624 {
625  ocs_hal_t *hal = cq->eq->hal;
626  hal_wq_t *wq = ocs_malloc(hal->os, sizeof(*wq), OCS_M_ZERO | OCS_M_NOWAIT);
627 
628  if (wq != NULL) {
629  wq->hal = cq->eq->hal;
630  wq->cq = cq;
631  wq->type = SLI_QTYPE_WQ;
632  wq->instance = cq->eq->hal->wq_count++;
633  wq->entry_count = entry_count;
634  wq->queue = hal->wq[wq->instance];
635  wq->ulp = ulp;
636  wq->wqec_set_count = OCS_HAL_WQEC_SET_COUNT;
637  wq->wqec_count = wq->wqec_set_count;
638  wq->free_count = wq->entry_count - 1;
639  wq->class = class;
640  ocs_list_init(&wq->pending_list, ocs_hal_wqe_t, link);
641 
642  if (sli_queue_alloc(&hal->sli, SLI_QTYPE_WQ, wq->queue, wq->entry_count, cq->queue, ulp)) {
643  ocs_log_err(hal->os, "WQ allocation failure\n");
644  ocs_free(hal->os, wq, sizeof(*wq));
645  wq = NULL;
646  } else {
647  hal->hal_wq[wq->instance] = wq;
648  ocs_list_add_tail(&cq->q_list, wq);
649  ocs_log_debug(hal->os, "create wq[%2d] id %3d len %4d cls %d ulp %d\n", wq->instance, wq->queue->id,
650  wq->entry_count, wq->class, wq->ulp);
651  }
652  }
653  return wq;
654 }
655 
656 /**
657  * @brief Allocate a hal_rq_t object
658  *
659  * Allocate an RQ object, which encapsulates 2 SLI queues (for rq pair)
660  *
661  * @param cq pointer to parent CQ object
662  * @param entry_count number of entries in the RQs
663  * @param ulp ULP index for this RQ
664  *
665  * @return pointer to newly allocated hal_rq_t
666  */
667 hal_rq_t*
668 hal_new_rq(hal_cq_t *cq, uint32_t entry_count, uint32_t ulp)
669 {
670  ocs_hal_t *hal = cq->eq->hal;
671  hal_rq_t *rq = ocs_malloc(hal->os, sizeof(*rq), OCS_M_ZERO | OCS_M_NOWAIT);
672 
673  if (rq != NULL) {
674  rq->instance = hal->hal_rq_count++;
675  rq->cq = cq;
676  rq->type = SLI_QTYPE_RQ;
677  rq->ulp = ulp;
678  rq->entry_count = entry_count;
679 
680  /* Create the header RQ */
681  ocs_hal_assert(hal->rq_count < OCS_HAL_MAX_NUM_RQ);
682  rq->hdr = hal->rq[hal->rq_count];
683  rq->hdr_entry_size = OCS_HAL_RQ_HEADER_SIZE;
684 
685  if (sli_fc_rq_alloc(&hal->sli, rq->hdr,
686  rq->entry_count,
687  rq->hdr_entry_size,
688  cq->queue,
689  ulp, TRUE)) {
690  ocs_log_err(hal->os, "RQ allocation failure - header\n");
691  ocs_free(hal->os, rq, sizeof(*rq));
692  return NULL;
693  }
694  hal->hal_rq_lookup[hal->rq_count] = rq->instance; /* Update hal_rq_lookup[] */
695  hal->rq_count++;
696  ocs_log_debug(hal->os, "create rq[%2d] id %3d len %4d hdr size %4d ulp %d\n",
697  rq->instance, rq->hdr->id, rq->entry_count, rq->hdr_entry_size, rq->ulp);
698 
699  /* Create the default data RQ */
700  ocs_hal_assert(hal->rq_count < OCS_HAL_MAX_NUM_RQ);
701  rq->data = hal->rq[hal->rq_count];
702  rq->data_entry_size = hal->config.rq_default_buffer_size;
703 
704  if (sli_fc_rq_alloc(&hal->sli, rq->data,
705  rq->entry_count,
706  rq->data_entry_size,
707  cq->queue,
708  ulp, FALSE)) {
709  ocs_log_err(hal->os, "RQ allocation failure - first burst\n");
710  ocs_free(hal->os, rq, sizeof(*rq));
711  return NULL;
712  }
713  hal->hal_rq_lookup[hal->rq_count] = rq->instance; /* Update hal_rq_lookup[] */
714  hal->rq_count++;
715  ocs_log_debug(hal->os, "create rq[%2d] id %3d len %4d data size %4d ulp %d\n", rq->instance,
716  rq->data->id, rq->entry_count, rq->data_entry_size, rq->ulp);
717 
718  hal->hal_rq[rq->instance] = rq;
719  ocs_list_add_tail(&cq->q_list, rq);
720 
721  rq->rq_tracker = ocs_malloc(hal->os, sizeof(ocs_hal_sequence_t*) *
722  rq->entry_count, OCS_M_ZERO | OCS_M_NOWAIT);
723  if (rq->rq_tracker == NULL) {
724  ocs_log_err(hal->os, "RQ tracker buf allocation failure\n");
725  return NULL;
726  }
727  }
728  return rq;
729 }
730 
731 
732 /**
733  * @brief Allocate a hal_rq_t object SET
734  *
735  * Allocate an RQ object SET, where each element in set
736  * encapsulates 2 SLI queues (for rq pair)
737  *
738  * @param cqs pointers to be associated with RQs.
739  * @param rqs RQ pointers to be returned on success.
740  * @param num_rq_pairs number of rq pairs in the Set.
741  * @param entry_count number of entries in the RQs
742  * @param ulp ULP index for this RQ
743  *
744  * @return 0 in success and -1 on failure.
745  */
746 uint32_t
747 hal_new_rq_set(hal_cq_t *cqs[], hal_rq_t *rqs[], uint32_t num_rq_pairs, uint32_t entry_count, uint32_t ulp)
748 {
749  ocs_hal_t *hal = cqs[0]->eq->hal;
750  hal_rq_t *rq = NULL;
751  sli4_queue_t *qs[SLI_MAX_RQ_SET_COUNT * 2] = { NULL };
752  uint32_t i, q_count;
753 
754  /* Initialise RQS pointers */
755  for (i = 0; i < num_rq_pairs; i++) {
756  rqs[i] = NULL;
757  }
758 
759  for (i = 0, q_count = 0; i < num_rq_pairs; i++, q_count += 2) {
760  rq = ocs_malloc(hal->os, sizeof(*rq), OCS_M_ZERO | OCS_M_NOWAIT);
761  if (rq == NULL)
762  goto error;
763 
764  rqs[i] = rq;
765  rq->instance = hal->hal_rq_count++;
766  rq->cq = cqs[i];
767  rq->type = SLI_QTYPE_RQ;
768  rq->ulp = ulp;
769  rq->entry_count = entry_count;
770 
771  /* Header RQ */
772  rq->hdr = hal->rq[hal->rq_count];
773  rq->hdr_entry_size = OCS_HAL_RQ_HEADER_SIZE;
774  hal->hal_rq_lookup[hal->rq_count] = rq->instance;
775  hal->rq_count++;
776  qs[q_count] = rq->hdr;
777 
778  /* Data RQ */
779  rq->data = hal->rq[hal->rq_count];
780  rq->data_entry_size = hal->config.rq_default_buffer_size;
781  hal->hal_rq_lookup[hal->rq_count] = rq->instance;
782  hal->rq_count++;
783  qs[q_count + 1] = rq->data;
784 
785  rq->rq_tracker = NULL;
786  }
787 
788  if (sli_fc_rq_set_alloc(&hal->sli, num_rq_pairs, qs,
789  cqs[0]->queue->id,
790  rqs[0]->entry_count,
791  rqs[0]->hdr_entry_size,
792  rqs[0]->data_entry_size,
793  ulp)) {
794  ocs_log_err(hal->os, "RQ Set allocation failure for base CQ=%d\n", cqs[0]->queue->id);
795  goto error;
796  }
797 
798 
799  for (i = 0; i < num_rq_pairs; i++) {
800  hal->hal_rq[rqs[i]->instance] = rqs[i];
801  ocs_list_add_tail(&cqs[i]->q_list, rqs[i]);
802  rqs[i]->rq_tracker = ocs_malloc(hal->os, sizeof(ocs_hal_sequence_t*) *
803  rqs[i]->entry_count, OCS_M_ZERO | OCS_M_NOWAIT);
804  if (rqs[i]->rq_tracker == NULL) {
805  ocs_log_err(hal->os, "RQ tracker buf allocation failure\n");
806  goto error;
807  }
808  }
809 
810  return 0;
811 
812 error:
813  for (i = 0; i < num_rq_pairs; i++) {
814  if (rqs[i] != NULL) {
815  if (rqs[i]->rq_tracker != NULL) {
816  ocs_free(hal->os, rqs[i]->rq_tracker,
817  sizeof(ocs_hal_sequence_t*) * rqs[i]->entry_count);
818  }
819  ocs_free(hal->os, rqs[i], sizeof(*rqs[i]));
820  }
821  }
822 
823  return -1;
824 }
825 
826 
827 /**
828  * @brief Free an EQ object
829  *
830  * The EQ object and any child queue objects are freed
831  *
832  * @param eq pointer to EQ object
833  *
834  * @return none
835  */
836 void
837 hal_del_eq(hal_eq_t *eq)
838 {
839  if (eq != NULL) {
840  hal_cq_t *cq;
841  hal_cq_t *cq_next;
842 
843  ocs_list_foreach_safe(&eq->cq_list, cq, cq_next) {
844  hal_del_cq(cq);
845  }
846  ocs_varray_free(eq->wq_array);
847  ocs_list_remove(&eq->hal->eq_list, eq);
848  eq->hal->hal_eq[eq->instance] = NULL;
849  ocs_free(eq->hal->os, eq, sizeof(*eq));
850  }
851 }
852 
853 /**
854  * @brief Free a CQ object
855  *
856  * The CQ object and any child queue objects are freed
857  *
858  * @param cq pointer to CQ object
859  *
860  * @return none
861  */
862 void
863 hal_del_cq(hal_cq_t *cq)
864 {
865  if (cq != NULL) {
866  hal_q_t *q;
867  hal_q_t *q_next;
868 
869  ocs_list_foreach_safe(&cq->q_list, q, q_next) {
870  switch(q->type) {
871  case SLI_QTYPE_MQ:
872  hal_del_mq((hal_mq_t*) q);
873  break;
874  case SLI_QTYPE_WQ:
875  hal_del_wq((hal_wq_t*) q);
876  break;
877  case SLI_QTYPE_RQ:
878  hal_del_rq((hal_rq_t*) q);
879  break;
880  default:
881  break;
882  }
883  }
884  ocs_list_remove(&cq->eq->cq_list, cq);
885  cq->eq->hal->hal_cq[cq->instance] = NULL;
886  ocs_free(cq->eq->hal->os, cq, sizeof(*cq));
887  }
888 }
889 
890 /**
891  * @brief Free a MQ object
892  *
893  * The MQ object is freed
894  *
895  * @param mq pointer to MQ object
896  *
897  * @return none
898  */
899 void
900 hal_del_mq(hal_mq_t *mq)
901 {
902  if (mq != NULL) {
903  ocs_list_remove(&mq->cq->q_list, mq);
904  mq->cq->eq->hal->hal_mq[mq->instance] = NULL;
905  ocs_free(mq->cq->eq->hal->os, mq, sizeof(*mq));
906  }
907 }
908 
909 /**
910  * @brief Free a WQ object
911  *
912  * The WQ object is freed
913  *
914  * @param wq pointer to WQ object
915  *
916  * @return none
917  */
918 void
919 hal_del_wq(hal_wq_t *wq)
920 {
921  if (wq != NULL) {
922  ocs_list_remove(&wq->cq->q_list, wq);
923  wq->cq->eq->hal->hal_wq[wq->instance] = NULL;
924  ocs_free(wq->cq->eq->hal->os, wq, sizeof(*wq));
925  }
926 }
927 
928 /**
929  * @brief Free an RQ object
930  *
931  * The RQ object is freed
932  *
933  * @param rq pointer to RQ object
934  *
935  * @return none
936  */
937 void
938 hal_del_rq(hal_rq_t *rq)
939 {
940  ocs_hal_t *hal = NULL;
941 
942  if (rq != NULL) {
943  hal = rq->cq->eq->hal;
944 
945  /* Free RQ tracker */
946  if (rq->rq_tracker != NULL) {
947  ocs_free(hal->os, rq->rq_tracker, sizeof(ocs_hal_sequence_t*) * rq->entry_count);
948  rq->rq_tracker = NULL;
949  }
950 
951  ocs_list_remove(&rq->cq->q_list, rq);
952  hal->hal_rq[rq->instance] = NULL;
953  ocs_free(hal->os, rq, sizeof(*rq));
954  }
955 }
956 
957 /**
958  * @brief Display HAL queue objects
959  *
960  * The HAL queue objects are displayed using ocs_log
961  *
962  * @param hal pointer to HAL object
963  *
964  * @return none
965  */
966 void
967 hal_queue_dump(ocs_hal_t *hal)
968 {
969  hal_eq_t *eq;
970  hal_cq_t *cq;
971  hal_q_t *q;
972  hal_mq_t *mq;
973  hal_wq_t *wq;
974  hal_rq_t *rq;
975 
976  ocs_list_foreach(&hal->eq_list, eq) {
977  ocs_printf("eq[%d] id %2d\n", eq->instance, eq->queue->id);
978  ocs_list_foreach(&eq->cq_list, cq) {
979  ocs_printf(" cq[%d] id %2d current\n", cq->instance, cq->queue->id);
980  ocs_list_foreach(&cq->q_list, q) {
981  switch(q->type) {
982  case SLI_QTYPE_MQ:
983  mq = (hal_mq_t *) q;
984  ocs_printf(" mq[%d] id %2d\n", mq->instance, mq->queue->id);
985  break;
986  case SLI_QTYPE_WQ:
987  wq = (hal_wq_t *) q;
988  ocs_printf(" wq[%d] id %2d\n", wq->instance, wq->queue->id);
989  break;
990  case SLI_QTYPE_RQ:
991  rq = (hal_rq_t *) q;
992  ocs_printf(" rq[%d] hdr id %2d\n", rq->instance, rq->hdr->id);
993  break;
994  default:
995  break;
996  }
997  }
998  }
999  }
1000 }
1001 
1002 /**
1003  * @brief Teardown HAL queue objects
1004  *
1005  * The HAL queue objects are freed
1006  *
1007  * @param hal pointer to HAL object
1008  *
1009  * @return none
1010  */
1011 void
1012 hal_queue_teardown(ocs_hal_t *hal)
1013 {
1014  uint32_t i;
1015  hal_eq_t *eq;
1016  hal_eq_t *eq_next;
1017 
1018  if (ocs_list_valid(&hal->eq_list)) {
1019  ocs_list_foreach_safe(&hal->eq_list, eq, eq_next) {
1020  hal_del_eq(eq);
1021  }
1022  }
1023  for (i = 0; i < ARRAY_SIZE(hal->wq_cpu_array); i++) {
1024  ocs_varray_free(hal->wq_cpu_array[i]);
1025  hal->wq_cpu_array[i] = NULL;
1026  }
1027  for (i = 0; i < ARRAY_SIZE(hal->wq_class_array); i++) {
1028  ocs_varray_free(hal->wq_class_array[i]);
1029  hal->wq_class_array[i] = NULL;
1030  }
1031 }
1032 
1033 /**
1034  * @brief Allocate a WQ to an IO object
1035  *
1036  * The next work queue index is used to assign a WQ to an IO.
1037  *
1038  * If wq_steering is OCS_HAL_WQ_STEERING_CLASS, a WQ from io->wq_class is
1039  * selected.
1040  *
1041  * If wq_steering is OCS_HAL_WQ_STEERING_REQUEST, then a WQ from the EQ that
1042  * the IO request came in on is selected.
1043  *
1044  * If wq_steering is OCS_HAL_WQ_STEERING_CPU, then a WQ associted with the
1045  * CPU the request is made on is selected.
1046  *
1047  * @param hal pointer to HAL object
1048  * @param io pointer to IO object
1049  *
1050  * @return Return pointer to next WQ
1051  */
1052 hal_wq_t *
1053 ocs_hal_queue_next_wq(ocs_hal_t *hal, ocs_hal_io_t *io)
1054 {
1055  hal_eq_t *eq;
1056  hal_wq_t *wq = NULL;
1057 
1058  switch(io->wq_steering) {
1060  if (likely(io->wq_class < ARRAY_SIZE(hal->wq_class_array))) {
1061  wq = ocs_varray_iter_next(hal->wq_class_array[io->wq_class]);
1062  }
1063  break;
1065  eq = io->eq;
1066  if (likely(eq != NULL)) {
1067  wq = ocs_varray_iter_next(eq->wq_array);
1068  }
1069  break;
1070  case OCS_HAL_WQ_STEERING_CPU: {
1071  uint32_t cpuidx = ocs_thread_getcpu();
1072 
1073  if (likely(cpuidx < ARRAY_SIZE(hal->wq_cpu_array))) {
1074  wq = ocs_varray_iter_next(hal->wq_cpu_array[cpuidx]);
1075  }
1076  break;
1077  }
1078  }
1079 
1080  if (unlikely(wq == NULL)) {
1081  wq = hal->hal_wq[0];
1082  }
1083 
1084  return wq;
1085 }
1086 
1087 /**
1088  * @brief Return count of EQs for a queue topology object
1089  *
1090  * The EQ count for in the HALs queue topology (hal->qtop) object is returned
1091  *
1092  * @param hal pointer to HAL object
1093  *
1094  * @return count of EQs
1095  */
1096 uint32_t
1097 ocs_hal_qtop_eq_count(ocs_hal_t *hal)
1098 {
1099  return hal->qtop->entry_counts[QTOP_EQ];
1100 }
1101 
1102 #define TOKEN_LEN 32
1103 
1104 /**
1105  * @brief return string given a QTOP entry
1106  *
1107  * @param entry QTOP entry
1108  *
1109  * @return returns string or "unknown"
1110  */
1111 #if HAL_QTOP_DEBUG
1112 static char *
1113 qtopentry2s(ocs_hal_qtop_entry_e entry) {
1114  switch(entry) {
1115  #define P(x) case x: return #x;
1116  P(QTOP_EQ)
1117  P(QTOP_CQ)
1118  P(QTOP_WQ)
1119  P(QTOP_RQ)
1120  P(QTOP_MQ)
1121  P(QTOP_THREAD_START)
1122  P(QTOP_THREAD_END)
1123  P(QTOP_LAST)
1124  #undef P
1125  }
1126  return "unknown";
1127 }
1128 #endif
1129 
1130 /**
1131  * @brief Declare token types
1132  */
1133 typedef enum {
1143 } tok_type_e;
1144 
1145 /**
1146  * @brief Declare token sub-types
1147  */
1148 typedef enum {
1149  TOK_SUB_EQ = 100,
1160 } tok_subtype_e;
1161 
1162 /**
1163  * @brief convert queue subtype to QTOP entry
1164  *
1165  * @param q queue subtype
1166  *
1167  * @return QTOP entry or 0
1168  */
1169 static ocs_hal_qtop_entry_e
1171 {
1172  switch(q) {
1173  case TOK_SUB_EQ: return QTOP_EQ;
1174  case TOK_SUB_CQ: return QTOP_CQ;
1175  case TOK_SUB_RQ: return QTOP_RQ;
1176  case TOK_SUB_MQ: return QTOP_MQ;
1177  case TOK_SUB_WQ: return QTOP_WQ;
1178  default:
1179  break;
1180  }
1181  return 0;
1182 }
1183 
1184 /**
1185  * @brief Declare token object
1186  */
1187 typedef struct {
1190  char string[TOKEN_LEN];
1191 } tok_t;
1192 
1193 /**
1194  * @brief Declare token array object
1195  */
1196 typedef struct {
1197  tok_t *tokens; /* Pointer to array of tokens */
1198  uint32_t alloc_count; /* Number of tokens in the array */
1199  uint32_t inuse_count; /* Number of tokens posted to array */
1200  uint32_t iter_idx; /* Iterator index */
1201 } tokarray_t;
1202 
1203 /**
1204  * @brief Declare token match structure
1205  */
1206 typedef struct {
1207  char *s;
1210 } tokmatch_t;
1211 
1212 /**
1213  * @brief test if character is ID start character
1214  *
1215  * @param c character to test
1216  *
1217  * @return TRUE if character is an ID start character
1218  */
1219 static int32_t
1220 idstart(int c)
1221 {
1222  return isalpha(c) || (c == '_') || (c == '$');
1223 }
1224 
1225 /**
1226  * @brief test if character is an ID character
1227  *
1228  * @param c character to test
1229  *
1230  * @return TRUE if character is an ID character
1231  */
1232 static int32_t
1233 idchar(int c)
1234 {
1235  return idstart(c) || ocs_isdigit(c);
1236 }
1237 
1238 /**
1239  * @brief Declare single character matches
1240  */
1241 static tokmatch_t cmatches[] = {
1242  {"(", TOK_LPAREN},
1243  {")", TOK_RPAREN},
1244  {":", TOK_COLON},
1245  {"=", TOK_EQUALS},
1246 };
1247 
1248 /**
1249  * @brief Declare identifier match strings
1250  */
1251 static tokmatch_t smatches[] = {
1252  {"eq", TOK_QUEUE, TOK_SUB_EQ},
1253  {"cq", TOK_QUEUE, TOK_SUB_CQ},
1254  {"rq", TOK_QUEUE, TOK_SUB_RQ},
1255  {"mq", TOK_QUEUE, TOK_SUB_MQ},
1256  {"wq", TOK_QUEUE, TOK_SUB_WQ},
1257  {"len", TOK_ATTR_NAME, TOK_SUB_LEN},
1258  {"class", TOK_ATTR_NAME, TOK_SUB_CLASS},
1259  {"ulp", TOK_ATTR_NAME, TOK_SUB_ULP},
1260  {"filter", TOK_ATTR_NAME, TOK_SUB_FILTER},
1261  {"rqpolicy", TOK_ATTR_NAME, TOK_SUB_RQ_POLICY},
1262  {"nvmeq", TOK_ATTR_NAME, TOK_SUB_NVMEQ},
1263 };
1264 
1265 /**
1266  * @brief Scan string and return next token
1267  *
1268  * The string is scanned and the next token is returned
1269  *
1270  * @param s input string to scan
1271  * @param tok pointer to place scanned token
1272  *
1273  * @return pointer to input string following scanned token, or NULL
1274  */
1275 static const char *
1276 tokenize(const char *s, tok_t *tok)
1277 {
1278  uint32_t i;
1279 
1280  memset(tok, 0, sizeof(*tok));
1281 
1282  /* Skip over whitespace */
1283  while (*s && ocs_isspace(*s)) {
1284  s++;
1285  }
1286 
1287  /* Return if nothing left in this string */
1288  if (*s == 0) {
1289  return NULL;
1290  }
1291 
1292  /* Look for single character matches */
1293  for (i = 0; i < ARRAY_SIZE(cmatches); i++) {
1294  if (cmatches[i].s[0] == *s) {
1295  tok->type = cmatches[i].type;
1296  tok->subtype = cmatches[i].subtype;
1297  tok->string[0] = *s++;
1298  return s;
1299  }
1300  }
1301 
1302  /* Scan for a hex number or decimal */
1303  if ((s[0] == '0') && ((s[1] == 'x') || (s[1] == 'X'))) {
1304  char *p = tok->string;
1305 
1306  tok->type = TOK_NUMBER;
1307 
1308  *p++ = *s++;
1309  *p++ = *s++;
1310  while ((*s == '.') || ocs_isxdigit(*s)) {
1311  if ((p - tok->string) < (int32_t)sizeof(tok->string)) {
1312  *p++ = *s;
1313  }
1314  if (*s == ',') {
1315  tok->type = TOK_NUMBER_LIST;
1316  }
1317  s++;
1318  }
1319  *p = 0;
1320  return s;
1321  } else if (ocs_isdigit(*s)) {
1322  char *p = tok->string;
1323 
1324  tok->type = TOK_NUMBER;
1325  while ((*s == ',') || ocs_isdigit(*s)) {
1326  if ((p - tok->string) < (int32_t)sizeof(tok->string)) {
1327  *p++ = *s;
1328  }
1329  if (*s == ',') {
1330  tok->type = TOK_NUMBER_LIST;
1331  }
1332  s++;
1333  }
1334  *p = 0;
1335  return s;
1336  }
1337 
1338  /* Scan for an ID */
1339  if (idstart(*s)) {
1340  char *p = tok->string;
1341 
1342  for (*p++ = *s++; idchar(*s); s++) {
1343  if ((p - tok->string) < TOKEN_LEN) {
1344  *p++ = *s;
1345  }
1346  }
1347 
1348  /* See if this is a $ number value */
1349  if (tok->string[0] == '$') {
1350  tok->type = TOK_NUMBER_VALUE;
1351  } else {
1352  /* Look for a string match */
1353  for (i = 0; i < ARRAY_SIZE(smatches); i++) {
1354  if (strcmp(smatches[i].s, tok->string) == 0) {
1355  tok->type = smatches[i].type;
1356  tok->subtype = smatches[i].subtype;
1357  return s;
1358  }
1359  }
1360  }
1361  }
1362  return s;
1363 }
1364 
1365 /**
1366  * @brief convert token type to string
1367  *
1368  * @param type token type
1369  *
1370  * @return string, or "unknown"
1371  */
1372 static const char *
1374 {
1375  switch(type) {
1376  #define P(x) case x: return #x;
1377  P(TOK_LPAREN)
1378  P(TOK_RPAREN)
1379  P(TOK_COLON)
1380  P(TOK_EQUALS)
1381  P(TOK_QUEUE)
1382  P(TOK_ATTR_NAME)
1383  P(TOK_NUMBER)
1386  #undef P
1387  }
1388  return "unknown";
1389 }
1390 
1391 /**
1392  * @brief convert token sub-type to string
1393  *
1394  * @param subtype token sub-type
1395  *
1396  * @return string, or "unknown"
1397  */
1398 static const char *
1400 {
1401  switch(subtype) {
1402  #define P(x) case x: return #x;
1403  P(TOK_SUB_EQ)
1404  P(TOK_SUB_CQ)
1405  P(TOK_SUB_RQ)
1406  P(TOK_SUB_MQ)
1407  P(TOK_SUB_WQ)
1408  P(TOK_SUB_LEN)
1409  P(TOK_SUB_CLASS)
1410  P(TOK_SUB_ULP)
1411  P(TOK_SUB_FILTER)
1413  P(TOK_SUB_NVMEQ)
1414  #undef P
1415  }
1416  return "";
1417 }
1418 
1419 /**
1420  * @brief Generate syntax error message
1421  *
1422  * A syntax error message is found, the input tokens are dumped up to and including
1423  * the token that failed as indicated by the current iterator index.
1424  *
1425  * @param hal pointer to HAL object
1426  * @param tokarray pointer to token array object
1427  *
1428  * @return none
1429  */
1430 static void
1431 tok_syntax(ocs_hal_t *hal, tokarray_t *tokarray)
1432 {
1433  uint32_t i;
1434  tok_t *tok;
1435 
1436  ocs_log_test(hal->os, "Syntax error:\n");
1437 
1438  for (i = 0, tok = tokarray->tokens; (i <= tokarray->inuse_count); i++, tok++) {
1439  ocs_log_test(hal->os, "%s [%2d] %-16s %-16s %s\n", (i == tokarray->iter_idx) ? ">>>" : " ", i,
1440  token_type2s(tok->type), token_subtype2s(tok->subtype), tok->string);
1441  }
1442 }
1443 
1444 /**
1445  * @brief parse a number
1446  *
1447  * Parses tokens of type TOK_NUMBER and TOK_NUMBER_VALUE, returning a numeric value
1448  *
1449  * @param hal pointer to HAL object
1450  * @param qtop pointer to QTOP object
1451  * @param tok pointer to token to parse
1452  *
1453  * @return numeric value
1454  */
1455 static uint32_t
1456 tok_getnumber(ocs_hal_t *hal, ocs_hal_qtop_t *qtop, tok_t *tok)
1457 {
1458  uint32_t rval = 0;
1459  uint32_t num_cpus = ocs_get_num_cpus();
1460 
1461  switch(tok->type) {
1462  case TOK_NUMBER_VALUE:
1463  if (ocs_strcmp(tok->string, "$ncpu") == 0) {
1464  rval = num_cpus;
1465  } else if (ocs_strcmp(tok->string, "$ncpu1") == 0) {
1466  rval = num_cpus - 1;
1467  } else if (ocs_strcmp(tok->string, "$nwq") == 0) {
1468  if (hal != NULL) {
1469  rval = hal->config.n_wq;
1470  }
1471  } else if (ocs_strcmp(tok->string, "$maxmrq") == 0) {
1472  rval = MIN(num_cpus, OCS_HAL_MAX_MRQS);
1473  } else if (ocs_strcmp(tok->string, "$nulp") == 0) {
1474  rval = hal->ulp_max - hal->ulp_start + 1;
1475  } else if ((qtop->rptcount_idx > 0) && ocs_strcmp(tok->string, "$rpt0") == 0) {
1476  rval = qtop->rptcount[qtop->rptcount_idx-1];
1477  } else if ((qtop->rptcount_idx > 1) && ocs_strcmp(tok->string, "$rpt1") == 0) {
1478  rval = qtop->rptcount[qtop->rptcount_idx-2];
1479  } else if ((qtop->rptcount_idx > 2) && ocs_strcmp(tok->string, "$rpt2") == 0) {
1480  rval = qtop->rptcount[qtop->rptcount_idx-3];
1481  } else if ((qtop->rptcount_idx > 3) && ocs_strcmp(tok->string, "$rpt3") == 0) {
1482  rval = qtop->rptcount[qtop->rptcount_idx-4];
1483  } else {
1484  rval = ocs_strtoul(tok->string, 0, 0);
1485  }
1486  break;
1487  case TOK_NUMBER:
1488  rval = ocs_strtoul(tok->string, 0, 0);
1489  break;
1490  default:
1491  break;
1492  }
1493  return rval;
1494 }
1495 
1496 
1497 /**
1498  * @brief parse an array of tokens
1499  *
1500  * The tokens are semantically parsed, to generate QTOP entries.
1501  *
1502  * @param hal pointer to HAL object
1503  * @param tokarray array array of tokens
1504  * @param qtop ouptut QTOP object
1505  *
1506  * @return returns 0 for success, a negative error code value for failure.
1507  */
1508 static int32_t
1509 parse_topology(ocs_hal_t *hal, tokarray_t *tokarray, ocs_hal_qtop_t *qtop)
1510 {
1511  ocs_hal_qtop_entry_t *qt = qtop->entries + qtop->inuse_count;
1512  tok_t *tok;
1513 
1514  for (; (tokarray->iter_idx < tokarray->inuse_count) &&
1515  ((tok = &tokarray->tokens[tokarray->iter_idx]) != NULL); ) {
1516  if (qtop->inuse_count >= qtop->alloc_count) {
1517  return -1;
1518  }
1519 
1520  qt = qtop->entries + qtop->inuse_count;
1521 
1522  switch (tok[0].type)
1523  {
1524  case TOK_QUEUE:
1525  qt->entry = subtype2qtop(tok[0].subtype);
1526  qt->set_default = FALSE;
1527  qt->len = 0;
1528  qt->class = 0;
1529  qtop->inuse_count++;
1530 
1531  tokarray->iter_idx++; /* Advance current token index */
1532 
1533  /* Parse for queue attributes, possibly multiple instances */
1534  while ((tokarray->iter_idx + 4) <= tokarray->inuse_count) {
1535  tok = &tokarray->tokens[tokarray->iter_idx];
1536  if( (tok[0].type == TOK_COLON) &&
1537  (tok[1].type == TOK_ATTR_NAME) &&
1538  (tok[2].type == TOK_EQUALS) &&
1539  ((tok[3].type == TOK_NUMBER) ||
1540  (tok[3].type == TOK_NUMBER_VALUE) ||
1541  (tok[3].type == TOK_NUMBER_LIST))) {
1542 
1543  switch (tok[1].subtype) {
1544  case TOK_SUB_LEN:
1545  qt->len = tok_getnumber(hal, qtop, &tok[3]);
1546  break;
1547 
1548  case TOK_SUB_CLASS:
1549  qt->class = tok_getnumber(hal, qtop, &tok[3]);
1550  break;
1551 
1552  case TOK_SUB_ULP:
1553  qt->ulp = tok_getnumber(hal, qtop, &tok[3]);
1554  break;
1555 
1556  case TOK_SUB_RQ_POLICY:
1557  qt->policy = tok_getnumber(hal, qtop, &tok[3]);
1558  break;
1559 
1560  case TOK_SUB_NVMEQ:
1561  qt->nvmeq = tok_getnumber(hal, qtop, &tok[3]);
1562  break;
1563 
1564  case TOK_SUB_FILTER:
1565  if (tok[3].type == TOK_NUMBER_LIST) {
1566  uint32_t mask = 0;
1567  char *p = tok[3].string;
1568 
1569  while ((p != NULL) && *p) {
1570  uint32_t v;
1571 
1572  v = ocs_strtoul(p, 0, 0);
1573  if (v < 32) {
1574  mask |= (1U << v);
1575  }
1576 
1577  p = ocs_strchr(p, ',');
1578  if (p != NULL) {
1579  p++;
1580  }
1581  }
1582  qt->filter_mask = mask;
1583  } else {
1584  qt->filter_mask = (1U << tok_getnumber(hal, qtop, &tok[3]));
1585  }
1586  break;
1587 
1588  default:
1589  break;
1590  }
1591  /* Advance current token index */
1592  tokarray->iter_idx += 4;
1593  } else {
1594  break;
1595  }
1596  }
1597  qtop->entry_counts[qt->entry]++;
1598  break;
1599 
1600  case TOK_ATTR_NAME:
1601  if ( ((tokarray->iter_idx + 5) <= tokarray->inuse_count) &&
1602  (tok[1].type == TOK_COLON) &&
1603  (tok[2].type == TOK_QUEUE) &&
1604  (tok[3].type == TOK_EQUALS) &&
1605  ((tok[4].type == TOK_NUMBER) || (tok[4].type == TOK_NUMBER_VALUE))) {
1606  qt->entry = subtype2qtop(tok[2].subtype);
1607  qt->set_default = TRUE;
1608  switch(tok[0].subtype) {
1609  case TOK_SUB_LEN:
1610  qt->len = tok_getnumber(hal, qtop, &tok[4]);
1611  break;
1612  case TOK_SUB_CLASS:
1613  qt->class = tok_getnumber(hal, qtop, &tok[4]);
1614  break;
1615  case TOK_SUB_ULP:
1616  qt->ulp = tok_getnumber(hal, qtop, &tok[4]);
1617  break;
1618  default:
1619  break;
1620  }
1621  qtop->inuse_count++;
1622  tokarray->iter_idx += 5;
1623  } else {
1624  tok_syntax(hal, tokarray);
1625  return -1;
1626  }
1627  break;
1628 
1629  case TOK_NUMBER:
1630  case TOK_NUMBER_VALUE: {
1631  uint32_t rpt_count = 1;
1632  uint32_t i;
1633 
1634  rpt_count = tok_getnumber(hal, qtop, tok);
1635 
1636  if (tok[1].type == TOK_LPAREN) {
1637  uint32_t iter_idx_save;
1638 
1639  tokarray->iter_idx += 2;
1640 
1641  /* save token array iteration index */
1642  iter_idx_save = tokarray->iter_idx;
1643 
1644  for (i = 0; i < rpt_count; i++) {
1645  uint32_t rptcount_idx = qtop->rptcount_idx;
1646 
1647  if (qtop->rptcount_idx < ARRAY_SIZE(qtop->rptcount)) {
1648  qtop->rptcount[qtop->rptcount_idx++] = i;
1649  }
1650 
1651  /* restore token array iteration index */
1652  tokarray->iter_idx = iter_idx_save;
1653 
1654  /* parse, append to qtop */
1655  parse_topology(hal, tokarray, qtop);
1656 
1657  qtop->rptcount_idx = rptcount_idx;
1658  }
1659  }
1660  break;
1661  }
1662 
1663  case TOK_RPAREN:
1664  tokarray->iter_idx++;
1665  return 0;
1666 
1667  default:
1668  tok_syntax(hal, tokarray);
1669  return -1;
1670  }
1671  }
1672  return 0;
1673 }
1674 
1675 /**
1676  * @brief Parse queue topology string
1677  *
1678  * The queue topology object is allocated, and filled with the results of parsing the
1679  * passed in queue topology string
1680  *
1681  * @param hal pointer to HAL object
1682  * @param qtop_string input queue topology string
1683  *
1684  * @return pointer to allocated QTOP object, or NULL if there was an error
1685  */
1687 ocs_hal_qtop_parse(ocs_hal_t *hal, const char *qtop_string)
1688 {
1689  ocs_hal_qtop_t *qtop;
1690  tokarray_t tokarray;
1691  const char *s;
1692 #if HAL_QTOP_DEBUG
1693  uint32_t i;
1695 #endif
1696 
1697  ocs_log_debug(hal->os, "queue topology: %s\n", qtop_string);
1698 
1699  /* Allocate a token array */
1700  tokarray.tokens = ocs_malloc(hal->os, MAX_TOKENS * sizeof(*tokarray.tokens),
1701  OCS_M_ZERO | OCS_M_NOWAIT | OCS_M_NONUMA);
1702  if (tokarray.tokens == NULL) {
1703  return NULL;
1704  }
1705  tokarray.alloc_count = MAX_TOKENS;
1706  tokarray.inuse_count = 0;
1707  tokarray.iter_idx = 0;
1708 
1709  /* Parse the tokens */
1710  for (s = qtop_string; (tokarray.inuse_count < tokarray.alloc_count) &&
1711  ((s = tokenize(s, &tokarray.tokens[tokarray.inuse_count]))) != NULL; ) {
1712  tokarray.inuse_count++;;
1713  }
1714 
1715  /* Allocate a queue topology structure */
1716  qtop = ocs_malloc(hal->os, sizeof(*qtop), OCS_M_ZERO | OCS_M_NOWAIT);
1717  if (qtop == NULL) {
1718  ocs_free(hal->os, tokarray.tokens, MAX_TOKENS * sizeof(*tokarray.tokens));
1719  ocs_log_err(hal->os, "malloc qtop failed\n");
1720  return NULL;
1721  }
1722  qtop->os = hal->os;
1723 
1724  /* Allocate queue topology entries */
1725  qtop->entries = ocs_malloc(hal->os, OCS_HAL_MAX_QTOP_ENTRIES * sizeof(*qtop->entries),
1726  OCS_M_ZERO | OCS_M_NOWAIT | OCS_M_NONUMA);
1727  if (qtop->entries == NULL) {
1728  ocs_log_err(hal->os, "malloc qtop entries failed\n");
1729  ocs_free(hal->os, qtop, sizeof(*qtop));
1730  ocs_free(hal->os, tokarray.tokens, MAX_TOKENS * sizeof(*tokarray.tokens));
1731  return NULL;
1732  }
1734  qtop->inuse_count = 0;
1735 
1736  /* Parse the tokens */
1737  if (parse_topology(hal, &tokarray, qtop)) {
1738  ocs_log_err(hal->os, "failed to parse tokens \n");
1739  ocs_hal_qtop_free(qtop);
1740  ocs_free(hal->os, tokarray.tokens, MAX_TOKENS * sizeof(*tokarray.tokens));
1741  return NULL;
1742  }
1743 
1744 #if HAL_QTOP_DEBUG
1745  for (i = 0, qt = qtop->entries; i < qtop->inuse_count; i++, qt++) {
1746  ocs_log_debug(hal->os, "entry %s set_df %d len %4d class %d ulp %d \n", qtopentry2s(qt->entry), qt->set_default, qt->len,
1747  qt->class, qt->ulp );
1748  }
1749 #endif
1750 
1751  /* Free the tokens array */
1752  ocs_free(hal->os, tokarray.tokens, MAX_TOKENS * sizeof(*tokarray.tokens));
1753 
1754  return qtop;
1755 }
1756 
1757 /**
1758  * @brief free queue topology object
1759  *
1760  * @param qtop pointer to QTOP object
1761  *
1762  * @return none
1763  */
1764 void
1766 {
1767  if (qtop != NULL) {
1768  if (qtop->entries != NULL) {
1769  ocs_free(qtop->os, qtop->entries, qtop->alloc_count*sizeof(*qtop->entries));
1770  }
1771  ocs_free(qtop->os, qtop, sizeof(*qtop));
1772  }
1773 }
uint32_t len
ocs_hal_qtop_entry_t * entries
tok_type_e type
ocs_hal_qtop_entry_e entry
uint32_t alloc_count
uint8_t nvmeq
HAL wqe object.
Definition: ocs_hal.h:572
uint8_t protocol
uint8_t class
int32_t sli_eq_modify_delay(sli4_t *sli4, sli4_queue_t *eq, uint32_t num_eq, uint32_t shift, uint32_t delay_mult)
Modify the delay timer for all the EQs.
Definition: sli4.c:5044
tok_type_e
return string given a QTOP entry
uint32_t rptcount[10]
void hal_queue_teardown(ocs_hal_t *hal)
Teardown HAL queue objects.
#define OCS_HAL_WQEC_SET_COUNT
void hal_del_wq(hal_wq_t *wq)
Free a WQ object.
#define OCS_HAL_CQ_ENTRIES_MIN
#define SLI_MAX_CQ_SET_COUNT
Definition: sli4.h:3433
#define OCS_HAL_RQ_ENTRIES_MIN
uint32_t ocs_hal_qtop_eq_count(ocs_hal_t *hal)
Return count of EQs for a queue topology object.
ocs_hal_rtn_e ocs_hal_init_queues(ocs_hal_t *hal, ocs_hal_qtop_t *qtop)
Initialize queues.
void hal_del_rq(hal_rq_t *rq)
Free an RQ object.
#define OCS_HAL_MAX_NUM_RQ
Definition: ocs_hal.h:120
uint8_t filter_mask
void hal_del_cq(hal_cq_t *cq)
Free a CQ object.
#define OCS_HAL_EQ_ENTRIES_DEF
bool protocol_valid
#define TOKEN_LEN
#define OCS_HAL_MAX_MRQ_SETS
Definition: ocs_hal.h:114
ocs_hal_rtn_e
Definition: ocs_hal.h:159
uint32_t entry_counts[QTOP_LAST]
static const char * tokenize(const char *s, tok_t *tok)
Scan string and return next token.
#define OCS_HAL_MAX_NUM_WQ
Definition: ocs_hal.h:122
hal_rq_t * hal_new_rq(hal_cq_t *cq, uint32_t entry_count, uint32_t ulp)
Allocate a hal_rq_t object.
static void tok_syntax(ocs_hal_t *hal, tokarray_t *tokarray)
Generate syntax error message.
#define MAX_TOKENS
#define OCS_HAL_CQ_ENTRIES_DEF
hal_cq_t * hal_new_cq(hal_eq_t *eq, uint32_t entry_count)
Allocate a new CQ object.
char string[TOKEN_LEN]
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
int32_t sli_fc_rq_alloc(sli4_t *sli4, sli4_queue_t *q, uint32_t n_entries, uint32_t buffer_size, sli4_queue_t *cq, uint16_t ulp, uint8_t is_hdr)
Allocate a receive queue.
Definition: sli4_fc.c:2948
ocs_hal_qtop_entry_e
uint32_t rptcount_idx
static uint32_t tok_getnumber(ocs_hal_t *hal, ocs_hal_qtop_t *qtop, tok_t *tok)
parse a number
Definition: sli4.h:3601
uint8_t ulp
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
tok_subtype_e subtype
static int ocs_list_valid(ocs_list_t *list)
Test if a list is valid (ready for use)
Definition: ocs_list.h:155
uint32_t alloc_count
hal_wq_t * ocs_hal_queue_next_wq(ocs_hal_t *hal, ocs_hal_io_t *io)
Allocate a WQ to an IO object.
static int32_t parse_topology(ocs_hal_t *hal, tokarray_t *tokarray, ocs_hal_qtop_t *qtop)
parse an array of tokens
#define ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Definition: ocs_list.h:446
static tokmatch_t cmatches[]
Declare single character matches.
uint8_t policy
int32_t sli_fc_rq_set_alloc(sli4_t *sli4, uint32_t num_rq_pairs, sli4_queue_t *qs[], uint32_t base_cq_id, uint32_t n_entries, uint32_t header_buffer_size, uint32_t payload_buffer_size, uint16_t ulp)
Allocate a receive queue set.
Definition: sli4_fc.c:3015
static int32_t idstart(int c)
test if character is ID start character
void ocs_hal_qtop_free(ocs_hal_qtop_t *qtop)
free queue topology object
uint32_t iter_idx
Declare token object.
hal_mq_t * hal_new_mq(hal_cq_t *cq, uint32_t entry_count)
Allocate a new MQ object.
#define ocs_hal_verify(cond,...)
Definition: ocs_hal.h:89
#define OCS_HAL_RQ_ENTRIES_DEF
static ocs_hal_qtop_entry_e subtype2qtop(tok_subtype_e q)
convert queue subtype to QTOP entry
ocs_os_handle_t os
#define OCS_HAL_MAX_MRQS
uint16_t id
Definition: sli4.h:3456
uint32_t hal_new_rq_set(hal_cq_t *cqs[], hal_rq_t *rqs[], uint32_t num_rq_pairs, uint32_t entry_count, uint32_t ulp)
Allocate a hal_rq_t object SET.
#define OCS_HAL_MAX_QTOP_ENTRIES
static tokmatch_t smatches[]
Declare identifier match strings.
static const char * token_subtype2s(tok_subtype_e subtype)
convert token sub-type to string
uint32_t inuse_count
Declare token array object.
void hal_queue_dump(ocs_hal_t *hal)
Display HAL queue objects.
int32_t sli_cq_alloc_set(sli4_t *sli4, sli4_queue_t *qs[], uint32_t num_cqs, uint32_t n_entries, sli4_queue_t *eqs[])
Allocate a c queue set.
Definition: sli4.c:5172
void * ocs_varray_iter_next(ocs_varray_t *va)
Return next entry from a void pointer array.
Definition: ocs_array.c:333
#define OCS_HAL_MQ_ENTRIES_DEF
sli4_qtype_e type
Definition: ocs_hal.h:1160
static void ocs_list_add_tail(ocs_list_t *list, void *item)
Add an item to the tail of the list.
Definition: ocs_list.h:263
void ocs_varray_free(ocs_varray_t *va)
Free a void pointer array.
Definition: ocs_array.c:268
static int32_t idchar(int c)
test if character is an ID character
ocs_hal_qtop_t * ocs_hal_qtop_parse(ocs_hal_t *hal, const char *qtop_string)
Parse queue topology string.
Defines a general FC sequence object, consisting of a header, payload buffers and a HAL IO in the cas...
Definition: ocs_hal.h:784
hal_wq_t * hal_new_wq(hal_cq_t *cq, uint32_t entry_count, uint32_t class, uint32_t ulp)
Allocate a new WQ object.
hal_eq_t * hal_new_eq(ocs_hal_t *hal, uint32_t entry_count)
Allocate a new EQ object.
hal_eq_t * eqs[OCE_HAL_MAX_NUM_MRQ_PAIRS]
#define ocs_hal_assert(cond)
Definition: ocs_hal.h:82
tok_subtype_e
Declare token sub-types.
#define P(type, name, value, desc)
void hal_del_eq(hal_eq_t *eq)
Free an EQ object.
#define OCS_HAL_EQ_ENTRIES_MIN
void hal_del_mq(hal_mq_t *mq)
Free a MQ object.
int32_t sli_queue_alloc(sli4_t *sli4, uint32_t qtype, sli4_queue_t *q, uint32_t n_entries, sli4_queue_t *assoc, uint16_t ulp)
Allocate a queue.
Definition: sli4.c:5078
uint32_t hal_new_cq_set(hal_eq_t *eqs[], hal_cq_t *cqs[], uint32_t num_cqs, uint32_t entry_count)
Allocate a new CQ Set of objects.
Declare token match structure.
#define OCE_HAL_MAX_NUM_MRQ_PAIRS
Definition: ocs_hal.h:123
#define OCS_HAL_RQ_HEADER_SIZE
Definition: ocs_hal.h:142
static const char * token_type2s(tok_type_e type)
convert token type to string
#define OCS_HAL_MQ_ENTRIES_MIN
tok_type_e type
#define ocs_list_foreach(list, item)
Iterate a linked list.
Definition: ocs_list.h:428
#define OCS_HAL_WQ_ENTRIES_DEF
static bool ocs_qlen_valid(uint32_t qlen, uint32_t min, uint32_t max)
int32_t ocs_varray_add(ocs_varray_t *va, void *entry)
Add an entry to a void pointer array.
Definition: ocs_array.c:290
tok_t * tokens
#define SLI_MAX_RQ_SET_COUNT
Definition: sli4.h:3434
struct ocs_hal_rqs_info_t::rq_config rq_cfg[OCS_HAL_MAX_RQ_PAIRS]
#define OCS_HAL_WQ_ENTRIES_MIN
uint32_t inuse_count
tok_subtype_e subtype
uint8_t set_default
ocs_varray_t * ocs_varray_alloc(ocs_os_handle_t os, uint32_t array_count)
Allocate a void pointer array.
Definition: ocs_array.c:238