efx_nic.c revision 342446
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 342446 2018-12-25 07:30:17Z 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 | 218293891Sarybchik EFX_FEATURE_FW_ASSISTED_TSO_V2; 219283514Sarybchik break; 220283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 221283514Sarybchik 222293887Sarybchik#if EFSYS_OPT_MEDFORD 223293887Sarybchik case EFX_FAMILY_MEDFORD: 224299517Sarybchik enp->en_enop = &__efx_nic_medford_ops; 225293887Sarybchik /* 226298955Spfg * FW_ASSISTED_TSO omitted as Medford only supports firmware 227293887Sarybchik * assisted TSO version 2, not the v1 scheme used on Huntington. 228293887Sarybchik */ 229293887Sarybchik enp->en_features = 230293887Sarybchik EFX_FEATURE_IPV6 | 231293887Sarybchik EFX_FEATURE_LINK_EVENTS | 232293887Sarybchik EFX_FEATURE_PERIODIC_MAC_STATS | 233293887Sarybchik EFX_FEATURE_MCDI | 234293887Sarybchik EFX_FEATURE_MAC_HEADER_FILTERS | 235293887Sarybchik EFX_FEATURE_MCDI_DMA | 236299917Sarybchik EFX_FEATURE_PIO_BUFFERS | 237299917Sarybchik EFX_FEATURE_FW_ASSISTED_TSO_V2; 238293887Sarybchik break; 239293887Sarybchik#endif /* EFSYS_OPT_MEDFORD */ 240293887Sarybchik 241227569Sphilip default: 242227569Sphilip rc = ENOTSUP; 243227569Sphilip goto fail2; 244227569Sphilip } 245227569Sphilip 246227569Sphilip enp->en_family = family; 247227569Sphilip enp->en_esip = esip; 248227569Sphilip enp->en_esbp = esbp; 249227569Sphilip enp->en_eslp = eslp; 250227569Sphilip 251227569Sphilip *enpp = enp; 252227569Sphilip 253227569Sphilip return (0); 254227569Sphilip 255227569Sphilipfail2: 256283514Sarybchik EFSYS_PROBE(fail2); 257227569Sphilip 258227569Sphilip enp->en_magic = 0; 259227569Sphilip 260227569Sphilip /* Free the NIC object */ 261227569Sphilip EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); 262227569Sphilip 263227569Sphilipfail1: 264291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 265227569Sphilip 266227569Sphilip return (rc); 267227569Sphilip} 268227569Sphilip 269291436Sarybchik __checkReturn efx_rc_t 270227569Sphilipefx_nic_probe( 271227569Sphilip __in efx_nic_t *enp) 272227569Sphilip{ 273299517Sarybchik const efx_nic_ops_t *enop; 274291436Sarybchik efx_rc_t rc; 275227569Sphilip 276227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 277227569Sphilip#if EFSYS_OPT_MCDI 278227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 279227569Sphilip#endif /* EFSYS_OPT_MCDI */ 280227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE)); 281227569Sphilip 282227569Sphilip enop = enp->en_enop; 283227569Sphilip if ((rc = enop->eno_probe(enp)) != 0) 284283514Sarybchik goto fail1; 285227569Sphilip 286227569Sphilip if ((rc = efx_phy_probe(enp)) != 0) 287283514Sarybchik goto fail2; 288227569Sphilip 289227569Sphilip enp->en_mod_flags |= EFX_MOD_PROBE; 290227569Sphilip 291227569Sphilip return (0); 292227569Sphilip 293283514Sarybchikfail2: 294283514Sarybchik EFSYS_PROBE(fail2); 295227569Sphilip 296227569Sphilip enop->eno_unprobe(enp); 297227569Sphilip 298227569Sphilipfail1: 299291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 300227569Sphilip 301227569Sphilip return (rc); 302227569Sphilip} 303227569Sphilip 304291436Sarybchik __checkReturn efx_rc_t 305283514Sarybchikefx_nic_set_drv_limits( 306283514Sarybchik __inout efx_nic_t *enp, 307283514Sarybchik __in efx_drv_limits_t *edlp) 308283514Sarybchik{ 309299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 310291436Sarybchik efx_rc_t rc; 311283514Sarybchik 312283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 313283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 314283514Sarybchik 315283514Sarybchik if (enop->eno_set_drv_limits != NULL) { 316283514Sarybchik if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0) 317283514Sarybchik goto fail1; 318283514Sarybchik } 319283514Sarybchik 320283514Sarybchik return (0); 321283514Sarybchik 322283514Sarybchikfail1: 323291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 324283514Sarybchik 325283514Sarybchik return (rc); 326283514Sarybchik} 327283514Sarybchik 328291436Sarybchik __checkReturn efx_rc_t 329283514Sarybchikefx_nic_get_bar_region( 330283514Sarybchik __in efx_nic_t *enp, 331283514Sarybchik __in efx_nic_region_t region, 332283514Sarybchik __out uint32_t *offsetp, 333283514Sarybchik __out size_t *sizep) 334283514Sarybchik{ 335299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 336291436Sarybchik efx_rc_t rc; 337283514Sarybchik 338283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 339283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 340283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 341283514Sarybchik 342283514Sarybchik if (enop->eno_get_bar_region == NULL) { 343283514Sarybchik rc = ENOTSUP; 344283514Sarybchik goto fail1; 345283514Sarybchik } 346283514Sarybchik if ((rc = (enop->eno_get_bar_region)(enp, 347283514Sarybchik region, offsetp, sizep)) != 0) { 348283514Sarybchik goto fail2; 349283514Sarybchik } 350283514Sarybchik 351283514Sarybchik return (0); 352283514Sarybchik 353283514Sarybchikfail2: 354283514Sarybchik EFSYS_PROBE(fail2); 355283514Sarybchik 356283514Sarybchikfail1: 357291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 358283514Sarybchik 359283514Sarybchik return (rc); 360283514Sarybchik} 361283514Sarybchik 362283514Sarybchik 363291436Sarybchik __checkReturn efx_rc_t 364283514Sarybchikefx_nic_get_vi_pool( 365283514Sarybchik __in efx_nic_t *enp, 366283514Sarybchik __out uint32_t *evq_countp, 367283514Sarybchik __out uint32_t *rxq_countp, 368283514Sarybchik __out uint32_t *txq_countp) 369283514Sarybchik{ 370299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 371283514Sarybchik efx_nic_cfg_t *encp = &enp->en_nic_cfg; 372291436Sarybchik efx_rc_t rc; 373283514Sarybchik 374283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 375283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 376283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 377283514Sarybchik 378283514Sarybchik if (enop->eno_get_vi_pool != NULL) { 379283514Sarybchik uint32_t vi_count = 0; 380283514Sarybchik 381283514Sarybchik if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0) 382283514Sarybchik goto fail1; 383283514Sarybchik 384283514Sarybchik *evq_countp = vi_count; 385283514Sarybchik *rxq_countp = vi_count; 386283514Sarybchik *txq_countp = vi_count; 387283514Sarybchik } else { 388283514Sarybchik /* Use NIC limits as default value */ 389283514Sarybchik *evq_countp = encp->enc_evq_limit; 390283514Sarybchik *rxq_countp = encp->enc_rxq_limit; 391283514Sarybchik *txq_countp = encp->enc_txq_limit; 392283514Sarybchik } 393283514Sarybchik 394283514Sarybchik return (0); 395283514Sarybchik 396283514Sarybchikfail1: 397291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 398283514Sarybchik 399283514Sarybchik return (rc); 400283514Sarybchik} 401283514Sarybchik 402283514Sarybchik 403291436Sarybchik __checkReturn efx_rc_t 404227569Sphilipefx_nic_init( 405227569Sphilip __in efx_nic_t *enp) 406227569Sphilip{ 407299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 408291436Sarybchik efx_rc_t rc; 409227569Sphilip 410227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 411227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 412227569Sphilip 413227569Sphilip if (enp->en_mod_flags & EFX_MOD_NIC) { 414227569Sphilip rc = EINVAL; 415227569Sphilip goto fail1; 416227569Sphilip } 417227569Sphilip 418227569Sphilip if ((rc = enop->eno_init(enp)) != 0) 419227569Sphilip goto fail2; 420227569Sphilip 421227569Sphilip enp->en_mod_flags |= EFX_MOD_NIC; 422227569Sphilip 423227569Sphilip return (0); 424227569Sphilip 425227569Sphilipfail2: 426227569Sphilip EFSYS_PROBE(fail2); 427227569Sphilipfail1: 428291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 429227569Sphilip 430227569Sphilip return (rc); 431227569Sphilip} 432227569Sphilip 433227569Sphilip void 434227569Sphilipefx_nic_fini( 435227569Sphilip __in efx_nic_t *enp) 436227569Sphilip{ 437299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 438227569Sphilip 439227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 440227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 441227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC); 442227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); 443227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 444227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 445227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 446227569Sphilip 447227569Sphilip enop->eno_fini(enp); 448227569Sphilip 449227569Sphilip enp->en_mod_flags &= ~EFX_MOD_NIC; 450227569Sphilip} 451227569Sphilip 452227569Sphilip void 453227569Sphilipefx_nic_unprobe( 454227569Sphilip __in efx_nic_t *enp) 455227569Sphilip{ 456299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 457227569Sphilip 458227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 459227569Sphilip#if EFSYS_OPT_MCDI 460227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 461227569Sphilip#endif /* EFSYS_OPT_MCDI */ 462227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 463227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 464227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); 465227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 466227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 467227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 468227569Sphilip 469227569Sphilip efx_phy_unprobe(enp); 470227569Sphilip 471227569Sphilip enop->eno_unprobe(enp); 472227569Sphilip 473227569Sphilip enp->en_mod_flags &= ~EFX_MOD_PROBE; 474227569Sphilip} 475227569Sphilip 476227569Sphilip void 477227569Sphilipefx_nic_destroy( 478227569Sphilip __in efx_nic_t *enp) 479227569Sphilip{ 480227569Sphilip efsys_identifier_t *esip = enp->en_esip; 481227569Sphilip 482227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 483227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); 484227569Sphilip 485310937Sarybchik enp->en_family = EFX_FAMILY_INVALID; 486227569Sphilip enp->en_esip = NULL; 487227569Sphilip enp->en_esbp = NULL; 488227569Sphilip enp->en_eslp = NULL; 489227569Sphilip 490227569Sphilip enp->en_enop = NULL; 491227569Sphilip 492227569Sphilip enp->en_magic = 0; 493227569Sphilip 494227569Sphilip /* Free the NIC object */ 495227569Sphilip EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); 496227569Sphilip} 497227569Sphilip 498291436Sarybchik __checkReturn efx_rc_t 499227569Sphilipefx_nic_reset( 500227569Sphilip __in efx_nic_t *enp) 501227569Sphilip{ 502299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 503227569Sphilip unsigned int mod_flags; 504291436Sarybchik efx_rc_t rc; 505227569Sphilip 506227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 507227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 508227569Sphilip /* 509300007Sarybchik * All modules except the MCDI, PROBE, NVRAM, VPD, MON 510293901Sarybchik * (which we do not reset here) must have been shut down or never 511293901Sarybchik * initialized. 512227569Sphilip * 513227569Sphilip * A rule of thumb here is: If the controller or MC reboots, is *any* 514227569Sphilip * state lost. If it's lost and needs reapplying, then the module 515227569Sphilip * *must* not be initialised during the reset. 516227569Sphilip */ 517227569Sphilip mod_flags = enp->en_mod_flags; 518227569Sphilip mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM | 519300007Sarybchik EFX_MOD_VPD | EFX_MOD_MON); 520227569Sphilip EFSYS_ASSERT3U(mod_flags, ==, 0); 521227569Sphilip if (mod_flags != 0) { 522227569Sphilip rc = EINVAL; 523227569Sphilip goto fail1; 524227569Sphilip } 525227569Sphilip 526227569Sphilip if ((rc = enop->eno_reset(enp)) != 0) 527227569Sphilip goto fail2; 528227569Sphilip 529227569Sphilip return (0); 530227569Sphilip 531227569Sphilipfail2: 532227569Sphilip EFSYS_PROBE(fail2); 533227569Sphilipfail1: 534291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 535227569Sphilip 536227569Sphilip return (rc); 537227569Sphilip} 538227569Sphilip 539227569Sphilip const efx_nic_cfg_t * 540227569Sphilipefx_nic_cfg_get( 541227569Sphilip __in efx_nic_t *enp) 542227569Sphilip{ 543227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 544342446Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 545227569Sphilip 546227569Sphilip return (&(enp->en_nic_cfg)); 547227569Sphilip} 548227569Sphilip 549227569Sphilip#if EFSYS_OPT_DIAG 550227569Sphilip 551291436Sarybchik __checkReturn efx_rc_t 552227569Sphilipefx_nic_register_test( 553227569Sphilip __in efx_nic_t *enp) 554227569Sphilip{ 555299517Sarybchik const efx_nic_ops_t *enop = enp->en_enop; 556291436Sarybchik efx_rc_t rc; 557227569Sphilip 558227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 559227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 560227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 561227569Sphilip 562227569Sphilip if ((rc = enop->eno_register_test(enp)) != 0) 563227569Sphilip goto fail1; 564227569Sphilip 565227569Sphilip return (0); 566227569Sphilip 567227569Sphilipfail1: 568291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 569227569Sphilip 570227569Sphilip return (rc); 571227569Sphilip} 572227569Sphilip 573227569Sphilip#endif /* EFSYS_OPT_DIAG */ 574283514Sarybchik 575283514Sarybchik#if EFSYS_OPT_LOOPBACK 576283514Sarybchik 577283514Sarybchikextern void 578283514Sarybchikefx_loopback_mask( 579283514Sarybchik __in efx_loopback_kind_t loopback_kind, 580283514Sarybchik __out efx_qword_t *maskp) 581283514Sarybchik{ 582283514Sarybchik efx_qword_t mask; 583283514Sarybchik 584283514Sarybchik EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS); 585283514Sarybchik EFSYS_ASSERT(maskp != NULL); 586283514Sarybchik 587283514Sarybchik /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ 588283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); 589283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); 590283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); 591283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); 592283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); 593283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); 594283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); 595283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); 596283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); 597283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); 598283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); 599283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); 600283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); 601283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); 602283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); 603283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); 604283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); 605283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); 606283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT); 607283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS); 608283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS); 609283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR == 610283514Sarybchik EFX_LOOPBACK_XAUI_WS_FAR); 611283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR == 612283514Sarybchik EFX_LOOPBACK_XAUI_WS_NEAR); 613283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS); 614283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS); 615283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR == 616283514Sarybchik EFX_LOOPBACK_XFI_WS_FAR); 617283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS); 618283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT); 619283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR); 620283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR); 621283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS == 622283514Sarybchik EFX_LOOPBACK_PMA_INT_WS); 623283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS == 624283514Sarybchik EFX_LOOPBACK_SD_FEP2_WS); 625283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS == 626283514Sarybchik EFX_LOOPBACK_SD_FEP1_5_WS); 627283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS); 628283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS); 629283514Sarybchik 630283514Sarybchik /* Build bitmask of possible loopback types */ 631283514Sarybchik EFX_ZERO_QWORD(mask); 632283514Sarybchik 633283514Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) || 634283514Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 635283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF); 636283514Sarybchik } 637283514Sarybchik 638283514Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) || 639283514Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 640283514Sarybchik /* 641283514Sarybchik * The "MAC" grouping has historically been used by drivers to 642283514Sarybchik * mean loopbacks supported by on-chip hardware. Keep that 643283514Sarybchik * meaning here, and include on-chip PHY layer loopbacks. 644283514Sarybchik */ 645283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA); 646283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC); 647283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII); 648283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS); 649283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI); 650283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII); 651283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII); 652283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR); 653283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI); 654283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR); 655283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR); 656283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR); 657283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR); 658283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT); 659283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR); 660283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR); 661283514Sarybchik } 662283514Sarybchik 663283514Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) || 664283514Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 665283514Sarybchik /* 666283514Sarybchik * The "PHY" grouping has historically been used by drivers to 667283514Sarybchik * mean loopbacks supported by off-chip hardware. Keep that 668283514Sarybchik * meaning here. 669283514Sarybchik */ 670283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY); 671283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PHY_XS); 672283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS); 673283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD); 674283514Sarybchik } 675283514Sarybchik 676283514Sarybchik *maskp = mask; 677283514Sarybchik} 678283514Sarybchik 679291436Sarybchik __checkReturn efx_rc_t 680283514Sarybchikefx_mcdi_get_loopback_modes( 681283514Sarybchik __in efx_nic_t *enp) 682283514Sarybchik{ 683283514Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 684283514Sarybchik efx_mcdi_req_t req; 685342445Sarybchik EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LOOPBACK_MODES_IN_LEN, 686342445Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_LEN); 687283514Sarybchik efx_qword_t mask; 688283514Sarybchik efx_qword_t modes; 689291436Sarybchik efx_rc_t rc; 690283514Sarybchik 691283514Sarybchik req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES; 692283514Sarybchik req.emr_in_buf = payload; 693283514Sarybchik req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN; 694283514Sarybchik req.emr_out_buf = payload; 695283514Sarybchik req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN; 696283514Sarybchik 697283514Sarybchik efx_mcdi_execute(enp, &req); 698283514Sarybchik 699283514Sarybchik if (req.emr_rc != 0) { 700283514Sarybchik rc = req.emr_rc; 701283514Sarybchik goto fail1; 702283514Sarybchik } 703283514Sarybchik 704283514Sarybchik if (req.emr_out_length_used < 705283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST + 706283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) { 707283514Sarybchik rc = EMSGSIZE; 708283514Sarybchik goto fail2; 709283514Sarybchik } 710283514Sarybchik 711283514Sarybchik /* 712283514Sarybchik * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree 713283514Sarybchik * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link(). 714283514Sarybchik */ 715283514Sarybchik efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask); 716283514Sarybchik 717283514Sarybchik EFX_AND_QWORD(mask, 718283514Sarybchik *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED)); 719283514Sarybchik 720283514Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M); 721283514Sarybchik EFX_AND_QWORD(modes, mask); 722283514Sarybchik encp->enc_loopback_types[EFX_LINK_100FDX] = modes; 723283514Sarybchik 724283514Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G); 725283514Sarybchik EFX_AND_QWORD(modes, mask); 726283514Sarybchik encp->enc_loopback_types[EFX_LINK_1000FDX] = modes; 727283514Sarybchik 728283514Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G); 729283514Sarybchik EFX_AND_QWORD(modes, mask); 730283514Sarybchik encp->enc_loopback_types[EFX_LINK_10000FDX] = modes; 731283514Sarybchik 732283514Sarybchik if (req.emr_out_length_used >= 733283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST + 734283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) { 735283514Sarybchik /* Response includes 40G loopback modes */ 736283514Sarybchik modes = 737283514Sarybchik *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G); 738283514Sarybchik EFX_AND_QWORD(modes, mask); 739283514Sarybchik encp->enc_loopback_types[EFX_LINK_40000FDX] = modes; 740283514Sarybchik } 741283514Sarybchik 742283514Sarybchik EFX_ZERO_QWORD(modes); 743283514Sarybchik EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF); 744283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]); 745283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]); 746283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]); 747283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]); 748283514Sarybchik encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes; 749283514Sarybchik 750283514Sarybchik return (0); 751283514Sarybchik 752283514Sarybchikfail2: 753283514Sarybchik EFSYS_PROBE(fail2); 754283514Sarybchikfail1: 755291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 756283514Sarybchik 757283514Sarybchik return (rc); 758283514Sarybchik} 759283514Sarybchik 760283514Sarybchik#endif /* EFSYS_OPT_LOOPBACK */ 761299904Sarybchik 762299904Sarybchik __checkReturn efx_rc_t 763299904Sarybchikefx_nic_calculate_pcie_link_bandwidth( 764299904Sarybchik __in uint32_t pcie_link_width, 765299904Sarybchik __in uint32_t pcie_link_gen, 766299904Sarybchik __out uint32_t *bandwidth_mbpsp) 767299904Sarybchik{ 768299904Sarybchik uint32_t lane_bandwidth; 769299904Sarybchik uint32_t total_bandwidth; 770299904Sarybchik efx_rc_t rc; 771299904Sarybchik 772299904Sarybchik if ((pcie_link_width == 0) || (pcie_link_width > 16) || 773299904Sarybchik !ISP2(pcie_link_width)) { 774299904Sarybchik rc = EINVAL; 775299904Sarybchik goto fail1; 776299904Sarybchik } 777299904Sarybchik 778299904Sarybchik switch (pcie_link_gen) { 779299904Sarybchik case EFX_PCIE_LINK_SPEED_GEN1: 780299904Sarybchik /* 2.5 Gb/s raw bandwidth with 8b/10b encoding */ 781299904Sarybchik lane_bandwidth = 2000; 782299904Sarybchik break; 783299904Sarybchik case EFX_PCIE_LINK_SPEED_GEN2: 784299904Sarybchik /* 5.0 Gb/s raw bandwidth with 8b/10b encoding */ 785299904Sarybchik lane_bandwidth = 4000; 786299904Sarybchik break; 787299904Sarybchik case EFX_PCIE_LINK_SPEED_GEN3: 788299904Sarybchik /* 8.0 Gb/s raw bandwidth with 128b/130b encoding */ 789299904Sarybchik lane_bandwidth = 7877; 790299904Sarybchik break; 791299904Sarybchik default: 792299904Sarybchik rc = EINVAL; 793299904Sarybchik goto fail2; 794299904Sarybchik } 795299904Sarybchik 796299904Sarybchik total_bandwidth = lane_bandwidth * pcie_link_width; 797299904Sarybchik *bandwidth_mbpsp = total_bandwidth; 798299904Sarybchik 799299904Sarybchik return (0); 800299904Sarybchik 801299904Sarybchikfail2: 802299904Sarybchik EFSYS_PROBE(fail2); 803299904Sarybchikfail1: 804299904Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 805299904Sarybchik 806299904Sarybchik return (rc); 807299904Sarybchik} 808299904Sarybchik 809299904Sarybchik 810299904Sarybchik __checkReturn efx_rc_t 811299904Sarybchikefx_nic_check_pcie_link_speed( 812299904Sarybchik __in efx_nic_t *enp, 813299904Sarybchik __in uint32_t pcie_link_width, 814299904Sarybchik __in uint32_t pcie_link_gen, 815299904Sarybchik __out efx_pcie_link_performance_t *resultp) 816299904Sarybchik{ 817299904Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 818299904Sarybchik uint32_t bandwidth; 819299904Sarybchik efx_pcie_link_performance_t result; 820299904Sarybchik efx_rc_t rc; 821299904Sarybchik 822299904Sarybchik if ((encp->enc_required_pcie_bandwidth_mbps == 0) || 823299904Sarybchik (pcie_link_width == 0) || (pcie_link_width == 32) || 824299904Sarybchik (pcie_link_gen == 0)) { 825299904Sarybchik /* 826299904Sarybchik * No usable info on what is required and/or in use. In virtual 827299904Sarybchik * machines, sometimes the PCIe link width is reported as 0 or 828299904Sarybchik * 32, or the speed as 0. 829299904Sarybchik */ 830299904Sarybchik result = EFX_PCIE_LINK_PERFORMANCE_UNKNOWN_BANDWIDTH; 831299904Sarybchik goto out; 832299904Sarybchik } 833299904Sarybchik 834299904Sarybchik /* Calculate the available bandwidth in megabits per second */ 835299904Sarybchik rc = efx_nic_calculate_pcie_link_bandwidth(pcie_link_width, 836299904Sarybchik pcie_link_gen, &bandwidth); 837299904Sarybchik if (rc != 0) 838299904Sarybchik goto fail1; 839299904Sarybchik 840299904Sarybchik if (bandwidth < encp->enc_required_pcie_bandwidth_mbps) { 841299904Sarybchik result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_BANDWIDTH; 842299904Sarybchik } else if (pcie_link_gen < encp->enc_max_pcie_link_gen) { 843299904Sarybchik /* The link provides enough bandwidth but not optimal latency */ 844299904Sarybchik result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_LATENCY; 845299904Sarybchik } else { 846299904Sarybchik result = EFX_PCIE_LINK_PERFORMANCE_OPTIMAL; 847299904Sarybchik } 848299904Sarybchik 849299904Sarybchikout: 850299904Sarybchik *resultp = result; 851299904Sarybchik 852299904Sarybchik return (0); 853299904Sarybchik 854299904Sarybchikfail1: 855299904Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 856299904Sarybchik 857299904Sarybchik return (rc); 858299904Sarybchik} 859