]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ixl/ixlvc.c
Fix insufficient oce(4) ioctl(2) privilege checking.
[FreeBSD/FreeBSD.git] / sys / dev / ixl / ixlvc.c
1 /******************************************************************************
2
3   Copyright (c) 2013-2019, Intel Corporation
4   All rights reserved.
5
6   Redistribution and use in source and binary forms, with or without 
7   modification, are permitted provided that the following conditions are met:
8   
9    1. Redistributions of source code must retain the above copyright notice, 
10       this list of conditions and the following disclaimer.
11   
12    2. Redistributions in binary form must reproduce the above copyright 
13       notice, this list of conditions and the following disclaimer in the 
14       documentation and/or other materials provided with the distribution.
15   
16    3. Neither the name of the Intel Corporation nor the names of its 
17       contributors may be used to endorse or promote products derived from 
18       this software without specific prior written permission.
19   
20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
22   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
23   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
24   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
25   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
26   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
27   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
28   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
29   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   POSSIBILITY OF SUCH DAMAGE.
31
32 ******************************************************************************/
33 /*$FreeBSD$*/
34
35 /*
36 **      Virtual Channel support
37 **              These are support functions to communication
38 **              between the VF and PF drivers.
39 */
40
41 #include "ixl.h"
42 #include "ixlv.h"
43 #include "i40e_prototype.h"
44
45
46 /* busy wait delay in msec */
47 #define IXLV_BUSY_WAIT_DELAY 10
48 #define IXLV_BUSY_WAIT_COUNT 50
49
50 static void     ixl_vc_process_resp(struct ixl_vc_mgr *, uint32_t,
51                     enum virtchnl_status_code);
52 static void     ixl_vc_process_next(struct ixl_vc_mgr *mgr);
53 static void     ixl_vc_schedule_retry(struct ixl_vc_mgr *mgr);
54 static void     ixl_vc_send_current(struct ixl_vc_mgr *mgr);
55
56 #ifdef IXL_DEBUG
57 /*
58 ** Validate VF messages
59 */
60 static int ixl_vc_validate_vf_msg(struct ixlv_sc *sc, u32 v_opcode,
61     u8 *msg, u16 msglen)
62 {
63         bool err_msg_format = false;
64         int valid_len;
65
66         /* Validate message length. */
67         switch (v_opcode) {
68         case VIRTCHNL_OP_VERSION:
69                 valid_len = sizeof(struct virtchnl_version_info);
70                 break;
71         case VIRTCHNL_OP_RESET_VF:
72                 valid_len = 0;
73                 break;
74         case VIRTCHNL_OP_GET_VF_RESOURCES:
75                 /* Valid length in api v1.0 is 0, v1.1 is 4 */
76                 valid_len = 4;
77                 break;
78         case VIRTCHNL_OP_CONFIG_TX_QUEUE:
79                 valid_len = sizeof(struct virtchnl_txq_info);
80                 break;
81         case VIRTCHNL_OP_CONFIG_RX_QUEUE:
82                 valid_len = sizeof(struct virtchnl_rxq_info);
83                 break;
84         case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
85                 valid_len = sizeof(struct virtchnl_vsi_queue_config_info);
86                 if (msglen >= valid_len) {
87                         struct virtchnl_vsi_queue_config_info *vqc =
88                             (struct virtchnl_vsi_queue_config_info *)msg;
89                         valid_len += (vqc->num_queue_pairs *
90                                       sizeof(struct
91                                              virtchnl_queue_pair_info));
92                         if (vqc->num_queue_pairs == 0)
93                                 err_msg_format = true;
94                 }
95                 break;
96         case VIRTCHNL_OP_CONFIG_IRQ_MAP:
97                 valid_len = sizeof(struct virtchnl_irq_map_info);
98                 if (msglen >= valid_len) {
99                         struct virtchnl_irq_map_info *vimi =
100                             (struct virtchnl_irq_map_info *)msg;
101                         valid_len += (vimi->num_vectors *
102                                       sizeof(struct virtchnl_vector_map));
103                         if (vimi->num_vectors == 0)
104                                 err_msg_format = true;
105                 }
106                 break;
107         case VIRTCHNL_OP_ENABLE_QUEUES:
108         case VIRTCHNL_OP_DISABLE_QUEUES:
109                 valid_len = sizeof(struct virtchnl_queue_select);
110                 break;
111         case VIRTCHNL_OP_ADD_ETH_ADDR:
112         case VIRTCHNL_OP_DEL_ETH_ADDR:
113                 valid_len = sizeof(struct virtchnl_ether_addr_list);
114                 if (msglen >= valid_len) {
115                         struct virtchnl_ether_addr_list *veal =
116                             (struct virtchnl_ether_addr_list *)msg;
117                         valid_len += veal->num_elements *
118                             sizeof(struct virtchnl_ether_addr);
119                         if (veal->num_elements == 0)
120                                 err_msg_format = true;
121                 }
122                 break;
123         case VIRTCHNL_OP_ADD_VLAN:
124         case VIRTCHNL_OP_DEL_VLAN:
125                 valid_len = sizeof(struct virtchnl_vlan_filter_list);
126                 if (msglen >= valid_len) {
127                         struct virtchnl_vlan_filter_list *vfl =
128                             (struct virtchnl_vlan_filter_list *)msg;
129                         valid_len += vfl->num_elements * sizeof(u16);
130                         if (vfl->num_elements == 0)
131                                 err_msg_format = true;
132                 }
133                 break;
134         case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
135                 valid_len = sizeof(struct virtchnl_promisc_info);
136                 break;
137         case VIRTCHNL_OP_GET_STATS:
138                 valid_len = sizeof(struct virtchnl_queue_select);
139                 break;
140         /* These are always errors coming from the VF. */
141         case VIRTCHNL_OP_EVENT:
142         case VIRTCHNL_OP_UNKNOWN:
143         default:
144                 return EPERM;
145                 break;
146         }
147         /* few more checks */
148         if ((valid_len != msglen) || (err_msg_format))
149                 return EINVAL;
150         else
151                 return 0;
152 }
153 #endif
154
155 /*
156 ** ixlv_send_pf_msg
157 **
158 ** Send message to PF and print status if failure.
159 */
160 static int
161 ixlv_send_pf_msg(struct ixlv_sc *sc,
162         enum virtchnl_ops op, u8 *msg, u16 len)
163 {
164         struct i40e_hw  *hw = &sc->hw;
165         device_t        dev = sc->dev;
166         i40e_status     err;
167
168 #ifdef IXL_DEBUG
169         /*
170         ** Pre-validating messages to the PF
171         */
172         int val_err;
173         val_err = ixl_vc_validate_vf_msg(sc, op, msg, len);
174         if (val_err)
175                 device_printf(dev, "Error validating msg to PF for op %d,"
176                     " msglen %d: error %d\n", op, len, val_err);
177 #endif
178
179         err = i40e_aq_send_msg_to_pf(hw, op, I40E_SUCCESS, msg, len, NULL);
180         if (err)
181                 device_printf(dev, "Unable to send opcode %s to PF, "
182                     "status %s, aq error %s\n",
183                     ixl_vc_opcode_str(op),
184                     i40e_stat_str(hw, err),
185                     i40e_aq_str(hw, hw->aq.asq_last_status));
186         return err;
187 }
188
189
190 /*
191 ** ixlv_send_api_ver
192 **
193 ** Send API version admin queue message to the PF. The reply is not checked
194 ** in this function. Returns 0 if the message was successfully
195 ** sent, or one of the I40E_ADMIN_QUEUE_ERROR_ statuses if not.
196 */
197 int
198 ixlv_send_api_ver(struct ixlv_sc *sc)
199 {
200         struct virtchnl_version_info vvi;
201
202         vvi.major = VIRTCHNL_VERSION_MAJOR;
203         vvi.minor = VIRTCHNL_VERSION_MINOR;
204
205         return ixlv_send_pf_msg(sc, VIRTCHNL_OP_VERSION,
206             (u8 *)&vvi, sizeof(vvi));
207 }
208
209 /*
210 ** ixlv_verify_api_ver
211 **
212 ** Compare API versions with the PF. Must be called after admin queue is
213 ** initialized. Returns 0 if API versions match, EIO if
214 ** they do not, or I40E_ERR_ADMIN_QUEUE_NO_WORK if the admin queue is empty.
215 */
216 int
217 ixlv_verify_api_ver(struct ixlv_sc *sc)
218 {
219         struct virtchnl_version_info *pf_vvi;
220         struct i40e_hw *hw = &sc->hw;
221         struct i40e_arq_event_info event;
222         device_t dev = sc->dev;
223         i40e_status err;
224         int retries = 0;
225
226         event.buf_len = IXL_AQ_BUF_SZ;
227         event.msg_buf = malloc(event.buf_len, M_DEVBUF, M_NOWAIT);
228         if (!event.msg_buf) {
229                 err = ENOMEM;
230                 goto out;
231         }
232
233         for (;;) {
234                 if (++retries > IXLV_AQ_MAX_ERR)
235                         goto out_alloc;
236
237                 /* Initial delay here is necessary */
238                 i40e_msec_pause(100);
239                 err = i40e_clean_arq_element(hw, &event, NULL);
240                 if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK)
241                         continue;
242                 else if (err) {
243                         err = EIO;
244                         goto out_alloc;
245                 }
246
247                 if ((enum virtchnl_ops)le32toh(event.desc.cookie_high) !=
248                     VIRTCHNL_OP_VERSION) {
249                         DDPRINTF(dev, "Received unexpected op response: %d\n",
250                             le32toh(event.desc.cookie_high));
251                         /* Don't stop looking for expected response */
252                         continue;
253                 }
254
255                 err = (i40e_status)le32toh(event.desc.cookie_low);
256                 if (err) {
257                         err = EIO;
258                         goto out_alloc;
259                 } else
260                         break;
261         }
262
263         pf_vvi = (struct virtchnl_version_info *)event.msg_buf;
264         if ((pf_vvi->major > VIRTCHNL_VERSION_MAJOR) ||
265             ((pf_vvi->major == VIRTCHNL_VERSION_MAJOR) &&
266             (pf_vvi->minor > VIRTCHNL_VERSION_MINOR))) {
267                 device_printf(dev, "Critical PF/VF API version mismatch!\n");
268                 err = EIO;
269         } else
270                 sc->pf_version = pf_vvi->minor;
271         
272         /* Log PF/VF api versions */
273         device_printf(dev, "PF API %d.%d / VF API %d.%d\n",
274             pf_vvi->major, pf_vvi->minor,
275             VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
276
277 out_alloc:
278         free(event.msg_buf, M_DEVBUF);
279 out:
280         return (err);
281 }
282
283 /*
284 ** ixlv_send_vf_config_msg
285 **
286 ** Send VF configuration request admin queue message to the PF. The reply
287 ** is not checked in this function. Returns 0 if the message was
288 ** successfully sent, or one of the I40E_ADMIN_QUEUE_ERROR_ statuses if not.
289 */
290 int
291 ixlv_send_vf_config_msg(struct ixlv_sc *sc)
292 {
293         u32     caps;
294
295         caps = VIRTCHNL_VF_OFFLOAD_L2 |
296             VIRTCHNL_VF_OFFLOAD_RSS_PF |
297             VIRTCHNL_VF_OFFLOAD_VLAN;
298
299         if (sc->pf_version == VIRTCHNL_VERSION_MINOR_NO_VF_CAPS)
300                 return ixlv_send_pf_msg(sc, VIRTCHNL_OP_GET_VF_RESOURCES,
301                                   NULL, 0);
302         else
303                 return ixlv_send_pf_msg(sc, VIRTCHNL_OP_GET_VF_RESOURCES,
304                                   (u8 *)&caps, sizeof(caps));
305 }
306
307 /*
308 ** ixlv_get_vf_config
309 **
310 ** Get VF configuration from PF and populate hw structure. Must be called after
311 ** admin queue is initialized. Busy waits until response is received from PF,
312 ** with maximum timeout. Response from PF is returned in the buffer for further
313 ** processing by the caller.
314 */
315 int
316 ixlv_get_vf_config(struct ixlv_sc *sc)
317 {
318         struct i40e_hw  *hw = &sc->hw;
319         device_t        dev = sc->dev;
320         struct i40e_arq_event_info event;
321         u16 len;
322         i40e_status err = 0;
323         u32 retries = 0;
324
325         /* Note this assumes a single VSI */
326         len = sizeof(struct virtchnl_vf_resource) +
327             sizeof(struct virtchnl_vsi_resource);
328         event.buf_len = len;
329         event.msg_buf = malloc(event.buf_len, M_DEVBUF, M_NOWAIT);
330         if (!event.msg_buf) {
331                 err = ENOMEM;
332                 goto out;
333         }
334
335         for (;;) {
336                 err = i40e_clean_arq_element(hw, &event, NULL);
337                 if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) {
338                         if (++retries <= IXLV_AQ_MAX_ERR)
339                                 i40e_msec_pause(10);
340                 } else if ((enum virtchnl_ops)le32toh(event.desc.cookie_high) !=
341                     VIRTCHNL_OP_GET_VF_RESOURCES) {
342                         DDPRINTF(dev, "Received a response from PF,"
343                             " opcode %d, error %d",
344                             le32toh(event.desc.cookie_high),
345                             le32toh(event.desc.cookie_low));
346                         retries++;
347                         continue;
348                 } else {
349                         err = (i40e_status)le32toh(event.desc.cookie_low);
350                         if (err) {
351                                 device_printf(dev, "%s: Error returned from PF,"
352                                     " opcode %d, error %d\n", __func__,
353                                     le32toh(event.desc.cookie_high),
354                                     le32toh(event.desc.cookie_low));
355                                 err = EIO;
356                                 goto out_alloc;
357                         }
358                         /* We retrieved the config message, with no errors */
359                         break;
360                 }
361
362                 if (retries > IXLV_AQ_MAX_ERR) {
363                         INIT_DBG_DEV(dev, "Did not receive response after %d tries.",
364                             retries);
365                         err = ETIMEDOUT;
366                         goto out_alloc;
367                 }
368         }
369
370         memcpy(sc->vf_res, event.msg_buf, min(event.msg_len, len));
371         i40e_vf_parse_hw_config(hw, sc->vf_res);
372
373 out_alloc:
374         free(event.msg_buf, M_DEVBUF);
375 out:
376         return err;
377 }
378
379 /*
380 ** ixlv_configure_queues
381 **
382 ** Request that the PF set up our queues.
383 */
384 void
385 ixlv_configure_queues(struct ixlv_sc *sc)
386 {
387         device_t                dev = sc->dev;
388         struct ixl_vsi          *vsi = &sc->vsi;
389         struct ixl_queue        *que = vsi->queues;
390         struct tx_ring          *txr;
391         struct rx_ring          *rxr;
392         int                     len, pairs;
393
394         struct virtchnl_vsi_queue_config_info *vqci;
395         struct virtchnl_queue_pair_info *vqpi;
396
397         pairs = vsi->num_queues;
398         len = sizeof(struct virtchnl_vsi_queue_config_info) +
399                        (sizeof(struct virtchnl_queue_pair_info) * pairs);
400         vqci = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
401         if (!vqci) {
402                 device_printf(dev, "%s: unable to allocate memory\n", __func__);
403                 ixl_vc_schedule_retry(&sc->vc_mgr);
404                 return;
405         }
406         vqci->vsi_id = sc->vsi_res->vsi_id;
407         vqci->num_queue_pairs = pairs;
408         vqpi = vqci->qpair;
409         /* Size check is not needed here - HW max is 16 queue pairs, and we
410          * can fit info for 31 of them into the AQ buffer before it overflows.
411          */
412         for (int i = 0; i < pairs; i++, que++, vqpi++) {
413                 txr = &que->txr;
414                 rxr = &que->rxr;
415                 vqpi->txq.vsi_id = vqci->vsi_id;
416                 vqpi->txq.queue_id = i;
417                 vqpi->txq.ring_len = que->num_tx_desc;
418                 vqpi->txq.dma_ring_addr = txr->dma.pa;
419                 /* Enable Head writeback */
420                 if (vsi->enable_head_writeback) {
421                         vqpi->txq.headwb_enabled = 1;
422                         vqpi->txq.dma_headwb_addr = txr->dma.pa +
423                             (que->num_tx_desc * sizeof(struct i40e_tx_desc));
424                 }
425
426                 vqpi->rxq.vsi_id = vqci->vsi_id;
427                 vqpi->rxq.queue_id = i;
428                 vqpi->rxq.ring_len = que->num_rx_desc;
429                 vqpi->rxq.dma_ring_addr = rxr->dma.pa;
430                 vqpi->rxq.max_pkt_size = vsi->max_frame_size;
431                 vqpi->rxq.databuffer_size = rxr->mbuf_sz;
432                 vqpi->rxq.splithdr_enabled = 0;
433         }
434
435         ixlv_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_VSI_QUEUES,
436                            (u8 *)vqci, len);
437         free(vqci, M_DEVBUF);
438 }
439
440 /*
441 ** ixlv_enable_queues
442 **
443 ** Request that the PF enable all of our queues.
444 */
445 void
446 ixlv_enable_queues(struct ixlv_sc *sc)
447 {
448         struct virtchnl_queue_select vqs;
449
450         vqs.vsi_id = sc->vsi_res->vsi_id;
451         vqs.tx_queues = (1 << sc->vsi_res->num_queue_pairs) - 1;
452         vqs.rx_queues = vqs.tx_queues;
453         ixlv_send_pf_msg(sc, VIRTCHNL_OP_ENABLE_QUEUES,
454                            (u8 *)&vqs, sizeof(vqs));
455 }
456
457 /*
458 ** ixlv_disable_queues
459 **
460 ** Request that the PF disable all of our queues.
461 */
462 void
463 ixlv_disable_queues(struct ixlv_sc *sc)
464 {
465         struct virtchnl_queue_select vqs;
466
467         vqs.vsi_id = sc->vsi_res->vsi_id;
468         vqs.tx_queues = (1 << sc->vsi_res->num_queue_pairs) - 1;
469         vqs.rx_queues = vqs.tx_queues;
470         ixlv_send_pf_msg(sc, VIRTCHNL_OP_DISABLE_QUEUES,
471                            (u8 *)&vqs, sizeof(vqs));
472 }
473
474 /*
475 ** ixlv_map_queues
476 **
477 ** Request that the PF map queues to interrupt vectors. Misc causes, including
478 ** admin queue, are always mapped to vector 0.
479 */
480 void
481 ixlv_map_queues(struct ixlv_sc *sc)
482 {
483         struct virtchnl_irq_map_info *vm;
484         int                     i, q, len;
485         struct ixl_vsi          *vsi = &sc->vsi;
486         struct ixl_queue        *que = vsi->queues;
487
488         /* How many queue vectors, adminq uses one */
489         q = sc->msix - 1;
490
491         len = sizeof(struct virtchnl_irq_map_info) +
492               (sc->msix * sizeof(struct virtchnl_vector_map));
493         vm = malloc(len, M_DEVBUF, M_NOWAIT);
494         if (!vm) {
495                 printf("%s: unable to allocate memory\n", __func__);
496                 ixl_vc_schedule_retry(&sc->vc_mgr);
497                 return;
498         }
499
500         vm->num_vectors = sc->msix;
501         /* Queue vectors first */
502         for (i = 0; i < q; i++, que++) {
503                 vm->vecmap[i].vsi_id = sc->vsi_res->vsi_id;
504                 vm->vecmap[i].vector_id = i + 1; /* first is adminq */
505                 vm->vecmap[i].txq_map = (1 << que->me);
506                 vm->vecmap[i].rxq_map = (1 << que->me);
507                 vm->vecmap[i].rxitr_idx = 0;
508                 vm->vecmap[i].txitr_idx = 1;
509         }
510
511         /* Misc vector last - this is only for AdminQ messages */
512         vm->vecmap[i].vsi_id = sc->vsi_res->vsi_id;
513         vm->vecmap[i].vector_id = 0;
514         vm->vecmap[i].txq_map = 0;
515         vm->vecmap[i].rxq_map = 0;
516         vm->vecmap[i].rxitr_idx = 0;
517         vm->vecmap[i].txitr_idx = 0;
518
519         ixlv_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_IRQ_MAP,
520             (u8 *)vm, len);
521         free(vm, M_DEVBUF);
522 }
523
524 /*
525 ** Scan the Filter List looking for vlans that need
526 ** to be added, then create the data to hand to the AQ
527 ** for handling.
528 */
529 void
530 ixlv_add_vlans(struct ixlv_sc *sc)
531 {
532         struct virtchnl_vlan_filter_list        *v;
533         struct ixlv_vlan_filter *f, *ftmp;
534         device_t        dev = sc->dev;
535         int             len, i = 0, cnt = 0;
536
537         /* Get count of VLAN filters to add */
538         SLIST_FOREACH(f, sc->vlan_filters, next) {
539                 if (f->flags & IXL_FILTER_ADD)
540                         cnt++;
541         }
542
543         if (!cnt) {  /* no work... */
544                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_VLAN_FILTER,
545                     VIRTCHNL_STATUS_SUCCESS);
546                 return;
547         }
548
549         len = sizeof(struct virtchnl_vlan_filter_list) +
550               (cnt * sizeof(u16));
551
552         if (len > IXL_AQ_BUF_SZ) {
553                 device_printf(dev, "%s: Exceeded Max AQ Buf size\n",
554                         __func__);
555                 ixl_vc_schedule_retry(&sc->vc_mgr);
556                 return;
557         }
558
559         v = malloc(len, M_DEVBUF, M_NOWAIT);
560         if (!v) {
561                 device_printf(dev, "%s: unable to allocate memory\n",
562                         __func__);
563                 ixl_vc_schedule_retry(&sc->vc_mgr);
564                 return;
565         }
566
567         v->vsi_id = sc->vsi_res->vsi_id;
568         v->num_elements = cnt;
569
570         /* Scan the filter array */
571         SLIST_FOREACH_SAFE(f, sc->vlan_filters, next, ftmp) {
572                 if (f->flags & IXL_FILTER_ADD) {
573                         bcopy(&f->vlan, &v->vlan_id[i], sizeof(u16));
574                         f->flags = IXL_FILTER_USED;
575                         i++;
576                 }
577                 if (i == cnt)
578                         break;
579         }
580
581         ixlv_send_pf_msg(sc, VIRTCHNL_OP_ADD_VLAN, (u8 *)v, len);
582         free(v, M_DEVBUF);
583         /* add stats? */
584 }
585
586 /*
587 ** Scan the Filter Table looking for vlans that need
588 ** to be removed, then create the data to hand to the AQ
589 ** for handling.
590 */
591 void
592 ixlv_del_vlans(struct ixlv_sc *sc)
593 {
594         device_t        dev = sc->dev;
595         struct virtchnl_vlan_filter_list *v;
596         struct ixlv_vlan_filter *f, *ftmp;
597         int len, i = 0, cnt = 0;
598
599         /* Get count of VLAN filters to delete */
600         SLIST_FOREACH(f, sc->vlan_filters, next) {
601                 if (f->flags & IXL_FILTER_DEL)
602                         cnt++;
603         }
604
605         if (!cnt) {  /* no work... */
606                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_VLAN_FILTER,
607                     VIRTCHNL_STATUS_SUCCESS);
608                 return;
609         }
610
611         len = sizeof(struct virtchnl_vlan_filter_list) +
612               (cnt * sizeof(u16));
613
614         if (len > IXL_AQ_BUF_SZ) {
615                 device_printf(dev, "%s: Exceeded Max AQ Buf size\n",
616                         __func__);
617                 ixl_vc_schedule_retry(&sc->vc_mgr);
618                 return;
619         }
620
621         v = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
622         if (!v) {
623                 device_printf(dev, "%s: unable to allocate memory\n",
624                         __func__);
625                 ixl_vc_schedule_retry(&sc->vc_mgr);
626                 return;
627         }
628
629         v->vsi_id = sc->vsi_res->vsi_id;
630         v->num_elements = cnt;
631
632         /* Scan the filter array */
633         SLIST_FOREACH_SAFE(f, sc->vlan_filters, next, ftmp) {
634                 if (f->flags & IXL_FILTER_DEL) {
635                         bcopy(&f->vlan, &v->vlan_id[i], sizeof(u16));
636                         i++;
637                         SLIST_REMOVE(sc->vlan_filters, f, ixlv_vlan_filter, next);
638                         free(f, M_DEVBUF);
639                 }
640                 if (i == cnt)
641                         break;
642         }
643
644         ixlv_send_pf_msg(sc, VIRTCHNL_OP_DEL_VLAN, (u8 *)v, len);
645         free(v, M_DEVBUF);
646         /* add stats? */
647 }
648
649
650 /*
651 ** This routine takes additions to the vsi filter
652 ** table and creates an Admin Queue call to create
653 ** the filters in the hardware.
654 */
655 void
656 ixlv_add_ether_filters(struct ixlv_sc *sc)
657 {
658         struct virtchnl_ether_addr_list *a;
659         struct ixlv_mac_filter  *f;
660         device_t                        dev = sc->dev;
661         int                             len, j = 0, cnt = 0;
662
663         /* Get count of MAC addresses to add */
664         SLIST_FOREACH(f, sc->mac_filters, next) {
665                 if (f->flags & IXL_FILTER_ADD)
666                         cnt++;
667         }
668         if (cnt == 0) { /* Should not happen... */
669                 DDPRINTF(dev, "cnt == 0, exiting...");
670                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_MAC_FILTER,
671                     VIRTCHNL_STATUS_SUCCESS);
672                 return;
673         }
674
675         len = sizeof(struct virtchnl_ether_addr_list) +
676             (cnt * sizeof(struct virtchnl_ether_addr));
677
678         a = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
679         if (a == NULL) {
680                 device_printf(dev, "%s: Failed to get memory for "
681                     "virtchnl_ether_addr_list\n", __func__);
682                 ixl_vc_schedule_retry(&sc->vc_mgr);
683                 return;
684         }
685         a->vsi_id = sc->vsi.id;
686         a->num_elements = cnt;
687
688         /* Scan the filter array */
689         SLIST_FOREACH(f, sc->mac_filters, next) {
690                 if (f->flags & IXL_FILTER_ADD) {
691                         bcopy(f->macaddr, a->list[j].addr, ETHER_ADDR_LEN);
692                         f->flags &= ~IXL_FILTER_ADD;
693                         j++;
694
695                         DDPRINTF(dev, "ADD: " MAC_FORMAT,
696                             MAC_FORMAT_ARGS(f->macaddr));
697                 }
698                 if (j == cnt)
699                         break;
700         }
701         DDPRINTF(dev, "len %d, j %d, cnt %d",
702             len, j, cnt);
703         ixlv_send_pf_msg(sc,
704             VIRTCHNL_OP_ADD_ETH_ADDR, (u8 *)a, len);
705         /* add stats? */
706         free(a, M_DEVBUF);
707         return;
708 }
709
710 /*
711 ** This routine takes filters flagged for deletion in the
712 ** sc MAC filter list and creates an Admin Queue call
713 ** to delete those filters in the hardware.
714 */
715 void
716 ixlv_del_ether_filters(struct ixlv_sc *sc)
717 {
718         struct virtchnl_ether_addr_list *d;
719         device_t                        dev = sc->dev;
720         struct ixlv_mac_filter  *f, *f_temp;
721         int                             len, j = 0, cnt = 0;
722
723         /* Get count of MAC addresses to delete */
724         SLIST_FOREACH(f, sc->mac_filters, next) {
725                 if (f->flags & IXL_FILTER_DEL)
726                         cnt++;
727         }
728         if (cnt == 0) {
729                 DDPRINTF(dev, "cnt == 0, exiting...");
730                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_MAC_FILTER,
731                     VIRTCHNL_STATUS_SUCCESS);
732                 return;
733         }
734
735         len = sizeof(struct virtchnl_ether_addr_list) +
736             (cnt * sizeof(struct virtchnl_ether_addr));
737
738         d = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
739         if (d == NULL) {
740                 device_printf(dev, "%s: Failed to get memory for "
741                     "virtchnl_ether_addr_list\n", __func__);
742                 ixl_vc_schedule_retry(&sc->vc_mgr);
743                 return;
744         }
745         d->vsi_id = sc->vsi.id;
746         d->num_elements = cnt;
747
748         /* Scan the filter array */
749         SLIST_FOREACH_SAFE(f, sc->mac_filters, next, f_temp) {
750                 if (f->flags & IXL_FILTER_DEL) {
751                         bcopy(f->macaddr, d->list[j].addr, ETHER_ADDR_LEN);
752                         DDPRINTF(dev, "DEL: " MAC_FORMAT,
753                             MAC_FORMAT_ARGS(f->macaddr));
754                         j++;
755                         SLIST_REMOVE(sc->mac_filters, f, ixlv_mac_filter, next);
756                         free(f, M_DEVBUF);
757                 }
758                 if (j == cnt)
759                         break;
760         }
761         ixlv_send_pf_msg(sc,
762             VIRTCHNL_OP_DEL_ETH_ADDR, (u8 *)d, len);
763         /* add stats? */
764         free(d, M_DEVBUF);
765         return;
766 }
767
768 /*
769 ** ixlv_request_reset
770 ** Request that the PF reset this VF. No response is expected.
771 */
772 void
773 ixlv_request_reset(struct ixlv_sc *sc)
774 {
775         /*
776         ** Set the reset status to "in progress" before
777         ** the request, this avoids any possibility of
778         ** a mistaken early detection of completion.
779         */
780         wr32(&sc->hw, I40E_VFGEN_RSTAT, VIRTCHNL_VFR_INPROGRESS);
781         ixlv_send_pf_msg(sc, VIRTCHNL_OP_RESET_VF, NULL, 0);
782 }
783
784 /*
785 ** ixlv_request_stats
786 ** Request the statistics for this VF's VSI from PF.
787 */
788 void
789 ixlv_request_stats(struct ixlv_sc *sc)
790 {
791         struct virtchnl_queue_select vqs;
792         int error = 0;
793
794         vqs.vsi_id = sc->vsi_res->vsi_id;
795         /* Low priority, we don't need to error check */
796         error = ixlv_send_pf_msg(sc, VIRTCHNL_OP_GET_STATS,
797             (u8 *)&vqs, sizeof(vqs));
798 #ifdef IXL_DEBUG
799         if (error)
800                 device_printf(sc->dev, "Error sending stats request to PF: %d\n", error);
801 #endif
802 }
803
804 /*
805 ** Updates driver's stats counters with VSI stats returned from PF.
806 */
807 void
808 ixlv_update_stats_counters(struct ixlv_sc *sc, struct i40e_eth_stats *es)
809 {
810         struct ixl_vsi *vsi = &sc->vsi;
811         uint64_t tx_discards;
812
813         tx_discards = es->tx_discards;
814         for (int i = 0; i < vsi->num_queues; i++)
815                 tx_discards += sc->vsi.queues[i].txr.br->br_drops;
816
817         /* Update ifnet stats */
818         IXL_SET_IPACKETS(vsi, es->rx_unicast +
819                            es->rx_multicast +
820                            es->rx_broadcast);
821         IXL_SET_OPACKETS(vsi, es->tx_unicast +
822                            es->tx_multicast +
823                            es->tx_broadcast);
824         IXL_SET_IBYTES(vsi, es->rx_bytes);
825         IXL_SET_OBYTES(vsi, es->tx_bytes);
826         IXL_SET_IMCASTS(vsi, es->rx_multicast);
827         IXL_SET_OMCASTS(vsi, es->tx_multicast);
828
829         IXL_SET_OERRORS(vsi, es->tx_errors);
830         IXL_SET_IQDROPS(vsi, es->rx_discards);
831         IXL_SET_OQDROPS(vsi, tx_discards);
832         IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol);
833         IXL_SET_COLLISIONS(vsi, 0);
834
835         vsi->eth_stats = *es;
836 }
837
838 void
839 ixlv_config_rss_key(struct ixlv_sc *sc)
840 {
841         struct virtchnl_rss_key *rss_key_msg;
842         int msg_len, key_length;
843         u8              rss_seed[IXL_RSS_KEY_SIZE];
844
845 #ifdef RSS
846         /* Fetch the configured RSS key */
847         rss_getkey((uint8_t *) &rss_seed);
848 #else
849         ixl_get_default_rss_key((u32 *)rss_seed);
850 #endif
851
852         /* Send the fetched key */
853         key_length = IXL_RSS_KEY_SIZE;
854         msg_len = sizeof(struct virtchnl_rss_key) + (sizeof(u8) * key_length) - 1;
855         rss_key_msg = malloc(msg_len, M_DEVBUF, M_NOWAIT | M_ZERO);
856         if (rss_key_msg == NULL) {
857                 device_printf(sc->dev, "Unable to allocate msg memory for RSS key msg.\n");
858                 return;
859         }
860
861         rss_key_msg->vsi_id = sc->vsi_res->vsi_id;
862         rss_key_msg->key_len = key_length;
863         bcopy(rss_seed, &rss_key_msg->key[0], key_length);
864
865         DDPRINTF(sc->dev, "config_rss: vsi_id %d, key_len %d",
866             rss_key_msg->vsi_id, rss_key_msg->key_len);
867         
868         ixlv_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_RSS_KEY,
869                           (u8 *)rss_key_msg, msg_len);
870
871         free(rss_key_msg, M_DEVBUF);
872 }
873
874 void
875 ixlv_set_rss_hena(struct ixlv_sc *sc)
876 {
877         struct virtchnl_rss_hena hena;
878
879         hena.hena = IXL_DEFAULT_RSS_HENA_X722;
880
881         ixlv_send_pf_msg(sc, VIRTCHNL_OP_SET_RSS_HENA,
882                           (u8 *)&hena, sizeof(hena));
883 }
884
885 void
886 ixlv_config_rss_lut(struct ixlv_sc *sc)
887 {
888         struct virtchnl_rss_lut *rss_lut_msg;
889         int msg_len;
890         u16 lut_length;
891         u32 lut;
892         int i, que_id;
893
894         lut_length = IXL_RSS_VSI_LUT_SIZE;
895         msg_len = sizeof(struct virtchnl_rss_lut) + (lut_length * sizeof(u8)) - 1;
896         rss_lut_msg = malloc(msg_len, M_DEVBUF, M_NOWAIT | M_ZERO);
897         if (rss_lut_msg == NULL) {
898                 device_printf(sc->dev, "Unable to allocate msg memory for RSS lut msg.\n");
899                 return;
900         }
901
902         rss_lut_msg->vsi_id = sc->vsi_res->vsi_id;
903         /* Each LUT entry is a max of 1 byte, so this is easy */
904         rss_lut_msg->lut_entries = lut_length;
905
906         /* Populate the LUT with max no. of queues in round robin fashion */
907         for (i = 0; i < lut_length; i++) {
908 #ifdef RSS
909                 /*
910                  * Fetch the RSS bucket id for the given indirection entry.
911                  * Cap it at the number of configured buckets (which is
912                  * num_queues.)
913                  */
914                 que_id = rss_get_indirection_to_bucket(i);
915                 que_id = que_id % sc->vsi.num_queues;
916 #else
917                 que_id = i % sc->vsi.num_queues;
918 #endif
919                 lut = que_id & IXL_RSS_VSI_LUT_ENTRY_MASK;
920                 rss_lut_msg->lut[i] = lut;
921         }
922
923         ixlv_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_RSS_LUT,
924                           (u8 *)rss_lut_msg, msg_len);
925
926         free(rss_lut_msg, M_DEVBUF);
927 }
928
929 /*
930 ** ixlv_vc_completion
931 **
932 ** Asynchronous completion function for admin queue messages. Rather than busy
933 ** wait, we fire off our requests and assume that no errors will be returned.
934 ** This function handles the reply messages.
935 */
936 void
937 ixlv_vc_completion(struct ixlv_sc *sc,
938     enum virtchnl_ops v_opcode,
939     enum virtchnl_status_code v_retval, u8 *msg, u16 msglen)
940 {
941         device_t        dev = sc->dev;
942         struct ixl_vsi  *vsi = &sc->vsi;
943
944         if (v_opcode == VIRTCHNL_OP_EVENT) {
945                 struct virtchnl_pf_event *vpe =
946                         (struct virtchnl_pf_event *)msg;
947
948                 switch (vpe->event) {
949                 case VIRTCHNL_EVENT_LINK_CHANGE:
950 #ifdef IXL_DEBUG
951                         device_printf(dev, "Link change: status %d, speed %d\n",
952                             vpe->event_data.link_event.link_status,
953                             vpe->event_data.link_event.link_speed);
954 #endif
955                         sc->link_up =
956                                 vpe->event_data.link_event.link_status;
957                         sc->link_speed =
958                                 vpe->event_data.link_event.link_speed;
959                         ixlv_update_link_status(sc);
960                         break;
961                 case VIRTCHNL_EVENT_RESET_IMPENDING:
962                         device_printf(dev, "PF initiated reset!\n");
963                         sc->init_state = IXLV_RESET_PENDING;
964                         mtx_unlock(&sc->mtx);
965                         ixlv_init(vsi);
966                         mtx_lock(&sc->mtx);
967                         break;
968                 default:
969                         device_printf(dev, "%s: Unknown event %d from AQ\n",
970                                 __func__, vpe->event);
971                         break;
972                 }
973
974                 return;
975         }
976
977         /* Catch-all error response */
978         if (v_retval) {
979                 device_printf(dev,
980                     "%s: AQ returned error %s to our request %s!\n",
981                     __func__, i40e_vc_stat_str(&sc->hw, v_retval), ixl_vc_opcode_str(v_opcode));
982         }
983
984 #ifdef IXL_DEBUG
985         if (v_opcode != VIRTCHNL_OP_GET_STATS)
986                 DDPRINTF(dev, "opcode %d", v_opcode);
987 #endif
988
989         switch (v_opcode) {
990         case VIRTCHNL_OP_GET_STATS:
991                 ixlv_update_stats_counters(sc, (struct i40e_eth_stats *)msg);
992                 break;
993         case VIRTCHNL_OP_ADD_ETH_ADDR:
994                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_MAC_FILTER,
995                     v_retval);
996                 if (v_retval) {
997                         device_printf(dev, "WARNING: Error adding VF mac filter!\n");
998                         device_printf(dev, "WARNING: Device may not receive traffic!\n");
999                 }
1000                 break;
1001         case VIRTCHNL_OP_DEL_ETH_ADDR:
1002                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_MAC_FILTER,
1003                     v_retval);
1004                 break;
1005         case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
1006                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_CONFIGURE_PROMISC,
1007                     v_retval);
1008                 break;
1009         case VIRTCHNL_OP_ADD_VLAN:
1010                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_VLAN_FILTER,
1011                     v_retval);
1012                 break;
1013         case VIRTCHNL_OP_DEL_VLAN:
1014                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_VLAN_FILTER,
1015                     v_retval);
1016                 break;
1017         case VIRTCHNL_OP_ENABLE_QUEUES:
1018                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ENABLE_QUEUES,
1019                     v_retval);
1020                 if (v_retval == 0) {
1021                         /* Update link status */
1022                         ixlv_update_link_status(sc);
1023                         /* Turn on all interrupts */
1024                         ixlv_enable_intr(vsi);
1025                         /* And inform the stack we're ready */
1026                         vsi->ifp->if_drv_flags |= IFF_DRV_RUNNING;
1027                         /* TODO: Clear a state flag, so we know we're ready to run init again */
1028                 }
1029                 break;
1030         case VIRTCHNL_OP_DISABLE_QUEUES:
1031                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DISABLE_QUEUES,
1032                     v_retval);
1033                 if (v_retval == 0) {
1034                         /* Turn off all interrupts */
1035                         ixlv_disable_intr(vsi);
1036                         /* Tell the stack that the interface is no longer active */
1037                         vsi->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING);
1038                 }
1039                 break;
1040         case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
1041                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_CONFIGURE_QUEUES,
1042                     v_retval);
1043                 break;
1044         case VIRTCHNL_OP_CONFIG_IRQ_MAP:
1045                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_MAP_VECTORS,
1046                     v_retval);
1047                 break;
1048         case VIRTCHNL_OP_CONFIG_RSS_KEY:
1049                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_CONFIG_RSS_KEY,
1050                     v_retval);
1051                 break;
1052         case VIRTCHNL_OP_SET_RSS_HENA:
1053                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_SET_RSS_HENA,
1054                     v_retval);
1055                 break;
1056         case VIRTCHNL_OP_CONFIG_RSS_LUT:
1057                 ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_CONFIG_RSS_LUT,
1058                     v_retval);
1059                 break;
1060         default:
1061 #ifdef IXL_DEBUG
1062                 device_printf(dev,
1063                     "%s: Received unexpected message %s from PF.\n",
1064                     __func__, ixl_vc_opcode_str(v_opcode));
1065 #endif
1066                 break;
1067         }
1068         return;
1069 }
1070
1071 static void
1072 ixl_vc_send_cmd(struct ixlv_sc *sc, uint32_t request)
1073 {
1074
1075         switch (request) {
1076         case IXLV_FLAG_AQ_MAP_VECTORS:
1077                 ixlv_map_queues(sc);
1078                 break;
1079
1080         case IXLV_FLAG_AQ_ADD_MAC_FILTER:
1081                 ixlv_add_ether_filters(sc);
1082                 break;
1083
1084         case IXLV_FLAG_AQ_ADD_VLAN_FILTER:
1085                 ixlv_add_vlans(sc);
1086                 break;
1087
1088         case IXLV_FLAG_AQ_DEL_MAC_FILTER:
1089                 ixlv_del_ether_filters(sc);
1090                 break;
1091
1092         case IXLV_FLAG_AQ_DEL_VLAN_FILTER:
1093                 ixlv_del_vlans(sc);
1094                 break;
1095
1096         case IXLV_FLAG_AQ_CONFIGURE_QUEUES:
1097                 ixlv_configure_queues(sc);
1098                 break;
1099
1100         case IXLV_FLAG_AQ_DISABLE_QUEUES:
1101                 ixlv_disable_queues(sc);
1102                 break;
1103
1104         case IXLV_FLAG_AQ_ENABLE_QUEUES:
1105                 ixlv_enable_queues(sc);
1106                 break;
1107
1108         case IXLV_FLAG_AQ_CONFIG_RSS_KEY:
1109                 ixlv_config_rss_key(sc);
1110                 break;
1111
1112         case IXLV_FLAG_AQ_SET_RSS_HENA:
1113                 ixlv_set_rss_hena(sc);
1114                 break;
1115
1116         case IXLV_FLAG_AQ_CONFIG_RSS_LUT:
1117                 ixlv_config_rss_lut(sc);
1118                 break;
1119         }
1120 }
1121
1122 void
1123 ixl_vc_init_mgr(struct ixlv_sc *sc, struct ixl_vc_mgr *mgr)
1124 {
1125         mgr->sc = sc;
1126         mgr->current = NULL;
1127         TAILQ_INIT(&mgr->pending);
1128         callout_init_mtx(&mgr->callout, &sc->mtx, 0);
1129 }
1130
1131 static void
1132 ixl_vc_process_completion(struct ixl_vc_mgr *mgr, enum i40e_status_code err)
1133 {
1134         struct ixl_vc_cmd *cmd;
1135
1136         cmd = mgr->current;
1137         mgr->current = NULL;
1138         cmd->flags &= ~IXLV_VC_CMD_FLAG_BUSY;
1139
1140         cmd->callback(cmd, cmd->arg, err);
1141         ixl_vc_process_next(mgr);
1142 }
1143
1144 static void
1145 ixl_vc_process_resp(struct ixl_vc_mgr *mgr, uint32_t request,
1146     enum virtchnl_status_code err)
1147 {
1148         struct ixl_vc_cmd *cmd;
1149
1150         cmd = mgr->current;
1151         if (cmd == NULL || cmd->request != request)
1152                 return;
1153
1154         callout_stop(&mgr->callout);
1155         /* ATM, the virtchnl codes map to i40e ones directly */
1156         ixl_vc_process_completion(mgr, (enum i40e_status_code)err);
1157 }
1158
1159 static void
1160 ixl_vc_cmd_timeout(void *arg)
1161 {
1162         struct ixl_vc_mgr *mgr = (struct ixl_vc_mgr *)arg;
1163
1164         IXLV_CORE_LOCK_ASSERT(mgr->sc);
1165         ixl_vc_process_completion(mgr, I40E_ERR_TIMEOUT);
1166 }
1167
1168 static void
1169 ixl_vc_cmd_retry(void *arg)
1170 {
1171         struct ixl_vc_mgr *mgr = (struct ixl_vc_mgr *)arg;
1172
1173         IXLV_CORE_LOCK_ASSERT(mgr->sc);
1174         ixl_vc_send_current(mgr);
1175 }
1176
1177 static void
1178 ixl_vc_send_current(struct ixl_vc_mgr *mgr)
1179 {
1180         struct ixl_vc_cmd *cmd;
1181
1182         cmd = mgr->current;
1183         ixl_vc_send_cmd(mgr->sc, cmd->request);
1184         callout_reset(&mgr->callout, IXLV_VC_TIMEOUT, ixl_vc_cmd_timeout, mgr);
1185 }
1186
1187 static void
1188 ixl_vc_process_next(struct ixl_vc_mgr *mgr)
1189 {
1190         struct ixl_vc_cmd *cmd;
1191
1192         if (mgr->current != NULL)
1193                 return;
1194
1195         if (TAILQ_EMPTY(&mgr->pending))
1196                 return;
1197
1198         cmd = TAILQ_FIRST(&mgr->pending);
1199         TAILQ_REMOVE(&mgr->pending, cmd, next);
1200
1201         mgr->current = cmd;
1202         ixl_vc_send_current(mgr);
1203 }
1204
1205 static void
1206 ixl_vc_schedule_retry(struct ixl_vc_mgr *mgr)
1207 {
1208
1209         callout_reset(&mgr->callout, howmany(hz, 100), ixl_vc_cmd_retry, mgr);
1210 }
1211
1212 void
1213 ixl_vc_enqueue(struct ixl_vc_mgr *mgr, struct ixl_vc_cmd *cmd,
1214             uint32_t req, ixl_vc_callback_t *callback, void *arg)
1215 {
1216         IXLV_CORE_LOCK_ASSERT(mgr->sc);
1217
1218         if (cmd->flags & IXLV_VC_CMD_FLAG_BUSY) {
1219                 if (mgr->current == cmd)
1220                         mgr->current = NULL;
1221                 else
1222                         TAILQ_REMOVE(&mgr->pending, cmd, next);
1223         }
1224
1225         cmd->request = req;
1226         cmd->callback = callback;
1227         cmd->arg = arg;
1228         cmd->flags |= IXLV_VC_CMD_FLAG_BUSY;
1229         TAILQ_INSERT_TAIL(&mgr->pending, cmd, next);
1230
1231         ixl_vc_process_next(mgr);
1232 }
1233
1234 void
1235 ixl_vc_flush(struct ixl_vc_mgr *mgr)
1236 {
1237         struct ixl_vc_cmd *cmd;
1238
1239         IXLV_CORE_LOCK_ASSERT(mgr->sc);
1240         KASSERT(TAILQ_EMPTY(&mgr->pending) || mgr->current != NULL,
1241             ("ixlv: pending commands waiting but no command in progress"));
1242
1243         cmd = mgr->current;
1244         if (cmd != NULL) {
1245                 mgr->current = NULL;
1246                 cmd->flags &= ~IXLV_VC_CMD_FLAG_BUSY;
1247                 cmd->callback(cmd, cmd->arg, I40E_ERR_ADAPTER_STOPPED);
1248         }
1249
1250         while ((cmd = TAILQ_FIRST(&mgr->pending)) != NULL) {
1251                 TAILQ_REMOVE(&mgr->pending, cmd, next);
1252                 cmd->flags &= ~IXLV_VC_CMD_FLAG_BUSY;
1253                 cmd->callback(cmd, cmd->arg, I40E_ERR_ADAPTER_STOPPED);
1254         }
1255
1256         callout_stop(&mgr->callout);
1257 }
1258