net/sfc: support flow API filters
[dpdk.git] / drivers / net / sfc / sfc.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 /* sysconf() */
31 #include <unistd.h>
32
33 #include <rte_errno.h>
34
35 #include "efx.h"
36
37 #include "sfc.h"
38 #include "sfc_log.h"
39 #include "sfc_ev.h"
40 #include "sfc_rx.h"
41 #include "sfc_tx.h"
42
43
44 int
45 sfc_dma_alloc(const struct sfc_adapter *sa, const char *name, uint16_t id,
46               size_t len, int socket_id, efsys_mem_t *esmp)
47 {
48         const struct rte_memzone *mz;
49
50         sfc_log_init(sa, "name=%s id=%u len=%lu socket_id=%d",
51                      name, id, len, socket_id);
52
53         mz = rte_eth_dma_zone_reserve(sa->eth_dev, name, id, len,
54                                       sysconf(_SC_PAGESIZE), socket_id);
55         if (mz == NULL) {
56                 sfc_err(sa, "cannot reserve DMA zone for %s:%u %#x@%d: %s",
57                         name, (unsigned int)id, (unsigned int)len, socket_id,
58                         rte_strerror(rte_errno));
59                 return ENOMEM;
60         }
61
62         esmp->esm_addr = rte_mem_phy2mch(mz->memseg_id, mz->phys_addr);
63         if (esmp->esm_addr == RTE_BAD_PHYS_ADDR) {
64                 (void)rte_memzone_free(mz);
65                 return EFAULT;
66         }
67
68         esmp->esm_mz = mz;
69         esmp->esm_base = mz->addr;
70
71         return 0;
72 }
73
74 void
75 sfc_dma_free(const struct sfc_adapter *sa, efsys_mem_t *esmp)
76 {
77         int rc;
78
79         sfc_log_init(sa, "name=%s", esmp->esm_mz->name);
80
81         rc = rte_memzone_free(esmp->esm_mz);
82         if (rc != 0)
83                 sfc_err(sa, "rte_memzone_free(() failed: %d", rc);
84
85         memset(esmp, 0, sizeof(*esmp));
86 }
87
88 static uint32_t
89 sfc_phy_cap_from_link_speeds(uint32_t speeds)
90 {
91         uint32_t phy_caps = 0;
92
93         if (~speeds & ETH_LINK_SPEED_FIXED) {
94                 phy_caps |= (1 << EFX_PHY_CAP_AN);
95                 /*
96                  * If no speeds are specified in the mask, any supported
97                  * may be negotiated
98                  */
99                 if (speeds == ETH_LINK_SPEED_AUTONEG)
100                         phy_caps |=
101                                 (1 << EFX_PHY_CAP_1000FDX) |
102                                 (1 << EFX_PHY_CAP_10000FDX) |
103                                 (1 << EFX_PHY_CAP_40000FDX);
104         }
105         if (speeds & ETH_LINK_SPEED_1G)
106                 phy_caps |= (1 << EFX_PHY_CAP_1000FDX);
107         if (speeds & ETH_LINK_SPEED_10G)
108                 phy_caps |= (1 << EFX_PHY_CAP_10000FDX);
109         if (speeds & ETH_LINK_SPEED_40G)
110                 phy_caps |= (1 << EFX_PHY_CAP_40000FDX);
111
112         return phy_caps;
113 }
114
115 /*
116  * Check requested device level configuration.
117  * Receive and transmit configuration is checked in corresponding
118  * modules.
119  */
120 static int
121 sfc_check_conf(struct sfc_adapter *sa)
122 {
123         const struct rte_eth_conf *conf = &sa->eth_dev->data->dev_conf;
124         int rc = 0;
125
126         sa->port.phy_adv_cap =
127                 sfc_phy_cap_from_link_speeds(conf->link_speeds) &
128                 sa->port.phy_adv_cap_mask;
129         if ((sa->port.phy_adv_cap & ~(1 << EFX_PHY_CAP_AN)) == 0) {
130                 sfc_err(sa, "No link speeds from mask %#x are supported",
131                         conf->link_speeds);
132                 rc = EINVAL;
133         }
134
135         if (conf->lpbk_mode != 0) {
136                 sfc_err(sa, "Loopback not supported");
137                 rc = EINVAL;
138         }
139
140         if (conf->dcb_capability_en != 0) {
141                 sfc_err(sa, "Priority-based flow control not supported");
142                 rc = EINVAL;
143         }
144
145         if (conf->fdir_conf.mode != RTE_FDIR_MODE_NONE) {
146                 sfc_err(sa, "Flow Director not supported");
147                 rc = EINVAL;
148         }
149
150         if ((conf->intr_conf.lsc != 0) &&
151             (sa->intr.type != EFX_INTR_LINE) &&
152             (sa->intr.type != EFX_INTR_MESSAGE)) {
153                 sfc_err(sa, "Link status change interrupt not supported");
154                 rc = EINVAL;
155         }
156
157         if (conf->intr_conf.rxq != 0) {
158                 sfc_err(sa, "Receive queue interrupt not supported");
159                 rc = EINVAL;
160         }
161
162         return rc;
163 }
164
165 /*
166  * Find out maximum number of receive and transmit queues which could be
167  * advertised.
168  *
169  * NIC is kept initialized on success to allow other modules acquire
170  * defaults and capabilities.
171  */
172 static int
173 sfc_estimate_resource_limits(struct sfc_adapter *sa)
174 {
175         const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
176         efx_drv_limits_t limits;
177         int rc;
178         uint32_t evq_allocated;
179         uint32_t rxq_allocated;
180         uint32_t txq_allocated;
181
182         memset(&limits, 0, sizeof(limits));
183
184         /* Request at least one Rx and Tx queue */
185         limits.edl_min_rxq_count = 1;
186         limits.edl_min_txq_count = 1;
187         /* Management event queue plus event queue for each Tx and Rx queue */
188         limits.edl_min_evq_count =
189                 1 + limits.edl_min_rxq_count + limits.edl_min_txq_count;
190
191         /* Divide by number of functions to guarantee that all functions
192          * will get promised resources
193          */
194         /* FIXME Divide by number of functions (not 2) below */
195         limits.edl_max_evq_count = encp->enc_evq_limit / 2;
196         SFC_ASSERT(limits.edl_max_evq_count >= limits.edl_min_rxq_count);
197
198         /* Split equally between receive and transmit */
199         limits.edl_max_rxq_count =
200                 MIN(encp->enc_rxq_limit, (limits.edl_max_evq_count - 1) / 2);
201         SFC_ASSERT(limits.edl_max_rxq_count >= limits.edl_min_rxq_count);
202
203         limits.edl_max_txq_count =
204                 MIN(encp->enc_txq_limit,
205                     limits.edl_max_evq_count - 1 - limits.edl_max_rxq_count);
206
207         if (sa->tso)
208                 limits.edl_max_txq_count =
209                         MIN(limits.edl_max_txq_count,
210                             encp->enc_fw_assisted_tso_v2_n_contexts /
211                             encp->enc_hw_pf_count);
212
213         SFC_ASSERT(limits.edl_max_txq_count >= limits.edl_min_rxq_count);
214
215         /* Configure the minimum required resources needed for the
216          * driver to operate, and the maximum desired resources that the
217          * driver is capable of using.
218          */
219         efx_nic_set_drv_limits(sa->nic, &limits);
220
221         sfc_log_init(sa, "init nic");
222         rc = efx_nic_init(sa->nic);
223         if (rc != 0)
224                 goto fail_nic_init;
225
226         /* Find resource dimensions assigned by firmware to this function */
227         rc = efx_nic_get_vi_pool(sa->nic, &evq_allocated, &rxq_allocated,
228                                  &txq_allocated);
229         if (rc != 0)
230                 goto fail_get_vi_pool;
231
232         /* It still may allocate more than maximum, ensure limit */
233         evq_allocated = MIN(evq_allocated, limits.edl_max_evq_count);
234         rxq_allocated = MIN(rxq_allocated, limits.edl_max_rxq_count);
235         txq_allocated = MIN(txq_allocated, limits.edl_max_txq_count);
236
237         /* Subtract management EVQ not used for traffic */
238         SFC_ASSERT(evq_allocated > 0);
239         evq_allocated--;
240
241         /* Right now we use separate EVQ for Rx and Tx */
242         sa->rxq_max = MIN(rxq_allocated, evq_allocated / 2);
243         sa->txq_max = MIN(txq_allocated, evq_allocated - sa->rxq_max);
244
245         /* Keep NIC initialized */
246         return 0;
247
248 fail_get_vi_pool:
249 fail_nic_init:
250         efx_nic_fini(sa->nic);
251         return rc;
252 }
253
254 static int
255 sfc_set_drv_limits(struct sfc_adapter *sa)
256 {
257         const struct rte_eth_dev_data *data = sa->eth_dev->data;
258         efx_drv_limits_t lim;
259
260         memset(&lim, 0, sizeof(lim));
261
262         /* Limits are strict since take into account initial estimation */
263         lim.edl_min_evq_count = lim.edl_max_evq_count =
264                 1 + data->nb_rx_queues + data->nb_tx_queues;
265         lim.edl_min_rxq_count = lim.edl_max_rxq_count = data->nb_rx_queues;
266         lim.edl_min_txq_count = lim.edl_max_txq_count = data->nb_tx_queues;
267
268         return efx_nic_set_drv_limits(sa->nic, &lim);
269 }
270
271 int
272 sfc_start(struct sfc_adapter *sa)
273 {
274         int rc;
275
276         sfc_log_init(sa, "entry");
277
278         SFC_ASSERT(sfc_adapter_is_locked(sa));
279
280         switch (sa->state) {
281         case SFC_ADAPTER_CONFIGURED:
282                 break;
283         case SFC_ADAPTER_STARTED:
284                 sfc_info(sa, "already started");
285                 return 0;
286         default:
287                 rc = EINVAL;
288                 goto fail_bad_state;
289         }
290
291         sa->state = SFC_ADAPTER_STARTING;
292
293         sfc_log_init(sa, "set resource limits");
294         rc = sfc_set_drv_limits(sa);
295         if (rc != 0)
296                 goto fail_set_drv_limits;
297
298         sfc_log_init(sa, "init nic");
299         rc = efx_nic_init(sa->nic);
300         if (rc != 0)
301                 goto fail_nic_init;
302
303         rc = sfc_intr_start(sa);
304         if (rc != 0)
305                 goto fail_intr_start;
306
307         rc = sfc_ev_start(sa);
308         if (rc != 0)
309                 goto fail_ev_start;
310
311         rc = sfc_port_start(sa);
312         if (rc != 0)
313                 goto fail_port_start;
314
315         rc = sfc_rx_start(sa);
316         if (rc != 0)
317                 goto fail_rx_start;
318
319         rc = sfc_tx_start(sa);
320         if (rc != 0)
321                 goto fail_tx_start;
322
323         rc = sfc_flow_start(sa);
324         if (rc != 0)
325                 goto fail_flows_insert;
326
327         sa->state = SFC_ADAPTER_STARTED;
328         sfc_log_init(sa, "done");
329         return 0;
330
331 fail_flows_insert:
332         sfc_tx_stop(sa);
333
334 fail_tx_start:
335         sfc_rx_stop(sa);
336
337 fail_rx_start:
338         sfc_port_stop(sa);
339
340 fail_port_start:
341         sfc_ev_stop(sa);
342
343 fail_ev_start:
344         sfc_intr_stop(sa);
345
346 fail_intr_start:
347         efx_nic_fini(sa->nic);
348
349 fail_nic_init:
350 fail_set_drv_limits:
351         sa->state = SFC_ADAPTER_CONFIGURED;
352 fail_bad_state:
353         sfc_log_init(sa, "failed %d", rc);
354         return rc;
355 }
356
357 void
358 sfc_stop(struct sfc_adapter *sa)
359 {
360         sfc_log_init(sa, "entry");
361
362         SFC_ASSERT(sfc_adapter_is_locked(sa));
363
364         switch (sa->state) {
365         case SFC_ADAPTER_STARTED:
366                 break;
367         case SFC_ADAPTER_CONFIGURED:
368                 sfc_info(sa, "already stopped");
369                 return;
370         default:
371                 sfc_err(sa, "stop in unexpected state %u", sa->state);
372                 SFC_ASSERT(B_FALSE);
373                 return;
374         }
375
376         sa->state = SFC_ADAPTER_STOPPING;
377
378         sfc_flow_stop(sa);
379         sfc_tx_stop(sa);
380         sfc_rx_stop(sa);
381         sfc_port_stop(sa);
382         sfc_ev_stop(sa);
383         sfc_intr_stop(sa);
384         efx_nic_fini(sa->nic);
385
386         sa->state = SFC_ADAPTER_CONFIGURED;
387         sfc_log_init(sa, "done");
388 }
389
390 int
391 sfc_configure(struct sfc_adapter *sa)
392 {
393         int rc;
394
395         sfc_log_init(sa, "entry");
396
397         SFC_ASSERT(sfc_adapter_is_locked(sa));
398
399         SFC_ASSERT(sa->state == SFC_ADAPTER_INITIALIZED);
400         sa->state = SFC_ADAPTER_CONFIGURING;
401
402         rc = sfc_check_conf(sa);
403         if (rc != 0)
404                 goto fail_check_conf;
405
406         rc = sfc_intr_init(sa);
407         if (rc != 0)
408                 goto fail_intr_init;
409
410         rc = sfc_ev_init(sa);
411         if (rc != 0)
412                 goto fail_ev_init;
413
414         rc = sfc_port_init(sa);
415         if (rc != 0)
416                 goto fail_port_init;
417
418         rc = sfc_rx_init(sa);
419         if (rc != 0)
420                 goto fail_rx_init;
421
422         rc = sfc_tx_init(sa);
423         if (rc != 0)
424                 goto fail_tx_init;
425
426         sa->state = SFC_ADAPTER_CONFIGURED;
427         sfc_log_init(sa, "done");
428         return 0;
429
430 fail_tx_init:
431         sfc_rx_fini(sa);
432
433 fail_rx_init:
434         sfc_port_fini(sa);
435
436 fail_port_init:
437         sfc_ev_fini(sa);
438
439 fail_ev_init:
440         sfc_intr_fini(sa);
441
442 fail_intr_init:
443 fail_check_conf:
444         sa->state = SFC_ADAPTER_INITIALIZED;
445         sfc_log_init(sa, "failed %d", rc);
446         return rc;
447 }
448
449 void
450 sfc_close(struct sfc_adapter *sa)
451 {
452         sfc_log_init(sa, "entry");
453
454         SFC_ASSERT(sfc_adapter_is_locked(sa));
455
456         SFC_ASSERT(sa->state == SFC_ADAPTER_CONFIGURED);
457         sa->state = SFC_ADAPTER_CLOSING;
458
459         sfc_tx_fini(sa);
460         sfc_rx_fini(sa);
461         sfc_port_fini(sa);
462         sfc_ev_fini(sa);
463         sfc_intr_fini(sa);
464
465         sa->state = SFC_ADAPTER_INITIALIZED;
466         sfc_log_init(sa, "done");
467 }
468
469 static int
470 sfc_mem_bar_init(struct sfc_adapter *sa)
471 {
472         struct rte_eth_dev *eth_dev = sa->eth_dev;
473         struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(eth_dev);
474         efsys_bar_t *ebp = &sa->mem_bar;
475         unsigned int i;
476         struct rte_mem_resource *res;
477
478         for (i = 0; i < RTE_DIM(pci_dev->mem_resource); i++) {
479                 res = &pci_dev->mem_resource[i];
480                 if ((res->len != 0) && (res->phys_addr != 0)) {
481                         /* Found first memory BAR */
482                         SFC_BAR_LOCK_INIT(ebp, eth_dev->data->name);
483                         ebp->esb_rid = i;
484                         ebp->esb_dev = pci_dev;
485                         ebp->esb_base = res->addr;
486                         return 0;
487                 }
488         }
489
490         return EFAULT;
491 }
492
493 static void
494 sfc_mem_bar_fini(struct sfc_adapter *sa)
495 {
496         efsys_bar_t *ebp = &sa->mem_bar;
497
498         SFC_BAR_LOCK_DESTROY(ebp);
499         memset(ebp, 0, sizeof(*ebp));
500 }
501
502 #if EFSYS_OPT_RX_SCALE
503 /*
504  * A fixed RSS key which has a property of being symmetric
505  * (symmetrical flows are distributed to the same CPU)
506  * and also known to give a uniform distribution
507  * (a good distribution of traffic between different CPUs)
508  */
509 static const uint8_t default_rss_key[SFC_RSS_KEY_SIZE] = {
510         0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
511         0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
512         0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
513         0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
514         0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
515 };
516 #endif
517
518 static int
519 sfc_set_rss_defaults(struct sfc_adapter *sa)
520 {
521 #if EFSYS_OPT_RX_SCALE
522         int rc;
523
524         rc = efx_intr_init(sa->nic, sa->intr.type, NULL);
525         if (rc != 0)
526                 goto fail_intr_init;
527
528         rc = efx_ev_init(sa->nic);
529         if (rc != 0)
530                 goto fail_ev_init;
531
532         rc = efx_rx_init(sa->nic);
533         if (rc != 0)
534                 goto fail_rx_init;
535
536         rc = efx_rx_scale_support_get(sa->nic, &sa->rss_support);
537         if (rc != 0)
538                 goto fail_scale_support_get;
539
540         rc = efx_rx_hash_support_get(sa->nic, &sa->hash_support);
541         if (rc != 0)
542                 goto fail_hash_support_get;
543
544         efx_rx_fini(sa->nic);
545         efx_ev_fini(sa->nic);
546         efx_intr_fini(sa->nic);
547
548         sa->rss_hash_types = sfc_rte_to_efx_hash_type(SFC_RSS_OFFLOADS);
549
550         rte_memcpy(sa->rss_key, default_rss_key, sizeof(sa->rss_key));
551
552         return 0;
553
554 fail_hash_support_get:
555 fail_scale_support_get:
556 fail_rx_init:
557         efx_ev_fini(sa->nic);
558
559 fail_ev_init:
560         efx_intr_fini(sa->nic);
561
562 fail_intr_init:
563         return rc;
564 #else
565         return 0;
566 #endif
567 }
568
569 int
570 sfc_attach(struct sfc_adapter *sa)
571 {
572         struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(sa->eth_dev);
573         const efx_nic_cfg_t *encp;
574         efx_nic_t *enp;
575         int rc;
576
577         sfc_log_init(sa, "entry");
578
579         SFC_ASSERT(sfc_adapter_is_locked(sa));
580
581         sa->socket_id = rte_socket_id();
582
583         sfc_log_init(sa, "init mem bar");
584         rc = sfc_mem_bar_init(sa);
585         if (rc != 0)
586                 goto fail_mem_bar_init;
587
588         sfc_log_init(sa, "get family");
589         rc = efx_family(pci_dev->id.vendor_id, pci_dev->id.device_id,
590                         &sa->family);
591         if (rc != 0)
592                 goto fail_family;
593         sfc_log_init(sa, "family is %u", sa->family);
594
595         sfc_log_init(sa, "create nic");
596         rte_spinlock_init(&sa->nic_lock);
597         rc = efx_nic_create(sa->family, (efsys_identifier_t *)sa,
598                             &sa->mem_bar, &sa->nic_lock, &enp);
599         if (rc != 0)
600                 goto fail_nic_create;
601         sa->nic = enp;
602
603         rc = sfc_mcdi_init(sa);
604         if (rc != 0)
605                 goto fail_mcdi_init;
606
607         sfc_log_init(sa, "probe nic");
608         rc = efx_nic_probe(enp);
609         if (rc != 0)
610                 goto fail_nic_probe;
611
612         efx_mcdi_new_epoch(enp);
613
614         sfc_log_init(sa, "reset nic");
615         rc = efx_nic_reset(enp);
616         if (rc != 0)
617                 goto fail_nic_reset;
618
619         encp = efx_nic_cfg_get(sa->nic);
620
621         sa->tso = encp->enc_fw_assisted_tso_v2_enabled;
622         if (!sa->tso)
623                 sfc_warn(sa, "TSO support isn't available on this adapter");
624
625         sfc_log_init(sa, "estimate resource limits");
626         rc = sfc_estimate_resource_limits(sa);
627         if (rc != 0)
628                 goto fail_estimate_rsrc_limits;
629
630         sa->txq_max_entries = encp->enc_txq_max_ndescs;
631         SFC_ASSERT(rte_is_power_of_2(sa->txq_max_entries));
632
633         rc = sfc_intr_attach(sa);
634         if (rc != 0)
635                 goto fail_intr_attach;
636
637         efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_PERM,
638                             &sa->port.phy_adv_cap_mask);
639
640         rc = sfc_set_rss_defaults(sa);
641         if (rc != 0)
642                 goto fail_set_rss_defaults;
643
644         rc = sfc_filter_attach(sa);
645         if (rc != 0)
646                 goto fail_filter_attach;
647
648         sfc_log_init(sa, "fini nic");
649         efx_nic_fini(enp);
650
651         sfc_flow_init(sa);
652
653         sa->state = SFC_ADAPTER_INITIALIZED;
654
655         sfc_log_init(sa, "done");
656         return 0;
657
658 fail_filter_attach:
659 fail_set_rss_defaults:
660         sfc_intr_detach(sa);
661
662 fail_intr_attach:
663         efx_nic_fini(sa->nic);
664
665 fail_estimate_rsrc_limits:
666 fail_nic_reset:
667         sfc_log_init(sa, "unprobe nic");
668         efx_nic_unprobe(enp);
669
670 fail_nic_probe:
671         sfc_mcdi_fini(sa);
672
673 fail_mcdi_init:
674         sfc_log_init(sa, "destroy nic");
675         sa->nic = NULL;
676         efx_nic_destroy(enp);
677
678 fail_nic_create:
679 fail_family:
680         sfc_mem_bar_fini(sa);
681
682 fail_mem_bar_init:
683         sfc_log_init(sa, "failed %d", rc);
684         return rc;
685 }
686
687 void
688 sfc_detach(struct sfc_adapter *sa)
689 {
690         efx_nic_t *enp = sa->nic;
691
692         sfc_log_init(sa, "entry");
693
694         SFC_ASSERT(sfc_adapter_is_locked(sa));
695
696         sfc_filter_detach(sa);
697
698         sfc_intr_detach(sa);
699
700         sfc_log_init(sa, "unprobe nic");
701         efx_nic_unprobe(enp);
702
703         sfc_mcdi_fini(sa);
704
705         sfc_log_init(sa, "destroy nic");
706         sa->nic = NULL;
707         efx_nic_destroy(enp);
708
709         sfc_mem_bar_fini(sa);
710
711         sfc_flow_fini(sa);
712         sa->state = SFC_ADAPTER_UNINITIALIZED;
713 }