efx_nic.c revision 283514
1227569Sphilip/*- 2283514Sarybchik * Copyright (c) 2007-2015 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: head/sys/dev/sfxge/common/efx_nic.c 283514 2015-05-25 08:34:55Z arybchik $"); 33228078Sphilip 34227569Sphilip#include "efsys.h" 35227569Sphilip#include "efx.h" 36227569Sphilip#include "efx_types.h" 37227569Sphilip#include "efx_regs.h" 38227569Sphilip#include "efx_impl.h" 39227569Sphilip 40227569Sphilip __checkReturn int 41227569Sphilipefx_family( 42227569Sphilip __in uint16_t venid, 43227569Sphilip __in uint16_t devid, 44227569Sphilip __out efx_family_t *efp) 45227569Sphilip{ 46283514Sarybchik if (venid == EFX_PCI_VENID_SFC) { 47283514Sarybchik switch (devid) { 48227569Sphilip#if EFSYS_OPT_FALCON 49283514Sarybchik case EFX_PCI_DEVID_FALCON: 50283514Sarybchik *efp = EFX_FAMILY_FALCON; 51283514Sarybchik return (0); 52227569Sphilip#endif 53227569Sphilip#if EFSYS_OPT_SIENA 54283514Sarybchik case EFX_PCI_DEVID_SIENA_F1_UNINIT: 55283514Sarybchik /* 56283514Sarybchik * Hardware default for PF0 of uninitialised Siena. 57283514Sarybchik * manftest must be able to cope with this device id. 58283514Sarybchik */ 59283514Sarybchik *efp = EFX_FAMILY_SIENA; 60283514Sarybchik return (0); 61283514Sarybchik 62283514Sarybchik case EFX_PCI_DEVID_BETHPAGE: 63283514Sarybchik case EFX_PCI_DEVID_SIENA: 64283514Sarybchik *efp = EFX_FAMILY_SIENA; 65283514Sarybchik return (0); 66283514Sarybchik#endif 67283514Sarybchik 68283514Sarybchik#if EFSYS_OPT_HUNTINGTON 69283514Sarybchik case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT: 70283514Sarybchik /* 71283514Sarybchik * Hardware default for PF0 of uninitialised Huntington. 72283514Sarybchik * manftest must be able to cope with this device id. 73283514Sarybchik */ 74283514Sarybchik *efp = EFX_FAMILY_HUNTINGTON; 75283514Sarybchik return (0); 76283514Sarybchik 77283514Sarybchik case EFX_PCI_DEVID_FARMINGDALE: 78283514Sarybchik case EFX_PCI_DEVID_GREENPORT: 79283514Sarybchik case EFX_PCI_DEVID_HUNTINGTON: 80283514Sarybchik *efp = EFX_FAMILY_HUNTINGTON; 81283514Sarybchik return (0); 82283514Sarybchik 83283514Sarybchik case EFX_PCI_DEVID_FARMINGDALE_VF: 84283514Sarybchik case EFX_PCI_DEVID_GREENPORT_VF: 85283514Sarybchik case EFX_PCI_DEVID_HUNTINGTON_VF: 86283514Sarybchik *efp = EFX_FAMILY_HUNTINGTON; 87283514Sarybchik return (0); 88283514Sarybchik#endif 89283514Sarybchik default: 90283514Sarybchik break; 91283514Sarybchik } 92227569Sphilip } 93283514Sarybchik 94283514Sarybchik *efp = EFX_FAMILY_INVALID; 95227569Sphilip return (ENOTSUP); 96227569Sphilip} 97227569Sphilip 98227569Sphilip/* 99227569Sphilip * To support clients which aren't provided with any PCI context infer 100227569Sphilip * the hardware family by inspecting the hardware. Obviously the caller 101227569Sphilip * must be damn sure they're really talking to a supported device. 102227569Sphilip */ 103227569Sphilip __checkReturn int 104227569Sphilipefx_infer_family( 105227569Sphilip __in efsys_bar_t *esbp, 106227569Sphilip __out efx_family_t *efp) 107227569Sphilip{ 108227569Sphilip efx_family_t family; 109227569Sphilip efx_oword_t oword; 110227569Sphilip unsigned int portnum; 111227569Sphilip int rc; 112227569Sphilip 113227569Sphilip EFSYS_BAR_READO(esbp, FR_AZ_CS_DEBUG_REG_OFST, &oword, B_TRUE); 114227569Sphilip portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM); 115227569Sphilip switch (portnum) { 116283514Sarybchik case 0: { 117283514Sarybchik efx_dword_t dword; 118283514Sarybchik uint32_t hw_rev; 119283514Sarybchik 120283514Sarybchik EFSYS_BAR_READD(esbp, ER_DZ_BIU_HW_REV_ID_REG_OFST, &dword, 121283514Sarybchik B_TRUE); 122283514Sarybchik hw_rev = EFX_DWORD_FIELD(dword, ERF_DZ_HW_REV_ID); 123283514Sarybchik if (hw_rev == ER_DZ_BIU_HW_REV_ID_REG_RESET) { 124283514Sarybchik#if EFSYS_OPT_HUNTINGTON 125283514Sarybchik family = EFX_FAMILY_HUNTINGTON; 126283514Sarybchik break; 127283514Sarybchik#endif 128283514Sarybchik } else { 129227569Sphilip#if EFSYS_OPT_FALCON 130283514Sarybchik family = EFX_FAMILY_FALCON; 131283514Sarybchik break; 132227569Sphilip#endif 133283514Sarybchik } 134283514Sarybchik rc = ENOTSUP; 135283514Sarybchik goto fail1; 136283514Sarybchik } 137283514Sarybchik 138227569Sphilip#if EFSYS_OPT_SIENA 139227569Sphilip case 1: 140227569Sphilip case 2: 141227569Sphilip family = EFX_FAMILY_SIENA; 142227569Sphilip break; 143227569Sphilip#endif 144227569Sphilip default: 145227569Sphilip rc = ENOTSUP; 146227569Sphilip goto fail1; 147227569Sphilip } 148227569Sphilip 149227569Sphilip if (efp != NULL) 150227569Sphilip *efp = family; 151227569Sphilip return (0); 152227569Sphilip 153227569Sphilipfail1: 154227569Sphilip EFSYS_PROBE1(fail1, int, rc); 155227569Sphilip 156227569Sphilip return (rc); 157227569Sphilip} 158227569Sphilip 159227569Sphilip#define EFX_BIU_MAGIC0 0x01234567 160227569Sphilip#define EFX_BIU_MAGIC1 0xfedcba98 161227569Sphilip 162283514Sarybchik __checkReturn int 163227569Sphilipefx_nic_biu_test( 164227569Sphilip __in efx_nic_t *enp) 165227569Sphilip{ 166227569Sphilip efx_oword_t oword; 167227569Sphilip int rc; 168227569Sphilip 169227569Sphilip /* 170227569Sphilip * Write magic values to scratch registers 0 and 1, then 171227569Sphilip * verify that the values were written correctly. Interleave 172227569Sphilip * the accesses to ensure that the BIU is not just reading 173227569Sphilip * back the cached value that was last written. 174227569Sphilip */ 175227569Sphilip EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); 176283514Sarybchik EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); 177227569Sphilip 178227569Sphilip EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); 179283514Sarybchik EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); 180227569Sphilip 181283514Sarybchik EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); 182227569Sphilip if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { 183227569Sphilip rc = EIO; 184227569Sphilip goto fail1; 185227569Sphilip } 186227569Sphilip 187283514Sarybchik EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); 188227569Sphilip if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { 189227569Sphilip rc = EIO; 190227569Sphilip goto fail2; 191227569Sphilip } 192227569Sphilip 193227569Sphilip /* 194227569Sphilip * Perform the same test, with the values swapped. This 195227569Sphilip * ensures that subsequent tests don't start with the correct 196227569Sphilip * values already written into the scratch registers. 197227569Sphilip */ 198227569Sphilip EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); 199283514Sarybchik EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); 200227569Sphilip 201227569Sphilip EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); 202283514Sarybchik EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); 203227569Sphilip 204283514Sarybchik EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); 205227569Sphilip if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { 206227569Sphilip rc = EIO; 207227569Sphilip goto fail3; 208227569Sphilip } 209227569Sphilip 210283514Sarybchik EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); 211227569Sphilip if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { 212227569Sphilip rc = EIO; 213227569Sphilip goto fail4; 214227569Sphilip } 215227569Sphilip 216227569Sphilip return (0); 217227569Sphilip 218227569Sphilipfail4: 219227569Sphilip EFSYS_PROBE(fail4); 220227569Sphilipfail3: 221227569Sphilip EFSYS_PROBE(fail3); 222227569Sphilipfail2: 223227569Sphilip EFSYS_PROBE(fail2); 224227569Sphilipfail1: 225227569Sphilip EFSYS_PROBE1(fail1, int, rc); 226227569Sphilip 227227569Sphilip return (rc); 228227569Sphilip} 229227569Sphilip 230227569Sphilip#if EFSYS_OPT_FALCON 231227569Sphilip 232283514Sarybchikstatic efx_nic_ops_t __efx_nic_falcon_ops = { 233227569Sphilip falcon_nic_probe, /* eno_probe */ 234283514Sarybchik NULL, /* eno_set_drv_limits */ 235227569Sphilip falcon_nic_reset, /* eno_reset */ 236227569Sphilip falcon_nic_init, /* eno_init */ 237283514Sarybchik NULL, /* eno_get_vi_pool */ 238283514Sarybchik NULL, /* eno_get_bar_region */ 239227569Sphilip#if EFSYS_OPT_DIAG 240227569Sphilip falcon_sram_test, /* eno_sram_test */ 241227569Sphilip falcon_nic_register_test, /* eno_register_test */ 242227569Sphilip#endif /* EFSYS_OPT_DIAG */ 243227569Sphilip falcon_nic_fini, /* eno_fini */ 244227569Sphilip falcon_nic_unprobe, /* eno_unprobe */ 245227569Sphilip}; 246227569Sphilip 247227569Sphilip#endif /* EFSYS_OPT_FALCON */ 248227569Sphilip 249227569Sphilip#if EFSYS_OPT_SIENA 250227569Sphilip 251283514Sarybchikstatic efx_nic_ops_t __efx_nic_siena_ops = { 252227569Sphilip siena_nic_probe, /* eno_probe */ 253283514Sarybchik NULL, /* eno_set_drv_limits */ 254227569Sphilip siena_nic_reset, /* eno_reset */ 255227569Sphilip siena_nic_init, /* eno_init */ 256283514Sarybchik NULL, /* eno_get_vi_pool */ 257283514Sarybchik NULL, /* eno_get_bar_region */ 258227569Sphilip#if EFSYS_OPT_DIAG 259227569Sphilip siena_sram_test, /* eno_sram_test */ 260227569Sphilip siena_nic_register_test, /* eno_register_test */ 261227569Sphilip#endif /* EFSYS_OPT_DIAG */ 262227569Sphilip siena_nic_fini, /* eno_fini */ 263227569Sphilip siena_nic_unprobe, /* eno_unprobe */ 264227569Sphilip}; 265227569Sphilip 266227569Sphilip#endif /* EFSYS_OPT_SIENA */ 267227569Sphilip 268283514Sarybchik#if EFSYS_OPT_HUNTINGTON 269283514Sarybchik 270283514Sarybchikstatic efx_nic_ops_t __efx_nic_hunt_ops = { 271283514Sarybchik hunt_nic_probe, /* eno_probe */ 272283514Sarybchik hunt_nic_set_drv_limits, /* eno_set_drv_limits */ 273283514Sarybchik hunt_nic_reset, /* eno_reset */ 274283514Sarybchik hunt_nic_init, /* eno_init */ 275283514Sarybchik hunt_nic_get_vi_pool, /* eno_get_vi_pool */ 276283514Sarybchik hunt_nic_get_bar_region, /* eno_get_bar_region */ 277283514Sarybchik#if EFSYS_OPT_DIAG 278283514Sarybchik hunt_sram_test, /* eno_sram_test */ 279283514Sarybchik hunt_nic_register_test, /* eno_register_test */ 280283514Sarybchik#endif /* EFSYS_OPT_DIAG */ 281283514Sarybchik hunt_nic_fini, /* eno_fini */ 282283514Sarybchik hunt_nic_unprobe, /* eno_unprobe */ 283283514Sarybchik}; 284283514Sarybchik 285283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 286283514Sarybchik 287227569Sphilip __checkReturn int 288227569Sphilipefx_nic_create( 289227569Sphilip __in efx_family_t family, 290227569Sphilip __in efsys_identifier_t *esip, 291227569Sphilip __in efsys_bar_t *esbp, 292227569Sphilip __in efsys_lock_t *eslp, 293227569Sphilip __deref_out efx_nic_t **enpp) 294227569Sphilip{ 295227569Sphilip efx_nic_t *enp; 296227569Sphilip int rc; 297227569Sphilip 298227569Sphilip EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID); 299227569Sphilip EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES); 300227569Sphilip 301227569Sphilip /* Allocate a NIC object */ 302227569Sphilip EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp); 303227569Sphilip 304227569Sphilip if (enp == NULL) { 305227569Sphilip rc = ENOMEM; 306227569Sphilip goto fail1; 307227569Sphilip } 308227569Sphilip 309227569Sphilip enp->en_magic = EFX_NIC_MAGIC; 310227569Sphilip 311227569Sphilip switch (family) { 312227569Sphilip#if EFSYS_OPT_FALCON 313227569Sphilip case EFX_FAMILY_FALCON: 314227569Sphilip enp->en_enop = (efx_nic_ops_t *)&__efx_nic_falcon_ops; 315227569Sphilip enp->en_features = 0; 316227569Sphilip break; 317227569Sphilip#endif /* EFSYS_OPT_FALCON */ 318227569Sphilip 319227569Sphilip#if EFSYS_OPT_SIENA 320227569Sphilip case EFX_FAMILY_SIENA: 321227569Sphilip enp->en_enop = (efx_nic_ops_t *)&__efx_nic_siena_ops; 322279141Sarybchik enp->en_features = 323279141Sarybchik EFX_FEATURE_IPV6 | 324227569Sphilip EFX_FEATURE_LFSR_HASH_INSERT | 325279141Sarybchik EFX_FEATURE_LINK_EVENTS | 326279141Sarybchik EFX_FEATURE_PERIODIC_MAC_STATS | 327279141Sarybchik EFX_FEATURE_WOL | 328279141Sarybchik EFX_FEATURE_MCDI | 329278839Sarybchik EFX_FEATURE_LOOKAHEAD_SPLIT | 330283514Sarybchik EFX_FEATURE_MAC_HEADER_FILTERS | 331283514Sarybchik EFX_FEATURE_TX_SRC_FILTERS; 332227569Sphilip break; 333227569Sphilip#endif /* EFSYS_OPT_SIENA */ 334227569Sphilip 335283514Sarybchik#if EFSYS_OPT_HUNTINGTON 336283514Sarybchik case EFX_FAMILY_HUNTINGTON: 337283514Sarybchik enp->en_enop = (efx_nic_ops_t *)&__efx_nic_hunt_ops; 338283514Sarybchik /* FIXME: Add WOL support */ 339283514Sarybchik enp->en_features = 340283514Sarybchik EFX_FEATURE_IPV6 | 341283514Sarybchik EFX_FEATURE_LINK_EVENTS | 342283514Sarybchik EFX_FEATURE_PERIODIC_MAC_STATS | 343283514Sarybchik EFX_FEATURE_MCDI | 344283514Sarybchik EFX_FEATURE_MAC_HEADER_FILTERS | 345283514Sarybchik EFX_FEATURE_MCDI_DMA | 346283514Sarybchik EFX_FEATURE_PIO_BUFFERS | 347283514Sarybchik EFX_FEATURE_FW_ASSISTED_TSO; 348283514Sarybchik break; 349283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 350283514Sarybchik 351227569Sphilip default: 352227569Sphilip rc = ENOTSUP; 353227569Sphilip goto fail2; 354227569Sphilip } 355227569Sphilip 356227569Sphilip enp->en_family = family; 357227569Sphilip enp->en_esip = esip; 358227569Sphilip enp->en_esbp = esbp; 359227569Sphilip enp->en_eslp = eslp; 360227569Sphilip 361227569Sphilip *enpp = enp; 362227569Sphilip 363227569Sphilip return (0); 364227569Sphilip 365227569Sphilipfail2: 366283514Sarybchik EFSYS_PROBE(fail2); 367227569Sphilip 368227569Sphilip enp->en_magic = 0; 369227569Sphilip 370227569Sphilip /* Free the NIC object */ 371227569Sphilip EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); 372227569Sphilip 373227569Sphilipfail1: 374227569Sphilip EFSYS_PROBE1(fail1, int, rc); 375227569Sphilip 376227569Sphilip return (rc); 377227569Sphilip} 378227569Sphilip 379227569Sphilip __checkReturn int 380227569Sphilipefx_nic_probe( 381227569Sphilip __in efx_nic_t *enp) 382227569Sphilip{ 383227569Sphilip efx_nic_ops_t *enop; 384227569Sphilip int rc; 385227569Sphilip 386227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 387227569Sphilip#if EFSYS_OPT_MCDI 388227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 389227569Sphilip#endif /* EFSYS_OPT_MCDI */ 390227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE)); 391227569Sphilip 392227569Sphilip enop = enp->en_enop; 393227569Sphilip if ((rc = enop->eno_probe(enp)) != 0) 394283514Sarybchik goto fail1; 395227569Sphilip 396227569Sphilip if ((rc = efx_phy_probe(enp)) != 0) 397283514Sarybchik goto fail2; 398227569Sphilip 399227569Sphilip enp->en_mod_flags |= EFX_MOD_PROBE; 400227569Sphilip 401227569Sphilip return (0); 402227569Sphilip 403283514Sarybchikfail2: 404283514Sarybchik EFSYS_PROBE(fail2); 405227569Sphilip 406227569Sphilip enop->eno_unprobe(enp); 407227569Sphilip 408227569Sphilipfail1: 409227569Sphilip EFSYS_PROBE1(fail1, int, rc); 410227569Sphilip 411227569Sphilip return (rc); 412227569Sphilip} 413227569Sphilip 414227569Sphilip#if EFSYS_OPT_PCIE_TUNE 415227569Sphilip 416227569Sphilip __checkReturn int 417227569Sphilipefx_nic_pcie_tune( 418227569Sphilip __in efx_nic_t *enp, 419227569Sphilip unsigned int nlanes) 420227569Sphilip{ 421227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 422227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 423227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 424227569Sphilip 425227569Sphilip#if EFSYS_OPT_FALCON 426227569Sphilip if (enp->en_family == EFX_FAMILY_FALCON) 427227569Sphilip return (falcon_nic_pcie_tune(enp, nlanes)); 428227569Sphilip#endif 429227569Sphilip return (ENOTSUP); 430227569Sphilip} 431227569Sphilip 432227569Sphilip __checkReturn int 433227569Sphilipefx_nic_pcie_extended_sync( 434227569Sphilip __in efx_nic_t *enp) 435227569Sphilip{ 436227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 437227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 438227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 439227569Sphilip 440227569Sphilip#if EFSYS_OPT_SIENA 441227569Sphilip if (enp->en_family == EFX_FAMILY_SIENA) 442227569Sphilip return (siena_nic_pcie_extended_sync(enp)); 443227569Sphilip#endif 444227569Sphilip 445227569Sphilip return (ENOTSUP); 446227569Sphilip} 447227569Sphilip 448227569Sphilip#endif /* EFSYS_OPT_PCIE_TUNE */ 449227569Sphilip 450227569Sphilip __checkReturn int 451283514Sarybchikefx_nic_set_drv_limits( 452283514Sarybchik __inout efx_nic_t *enp, 453283514Sarybchik __in efx_drv_limits_t *edlp) 454283514Sarybchik{ 455283514Sarybchik efx_nic_ops_t *enop = enp->en_enop; 456283514Sarybchik int rc; 457283514Sarybchik 458283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 459283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 460283514Sarybchik 461283514Sarybchik if (enop->eno_set_drv_limits != NULL) { 462283514Sarybchik if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0) 463283514Sarybchik goto fail1; 464283514Sarybchik } 465283514Sarybchik 466283514Sarybchik return (0); 467283514Sarybchik 468283514Sarybchikfail1: 469283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 470283514Sarybchik 471283514Sarybchik return (rc); 472283514Sarybchik} 473283514Sarybchik 474283514Sarybchik __checkReturn int 475283514Sarybchikefx_nic_get_bar_region( 476283514Sarybchik __in efx_nic_t *enp, 477283514Sarybchik __in efx_nic_region_t region, 478283514Sarybchik __out uint32_t *offsetp, 479283514Sarybchik __out size_t *sizep) 480283514Sarybchik{ 481283514Sarybchik efx_nic_ops_t *enop = enp->en_enop; 482283514Sarybchik int rc; 483283514Sarybchik 484283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 485283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 486283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 487283514Sarybchik 488283514Sarybchik if (enop->eno_get_bar_region == NULL) { 489283514Sarybchik rc = ENOTSUP; 490283514Sarybchik goto fail1; 491283514Sarybchik } 492283514Sarybchik if ((rc = (enop->eno_get_bar_region)(enp, 493283514Sarybchik region, offsetp, sizep)) != 0) { 494283514Sarybchik goto fail2; 495283514Sarybchik } 496283514Sarybchik 497283514Sarybchik return (0); 498283514Sarybchik 499283514Sarybchikfail2: 500283514Sarybchik EFSYS_PROBE(fail2); 501283514Sarybchik 502283514Sarybchikfail1: 503283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 504283514Sarybchik 505283514Sarybchik return (rc); 506283514Sarybchik} 507283514Sarybchik 508283514Sarybchik 509283514Sarybchik __checkReturn int 510283514Sarybchikefx_nic_get_vi_pool( 511283514Sarybchik __in efx_nic_t *enp, 512283514Sarybchik __out uint32_t *evq_countp, 513283514Sarybchik __out uint32_t *rxq_countp, 514283514Sarybchik __out uint32_t *txq_countp) 515283514Sarybchik{ 516283514Sarybchik efx_nic_ops_t *enop = enp->en_enop; 517283514Sarybchik efx_nic_cfg_t *encp = &enp->en_nic_cfg; 518283514Sarybchik int rc; 519283514Sarybchik 520283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 521283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 522283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 523283514Sarybchik 524283514Sarybchik if (enop->eno_get_vi_pool != NULL) { 525283514Sarybchik uint32_t vi_count = 0; 526283514Sarybchik 527283514Sarybchik if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0) 528283514Sarybchik goto fail1; 529283514Sarybchik 530283514Sarybchik *evq_countp = vi_count; 531283514Sarybchik *rxq_countp = vi_count; 532283514Sarybchik *txq_countp = vi_count; 533283514Sarybchik } else { 534283514Sarybchik /* Use NIC limits as default value */ 535283514Sarybchik *evq_countp = encp->enc_evq_limit; 536283514Sarybchik *rxq_countp = encp->enc_rxq_limit; 537283514Sarybchik *txq_countp = encp->enc_txq_limit; 538283514Sarybchik } 539283514Sarybchik 540283514Sarybchik return (0); 541283514Sarybchik 542283514Sarybchikfail1: 543283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 544283514Sarybchik 545283514Sarybchik return (rc); 546283514Sarybchik} 547283514Sarybchik 548283514Sarybchik 549283514Sarybchik __checkReturn int 550227569Sphilipefx_nic_init( 551227569Sphilip __in efx_nic_t *enp) 552227569Sphilip{ 553227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 554227569Sphilip int rc; 555227569Sphilip 556227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 557227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 558227569Sphilip 559227569Sphilip if (enp->en_mod_flags & EFX_MOD_NIC) { 560227569Sphilip rc = EINVAL; 561227569Sphilip goto fail1; 562227569Sphilip } 563227569Sphilip 564227569Sphilip if ((rc = enop->eno_init(enp)) != 0) 565227569Sphilip goto fail2; 566227569Sphilip 567227569Sphilip enp->en_mod_flags |= EFX_MOD_NIC; 568227569Sphilip 569227569Sphilip return (0); 570227569Sphilip 571227569Sphilipfail2: 572227569Sphilip EFSYS_PROBE(fail2); 573227569Sphilipfail1: 574227569Sphilip EFSYS_PROBE1(fail1, int, rc); 575227569Sphilip 576227569Sphilip return (rc); 577227569Sphilip} 578227569Sphilip 579227569Sphilip void 580227569Sphilipefx_nic_fini( 581227569Sphilip __in efx_nic_t *enp) 582227569Sphilip{ 583227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 584227569Sphilip 585227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 586227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 587227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC); 588227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); 589227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 590227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 591227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 592227569Sphilip 593227569Sphilip enop->eno_fini(enp); 594227569Sphilip 595227569Sphilip enp->en_mod_flags &= ~EFX_MOD_NIC; 596227569Sphilip} 597227569Sphilip 598227569Sphilip void 599227569Sphilipefx_nic_unprobe( 600227569Sphilip __in efx_nic_t *enp) 601227569Sphilip{ 602227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 603227569Sphilip 604227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 605227569Sphilip#if EFSYS_OPT_MCDI 606227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 607227569Sphilip#endif /* EFSYS_OPT_MCDI */ 608227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 609227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 610227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); 611227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 612227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 613227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 614227569Sphilip 615227569Sphilip efx_phy_unprobe(enp); 616227569Sphilip 617227569Sphilip enop->eno_unprobe(enp); 618227569Sphilip 619227569Sphilip enp->en_mod_flags &= ~EFX_MOD_PROBE; 620227569Sphilip} 621227569Sphilip 622227569Sphilip void 623227569Sphilipefx_nic_destroy( 624227569Sphilip __in efx_nic_t *enp) 625227569Sphilip{ 626227569Sphilip efsys_identifier_t *esip = enp->en_esip; 627227569Sphilip 628227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 629227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); 630227569Sphilip 631227569Sphilip enp->en_family = 0; 632227569Sphilip enp->en_esip = NULL; 633227569Sphilip enp->en_esbp = NULL; 634227569Sphilip enp->en_eslp = NULL; 635227569Sphilip 636227569Sphilip enp->en_enop = NULL; 637227569Sphilip 638227569Sphilip enp->en_magic = 0; 639227569Sphilip 640227569Sphilip /* Free the NIC object */ 641227569Sphilip EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); 642227569Sphilip} 643227569Sphilip 644227569Sphilip __checkReturn int 645227569Sphilipefx_nic_reset( 646227569Sphilip __in efx_nic_t *enp) 647227569Sphilip{ 648227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 649227569Sphilip unsigned int mod_flags; 650227569Sphilip int rc; 651227569Sphilip 652227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 653227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 654227569Sphilip /* 655227569Sphilip * All modules except the MCDI, PROBE, NVRAM, VPD, MON (which we 656227569Sphilip * do not reset here) must have been shut down or never initialized. 657227569Sphilip * 658227569Sphilip * A rule of thumb here is: If the controller or MC reboots, is *any* 659227569Sphilip * state lost. If it's lost and needs reapplying, then the module 660227569Sphilip * *must* not be initialised during the reset. 661227569Sphilip */ 662227569Sphilip mod_flags = enp->en_mod_flags; 663227569Sphilip mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM | 664227569Sphilip EFX_MOD_VPD | EFX_MOD_MON); 665227569Sphilip EFSYS_ASSERT3U(mod_flags, ==, 0); 666227569Sphilip if (mod_flags != 0) { 667227569Sphilip rc = EINVAL; 668227569Sphilip goto fail1; 669227569Sphilip } 670227569Sphilip 671227569Sphilip if ((rc = enop->eno_reset(enp)) != 0) 672227569Sphilip goto fail2; 673227569Sphilip 674227569Sphilip enp->en_reset_flags |= EFX_RESET_MAC; 675227569Sphilip 676227569Sphilip return (0); 677227569Sphilip 678227569Sphilipfail2: 679227569Sphilip EFSYS_PROBE(fail2); 680227569Sphilipfail1: 681227569Sphilip EFSYS_PROBE1(fail1, int, rc); 682227569Sphilip 683227569Sphilip return (rc); 684227569Sphilip} 685227569Sphilip 686227569Sphilip const efx_nic_cfg_t * 687227569Sphilipefx_nic_cfg_get( 688227569Sphilip __in efx_nic_t *enp) 689227569Sphilip{ 690227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 691227569Sphilip 692227569Sphilip return (&(enp->en_nic_cfg)); 693227569Sphilip} 694227569Sphilip 695227569Sphilip#if EFSYS_OPT_DIAG 696227569Sphilip 697227569Sphilip __checkReturn int 698227569Sphilipefx_nic_register_test( 699227569Sphilip __in efx_nic_t *enp) 700227569Sphilip{ 701227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 702227569Sphilip int rc; 703227569Sphilip 704227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 705227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 706227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 707227569Sphilip 708227569Sphilip if ((rc = enop->eno_register_test(enp)) != 0) 709227569Sphilip goto fail1; 710227569Sphilip 711227569Sphilip return (0); 712227569Sphilip 713227569Sphilipfail1: 714227569Sphilip EFSYS_PROBE1(fail1, int, rc); 715227569Sphilip 716227569Sphilip return (rc); 717227569Sphilip} 718227569Sphilip 719227569Sphilip __checkReturn int 720227569Sphilipefx_nic_test_registers( 721227569Sphilip __in efx_nic_t *enp, 722227569Sphilip __in efx_register_set_t *rsp, 723227569Sphilip __in size_t count) 724227569Sphilip{ 725227569Sphilip unsigned int bit; 726227569Sphilip efx_oword_t original; 727227569Sphilip efx_oword_t reg; 728227569Sphilip efx_oword_t buf; 729227569Sphilip int rc; 730227569Sphilip 731227569Sphilip while (count > 0) { 732227569Sphilip /* This function is only suitable for registers */ 733227569Sphilip EFSYS_ASSERT(rsp->rows == 1); 734227569Sphilip 735227569Sphilip /* bit sweep on and off */ 736227569Sphilip EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original, 737227569Sphilip B_TRUE); 738227569Sphilip for (bit = 0; bit < 128; bit++) { 739227569Sphilip /* Is this bit in the mask? */ 740227569Sphilip if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit)) 741227569Sphilip continue; 742227569Sphilip 743227569Sphilip /* Test this bit can be set in isolation */ 744227569Sphilip reg = original; 745227569Sphilip EFX_AND_OWORD(reg, rsp->mask); 746227569Sphilip EFX_SET_OWORD_BIT(reg, bit); 747227569Sphilip 748227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, ®, 749227569Sphilip B_TRUE); 750227569Sphilip EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf, 751227569Sphilip B_TRUE); 752227569Sphilip 753227569Sphilip EFX_AND_OWORD(buf, rsp->mask); 754227569Sphilip if (memcmp(®, &buf, sizeof (reg))) { 755227569Sphilip rc = EIO; 756227569Sphilip goto fail1; 757227569Sphilip } 758227569Sphilip 759227569Sphilip /* Test this bit can be cleared in isolation */ 760227569Sphilip EFX_OR_OWORD(reg, rsp->mask); 761227569Sphilip EFX_CLEAR_OWORD_BIT(reg, bit); 762227569Sphilip 763227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, ®, 764227569Sphilip B_TRUE); 765227569Sphilip EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf, 766227569Sphilip B_TRUE); 767227569Sphilip 768227569Sphilip EFX_AND_OWORD(buf, rsp->mask); 769227569Sphilip if (memcmp(®, &buf, sizeof (reg))) { 770227569Sphilip rc = EIO; 771227569Sphilip goto fail2; 772227569Sphilip } 773227569Sphilip } 774227569Sphilip 775227569Sphilip /* Restore the old value */ 776227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, 777227569Sphilip B_TRUE); 778227569Sphilip 779227569Sphilip --count; 780227569Sphilip ++rsp; 781227569Sphilip } 782227569Sphilip 783227569Sphilip return (0); 784227569Sphilip 785227569Sphilipfail2: 786227569Sphilip EFSYS_PROBE(fail2); 787227569Sphilipfail1: 788227569Sphilip EFSYS_PROBE1(fail1, int, rc); 789227569Sphilip 790227569Sphilip /* Restore the old value */ 791227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE); 792227569Sphilip 793227569Sphilip return (rc); 794227569Sphilip} 795227569Sphilip 796227569Sphilip __checkReturn int 797227569Sphilipefx_nic_test_tables( 798227569Sphilip __in efx_nic_t *enp, 799227569Sphilip __in efx_register_set_t *rsp, 800227569Sphilip __in efx_pattern_type_t pattern, 801227569Sphilip __in size_t count) 802227569Sphilip{ 803227569Sphilip efx_sram_pattern_fn_t func; 804227569Sphilip unsigned int index; 805227569Sphilip unsigned int address; 806227569Sphilip efx_oword_t reg; 807227569Sphilip efx_oword_t buf; 808227569Sphilip int rc; 809227569Sphilip 810227569Sphilip EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES); 811227569Sphilip func = __efx_sram_pattern_fns[pattern]; 812227569Sphilip 813227569Sphilip while (count > 0) { 814227569Sphilip /* Write */ 815227569Sphilip address = rsp->address; 816227569Sphilip for (index = 0; index < rsp->rows; ++index) { 817227569Sphilip func(2 * index + 0, B_FALSE, ®.eo_qword[0]); 818227569Sphilip func(2 * index + 1, B_FALSE, ®.eo_qword[1]); 819227569Sphilip EFX_AND_OWORD(reg, rsp->mask); 820227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, address, ®, B_TRUE); 821227569Sphilip 822227569Sphilip address += rsp->step; 823227569Sphilip } 824227569Sphilip 825227569Sphilip /* Read */ 826227569Sphilip address = rsp->address; 827227569Sphilip for (index = 0; index < rsp->rows; ++index) { 828227569Sphilip func(2 * index + 0, B_FALSE, ®.eo_qword[0]); 829227569Sphilip func(2 * index + 1, B_FALSE, ®.eo_qword[1]); 830227569Sphilip EFX_AND_OWORD(reg, rsp->mask); 831227569Sphilip EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE); 832227569Sphilip if (memcmp(®, &buf, sizeof (reg))) { 833227569Sphilip rc = EIO; 834227569Sphilip goto fail1; 835227569Sphilip } 836227569Sphilip 837227569Sphilip address += rsp->step; 838227569Sphilip } 839227569Sphilip 840227569Sphilip ++rsp; 841227569Sphilip --count; 842227569Sphilip } 843227569Sphilip 844227569Sphilip return (0); 845227569Sphilip 846227569Sphilipfail1: 847227569Sphilip EFSYS_PROBE1(fail1, int, rc); 848227569Sphilip 849227569Sphilip return (rc); 850227569Sphilip} 851227569Sphilip 852227569Sphilip#endif /* EFSYS_OPT_DIAG */ 853283514Sarybchik 854283514Sarybchik#if EFSYS_OPT_LOOPBACK 855283514Sarybchik 856283514Sarybchikextern void 857283514Sarybchikefx_loopback_mask( 858283514Sarybchik __in efx_loopback_kind_t loopback_kind, 859283514Sarybchik __out efx_qword_t *maskp) 860283514Sarybchik{ 861283514Sarybchik efx_qword_t mask; 862283514Sarybchik 863283514Sarybchik EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS); 864283514Sarybchik EFSYS_ASSERT(maskp != NULL); 865283514Sarybchik 866283514Sarybchik /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ 867283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); 868283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); 869283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); 870283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); 871283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); 872283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); 873283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); 874283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); 875283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); 876283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); 877283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); 878283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); 879283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); 880283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); 881283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); 882283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); 883283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); 884283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); 885283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT); 886283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS); 887283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS); 888283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR == 889283514Sarybchik EFX_LOOPBACK_XAUI_WS_FAR); 890283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR == 891283514Sarybchik EFX_LOOPBACK_XAUI_WS_NEAR); 892283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS); 893283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS); 894283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR == 895283514Sarybchik EFX_LOOPBACK_XFI_WS_FAR); 896283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS); 897283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT); 898283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR); 899283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR); 900283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS == 901283514Sarybchik EFX_LOOPBACK_PMA_INT_WS); 902283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS == 903283514Sarybchik EFX_LOOPBACK_SD_FEP2_WS); 904283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS == 905283514Sarybchik EFX_LOOPBACK_SD_FEP1_5_WS); 906283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS); 907283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS); 908283514Sarybchik 909283514Sarybchik /* Build bitmask of possible loopback types */ 910283514Sarybchik EFX_ZERO_QWORD(mask); 911283514Sarybchik 912283514Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) || 913283514Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 914283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF); 915283514Sarybchik } 916283514Sarybchik 917283514Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) || 918283514Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 919283514Sarybchik /* 920283514Sarybchik * The "MAC" grouping has historically been used by drivers to 921283514Sarybchik * mean loopbacks supported by on-chip hardware. Keep that 922283514Sarybchik * meaning here, and include on-chip PHY layer loopbacks. 923283514Sarybchik */ 924283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA); 925283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC); 926283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII); 927283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS); 928283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI); 929283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII); 930283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII); 931283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR); 932283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI); 933283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR); 934283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR); 935283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR); 936283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR); 937283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT); 938283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR); 939283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR); 940283514Sarybchik } 941283514Sarybchik 942283514Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) || 943283514Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 944283514Sarybchik /* 945283514Sarybchik * The "PHY" grouping has historically been used by drivers to 946283514Sarybchik * mean loopbacks supported by off-chip hardware. Keep that 947283514Sarybchik * meaning here. 948283514Sarybchik */ 949283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY); 950283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PHY_XS); 951283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS); 952283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD); 953283514Sarybchik } 954283514Sarybchik 955283514Sarybchik *maskp = mask; 956283514Sarybchik} 957283514Sarybchik 958283514Sarybchik__checkReturn int 959283514Sarybchikefx_mcdi_get_loopback_modes( 960283514Sarybchik __in efx_nic_t *enp) 961283514Sarybchik{ 962283514Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 963283514Sarybchik efx_mcdi_req_t req; 964283514Sarybchik uint8_t payload[MAX(MC_CMD_GET_LOOPBACK_MODES_IN_LEN, 965283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_LEN)]; 966283514Sarybchik efx_qword_t mask; 967283514Sarybchik efx_qword_t modes; 968283514Sarybchik int rc; 969283514Sarybchik 970283514Sarybchik (void) memset(payload, 0, sizeof (payload)); 971283514Sarybchik req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES; 972283514Sarybchik req.emr_in_buf = payload; 973283514Sarybchik req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN; 974283514Sarybchik req.emr_out_buf = payload; 975283514Sarybchik req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN; 976283514Sarybchik 977283514Sarybchik efx_mcdi_execute(enp, &req); 978283514Sarybchik 979283514Sarybchik if (req.emr_rc != 0) { 980283514Sarybchik rc = req.emr_rc; 981283514Sarybchik goto fail1; 982283514Sarybchik } 983283514Sarybchik 984283514Sarybchik if (req.emr_out_length_used < 985283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST + 986283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) { 987283514Sarybchik rc = EMSGSIZE; 988283514Sarybchik goto fail2; 989283514Sarybchik } 990283514Sarybchik 991283514Sarybchik /* 992283514Sarybchik * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree 993283514Sarybchik * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link(). 994283514Sarybchik */ 995283514Sarybchik efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask); 996283514Sarybchik 997283514Sarybchik EFX_AND_QWORD(mask, 998283514Sarybchik *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED)); 999283514Sarybchik 1000283514Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M); 1001283514Sarybchik EFX_AND_QWORD(modes, mask); 1002283514Sarybchik encp->enc_loopback_types[EFX_LINK_100FDX] = modes; 1003283514Sarybchik 1004283514Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G); 1005283514Sarybchik EFX_AND_QWORD(modes, mask); 1006283514Sarybchik encp->enc_loopback_types[EFX_LINK_1000FDX] = modes; 1007283514Sarybchik 1008283514Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G); 1009283514Sarybchik EFX_AND_QWORD(modes, mask); 1010283514Sarybchik encp->enc_loopback_types[EFX_LINK_10000FDX] = modes; 1011283514Sarybchik 1012283514Sarybchik if (req.emr_out_length_used >= 1013283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST + 1014283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) { 1015283514Sarybchik /* Response includes 40G loopback modes */ 1016283514Sarybchik modes = 1017283514Sarybchik *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G); 1018283514Sarybchik EFX_AND_QWORD(modes, mask); 1019283514Sarybchik encp->enc_loopback_types[EFX_LINK_40000FDX] = modes; 1020283514Sarybchik } 1021283514Sarybchik 1022283514Sarybchik EFX_ZERO_QWORD(modes); 1023283514Sarybchik EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF); 1024283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]); 1025283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]); 1026283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]); 1027283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]); 1028283514Sarybchik encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes; 1029283514Sarybchik 1030283514Sarybchik return (0); 1031283514Sarybchik 1032283514Sarybchikfail2: 1033283514Sarybchik EFSYS_PROBE(fail2); 1034283514Sarybchikfail1: 1035283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 1036283514Sarybchik 1037283514Sarybchik return (rc); 1038283514Sarybchik} 1039283514Sarybchik 1040283514Sarybchik#endif /* EFSYS_OPT_LOOPBACK */ 1041