1227569Sphilip/*- 2300607Sarybchik * Copyright (c) 2007-2016 Solarflare Communications Inc. 3283514Sarybchik * All rights reserved. 4227569Sphilip * 5227569Sphilip * Redistribution and use in source and binary forms, with or without 6283514Sarybchik * modification, are permitted provided that the following conditions are met: 7227569Sphilip * 8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice, 9283514Sarybchik * this list of conditions and the following disclaimer. 10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice, 11283514Sarybchik * this list of conditions and the following disclaimer in the documentation 12283514Sarybchik * and/or other materials provided with the distribution. 13283514Sarybchik * 14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25283514Sarybchik * 26283514Sarybchik * The views and conclusions contained in the software and documentation are 27283514Sarybchik * those of the authors and should not be interpreted as representing official 28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project. 29227569Sphilip */ 30227569Sphilip 31228078Sphilip#include <sys/cdefs.h> 32228078Sphilip__FBSDID("$FreeBSD: stable/11/sys/dev/sfxge/common/efx_nic.c 342453 2018-12-25 07:37:42Z arybchik $"); 33228078Sphilip 34227569Sphilip#include "efx.h" 35227569Sphilip#include "efx_impl.h" 36227569Sphilip 37291436Sarybchik __checkReturn efx_rc_t 38227569Sphilipefx_family( 39227569Sphilip __in uint16_t venid, 40227569Sphilip __in uint16_t devid, 41227569Sphilip __out efx_family_t *efp) 42227569Sphilip{ 43283514Sarybchik if (venid == EFX_PCI_VENID_SFC) { 44283514Sarybchik switch (devid) { 45227569Sphilip#if EFSYS_OPT_SIENA 46283514Sarybchik case EFX_PCI_DEVID_SIENA_F1_UNINIT: 47283514Sarybchik /* 48283514Sarybchik * Hardware default for PF0 of uninitialised Siena. 49283514Sarybchik * manftest must be able to cope with this device id. 50283514Sarybchik */ 51283514Sarybchik *efp = EFX_FAMILY_SIENA; 52283514Sarybchik return (0); 53283514Sarybchik 54283514Sarybchik case EFX_PCI_DEVID_BETHPAGE: 55283514Sarybchik case EFX_PCI_DEVID_SIENA: 56283514Sarybchik *efp = EFX_FAMILY_SIENA; 57283514Sarybchik return (0); 58293731Sarybchik#endif /* EFSYS_OPT_SIENA */ 59283514Sarybchik 60283514Sarybchik#if EFSYS_OPT_HUNTINGTON 61283514Sarybchik case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT: 62283514Sarybchik /* 63283514Sarybchik * Hardware default for PF0 of uninitialised Huntington. 64283514Sarybchik * manftest must be able to cope with this device id. 65283514Sarybchik */ 66283514Sarybchik *efp = EFX_FAMILY_HUNTINGTON; 67283514Sarybchik return (0); 68283514Sarybchik 69283514Sarybchik case EFX_PCI_DEVID_FARMINGDALE: 70283514Sarybchik case EFX_PCI_DEVID_GREENPORT: 71283514Sarybchik *efp = EFX_FAMILY_HUNTINGTON; 72283514Sarybchik return (0); 73283514Sarybchik 74283514Sarybchik case EFX_PCI_DEVID_FARMINGDALE_VF: 75283514Sarybchik case EFX_PCI_DEVID_GREENPORT_VF: 76283514Sarybchik *efp = EFX_FAMILY_HUNTINGTON; 77283514Sarybchik return (0); 78293731Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 79293731Sarybchik 80293731Sarybchik#if EFSYS_OPT_MEDFORD 81293731Sarybchik case EFX_PCI_DEVID_MEDFORD_PF_UNINIT: 82293731Sarybchik /* 83293731Sarybchik * Hardware default for PF0 of uninitialised Medford. 84293731Sarybchik * manftest must be able to cope with this device id. 85293731Sarybchik */ 86293731Sarybchik *efp = EFX_FAMILY_MEDFORD; 87293731Sarybchik return (0); 88293731Sarybchik 89293731Sarybchik case EFX_PCI_DEVID_MEDFORD: 90293731Sarybchik *efp = EFX_FAMILY_MEDFORD; 91293731Sarybchik return (0); 92293731Sarybchik 93293731Sarybchik case EFX_PCI_DEVID_MEDFORD_VF: 94293731Sarybchik *efp = EFX_FAMILY_MEDFORD; 95293731Sarybchik return (0); 96293731Sarybchik#endif /* EFSYS_OPT_MEDFORD */ 97293731Sarybchik 98299320Sarybchik case EFX_PCI_DEVID_FALCON: /* Obsolete, not supported */ 99283514Sarybchik default: 100283514Sarybchik break; 101283514Sarybchik } 102227569Sphilip } 103283514Sarybchik 104283514Sarybchik *efp = EFX_FAMILY_INVALID; 105227569Sphilip return (ENOTSUP); 106227569Sphilip} 107227569Sphilip 108227569Sphilip#if EFSYS_OPT_SIENA 109227569Sphilip 110299517Sarybchikstatic const efx_nic_ops_t __efx_nic_siena_ops = { 111227569Sphilip siena_nic_probe, /* eno_probe */ 112293887Sarybchik NULL, /* eno_board_cfg */ 113283514Sarybchik NULL, /* eno_set_drv_limits */ 114227569Sphilip siena_nic_reset, /* eno_reset */ 115227569Sphilip siena_nic_init, /* eno_init */ 116283514Sarybchik NULL, /* eno_get_vi_pool */ 117283514Sarybchik 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 127283514Sarybchik#if EFSYS_OPT_HUNTINGTON 128283514Sarybchik 129299517Sarybchikstatic const efx_nic_ops_t __efx_nic_hunt_ops = { 130293805Sarybchik ef10_nic_probe, /* eno_probe */ 131293887Sarybchik hunt_board_cfg, /* eno_board_cfg */ 132293805Sarybchik ef10_nic_set_drv_limits, /* eno_set_drv_limits */ 133293805Sarybchik ef10_nic_reset, /* eno_reset */ 134293805Sarybchik ef10_nic_init, /* eno_init */ 135293805Sarybchik ef10_nic_get_vi_pool, /* eno_get_vi_pool */ 136293805Sarybchik ef10_nic_get_bar_region, /* eno_get_bar_region */ 137283514Sarybchik#if EFSYS_OPT_DIAG 138293805Sarybchik ef10_nic_register_test, /* eno_register_test */ 139283514Sarybchik#endif /* EFSYS_OPT_DIAG */ 140293805Sarybchik ef10_nic_fini, /* eno_fini */ 141293805Sarybchik ef10_nic_unprobe, /* eno_unprobe */ 142283514Sarybchik}; 143283514Sarybchik 144283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 145283514Sarybchik 146293887Sarybchik#if EFSYS_OPT_MEDFORD 147293887Sarybchik 148299517Sarybchikstatic const efx_nic_ops_t __efx_nic_medford_ops = { 149293887Sarybchik ef10_nic_probe, /* eno_probe */ 150293887Sarybchik medford_board_cfg, /* eno_board_cfg */ 151293887Sarybchik ef10_nic_set_drv_limits, /* eno_set_drv_limits */ 152293887Sarybchik ef10_nic_reset, /* eno_reset */ 153293887Sarybchik ef10_nic_init, /* eno_init */ 154293887Sarybchik ef10_nic_get_vi_pool, /* eno_get_vi_pool */ 155293887Sarybchik ef10_nic_get_bar_region, /* eno_get_bar_region */ 156293887Sarybchik#if EFSYS_OPT_DIAG 157293887Sarybchik ef10_nic_register_test, /* eno_register_test */ 158293887Sarybchik#endif /* EFSYS_OPT_DIAG */ 159293887Sarybchik ef10_nic_fini, /* eno_fini */ 160293887Sarybchik ef10_nic_unprobe, /* eno_unprobe */ 161293887Sarybchik}; 162293887Sarybchik 163293887Sarybchik#endif /* EFSYS_OPT_MEDFORD */ 164293887Sarybchik 165293887Sarybchik 166291436Sarybchik __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; 175291436Sarybchik 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: 193299517Sarybchik enp->en_enop = &__efx_nic_siena_ops; 194279141Sarybchik enp->en_features = 195279141Sarybchik EFX_FEATURE_IPV6 | 196227569Sphilip EFX_FEATURE_LFSR_HASH_INSERT | 197279141Sarybchik EFX_FEATURE_LINK_EVENTS | 198279141Sarybchik EFX_FEATURE_PERIODIC_MAC_STATS | 199279141Sarybchik EFX_FEATURE_MCDI | 200278839Sarybchik EFX_FEATURE_LOOKAHEAD_SPLIT | 201283514Sarybchik EFX_FEATURE_MAC_HEADER_FILTERS | 202283514Sarybchik EFX_FEATURE_TX_SRC_FILTERS; 203227569Sphilip break; 204227569Sphilip#endif /* EFSYS_OPT_SIENA */ 205227569Sphilip 206283514Sarybchik#if EFSYS_OPT_HUNTINGTON 207283514Sarybchik case EFX_FAMILY_HUNTINGTON: 208299517Sarybchik enp->en_enop = &__efx_nic_hunt_ops; 209283514Sarybchik enp->en_features = 210283514Sarybchik EFX_FEATURE_IPV6 | 211283514Sarybchik EFX_FEATURE_LINK_EVENTS | 212283514Sarybchik EFX_FEATURE_PERIODIC_MAC_STATS | 213283514Sarybchik EFX_FEATURE_MCDI | 214283514Sarybchik EFX_FEATURE_MAC_HEADER_FILTERS | 215283514Sarybchik EFX_FEATURE_MCDI_DMA | 216283514Sarybchik EFX_FEATURE_PIO_BUFFERS | 217293891Sarybchik EFX_FEATURE_FW_ASSISTED_TSO | 218342453Sarybchik EFX_FEATURE_FW_ASSISTED_TSO_V2 | 219342453Sarybchik EFX_FEATURE_TXQ_CKSUM_OP_DESC; 220283514Sarybchik break; 221283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 222283514Sarybchik 223293887Sarybchik#if EFSYS_OPT_MEDFORD 224293887Sarybchik case EFX_FAMILY_MEDFORD: 225299517Sarybchik enp->en_enop = &__efx_nic_medford_ops; 226293887Sarybchik /* 227298955Spfg * FW_ASSISTED_TSO omitted as Medford only supports firmware 228293887Sarybchik * assisted TSO version 2, not the v1 scheme used on Huntington. 229293887Sarybchik */ 230293887Sarybchik enp->en_features = 231293887Sarybchik EFX_FEATURE_IPV6 | 232293887Sarybchik EFX_FEATURE_LINK_EVENTS | 233293887Sarybchik EFX_FEATURE_PERIODIC_MAC_STATS | 234293887Sarybchik EFX_FEATURE_MCDI | 235293887Sarybchik EFX_FEATURE_MAC_HEADER_FILTERS | 236293887Sarybchik EFX_FEATURE_MCDI_DMA | 237299917Sarybchik EFX_FEATURE_PIO_BUFFERS | 238342453Sarybchik EFX_FEATURE_FW_ASSISTED_TSO_V2 | 239342453Sarybchik EFX_FEATURE_TXQ_CKSUM_OP_DESC; 240293887Sarybchik break; 241293887Sarybchik#endif /* EFSYS_OPT_MEDFORD */ 242293887Sarybchik 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: 258283514Sarybchik 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: 266291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 267227569Sphilip 268227569Sphilip return (rc); 269227569Sphilip} 270227569Sphilip 271291436Sarybchik __checkReturn efx_rc_t 272227569Sphilipefx_nic_probe( 273227569Sphilip __in efx_nic_t *enp) 274227569Sphilip{ 275299517Sarybchik const efx_nic_ops_t *enop; 276291436Sarybchik 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) 286283514Sarybchik goto fail1; 287227569Sphilip 288227569Sphilip if ((rc = efx_phy_probe(enp)) != 0) 289283514Sarybchik goto fail2; 290227569Sphilip 291227569Sphilip enp->en_mod_flags |= EFX_MOD_PROBE; 292227569Sphilip 293227569Sphilip return (0); 294227569Sphilip 295283514Sarybchikfail2: 296283514Sarybchik EFSYS_PROBE(fail2); 297227569Sphilip 298227569Sphilip enop->eno_unprobe(enp); 299227569Sphilip 300227569Sphilipfail1: 301291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 302227569Sphilip 303227569Sphilip return (rc); 304227569Sphilip} 305227569Sphilip 306291436Sarybchik __checkReturn efx_rc_t 307283514Sarybchikefx_nic_set_drv_limits( 308283514Sarybchik __inout efx_nic_t *enp, 309283514Sarybchik __in efx_drv_limits_t *edlp) 310283514Sarybchik{ 311299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 312291436Sarybchik efx_rc_t rc; 313283514Sarybchik 314283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 315283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 316283514Sarybchik 317283514Sarybchik if (enop->eno_set_drv_limits != NULL) { 318283514Sarybchik if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0) 319283514Sarybchik goto fail1; 320283514Sarybchik } 321283514Sarybchik 322283514Sarybchik return (0); 323283514Sarybchik 324283514Sarybchikfail1: 325291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 326283514Sarybchik 327283514Sarybchik return (rc); 328283514Sarybchik} 329283514Sarybchik 330291436Sarybchik __checkReturn efx_rc_t 331283514Sarybchikefx_nic_get_bar_region( 332283514Sarybchik __in efx_nic_t *enp, 333283514Sarybchik __in efx_nic_region_t region, 334283514Sarybchik __out uint32_t *offsetp, 335283514Sarybchik __out size_t *sizep) 336283514Sarybchik{ 337299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 338291436Sarybchik efx_rc_t rc; 339283514Sarybchik 340283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 341283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 342283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 343283514Sarybchik 344283514Sarybchik if (enop->eno_get_bar_region == NULL) { 345283514Sarybchik rc = ENOTSUP; 346283514Sarybchik goto fail1; 347283514Sarybchik } 348283514Sarybchik if ((rc = (enop->eno_get_bar_region)(enp, 349283514Sarybchik region, offsetp, sizep)) != 0) { 350283514Sarybchik goto fail2; 351283514Sarybchik } 352283514Sarybchik 353283514Sarybchik return (0); 354283514Sarybchik 355283514Sarybchikfail2: 356283514Sarybchik EFSYS_PROBE(fail2); 357283514Sarybchik 358283514Sarybchikfail1: 359291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 360283514Sarybchik 361283514Sarybchik return (rc); 362283514Sarybchik} 363283514Sarybchik 364283514Sarybchik 365291436Sarybchik __checkReturn efx_rc_t 366283514Sarybchikefx_nic_get_vi_pool( 367283514Sarybchik __in efx_nic_t *enp, 368283514Sarybchik __out uint32_t *evq_countp, 369283514Sarybchik __out uint32_t *rxq_countp, 370283514Sarybchik __out uint32_t *txq_countp) 371283514Sarybchik{ 372299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 373283514Sarybchik efx_nic_cfg_t *encp = &enp->en_nic_cfg; 374291436Sarybchik efx_rc_t rc; 375283514Sarybchik 376283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 377283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 378283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 379283514Sarybchik 380283514Sarybchik if (enop->eno_get_vi_pool != NULL) { 381283514Sarybchik uint32_t vi_count = 0; 382283514Sarybchik 383283514Sarybchik if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0) 384283514Sarybchik goto fail1; 385283514Sarybchik 386283514Sarybchik *evq_countp = vi_count; 387283514Sarybchik *rxq_countp = vi_count; 388283514Sarybchik *txq_countp = vi_count; 389283514Sarybchik } else { 390283514Sarybchik /* Use NIC limits as default value */ 391283514Sarybchik *evq_countp = encp->enc_evq_limit; 392283514Sarybchik *rxq_countp = encp->enc_rxq_limit; 393283514Sarybchik *txq_countp = encp->enc_txq_limit; 394283514Sarybchik } 395283514Sarybchik 396283514Sarybchik return (0); 397283514Sarybchik 398283514Sarybchikfail1: 399291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 400283514Sarybchik 401283514Sarybchik return (rc); 402283514Sarybchik} 403283514Sarybchik 404283514Sarybchik 405291436Sarybchik __checkReturn efx_rc_t 406227569Sphilipefx_nic_init( 407227569Sphilip __in efx_nic_t *enp) 408227569Sphilip{ 409299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 410291436Sarybchik 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: 430291436Sarybchik 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{ 439299517Sarybchik 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{ 458299517Sarybchik 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 487310937Sarybchik 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 500291436Sarybchik __checkReturn efx_rc_t 501227569Sphilipefx_nic_reset( 502227569Sphilip __in efx_nic_t *enp) 503227569Sphilip{ 504299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 505227569Sphilip unsigned int mod_flags; 506291436Sarybchik 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 /* 511300007Sarybchik * All modules except the MCDI, PROBE, NVRAM, VPD, MON 512293901Sarybchik * (which we do not reset here) must have been shut down or never 513293901Sarybchik * 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 | 521300007Sarybchik 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: 536291436Sarybchik 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); 546342446Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 547227569Sphilip 548227569Sphilip return (&(enp->en_nic_cfg)); 549227569Sphilip} 550227569Sphilip 551227569Sphilip#if EFSYS_OPT_DIAG 552227569Sphilip 553291436Sarybchik __checkReturn efx_rc_t 554227569Sphilipefx_nic_register_test( 555227569Sphilip __in efx_nic_t *enp) 556227569Sphilip{ 557299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 558291436Sarybchik 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: 570291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 571227569Sphilip 572227569Sphilip return (rc); 573227569Sphilip} 574227569Sphilip 575227569Sphilip#endif /* EFSYS_OPT_DIAG */ 576283514Sarybchik 577283514Sarybchik#if EFSYS_OPT_LOOPBACK 578283514Sarybchik 579283514Sarybchikextern void 580283514Sarybchikefx_loopback_mask( 581283514Sarybchik __in efx_loopback_kind_t loopback_kind, 582283514Sarybchik __out efx_qword_t *maskp) 583283514Sarybchik{ 584283514Sarybchik efx_qword_t mask; 585283514Sarybchik 586283514Sarybchik EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS); 587283514Sarybchik EFSYS_ASSERT(maskp != NULL); 588283514Sarybchik 589283514Sarybchik /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ 590283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); 591283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); 592283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); 593283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); 594283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); 595283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); 596283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); 597283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); 598283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); 599283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); 600283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); 601283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); 602283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); 603283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); 604283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); 605283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); 606283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); 607283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); 608283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT); 609283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS); 610283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS); 611283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR == 612283514Sarybchik EFX_LOOPBACK_XAUI_WS_FAR); 613283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR == 614283514Sarybchik EFX_LOOPBACK_XAUI_WS_NEAR); 615283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS); 616283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS); 617283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR == 618283514Sarybchik EFX_LOOPBACK_XFI_WS_FAR); 619283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS); 620283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT); 621283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR); 622283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR); 623283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS == 624283514Sarybchik EFX_LOOPBACK_PMA_INT_WS); 625283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS == 626283514Sarybchik EFX_LOOPBACK_SD_FEP2_WS); 627283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS == 628283514Sarybchik EFX_LOOPBACK_SD_FEP1_5_WS); 629283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS); 630283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS); 631283514Sarybchik 632283514Sarybchik /* Build bitmask of possible loopback types */ 633283514Sarybchik EFX_ZERO_QWORD(mask); 634283514Sarybchik 635283514Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) || 636283514Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 637283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF); 638283514Sarybchik } 639283514Sarybchik 640283514Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) || 641283514Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 642283514Sarybchik /* 643283514Sarybchik * The "MAC" grouping has historically been used by drivers to 644283514Sarybchik * mean loopbacks supported by on-chip hardware. Keep that 645283514Sarybchik * meaning here, and include on-chip PHY layer loopbacks. 646283514Sarybchik */ 647283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA); 648283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC); 649283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII); 650283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS); 651283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI); 652283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII); 653283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII); 654283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR); 655283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI); 656283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR); 657283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR); 658283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR); 659283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR); 660283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT); 661283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR); 662283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR); 663283514Sarybchik } 664283514Sarybchik 665283514Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) || 666283514Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 667283514Sarybchik /* 668283514Sarybchik * The "PHY" grouping has historically been used by drivers to 669283514Sarybchik * mean loopbacks supported by off-chip hardware. Keep that 670283514Sarybchik * meaning here. 671283514Sarybchik */ 672283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY); 673283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PHY_XS); 674283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS); 675283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD); 676283514Sarybchik } 677283514Sarybchik 678283514Sarybchik *maskp = mask; 679283514Sarybchik} 680283514Sarybchik 681291436Sarybchik __checkReturn efx_rc_t 682283514Sarybchikefx_mcdi_get_loopback_modes( 683283514Sarybchik __in efx_nic_t *enp) 684283514Sarybchik{ 685283514Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 686283514Sarybchik efx_mcdi_req_t req; 687342445Sarybchik EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LOOPBACK_MODES_IN_LEN, 688342445Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_LEN); 689283514Sarybchik efx_qword_t mask; 690283514Sarybchik efx_qword_t modes; 691291436Sarybchik efx_rc_t rc; 692283514Sarybchik 693283514Sarybchik req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES; 694283514Sarybchik req.emr_in_buf = payload; 695283514Sarybchik req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN; 696283514Sarybchik req.emr_out_buf = payload; 697283514Sarybchik req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN; 698283514Sarybchik 699283514Sarybchik efx_mcdi_execute(enp, &req); 700283514Sarybchik 701283514Sarybchik if (req.emr_rc != 0) { 702283514Sarybchik rc = req.emr_rc; 703283514Sarybchik goto fail1; 704283514Sarybchik } 705283514Sarybchik 706283514Sarybchik if (req.emr_out_length_used < 707283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST + 708283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) { 709283514Sarybchik rc = EMSGSIZE; 710283514Sarybchik goto fail2; 711283514Sarybchik } 712283514Sarybchik 713283514Sarybchik /* 714283514Sarybchik * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree 715283514Sarybchik * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link(). 716283514Sarybchik */ 717283514Sarybchik efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask); 718283514Sarybchik 719283514Sarybchik EFX_AND_QWORD(mask, 720283514Sarybchik *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED)); 721283514Sarybchik 722283514Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M); 723283514Sarybchik EFX_AND_QWORD(modes, mask); 724283514Sarybchik encp->enc_loopback_types[EFX_LINK_100FDX] = modes; 725283514Sarybchik 726283514Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G); 727283514Sarybchik EFX_AND_QWORD(modes, mask); 728283514Sarybchik encp->enc_loopback_types[EFX_LINK_1000FDX] = modes; 729283514Sarybchik 730283514Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G); 731283514Sarybchik EFX_AND_QWORD(modes, mask); 732283514Sarybchik encp->enc_loopback_types[EFX_LINK_10000FDX] = modes; 733283514Sarybchik 734283514Sarybchik if (req.emr_out_length_used >= 735283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST + 736283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) { 737283514Sarybchik /* Response includes 40G loopback modes */ 738283514Sarybchik modes = 739283514Sarybchik *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G); 740283514Sarybchik EFX_AND_QWORD(modes, mask); 741283514Sarybchik encp->enc_loopback_types[EFX_LINK_40000FDX] = modes; 742283514Sarybchik } 743283514Sarybchik 744283514Sarybchik EFX_ZERO_QWORD(modes); 745283514Sarybchik EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF); 746283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]); 747283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]); 748283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]); 749283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]); 750283514Sarybchik encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes; 751283514Sarybchik 752283514Sarybchik return (0); 753283514Sarybchik 754283514Sarybchikfail2: 755283514Sarybchik EFSYS_PROBE(fail2); 756283514Sarybchikfail1: 757291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 758283514Sarybchik 759283514Sarybchik return (rc); 760283514Sarybchik} 761283514Sarybchik 762283514Sarybchik#endif /* EFSYS_OPT_LOOPBACK */ 763299904Sarybchik 764299904Sarybchik __checkReturn efx_rc_t 765299904Sarybchikefx_nic_calculate_pcie_link_bandwidth( 766299904Sarybchik __in uint32_t pcie_link_width, 767299904Sarybchik __in uint32_t pcie_link_gen, 768299904Sarybchik __out uint32_t *bandwidth_mbpsp) 769299904Sarybchik{ 770299904Sarybchik uint32_t lane_bandwidth; 771299904Sarybchik uint32_t total_bandwidth; 772299904Sarybchik efx_rc_t rc; 773299904Sarybchik 774299904Sarybchik if ((pcie_link_width == 0) || (pcie_link_width > 16) || 775299904Sarybchik !ISP2(pcie_link_width)) { 776299904Sarybchik rc = EINVAL; 777299904Sarybchik goto fail1; 778299904Sarybchik } 779299904Sarybchik 780299904Sarybchik switch (pcie_link_gen) { 781299904Sarybchik case EFX_PCIE_LINK_SPEED_GEN1: 782299904Sarybchik /* 2.5 Gb/s raw bandwidth with 8b/10b encoding */ 783299904Sarybchik lane_bandwidth = 2000; 784299904Sarybchik break; 785299904Sarybchik case EFX_PCIE_LINK_SPEED_GEN2: 786299904Sarybchik /* 5.0 Gb/s raw bandwidth with 8b/10b encoding */ 787299904Sarybchik lane_bandwidth = 4000; 788299904Sarybchik break; 789299904Sarybchik case EFX_PCIE_LINK_SPEED_GEN3: 790299904Sarybchik /* 8.0 Gb/s raw bandwidth with 128b/130b encoding */ 791299904Sarybchik lane_bandwidth = 7877; 792299904Sarybchik break; 793299904Sarybchik default: 794299904Sarybchik rc = EINVAL; 795299904Sarybchik goto fail2; 796299904Sarybchik } 797299904Sarybchik 798299904Sarybchik total_bandwidth = lane_bandwidth * pcie_link_width; 799299904Sarybchik *bandwidth_mbpsp = total_bandwidth; 800299904Sarybchik 801299904Sarybchik return (0); 802299904Sarybchik 803299904Sarybchikfail2: 804299904Sarybchik EFSYS_PROBE(fail2); 805299904Sarybchikfail1: 806299904Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 807299904Sarybchik 808299904Sarybchik return (rc); 809299904Sarybchik} 810299904Sarybchik 811299904Sarybchik 812299904Sarybchik __checkReturn efx_rc_t 813299904Sarybchikefx_nic_check_pcie_link_speed( 814299904Sarybchik __in efx_nic_t *enp, 815299904Sarybchik __in uint32_t pcie_link_width, 816299904Sarybchik __in uint32_t pcie_link_gen, 817299904Sarybchik __out efx_pcie_link_performance_t *resultp) 818299904Sarybchik{ 819299904Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 820299904Sarybchik uint32_t bandwidth; 821299904Sarybchik efx_pcie_link_performance_t result; 822299904Sarybchik efx_rc_t rc; 823299904Sarybchik 824299904Sarybchik if ((encp->enc_required_pcie_bandwidth_mbps == 0) || 825299904Sarybchik (pcie_link_width == 0) || (pcie_link_width == 32) || 826299904Sarybchik (pcie_link_gen == 0)) { 827299904Sarybchik /* 828299904Sarybchik * No usable info on what is required and/or in use. In virtual 829299904Sarybchik * machines, sometimes the PCIe link width is reported as 0 or 830299904Sarybchik * 32, or the speed as 0. 831299904Sarybchik */ 832299904Sarybchik result = EFX_PCIE_LINK_PERFORMANCE_UNKNOWN_BANDWIDTH; 833299904Sarybchik goto out; 834299904Sarybchik } 835299904Sarybchik 836299904Sarybchik /* Calculate the available bandwidth in megabits per second */ 837299904Sarybchik rc = efx_nic_calculate_pcie_link_bandwidth(pcie_link_width, 838299904Sarybchik pcie_link_gen, &bandwidth); 839299904Sarybchik if (rc != 0) 840299904Sarybchik goto fail1; 841299904Sarybchik 842299904Sarybchik if (bandwidth < encp->enc_required_pcie_bandwidth_mbps) { 843299904Sarybchik result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_BANDWIDTH; 844299904Sarybchik } else if (pcie_link_gen < encp->enc_max_pcie_link_gen) { 845299904Sarybchik /* The link provides enough bandwidth but not optimal latency */ 846299904Sarybchik result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_LATENCY; 847299904Sarybchik } else { 848299904Sarybchik result = EFX_PCIE_LINK_PERFORMANCE_OPTIMAL; 849299904Sarybchik } 850299904Sarybchik 851299904Sarybchikout: 852299904Sarybchik *resultp = result; 853299904Sarybchik 854299904Sarybchik return (0); 855299904Sarybchik 856299904Sarybchikfail1: 857299904Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 858299904Sarybchik 859299904Sarybchik return (rc); 860299904Sarybchik} 861