efx_nic.c revision 299517
1206084Srdivacky/*- 2206084Srdivacky * Copyright (c) 2007-2015 Solarflare Communications Inc. 3206084Srdivacky * All rights reserved. 4206084Srdivacky * 5206084Srdivacky * Redistribution and use in source and binary forms, with or without 6206084Srdivacky * modification, are permitted provided that the following conditions are met: 7206084Srdivacky * 8206084Srdivacky * 1. Redistributions of source code must retain the above copyright notice, 9206084Srdivacky * this list of conditions and the following disclaimer. 10206084Srdivacky * 2. Redistributions in binary form must reproduce the above copyright notice, 11206084Srdivacky * this list of conditions and the following disclaimer in the documentation 12206084Srdivacky * and/or other materials provided with the distribution. 13206084Srdivacky * 14206084Srdivacky * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15206084Srdivacky * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16206084Srdivacky * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17206084Srdivacky * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18206084Srdivacky * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19206084Srdivacky * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20206084Srdivacky * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21206084Srdivacky * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22206084Srdivacky * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23204793Srdivacky * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24204793Srdivacky * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25204793Srdivacky * 26204793Srdivacky * The views and conclusions contained in the software and documentation are 27204793Srdivacky * those of the authors and should not be interpreted as representing official 28204793Srdivacky * policies, either expressed or implied, of the FreeBSD Project. 29204793Srdivacky */ 30204793Srdivacky 31204793Srdivacky#include <sys/cdefs.h> 32204793Srdivacky__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/efx_nic.c 299517 2016-05-12 06:19:06Z arybchik $"); 33204793Srdivacky 34204793Srdivacky#include "efx.h" 35204793Srdivacky#include "efx_impl.h" 36204793Srdivacky 37204793Srdivacky __checkReturn efx_rc_t 38204793Srdivackyefx_family( 39204793Srdivacky __in uint16_t venid, 40204793Srdivacky __in uint16_t devid, 41204793Srdivacky __out efx_family_t *efp) 42204793Srdivacky{ 43204793Srdivacky if (venid == EFX_PCI_VENID_SFC) { 44204793Srdivacky switch (devid) { 45204793Srdivacky#if EFSYS_OPT_SIENA 46204793Srdivacky case EFX_PCI_DEVID_SIENA_F1_UNINIT: 47204793Srdivacky /* 48204962Srdivacky * Hardware default for PF0 of uninitialised Siena. 49204793Srdivacky * manftest must be able to cope with this device id. 50204793Srdivacky */ 51204793Srdivacky *efp = EFX_FAMILY_SIENA; 52204793Srdivacky return (0); 53204793Srdivacky 54204793Srdivacky case EFX_PCI_DEVID_BETHPAGE: 55204793Srdivacky case EFX_PCI_DEVID_SIENA: 56204793Srdivacky *efp = EFX_FAMILY_SIENA; 57204793Srdivacky return (0); 58204793Srdivacky#endif /* EFSYS_OPT_SIENA */ 59204793Srdivacky 60234353Sdim#if EFSYS_OPT_HUNTINGTON 61234353Sdim case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT: 62234353Sdim /* 63204793Srdivacky * Hardware default for PF0 of uninitialised Huntington. 64234353Sdim * manftest must be able to cope with this device id. 65234353Sdim */ 66234353Sdim *efp = EFX_FAMILY_HUNTINGTON; 67234353Sdim return (0); 68234353Sdim 69234353Sdim case EFX_PCI_DEVID_FARMINGDALE: 70234353Sdim case EFX_PCI_DEVID_GREENPORT: 71234353Sdim *efp = EFX_FAMILY_HUNTINGTON; 72234353Sdim return (0); 73234353Sdim 74234353Sdim case EFX_PCI_DEVID_FARMINGDALE_VF: 75234353Sdim case EFX_PCI_DEVID_GREENPORT_VF: 76234353Sdim *efp = EFX_FAMILY_HUNTINGTON; 77234353Sdim return (0); 78204793Srdivacky#endif /* EFSYS_OPT_HUNTINGTON */ 79234353Sdim 80234353Sdim#if EFSYS_OPT_MEDFORD 81234353Sdim case EFX_PCI_DEVID_MEDFORD_PF_UNINIT: 82234353Sdim /* 83204793Srdivacky * Hardware default for PF0 of uninitialised Medford. 84234353Sdim * manftest must be able to cope with this device id. 85234353Sdim */ 86234353Sdim *efp = EFX_FAMILY_MEDFORD; 87234353Sdim return (0); 88204793Srdivacky 89206084Srdivacky case EFX_PCI_DEVID_MEDFORD: 90204793Srdivacky *efp = EFX_FAMILY_MEDFORD; 91204793Srdivacky return (0); 92204793Srdivacky 93204793Srdivacky case EFX_PCI_DEVID_MEDFORD_VF: 94204793Srdivacky *efp = EFX_FAMILY_MEDFORD; 95204793Srdivacky return (0); 96206084Srdivacky#endif /* EFSYS_OPT_MEDFORD */ 97204793Srdivacky 98204793Srdivacky case EFX_PCI_DEVID_FALCON: /* Obsolete, not supported */ 99204793Srdivacky default: 100204793Srdivacky break; 101204793Srdivacky } 102204793Srdivacky } 103206084Srdivacky 104204793Srdivacky *efp = EFX_FAMILY_INVALID; 105204793Srdivacky return (ENOTSUP); 106204793Srdivacky} 107204793Srdivacky 108204793Srdivacky 109204793Srdivacky#define EFX_BIU_MAGIC0 0x01234567 110234353Sdim#define EFX_BIU_MAGIC1 0xfedcba98 111234353Sdim 112234353Sdim __checkReturn efx_rc_t 113234353Sdimefx_nic_biu_test( 114204793Srdivacky __in efx_nic_t *enp) 115204962Srdivacky{ 116206084Srdivacky efx_oword_t oword; 117204962Srdivacky efx_rc_t rc; 118204962Srdivacky 119206084Srdivacky /* 120204962Srdivacky * Write magic values to scratch registers 0 and 1, then 121204962Srdivacky * verify that the values were written correctly. Interleave 122206084Srdivacky * the accesses to ensure that the BIU is not just reading 123204962Srdivacky * back the cached value that was last written. 124204962Srdivacky */ 125204962Srdivacky EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); 126204962Srdivacky EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); 127204962Srdivacky 128204962Srdivacky EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); 129234353Sdim EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); 130234353Sdim 131234353Sdim EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); 132234353Sdim if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { 133204962Srdivacky rc = EIO; 134234353Sdim goto fail1; 135234353Sdim } 136234353Sdim 137234353Sdim EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); 138234353Sdim if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { 139204962Srdivacky rc = EIO; 140206084Srdivacky goto fail2; 141204962Srdivacky } 142204962Srdivacky 143204962Srdivacky /* 144204962Srdivacky * Perform the same test, with the values swapped. This 145204962Srdivacky * ensures that subsequent tests don't start with the correct 146204962Srdivacky * values already written into the scratch registers. 147206084Srdivacky */ 148204962Srdivacky EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); 149204962Srdivacky EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); 150204962Srdivacky 151204962Srdivacky EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); 152204962Srdivacky EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); 153206084Srdivacky 154204962Srdivacky EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); 155204962Srdivacky if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { 156204962Srdivacky rc = EIO; 157204962Srdivacky goto fail3; 158204962Srdivacky } 159206084Srdivacky 160204962Srdivacky EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); 161204962Srdivacky if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { 162204962Srdivacky rc = EIO; 163204962Srdivacky goto fail4; 164204962Srdivacky } 165206084Srdivacky 166204962Srdivacky return (0); 167204962Srdivacky 168204962Srdivackyfail4: 169204962Srdivacky EFSYS_PROBE(fail4); 170204962Srdivackyfail3: 171206084Srdivacky EFSYS_PROBE(fail3); 172204962Srdivackyfail2: 173204962Srdivacky EFSYS_PROBE(fail2); 174204962Srdivackyfail1: 175204962Srdivacky EFSYS_PROBE1(fail1, efx_rc_t, rc); 176204962Srdivacky 177206084Srdivacky return (rc); 178204962Srdivacky} 179204962Srdivacky 180204962Srdivacky#if EFSYS_OPT_SIENA 181204962Srdivacky 182204962Srdivackystatic const efx_nic_ops_t __efx_nic_siena_ops = { 183206084Srdivacky siena_nic_probe, /* eno_probe */ 184204962Srdivacky NULL, /* eno_board_cfg */ 185204962Srdivacky NULL, /* eno_set_drv_limits */ 186204962Srdivacky siena_nic_reset, /* eno_reset */ 187204962Srdivacky siena_nic_init, /* eno_init */ 188204962Srdivacky NULL, /* eno_get_vi_pool */ 189206084Srdivacky NULL, /* eno_get_bar_region */ 190204962Srdivacky#if EFSYS_OPT_DIAG 191204962Srdivacky siena_nic_register_test, /* eno_register_test */ 192204962Srdivacky#endif /* EFSYS_OPT_DIAG */ 193204962Srdivacky siena_nic_fini, /* eno_fini */ 194204962Srdivacky siena_nic_unprobe, /* eno_unprobe */ 195204962Srdivacky}; 196204962Srdivacky 197204962Srdivacky#endif /* EFSYS_OPT_SIENA */ 198249423Sdim 199210299Sed#if EFSYS_OPT_HUNTINGTON 200249423Sdim 201249423Sdimstatic const efx_nic_ops_t __efx_nic_hunt_ops = { 202204962Srdivacky ef10_nic_probe, /* eno_probe */ 203204962Srdivacky hunt_board_cfg, /* eno_board_cfg */ 204204962Srdivacky ef10_nic_set_drv_limits, /* eno_set_drv_limits */ 205210299Sed ef10_nic_reset, /* eno_reset */ 206204962Srdivacky ef10_nic_init, /* eno_init */ 207204962Srdivacky ef10_nic_get_vi_pool, /* eno_get_vi_pool */ 208204962Srdivacky ef10_nic_get_bar_region, /* eno_get_bar_region */ 209204962Srdivacky#if EFSYS_OPT_DIAG 210204962Srdivacky ef10_nic_register_test, /* eno_register_test */ 211204962Srdivacky#endif /* EFSYS_OPT_DIAG */ 212204962Srdivacky ef10_nic_fini, /* eno_fini */ 213204962Srdivacky ef10_nic_unprobe, /* eno_unprobe */ 214204962Srdivacky}; 215205219Srdivacky 216205219Srdivacky#endif /* EFSYS_OPT_HUNTINGTON */ 217210299Sed 218234353Sdim#if EFSYS_OPT_MEDFORD 219205219Srdivacky 220210299Sedstatic const efx_nic_ops_t __efx_nic_medford_ops = { 221234353Sdim ef10_nic_probe, /* eno_probe */ 222205219Srdivacky medford_board_cfg, /* eno_board_cfg */ 223205219Srdivacky ef10_nic_set_drv_limits, /* eno_set_drv_limits */ 224210299Sed ef10_nic_reset, /* eno_reset */ 225234353Sdim ef10_nic_init, /* eno_init */ 226205219Srdivacky ef10_nic_get_vi_pool, /* eno_get_vi_pool */ 227205219Srdivacky ef10_nic_get_bar_region, /* eno_get_bar_region */ 228204962Srdivacky#if EFSYS_OPT_DIAG 229212904Sdim ef10_nic_register_test, /* eno_register_test */ 230212904Sdim#endif /* EFSYS_OPT_DIAG */ 231212904Sdim ef10_nic_fini, /* eno_fini */ 232210299Sed ef10_nic_unprobe, /* eno_unprobe */ 233234353Sdim}; 234210299Sed 235234353Sdim#endif /* EFSYS_OPT_MEDFORD */ 236205219Srdivacky 237210299Sed 238234353Sdim __checkReturn efx_rc_t 239205219Srdivackyefx_nic_create( 240205219Srdivacky __in efx_family_t family, 241205219Srdivacky __in efsys_identifier_t *esip, 242206084Srdivacky __in efsys_bar_t *esbp, 243205219Srdivacky __in efsys_lock_t *eslp, 244205219Srdivacky __deref_out efx_nic_t **enpp) 245205219Srdivacky{ 246205219Srdivacky efx_nic_t *enp; 247205219Srdivacky efx_rc_t rc; 248206084Srdivacky 249205219Srdivacky EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID); 250205219Srdivacky EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES); 251205219Srdivacky 252205219Srdivacky /* Allocate a NIC object */ 253205219Srdivacky EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp); 254206084Srdivacky 255205219Srdivacky if (enp == NULL) { 256205219Srdivacky rc = ENOMEM; 257205219Srdivacky goto fail1; 258205219Srdivacky } 259205219Srdivacky 260205219Srdivacky enp->en_magic = EFX_NIC_MAGIC; 261205219Srdivacky 262234353Sdim switch (family) { 263205219Srdivacky#if EFSYS_OPT_SIENA 264205219Srdivacky case EFX_FAMILY_SIENA: 265206084Srdivacky enp->en_enop = &__efx_nic_siena_ops; 266205219Srdivacky enp->en_features = 267205219Srdivacky EFX_FEATURE_IPV6 | 268234353Sdim EFX_FEATURE_LFSR_HASH_INSERT | 269205219Srdivacky EFX_FEATURE_LINK_EVENTS | 270205219Srdivacky EFX_FEATURE_PERIODIC_MAC_STATS | 271205219Srdivacky EFX_FEATURE_WOL | 272206084Srdivacky EFX_FEATURE_MCDI | 273205219Srdivacky EFX_FEATURE_LOOKAHEAD_SPLIT | 274205219Srdivacky EFX_FEATURE_MAC_HEADER_FILTERS | 275205219Srdivacky EFX_FEATURE_TX_SRC_FILTERS; 276205219Srdivacky break; 277205219Srdivacky#endif /* EFSYS_OPT_SIENA */ 278206084Srdivacky 279205219Srdivacky#if EFSYS_OPT_HUNTINGTON 280205219Srdivacky case EFX_FAMILY_HUNTINGTON: 281205219Srdivacky enp->en_enop = &__efx_nic_hunt_ops; 282205219Srdivacky /* FIXME: Add WOL support */ 283205219Srdivacky enp->en_features = 284206084Srdivacky EFX_FEATURE_IPV6 | 285205219Srdivacky EFX_FEATURE_LINK_EVENTS | 286205219Srdivacky EFX_FEATURE_PERIODIC_MAC_STATS | 287205219Srdivacky EFX_FEATURE_MCDI | 288205219Srdivacky EFX_FEATURE_MAC_HEADER_FILTERS | 289205219Srdivacky EFX_FEATURE_MCDI_DMA | 290206084Srdivacky EFX_FEATURE_PIO_BUFFERS | 291205219Srdivacky EFX_FEATURE_FW_ASSISTED_TSO | 292205219Srdivacky EFX_FEATURE_FW_ASSISTED_TSO_V2; 293205219Srdivacky break; 294205219Srdivacky#endif /* EFSYS_OPT_HUNTINGTON */ 295205219Srdivacky 296206084Srdivacky#if EFSYS_OPT_MEDFORD 297205219Srdivacky case EFX_FAMILY_MEDFORD: 298205219Srdivacky enp->en_enop = &__efx_nic_medford_ops; 299205219Srdivacky /* 300205219Srdivacky * FW_ASSISTED_TSO omitted as Medford only supports firmware 301205219Srdivacky * assisted TSO version 2, not the v1 scheme used on Huntington. 302206084Srdivacky */ 303205219Srdivacky enp->en_features = 304205219Srdivacky EFX_FEATURE_IPV6 | 305205219Srdivacky EFX_FEATURE_LINK_EVENTS | 306205219Srdivacky EFX_FEATURE_PERIODIC_MAC_STATS | 307205219Srdivacky EFX_FEATURE_MCDI | 308205219Srdivacky EFX_FEATURE_MAC_HEADER_FILTERS | 309206084Srdivacky EFX_FEATURE_MCDI_DMA | 310205219Srdivacky EFX_FEATURE_PIO_BUFFERS; 311205219Srdivacky break; 312205219Srdivacky#endif /* EFSYS_OPT_MEDFORD */ 313205219Srdivacky 314205219Srdivacky default: 315206084Srdivacky rc = ENOTSUP; 316205219Srdivacky goto fail2; 317205219Srdivacky } 318205219Srdivacky 319205219Srdivacky enp->en_family = family; 320205219Srdivacky enp->en_esip = esip; 321206084Srdivacky enp->en_esbp = esbp; 322205219Srdivacky enp->en_eslp = eslp; 323205219Srdivacky 324205219Srdivacky *enpp = enp; 325205219Srdivacky 326205219Srdivacky return (0); 327206084Srdivacky 328205219Srdivackyfail2: 329205219Srdivacky EFSYS_PROBE(fail2); 330205219Srdivacky 331205219Srdivacky enp->en_magic = 0; 332205219Srdivacky 333206084Srdivacky /* Free the NIC object */ 334205219Srdivacky EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); 335205219Srdivacky 336205219Srdivackyfail1: 337205219Srdivacky EFSYS_PROBE1(fail1, efx_rc_t, rc); 338205219Srdivacky 339206084Srdivacky return (rc); 340205219Srdivacky} 341205219Srdivacky 342205219Srdivacky __checkReturn efx_rc_t 343205219Srdivackyefx_nic_probe( 344205219Srdivacky __in efx_nic_t *enp) 345205219Srdivacky{ 346206084Srdivacky const efx_nic_ops_t *enop; 347205219Srdivacky efx_rc_t rc; 348205219Srdivacky 349205219Srdivacky EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 350205219Srdivacky#if EFSYS_OPT_MCDI 351205219Srdivacky EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 352205219Srdivacky#endif /* EFSYS_OPT_MCDI */ 353234353Sdim EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE)); 354234353Sdim 355234353Sdim enop = enp->en_enop; 356234353Sdim if ((rc = enop->eno_probe(enp)) != 0) 357205219Srdivacky goto fail1; 358234353Sdim 359234353Sdim if ((rc = efx_phy_probe(enp)) != 0) 360234353Sdim goto fail2; 361234353Sdim 362234353Sdim enp->en_mod_flags |= EFX_MOD_PROBE; 363234353Sdim 364205408Srdivacky return (0); 365205408Srdivacky 366205408Srdivackyfail2: 367205408Srdivacky EFSYS_PROBE(fail2); 368205408Srdivacky 369205408Srdivacky enop->eno_unprobe(enp); 370205408Srdivacky 371205408Srdivackyfail1: 372205408Srdivacky EFSYS_PROBE1(fail1, efx_rc_t, rc); 373205408Srdivacky 374205408Srdivacky return (rc); 375205408Srdivacky} 376205408Srdivacky 377205408Srdivacky __checkReturn efx_rc_t 378205408Srdivackyefx_nic_set_drv_limits( 379205408Srdivacky __inout efx_nic_t *enp, 380205408Srdivacky __in efx_drv_limits_t *edlp) 381205408Srdivacky{ 382205408Srdivacky const efx_nic_ops_t *enop = enp->en_enop; 383205408Srdivacky efx_rc_t rc; 384205408Srdivacky 385205408Srdivacky EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 386205408Srdivacky EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 387205408Srdivacky 388205408Srdivacky if (enop->eno_set_drv_limits != NULL) { 389205408Srdivacky if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0) 390205408Srdivacky goto fail1; 391205408Srdivacky } 392205408Srdivacky 393205408Srdivacky return (0); 394205408Srdivacky 395205408Srdivackyfail1: 396205408Srdivacky EFSYS_PROBE1(fail1, efx_rc_t, rc); 397205408Srdivacky 398205408Srdivacky return (rc); 399205408Srdivacky} 400234353Sdim 401205408Srdivacky __checkReturn efx_rc_t 402205408Srdivackyefx_nic_get_bar_region( 403205408Srdivacky __in efx_nic_t *enp, 404234353Sdim __in efx_nic_region_t region, 405234353Sdim __out uint32_t *offsetp, 406234353Sdim __out size_t *sizep) 407234353Sdim{ 408234353Sdim const efx_nic_ops_t *enop = enp->en_enop; 409234353Sdim efx_rc_t rc; 410234353Sdim 411234353Sdim EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 412234353Sdim EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 413234353Sdim EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 414205408Srdivacky 415205408Srdivacky if (enop->eno_get_bar_region == NULL) { 416205408Srdivacky rc = ENOTSUP; 417205408Srdivacky goto fail1; 418205408Srdivacky } 419205408Srdivacky if ((rc = (enop->eno_get_bar_region)(enp, 420205408Srdivacky region, offsetp, sizep)) != 0) { 421205408Srdivacky goto fail2; 422205408Srdivacky } 423205408Srdivacky 424205408Srdivacky return (0); 425205408Srdivacky 426205408Srdivackyfail2: 427206084Srdivacky EFSYS_PROBE(fail2); 428205408Srdivacky 429205408Srdivackyfail1: 430234353Sdim EFSYS_PROBE1(fail1, efx_rc_t, rc); 431205408Srdivacky 432205408Srdivacky return (rc); 433205408Srdivacky} 434206084Srdivacky 435205408Srdivacky 436205408Srdivacky __checkReturn efx_rc_t 437205408Srdivackyefx_nic_get_vi_pool( 438205408Srdivacky __in efx_nic_t *enp, 439205408Srdivacky __out uint32_t *evq_countp, 440206084Srdivacky __out uint32_t *rxq_countp, 441205408Srdivacky __out uint32_t *txq_countp) 442205408Srdivacky{ 443205408Srdivacky const efx_nic_ops_t *enop = enp->en_enop; 444205408Srdivacky efx_nic_cfg_t *encp = &enp->en_nic_cfg; 445205408Srdivacky efx_rc_t rc; 446206084Srdivacky 447205408Srdivacky EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 448205408Srdivacky EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 449205408Srdivacky EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 450205408Srdivacky 451205408Srdivacky if (enop->eno_get_vi_pool != NULL) { 452205408Srdivacky uint32_t vi_count = 0; 453206084Srdivacky 454205408Srdivacky if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0) 455205408Srdivacky goto fail1; 456205408Srdivacky 457205408Srdivacky *evq_countp = vi_count; 458205408Srdivacky *rxq_countp = vi_count; 459205408Srdivacky *txq_countp = vi_count; 460234353Sdim } else { 461234353Sdim /* Use NIC limits as default value */ 462234353Sdim *evq_countp = encp->enc_evq_limit; 463205408Srdivacky *rxq_countp = encp->enc_rxq_limit; 464205408Srdivacky *txq_countp = encp->enc_txq_limit; 465204793Srdivacky } 466204793Srdivacky 467204793Srdivacky return (0); 468 469fail1: 470 EFSYS_PROBE1(fail1, efx_rc_t, rc); 471 472 return (rc); 473} 474 475 476 __checkReturn efx_rc_t 477efx_nic_init( 478 __in efx_nic_t *enp) 479{ 480 const efx_nic_ops_t *enop = enp->en_enop; 481 efx_rc_t rc; 482 483 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 484 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 485 486 if (enp->en_mod_flags & EFX_MOD_NIC) { 487 rc = EINVAL; 488 goto fail1; 489 } 490 491 if ((rc = enop->eno_init(enp)) != 0) 492 goto fail2; 493 494 enp->en_mod_flags |= EFX_MOD_NIC; 495 496 return (0); 497 498fail2: 499 EFSYS_PROBE(fail2); 500fail1: 501 EFSYS_PROBE1(fail1, efx_rc_t, rc); 502 503 return (rc); 504} 505 506 void 507efx_nic_fini( 508 __in efx_nic_t *enp) 509{ 510 const efx_nic_ops_t *enop = enp->en_enop; 511 512 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 513 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 514 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC); 515 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); 516 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 517 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 518 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 519 520 enop->eno_fini(enp); 521 522 enp->en_mod_flags &= ~EFX_MOD_NIC; 523} 524 525 void 526efx_nic_unprobe( 527 __in efx_nic_t *enp) 528{ 529 const efx_nic_ops_t *enop = enp->en_enop; 530 531 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 532#if EFSYS_OPT_MCDI 533 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 534#endif /* EFSYS_OPT_MCDI */ 535 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 536 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 537 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); 538 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 539 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 540 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 541 542 efx_phy_unprobe(enp); 543 544 enop->eno_unprobe(enp); 545 546 enp->en_mod_flags &= ~EFX_MOD_PROBE; 547} 548 549 void 550efx_nic_destroy( 551 __in efx_nic_t *enp) 552{ 553 efsys_identifier_t *esip = enp->en_esip; 554 555 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 556 EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); 557 558 enp->en_family = 0; 559 enp->en_esip = NULL; 560 enp->en_esbp = NULL; 561 enp->en_eslp = NULL; 562 563 enp->en_enop = NULL; 564 565 enp->en_magic = 0; 566 567 /* Free the NIC object */ 568 EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); 569} 570 571 __checkReturn efx_rc_t 572efx_nic_reset( 573 __in efx_nic_t *enp) 574{ 575 const efx_nic_ops_t *enop = enp->en_enop; 576 unsigned int mod_flags; 577 efx_rc_t rc; 578 579 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 580 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 581 /* 582 * All modules except the MCDI, PROBE, NVRAM, VPD, MON, LIC 583 * (which we do not reset here) must have been shut down or never 584 * initialized. 585 * 586 * A rule of thumb here is: If the controller or MC reboots, is *any* 587 * state lost. If it's lost and needs reapplying, then the module 588 * *must* not be initialised during the reset. 589 */ 590 mod_flags = enp->en_mod_flags; 591 mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM | 592 EFX_MOD_VPD | EFX_MOD_MON | EFX_MOD_LIC); 593 EFSYS_ASSERT3U(mod_flags, ==, 0); 594 if (mod_flags != 0) { 595 rc = EINVAL; 596 goto fail1; 597 } 598 599 if ((rc = enop->eno_reset(enp)) != 0) 600 goto fail2; 601 602 enp->en_reset_flags |= EFX_RESET_MAC; 603 604 return (0); 605 606fail2: 607 EFSYS_PROBE(fail2); 608fail1: 609 EFSYS_PROBE1(fail1, efx_rc_t, rc); 610 611 return (rc); 612} 613 614 const efx_nic_cfg_t * 615efx_nic_cfg_get( 616 __in efx_nic_t *enp) 617{ 618 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 619 620 return (&(enp->en_nic_cfg)); 621} 622 623#if EFSYS_OPT_DIAG 624 625 __checkReturn efx_rc_t 626efx_nic_register_test( 627 __in efx_nic_t *enp) 628{ 629 const efx_nic_ops_t *enop = enp->en_enop; 630 efx_rc_t rc; 631 632 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 633 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 634 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 635 636 if ((rc = enop->eno_register_test(enp)) != 0) 637 goto fail1; 638 639 return (0); 640 641fail1: 642 EFSYS_PROBE1(fail1, efx_rc_t, rc); 643 644 return (rc); 645} 646 647 __checkReturn efx_rc_t 648efx_nic_test_registers( 649 __in efx_nic_t *enp, 650 __in efx_register_set_t *rsp, 651 __in size_t count) 652{ 653 unsigned int bit; 654 efx_oword_t original; 655 efx_oword_t reg; 656 efx_oword_t buf; 657 efx_rc_t rc; 658 659 while (count > 0) { 660 /* This function is only suitable for registers */ 661 EFSYS_ASSERT(rsp->rows == 1); 662 663 /* bit sweep on and off */ 664 EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original, 665 B_TRUE); 666 for (bit = 0; bit < 128; bit++) { 667 /* Is this bit in the mask? */ 668 if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit)) 669 continue; 670 671 /* Test this bit can be set in isolation */ 672 reg = original; 673 EFX_AND_OWORD(reg, rsp->mask); 674 EFX_SET_OWORD_BIT(reg, bit); 675 676 EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, ®, 677 B_TRUE); 678 EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf, 679 B_TRUE); 680 681 EFX_AND_OWORD(buf, rsp->mask); 682 if (memcmp(®, &buf, sizeof (reg))) { 683 rc = EIO; 684 goto fail1; 685 } 686 687 /* Test this bit can be cleared in isolation */ 688 EFX_OR_OWORD(reg, rsp->mask); 689 EFX_CLEAR_OWORD_BIT(reg, bit); 690 691 EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, ®, 692 B_TRUE); 693 EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf, 694 B_TRUE); 695 696 EFX_AND_OWORD(buf, rsp->mask); 697 if (memcmp(®, &buf, sizeof (reg))) { 698 rc = EIO; 699 goto fail2; 700 } 701 } 702 703 /* Restore the old value */ 704 EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, 705 B_TRUE); 706 707 --count; 708 ++rsp; 709 } 710 711 return (0); 712 713fail2: 714 EFSYS_PROBE(fail2); 715fail1: 716 EFSYS_PROBE1(fail1, efx_rc_t, rc); 717 718 /* Restore the old value */ 719 EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE); 720 721 return (rc); 722} 723 724 __checkReturn efx_rc_t 725efx_nic_test_tables( 726 __in efx_nic_t *enp, 727 __in efx_register_set_t *rsp, 728 __in efx_pattern_type_t pattern, 729 __in size_t count) 730{ 731 efx_sram_pattern_fn_t func; 732 unsigned int index; 733 unsigned int address; 734 efx_oword_t reg; 735 efx_oword_t buf; 736 efx_rc_t rc; 737 738 EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES); 739 func = __efx_sram_pattern_fns[pattern]; 740 741 while (count > 0) { 742 /* Write */ 743 address = rsp->address; 744 for (index = 0; index < rsp->rows; ++index) { 745 func(2 * index + 0, B_FALSE, ®.eo_qword[0]); 746 func(2 * index + 1, B_FALSE, ®.eo_qword[1]); 747 EFX_AND_OWORD(reg, rsp->mask); 748 EFSYS_BAR_WRITEO(enp->en_esbp, address, ®, B_TRUE); 749 750 address += rsp->step; 751 } 752 753 /* Read */ 754 address = rsp->address; 755 for (index = 0; index < rsp->rows; ++index) { 756 func(2 * index + 0, B_FALSE, ®.eo_qword[0]); 757 func(2 * index + 1, B_FALSE, ®.eo_qword[1]); 758 EFX_AND_OWORD(reg, rsp->mask); 759 EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE); 760 if (memcmp(®, &buf, sizeof (reg))) { 761 rc = EIO; 762 goto fail1; 763 } 764 765 address += rsp->step; 766 } 767 768 ++rsp; 769 --count; 770 } 771 772 return (0); 773 774fail1: 775 EFSYS_PROBE1(fail1, efx_rc_t, rc); 776 777 return (rc); 778} 779 780#endif /* EFSYS_OPT_DIAG */ 781 782#if EFSYS_OPT_LOOPBACK 783 784extern void 785efx_loopback_mask( 786 __in efx_loopback_kind_t loopback_kind, 787 __out efx_qword_t *maskp) 788{ 789 efx_qword_t mask; 790 791 EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS); 792 EFSYS_ASSERT(maskp != NULL); 793 794 /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ 795 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); 796 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); 797 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); 798 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); 799 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); 800 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); 801 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); 802 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); 803 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); 804 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); 805 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); 806 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); 807 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); 808 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); 809 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); 810 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); 811 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); 812 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); 813 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT); 814 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS); 815 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS); 816 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR == 817 EFX_LOOPBACK_XAUI_WS_FAR); 818 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR == 819 EFX_LOOPBACK_XAUI_WS_NEAR); 820 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS); 821 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS); 822 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR == 823 EFX_LOOPBACK_XFI_WS_FAR); 824 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS); 825 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT); 826 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR); 827 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR); 828 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS == 829 EFX_LOOPBACK_PMA_INT_WS); 830 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS == 831 EFX_LOOPBACK_SD_FEP2_WS); 832 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS == 833 EFX_LOOPBACK_SD_FEP1_5_WS); 834 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS); 835 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS); 836 837 /* Build bitmask of possible loopback types */ 838 EFX_ZERO_QWORD(mask); 839 840 if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) || 841 (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 842 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF); 843 } 844 845 if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) || 846 (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 847 /* 848 * The "MAC" grouping has historically been used by drivers to 849 * mean loopbacks supported by on-chip hardware. Keep that 850 * meaning here, and include on-chip PHY layer loopbacks. 851 */ 852 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA); 853 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC); 854 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII); 855 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS); 856 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI); 857 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII); 858 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII); 859 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR); 860 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI); 861 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR); 862 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR); 863 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR); 864 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR); 865 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT); 866 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR); 867 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR); 868 } 869 870 if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) || 871 (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 872 /* 873 * The "PHY" grouping has historically been used by drivers to 874 * mean loopbacks supported by off-chip hardware. Keep that 875 * meaning here. 876 */ 877 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY); 878 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PHY_XS); 879 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS); 880 EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD); 881 } 882 883 *maskp = mask; 884} 885 886 __checkReturn efx_rc_t 887efx_mcdi_get_loopback_modes( 888 __in efx_nic_t *enp) 889{ 890 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 891 efx_mcdi_req_t req; 892 uint8_t payload[MAX(MC_CMD_GET_LOOPBACK_MODES_IN_LEN, 893 MC_CMD_GET_LOOPBACK_MODES_OUT_LEN)]; 894 efx_qword_t mask; 895 efx_qword_t modes; 896 efx_rc_t rc; 897 898 (void) memset(payload, 0, sizeof (payload)); 899 req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES; 900 req.emr_in_buf = payload; 901 req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN; 902 req.emr_out_buf = payload; 903 req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN; 904 905 efx_mcdi_execute(enp, &req); 906 907 if (req.emr_rc != 0) { 908 rc = req.emr_rc; 909 goto fail1; 910 } 911 912 if (req.emr_out_length_used < 913 MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST + 914 MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) { 915 rc = EMSGSIZE; 916 goto fail2; 917 } 918 919 /* 920 * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree 921 * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link(). 922 */ 923 efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask); 924 925 EFX_AND_QWORD(mask, 926 *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED)); 927 928 modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M); 929 EFX_AND_QWORD(modes, mask); 930 encp->enc_loopback_types[EFX_LINK_100FDX] = modes; 931 932 modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G); 933 EFX_AND_QWORD(modes, mask); 934 encp->enc_loopback_types[EFX_LINK_1000FDX] = modes; 935 936 modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G); 937 EFX_AND_QWORD(modes, mask); 938 encp->enc_loopback_types[EFX_LINK_10000FDX] = modes; 939 940 if (req.emr_out_length_used >= 941 MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST + 942 MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) { 943 /* Response includes 40G loopback modes */ 944 modes = 945 *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G); 946 EFX_AND_QWORD(modes, mask); 947 encp->enc_loopback_types[EFX_LINK_40000FDX] = modes; 948 } 949 950 EFX_ZERO_QWORD(modes); 951 EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF); 952 EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]); 953 EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]); 954 EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]); 955 EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]); 956 encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes; 957 958 return (0); 959 960fail2: 961 EFSYS_PROBE(fail2); 962fail1: 963 EFSYS_PROBE1(fail1, efx_rc_t, rc); 964 965 return (rc); 966} 967 968#endif /* EFSYS_OPT_LOOPBACK */ 969