1227569Sphilip/*- 2227569Sphilip * Copyright 2007-2009 Solarflare Communications Inc. All rights reserved. 3227569Sphilip * 4227569Sphilip * Redistribution and use in source and binary forms, with or without 5227569Sphilip * modification, are permitted provided that the following conditions 6227569Sphilip * are met: 7227569Sphilip * 1. Redistributions of source code must retain the above copyright 8227569Sphilip * notice, this list of conditions and the following disclaimer. 9227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright 10227569Sphilip * notice, this list of conditions and the following disclaimer in the 11227569Sphilip * documentation and/or other materials provided with the distribution. 12227569Sphilip * 13227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND 14227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16227569Sphilip * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23227569Sphilip * SUCH DAMAGE. 24227569Sphilip */ 25227569Sphilip 26228100Sphilip#include <sys/cdefs.h> 27228100Sphilip__FBSDID("$FreeBSD$"); 28228100Sphilip 29227569Sphilip#include "efsys.h" 30227569Sphilip#include "efx.h" 31227569Sphilip#include "efx_types.h" 32227569Sphilip#include "efx_regs.h" 33227569Sphilip#include "efx_impl.h" 34227569Sphilip 35227569Sphilip __checkReturn int 36227569Sphilipefx_family( 37227569Sphilip __in uint16_t venid, 38227569Sphilip __in uint16_t devid, 39227569Sphilip __out efx_family_t *efp) 40227569Sphilip{ 41227569Sphilip#if EFSYS_OPT_FALCON 42227569Sphilip if (venid == EFX_PCI_VENID_SFC && devid == EFX_PCI_DEVID_FALCON) { 43227569Sphilip *efp = EFX_FAMILY_FALCON; 44227569Sphilip return (0); 45227569Sphilip } 46227569Sphilip#endif 47227569Sphilip#if EFSYS_OPT_SIENA 48227569Sphilip if (venid == EFX_PCI_VENID_SFC && devid == EFX_PCI_DEVID_BETHPAGE) { 49227569Sphilip *efp = EFX_FAMILY_SIENA; 50227569Sphilip return (0); 51227569Sphilip } 52227569Sphilip if (venid == EFX_PCI_VENID_SFC && devid == EFX_PCI_DEVID_SIENA) { 53227569Sphilip *efp = EFX_FAMILY_SIENA; 54227569Sphilip return (0); 55227569Sphilip } 56227569Sphilip if (venid == EFX_PCI_VENID_SFC && 57227569Sphilip devid == EFX_PCI_DEVID_SIENA_F1_UNINIT) { 58227569Sphilip *efp = EFX_FAMILY_SIENA; 59227569Sphilip return (0); 60227569Sphilip } 61227569Sphilip#endif 62227569Sphilip return (ENOTSUP); 63227569Sphilip} 64227569Sphilip 65227569Sphilip/* 66227569Sphilip * To support clients which aren't provided with any PCI context infer 67227569Sphilip * the hardware family by inspecting the hardware. Obviously the caller 68227569Sphilip * must be damn sure they're really talking to a supported device. 69227569Sphilip */ 70227569Sphilip __checkReturn int 71227569Sphilipefx_infer_family( 72227569Sphilip __in efsys_bar_t *esbp, 73227569Sphilip __out efx_family_t *efp) 74227569Sphilip{ 75227569Sphilip efx_family_t family; 76227569Sphilip efx_oword_t oword; 77227569Sphilip unsigned int portnum; 78227569Sphilip int rc; 79227569Sphilip 80227569Sphilip EFSYS_BAR_READO(esbp, FR_AZ_CS_DEBUG_REG_OFST, &oword, B_TRUE); 81227569Sphilip portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM); 82227569Sphilip switch (portnum) { 83227569Sphilip#if EFSYS_OPT_FALCON 84227569Sphilip case 0: 85227569Sphilip family = EFX_FAMILY_FALCON; 86227569Sphilip break; 87227569Sphilip#endif 88227569Sphilip#if EFSYS_OPT_SIENA 89227569Sphilip case 1: 90227569Sphilip case 2: 91227569Sphilip family = EFX_FAMILY_SIENA; 92227569Sphilip break; 93227569Sphilip#endif 94227569Sphilip default: 95227569Sphilip rc = ENOTSUP; 96227569Sphilip goto fail1; 97227569Sphilip } 98227569Sphilip 99227569Sphilip if (efp != NULL) 100227569Sphilip *efp = family; 101227569Sphilip return (0); 102227569Sphilip 103227569Sphilipfail1: 104227569Sphilip EFSYS_PROBE1(fail1, int, rc); 105227569Sphilip 106227569Sphilip return (rc); 107227569Sphilip} 108227569Sphilip 109227569Sphilip/* 110227569Sphilip * The built-in default value device id for port 1 of Siena is 0x0810. 111227569Sphilip * manftest needs to be able to cope with that. 112227569Sphilip */ 113227569Sphilip 114227569Sphilip#define EFX_BIU_MAGIC0 0x01234567 115227569Sphilip#define EFX_BIU_MAGIC1 0xfedcba98 116227569Sphilip 117227569Sphilipstatic __checkReturn int 118227569Sphilipefx_nic_biu_test( 119227569Sphilip __in efx_nic_t *enp) 120227569Sphilip{ 121227569Sphilip efx_oword_t oword; 122227569Sphilip int rc; 123227569Sphilip 124227569Sphilip /* 125227569Sphilip * Write magic values to scratch registers 0 and 1, then 126227569Sphilip * verify that the values were written correctly. Interleave 127227569Sphilip * the accesses to ensure that the BIU is not just reading 128227569Sphilip * back the cached value that was last written. 129227569Sphilip */ 130227569Sphilip EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); 131227569Sphilip EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword); 132227569Sphilip 133227569Sphilip EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); 134227569Sphilip EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword); 135227569Sphilip 136227569Sphilip EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword); 137227569Sphilip if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { 138227569Sphilip rc = EIO; 139227569Sphilip goto fail1; 140227569Sphilip } 141227569Sphilip 142227569Sphilip EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword); 143227569Sphilip if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { 144227569Sphilip rc = EIO; 145227569Sphilip goto fail2; 146227569Sphilip } 147227569Sphilip 148227569Sphilip /* 149227569Sphilip * Perform the same test, with the values swapped. This 150227569Sphilip * ensures that subsequent tests don't start with the correct 151227569Sphilip * values already written into the scratch registers. 152227569Sphilip */ 153227569Sphilip EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); 154227569Sphilip EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword); 155227569Sphilip 156227569Sphilip EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); 157227569Sphilip EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword); 158227569Sphilip 159227569Sphilip EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword); 160227569Sphilip if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { 161227569Sphilip rc = EIO; 162227569Sphilip goto fail3; 163227569Sphilip } 164227569Sphilip 165227569Sphilip EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword); 166227569Sphilip if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { 167227569Sphilip rc = EIO; 168227569Sphilip goto fail4; 169227569Sphilip } 170227569Sphilip 171227569Sphilip return (0); 172227569Sphilip 173227569Sphilipfail4: 174227569Sphilip EFSYS_PROBE(fail4); 175227569Sphilipfail3: 176227569Sphilip EFSYS_PROBE(fail3); 177227569Sphilipfail2: 178227569Sphilip EFSYS_PROBE(fail2); 179227569Sphilipfail1: 180227569Sphilip EFSYS_PROBE1(fail1, int, rc); 181227569Sphilip 182227569Sphilip return (rc); 183227569Sphilip} 184227569Sphilip 185227569Sphilip#if EFSYS_OPT_FALCON 186227569Sphilip 187227569Sphilipstatic efx_nic_ops_t __cs __efx_nic_falcon_ops = { 188227569Sphilip falcon_nic_probe, /* eno_probe */ 189227569Sphilip falcon_nic_reset, /* eno_reset */ 190227569Sphilip falcon_nic_init, /* eno_init */ 191227569Sphilip#if EFSYS_OPT_DIAG 192227569Sphilip falcon_sram_test, /* eno_sram_test */ 193227569Sphilip falcon_nic_register_test, /* eno_register_test */ 194227569Sphilip#endif /* EFSYS_OPT_DIAG */ 195227569Sphilip falcon_nic_fini, /* eno_fini */ 196227569Sphilip falcon_nic_unprobe, /* eno_unprobe */ 197227569Sphilip}; 198227569Sphilip 199227569Sphilip#endif /* EFSYS_OPT_FALCON */ 200227569Sphilip 201227569Sphilip#if EFSYS_OPT_SIENA 202227569Sphilip 203227569Sphilipstatic efx_nic_ops_t __cs __efx_nic_siena_ops = { 204227569Sphilip siena_nic_probe, /* eno_probe */ 205227569Sphilip siena_nic_reset, /* eno_reset */ 206227569Sphilip siena_nic_init, /* eno_init */ 207227569Sphilip#if EFSYS_OPT_DIAG 208227569Sphilip siena_sram_test, /* eno_sram_test */ 209227569Sphilip siena_nic_register_test, /* eno_register_test */ 210227569Sphilip#endif /* EFSYS_OPT_DIAG */ 211227569Sphilip siena_nic_fini, /* eno_fini */ 212227569Sphilip siena_nic_unprobe, /* eno_unprobe */ 213227569Sphilip}; 214227569Sphilip 215227569Sphilip#endif /* EFSYS_OPT_SIENA */ 216227569Sphilip 217227569Sphilip __checkReturn int 218227569Sphilipefx_nic_create( 219227569Sphilip __in efx_family_t family, 220227569Sphilip __in efsys_identifier_t *esip, 221227569Sphilip __in efsys_bar_t *esbp, 222227569Sphilip __in efsys_lock_t *eslp, 223227569Sphilip __deref_out efx_nic_t **enpp) 224227569Sphilip{ 225227569Sphilip efx_nic_t *enp; 226227569Sphilip int rc; 227227569Sphilip 228227569Sphilip EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID); 229227569Sphilip EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES); 230227569Sphilip 231227569Sphilip /* Allocate a NIC object */ 232227569Sphilip EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp); 233227569Sphilip 234227569Sphilip if (enp == NULL) { 235227569Sphilip rc = ENOMEM; 236227569Sphilip goto fail1; 237227569Sphilip } 238227569Sphilip 239227569Sphilip enp->en_magic = EFX_NIC_MAGIC; 240227569Sphilip 241227569Sphilip switch (family) { 242227569Sphilip#if EFSYS_OPT_FALCON 243227569Sphilip case EFX_FAMILY_FALCON: 244227569Sphilip enp->en_enop = (efx_nic_ops_t *)&__efx_nic_falcon_ops; 245227569Sphilip enp->en_features = 0; 246227569Sphilip break; 247227569Sphilip#endif /* EFSYS_OPT_FALCON */ 248227569Sphilip 249227569Sphilip#if EFSYS_OPT_SIENA 250227569Sphilip case EFX_FAMILY_SIENA: 251227569Sphilip enp->en_enop = (efx_nic_ops_t *)&__efx_nic_siena_ops; 252227569Sphilip enp->en_features = EFX_FEATURE_IPV6 | 253227569Sphilip EFX_FEATURE_LFSR_HASH_INSERT | 254227569Sphilip EFX_FEATURE_LINK_EVENTS | EFX_FEATURE_PERIODIC_MAC_STATS | 255227569Sphilip EFX_FEATURE_WOL | EFX_FEATURE_MCDI | 256227569Sphilip EFX_FEATURE_LOOKAHEAD_SPLIT | EFX_FEATURE_MAC_HEADER_FILTERS; 257227569Sphilip break; 258227569Sphilip#endif /* EFSYS_OPT_SIENA */ 259227569Sphilip 260227569Sphilip default: 261227569Sphilip rc = ENOTSUP; 262227569Sphilip goto fail2; 263227569Sphilip } 264227569Sphilip 265227569Sphilip enp->en_family = family; 266227569Sphilip enp->en_esip = esip; 267227569Sphilip enp->en_esbp = esbp; 268227569Sphilip enp->en_eslp = eslp; 269227569Sphilip 270227569Sphilip *enpp = enp; 271227569Sphilip 272227569Sphilip return (0); 273227569Sphilip 274227569Sphilipfail2: 275227569Sphilip EFSYS_PROBE(fail3); 276227569Sphilip 277227569Sphilip enp->en_magic = 0; 278227569Sphilip 279227569Sphilip /* Free the NIC object */ 280227569Sphilip EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); 281227569Sphilip 282227569Sphilipfail1: 283227569Sphilip EFSYS_PROBE1(fail1, int, rc); 284227569Sphilip 285227569Sphilip return (rc); 286227569Sphilip} 287227569Sphilip 288227569Sphilip __checkReturn int 289227569Sphilipefx_nic_probe( 290227569Sphilip __in efx_nic_t *enp) 291227569Sphilip{ 292227569Sphilip efx_nic_ops_t *enop; 293227569Sphilip efx_oword_t oword; 294227569Sphilip int rc; 295227569Sphilip 296227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 297227569Sphilip#if EFSYS_OPT_MCDI 298227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 299227569Sphilip#endif /* EFSYS_OPT_MCDI */ 300227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE)); 301227569Sphilip 302227569Sphilip /* Test BIU */ 303227569Sphilip if ((rc = efx_nic_biu_test(enp)) != 0) 304227569Sphilip goto fail1; 305227569Sphilip 306227569Sphilip /* Clear the region register */ 307227569Sphilip EFX_POPULATE_OWORD_4(oword, 308227569Sphilip FRF_AZ_ADR_REGION0, 0, 309227569Sphilip FRF_AZ_ADR_REGION1, (1 << 16), 310227569Sphilip FRF_AZ_ADR_REGION2, (2 << 16), 311227569Sphilip FRF_AZ_ADR_REGION3, (3 << 16)); 312227569Sphilip EFX_BAR_WRITEO(enp, FR_AZ_ADR_REGION_REG, &oword); 313227569Sphilip 314227569Sphilip enop = enp->en_enop; 315227569Sphilip if ((rc = enop->eno_probe(enp)) != 0) 316227569Sphilip goto fail2; 317227569Sphilip 318227569Sphilip if ((rc = efx_phy_probe(enp)) != 0) 319227569Sphilip goto fail3; 320227569Sphilip 321227569Sphilip enp->en_mod_flags |= EFX_MOD_PROBE; 322227569Sphilip 323227569Sphilip return (0); 324227569Sphilip 325227569Sphilipfail3: 326227569Sphilip EFSYS_PROBE(fail3); 327227569Sphilip 328227569Sphilip enop->eno_unprobe(enp); 329227569Sphilip 330227569Sphilipfail2: 331227569Sphilip EFSYS_PROBE(fail2); 332227569Sphilipfail1: 333227569Sphilip EFSYS_PROBE1(fail1, int, rc); 334227569Sphilip 335227569Sphilip return (rc); 336227569Sphilip} 337227569Sphilip 338227569Sphilip#if EFSYS_OPT_PCIE_TUNE 339227569Sphilip 340227569Sphilip __checkReturn int 341227569Sphilipefx_nic_pcie_tune( 342227569Sphilip __in efx_nic_t *enp, 343227569Sphilip unsigned int nlanes) 344227569Sphilip{ 345227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 346227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 347227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 348227569Sphilip 349227569Sphilip#if EFSYS_OPT_FALCON 350227569Sphilip if (enp->en_family == EFX_FAMILY_FALCON) 351227569Sphilip return (falcon_nic_pcie_tune(enp, nlanes)); 352227569Sphilip#endif 353227569Sphilip return (ENOTSUP); 354227569Sphilip} 355227569Sphilip 356227569Sphilip __checkReturn int 357227569Sphilipefx_nic_pcie_extended_sync( 358227569Sphilip __in efx_nic_t *enp) 359227569Sphilip{ 360227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 361227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 362227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 363227569Sphilip 364227569Sphilip#if EFSYS_OPT_SIENA 365227569Sphilip if (enp->en_family == EFX_FAMILY_SIENA) 366227569Sphilip return (siena_nic_pcie_extended_sync(enp)); 367227569Sphilip#endif 368227569Sphilip 369227569Sphilip return (ENOTSUP); 370227569Sphilip} 371227569Sphilip 372227569Sphilip#endif /* EFSYS_OPT_PCIE_TUNE */ 373227569Sphilip 374227569Sphilip __checkReturn int 375227569Sphilipefx_nic_init( 376227569Sphilip __in efx_nic_t *enp) 377227569Sphilip{ 378227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 379227569Sphilip int rc; 380227569Sphilip 381227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 382227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 383227569Sphilip 384227569Sphilip if (enp->en_mod_flags & EFX_MOD_NIC) { 385227569Sphilip rc = EINVAL; 386227569Sphilip goto fail1; 387227569Sphilip } 388227569Sphilip 389227569Sphilip if ((rc = enop->eno_init(enp)) != 0) 390227569Sphilip goto fail2; 391227569Sphilip 392227569Sphilip enp->en_mod_flags |= EFX_MOD_NIC; 393227569Sphilip 394227569Sphilip return (0); 395227569Sphilip 396227569Sphilipfail2: 397227569Sphilip EFSYS_PROBE(fail2); 398227569Sphilipfail1: 399227569Sphilip EFSYS_PROBE1(fail1, int, rc); 400227569Sphilip 401227569Sphilip return (rc); 402227569Sphilip} 403227569Sphilip 404227569Sphilip void 405227569Sphilipefx_nic_fini( 406227569Sphilip __in efx_nic_t *enp) 407227569Sphilip{ 408227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 409227569Sphilip 410227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 411227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 412227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC); 413227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); 414227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 415227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 416227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 417227569Sphilip 418227569Sphilip enop->eno_fini(enp); 419227569Sphilip 420227569Sphilip enp->en_mod_flags &= ~EFX_MOD_NIC; 421227569Sphilip} 422227569Sphilip 423227569Sphilip void 424227569Sphilipefx_nic_unprobe( 425227569Sphilip __in efx_nic_t *enp) 426227569Sphilip{ 427227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 428227569Sphilip 429227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 430227569Sphilip#if EFSYS_OPT_MCDI 431227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 432227569Sphilip#endif /* EFSYS_OPT_MCDI */ 433227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 434227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 435227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); 436227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 437227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 438227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 439227569Sphilip 440227569Sphilip efx_phy_unprobe(enp); 441227569Sphilip 442227569Sphilip enop->eno_unprobe(enp); 443227569Sphilip 444227569Sphilip enp->en_mod_flags &= ~EFX_MOD_PROBE; 445227569Sphilip} 446227569Sphilip 447227569Sphilip void 448227569Sphilipefx_nic_destroy( 449227569Sphilip __in efx_nic_t *enp) 450227569Sphilip{ 451227569Sphilip efsys_identifier_t *esip = enp->en_esip; 452227569Sphilip 453227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 454227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); 455227569Sphilip 456227569Sphilip enp->en_family = 0; 457227569Sphilip enp->en_esip = NULL; 458227569Sphilip enp->en_esbp = NULL; 459227569Sphilip enp->en_eslp = NULL; 460227569Sphilip 461227569Sphilip enp->en_enop = NULL; 462227569Sphilip 463227569Sphilip enp->en_magic = 0; 464227569Sphilip 465227569Sphilip /* Free the NIC object */ 466227569Sphilip EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); 467227569Sphilip} 468227569Sphilip 469227569Sphilip __checkReturn int 470227569Sphilipefx_nic_reset( 471227569Sphilip __in efx_nic_t *enp) 472227569Sphilip{ 473227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 474227569Sphilip unsigned int mod_flags; 475227569Sphilip int rc; 476227569Sphilip 477227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 478227569Sphilip EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 479227569Sphilip /* 480227569Sphilip * All modules except the MCDI, PROBE, NVRAM, VPD, MON (which we 481227569Sphilip * do not reset here) must have been shut down or never initialized. 482227569Sphilip * 483227569Sphilip * A rule of thumb here is: If the controller or MC reboots, is *any* 484227569Sphilip * state lost. If it's lost and needs reapplying, then the module 485227569Sphilip * *must* not be initialised during the reset. 486227569Sphilip */ 487227569Sphilip mod_flags = enp->en_mod_flags; 488227569Sphilip mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM | 489227569Sphilip EFX_MOD_VPD | EFX_MOD_MON); 490227569Sphilip EFSYS_ASSERT3U(mod_flags, ==, 0); 491227569Sphilip if (mod_flags != 0) { 492227569Sphilip rc = EINVAL; 493227569Sphilip goto fail1; 494227569Sphilip } 495227569Sphilip 496227569Sphilip if ((rc = enop->eno_reset(enp)) != 0) 497227569Sphilip goto fail2; 498227569Sphilip 499227569Sphilip enp->en_reset_flags |= EFX_RESET_MAC; 500227569Sphilip 501227569Sphilip return (0); 502227569Sphilip 503227569Sphilipfail2: 504227569Sphilip EFSYS_PROBE(fail2); 505227569Sphilipfail1: 506227569Sphilip EFSYS_PROBE1(fail1, int, rc); 507227569Sphilip 508227569Sphilip return (rc); 509227569Sphilip} 510227569Sphilip 511227569Sphilip const efx_nic_cfg_t * 512227569Sphilipefx_nic_cfg_get( 513227569Sphilip __in efx_nic_t *enp) 514227569Sphilip{ 515227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 516227569Sphilip 517227569Sphilip return (&(enp->en_nic_cfg)); 518227569Sphilip} 519227569Sphilip 520227569Sphilip#if EFSYS_OPT_DIAG 521227569Sphilip 522227569Sphilip __checkReturn int 523227569Sphilipefx_nic_register_test( 524227569Sphilip __in efx_nic_t *enp) 525227569Sphilip{ 526227569Sphilip efx_nic_ops_t *enop = enp->en_enop; 527227569Sphilip int rc; 528227569Sphilip 529227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 530227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 531227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 532227569Sphilip 533227569Sphilip if ((rc = enop->eno_register_test(enp)) != 0) 534227569Sphilip goto fail1; 535227569Sphilip 536227569Sphilip return (0); 537227569Sphilip 538227569Sphilipfail1: 539227569Sphilip EFSYS_PROBE1(fail1, int, rc); 540227569Sphilip 541227569Sphilip return (rc); 542227569Sphilip} 543227569Sphilip 544227569Sphilip __checkReturn int 545227569Sphilipefx_nic_test_registers( 546227569Sphilip __in efx_nic_t *enp, 547227569Sphilip __in efx_register_set_t *rsp, 548227569Sphilip __in size_t count) 549227569Sphilip{ 550227569Sphilip unsigned int bit; 551227569Sphilip efx_oword_t original; 552227569Sphilip efx_oword_t reg; 553227569Sphilip efx_oword_t buf; 554227569Sphilip int rc; 555227569Sphilip 556227569Sphilip while (count > 0) { 557227569Sphilip /* This function is only suitable for registers */ 558227569Sphilip EFSYS_ASSERT(rsp->rows == 1); 559227569Sphilip 560227569Sphilip /* bit sweep on and off */ 561227569Sphilip EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original, 562227569Sphilip B_TRUE); 563227569Sphilip for (bit = 0; bit < 128; bit++) { 564227569Sphilip /* Is this bit in the mask? */ 565227569Sphilip if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit)) 566227569Sphilip continue; 567227569Sphilip 568227569Sphilip /* Test this bit can be set in isolation */ 569227569Sphilip reg = original; 570227569Sphilip EFX_AND_OWORD(reg, rsp->mask); 571227569Sphilip EFX_SET_OWORD_BIT(reg, bit); 572227569Sphilip 573227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, ®, 574227569Sphilip B_TRUE); 575227569Sphilip EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf, 576227569Sphilip B_TRUE); 577227569Sphilip 578227569Sphilip EFX_AND_OWORD(buf, rsp->mask); 579227569Sphilip if (memcmp(®, &buf, sizeof (reg))) { 580227569Sphilip rc = EIO; 581227569Sphilip goto fail1; 582227569Sphilip } 583227569Sphilip 584227569Sphilip /* Test this bit can be cleared in isolation */ 585227569Sphilip EFX_OR_OWORD(reg, rsp->mask); 586227569Sphilip EFX_CLEAR_OWORD_BIT(reg, bit); 587227569Sphilip 588227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, ®, 589227569Sphilip B_TRUE); 590227569Sphilip EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf, 591227569Sphilip B_TRUE); 592227569Sphilip 593227569Sphilip EFX_AND_OWORD(buf, rsp->mask); 594227569Sphilip if (memcmp(®, &buf, sizeof (reg))) { 595227569Sphilip rc = EIO; 596227569Sphilip goto fail2; 597227569Sphilip } 598227569Sphilip } 599227569Sphilip 600227569Sphilip /* Restore the old value */ 601227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, 602227569Sphilip B_TRUE); 603227569Sphilip 604227569Sphilip --count; 605227569Sphilip ++rsp; 606227569Sphilip } 607227569Sphilip 608227569Sphilip return (0); 609227569Sphilip 610227569Sphilipfail2: 611227569Sphilip EFSYS_PROBE(fail2); 612227569Sphilipfail1: 613227569Sphilip EFSYS_PROBE1(fail1, int, rc); 614227569Sphilip 615227569Sphilip /* Restore the old value */ 616227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE); 617227569Sphilip 618227569Sphilip return (rc); 619227569Sphilip} 620227569Sphilip 621227569Sphilip __checkReturn int 622227569Sphilipefx_nic_test_tables( 623227569Sphilip __in efx_nic_t *enp, 624227569Sphilip __in efx_register_set_t *rsp, 625227569Sphilip __in efx_pattern_type_t pattern, 626227569Sphilip __in size_t count) 627227569Sphilip{ 628227569Sphilip efx_sram_pattern_fn_t func; 629227569Sphilip unsigned int index; 630227569Sphilip unsigned int address; 631227569Sphilip efx_oword_t reg; 632227569Sphilip efx_oword_t buf; 633227569Sphilip int rc; 634227569Sphilip 635227569Sphilip EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES); 636227569Sphilip func = __efx_sram_pattern_fns[pattern]; 637227569Sphilip 638227569Sphilip while (count > 0) { 639227569Sphilip /* Write */ 640227569Sphilip address = rsp->address; 641227569Sphilip for (index = 0; index < rsp->rows; ++index) { 642227569Sphilip func(2 * index + 0, B_FALSE, ®.eo_qword[0]); 643227569Sphilip func(2 * index + 1, B_FALSE, ®.eo_qword[1]); 644227569Sphilip EFX_AND_OWORD(reg, rsp->mask); 645227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, address, ®, B_TRUE); 646227569Sphilip 647227569Sphilip address += rsp->step; 648227569Sphilip } 649227569Sphilip 650227569Sphilip /* Read */ 651227569Sphilip address = rsp->address; 652227569Sphilip for (index = 0; index < rsp->rows; ++index) { 653227569Sphilip func(2 * index + 0, B_FALSE, ®.eo_qword[0]); 654227569Sphilip func(2 * index + 1, B_FALSE, ®.eo_qword[1]); 655227569Sphilip EFX_AND_OWORD(reg, rsp->mask); 656227569Sphilip EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE); 657227569Sphilip if (memcmp(®, &buf, sizeof (reg))) { 658227569Sphilip rc = EIO; 659227569Sphilip goto fail1; 660227569Sphilip } 661227569Sphilip 662227569Sphilip address += rsp->step; 663227569Sphilip } 664227569Sphilip 665227569Sphilip ++rsp; 666227569Sphilip --count; 667227569Sphilip } 668227569Sphilip 669227569Sphilip return (0); 670227569Sphilip 671227569Sphilipfail1: 672227569Sphilip EFSYS_PROBE1(fail1, int, rc); 673227569Sphilip 674227569Sphilip return (rc); 675227569Sphilip} 676227569Sphilip 677227569Sphilip#endif /* EFSYS_OPT_DIAG */ 678