idpf: add native idpf driver plugin
[vpp.git] / src / plugins / idpf / idpf_controlq.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2023 Intel and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <idpf/idpf.h>
19
20 /**
21  * idpf_ctlq_alloc_desc_ring - Allocate Control Queue (CQ) rings
22  * @hw: pointer to hw struct
23  * @cq: pointer to the specific Control queue
24  */
25 static int
26 idpf_ctlq_alloc_desc_ring (vlib_main_t *vm, idpf_device_t *id,
27                            struct idpf_ctlq_info *cq)
28 {
29   size_t size = cq->ring_size * sizeof (idpf_ctlq_desc_t);
30
31   /* Fixme: alloc dma va */
32   cq->desc_ring.va = idpf_alloc_dma_mem (vm, id, &cq->desc_ring, size);
33   if (!cq->desc_ring.va)
34     return IDPF_ERR_NO_MEMORY;
35
36   return IDPF_SUCCESS;
37 }
38
39 /**
40  * idpf_ctlq_alloc_bufs - Allocate Control Queue (CQ) buffers
41  * @hw: pointer to hw struct
42  * @cq: pointer to the specific Control queue
43  *
44  * Allocate the buffer head for all control queues, and if it's a receive
45  * queue, allocate DMA buffers
46  */
47 static int
48 idpf_ctlq_alloc_bufs (vlib_main_t *vm, idpf_device_t *id,
49                       struct idpf_ctlq_info *cq)
50 {
51   int i = 0;
52   u16 len;
53
54   /* Do not allocate DMA buffers for transmit queues */
55   if (cq->cq_type == IDPF_CTLQ_TYPE_MAILBOX_TX)
56     return IDPF_SUCCESS;
57
58   /* We'll be allocating the buffer info memory first, then we can
59    * allocate the mapped buffers for the event processing
60    */
61   len = cq->ring_size * sizeof (idpf_dma_mem_t *);
62   cq->bi.rx_buff = (idpf_dma_mem_t **) clib_mem_alloc (len);
63   if (!cq->bi.rx_buff)
64     return IDPF_ERR_NO_MEMORY;
65   clib_memset (cq->bi.rx_buff, 0, len);
66
67   /* allocate the mapped buffers (except for the last one) */
68   for (i = 0; i < cq->ring_size - 1; i++)
69     {
70       idpf_dma_mem_t *bi;
71       int num = 1; /* number of idpf_dma_mem to be allocated */
72
73       cq->bi.rx_buff[i] =
74         (idpf_dma_mem_t *) clib_mem_alloc (num * sizeof (idpf_dma_mem_t));
75       if (!cq->bi.rx_buff[i])
76         goto unwind_alloc_cq_bufs;
77
78       bi = cq->bi.rx_buff[i];
79
80       bi->va = idpf_alloc_dma_mem (vm, id, bi, cq->buf_size);
81       if (!bi->va)
82         {
83           /* unwind will not free the failed entry */
84           clib_mem_free (cq->bi.rx_buff[i]);
85           goto unwind_alloc_cq_bufs;
86         }
87     }
88
89   return IDPF_SUCCESS;
90
91 unwind_alloc_cq_bufs:
92   /* don't try to free the one that failed... */
93   i--;
94   for (; i >= 0; i--)
95     {
96       idpf_free_dma_mem (id, cq->bi.rx_buff[i]);
97       clib_mem_free (cq->bi.rx_buff[i]);
98     }
99   clib_mem_free (cq->bi.rx_buff);
100
101   return IDPF_ERR_NO_MEMORY;
102 }
103
104 /**
105  * idpf_ctlq_free_desc_ring - Free Control Queue (CQ) rings
106  * @hw: pointer to hw struct
107  * @cq: pointer to the specific Control queue
108  *
109  * This assumes the posted send buffers have already been cleaned
110  * and de-allocated
111  */
112 static void
113 idpf_ctlq_free_desc_ring (idpf_device_t *id, struct idpf_ctlq_info *cq)
114 {
115   idpf_free_dma_mem (id, &cq->desc_ring);
116 }
117
118 /**
119  * idpf_ctlq_free_bufs - Free CQ buffer info elements
120  * @hw: pointer to hw struct
121  * @cq: pointer to the specific Control queue
122  *
123  * Free the DMA buffers for RX queues, and DMA buffer header for both RX and TX
124  * queues.  The upper layers are expected to manage freeing of TX DMA buffers
125  */
126 static void
127 idpf_ctlq_free_bufs (idpf_device_t *id, struct idpf_ctlq_info *cq)
128 {
129   void *bi;
130
131   if (cq->cq_type == IDPF_CTLQ_TYPE_MAILBOX_RX)
132     {
133       int i;
134
135       /* free DMA buffers for rx queues*/
136       for (i = 0; i < cq->ring_size; i++)
137         {
138           if (cq->bi.rx_buff[i])
139             {
140               idpf_free_dma_mem (id, cq->bi.rx_buff[i]);
141               /* Attention */
142               clib_mem_free (cq->bi.rx_buff[i]);
143             }
144         }
145
146       bi = (void *) cq->bi.rx_buff;
147     }
148   else
149     {
150       bi = (void *) cq->bi.tx_msg;
151     }
152
153   /* free the buffer header */
154   clib_mem_free (bi);
155 }
156
157 /**
158  * idpf_ctlq_dealloc_ring_res - Free memory allocated for control queue
159  * @hw: pointer to hw struct
160  * @cq: pointer to the specific Control queue
161  *
162  * Free the memory used by the ring, buffers and other related structures
163  */
164 void
165 idpf_ctlq_dealloc_ring_res (idpf_device_t *id, struct idpf_ctlq_info *cq)
166 {
167   /* free ring buffers and the ring itself */
168   idpf_ctlq_free_bufs (id, cq);
169   idpf_ctlq_free_desc_ring (id, cq);
170 }
171
172 /**
173  * idpf_ctlq_alloc_ring_res - allocate memory for descriptor ring and bufs
174  * @hw: pointer to hw struct
175  * @cq: pointer to control queue struct
176  *
177  * Do *NOT* hold the lock when calling this as the memory allocation routines
178  * called are not going to be atomic context safe
179  */
180 int
181 idpf_ctlq_alloc_ring_res (vlib_main_t *vm, idpf_device_t *id,
182                           struct idpf_ctlq_info *cq)
183 {
184   int ret_code;
185
186   /* verify input for valid configuration */
187   if (!cq->ring_size || !cq->buf_size)
188     return IDPF_ERR_CFG;
189
190   /* allocate the ring memory */
191   ret_code = idpf_ctlq_alloc_desc_ring (vm, id, cq);
192   if (ret_code)
193     return ret_code;
194
195   /* allocate buffers in the rings */
196   ret_code = idpf_ctlq_alloc_bufs (vm, id, cq);
197   if (ret_code)
198     goto idpf_init_cq_free_ring;
199
200   /* success! */
201   return IDPF_SUCCESS;
202
203 idpf_init_cq_free_ring:
204   idpf_free_dma_mem (id, &cq->desc_ring);
205   return ret_code;
206 }
207
208 /**
209  * idpf_ctlq_setup_regs - initialize control queue registers
210  * @cq: pointer to the specific control queue
211  * @q_create_info: structs containing info for each queue to be initialized
212  */
213 static void
214 idpf_ctlq_setup_regs (struct idpf_ctlq_info *cq,
215                       idpf_ctlq_create_info_t *q_create_info)
216 {
217   /* set head and tail registers in our local struct */
218   cq->reg.head = q_create_info->reg.head;
219   cq->reg.tail = q_create_info->reg.tail;
220   cq->reg.len = q_create_info->reg.len;
221   cq->reg.bah = q_create_info->reg.bah;
222   cq->reg.bal = q_create_info->reg.bal;
223   cq->reg.len_mask = q_create_info->reg.len_mask;
224   cq->reg.len_ena_mask = q_create_info->reg.len_ena_mask;
225   cq->reg.head_mask = q_create_info->reg.head_mask;
226 }
227
228 /**
229  * idpf_ctlq_init_regs - Initialize control queue registers
230  * @hw: pointer to hw struct
231  * @cq: pointer to the specific Control queue
232  * @is_rxq: true if receive control queue, false otherwise
233  *
234  * Initialize registers. The caller is expected to have already initialized the
235  * descriptor ring memory and buffer memory
236  */
237 static void
238 idpf_ctlq_init_regs (vlib_main_t *vm, idpf_device_t *id,
239                      struct idpf_ctlq_info *cq, bool is_rxq)
240 {
241   /* Update tail to post pre-allocated buffers for rx queues */
242   if (is_rxq)
243     idpf_reg_write (id, cq->reg.tail, (u32) (cq->ring_size - 1));
244
245   /* For non-Mailbox control queues only TAIL need to be set */
246   if (cq->q_id != -1)
247     return;
248
249   /* Clear Head for both send or receive */
250   idpf_reg_write (id, cq->reg.head, 0);
251
252   /* set starting point */
253   idpf_reg_write (id, cq->reg.bal, IDPF_LO_DWORD (cq->desc_ring.pa));
254   idpf_reg_write (id, cq->reg.bah, IDPF_HI_DWORD (cq->desc_ring.pa));
255   idpf_reg_write (id, cq->reg.len, (cq->ring_size | cq->reg.len_ena_mask));
256 }
257
258 /**
259  * idpf_ctlq_init_rxq_bufs - populate receive queue descriptors with buf
260  * @cq: pointer to the specific Control queue
261  *
262  * Record the address of the receive queue DMA buffers in the descriptors.
263  * The buffers must have been previously allocated.
264  */
265 static void
266 idpf_ctlq_init_rxq_bufs (struct idpf_ctlq_info *cq)
267 {
268   int i = 0;
269
270   for (i = 0; i < cq->ring_size; i++)
271     {
272       idpf_ctlq_desc_t *desc = IDPF_CTLQ_DESC (cq, i);
273       idpf_dma_mem_t *bi = cq->bi.rx_buff[i];
274
275       /* No buffer to post to descriptor, continue */
276       if (!bi)
277         continue;
278
279       desc->flags = IDPF_CTLQ_FLAG_BUF | IDPF_CTLQ_FLAG_RD;
280       desc->opcode = 0;
281       desc->datalen = (u16) bi->size;
282       desc->ret_val = 0;
283       desc->cookie_high = 0;
284       desc->cookie_low = 0;
285       desc->params.indirect.addr_high = IDPF_HI_DWORD (bi->pa);
286       desc->params.indirect.addr_low = IDPF_LO_DWORD (bi->pa);
287       desc->params.indirect.param0 = 0;
288       desc->params.indirect.param1 = 0;
289     }
290 }
291
292 /**
293  * idpf_ctlq_shutdown - shutdown the CQ
294  * @hw: pointer to hw struct
295  * @cq: pointer to the specific Control queue
296  *
297  * The main shutdown routine for any controq queue
298  */
299 static void
300 idpf_ctlq_shutdown (idpf_device_t *id, struct idpf_ctlq_info *cq)
301 {
302   clib_spinlock_init (&cq->cq_lock);
303
304   if (!cq->ring_size)
305     goto shutdown_sq_out;
306
307   /* free ring buffers and the ring itself */
308   idpf_ctlq_dealloc_ring_res (id, cq);
309
310   /* Set ring_size to 0 to indicate uninitialized queue */
311   cq->ring_size = 0;
312
313 shutdown_sq_out:
314   clib_spinlock_unlock (&cq->cq_lock);
315   clib_spinlock_free (&cq->cq_lock);
316 }
317
318 /**
319  * idpf_ctlq_add - add one control queue
320  * @hw: pointer to hardware struct
321  * @qinfo: info for queue to be created
322  * @cq_out: (output) double pointer to control queue to be created
323  *
324  * Allocate and initialize a control queue and add it to the control queue
325  * list. The cq parameter will be allocated/initialized and passed back to the
326  * caller if no errors occur.
327  *
328  * Note: idpf_ctlq_init must be called prior to any calls to idpf_ctlq_add
329  */
330 int
331 idpf_ctlq_add (vlib_main_t *vm, idpf_device_t *id,
332                idpf_ctlq_create_info_t *qinfo, struct idpf_ctlq_info **cq_out)
333 {
334   bool is_rxq = false;
335   int status = IDPF_SUCCESS;
336
337   if (!qinfo->len || !qinfo->buf_size ||
338       qinfo->len > IDPF_CTLQ_MAX_RING_SIZE ||
339       qinfo->buf_size > IDPF_CTLQ_MAX_BUF_LEN)
340     return IDPF_ERR_CFG;
341
342   /* Fixme: memory allocation */
343   *cq_out = vlib_physmem_alloc_aligned_on_numa (
344     vm, sizeof (struct idpf_ctlq_info), CLIB_CACHE_LINE_BYTES, id->numa_node);
345   if (!(*cq_out))
346     return IDPF_ERR_NO_MEMORY;
347
348   if ((vlib_pci_map_dma (vm, id->pci_dev_handle, *cq_out)))
349     {
350       status = IDPF_ERR_NO_MEMORY;
351       goto init_free_q;
352     }
353
354   (*cq_out)->cq_type = qinfo->type;
355   (*cq_out)->q_id = qinfo->id;
356   (*cq_out)->buf_size = qinfo->buf_size;
357   (*cq_out)->ring_size = qinfo->len;
358
359   (*cq_out)->next_to_use = 0;
360   (*cq_out)->next_to_clean = 0;
361   (*cq_out)->next_to_post = (*cq_out)->ring_size - 1;
362
363   switch (qinfo->type)
364     {
365     case IDPF_CTLQ_TYPE_MAILBOX_RX:
366       is_rxq = true;
367     case IDPF_CTLQ_TYPE_MAILBOX_TX:
368       status = idpf_ctlq_alloc_ring_res (vm, id, *cq_out);
369       break;
370     default:
371       status = IDPF_ERR_PARAM;
372       break;
373     }
374
375   if (status)
376     goto init_free_q;
377
378   if (is_rxq)
379     {
380       idpf_ctlq_init_rxq_bufs (*cq_out);
381     }
382   else
383     {
384       /* Allocate the array of msg pointers for TX queues */
385       (*cq_out)->bi.tx_msg = (idpf_ctlq_msg_t **) clib_mem_alloc (
386         qinfo->len * sizeof (idpf_ctlq_msg_t *));
387       if (!(*cq_out)->bi.tx_msg)
388         {
389           status = IDPF_ERR_NO_MEMORY;
390           goto init_dealloc_q_mem;
391         }
392     }
393
394   idpf_ctlq_setup_regs (*cq_out, qinfo);
395
396   idpf_ctlq_init_regs (vm, id, *cq_out, is_rxq);
397
398   /* Fixeme: lock issue */
399   clib_spinlock_init (&(*cq_out)->cq_lock);
400
401   LIST_INSERT_HEAD (&id->cq_list_head, (*cq_out), cq_list);
402
403   return status;
404
405 init_dealloc_q_mem:
406   /* free ring buffers and the ring itself */
407   idpf_ctlq_dealloc_ring_res (id, *cq_out);
408 init_free_q:
409   clib_mem_free (*cq_out);
410
411   return status;
412 }
413
414 /**
415  * idpf_ctlq_remove - deallocate and remove specified control queue
416  * @hw: pointer to hardware struct
417  * @cq: pointer to control queue to be removed
418  */
419 void
420 idpf_ctlq_remove (idpf_device_t *id, struct idpf_ctlq_info *cq)
421 {
422   LIST_REMOVE (cq, cq_list);
423   idpf_ctlq_shutdown (id, cq);
424   clib_mem_free (cq);
425 }
426
427 /**
428  * idpf_ctlq_init - main initialization routine for all control queues
429  * @hw: pointer to hardware struct
430  * @num_q: number of queues to initialize
431  * @q_info: array of structs containing info for each queue to be initialized
432  *
433  * This initializes any number and any type of control queues. This is an all
434  * or nothing routine; if one fails, all previously allocated queues will be
435  * destroyed. This must be called prior to using the individual add/remove
436  * APIs.
437  */
438 int
439 idpf_ctlq_init (vlib_main_t *vm, idpf_device_t *id, u8 num_q,
440                 idpf_ctlq_create_info_t *q_info)
441 {
442   struct idpf_ctlq_info *cq = NULL;
443   int ret_code = IDPF_SUCCESS;
444   int i = 0;
445
446   LIST_INIT (&id->cq_list_head);
447
448   for (i = 0; i < num_q; i++)
449     {
450       idpf_ctlq_create_info_t *qinfo = q_info + i;
451
452       ret_code = idpf_ctlq_add (vm, id, qinfo, &cq);
453       if (ret_code)
454         goto init_destroy_qs;
455     }
456
457   return ret_code;
458
459 init_destroy_qs:
460   LIST_FOR_EACH_ENTRY_SAFE (cq, NULL, &id->cq_list_head, struct idpf_ctlq_info,
461                             cq_list)
462   {
463     idpf_ctlq_remove (id, cq);
464   }
465
466   return ret_code;
467 }
468
469 /**
470  * idpf_ctlq_deinit - destroy all control queues
471  * @hw: pointer to hw struct
472  */
473 void
474 idpf_ctlq_deinit (idpf_device_t *id)
475 {
476   struct idpf_ctlq_info *cq = NULL;
477
478   LIST_FOR_EACH_ENTRY_SAFE (cq, NULL, &id->cq_list_head, struct idpf_ctlq_info,
479                             cq_list)
480   {
481     idpf_ctlq_remove (id, cq);
482   }
483
484   return;
485 }
486
487 /**
488  * idpf_ctlq_send - send command to Control Queue (CTQ)
489  * @id: pointer to device struct
490  * @cq: handle to control queue struct to send on
491  * @num_q_msg: number of messages to send on control queue
492  * @q_msg: pointer to array of queue messages to be sent
493  *
494  * The caller is expected to allocate DMAable buffers and pass them to the
495  * send routine via the q_msg struct / control queue specific data struct.
496  * The control queue will hold a reference to each send message until
497  * the completion for that message has been cleaned.
498  */
499 int
500 idpf_ctlq_send (idpf_device_t *id, struct idpf_ctlq_info *cq, u16 num_q_msg,
501                 idpf_ctlq_msg_t q_msg[])
502 {
503   idpf_ctlq_desc_t *desc;
504   int num_desc_avail = 0;
505   int status = IDPF_SUCCESS;
506   int i = 0;
507
508   if (!cq || !cq->ring_size)
509     return -ENOBUFS;
510
511   clib_spinlock_lock (&cq->cq_lock);
512
513   /* Ensure there are enough descriptors to send all messages */
514   num_desc_avail = IDPF_CTLQ_DESC_UNUSED (cq);
515   if (num_desc_avail == 0 || num_desc_avail < num_q_msg)
516     {
517       status = -ENOSPC;
518       goto sq_send_command_out;
519     }
520
521   for (i = 0; i < num_q_msg; i++)
522     {
523       idpf_ctlq_msg_t *msg = &q_msg[i];
524       u64 msg_cookie;
525
526       desc = IDPF_CTLQ_DESC (cq, cq->next_to_use);
527
528       /* Pay attention to CPU_TO_LE16 */
529       desc->opcode = msg->opcode;
530       desc->pfid_vfid = msg->func_id;
531
532       msg_cookie = msg->cookie.cookie;
533       desc->cookie_high = IDPF_HI_DWORD (msg_cookie);
534       desc->cookie_low = IDPF_LO_DWORD (msg_cookie);
535
536       desc->flags = (msg->host_id & IDPF_HOST_ID_MASK)
537                     << IDPF_CTLQ_FLAG_HOST_ID_S;
538       if (msg->data_len)
539         {
540           idpf_dma_mem_t *buff = msg->ctx.indirect.payload;
541
542           desc->datalen |= msg->data_len;
543           desc->flags |= IDPF_CTLQ_FLAG_BUF;
544           desc->flags |= IDPF_CTLQ_FLAG_RD;
545
546           /* Update the address values in the desc with the pa
547            * value for respective buffer
548            */
549           desc->params.indirect.addr_high = IDPF_HI_DWORD (buff->pa);
550           desc->params.indirect.addr_low = IDPF_LO_DWORD (buff->pa);
551
552           clib_memcpy (&desc->params, msg->ctx.indirect.context,
553                        IDPF_INDIRECT_CTX_SIZE);
554         }
555       else
556         {
557           clib_memcpy (&desc->params, msg->ctx.direct, IDPF_DIRECT_CTX_SIZE);
558         }
559
560       /* Store buffer info */
561       cq->bi.tx_msg[cq->next_to_use] = msg;
562
563       (cq->next_to_use)++;
564       if (cq->next_to_use == cq->ring_size)
565         cq->next_to_use = 0;
566     }
567
568   /* Force memory write to complete before letting hardware
569    * know that there are new descriptors to fetch.
570    */
571   CLIB_MEMORY_BARRIER ();
572
573   idpf_reg_write (id, cq->reg.tail, cq->next_to_use);
574
575 sq_send_command_out:
576   clib_spinlock_unlock (&cq->cq_lock);
577
578   return status;
579 }
580
581 /**
582  * idpf_ctlq_clean_sq - reclaim send descriptors on HW write back for the
583  * requested queue
584  * @cq: pointer to the specific Control queue
585  * @clean_count: (input|output) number of descriptors to clean as input, and
586  * number of descriptors actually cleaned as output
587  * @msg_status: (output) pointer to msg pointer array to be populated; needs
588  * to be allocated by caller
589  *
590  * Returns an array of message pointers associated with the cleaned
591  * descriptors. The pointers are to the original ctlq_msgs sent on the cleaned
592  * descriptors.  The status will be returned for each; any messages that failed
593  * to send will have a non-zero status. The caller is expected to free original
594  * ctlq_msgs and free or reuse the DMA buffers.
595  */
596 int
597 idpf_ctlq_clean_sq (struct idpf_ctlq_info *cq, u16 *clean_count,
598                     idpf_ctlq_msg_t *msg_status[])
599 {
600   idpf_ctlq_desc_t *desc;
601   u16 i = 0, num_to_clean;
602   u16 ntc, desc_err;
603   int ret = IDPF_SUCCESS;
604
605   if (!cq || !cq->ring_size)
606     return IDPF_ERR_CTLQ_EMPTY;
607
608   if (*clean_count == 0)
609     return IDPF_SUCCESS;
610   if (*clean_count > cq->ring_size)
611     return IDPF_ERR_PARAM;
612
613   /* Fixme rte func */
614   clib_spinlock_lock (&cq->cq_lock);
615
616   ntc = cq->next_to_clean;
617
618   num_to_clean = *clean_count;
619
620   for (i = 0; i < num_to_clean; i++)
621     {
622       /* Fetch next descriptor and check if marked as done */
623       desc = IDPF_CTLQ_DESC (cq, ntc);
624       if (!(desc->flags & IDPF_CTLQ_FLAG_DD))
625         break;
626
627       desc_err = desc->ret_val;
628       if (desc_err)
629         {
630           /* strip off FW internal code */
631           desc_err &= 0xff;
632         }
633
634       msg_status[i] = cq->bi.tx_msg[ntc];
635       msg_status[i]->status = desc_err;
636
637       cq->bi.tx_msg[ntc] = NULL;
638
639       /* Zero out any stale data */
640       clib_memset (desc, 0, sizeof (*desc));
641
642       ntc++;
643       if (ntc == cq->ring_size)
644         ntc = 0;
645     }
646
647   cq->next_to_clean = ntc;
648
649   clib_spinlock_unlock (&cq->cq_lock);
650
651   /* Return number of descriptors actually cleaned */
652   *clean_count = i;
653
654   return ret;
655 }
656
657 /**
658  * idpf_ctlq_post_rx_buffs - post buffers to descriptor ring
659  * @hw: pointer to hw struct
660  * @cq: pointer to control queue handle
661  * @buff_count: (input|output) input is number of buffers caller is trying to
662  * return; output is number of buffers that were not posted
663  * @buffs: array of pointers to dma mem structs to be given to hardware
664  *
665  * Caller uses this function to return DMA buffers to the descriptor ring after
666  * consuming them; buff_count will be the number of buffers.
667  *
668  * Note: this function needs to be called after a receive call even
669  * if there are no DMA buffers to be returned, i.e. buff_count = 0,
670  * buffs = NULL to support direct commands
671  */
672 int
673 idpf_ctlq_post_rx_buffs (idpf_device_t *id, struct idpf_ctlq_info *cq,
674                          u16 *buff_count, idpf_dma_mem_t **buffs)
675 {
676   idpf_ctlq_desc_t *desc;
677   u16 ntp = cq->next_to_post;
678   bool buffs_avail = false;
679   u16 tbp = ntp + 1;
680   int status = IDPF_SUCCESS;
681   int i = 0;
682
683   if (*buff_count > cq->ring_size)
684     return IDPF_ERR_PARAM;
685
686   if (*buff_count > 0)
687     buffs_avail = true;
688
689   clib_spinlock_lock (&cq->cq_lock);
690
691   if (tbp >= cq->ring_size)
692     tbp = 0;
693
694   if (tbp == cq->next_to_clean)
695     /* Nothing to do */
696     goto post_buffs_out;
697
698   /* Post buffers for as many as provided or up until the last one used */
699   while (ntp != cq->next_to_clean)
700     {
701       desc = IDPF_CTLQ_DESC (cq, ntp);
702
703       if (cq->bi.rx_buff[ntp])
704         goto fill_desc;
705       if (!buffs_avail)
706         {
707           /* If the caller hasn't given us any buffers or
708            * there are none left, search the ring itself
709            * for an available buffer to move to this
710            * entry starting at the next entry in the ring
711            */
712           tbp = ntp + 1;
713
714           /* Wrap ring if necessary */
715           if (tbp >= cq->ring_size)
716             tbp = 0;
717
718           while (tbp != cq->next_to_clean)
719             {
720               if (cq->bi.rx_buff[tbp])
721                 {
722                   cq->bi.rx_buff[ntp] = cq->bi.rx_buff[tbp];
723                   cq->bi.rx_buff[tbp] = NULL;
724
725                   /* Found a buffer, no need to
726                    * search anymore
727                    */
728                   break;
729                 }
730
731               /* Wrap ring if necessary */
732               tbp++;
733               if (tbp >= cq->ring_size)
734                 tbp = 0;
735             }
736
737           if (tbp == cq->next_to_clean)
738             goto post_buffs_out;
739         }
740       else
741         {
742           /* Give back pointer to DMA buffer */
743           cq->bi.rx_buff[ntp] = buffs[i];
744           i++;
745
746           if (i >= *buff_count)
747             buffs_avail = false;
748         }
749
750     fill_desc:
751       desc->flags = IDPF_CTLQ_FLAG_BUF | IDPF_CTLQ_FLAG_RD;
752
753       /* Post buffers to descriptor */
754       desc->datalen = cq->bi.rx_buff[ntp]->size;
755       desc->params.indirect.addr_high =
756         IDPF_HI_DWORD (cq->bi.rx_buff[ntp]->pa);
757       desc->params.indirect.addr_low = IDPF_LO_DWORD (cq->bi.rx_buff[ntp]->pa);
758
759       ntp++;
760       if (ntp == cq->ring_size)
761         ntp = 0;
762     }
763
764 post_buffs_out:
765   /* Only update tail if buffers were actually posted */
766   if (cq->next_to_post != ntp)
767     {
768       if (ntp)
769         /* Update next_to_post to ntp - 1 since current ntp
770          * will not have a buffer
771          */
772         cq->next_to_post = ntp - 1;
773       else
774         /* Wrap to end of end ring since current ntp is 0 */
775         cq->next_to_post = cq->ring_size - 1;
776
777       idpf_reg_write (id, cq->reg.tail, cq->next_to_post);
778     }
779
780   clib_spinlock_unlock (&cq->cq_lock);
781
782   /* return the number of buffers that were not posted */
783   *buff_count = *buff_count - i;
784
785   return status;
786 }
787
788 /**
789  * idpf_ctlq_recv - receive control queue message call back
790  * @cq: pointer to control queue handle to receive on
791  * @num_q_msg: (input|output) input number of messages that should be received;
792  * output number of messages actually received
793  * @q_msg: (output) array of received control queue messages on this q;
794  * needs to be pre-allocated by caller for as many messages as requested
795  *
796  * Called by interrupt handler or polling mechanism. Caller is expected
797  * to free buffers
798  */
799 int
800 idpf_ctlq_recv (struct idpf_ctlq_info *cq, u16 *num_q_msg,
801                 idpf_ctlq_msg_t *q_msg)
802 {
803   u16 num_to_clean, ntc, ret_val, flags;
804   idpf_ctlq_desc_t *desc;
805   int ret_code = 0;
806   u16 i = 0;
807
808   if (!cq || !cq->ring_size)
809     return -ENOBUFS;
810
811   if (*num_q_msg == 0)
812     return 0;
813   else if (*num_q_msg > cq->ring_size)
814     return -EINVAL;
815
816   /* Fixme: take the lock before we start messing with the ring */
817   clib_spinlock_lock (&cq->cq_lock);
818
819   ntc = cq->next_to_clean;
820
821   num_to_clean = *num_q_msg;
822
823   for (i = 0; i < num_to_clean; i++)
824     {
825       u64 msg_cookie;
826
827       /* Fetch next descriptor and check if marked as done */
828       desc = IDPF_CTLQ_DESC (cq, ntc);
829       flags = desc->flags;
830
831       if (!(flags & IDPF_CTLQ_FLAG_DD))
832         break;
833
834       ret_val = desc->ret_val;
835
836       q_msg[i].vmvf_type =
837         (flags & (IDPF_CTLQ_FLAG_FTYPE_VM | IDPF_CTLQ_FLAG_FTYPE_PF)) >>
838         IDPF_CTLQ_FLAG_FTYPE_S;
839
840       if (flags & IDPF_CTLQ_FLAG_ERR)
841         ret_code = IDPF_ERR_CTLQ_ERROR;
842
843       msg_cookie = (u64) desc->cookie_high << 32;
844       msg_cookie |= (u64) desc->cookie_low;
845       clib_memcpy_fast (&q_msg[i].cookie, &msg_cookie, sizeof (u64));
846
847       q_msg[i].opcode = desc->opcode;
848       q_msg[i].data_len = desc->datalen;
849       q_msg[i].status = ret_val;
850
851       if (desc->datalen)
852         {
853           clib_memcpy_fast (q_msg[i].ctx.indirect.context,
854                             &desc->params.indirect, IDPF_INDIRECT_CTX_SIZE);
855
856           /* Assign pointer to dma buffer to ctlq_msg array
857            * to be given to upper layer
858            */
859           q_msg[i].ctx.indirect.payload = cq->bi.rx_buff[ntc];
860
861           /* Zero out pointer to DMA buffer info;
862            * will be repopulated by post buffers API
863            */
864           cq->bi.rx_buff[ntc] = NULL;
865         }
866       else
867         {
868           clib_memcpy_fast (q_msg[i].ctx.direct, desc->params.raw,
869                             IDPF_DIRECT_CTX_SIZE);
870         }
871
872       /* Zero out stale data in descriptor */
873       clib_memset (desc, 0, sizeof (idpf_ctlq_desc_t));
874
875       ntc++;
876       if (ntc == cq->ring_size)
877         ntc = 0;
878     };
879
880   cq->next_to_clean = ntc;
881
882   /* Fixme */
883   clib_spinlock_unlock (&cq->cq_lock);
884
885   *num_q_msg = i;
886   if (*num_q_msg == 0)
887     ret_code = -ENOMSG;
888
889   return ret_code;
890 }