net/sfc/base: import SFN7xxx family support
[dpdk.git] / drivers / net / sfc / base / efx_nic.c
1 /*
2  * Copyright (c) 2007-2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30
31 #include "efx.h"
32 #include "efx_impl.h"
33
34         __checkReturn   efx_rc_t
35 efx_family(
36         __in            uint16_t venid,
37         __in            uint16_t devid,
38         __out           efx_family_t *efp)
39 {
40         if (venid == EFX_PCI_VENID_SFC) {
41                 switch (devid) {
42 #if EFSYS_OPT_SIENA
43                 case EFX_PCI_DEVID_SIENA_F1_UNINIT:
44                         /*
45                          * Hardware default for PF0 of uninitialised Siena.
46                          * manftest must be able to cope with this device id.
47                          */
48                         *efp = EFX_FAMILY_SIENA;
49                         return (0);
50
51                 case EFX_PCI_DEVID_BETHPAGE:
52                 case EFX_PCI_DEVID_SIENA:
53                         *efp = EFX_FAMILY_SIENA;
54                         return (0);
55 #endif /* EFSYS_OPT_SIENA */
56
57 #if EFSYS_OPT_HUNTINGTON
58                 case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT:
59                         /*
60                          * Hardware default for PF0 of uninitialised Huntington.
61                          * manftest must be able to cope with this device id.
62                          */
63                         *efp = EFX_FAMILY_HUNTINGTON;
64                         return (0);
65
66                 case EFX_PCI_DEVID_FARMINGDALE:
67                 case EFX_PCI_DEVID_GREENPORT:
68                         *efp = EFX_FAMILY_HUNTINGTON;
69                         return (0);
70
71                 case EFX_PCI_DEVID_FARMINGDALE_VF:
72                 case EFX_PCI_DEVID_GREENPORT_VF:
73                         *efp = EFX_FAMILY_HUNTINGTON;
74                         return (0);
75 #endif /* EFSYS_OPT_HUNTINGTON */
76
77                 case EFX_PCI_DEVID_FALCON:      /* Obsolete, not supported */
78                 default:
79                         break;
80                 }
81         }
82
83         *efp = EFX_FAMILY_INVALID;
84         return (ENOTSUP);
85 }
86
87
88 #define EFX_BIU_MAGIC0  0x01234567
89 #define EFX_BIU_MAGIC1  0xfedcba98
90
91         __checkReturn   efx_rc_t
92 efx_nic_biu_test(
93         __in            efx_nic_t *enp)
94 {
95         efx_oword_t oword;
96         efx_rc_t rc;
97
98         /*
99          * Write magic values to scratch registers 0 and 1, then
100          * verify that the values were written correctly.  Interleave
101          * the accesses to ensure that the BIU is not just reading
102          * back the cached value that was last written.
103          */
104         EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
105         EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
106
107         EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
108         EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
109
110         EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
111         if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) {
112                 rc = EIO;
113                 goto fail1;
114         }
115
116         EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
117         if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) {
118                 rc = EIO;
119                 goto fail2;
120         }
121
122         /*
123          * Perform the same test, with the values swapped.  This
124          * ensures that subsequent tests don't start with the correct
125          * values already written into the scratch registers.
126          */
127         EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
128         EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
129
130         EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
131         EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
132
133         EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
134         if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) {
135                 rc = EIO;
136                 goto fail3;
137         }
138
139         EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
140         if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) {
141                 rc = EIO;
142                 goto fail4;
143         }
144
145         return (0);
146
147 fail4:
148         EFSYS_PROBE(fail4);
149 fail3:
150         EFSYS_PROBE(fail3);
151 fail2:
152         EFSYS_PROBE(fail2);
153 fail1:
154         EFSYS_PROBE1(fail1, efx_rc_t, rc);
155
156         return (rc);
157 }
158
159 #if EFSYS_OPT_SIENA
160
161 static const efx_nic_ops_t      __efx_nic_siena_ops = {
162         siena_nic_probe,                /* eno_probe */
163         NULL,                           /* eno_board_cfg */
164         NULL,                           /* eno_set_drv_limits */
165         siena_nic_reset,                /* eno_reset */
166         siena_nic_init,                 /* eno_init */
167         NULL,                           /* eno_get_vi_pool */
168         NULL,                           /* eno_get_bar_region */
169         siena_nic_fini,                 /* eno_fini */
170         siena_nic_unprobe,              /* eno_unprobe */
171 };
172
173 #endif  /* EFSYS_OPT_SIENA */
174
175 #if EFSYS_OPT_HUNTINGTON
176
177 static const efx_nic_ops_t      __efx_nic_hunt_ops = {
178         ef10_nic_probe,                 /* eno_probe */
179         hunt_board_cfg,                 /* eno_board_cfg */
180         ef10_nic_set_drv_limits,        /* eno_set_drv_limits */
181         ef10_nic_reset,                 /* eno_reset */
182         ef10_nic_init,                  /* eno_init */
183         ef10_nic_get_vi_pool,           /* eno_get_vi_pool */
184         ef10_nic_get_bar_region,        /* eno_get_bar_region */
185         ef10_nic_fini,                  /* eno_fini */
186         ef10_nic_unprobe,               /* eno_unprobe */
187 };
188
189 #endif  /* EFSYS_OPT_HUNTINGTON */
190
191
192         __checkReturn   efx_rc_t
193 efx_nic_create(
194         __in            efx_family_t family,
195         __in            efsys_identifier_t *esip,
196         __in            efsys_bar_t *esbp,
197         __in            efsys_lock_t *eslp,
198         __deref_out     efx_nic_t **enpp)
199 {
200         efx_nic_t *enp;
201         efx_rc_t rc;
202
203         EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID);
204         EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES);
205
206         /* Allocate a NIC object */
207         EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp);
208
209         if (enp == NULL) {
210                 rc = ENOMEM;
211                 goto fail1;
212         }
213
214         enp->en_magic = EFX_NIC_MAGIC;
215
216         switch (family) {
217 #if EFSYS_OPT_SIENA
218         case EFX_FAMILY_SIENA:
219                 enp->en_enop = &__efx_nic_siena_ops;
220                 enp->en_features =
221                     EFX_FEATURE_IPV6 |
222                     EFX_FEATURE_LFSR_HASH_INSERT |
223                     EFX_FEATURE_LINK_EVENTS |
224                     EFX_FEATURE_PERIODIC_MAC_STATS |
225                     EFX_FEATURE_MCDI |
226                     EFX_FEATURE_LOOKAHEAD_SPLIT |
227                     EFX_FEATURE_MAC_HEADER_FILTERS |
228                     EFX_FEATURE_TX_SRC_FILTERS;
229                 break;
230 #endif  /* EFSYS_OPT_SIENA */
231
232 #if EFSYS_OPT_HUNTINGTON
233         case EFX_FAMILY_HUNTINGTON:
234                 enp->en_enop = &__efx_nic_hunt_ops;
235                 enp->en_features =
236                     EFX_FEATURE_IPV6 |
237                     EFX_FEATURE_LINK_EVENTS |
238                     EFX_FEATURE_PERIODIC_MAC_STATS |
239                     EFX_FEATURE_MCDI |
240                     EFX_FEATURE_MAC_HEADER_FILTERS |
241                     EFX_FEATURE_MCDI_DMA |
242                     EFX_FEATURE_PIO_BUFFERS |
243                     EFX_FEATURE_FW_ASSISTED_TSO |
244                     EFX_FEATURE_FW_ASSISTED_TSO_V2 |
245                     EFX_FEATURE_PACKED_STREAM;
246                 break;
247 #endif  /* EFSYS_OPT_HUNTINGTON */
248
249         default:
250                 rc = ENOTSUP;
251                 goto fail2;
252         }
253
254         enp->en_family = family;
255         enp->en_esip = esip;
256         enp->en_esbp = esbp;
257         enp->en_eslp = eslp;
258
259         *enpp = enp;
260
261         return (0);
262
263 fail2:
264         EFSYS_PROBE(fail2);
265
266         enp->en_magic = 0;
267
268         /* Free the NIC object */
269         EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
270
271 fail1:
272         EFSYS_PROBE1(fail1, efx_rc_t, rc);
273
274         return (rc);
275 }
276
277         __checkReturn   efx_rc_t
278 efx_nic_probe(
279         __in            efx_nic_t *enp)
280 {
281         const efx_nic_ops_t *enop;
282         efx_rc_t rc;
283
284         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
285 #if EFSYS_OPT_MCDI
286         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
287 #endif  /* EFSYS_OPT_MCDI */
288         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE));
289
290         enop = enp->en_enop;
291         if ((rc = enop->eno_probe(enp)) != 0)
292                 goto fail1;
293
294         if ((rc = efx_phy_probe(enp)) != 0)
295                 goto fail2;
296
297         enp->en_mod_flags |= EFX_MOD_PROBE;
298
299         return (0);
300
301 fail2:
302         EFSYS_PROBE(fail2);
303
304         enop->eno_unprobe(enp);
305
306 fail1:
307         EFSYS_PROBE1(fail1, efx_rc_t, rc);
308
309         return (rc);
310 }
311
312         __checkReturn   efx_rc_t
313 efx_nic_set_drv_limits(
314         __inout         efx_nic_t *enp,
315         __in            efx_drv_limits_t *edlp)
316 {
317         const efx_nic_ops_t *enop = enp->en_enop;
318         efx_rc_t rc;
319
320         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
321         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
322
323         if (enop->eno_set_drv_limits != NULL) {
324                 if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0)
325                         goto fail1;
326         }
327
328         return (0);
329
330 fail1:
331         EFSYS_PROBE1(fail1, efx_rc_t, rc);
332
333         return (rc);
334 }
335
336         __checkReturn   efx_rc_t
337 efx_nic_get_bar_region(
338         __in            efx_nic_t *enp,
339         __in            efx_nic_region_t region,
340         __out           uint32_t *offsetp,
341         __out           size_t *sizep)
342 {
343         const efx_nic_ops_t *enop = enp->en_enop;
344         efx_rc_t rc;
345
346         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
347         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
348         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
349
350         if (enop->eno_get_bar_region == NULL) {
351                 rc = ENOTSUP;
352                 goto fail1;
353         }
354         if ((rc = (enop->eno_get_bar_region)(enp,
355                     region, offsetp, sizep)) != 0) {
356                 goto fail2;
357         }
358
359         return (0);
360
361 fail2:
362         EFSYS_PROBE(fail2);
363
364 fail1:
365         EFSYS_PROBE1(fail1, efx_rc_t, rc);
366
367         return (rc);
368 }
369
370
371         __checkReturn   efx_rc_t
372 efx_nic_get_vi_pool(
373         __in            efx_nic_t *enp,
374         __out           uint32_t *evq_countp,
375         __out           uint32_t *rxq_countp,
376         __out           uint32_t *txq_countp)
377 {
378         const efx_nic_ops_t *enop = enp->en_enop;
379         efx_nic_cfg_t *encp = &enp->en_nic_cfg;
380         efx_rc_t rc;
381
382         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
383         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
384         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
385
386         if (enop->eno_get_vi_pool != NULL) {
387                 uint32_t vi_count = 0;
388
389                 if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0)
390                         goto fail1;
391
392                 *evq_countp = vi_count;
393                 *rxq_countp = vi_count;
394                 *txq_countp = vi_count;
395         } else {
396                 /* Use NIC limits as default value */
397                 *evq_countp = encp->enc_evq_limit;
398                 *rxq_countp = encp->enc_rxq_limit;
399                 *txq_countp = encp->enc_txq_limit;
400         }
401
402         return (0);
403
404 fail1:
405         EFSYS_PROBE1(fail1, efx_rc_t, rc);
406
407         return (rc);
408 }
409
410
411         __checkReturn   efx_rc_t
412 efx_nic_init(
413         __in            efx_nic_t *enp)
414 {
415         const efx_nic_ops_t *enop = enp->en_enop;
416         efx_rc_t rc;
417
418         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
419         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
420
421         if (enp->en_mod_flags & EFX_MOD_NIC) {
422                 rc = EINVAL;
423                 goto fail1;
424         }
425
426         if ((rc = enop->eno_init(enp)) != 0)
427                 goto fail2;
428
429         enp->en_mod_flags |= EFX_MOD_NIC;
430
431         return (0);
432
433 fail2:
434         EFSYS_PROBE(fail2);
435 fail1:
436         EFSYS_PROBE1(fail1, efx_rc_t, rc);
437
438         return (rc);
439 }
440
441                         void
442 efx_nic_fini(
443         __in            efx_nic_t *enp)
444 {
445         const efx_nic_ops_t *enop = enp->en_enop;
446
447         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
448         EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
449         EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC);
450         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
451         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
452         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
453         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
454
455         enop->eno_fini(enp);
456
457         enp->en_mod_flags &= ~EFX_MOD_NIC;
458 }
459
460                         void
461 efx_nic_unprobe(
462         __in            efx_nic_t *enp)
463 {
464         const efx_nic_ops_t *enop = enp->en_enop;
465
466         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
467 #if EFSYS_OPT_MCDI
468         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
469 #endif  /* EFSYS_OPT_MCDI */
470         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
471         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
472         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
473         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
474         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
475         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
476
477         efx_phy_unprobe(enp);
478
479         enop->eno_unprobe(enp);
480
481         enp->en_mod_flags &= ~EFX_MOD_PROBE;
482 }
483
484                         void
485 efx_nic_destroy(
486         __in    efx_nic_t *enp)
487 {
488         efsys_identifier_t *esip = enp->en_esip;
489
490         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
491         EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
492
493         enp->en_family = EFX_FAMILY_INVALID;
494         enp->en_esip = NULL;
495         enp->en_esbp = NULL;
496         enp->en_eslp = NULL;
497
498         enp->en_enop = NULL;
499
500         enp->en_magic = 0;
501
502         /* Free the NIC object */
503         EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
504 }
505
506         __checkReturn   efx_rc_t
507 efx_nic_reset(
508         __in            efx_nic_t *enp)
509 {
510         const efx_nic_ops_t *enop = enp->en_enop;
511         unsigned int mod_flags;
512         efx_rc_t rc;
513
514         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
515         EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
516         /*
517          * All modules except the MCDI, PROBE, NVRAM, VPD, MON
518          * (which we do not reset here) must have been shut down or never
519          * initialized.
520          *
521          * A rule of thumb here is: If the controller or MC reboots, is *any*
522          * state lost. If it's lost and needs reapplying, then the module
523          * *must* not be initialised during the reset.
524          */
525         mod_flags = enp->en_mod_flags;
526         mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM |
527                     EFX_MOD_VPD | EFX_MOD_MON);
528         EFSYS_ASSERT3U(mod_flags, ==, 0);
529         if (mod_flags != 0) {
530                 rc = EINVAL;
531                 goto fail1;
532         }
533
534         if ((rc = enop->eno_reset(enp)) != 0)
535                 goto fail2;
536
537         return (0);
538
539 fail2:
540         EFSYS_PROBE(fail2);
541 fail1:
542         EFSYS_PROBE1(fail1, efx_rc_t, rc);
543
544         return (rc);
545 }
546
547                         const efx_nic_cfg_t *
548 efx_nic_cfg_get(
549         __in            efx_nic_t *enp)
550 {
551         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
552
553         return (&(enp->en_nic_cfg));
554 }
555
556         __checkReturn   efx_rc_t
557 efx_nic_calculate_pcie_link_bandwidth(
558         __in            uint32_t pcie_link_width,
559         __in            uint32_t pcie_link_gen,
560         __out           uint32_t *bandwidth_mbpsp)
561 {
562         uint32_t lane_bandwidth;
563         uint32_t total_bandwidth;
564         efx_rc_t rc;
565
566         if ((pcie_link_width == 0) || (pcie_link_width > 16) ||
567             !ISP2(pcie_link_width)) {
568                 rc = EINVAL;
569                 goto fail1;
570         }
571
572         switch (pcie_link_gen) {
573         case EFX_PCIE_LINK_SPEED_GEN1:
574                 /* 2.5 Gb/s raw bandwidth with 8b/10b encoding */
575                 lane_bandwidth = 2000;
576                 break;
577         case EFX_PCIE_LINK_SPEED_GEN2:
578                 /* 5.0 Gb/s raw bandwidth with 8b/10b encoding */
579                 lane_bandwidth = 4000;
580                 break;
581         case EFX_PCIE_LINK_SPEED_GEN3:
582                 /* 8.0 Gb/s raw bandwidth with 128b/130b encoding */
583                 lane_bandwidth = 7877;
584                 break;
585         default:
586                 rc = EINVAL;
587                 goto fail2;
588         }
589
590         total_bandwidth = lane_bandwidth * pcie_link_width;
591         *bandwidth_mbpsp = total_bandwidth;
592
593         return (0);
594
595 fail2:
596         EFSYS_PROBE(fail2);
597 fail1:
598         EFSYS_PROBE1(fail1, efx_rc_t, rc);
599
600         return (rc);
601 }
602
603
604         __checkReturn   efx_rc_t
605 efx_nic_check_pcie_link_speed(
606         __in            efx_nic_t *enp,
607         __in            uint32_t pcie_link_width,
608         __in            uint32_t pcie_link_gen,
609         __out           efx_pcie_link_performance_t *resultp)
610 {
611         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
612         uint32_t bandwidth;
613         efx_pcie_link_performance_t result;
614         efx_rc_t rc;
615
616         if ((encp->enc_required_pcie_bandwidth_mbps == 0) ||
617             (pcie_link_width == 0) || (pcie_link_width == 32) ||
618             (pcie_link_gen == 0)) {
619                 /*
620                  * No usable info on what is required and/or in use. In virtual
621                  * machines, sometimes the PCIe link width is reported as 0 or
622                  * 32, or the speed as 0.
623                  */
624                 result = EFX_PCIE_LINK_PERFORMANCE_UNKNOWN_BANDWIDTH;
625                 goto out;
626         }
627
628         /* Calculate the available bandwidth in megabits per second */
629         rc = efx_nic_calculate_pcie_link_bandwidth(pcie_link_width,
630                                             pcie_link_gen, &bandwidth);
631         if (rc != 0)
632                 goto fail1;
633
634         if (bandwidth < encp->enc_required_pcie_bandwidth_mbps) {
635                 result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_BANDWIDTH;
636         } else if (pcie_link_gen < encp->enc_max_pcie_link_gen) {
637                 /* The link provides enough bandwidth but not optimal latency */
638                 result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_LATENCY;
639         } else {
640                 result = EFX_PCIE_LINK_PERFORMANCE_OPTIMAL;
641         }
642
643 out:
644         *resultp = result;
645
646         return (0);
647
648 fail1:
649         EFSYS_PROBE1(fail1, efx_rc_t, rc);
650
651         return (rc);
652 }