efx_nic.c revision 298955
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 298955 2016-05-03 03:41:25Z pfg $"); 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_FALCON 46283514Sarybchik case EFX_PCI_DEVID_FALCON: 47283514Sarybchik *efp = EFX_FAMILY_FALCON; 48283514Sarybchik return (0); 49293731Sarybchik#endif /* EFSYS_OPT_FALCON */ 50293731Sarybchik 51227569Sphilip#if EFSYS_OPT_SIENA 52283514Sarybchik case EFX_PCI_DEVID_SIENA_F1_UNINIT: 53283514Sarybchik /* 54283514Sarybchik * Hardware default for PF0 of uninitialised Siena. 55283514Sarybchik * manftest must be able to cope with this device id. 56283514Sarybchik */ 57283514Sarybchik *efp = EFX_FAMILY_SIENA; 58283514Sarybchik return (0); 59283514Sarybchik 60283514Sarybchik case EFX_PCI_DEVID_BETHPAGE: 61283514Sarybchik case EFX_PCI_DEVID_SIENA: 62283514Sarybchik *efp = EFX_FAMILY_SIENA; 63283514Sarybchik return (0); 64293731Sarybchik#endif /* EFSYS_OPT_SIENA */ 65283514Sarybchik 66283514Sarybchik#if EFSYS_OPT_HUNTINGTON 67283514Sarybchik case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT: 68283514Sarybchik /* 69283514Sarybchik * Hardware default for PF0 of uninitialised Huntington. 70283514Sarybchik * manftest must be able to cope with this device id. 71283514Sarybchik */ 72283514Sarybchik *efp = EFX_FAMILY_HUNTINGTON; 73283514Sarybchik return (0); 74283514Sarybchik 75283514Sarybchik case EFX_PCI_DEVID_FARMINGDALE: 76283514Sarybchik case EFX_PCI_DEVID_GREENPORT: 77283514Sarybchik *efp = EFX_FAMILY_HUNTINGTON; 78283514Sarybchik return (0); 79283514Sarybchik 80283514Sarybchik case EFX_PCI_DEVID_FARMINGDALE_VF: 81283514Sarybchik case EFX_PCI_DEVID_GREENPORT_VF: 82283514Sarybchik *efp = EFX_FAMILY_HUNTINGTON; 83283514Sarybchik return (0); 84293731Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 85293731Sarybchik 86293731Sarybchik#if EFSYS_OPT_MEDFORD 87293731Sarybchik case EFX_PCI_DEVID_MEDFORD_PF_UNINIT: 88293731Sarybchik /* 89293731Sarybchik * Hardware default for PF0 of uninitialised Medford. 90293731Sarybchik * manftest must be able to cope with this device id. 91293731Sarybchik */ 92293731Sarybchik *efp = EFX_FAMILY_MEDFORD; 93293731Sarybchik return (0); 94293731Sarybchik 95293731Sarybchik case EFX_PCI_DEVID_MEDFORD: 96293731Sarybchik *efp = EFX_FAMILY_MEDFORD; 97293731Sarybchik return (0); 98293731Sarybchik 99293731Sarybchik case EFX_PCI_DEVID_MEDFORD_VF: 100293731Sarybchik *efp = EFX_FAMILY_MEDFORD; 101293731Sarybchik return (0); 102293731Sarybchik#endif /* EFSYS_OPT_MEDFORD */ 103293731Sarybchik 104283514Sarybchik default: 105283514Sarybchik break; 106283514Sarybchik } 107227569Sphilip } 108283514Sarybchik 109283514Sarybchik *efp = EFX_FAMILY_INVALID; 110227569Sphilip return (ENOTSUP); 111227569Sphilip} 112227569Sphilip 113227569Sphilip/* 114227569Sphilip * To support clients which aren't provided with any PCI context infer 115227569Sphilip * the hardware family by inspecting the hardware. Obviously the caller 116227569Sphilip * must be damn sure they're really talking to a supported device. 117227569Sphilip */ 118291436Sarybchik __checkReturn efx_rc_t 119227569Sphilipefx_infer_family( 120227569Sphilip __in efsys_bar_t *esbp, 121227569Sphilip __out efx_family_t *efp) 122227569Sphilip{ 123227569Sphilip efx_family_t family; 124227569Sphilip efx_oword_t oword; 125227569Sphilip unsigned int portnum; 126291436Sarybchik efx_rc_t rc; 127227569Sphilip 128227569Sphilip EFSYS_BAR_READO(esbp, FR_AZ_CS_DEBUG_REG_OFST, &oword, B_TRUE); 129227569Sphilip portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM); 130293731Sarybchik if ((portnum == 1) || (portnum == 2)) { 131293731Sarybchik#if EFSYS_OPT_SIENA 132293731Sarybchik family = EFX_FAMILY_SIENA; 133293731Sarybchik goto out; 134293731Sarybchik#endif 135293731Sarybchik } else if (portnum == 0) { 136283514Sarybchik efx_dword_t dword; 137283514Sarybchik uint32_t hw_rev; 138283514Sarybchik 139283514Sarybchik EFSYS_BAR_READD(esbp, ER_DZ_BIU_HW_REV_ID_REG_OFST, &dword, 140283514Sarybchik B_TRUE); 141283514Sarybchik hw_rev = EFX_DWORD_FIELD(dword, ERF_DZ_HW_REV_ID); 142283514Sarybchik if (hw_rev == ER_DZ_BIU_HW_REV_ID_REG_RESET) { 143293731Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 144293731Sarybchik /* 145293731Sarybchik * BIU_HW_REV_ID is the same for Huntington and Medford. 146293731Sarybchik * Assume Huntington, as Medford is very similar. 147293731Sarybchik */ 148283514Sarybchik family = EFX_FAMILY_HUNTINGTON; 149293731Sarybchik goto out; 150283514Sarybchik#endif 151283514Sarybchik } else { 152227569Sphilip#if EFSYS_OPT_FALCON 153283514Sarybchik family = EFX_FAMILY_FALCON; 154293731Sarybchik goto out; 155227569Sphilip#endif 156283514Sarybchik } 157283514Sarybchik } 158293731Sarybchik rc = ENOTSUP; 159293731Sarybchik goto fail1; 160283514Sarybchik 161293731Sarybchikout: 162227569Sphilip if (efp != NULL) 163227569Sphilip *efp = family; 164227569Sphilip return (0); 165227569Sphilip 166227569Sphilipfail1: 167291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 168227569Sphilip 169227569Sphilip return (rc); 170227569Sphilip} 171227569Sphilip 172227569Sphilip#define EFX_BIU_MAGIC0 0x01234567 173227569Sphilip#define EFX_BIU_MAGIC1 0xfedcba98 174227569Sphilip 175291436Sarybchik __checkReturn efx_rc_t 176227569Sphilipefx_nic_biu_test( 177227569Sphilip __in efx_nic_t *enp) 178227569Sphilip{ 179227569Sphilip efx_oword_t oword; 180291436Sarybchik efx_rc_t rc; 181227569Sphilip 182227569Sphilip /* 183227569Sphilip * Write magic values to scratch registers 0 and 1, then 184227569Sphilip * verify that the values were written correctly. Interleave 185227569Sphilip * the accesses to ensure that the BIU is not just reading 186227569Sphilip * back the cached value that was last written. 187227569Sphilip */ 188227569Sphilip EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); 189283514Sarybchik EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); 190227569Sphilip 191227569Sphilip EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); 192283514Sarybchik EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); 193227569Sphilip 194283514Sarybchik EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); 195227569Sphilip if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { 196227569Sphilip rc = EIO; 197227569Sphilip goto fail1; 198227569Sphilip } 199227569Sphilip 200283514Sarybchik EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); 201227569Sphilip if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { 202227569Sphilip rc = EIO; 203227569Sphilip goto fail2; 204227569Sphilip } 205227569Sphilip 206227569Sphilip /* 207227569Sphilip * Perform the same test, with the values swapped. This 208227569Sphilip * ensures that subsequent tests don't start with the correct 209227569Sphilip * values already written into the scratch registers. 210227569Sphilip */ 211227569Sphilip EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); 212283514Sarybchik EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); 213227569Sphilip 214227569Sphilip EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); 215283514Sarybchik EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); 216227569Sphilip 217283514Sarybchik EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); 218227569Sphilip if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { 219227569Sphilip rc = EIO; 220227569Sphilip goto fail3; 221227569Sphilip } 222227569Sphilip 223283514Sarybchik EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); 224227569Sphilip if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { 225227569Sphilip rc = EIO; 226227569Sphilip goto fail4; 227227569Sphilip } 228227569Sphilip 229227569Sphilip return (0); 230227569Sphilip 231227569Sphilipfail4: 232227569Sphilip EFSYS_PROBE(fail4); 233227569Sphilipfail3: 234227569Sphilip EFSYS_PROBE(fail3); 235227569Sphilipfail2: 236227569Sphilip EFSYS_PROBE(fail2); 237227569Sphilipfail1: 238291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 239227569Sphilip 240227569Sphilip return (rc); 241227569Sphilip} 242227569Sphilip 243227569Sphilip#if EFSYS_OPT_FALCON 244227569Sphilip 245283514Sarybchikstatic efx_nic_ops_t __efx_nic_falcon_ops = { 246227569Sphilip falcon_nic_probe, /* eno_probe */ 247293887Sarybchik NULL, /* eno_board_cfg */ 248283514Sarybchik NULL, /* eno_set_drv_limits */ 249227569Sphilip falcon_nic_reset, /* eno_reset */ 250227569Sphilip falcon_nic_init, /* eno_init */ 251283514Sarybchik NULL, /* eno_get_vi_pool */ 252283514Sarybchik NULL, /* eno_get_bar_region */ 253227569Sphilip#if EFSYS_OPT_DIAG 254227569Sphilip falcon_sram_test, /* eno_sram_test */ 255227569Sphilip falcon_nic_register_test, /* eno_register_test */ 256227569Sphilip#endif /* EFSYS_OPT_DIAG */ 257227569Sphilip falcon_nic_fini, /* eno_fini */ 258227569Sphilip falcon_nic_unprobe, /* eno_unprobe */ 259227569Sphilip}; 260227569Sphilip 261227569Sphilip#endif /* EFSYS_OPT_FALCON */ 262227569Sphilip 263227569Sphilip#if EFSYS_OPT_SIENA 264227569Sphilip 265283514Sarybchikstatic efx_nic_ops_t __efx_nic_siena_ops = { 266227569Sphilip siena_nic_probe, /* eno_probe */ 267293887Sarybchik NULL, /* eno_board_cfg */ 268283514Sarybchik NULL, /* eno_set_drv_limits */ 269227569Sphilip siena_nic_reset, /* eno_reset */ 270227569Sphilip siena_nic_init, /* eno_init */ 271283514Sarybchik NULL, /* eno_get_vi_pool */ 272283514Sarybchik NULL, /* eno_get_bar_region */ 273227569Sphilip#if EFSYS_OPT_DIAG 274227569Sphilip siena_sram_test, /* eno_sram_test */ 275227569Sphilip siena_nic_register_test, /* eno_register_test */ 276227569Sphilip#endif /* EFSYS_OPT_DIAG */ 277227569Sphilip siena_nic_fini, /* eno_fini */ 278227569Sphilip siena_nic_unprobe, /* eno_unprobe */ 279227569Sphilip}; 280227569Sphilip 281227569Sphilip#endif /* EFSYS_OPT_SIENA */ 282227569Sphilip 283283514Sarybchik#if EFSYS_OPT_HUNTINGTON 284283514Sarybchik 285283514Sarybchikstatic efx_nic_ops_t __efx_nic_hunt_ops = { 286293805Sarybchik ef10_nic_probe, /* eno_probe */ 287293887Sarybchik hunt_board_cfg, /* eno_board_cfg */ 288293805Sarybchik ef10_nic_set_drv_limits, /* eno_set_drv_limits */ 289293805Sarybchik ef10_nic_reset, /* eno_reset */ 290293805Sarybchik ef10_nic_init, /* eno_init */ 291293805Sarybchik ef10_nic_get_vi_pool, /* eno_get_vi_pool */ 292293805Sarybchik ef10_nic_get_bar_region, /* eno_get_bar_region */ 293283514Sarybchik#if EFSYS_OPT_DIAG 294293750Sarybchik ef10_sram_test, /* eno_sram_test */ 295293805Sarybchik ef10_nic_register_test, /* eno_register_test */ 296283514Sarybchik#endif /* EFSYS_OPT_DIAG */ 297293805Sarybchik ef10_nic_fini, /* eno_fini */ 298293805Sarybchik ef10_nic_unprobe, /* eno_unprobe */ 299283514Sarybchik}; 300283514Sarybchik 301283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 302283514Sarybchik 303293887Sarybchik#if EFSYS_OPT_MEDFORD 304293887Sarybchik 305293887Sarybchikstatic efx_nic_ops_t __efx_nic_medford_ops = { 306293887Sarybchik ef10_nic_probe, /* eno_probe */ 307293887Sarybchik medford_board_cfg, /* eno_board_cfg */ 308293887Sarybchik ef10_nic_set_drv_limits, /* eno_set_drv_limits */ 309293887Sarybchik ef10_nic_reset, /* eno_reset */ 310293887Sarybchik ef10_nic_init, /* eno_init */ 311293887Sarybchik ef10_nic_get_vi_pool, /* eno_get_vi_pool */ 312293887Sarybchik ef10_nic_get_bar_region, /* eno_get_bar_region */ 313293887Sarybchik#if EFSYS_OPT_DIAG 314293887Sarybchik ef10_sram_test, /* eno_sram_test */ 315293887Sarybchik ef10_nic_register_test, /* eno_register_test */ 316293887Sarybchik#endif /* EFSYS_OPT_DIAG */ 317293887Sarybchik ef10_nic_fini, /* eno_fini */ 318293887Sarybchik ef10_nic_unprobe, /* eno_unprobe */ 319293887Sarybchik}; 320293887Sarybchik 321293887Sarybchik#endif /* EFSYS_OPT_MEDFORD */ 322293887Sarybchik 323293887Sarybchik 324291436Sarybchik __checkReturn efx_rc_t 325227569Sphilipefx_nic_create( 326227569Sphilip __in efx_family_t family, 327227569Sphilip __in efsys_identifier_t *esip, 328227569Sphilip __in efsys_bar_t *esbp, 329227569Sphilip __in efsys_lock_t *eslp, 330227569Sphilip __deref_out efx_nic_t **enpp) 331227569Sphilip{ 332227569Sphilip efx_nic_t *enp; 333291436Sarybchik efx_rc_t rc; 334227569Sphilip 335227569Sphilip EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID); 336227569Sphilip EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES); 337227569Sphilip 338227569Sphilip /* Allocate a NIC object */ 339227569Sphilip EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp); 340227569Sphilip 341227569Sphilip if (enp == NULL) { 342227569Sphilip rc = ENOMEM; 343227569Sphilip goto fail1; 344227569Sphilip } 345227569Sphilip 346227569Sphilip enp->en_magic = EFX_NIC_MAGIC; 347227569Sphilip 348227569Sphilip switch (family) { 349227569Sphilip#if EFSYS_OPT_FALCON 350227569Sphilip case EFX_FAMILY_FALCON: 351227569Sphilip enp->en_enop = (efx_nic_ops_t *)&__efx_nic_falcon_ops; 352227569Sphilip enp->en_features = 0; 353227569Sphilip break; 354227569Sphilip#endif /* EFSYS_OPT_FALCON */ 355227569Sphilip 356227569Sphilip#if EFSYS_OPT_SIENA 357227569Sphilip case EFX_FAMILY_SIENA: 358227569Sphilip enp->en_enop = (efx_nic_ops_t *)&__efx_nic_siena_ops; 359279141Sarybchik enp->en_features = 360279141Sarybchik EFX_FEATURE_IPV6 | 361227569Sphilip EFX_FEATURE_LFSR_HASH_INSERT | 362279141Sarybchik EFX_FEATURE_LINK_EVENTS | 363279141Sarybchik EFX_FEATURE_PERIODIC_MAC_STATS | 364279141Sarybchik EFX_FEATURE_WOL | 365279141Sarybchik EFX_FEATURE_MCDI | 366278839Sarybchik EFX_FEATURE_LOOKAHEAD_SPLIT | 367283514Sarybchik EFX_FEATURE_MAC_HEADER_FILTERS | 368283514Sarybchik EFX_FEATURE_TX_SRC_FILTERS; 369227569Sphilip break; 370227569Sphilip#endif /* EFSYS_OPT_SIENA */ 371227569Sphilip 372283514Sarybchik#if EFSYS_OPT_HUNTINGTON 373283514Sarybchik case EFX_FAMILY_HUNTINGTON: 374283514Sarybchik enp->en_enop = (efx_nic_ops_t *)&__efx_nic_hunt_ops; 375283514Sarybchik /* FIXME: Add WOL support */ 376283514Sarybchik enp->en_features = 377283514Sarybchik EFX_FEATURE_IPV6 | 378283514Sarybchik EFX_FEATURE_LINK_EVENTS | 379283514Sarybchik EFX_FEATURE_PERIODIC_MAC_STATS | 380283514Sarybchik EFX_FEATURE_MCDI | 381283514Sarybchik EFX_FEATURE_MAC_HEADER_FILTERS | 382283514Sarybchik EFX_FEATURE_MCDI_DMA | 383283514Sarybchik EFX_FEATURE_PIO_BUFFERS | 384293891Sarybchik EFX_FEATURE_FW_ASSISTED_TSO | 385293891Sarybchik EFX_FEATURE_FW_ASSISTED_TSO_V2; 386283514Sarybchik break; 387283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 388283514Sarybchik 389293887Sarybchik#if EFSYS_OPT_MEDFORD 390293887Sarybchik case EFX_FAMILY_MEDFORD: 391293887Sarybchik enp->en_enop = (efx_nic_ops_t *)&__efx_nic_medford_ops; 392293887Sarybchik /* 393298955Spfg * FW_ASSISTED_TSO omitted as Medford only supports firmware 394293887Sarybchik * assisted TSO version 2, not the v1 scheme used on Huntington. 395293887Sarybchik */ 396293887Sarybchik enp->en_features = 397293887Sarybchik EFX_FEATURE_IPV6 | 398293887Sarybchik EFX_FEATURE_LINK_EVENTS | 399293887Sarybchik EFX_FEATURE_PERIODIC_MAC_STATS | 400293887Sarybchik EFX_FEATURE_MCDI | 401293887Sarybchik EFX_FEATURE_MAC_HEADER_FILTERS | 402293887Sarybchik EFX_FEATURE_MCDI_DMA | 403293887Sarybchik EFX_FEATURE_PIO_BUFFERS; 404293887Sarybchik break; 405293887Sarybchik#endif /* EFSYS_OPT_MEDFORD */ 406293887Sarybchik 407227569Sphilip default: 408227569Sphilip rc = ENOTSUP; 409227569Sphilip goto fail2; 410227569Sphilip } 411227569Sphilip 412227569Sphilip enp->en_family = family; 413227569Sphilip enp->en_esip = esip; 414227569Sphilip enp->en_esbp = esbp; 415227569Sphilip enp->en_eslp = eslp; 416227569Sphilip 417227569Sphilip *enpp = enp; 418227569Sphilip 419227569Sphilip return (0); 420227569Sphilip 421227569Sphilipfail2: 422283514Sarybchik EFSYS_PROBE(fail2); 423227569Sphilip 424227569Sphilip enp->en_magic = 0; 425227569Sphilip 426227569Sphilip /* Free the NIC object */ 427227569Sphilip EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); 428227569Sphilip 429227569Sphilipfail1: 430291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 431227569Sphilip 432227569Sphilip return (rc); 433227569Sphilip} 434227569Sphilip 435291436Sarybchik __checkReturn efx_rc_t 436227569Sphilipefx_nic_probe( 437227569Sphilip __in efx_nic_t *enp) 438227569Sphilip{ 439227569Sphilip efx_nic_ops_t *enop; 440291436Sarybchik efx_rc_t rc; 441227569Sphilip 442227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 443227569Sphilip#if EFSYS_OPT_MCDI 444227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 445227569Sphilip#endif /* EFSYS_OPT_MCDI */ 446227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE)); 447227569Sphilip 448227569Sphilip enop = enp->en_enop; 449227569Sphilip if ((rc = enop->eno_probe(enp)) != 0) 450283514Sarybchik goto fail1; 451227569Sphilip 452227569Sphilip if ((rc = efx_phy_probe(enp)) != 0) 453283514Sarybchik goto fail2; 454227569Sphilip 455227569Sphilip enp->en_mod_flags |= EFX_MOD_PROBE; 456227569Sphilip 457227569Sphilip return (0); 458227569Sphilip 459283514Sarybchikfail2: 460283514Sarybchik EFSYS_PROBE(fail2); 461227569Sphilip 462227569Sphilip enop->eno_unprobe(enp); 463227569Sphilip 464227569Sphilipfail1: 465291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 466227569Sphilip 467227569Sphilip return (rc); 468227569Sphilip} 469227569Sphilip 470227569Sphilip#if EFSYS_OPT_PCIE_TUNE 471227569Sphilip 472291436Sarybchik __checkReturn efx_rc_t 473227569Sphilipefx_nic_pcie_tune( 474227569Sphilip __in efx_nic_t *enp, 475227569Sphilip unsigned int nlanes) 476227569Sphilip{ 477227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 478227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 479227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 480227569Sphilip 481227569Sphilip#if EFSYS_OPT_FALCON 482227569Sphilip if (enp->en_family == EFX_FAMILY_FALCON) 483227569Sphilip return (falcon_nic_pcie_tune(enp, nlanes)); 484227569Sphilip#endif 485227569Sphilip return (ENOTSUP); 486227569Sphilip} 487227569Sphilip 488291436Sarybchik __checkReturn efx_rc_t 489227569Sphilipefx_nic_pcie_extended_sync( 490227569Sphilip __in efx_nic_t *enp) 491227569Sphilip{ 492227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 493227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 494227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 495227569Sphilip 496227569Sphilip#if EFSYS_OPT_SIENA 497227569Sphilip if (enp->en_family == EFX_FAMILY_SIENA) 498227569Sphilip return (siena_nic_pcie_extended_sync(enp)); 499227569Sphilip#endif 500227569Sphilip 501227569Sphilip return (ENOTSUP); 502227569Sphilip} 503227569Sphilip 504227569Sphilip#endif /* EFSYS_OPT_PCIE_TUNE */ 505227569Sphilip 506291436Sarybchik __checkReturn efx_rc_t 507283514Sarybchikefx_nic_set_drv_limits( 508283514Sarybchik __inout efx_nic_t *enp, 509283514Sarybchik __in efx_drv_limits_t *edlp) 510283514Sarybchik{ 511283514Sarybchik efx_nic_ops_t *enop = enp->en_enop; 512291436Sarybchik efx_rc_t rc; 513283514Sarybchik 514283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 515283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 516283514Sarybchik 517283514Sarybchik if (enop->eno_set_drv_limits != NULL) { 518283514Sarybchik if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0) 519283514Sarybchik goto fail1; 520283514Sarybchik } 521283514Sarybchik 522283514Sarybchik return (0); 523283514Sarybchik 524283514Sarybchikfail1: 525291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 526283514Sarybchik 527283514Sarybchik return (rc); 528283514Sarybchik} 529283514Sarybchik 530291436Sarybchik __checkReturn efx_rc_t 531283514Sarybchikefx_nic_get_bar_region( 532283514Sarybchik __in efx_nic_t *enp, 533283514Sarybchik __in efx_nic_region_t region, 534283514Sarybchik __out uint32_t *offsetp, 535283514Sarybchik __out size_t *sizep) 536283514Sarybchik{ 537283514Sarybchik efx_nic_ops_t *enop = enp->en_enop; 538291436Sarybchik efx_rc_t rc; 539283514Sarybchik 540283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 541283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 542283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 543283514Sarybchik 544283514Sarybchik if (enop->eno_get_bar_region == NULL) { 545283514Sarybchik rc = ENOTSUP; 546283514Sarybchik goto fail1; 547283514Sarybchik } 548283514Sarybchik if ((rc = (enop->eno_get_bar_region)(enp, 549283514Sarybchik region, offsetp, sizep)) != 0) { 550283514Sarybchik goto fail2; 551283514Sarybchik } 552283514Sarybchik 553283514Sarybchik return (0); 554283514Sarybchik 555283514Sarybchikfail2: 556283514Sarybchik EFSYS_PROBE(fail2); 557283514Sarybchik 558283514Sarybchikfail1: 559291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 560283514Sarybchik 561283514Sarybchik return (rc); 562283514Sarybchik} 563283514Sarybchik 564283514Sarybchik 565291436Sarybchik __checkReturn efx_rc_t 566283514Sarybchikefx_nic_get_vi_pool( 567283514Sarybchik __in efx_nic_t *enp, 568283514Sarybchik __out uint32_t *evq_countp, 569283514Sarybchik __out uint32_t *rxq_countp, 570283514Sarybchik __out uint32_t *txq_countp) 571283514Sarybchik{ 572283514Sarybchik efx_nic_ops_t *enop = enp->en_enop; 573283514Sarybchik efx_nic_cfg_t *encp = &enp->en_nic_cfg; 574291436Sarybchik efx_rc_t rc; 575283514Sarybchik 576283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 577283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 578283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 579283514Sarybchik 580283514Sarybchik if (enop->eno_get_vi_pool != NULL) { 581283514Sarybchik uint32_t vi_count = 0; 582283514Sarybchik 583283514Sarybchik if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0) 584283514Sarybchik goto fail1; 585283514Sarybchik 586283514Sarybchik *evq_countp = vi_count; 587283514Sarybchik *rxq_countp = vi_count; 588283514Sarybchik *txq_countp = vi_count; 589283514Sarybchik } else { 590283514Sarybchik /* Use NIC limits as default value */ 591283514Sarybchik *evq_countp = encp->enc_evq_limit; 592283514Sarybchik *rxq_countp = encp->enc_rxq_limit; 593283514Sarybchik *txq_countp = encp->enc_txq_limit; 594283514Sarybchik } 595283514Sarybchik 596283514Sarybchik return (0); 597283514Sarybchik 598283514Sarybchikfail1: 599291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 600283514Sarybchik 601283514Sarybchik return (rc); 602283514Sarybchik} 603283514Sarybchik 604283514Sarybchik 605291436Sarybchik __checkReturn efx_rc_t 606227569Sphilipefx_nic_init( 607227569Sphilip __in efx_nic_t *enp) 608227569Sphilip{ 609227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 610291436Sarybchik efx_rc_t rc; 611227569Sphilip 612227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 613227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 614227569Sphilip 615227569Sphilip if (enp->en_mod_flags & EFX_MOD_NIC) { 616227569Sphilip rc = EINVAL; 617227569Sphilip goto fail1; 618227569Sphilip } 619227569Sphilip 620227569Sphilip if ((rc = enop->eno_init(enp)) != 0) 621227569Sphilip goto fail2; 622227569Sphilip 623227569Sphilip enp->en_mod_flags |= EFX_MOD_NIC; 624227569Sphilip 625227569Sphilip return (0); 626227569Sphilip 627227569Sphilipfail2: 628227569Sphilip EFSYS_PROBE(fail2); 629227569Sphilipfail1: 630291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 631227569Sphilip 632227569Sphilip return (rc); 633227569Sphilip} 634227569Sphilip 635227569Sphilip void 636227569Sphilipefx_nic_fini( 637227569Sphilip __in efx_nic_t *enp) 638227569Sphilip{ 639227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 640227569Sphilip 641227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 642227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 643227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC); 644227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); 645227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 646227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 647227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 648227569Sphilip 649227569Sphilip enop->eno_fini(enp); 650227569Sphilip 651227569Sphilip enp->en_mod_flags &= ~EFX_MOD_NIC; 652227569Sphilip} 653227569Sphilip 654227569Sphilip void 655227569Sphilipefx_nic_unprobe( 656227569Sphilip __in efx_nic_t *enp) 657227569Sphilip{ 658227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 659227569Sphilip 660227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 661227569Sphilip#if EFSYS_OPT_MCDI 662227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 663227569Sphilip#endif /* EFSYS_OPT_MCDI */ 664227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 665227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 666227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); 667227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 668227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 669227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 670227569Sphilip 671227569Sphilip efx_phy_unprobe(enp); 672227569Sphilip 673227569Sphilip enop->eno_unprobe(enp); 674227569Sphilip 675227569Sphilip enp->en_mod_flags &= ~EFX_MOD_PROBE; 676227569Sphilip} 677227569Sphilip 678227569Sphilip void 679227569Sphilipefx_nic_destroy( 680227569Sphilip __in efx_nic_t *enp) 681227569Sphilip{ 682227569Sphilip efsys_identifier_t *esip = enp->en_esip; 683227569Sphilip 684227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 685227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); 686227569Sphilip 687227569Sphilip enp->en_family = 0; 688227569Sphilip enp->en_esip = NULL; 689227569Sphilip enp->en_esbp = NULL; 690227569Sphilip enp->en_eslp = NULL; 691227569Sphilip 692227569Sphilip enp->en_enop = NULL; 693227569Sphilip 694227569Sphilip enp->en_magic = 0; 695227569Sphilip 696227569Sphilip /* Free the NIC object */ 697227569Sphilip EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); 698227569Sphilip} 699227569Sphilip 700291436Sarybchik __checkReturn efx_rc_t 701227569Sphilipefx_nic_reset( 702227569Sphilip __in efx_nic_t *enp) 703227569Sphilip{ 704227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 705227569Sphilip unsigned int mod_flags; 706291436Sarybchik efx_rc_t rc; 707227569Sphilip 708227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 709227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 710227569Sphilip /* 711293901Sarybchik * All modules except the MCDI, PROBE, NVRAM, VPD, MON, LIC 712293901Sarybchik * (which we do not reset here) must have been shut down or never 713293901Sarybchik * initialized. 714227569Sphilip * 715227569Sphilip * A rule of thumb here is: If the controller or MC reboots, is *any* 716227569Sphilip * state lost. If it's lost and needs reapplying, then the module 717227569Sphilip * *must* not be initialised during the reset. 718227569Sphilip */ 719227569Sphilip mod_flags = enp->en_mod_flags; 720227569Sphilip mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM | 721293901Sarybchik EFX_MOD_VPD | EFX_MOD_MON | EFX_MOD_LIC); 722227569Sphilip EFSYS_ASSERT3U(mod_flags, ==, 0); 723227569Sphilip if (mod_flags != 0) { 724227569Sphilip rc = EINVAL; 725227569Sphilip goto fail1; 726227569Sphilip } 727227569Sphilip 728227569Sphilip if ((rc = enop->eno_reset(enp)) != 0) 729227569Sphilip goto fail2; 730227569Sphilip 731227569Sphilip enp->en_reset_flags |= EFX_RESET_MAC; 732227569Sphilip 733227569Sphilip return (0); 734227569Sphilip 735227569Sphilipfail2: 736227569Sphilip EFSYS_PROBE(fail2); 737227569Sphilipfail1: 738291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 739227569Sphilip 740227569Sphilip return (rc); 741227569Sphilip} 742227569Sphilip 743227569Sphilip const efx_nic_cfg_t * 744227569Sphilipefx_nic_cfg_get( 745227569Sphilip __in efx_nic_t *enp) 746227569Sphilip{ 747227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 748227569Sphilip 749227569Sphilip return (&(enp->en_nic_cfg)); 750227569Sphilip} 751227569Sphilip 752227569Sphilip#if EFSYS_OPT_DIAG 753227569Sphilip 754291436Sarybchik __checkReturn efx_rc_t 755227569Sphilipefx_nic_register_test( 756227569Sphilip __in efx_nic_t *enp) 757227569Sphilip{ 758227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 759291436Sarybchik efx_rc_t rc; 760227569Sphilip 761227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 762227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 763227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 764227569Sphilip 765227569Sphilip if ((rc = enop->eno_register_test(enp)) != 0) 766227569Sphilip goto fail1; 767227569Sphilip 768227569Sphilip return (0); 769227569Sphilip 770227569Sphilipfail1: 771291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 772227569Sphilip 773227569Sphilip return (rc); 774227569Sphilip} 775227569Sphilip 776291436Sarybchik __checkReturn efx_rc_t 777227569Sphilipefx_nic_test_registers( 778227569Sphilip __in efx_nic_t *enp, 779227569Sphilip __in efx_register_set_t *rsp, 780227569Sphilip __in size_t count) 781227569Sphilip{ 782227569Sphilip unsigned int bit; 783227569Sphilip efx_oword_t original; 784227569Sphilip efx_oword_t reg; 785227569Sphilip efx_oword_t buf; 786291436Sarybchik efx_rc_t rc; 787227569Sphilip 788227569Sphilip while (count > 0) { 789227569Sphilip /* This function is only suitable for registers */ 790227569Sphilip EFSYS_ASSERT(rsp->rows == 1); 791227569Sphilip 792227569Sphilip /* bit sweep on and off */ 793227569Sphilip EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original, 794227569Sphilip B_TRUE); 795227569Sphilip for (bit = 0; bit < 128; bit++) { 796227569Sphilip /* Is this bit in the mask? */ 797227569Sphilip if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit)) 798227569Sphilip continue; 799227569Sphilip 800227569Sphilip /* Test this bit can be set in isolation */ 801227569Sphilip reg = original; 802227569Sphilip EFX_AND_OWORD(reg, rsp->mask); 803227569Sphilip EFX_SET_OWORD_BIT(reg, bit); 804227569Sphilip 805227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, ®, 806227569Sphilip B_TRUE); 807227569Sphilip EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf, 808227569Sphilip B_TRUE); 809227569Sphilip 810227569Sphilip EFX_AND_OWORD(buf, rsp->mask); 811227569Sphilip if (memcmp(®, &buf, sizeof (reg))) { 812227569Sphilip rc = EIO; 813227569Sphilip goto fail1; 814227569Sphilip } 815227569Sphilip 816227569Sphilip /* Test this bit can be cleared in isolation */ 817227569Sphilip EFX_OR_OWORD(reg, rsp->mask); 818227569Sphilip EFX_CLEAR_OWORD_BIT(reg, bit); 819227569Sphilip 820227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, ®, 821227569Sphilip B_TRUE); 822227569Sphilip EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf, 823227569Sphilip B_TRUE); 824227569Sphilip 825227569Sphilip EFX_AND_OWORD(buf, rsp->mask); 826227569Sphilip if (memcmp(®, &buf, sizeof (reg))) { 827227569Sphilip rc = EIO; 828227569Sphilip goto fail2; 829227569Sphilip } 830227569Sphilip } 831227569Sphilip 832227569Sphilip /* Restore the old value */ 833227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, 834227569Sphilip B_TRUE); 835227569Sphilip 836227569Sphilip --count; 837227569Sphilip ++rsp; 838227569Sphilip } 839227569Sphilip 840227569Sphilip return (0); 841227569Sphilip 842227569Sphilipfail2: 843227569Sphilip EFSYS_PROBE(fail2); 844227569Sphilipfail1: 845291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 846227569Sphilip 847227569Sphilip /* Restore the old value */ 848227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE); 849227569Sphilip 850227569Sphilip return (rc); 851227569Sphilip} 852227569Sphilip 853291436Sarybchik __checkReturn efx_rc_t 854227569Sphilipefx_nic_test_tables( 855227569Sphilip __in efx_nic_t *enp, 856227569Sphilip __in efx_register_set_t *rsp, 857227569Sphilip __in efx_pattern_type_t pattern, 858227569Sphilip __in size_t count) 859227569Sphilip{ 860227569Sphilip efx_sram_pattern_fn_t func; 861227569Sphilip unsigned int index; 862227569Sphilip unsigned int address; 863227569Sphilip efx_oword_t reg; 864227569Sphilip efx_oword_t buf; 865291436Sarybchik efx_rc_t rc; 866227569Sphilip 867227569Sphilip EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES); 868227569Sphilip func = __efx_sram_pattern_fns[pattern]; 869227569Sphilip 870227569Sphilip while (count > 0) { 871227569Sphilip /* Write */ 872227569Sphilip address = rsp->address; 873227569Sphilip for (index = 0; index < rsp->rows; ++index) { 874227569Sphilip func(2 * index + 0, B_FALSE, ®.eo_qword[0]); 875227569Sphilip func(2 * index + 1, B_FALSE, ®.eo_qword[1]); 876227569Sphilip EFX_AND_OWORD(reg, rsp->mask); 877227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, address, ®, B_TRUE); 878227569Sphilip 879227569Sphilip address += rsp->step; 880227569Sphilip } 881227569Sphilip 882227569Sphilip /* Read */ 883227569Sphilip address = rsp->address; 884227569Sphilip for (index = 0; index < rsp->rows; ++index) { 885227569Sphilip func(2 * index + 0, B_FALSE, ®.eo_qword[0]); 886227569Sphilip func(2 * index + 1, B_FALSE, ®.eo_qword[1]); 887227569Sphilip EFX_AND_OWORD(reg, rsp->mask); 888227569Sphilip EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE); 889227569Sphilip if (memcmp(®, &buf, sizeof (reg))) { 890227569Sphilip rc = EIO; 891227569Sphilip goto fail1; 892227569Sphilip } 893227569Sphilip 894227569Sphilip address += rsp->step; 895227569Sphilip } 896227569Sphilip 897227569Sphilip ++rsp; 898227569Sphilip --count; 899227569Sphilip } 900227569Sphilip 901227569Sphilip return (0); 902227569Sphilip 903227569Sphilipfail1: 904291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 905227569Sphilip 906227569Sphilip return (rc); 907227569Sphilip} 908227569Sphilip 909227569Sphilip#endif /* EFSYS_OPT_DIAG */ 910283514Sarybchik 911283514Sarybchik#if EFSYS_OPT_LOOPBACK 912283514Sarybchik 913283514Sarybchikextern void 914283514Sarybchikefx_loopback_mask( 915283514Sarybchik __in efx_loopback_kind_t loopback_kind, 916283514Sarybchik __out efx_qword_t *maskp) 917283514Sarybchik{ 918283514Sarybchik efx_qword_t mask; 919283514Sarybchik 920283514Sarybchik EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS); 921283514Sarybchik EFSYS_ASSERT(maskp != NULL); 922283514Sarybchik 923283514Sarybchik /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ 924283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); 925283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); 926283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); 927283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); 928283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); 929283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); 930283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); 931283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); 932283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); 933283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); 934283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); 935283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); 936283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); 937283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); 938283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); 939283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); 940283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); 941283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); 942283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT); 943283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS); 944283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS); 945283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR == 946283514Sarybchik EFX_LOOPBACK_XAUI_WS_FAR); 947283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR == 948283514Sarybchik EFX_LOOPBACK_XAUI_WS_NEAR); 949283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS); 950283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS); 951283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR == 952283514Sarybchik EFX_LOOPBACK_XFI_WS_FAR); 953283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS); 954283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT); 955283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR); 956283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR); 957283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS == 958283514Sarybchik EFX_LOOPBACK_PMA_INT_WS); 959283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS == 960283514Sarybchik EFX_LOOPBACK_SD_FEP2_WS); 961283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS == 962283514Sarybchik EFX_LOOPBACK_SD_FEP1_5_WS); 963283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS); 964283514Sarybchik EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS); 965283514Sarybchik 966283514Sarybchik /* Build bitmask of possible loopback types */ 967283514Sarybchik EFX_ZERO_QWORD(mask); 968283514Sarybchik 969283514Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) || 970283514Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 971283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF); 972283514Sarybchik } 973283514Sarybchik 974283514Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) || 975283514Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 976283514Sarybchik /* 977283514Sarybchik * The "MAC" grouping has historically been used by drivers to 978283514Sarybchik * mean loopbacks supported by on-chip hardware. Keep that 979283514Sarybchik * meaning here, and include on-chip PHY layer loopbacks. 980283514Sarybchik */ 981283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA); 982283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC); 983283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII); 984283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS); 985283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI); 986283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII); 987283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII); 988283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR); 989283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI); 990283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR); 991283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR); 992283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR); 993283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR); 994283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT); 995283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR); 996283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR); 997283514Sarybchik } 998283514Sarybchik 999283514Sarybchik if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) || 1000283514Sarybchik (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { 1001283514Sarybchik /* 1002283514Sarybchik * The "PHY" grouping has historically been used by drivers to 1003283514Sarybchik * mean loopbacks supported by off-chip hardware. Keep that 1004283514Sarybchik * meaning here. 1005283514Sarybchik */ 1006283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY); 1007283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PHY_XS); 1008283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS); 1009283514Sarybchik EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD); 1010283514Sarybchik } 1011283514Sarybchik 1012283514Sarybchik *maskp = mask; 1013283514Sarybchik} 1014283514Sarybchik 1015291436Sarybchik __checkReturn efx_rc_t 1016283514Sarybchikefx_mcdi_get_loopback_modes( 1017283514Sarybchik __in efx_nic_t *enp) 1018283514Sarybchik{ 1019283514Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1020283514Sarybchik efx_mcdi_req_t req; 1021283514Sarybchik uint8_t payload[MAX(MC_CMD_GET_LOOPBACK_MODES_IN_LEN, 1022283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_LEN)]; 1023283514Sarybchik efx_qword_t mask; 1024283514Sarybchik efx_qword_t modes; 1025291436Sarybchik efx_rc_t rc; 1026283514Sarybchik 1027283514Sarybchik (void) memset(payload, 0, sizeof (payload)); 1028283514Sarybchik req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES; 1029283514Sarybchik req.emr_in_buf = payload; 1030283514Sarybchik req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN; 1031283514Sarybchik req.emr_out_buf = payload; 1032283514Sarybchik req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN; 1033283514Sarybchik 1034283514Sarybchik efx_mcdi_execute(enp, &req); 1035283514Sarybchik 1036283514Sarybchik if (req.emr_rc != 0) { 1037283514Sarybchik rc = req.emr_rc; 1038283514Sarybchik goto fail1; 1039283514Sarybchik } 1040283514Sarybchik 1041283514Sarybchik if (req.emr_out_length_used < 1042283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST + 1043283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) { 1044283514Sarybchik rc = EMSGSIZE; 1045283514Sarybchik goto fail2; 1046283514Sarybchik } 1047283514Sarybchik 1048283514Sarybchik /* 1049283514Sarybchik * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree 1050283514Sarybchik * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link(). 1051283514Sarybchik */ 1052283514Sarybchik efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask); 1053283514Sarybchik 1054283514Sarybchik EFX_AND_QWORD(mask, 1055283514Sarybchik *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED)); 1056283514Sarybchik 1057283514Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M); 1058283514Sarybchik EFX_AND_QWORD(modes, mask); 1059283514Sarybchik encp->enc_loopback_types[EFX_LINK_100FDX] = modes; 1060283514Sarybchik 1061283514Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G); 1062283514Sarybchik EFX_AND_QWORD(modes, mask); 1063283514Sarybchik encp->enc_loopback_types[EFX_LINK_1000FDX] = modes; 1064283514Sarybchik 1065283514Sarybchik modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G); 1066283514Sarybchik EFX_AND_QWORD(modes, mask); 1067283514Sarybchik encp->enc_loopback_types[EFX_LINK_10000FDX] = modes; 1068283514Sarybchik 1069283514Sarybchik if (req.emr_out_length_used >= 1070283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST + 1071283514Sarybchik MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) { 1072283514Sarybchik /* Response includes 40G loopback modes */ 1073283514Sarybchik modes = 1074283514Sarybchik *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G); 1075283514Sarybchik EFX_AND_QWORD(modes, mask); 1076283514Sarybchik encp->enc_loopback_types[EFX_LINK_40000FDX] = modes; 1077283514Sarybchik } 1078283514Sarybchik 1079283514Sarybchik EFX_ZERO_QWORD(modes); 1080283514Sarybchik EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF); 1081283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]); 1082283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]); 1083283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]); 1084283514Sarybchik EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]); 1085283514Sarybchik encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes; 1086283514Sarybchik 1087283514Sarybchik return (0); 1088283514Sarybchik 1089283514Sarybchikfail2: 1090283514Sarybchik EFSYS_PROBE(fail2); 1091283514Sarybchikfail1: 1092291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1093283514Sarybchik 1094283514Sarybchik return (rc); 1095283514Sarybchik} 1096283514Sarybchik 1097283514Sarybchik#endif /* EFSYS_OPT_LOOPBACK */ 1098