net/sfc: restart RxQ in case of exception on event queue
[dpdk.git] / drivers / net / sfc / sfc_ev.c
1 /*-
2  * Copyright (c) 2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * This software was jointly developed between OKTET Labs (under contract
6  * for Solarflare) and Solarflare Communications, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice,
12  *    this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <rte_debug.h>
31 #include <rte_cycles.h>
32 #include <rte_alarm.h>
33 #include <rte_branch_prediction.h>
34
35 #include "efx.h"
36
37 #include "sfc.h"
38 #include "sfc_debug.h"
39 #include "sfc_log.h"
40 #include "sfc_ev.h"
41 #include "sfc_rx.h"
42 #include "sfc_tx.h"
43
44
45 /* Initial delay when waiting for event queue init complete event */
46 #define SFC_EVQ_INIT_BACKOFF_START_US   (1)
47 /* Maximum delay between event queue polling attempts */
48 #define SFC_EVQ_INIT_BACKOFF_MAX_US     (10 * 1000)
49 /* Event queue init approx timeout */
50 #define SFC_EVQ_INIT_TIMEOUT_US         (2 * US_PER_S)
51
52 /* Management event queue polling period in microseconds */
53 #define SFC_MGMT_EV_QPOLL_PERIOD_US     (US_PER_S)
54
55
56 static boolean_t
57 sfc_ev_initialized(void *arg)
58 {
59         struct sfc_evq *evq = arg;
60
61         /* Init done events may be duplicated on SFN7xxx (SFC bug 31631) */
62         SFC_ASSERT(evq->init_state == SFC_EVQ_STARTING ||
63                    evq->init_state == SFC_EVQ_STARTED);
64
65         evq->init_state = SFC_EVQ_STARTED;
66
67         return B_FALSE;
68 }
69
70 static boolean_t
71 sfc_ev_rx(void *arg, __rte_unused uint32_t label, uint32_t id,
72           uint32_t size, uint16_t flags)
73 {
74         struct sfc_evq *evq = arg;
75         struct sfc_rxq *rxq;
76         unsigned int stop;
77         unsigned int pending_id;
78         unsigned int delta;
79         unsigned int i;
80         struct sfc_rx_sw_desc *rxd;
81
82         if (unlikely(evq->exception))
83                 goto done;
84
85         rxq = evq->rxq;
86
87         SFC_ASSERT(rxq != NULL);
88         SFC_ASSERT(rxq->evq == evq);
89         SFC_ASSERT(rxq->state & SFC_RXQ_STARTED);
90
91         stop = (id + 1) & rxq->ptr_mask;
92         pending_id = rxq->pending & rxq->ptr_mask;
93         delta = (stop >= pending_id) ? (stop - pending_id) :
94                 (rxq->ptr_mask + 1 - pending_id + stop);
95
96         if (delta == 0) {
97                 /*
98                  * Rx event with no new descriptors done and zero length
99                  * is used to abort scattered packet when there is no room
100                  * for the tail.
101                  */
102                 if (unlikely(size != 0)) {
103                         evq->exception = B_TRUE;
104                         sfc_err(evq->sa,
105                                 "EVQ %u RxQ %u invalid RX abort "
106                                 "(id=%#x size=%u flags=%#x); needs restart\n",
107                                 evq->evq_index, sfc_rxq_sw_index(rxq),
108                                 id, size, flags);
109                         goto done;
110                 }
111
112                 /* Add discard flag to the first fragment */
113                 rxq->sw_desc[pending_id].flags |= EFX_DISCARD;
114                 /* Remove continue flag from the last fragment */
115                 rxq->sw_desc[id].flags &= ~EFX_PKT_CONT;
116         } else if (unlikely(delta > rxq->batch_max)) {
117                 evq->exception = B_TRUE;
118
119                 sfc_err(evq->sa,
120                         "EVQ %u RxQ %u completion out of order "
121                         "(id=%#x delta=%u flags=%#x); needs restart\n",
122                         evq->evq_index, sfc_rxq_sw_index(rxq), id, delta,
123                         flags);
124
125                 goto done;
126         }
127
128         for (i = pending_id; i != stop; i = (i + 1) & rxq->ptr_mask) {
129                 rxd = &rxq->sw_desc[i];
130
131                 rxd->flags = flags;
132
133                 SFC_ASSERT(size < (1 << 16));
134                 rxd->size = (uint16_t)size;
135         }
136
137         rxq->pending += delta;
138
139 done:
140         return B_FALSE;
141 }
142
143 static boolean_t
144 sfc_ev_tx(void *arg, __rte_unused uint32_t label, uint32_t id)
145 {
146         struct sfc_evq *evq = arg;
147         struct sfc_txq *txq;
148         unsigned int stop;
149         unsigned int delta;
150
151         txq = evq->txq;
152
153         SFC_ASSERT(txq != NULL);
154         SFC_ASSERT(txq->evq == evq);
155
156         if (unlikely((txq->state & SFC_TXQ_STARTED) == 0))
157                 goto done;
158
159         stop = (id + 1) & txq->ptr_mask;
160         id = txq->pending & txq->ptr_mask;
161
162         delta = (stop >= id) ? (stop - id) : (txq->ptr_mask + 1 - id + stop);
163
164         txq->pending += delta;
165
166 done:
167         return B_FALSE;
168 }
169
170 static boolean_t
171 sfc_ev_exception(void *arg, __rte_unused uint32_t code,
172                  __rte_unused uint32_t data)
173 {
174         struct sfc_evq *evq = arg;
175
176         if (code == EFX_EXCEPTION_UNKNOWN_SENSOREVT)
177                 return B_FALSE;
178
179         evq->exception = B_TRUE;
180         sfc_warn(evq->sa,
181                  "hardware exception %s (code=%u, data=%#x) on EVQ %u;"
182                  " needs recovery",
183                  (code == EFX_EXCEPTION_RX_RECOVERY) ? "RX_RECOVERY" :
184                  (code == EFX_EXCEPTION_RX_DSC_ERROR) ? "RX_DSC_ERROR" :
185                  (code == EFX_EXCEPTION_TX_DSC_ERROR) ? "TX_DSC_ERROR" :
186                  (code == EFX_EXCEPTION_FWALERT_SRAM) ? "FWALERT_SRAM" :
187                  (code == EFX_EXCEPTION_UNKNOWN_FWALERT) ? "UNKNOWN_FWALERT" :
188                  (code == EFX_EXCEPTION_RX_ERROR) ? "RX_ERROR" :
189                  (code == EFX_EXCEPTION_TX_ERROR) ? "TX_ERROR" :
190                  (code == EFX_EXCEPTION_EV_ERROR) ? "EV_ERROR" :
191                  "UNKNOWN",
192                  code, data, evq->evq_index);
193
194         return B_TRUE;
195 }
196
197 static boolean_t
198 sfc_ev_rxq_flush_done(void *arg, __rte_unused uint32_t rxq_hw_index)
199 {
200         struct sfc_evq *evq = arg;
201         struct sfc_rxq *rxq;
202
203         rxq = evq->rxq;
204         SFC_ASSERT(rxq != NULL);
205         SFC_ASSERT(rxq->hw_index == rxq_hw_index);
206         SFC_ASSERT(rxq->evq == evq);
207         sfc_rx_qflush_done(rxq);
208
209         return B_FALSE;
210 }
211
212 static boolean_t
213 sfc_ev_rxq_flush_failed(void *arg, __rte_unused uint32_t rxq_hw_index)
214 {
215         struct sfc_evq *evq = arg;
216         struct sfc_rxq *rxq;
217
218         rxq = evq->rxq;
219         SFC_ASSERT(rxq != NULL);
220         SFC_ASSERT(rxq->hw_index == rxq_hw_index);
221         SFC_ASSERT(rxq->evq == evq);
222         sfc_rx_qflush_failed(rxq);
223
224         return B_FALSE;
225 }
226
227 static boolean_t
228 sfc_ev_txq_flush_done(void *arg, __rte_unused uint32_t txq_hw_index)
229 {
230         struct sfc_evq *evq = arg;
231         struct sfc_txq *txq;
232
233         txq = evq->txq;
234         SFC_ASSERT(txq != NULL);
235         SFC_ASSERT(txq->hw_index == txq_hw_index);
236         SFC_ASSERT(txq->evq == evq);
237         sfc_tx_qflush_done(txq);
238
239         return B_FALSE;
240 }
241
242 static boolean_t
243 sfc_ev_software(void *arg, uint16_t magic)
244 {
245         struct sfc_evq *evq = arg;
246
247         sfc_err(evq->sa, "EVQ %u unexpected software event magic=%#.4x",
248                 evq->evq_index, magic);
249         return B_TRUE;
250 }
251
252 static boolean_t
253 sfc_ev_sram(void *arg, uint32_t code)
254 {
255         struct sfc_evq *evq = arg;
256
257         sfc_err(evq->sa, "EVQ %u unexpected SRAM event code=%u",
258                 evq->evq_index, code);
259         return B_TRUE;
260 }
261
262 static boolean_t
263 sfc_ev_wake_up(void *arg, uint32_t index)
264 {
265         struct sfc_evq *evq = arg;
266
267         sfc_err(evq->sa, "EVQ %u unexpected wake up event index=%u",
268                 evq->evq_index, index);
269         return B_TRUE;
270 }
271
272 static boolean_t
273 sfc_ev_timer(void *arg, uint32_t index)
274 {
275         struct sfc_evq *evq = arg;
276
277         sfc_err(evq->sa, "EVQ %u unexpected timer event index=%u",
278                 evq->evq_index, index);
279         return B_TRUE;
280 }
281
282 static boolean_t
283 sfc_ev_link_change(void *arg, efx_link_mode_t link_mode)
284 {
285         struct sfc_evq *evq = arg;
286         struct sfc_adapter *sa = evq->sa;
287         struct rte_eth_link *dev_link = &sa->eth_dev->data->dev_link;
288         struct rte_eth_link new_link;
289
290         EFX_STATIC_ASSERT(sizeof(*dev_link) == sizeof(rte_atomic64_t));
291
292         sfc_port_link_mode_to_info(link_mode, &new_link);
293         rte_atomic64_set((rte_atomic64_t *)dev_link, *(uint64_t *)&new_link);
294
295         return B_FALSE;
296 }
297
298 static const efx_ev_callbacks_t sfc_ev_callbacks = {
299         .eec_initialized        = sfc_ev_initialized,
300         .eec_rx                 = sfc_ev_rx,
301         .eec_tx                 = sfc_ev_tx,
302         .eec_exception          = sfc_ev_exception,
303         .eec_rxq_flush_done     = sfc_ev_rxq_flush_done,
304         .eec_rxq_flush_failed   = sfc_ev_rxq_flush_failed,
305         .eec_txq_flush_done     = sfc_ev_txq_flush_done,
306         .eec_software           = sfc_ev_software,
307         .eec_sram               = sfc_ev_sram,
308         .eec_wake_up            = sfc_ev_wake_up,
309         .eec_timer              = sfc_ev_timer,
310         .eec_link_change        = sfc_ev_link_change,
311 };
312
313
314 void
315 sfc_ev_qpoll(struct sfc_evq *evq)
316 {
317         SFC_ASSERT(evq->init_state == SFC_EVQ_STARTED ||
318                    evq->init_state == SFC_EVQ_STARTING);
319
320         /* Synchronize the DMA memory for reading not required */
321
322         efx_ev_qpoll(evq->common, &evq->read_ptr, &sfc_ev_callbacks, evq);
323
324         if (unlikely(evq->exception) && sfc_adapter_trylock(evq->sa)) {
325                 struct sfc_adapter *sa = evq->sa;
326                 int rc;
327
328                 if ((evq->rxq != NULL) && (evq->rxq->state & SFC_RXQ_RUNNING)) {
329                         unsigned int rxq_sw_index = sfc_rxq_sw_index(evq->rxq);
330
331                         sfc_warn(sa,
332                                  "restart RxQ %u because of exception on its EvQ %u",
333                                  rxq_sw_index, evq->evq_index);
334
335                         sfc_rx_qstop(sa, rxq_sw_index);
336                         rc = sfc_rx_qstart(sa, rxq_sw_index);
337                         if (rc != 0)
338                                 sfc_err(sa, "cannot restart RxQ %u",
339                                         rxq_sw_index);
340                 }
341
342                 if (evq->exception)
343                         sfc_panic(sa, "unrecoverable exception on EvQ %u",
344                                   evq->evq_index);
345
346                 sfc_adapter_unlock(sa);
347         }
348
349         /* Poll-mode driver does not re-prime the event queue for interrupts */
350 }
351
352 void
353 sfc_ev_mgmt_qpoll(struct sfc_adapter *sa)
354 {
355         if (rte_spinlock_trylock(&sa->mgmt_evq_lock)) {
356                 struct sfc_evq *mgmt_evq = sa->evq_info[sa->mgmt_evq_index].evq;
357
358                 if (mgmt_evq->init_state == SFC_EVQ_STARTED)
359                         sfc_ev_qpoll(mgmt_evq);
360
361                 rte_spinlock_unlock(&sa->mgmt_evq_lock);
362         }
363 }
364
365 int
366 sfc_ev_qprime(struct sfc_evq *evq)
367 {
368         SFC_ASSERT(evq->init_state == SFC_EVQ_STARTED);
369         return efx_ev_qprime(evq->common, evq->read_ptr);
370 }
371
372 int
373 sfc_ev_qstart(struct sfc_adapter *sa, unsigned int sw_index)
374 {
375         const struct sfc_evq_info *evq_info;
376         struct sfc_evq *evq;
377         efsys_mem_t *esmp;
378         unsigned int total_delay_us;
379         unsigned int delay_us;
380         int rc;
381
382         sfc_log_init(sa, "sw_index=%u", sw_index);
383
384         evq_info = &sa->evq_info[sw_index];
385         evq = evq_info->evq;
386         esmp = &evq->mem;
387
388         /* Clear all events */
389         (void)memset((void *)esmp->esm_base, 0xff,
390                      EFX_EVQ_SIZE(evq_info->entries));
391
392         /* Create the common code event queue */
393         rc = efx_ev_qcreate(sa->nic, sw_index, esmp, evq_info->entries,
394                             0 /* unused on EF10 */, 0,
395                             EFX_EVQ_FLAGS_TYPE_THROUGHPUT |
396                             EFX_EVQ_FLAGS_NOTIFY_DISABLED,
397                             &evq->common);
398         if (rc != 0)
399                 goto fail_ev_qcreate;
400
401         evq->init_state = SFC_EVQ_STARTING;
402
403         /* Wait for the initialization event */
404         total_delay_us = 0;
405         delay_us = SFC_EVQ_INIT_BACKOFF_START_US;
406         do {
407                 (void)sfc_ev_qpoll(evq);
408
409                 /* Check to see if the initialization complete indication
410                  * posted by the hardware.
411                  */
412                 if (evq->init_state == SFC_EVQ_STARTED)
413                         goto done;
414
415                 /* Give event queue some time to init */
416                 rte_delay_us(delay_us);
417
418                 total_delay_us += delay_us;
419
420                 /* Exponential backoff */
421                 delay_us *= 2;
422                 if (delay_us > SFC_EVQ_INIT_BACKOFF_MAX_US)
423                         delay_us = SFC_EVQ_INIT_BACKOFF_MAX_US;
424
425         } while (total_delay_us < SFC_EVQ_INIT_TIMEOUT_US);
426
427         rc = ETIMEDOUT;
428         goto fail_timedout;
429
430 done:
431         return 0;
432
433 fail_timedout:
434         evq->init_state = SFC_EVQ_INITIALIZED;
435         efx_ev_qdestroy(evq->common);
436
437 fail_ev_qcreate:
438         sfc_log_init(sa, "failed %d", rc);
439         return rc;
440 }
441
442 void
443 sfc_ev_qstop(struct sfc_adapter *sa, unsigned int sw_index)
444 {
445         const struct sfc_evq_info *evq_info;
446         struct sfc_evq *evq;
447
448         sfc_log_init(sa, "sw_index=%u", sw_index);
449
450         SFC_ASSERT(sw_index < sa->evq_count);
451
452         evq_info = &sa->evq_info[sw_index];
453         evq = evq_info->evq;
454
455         if (evq == NULL || evq->init_state != SFC_EVQ_STARTED)
456                 return;
457
458         evq->init_state = SFC_EVQ_INITIALIZED;
459         evq->read_ptr = 0;
460         evq->exception = B_FALSE;
461
462         efx_ev_qdestroy(evq->common);
463 }
464
465 static void
466 sfc_ev_mgmt_periodic_qpoll(void *arg)
467 {
468         struct sfc_adapter *sa = arg;
469         int rc;
470
471         sfc_ev_mgmt_qpoll(sa);
472
473         rc = rte_eal_alarm_set(SFC_MGMT_EV_QPOLL_PERIOD_US,
474                                sfc_ev_mgmt_periodic_qpoll, sa);
475         if (rc != 0)
476                 sfc_panic(sa,
477                           "cannot rearm management EVQ polling alarm (rc=%d)",
478                           rc);
479 }
480
481 static void
482 sfc_ev_mgmt_periodic_qpoll_start(struct sfc_adapter *sa)
483 {
484         sfc_ev_mgmt_periodic_qpoll(sa);
485 }
486
487 static void
488 sfc_ev_mgmt_periodic_qpoll_stop(struct sfc_adapter *sa)
489 {
490         rte_eal_alarm_cancel(sfc_ev_mgmt_periodic_qpoll, sa);
491 }
492
493 int
494 sfc_ev_start(struct sfc_adapter *sa)
495 {
496         int rc;
497
498         sfc_log_init(sa, "entry");
499
500         rc = efx_ev_init(sa->nic);
501         if (rc != 0)
502                 goto fail_ev_init;
503
504         /* Start management EVQ used for global events */
505         rte_spinlock_lock(&sa->mgmt_evq_lock);
506
507         rc = sfc_ev_qstart(sa, sa->mgmt_evq_index);
508         if (rc != 0)
509                 goto fail_mgmt_evq_start;
510
511         rte_spinlock_unlock(&sa->mgmt_evq_lock);
512
513         /*
514          * Start management EVQ polling. If interrupts are disabled
515          * (not used), it is required to process link status change
516          * and other device level events to avoid unrecoverable
517          * error because the event queue overflow.
518          */
519         sfc_ev_mgmt_periodic_qpoll_start(sa);
520
521         /*
522          * Rx/Tx event queues are started/stopped when corresponding
523          * Rx/Tx queue is started/stopped.
524          */
525
526         return 0;
527
528 fail_mgmt_evq_start:
529         rte_spinlock_unlock(&sa->mgmt_evq_lock);
530         efx_ev_fini(sa->nic);
531
532 fail_ev_init:
533         sfc_log_init(sa, "failed %d", rc);
534         return rc;
535 }
536
537 void
538 sfc_ev_stop(struct sfc_adapter *sa)
539 {
540         unsigned int sw_index;
541
542         sfc_log_init(sa, "entry");
543
544         sfc_ev_mgmt_periodic_qpoll_stop(sa);
545
546         /* Make sure that all event queues are stopped */
547         sw_index = sa->evq_count;
548         while (sw_index-- > 0) {
549                 if (sw_index == sa->mgmt_evq_index) {
550                         /* Locks are required for the management EVQ */
551                         rte_spinlock_lock(&sa->mgmt_evq_lock);
552                         sfc_ev_qstop(sa, sa->mgmt_evq_index);
553                         rte_spinlock_unlock(&sa->mgmt_evq_lock);
554                 } else {
555                         sfc_ev_qstop(sa, sw_index);
556                 }
557         }
558
559         efx_ev_fini(sa->nic);
560 }
561
562 int
563 sfc_ev_qinit(struct sfc_adapter *sa, unsigned int sw_index,
564              unsigned int entries, int socket_id)
565 {
566         struct sfc_evq_info *evq_info;
567         struct sfc_evq *evq;
568         int rc;
569
570         sfc_log_init(sa, "sw_index=%u", sw_index);
571
572         evq_info = &sa->evq_info[sw_index];
573
574         SFC_ASSERT(rte_is_power_of_2(entries));
575         SFC_ASSERT(entries <= evq_info->max_entries);
576         evq_info->entries = entries;
577
578         evq = rte_zmalloc_socket("sfc-evq", sizeof(*evq), RTE_CACHE_LINE_SIZE,
579                                  socket_id);
580         if (evq == NULL)
581                 return ENOMEM;
582
583         evq->sa = sa;
584         evq->evq_index = sw_index;
585
586         /* Allocate DMA space */
587         rc = sfc_dma_alloc(sa, "evq", sw_index, EFX_EVQ_SIZE(evq_info->entries),
588                            socket_id, &evq->mem);
589         if (rc != 0)
590                 return rc;
591
592         evq->init_state = SFC_EVQ_INITIALIZED;
593
594         evq_info->evq = evq;
595
596         return 0;
597 }
598
599 void
600 sfc_ev_qfini(struct sfc_adapter *sa, unsigned int sw_index)
601 {
602         struct sfc_evq *evq;
603
604         sfc_log_init(sa, "sw_index=%u", sw_index);
605
606         evq = sa->evq_info[sw_index].evq;
607
608         SFC_ASSERT(evq->init_state == SFC_EVQ_INITIALIZED);
609
610         sa->evq_info[sw_index].evq = NULL;
611
612         sfc_dma_free(sa, &evq->mem);
613
614         rte_free(evq);
615 }
616
617 static int
618 sfc_ev_qinit_info(struct sfc_adapter *sa, unsigned int sw_index)
619 {
620         struct sfc_evq_info *evq_info = &sa->evq_info[sw_index];
621         unsigned int max_entries;
622
623         sfc_log_init(sa, "sw_index=%u", sw_index);
624
625         max_entries = sfc_evq_max_entries(sa, sw_index);
626         SFC_ASSERT(rte_is_power_of_2(max_entries));
627
628         evq_info->max_entries = max_entries;
629
630         return 0;
631 }
632
633 static void
634 sfc_ev_qfini_info(struct sfc_adapter *sa, unsigned int sw_index)
635 {
636         sfc_log_init(sa, "sw_index=%u", sw_index);
637
638         /* Nothing to cleanup */
639 }
640
641 int
642 sfc_ev_init(struct sfc_adapter *sa)
643 {
644         int rc;
645         unsigned int sw_index;
646
647         sfc_log_init(sa, "entry");
648
649         sa->evq_count = sfc_ev_qcount(sa);
650         sa->mgmt_evq_index = 0;
651         rte_spinlock_init(&sa->mgmt_evq_lock);
652
653         /* Allocate EVQ info array */
654         rc = ENOMEM;
655         sa->evq_info = rte_calloc_socket("sfc-evqs", sa->evq_count,
656                                          sizeof(struct sfc_evq_info), 0,
657                                          sa->socket_id);
658         if (sa->evq_info == NULL)
659                 goto fail_evqs_alloc;
660
661         for (sw_index = 0; sw_index < sa->evq_count; ++sw_index) {
662                 rc = sfc_ev_qinit_info(sa, sw_index);
663                 if (rc != 0)
664                         goto fail_ev_qinit_info;
665         }
666
667         rc = sfc_ev_qinit(sa, sa->mgmt_evq_index, SFC_MGMT_EVQ_ENTRIES,
668                           sa->socket_id);
669         if (rc != 0)
670                 goto fail_mgmt_evq_init;
671
672         /*
673          * Rx/Tx event queues are created/destroyed when corresponding
674          * Rx/Tx queue is created/destroyed.
675          */
676
677         return 0;
678
679 fail_mgmt_evq_init:
680 fail_ev_qinit_info:
681         while (sw_index-- > 0)
682                 sfc_ev_qfini_info(sa, sw_index);
683
684         rte_free(sa->evq_info);
685         sa->evq_info = NULL;
686
687 fail_evqs_alloc:
688         sa->evq_count = 0;
689         sfc_log_init(sa, "failed %d", rc);
690         return rc;
691 }
692
693 void
694 sfc_ev_fini(struct sfc_adapter *sa)
695 {
696         int sw_index;
697
698         sfc_log_init(sa, "entry");
699
700         /* Cleanup all event queues */
701         sw_index = sa->evq_count;
702         while (--sw_index >= 0) {
703                 if (sa->evq_info[sw_index].evq != NULL)
704                         sfc_ev_qfini(sa, sw_index);
705                 sfc_ev_qfini_info(sa, sw_index);
706         }
707
708         rte_free(sa->evq_info);
709         sa->evq_info = NULL;
710         sa->evq_count = 0;
711 }