1227569Sphilip/*- 2301388Sarybchik * Copyright (c) 2007-2016 Solarflare Communications Inc. 3284555Sarybchik * All rights reserved. 4227569Sphilip * 5227569Sphilip * Redistribution and use in source and binary forms, with or without 6284555Sarybchik * modification, are permitted provided that the following conditions are met: 7227569Sphilip * 8284555Sarybchik * 1. Redistributions of source code must retain the above copyright notice, 9284555Sarybchik * this list of conditions and the following disclaimer. 10284555Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice, 11284555Sarybchik * this list of conditions and the following disclaimer in the documentation 12284555Sarybchik * and/or other materials provided with the distribution. 13284555Sarybchik * 14284555Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15284555Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16284555Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17284555Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18284555Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19284555Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20284555Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21284555Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22284555Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23284555Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24284555Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25284555Sarybchik * 26284555Sarybchik * The views and conclusions contained in the software and documentation are 27284555Sarybchik * those of the authors and should not be interpreted as representing official 28284555Sarybchik * policies, either expressed or implied, of the FreeBSD Project. 29227569Sphilip */ 30227569Sphilip 31228078Sphilip#include <sys/cdefs.h> 32228078Sphilip__FBSDID("$FreeBSD: stable/10/sys/dev/sfxge/common/efx_nic.c 342524 2018-12-26 10:37:06Z arybchik $"); 33228078Sphilip 34227569Sphilip#include "efx.h" 35227569Sphilip#include "efx_impl.h" 36227569Sphilip 37293927Sarybchik __checkReturn efx_rc_t 38227569Sphilipefx_family( 39227569Sphilip __in uint16_t venid, 40227569Sphilip __in uint16_t devid, 41227569Sphilip __out efx_family_t *efp) 42227569Sphilip{ 43284555Sarybchik if (venid == EFX_PCI_VENID_SFC) { 44284555Sarybchik switch (devid) { 45227569Sphilip#if EFSYS_OPT_SIENA 46284555Sarybchik case EFX_PCI_DEVID_SIENA_F1_UNINIT: 47284555Sarybchik /* 48284555Sarybchik * Hardware default for PF0 of uninitialised Siena. 49284555Sarybchik * manftest must be able to cope with this device id. 50284555Sarybchik */ 51284555Sarybchik *efp = EFX_FAMILY_SIENA; 52284555Sarybchik return (0); 53284555Sarybchik 54284555Sarybchik case EFX_PCI_DEVID_BETHPAGE: 55284555Sarybchik case EFX_PCI_DEVID_SIENA: 56284555Sarybchik *efp = EFX_FAMILY_SIENA; 57284555Sarybchik return (0); 58293975Sarybchik#endif /* EFSYS_OPT_SIENA */ 59284555Sarybchik 60284555Sarybchik#if EFSYS_OPT_HUNTINGTON 61284555Sarybchik case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT: 62284555Sarybchik /* 63284555Sarybchik * Hardware default for PF0 of uninitialised Huntington. 64284555Sarybchik * manftest must be able to cope with this device id. 65284555Sarybchik */ 66284555Sarybchik *efp = EFX_FAMILY_HUNTINGTON; 67284555Sarybchik return (0); 68284555Sarybchik 69284555Sarybchik case EFX_PCI_DEVID_FARMINGDALE: 70284555Sarybchik case EFX_PCI_DEVID_GREENPORT: 71284555Sarybchik *efp = EFX_FAMILY_HUNTINGTON; 72284555Sarybchik return (0); 73284555Sarybchik 74284555Sarybchik case EFX_PCI_DEVID_FARMINGDALE_VF: 75284555Sarybchik case EFX_PCI_DEVID_GREENPORT_VF: 76284555Sarybchik *efp = EFX_FAMILY_HUNTINGTON; 77284555Sarybchik return (0); 78293975Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 79293975Sarybchik 80293975Sarybchik#if EFSYS_OPT_MEDFORD 81293975Sarybchik case EFX_PCI_DEVID_MEDFORD_PF_UNINIT: 82293975Sarybchik /* 83293975Sarybchik * Hardware default for PF0 of uninitialised Medford. 84293975Sarybchik * manftest must be able to cope with this device id. 85293975Sarybchik */ 86293975Sarybchik *efp = EFX_FAMILY_MEDFORD; 87293975Sarybchik return (0); 88293975Sarybchik 89293975Sarybchik case EFX_PCI_DEVID_MEDFORD: 90293975Sarybchik *efp = EFX_FAMILY_MEDFORD; 91293975Sarybchik return (0); 92293975Sarybchik 93293975Sarybchik case EFX_PCI_DEVID_MEDFORD_VF: 94293975Sarybchik *efp = EFX_FAMILY_MEDFORD; 95293975Sarybchik return (0); 96293975Sarybchik#endif /* EFSYS_OPT_MEDFORD */ 97293975Sarybchik 98301324Sarybchik case EFX_PCI_DEVID_FALCON: /* Obsolete, not supported */ 99284555Sarybchik default: 100284555Sarybchik break; 101284555Sarybchik } 102227569Sphilip } 103284555Sarybchik 104284555Sarybchik *efp = EFX_FAMILY_INVALID; 105227569Sphilip return (ENOTSUP); 106227569Sphilip} 107227569Sphilip 108227569Sphilip#if EFSYS_OPT_SIENA 109227569Sphilip 110301340Sarybchikstatic const efx_nic_ops_t __efx_nic_siena_ops = { 111227569Sphilip siena_nic_probe, /* eno_probe */ 112294377Sarybchik NULL, /* eno_board_cfg */ 113284555Sarybchik NULL, /* eno_set_drv_limits */ 114227569Sphilip siena_nic_reset, /* eno_reset */ 115227569Sphilip siena_nic_init, /* eno_init */ 116284555Sarybchik NULL, /* eno_get_vi_pool */ 117284555Sarybchik NULL, /* eno_get_bar_region */ 118227569Sphilip#if EFSYS_OPT_DIAG 119227569Sphilip siena_nic_register_test, /* eno_register_test */ 120227569Sphilip#endif /* EFSYS_OPT_DIAG */ 121227569Sphilip siena_nic_fini, /* eno_fini */ 122227569Sphilip siena_nic_unprobe, /* eno_unprobe */ 123227569Sphilip}; 124227569Sphilip 125227569Sphilip#endif /* EFSYS_OPT_SIENA */ 126227569Sphilip 127284555Sarybchik#if EFSYS_OPT_HUNTINGTON 128284555Sarybchik 129301340Sarybchikstatic const efx_nic_ops_t __efx_nic_hunt_ops = { 130294006Sarybchik ef10_nic_probe, /* eno_probe */ 131294377Sarybchik hunt_board_cfg, /* eno_board_cfg */ 132294006Sarybchik ef10_nic_set_drv_limits, /* eno_set_drv_limits */ 133294006Sarybchik ef10_nic_reset, /* eno_reset */ 134294006Sarybchik ef10_nic_init, /* eno_init */ 135294006Sarybchik ef10_nic_get_vi_pool, /* eno_get_vi_pool */ 136294006Sarybchik ef10_nic_get_bar_region, /* eno_get_bar_region */ 137284555Sarybchik#if EFSYS_OPT_DIAG 138294006Sarybchik ef10_nic_register_test, /* eno_register_test */ 139284555Sarybchik#endif /* EFSYS_OPT_DIAG */ 140294006Sarybchik ef10_nic_fini, /* eno_fini */ 141294006Sarybchik ef10_nic_unprobe, /* eno_unprobe */ 142284555Sarybchik}; 143284555Sarybchik 144284555Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 145284555Sarybchik 146294377Sarybchik#if EFSYS_OPT_MEDFORD 147294377Sarybchik 148301340Sarybchikstatic const efx_nic_ops_t __efx_nic_medford_ops = { 149294377Sarybchik ef10_nic_probe, /* eno_probe */ 150294377Sarybchik medford_board_cfg, /* eno_board_cfg */ 151294377Sarybchik ef10_nic_set_drv_limits, /* eno_set_drv_limits */ 152294377Sarybchik ef10_nic_reset, /* eno_reset */ 153294377Sarybchik ef10_nic_init, /* eno_init */ 154294377Sarybchik ef10_nic_get_vi_pool, /* eno_get_vi_pool */ 155294377Sarybchik ef10_nic_get_bar_region, /* eno_get_bar_region */ 156294377Sarybchik#if EFSYS_OPT_DIAG 157294377Sarybchik ef10_nic_register_test, /* eno_register_test */ 158294377Sarybchik#endif /* EFSYS_OPT_DIAG */ 159294377Sarybchik ef10_nic_fini, /* eno_fini */ 160294377Sarybchik ef10_nic_unprobe, /* eno_unprobe */ 161294377Sarybchik}; 162294377Sarybchik 163294377Sarybchik#endif /* EFSYS_OPT_MEDFORD */ 164294377Sarybchik 165294377Sarybchik 166293927Sarybchik __checkReturn efx_rc_t 167227569Sphilipefx_nic_create( 168227569Sphilip __in efx_family_t family, 169227569Sphilip __in efsys_identifier_t *esip, 170227569Sphilip __in efsys_bar_t *esbp, 171227569Sphilip __in efsys_lock_t *eslp, 172227569Sphilip __deref_out efx_nic_t **enpp) 173227569Sphilip{ 174227569Sphilip efx_nic_t *enp; 175293927Sarybchik efx_rc_t rc; 176227569Sphilip 177227569Sphilip EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID); 178227569Sphilip EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES); 179227569Sphilip 180227569Sphilip /* Allocate a NIC object */ 181227569Sphilip EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp); 182227569Sphilip 183227569Sphilip if (enp == NULL) { 184227569Sphilip rc = ENOMEM; 185227569Sphilip goto fail1; 186227569Sphilip } 187227569Sphilip 188227569Sphilip enp->en_magic = EFX_NIC_MAGIC; 189227569Sphilip 190227569Sphilip switch (family) { 191227569Sphilip#if EFSYS_OPT_SIENA 192227569Sphilip case EFX_FAMILY_SIENA: 193301340Sarybchik enp->en_enop = &__efx_nic_siena_ops; 194280563Sarybchik enp->en_features = 195280563Sarybchik EFX_FEATURE_IPV6 | 196227569Sphilip EFX_FEATURE_LFSR_HASH_INSERT | 197280563Sarybchik EFX_FEATURE_LINK_EVENTS | 198280563Sarybchik EFX_FEATURE_PERIODIC_MAC_STATS | 199280563Sarybchik EFX_FEATURE_MCDI | 200280535Sarybchik EFX_FEATURE_LOOKAHEAD_SPLIT | 201284555Sarybchik EFX_FEATURE_MAC_HEADER_FILTERS | 202284555Sarybchik EFX_FEATURE_TX_SRC_FILTERS; 203227569Sphilip break; 204227569Sphilip#endif /* EFSYS_OPT_SIENA */ 205227569Sphilip 206284555Sarybchik#if EFSYS_OPT_HUNTINGTON 207284555Sarybchik case EFX_FAMILY_HUNTINGTON: 208301340Sarybchik enp->en_enop = &__efx_nic_hunt_ops; 209284555Sarybchik enp->en_features = 210284555Sarybchik EFX_FEATURE_IPV6 | 211284555Sarybchik EFX_FEATURE_LINK_EVENTS | 212284555Sarybchik EFX_FEATURE_PERIODIC_MAC_STATS | 213284555Sarybchik EFX_FEATURE_MCDI | 214284555Sarybchik EFX_FEATURE_MAC_HEADER_FILTERS | 215284555Sarybchik EFX_FEATURE_MCDI_DMA | 216284555Sarybchik EFX_FEATURE_PIO_BUFFERS | 217294381Sarybchik EFX_FEATURE_FW_ASSISTED_TSO | 218342524Sarybchik EFX_FEATURE_FW_ASSISTED_TSO_V2 | 219342524Sarybchik EFX_FEATURE_TXQ_CKSUM_OP_DESC; 220284555Sarybchik break; 221284555Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 222284555Sarybchik 223294377Sarybchik#if EFSYS_OPT_MEDFORD 224294377Sarybchik case EFX_FAMILY_MEDFORD: 225301340Sarybchik enp->en_enop = &__efx_nic_medford_ops; 226294377Sarybchik /* 227294377Sarybchik * FW_ASSISTED_TSO ommitted as Medford only supports firmware 228294377Sarybchik * assisted TSO version 2, not the v1 scheme used on Huntington. 229294377Sarybchik */ 230294377Sarybchik enp->en_features = 231294377Sarybchik EFX_FEATURE_IPV6 | 232294377Sarybchik EFX_FEATURE_LINK_EVENTS | 233294377Sarybchik EFX_FEATURE_PERIODIC_MAC_STATS | 234294377Sarybchik EFX_FEATURE_MCDI | 235294377Sarybchik EFX_FEATURE_MAC_HEADER_FILTERS | 236294377Sarybchik EFX_FEATURE_MCDI_DMA | 237301372Sarybchik EFX_FEATURE_PIO_BUFFERS | 238342524Sarybchik EFX_FEATURE_FW_ASSISTED_TSO_V2 | 239342524Sarybchik EFX_FEATURE_TXQ_CKSUM_OP_DESC; 240294377Sarybchik break; 241294377Sarybchik#endif /* EFSYS_OPT_MEDFORD */ 242294377Sarybchik 243227569Sphilip default: 244227569Sphilip rc = ENOTSUP; 245227569Sphilip goto fail2; 246227569Sphilip } 247227569Sphilip 248227569Sphilip enp->en_family = family; 249227569Sphilip enp->en_esip = esip; 250227569Sphilip enp->en_esbp = esbp; 251227569Sphilip enp->en_eslp = eslp; 252227569Sphilip 253227569Sphilip *enpp = enp; 254227569Sphilip 255227569Sphilip return (0); 256227569Sphilip 257227569Sphilipfail2: 258284555Sarybchik EFSYS_PROBE(fail2); 259227569Sphilip 260227569Sphilip enp->en_magic = 0; 261227569Sphilip 262227569Sphilip /* Free the NIC object */ 263227569Sphilip EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); 264227569Sphilip 265227569Sphilipfail1: 266293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 267227569Sphilip 268227569Sphilip return (rc); 269227569Sphilip} 270227569Sphilip 271293927Sarybchik __checkReturn efx_rc_t 272227569Sphilipefx_nic_probe( 273227569Sphilip __in efx_nic_t *enp) 274227569Sphilip{ 275301340Sarybchik const efx_nic_ops_t *enop; 276293927Sarybchik efx_rc_t rc; 277227569Sphilip 278227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 279227569Sphilip#if EFSYS_OPT_MCDI 280227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 281227569Sphilip#endif /* EFSYS_OPT_MCDI */ 282227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE)); 283227569Sphilip 284227569Sphilip enop = enp->en_enop; 285227569Sphilip if ((rc = enop->eno_probe(enp)) != 0) 286284555Sarybchik goto fail1; 287227569Sphilip 288227569Sphilip if ((rc = efx_phy_probe(enp)) != 0) 289284555Sarybchik goto fail2; 290227569Sphilip 291227569Sphilip enp->en_mod_flags |= EFX_MOD_PROBE; 292227569Sphilip 293227569Sphilip return (0); 294227569Sphilip 295284555Sarybchikfail2: 296284555Sarybchik EFSYS_PROBE(fail2); 297227569Sphilip 298227569Sphilip enop->eno_unprobe(enp); 299227569Sphilip 300227569Sphilipfail1: 301293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 302227569Sphilip 303227569Sphilip return (rc); 304227569Sphilip} 305227569Sphilip 306293927Sarybchik __checkReturn efx_rc_t 307284555Sarybchikefx_nic_set_drv_limits( 308284555Sarybchik __inout efx_nic_t *enp, 309284555Sarybchik __in efx_drv_limits_t *edlp) 310284555Sarybchik{ 311301340Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 312293927Sarybchik efx_rc_t rc; 313284555Sarybchik 314284555Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 315284555Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 316284555Sarybchik 317284555Sarybchik if (enop->eno_set_drv_limits != NULL) { 318284555Sarybchik if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0) 319284555Sarybchik goto fail1; 320284555Sarybchik } 321284555Sarybchik 322284555Sarybchik return (0); 323284555Sarybchik 324284555Sarybchikfail1: 325293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 326284555Sarybchik 327284555Sarybchik return (rc); 328284555Sarybchik} 329284555Sarybchik 330293927Sarybchik __checkReturn efx_rc_t 331284555Sarybchikefx_nic_get_bar_region( 332284555Sarybchik __in efx_nic_t *enp, 333284555Sarybchik __in efx_nic_region_t region, 334284555Sarybchik __out uint32_t *offsetp, 335284555Sarybchik __out size_t *sizep) 336284555Sarybchik{ 337301340Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 338293927Sarybchik efx_rc_t rc; 339284555Sarybchik 340284555Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 341284555Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 342284555Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 343284555Sarybchik 344284555Sarybchik if (enop->eno_get_bar_region == NULL) { 345284555Sarybchik rc = ENOTSUP; 346284555Sarybchik goto fail1; 347284555Sarybchik } 348284555Sarybchik if ((rc = (enop->eno_get_bar_region)(enp, 349284555Sarybchik region, offsetp, sizep)) != 0) { 350284555Sarybchik goto fail2; 351284555Sarybchik } 352284555Sarybchik 353284555Sarybchik return (0); 354284555Sarybchik 355284555Sarybchikfail2: 356284555Sarybchik EFSYS_PROBE(fail2); 357284555Sarybchik 358284555Sarybchikfail1: 359293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 360284555Sarybchik 361284555Sarybchik return (rc); 362284555Sarybchik} 363284555Sarybchik 364284555Sarybchik 365293927Sarybchik __checkReturn efx_rc_t 366284555Sarybchikefx_nic_get_vi_pool( 367284555Sarybchik __in efx_nic_t *enp, 368284555Sarybchik __out uint32_t *evq_countp, 369284555Sarybchik __out uint32_t *rxq_countp, 370284555Sarybchik __out uint32_t *txq_countp) 371284555Sarybchik{ 372301340Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 373284555Sarybchik efx_nic_cfg_t *encp = &enp->en_nic_cfg; 374293927Sarybchik efx_rc_t rc; 375284555Sarybchik 376284555Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 377284555Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 378284555Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 379284555Sarybchik 380284555Sarybchik if (enop->eno_get_vi_pool != NULL) { 381284555Sarybchik uint32_t vi_count = 0; 382284555Sarybchik 383284555Sarybchik if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0) 384284555Sarybchik goto fail1; 385284555Sarybchik 386284555Sarybchik *evq_countp = vi_count; 387284555Sarybchik *rxq_countp = vi_count; 388284555Sarybchik *txq_countp = vi_count; 389284555Sarybchik } else { 390284555Sarybchik /* Use NIC limits as default value */ 391284555Sarybchik *evq_countp = encp->enc_evq_limit; 392284555Sarybchik *rxq_countp = encp->enc_rxq_limit; 393284555Sarybchik *txq_countp = encp->enc_txq_limit; 394284555Sarybchik } 395284555Sarybchik 396284555Sarybchik return (0); 397284555Sarybchik 398284555Sarybchikfail1: 399293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 400284555Sarybchik 401284555Sarybchik return (rc); 402284555Sarybchik} 403284555Sarybchik 404284555Sarybchik 405293927Sarybchik __checkReturn efx_rc_t 406227569Sphilipefx_nic_init( 407227569Sphilip __in efx_nic_t *enp) 408227569Sphilip{ 409301340Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 410293927Sarybchik efx_rc_t rc; 411227569Sphilip 412227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 413227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 414227569Sphilip 415227569Sphilip if (enp->en_mod_flags & EFX_MOD_NIC) { 416227569Sphilip rc = EINVAL; 417227569Sphilip goto fail1; 418227569Sphilip } 419227569Sphilip 420227569Sphilip if ((rc = enop->eno_init(enp)) != 0) 421227569Sphilip goto fail2; 422227569Sphilip 423227569Sphilip enp->en_mod_flags |= EFX_MOD_NIC; 424227569Sphilip 425227569Sphilip return (0); 426227569Sphilip 427227569Sphilipfail2: 428227569Sphilip EFSYS_PROBE(fail2); 429227569Sphilipfail1: 430293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 431227569Sphilip 432227569Sphilip return (rc); 433227569Sphilip} 434227569Sphilip 435227569Sphilip void 436227569Sphilipefx_nic_fini( 437227569Sphilip __in efx_nic_t *enp) 438227569Sphilip{ 439301340Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 440227569Sphilip 441227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 442227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 443227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC); 444227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); 445227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 446227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 447227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 448227569Sphilip 449227569Sphilip enop->eno_fini(enp); 450227569Sphilip 451227569Sphilip enp->en_mod_flags &= ~EFX_MOD_NIC; 452227569Sphilip} 453227569Sphilip 454227569Sphilip void 455227569Sphilipefx_nic_unprobe( 456227569Sphilip __in efx_nic_t *enp) 457227569Sphilip{ 458301340Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 459227569Sphilip 460227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 461227569Sphilip#if EFSYS_OPT_MCDI 462227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 463227569Sphilip#endif /* EFSYS_OPT_MCDI */ 464227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 465227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 466227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); 467227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 468227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 469227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 470227569Sphilip 471227569Sphilip efx_phy_unprobe(enp); 472227569Sphilip 473227569Sphilip enop->eno_unprobe(enp); 474227569Sphilip 475227569Sphilip enp->en_mod_flags &= ~EFX_MOD_PROBE; 476227569Sphilip} 477227569Sphilip 478227569Sphilip void 479227569Sphilipefx_nic_destroy( 480227569Sphilip __in efx_nic_t *enp) 481227569Sphilip{ 482227569Sphilip efsys_identifier_t *esip = enp->en_esip; 483227569Sphilip 484227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 485227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); 486227569Sphilip 487311068Sarybchik enp->en_family = EFX_FAMILY_INVALID; 488227569Sphilip enp->en_esip = NULL; 489227569Sphilip enp->en_esbp = NULL; 490227569Sphilip enp->en_eslp = NULL; 491227569Sphilip 492227569Sphilip enp->en_enop = NULL; 493227569Sphilip 494227569Sphilip enp->en_magic = 0; 495227569Sphilip 496227569Sphilip /* Free the NIC object */ 497227569Sphilip EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); 498227569Sphilip} 499227569Sphilip 500293927Sarybchik __checkReturn efx_rc_t 501227569Sphilipefx_nic_reset( 502227569Sphilip __in efx_nic_t *enp) 503227569Sphilip{ 504301340Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 505227569Sphilip unsigned int mod_flags; 506293927Sarybchik efx_rc_t rc; 507227569Sphilip 508227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 509227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 510227569Sphilip /* 511301379Sarybchik * All modules except the MCDI, PROBE, NVRAM, VPD, MON 512294386Sarybchik * (which we do not reset here) must have been shut down or never 513294386Sarybchik * initialized. 514227569Sphilip * 515227569Sphilip * A rule of thumb here is: If the controller or MC reboots, is *any* 516227569Sphilip * state lost. If it's lost and needs reapplying, then the module 517227569Sphilip * *must* not be initialised during the reset. 518227569Sphilip */ 519227569Sphilip mod_flags = enp->en_mod_flags; 520227569Sphilip mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM | 521301379Sarybchik EFX_MOD_VPD | EFX_MOD_MON); 522227569Sphilip EFSYS_ASSERT3U(mod_flags, ==, 0); 523227569Sphilip if (mod_flags != 0) { 524227569Sphilip rc = EINVAL; 525227569Sphilip goto fail1; 526227569Sphilip } 527227569Sphilip 528227569Sphilip if ((rc = enop->eno_reset(enp)) != 0) 529227569Sphilip goto fail2; 530227569Sphilip 531227569Sphilip return (0); 532227569Sphilip 533227569Sphilipfail2: 534227569Sphilip EFSYS_PROBE(fail2); 535227569Sphilipfail1: 536293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 537227569Sphilip 538227569Sphilip return (rc); 539227569Sphilip} 540227569Sphilip 541227569Sphilip const efx_nic_cfg_t * 542227569Sphilipefx_nic_cfg_get( 543227569Sphilip __in efx_nic_t *enp) 544227569Sphilip{ 545227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 546342517Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 547227569Sphilip 548227569Sphilip return (&(enp->en_nic_cfg)); 549227569Sphilip} 550227569Sphilip 551227569Sphilip#if EFSYS_OPT_DIAG 552227569Sphilip 553293927Sarybchik __checkReturn efx_rc_t 554227569Sphilipefx_nic_register_test( 555227569Sphilip __in efx_nic_t *enp) 556227569Sphilip{ 557301340Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 558293927Sarybchik efx_rc_t rc; 559227569Sphilip 560227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 561227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 562227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 563227569Sphilip 564227569Sphilip if ((rc = enop->eno_register_test(enp)) != 0) 565227569Sphilip goto fail1; 566227569Sphilip 567227569Sphilip return (0); 568227569Sphilip 569227569Sphilipfail1: 570293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 571227569Sphilip 572227569Sphilip return (rc); 573227569Sphilip} 574227569Sphilip 575227569Sphilip#endif /* EFSYS_OPT_DIAG */ 576284555Sarybchik 577284555Sarybchik#if EFSYS_OPT_LOOPBACK 578284555Sarybchik 579284555Sarybchikextern void 580284555Sarybchikefx_loopback_mask( 581284555Sarybchik __in efx_loopback_kind_t loopback_kind, 582284555Sarybchik __out efx_qword_t *maskp) 583284555Sarybchik{ 584284555Sarybchik efx_qword_t mask; 585284555Sarybchik 586284555Sarybchik EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS); 587284555Sarybchik EFSYS_ASSERT(maskp != NULL); 588284555Sarybchik 589284555Sarybchik /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ 590284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); 591284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); 592284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); 593284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); 594284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); 595284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); 596284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); 597284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); 598284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); 599284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); 600284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); 601284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); 602284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); 603284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); 604284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); 605284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); 606284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); 607284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); 608284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT); 609284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS); 610284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS); 611284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR == 612284555Sarybchik EFX_LOOPBACK_XAUI_WS_FAR); 613284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR == 614284555Sarybchik EFX_LOOPBACK_XAUI_WS_NEAR); 615284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS); 616284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS); 617284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR == 618284555Sarybchik EFX_LOOPBACK_XFI_WS_FAR); 619284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS); 620284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT); 621284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR); 622284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR); 623284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS == 624284555Sarybchik EFX_LOOPBACK_PMA_INT_WS); 625284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS == 626284555Sarybchik EFX_LOOPBACK_SD_FEP2_WS); 627284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS == 628284555Sarybchik EFX_LOOPBACK_SD_FEP1_5_WS); 629284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS); 630284555Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS); 631284555Sarybchik 632284555Sarybchik /* Build bitmask of possible loopback types */ 633284555Sarybchik EFX_ZERO_QWORD(mask); 634284555Sarybchik 635284555Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) || 636284555Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 637284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF); 638284555Sarybchik } 639284555Sarybchik 640284555Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) || 641284555Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 642284555Sarybchik /* 643284555Sarybchik * The "MAC" grouping has historically been used by drivers to 644284555Sarybchik * mean loopbacks supported by on-chip hardware. Keep that 645284555Sarybchik * meaning here, and include on-chip PHY layer loopbacks. 646284555Sarybchik */ 647284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA); 648284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC); 649284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII); 650284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS); 651284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI); 652284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII); 653284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII); 654284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR); 655284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI); 656284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR); 657284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR); 658284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR); 659284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR); 660284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT); 661284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR); 662284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR); 663284555Sarybchik } 664284555Sarybchik 665284555Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) || 666284555Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 667284555Sarybchik /* 668284555Sarybchik * The "PHY" grouping has historically been used by drivers to 669284555Sarybchik * mean loopbacks supported by off-chip hardware. Keep that 670284555Sarybchik * meaning here. 671284555Sarybchik */ 672284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY); 673284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PHY_XS); 674284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS); 675284555Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD); 676284555Sarybchik } 677284555Sarybchik 678284555Sarybchik *maskp = mask; 679284555Sarybchik} 680284555Sarybchik 681293927Sarybchik __checkReturn efx_rc_t 682284555Sarybchikefx_mcdi_get_loopback_modes( 683284555Sarybchik __in efx_nic_t *enp) 684284555Sarybchik{ 685284555Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 686284555Sarybchik efx_mcdi_req_t req; 687342516Sarybchik EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LOOPBACK_MODES_IN_LEN, 688342516Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_LEN); 689284555Sarybchik efx_qword_t mask; 690284555Sarybchik efx_qword_t modes; 691293927Sarybchik efx_rc_t rc; 692284555Sarybchik 693284555Sarybchik req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES; 694284555Sarybchik req.emr_in_buf = payload; 695284555Sarybchik req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN; 696284555Sarybchik req.emr_out_buf = payload; 697284555Sarybchik req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN; 698284555Sarybchik 699284555Sarybchik efx_mcdi_execute(enp, &req); 700284555Sarybchik 701284555Sarybchik if (req.emr_rc != 0) { 702284555Sarybchik rc = req.emr_rc; 703284555Sarybchik goto fail1; 704284555Sarybchik } 705284555Sarybchik 706284555Sarybchik if (req.emr_out_length_used < 707284555Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST + 708284555Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) { 709284555Sarybchik rc = EMSGSIZE; 710284555Sarybchik goto fail2; 711284555Sarybchik } 712284555Sarybchik 713284555Sarybchik /* 714284555Sarybchik * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree 715284555Sarybchik * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link(). 716284555Sarybchik */ 717284555Sarybchik efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask); 718284555Sarybchik 719284555Sarybchik EFX_AND_QWORD(mask, 720284555Sarybchik *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED)); 721284555Sarybchik 722284555Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M); 723284555Sarybchik EFX_AND_QWORD(modes, mask); 724284555Sarybchik encp->enc_loopback_types[EFX_LINK_100FDX] = modes; 725284555Sarybchik 726284555Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G); 727284555Sarybchik EFX_AND_QWORD(modes, mask); 728284555Sarybchik encp->enc_loopback_types[EFX_LINK_1000FDX] = modes; 729284555Sarybchik 730284555Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G); 731284555Sarybchik EFX_AND_QWORD(modes, mask); 732284555Sarybchik encp->enc_loopback_types[EFX_LINK_10000FDX] = modes; 733284555Sarybchik 734284555Sarybchik if (req.emr_out_length_used >= 735284555Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST + 736284555Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) { 737284555Sarybchik /* Response includes 40G loopback modes */ 738284555Sarybchik modes = 739284555Sarybchik *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G); 740284555Sarybchik EFX_AND_QWORD(modes, mask); 741284555Sarybchik encp->enc_loopback_types[EFX_LINK_40000FDX] = modes; 742284555Sarybchik } 743284555Sarybchik 744284555Sarybchik EFX_ZERO_QWORD(modes); 745284555Sarybchik EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF); 746284555Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]); 747284555Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]); 748284555Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]); 749284555Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]); 750284555Sarybchik encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes; 751284555Sarybchik 752284555Sarybchik return (0); 753284555Sarybchik 754284555Sarybchikfail2: 755284555Sarybchik EFSYS_PROBE(fail2); 756284555Sarybchikfail1: 757293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 758284555Sarybchik 759284555Sarybchik return (rc); 760284555Sarybchik} 761284555Sarybchik 762284555Sarybchik#endif /* EFSYS_OPT_LOOPBACK */ 763301365Sarybchik 764301365Sarybchik __checkReturn efx_rc_t 765301365Sarybchikefx_nic_calculate_pcie_link_bandwidth( 766301365Sarybchik __in uint32_t pcie_link_width, 767301365Sarybchik __in uint32_t pcie_link_gen, 768301365Sarybchik __out uint32_t *bandwidth_mbpsp) 769301365Sarybchik{ 770301365Sarybchik uint32_t lane_bandwidth; 771301365Sarybchik uint32_t total_bandwidth; 772301365Sarybchik efx_rc_t rc; 773301365Sarybchik 774301365Sarybchik if ((pcie_link_width == 0) || (pcie_link_width > 16) || 775301365Sarybchik !ISP2(pcie_link_width)) { 776301365Sarybchik rc = EINVAL; 777301365Sarybchik goto fail1; 778301365Sarybchik } 779301365Sarybchik 780301365Sarybchik switch (pcie_link_gen) { 781301365Sarybchik case EFX_PCIE_LINK_SPEED_GEN1: 782301365Sarybchik /* 2.5 Gb/s raw bandwidth with 8b/10b encoding */ 783301365Sarybchik lane_bandwidth = 2000; 784301365Sarybchik break; 785301365Sarybchik case EFX_PCIE_LINK_SPEED_GEN2: 786301365Sarybchik /* 5.0 Gb/s raw bandwidth with 8b/10b encoding */ 787301365Sarybchik lane_bandwidth = 4000; 788301365Sarybchik break; 789301365Sarybchik case EFX_PCIE_LINK_SPEED_GEN3: 790301365Sarybchik /* 8.0 Gb/s raw bandwidth with 128b/130b encoding */ 791301365Sarybchik lane_bandwidth = 7877; 792301365Sarybchik break; 793301365Sarybchik default: 794301365Sarybchik rc = EINVAL; 795301365Sarybchik goto fail2; 796301365Sarybchik } 797301365Sarybchik 798301365Sarybchik total_bandwidth = lane_bandwidth * pcie_link_width; 799301365Sarybchik *bandwidth_mbpsp = total_bandwidth; 800301365Sarybchik 801301365Sarybchik return (0); 802301365Sarybchik 803301365Sarybchikfail2: 804301365Sarybchik EFSYS_PROBE(fail2); 805301365Sarybchikfail1: 806301365Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 807301365Sarybchik 808301365Sarybchik return (rc); 809301365Sarybchik} 810301365Sarybchik 811301365Sarybchik 812301365Sarybchik __checkReturn efx_rc_t 813301365Sarybchikefx_nic_check_pcie_link_speed( 814301365Sarybchik __in efx_nic_t *enp, 815301365Sarybchik __in uint32_t pcie_link_width, 816301365Sarybchik __in uint32_t pcie_link_gen, 817301365Sarybchik __out efx_pcie_link_performance_t *resultp) 818301365Sarybchik{ 819301365Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 820301365Sarybchik uint32_t bandwidth; 821301365Sarybchik efx_pcie_link_performance_t result; 822301365Sarybchik efx_rc_t rc; 823301365Sarybchik 824301365Sarybchik if ((encp->enc_required_pcie_bandwidth_mbps == 0) || 825301365Sarybchik (pcie_link_width == 0) || (pcie_link_width == 32) || 826301365Sarybchik (pcie_link_gen == 0)) { 827301365Sarybchik /* 828301365Sarybchik * No usable info on what is required and/or in use. In virtual 829301365Sarybchik * machines, sometimes the PCIe link width is reported as 0 or 830301365Sarybchik * 32, or the speed as 0. 831301365Sarybchik */ 832301365Sarybchik result = EFX_PCIE_LINK_PERFORMANCE_UNKNOWN_BANDWIDTH; 833301365Sarybchik goto out; 834301365Sarybchik } 835301365Sarybchik 836301365Sarybchik /* Calculate the available bandwidth in megabits per second */ 837301365Sarybchik rc = efx_nic_calculate_pcie_link_bandwidth(pcie_link_width, 838301365Sarybchik pcie_link_gen, &bandwidth); 839301365Sarybchik if (rc != 0) 840301365Sarybchik goto fail1; 841301365Sarybchik 842301365Sarybchik if (bandwidth < encp->enc_required_pcie_bandwidth_mbps) { 843301365Sarybchik result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_BANDWIDTH; 844301365Sarybchik } else if (pcie_link_gen < encp->enc_max_pcie_link_gen) { 845301365Sarybchik /* The link provides enough bandwidth but not optimal latency */ 846301365Sarybchik result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_LATENCY; 847301365Sarybchik } else { 848301365Sarybchik result = EFX_PCIE_LINK_PERFORMANCE_OPTIMAL; 849301365Sarybchik } 850301365Sarybchik 851301365Sarybchikout: 852301365Sarybchik *resultp = result; 853301365Sarybchik 854301365Sarybchik return (0); 855301365Sarybchik 856301365Sarybchikfail1: 857301365Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 858301365Sarybchik 859301365Sarybchik return (rc); 860301365Sarybchik} 861