Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/sfxge/common/efx_nic.c
Property | Old Value | New Value |
---|---|---|
svn:eol-style | null | native \ No newline at end of property |
svn:mime-type | null | text/plain \ No newline at end of property |
/*- | /*- | ||||
* Copyright 2007-2009 Solarflare Communications Inc. All rights reserved. | * Copyright (c) 2007-2015 Solarflare Communications Inc. | ||||
* All rights reserved. | |||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions are met: | ||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | * | ||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND | * 1. Redistributions of source code must retain the above copyright notice, | ||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | * this list of conditions and the following disclaimer. | ||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | * this list of conditions and the following disclaimer in the documentation | ||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | * and/or other materials provided with the distribution. | ||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | * | ||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | ||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||||
* SUCH DAMAGE. | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
* | |||||
* The views and conclusions contained in the software and documentation are | |||||
* those of the authors and should not be interpreted as representing official | |||||
* policies, either expressed or implied, of the FreeBSD Project. | |||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "efsys.h" | #include "efsys.h" | ||||
#include "efx.h" | #include "efx.h" | ||||
#include "efx_types.h" | #include "efx_types.h" | ||||
#include "efx_regs.h" | #include "efx_regs.h" | ||||
#include "efx_impl.h" | #include "efx_impl.h" | ||||
__checkReturn int | __checkReturn int | ||||
efx_family( | efx_family( | ||||
__in uint16_t venid, | __in uint16_t venid, | ||||
__in uint16_t devid, | __in uint16_t devid, | ||||
__out efx_family_t *efp) | __out efx_family_t *efp) | ||||
{ | { | ||||
if (venid == EFX_PCI_VENID_SFC) { | |||||
switch (devid) { | |||||
#if EFSYS_OPT_FALCON | #if EFSYS_OPT_FALCON | ||||
if (venid == EFX_PCI_VENID_SFC && devid == EFX_PCI_DEVID_FALCON) { | case EFX_PCI_DEVID_FALCON: | ||||
*efp = EFX_FAMILY_FALCON; | *efp = EFX_FAMILY_FALCON; | ||||
return (0); | return (0); | ||||
} | |||||
#endif | #endif | ||||
#if EFSYS_OPT_SIENA | #if EFSYS_OPT_SIENA | ||||
if (venid == EFX_PCI_VENID_SFC && devid == EFX_PCI_DEVID_BETHPAGE) { | case EFX_PCI_DEVID_SIENA_F1_UNINIT: | ||||
/* | |||||
* Hardware default for PF0 of uninitialised Siena. | |||||
* manftest must be able to cope with this device id. | |||||
*/ | |||||
*efp = EFX_FAMILY_SIENA; | *efp = EFX_FAMILY_SIENA; | ||||
return (0); | return (0); | ||||
} | |||||
if (venid == EFX_PCI_VENID_SFC && devid == EFX_PCI_DEVID_SIENA) { | case EFX_PCI_DEVID_BETHPAGE: | ||||
case EFX_PCI_DEVID_SIENA: | |||||
*efp = EFX_FAMILY_SIENA; | *efp = EFX_FAMILY_SIENA; | ||||
return (0); | return (0); | ||||
} | #endif | ||||
if (venid == EFX_PCI_VENID_SFC && | |||||
devid == EFX_PCI_DEVID_SIENA_F1_UNINIT) { | #if EFSYS_OPT_HUNTINGTON | ||||
*efp = EFX_FAMILY_SIENA; | case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT: | ||||
/* | |||||
* Hardware default for PF0 of uninitialised Huntington. | |||||
* manftest must be able to cope with this device id. | |||||
*/ | |||||
*efp = EFX_FAMILY_HUNTINGTON; | |||||
return (0); | return (0); | ||||
} | |||||
case EFX_PCI_DEVID_FARMINGDALE: | |||||
case EFX_PCI_DEVID_GREENPORT: | |||||
case EFX_PCI_DEVID_HUNTINGTON: | |||||
*efp = EFX_FAMILY_HUNTINGTON; | |||||
return (0); | |||||
case EFX_PCI_DEVID_FARMINGDALE_VF: | |||||
case EFX_PCI_DEVID_GREENPORT_VF: | |||||
case EFX_PCI_DEVID_HUNTINGTON_VF: | |||||
*efp = EFX_FAMILY_HUNTINGTON; | |||||
return (0); | |||||
#endif | #endif | ||||
default: | |||||
break; | |||||
} | |||||
} | |||||
*efp = EFX_FAMILY_INVALID; | |||||
return (ENOTSUP); | return (ENOTSUP); | ||||
} | } | ||||
/* | /* | ||||
* To support clients which aren't provided with any PCI context infer | * To support clients which aren't provided with any PCI context infer | ||||
* the hardware family by inspecting the hardware. Obviously the caller | * the hardware family by inspecting the hardware. Obviously the caller | ||||
* must be damn sure they're really talking to a supported device. | * must be damn sure they're really talking to a supported device. | ||||
*/ | */ | ||||
__checkReturn int | __checkReturn int | ||||
efx_infer_family( | efx_infer_family( | ||||
__in efsys_bar_t *esbp, | __in efsys_bar_t *esbp, | ||||
__out efx_family_t *efp) | __out efx_family_t *efp) | ||||
{ | { | ||||
efx_family_t family; | efx_family_t family; | ||||
efx_oword_t oword; | efx_oword_t oword; | ||||
unsigned int portnum; | unsigned int portnum; | ||||
int rc; | int rc; | ||||
EFSYS_BAR_READO(esbp, FR_AZ_CS_DEBUG_REG_OFST, &oword, B_TRUE); | EFSYS_BAR_READO(esbp, FR_AZ_CS_DEBUG_REG_OFST, &oword, B_TRUE); | ||||
portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM); | portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM); | ||||
switch (portnum) { | switch (portnum) { | ||||
case 0: { | |||||
efx_dword_t dword; | |||||
uint32_t hw_rev; | |||||
EFSYS_BAR_READD(esbp, ER_DZ_BIU_HW_REV_ID_REG_OFST, &dword, | |||||
B_TRUE); | |||||
hw_rev = EFX_DWORD_FIELD(dword, ERF_DZ_HW_REV_ID); | |||||
if (hw_rev == ER_DZ_BIU_HW_REV_ID_REG_RESET) { | |||||
#if EFSYS_OPT_HUNTINGTON | |||||
family = EFX_FAMILY_HUNTINGTON; | |||||
break; | |||||
#endif | |||||
} else { | |||||
#if EFSYS_OPT_FALCON | #if EFSYS_OPT_FALCON | ||||
case 0: | |||||
family = EFX_FAMILY_FALCON; | family = EFX_FAMILY_FALCON; | ||||
break; | break; | ||||
#endif | #endif | ||||
} | |||||
rc = ENOTSUP; | |||||
goto fail1; | |||||
} | |||||
#if EFSYS_OPT_SIENA | #if EFSYS_OPT_SIENA | ||||
case 1: | case 1: | ||||
case 2: | case 2: | ||||
family = EFX_FAMILY_SIENA; | family = EFX_FAMILY_SIENA; | ||||
break; | break; | ||||
#endif | #endif | ||||
default: | default: | ||||
rc = ENOTSUP; | rc = ENOTSUP; | ||||
goto fail1; | goto fail1; | ||||
} | } | ||||
if (efp != NULL) | if (efp != NULL) | ||||
*efp = family; | *efp = family; | ||||
return (0); | return (0); | ||||
fail1: | fail1: | ||||
EFSYS_PROBE1(fail1, int, rc); | EFSYS_PROBE1(fail1, int, rc); | ||||
return (rc); | return (rc); | ||||
} | } | ||||
/* | |||||
* The built-in default value device id for port 1 of Siena is 0x0810. | |||||
* manftest needs to be able to cope with that. | |||||
*/ | |||||
#define EFX_BIU_MAGIC0 0x01234567 | #define EFX_BIU_MAGIC0 0x01234567 | ||||
#define EFX_BIU_MAGIC1 0xfedcba98 | #define EFX_BIU_MAGIC1 0xfedcba98 | ||||
static __checkReturn int | __checkReturn int | ||||
efx_nic_biu_test( | efx_nic_biu_test( | ||||
__in efx_nic_t *enp) | __in efx_nic_t *enp) | ||||
{ | { | ||||
efx_oword_t oword; | efx_oword_t oword; | ||||
int rc; | int rc; | ||||
/* | /* | ||||
* Write magic values to scratch registers 0 and 1, then | * Write magic values to scratch registers 0 and 1, then | ||||
* verify that the values were written correctly. Interleave | * verify that the values were written correctly. Interleave | ||||
* the accesses to ensure that the BIU is not just reading | * the accesses to ensure that the BIU is not just reading | ||||
* back the cached value that was last written. | * back the cached value that was last written. | ||||
*/ | */ | ||||
EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); | EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); | ||||
EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword); | EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); | ||||
EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); | EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); | ||||
EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword); | EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); | ||||
EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword); | EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); | ||||
if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { | if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { | ||||
rc = EIO; | rc = EIO; | ||||
goto fail1; | goto fail1; | ||||
} | } | ||||
EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword); | EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); | ||||
if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { | if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { | ||||
rc = EIO; | rc = EIO; | ||||
goto fail2; | goto fail2; | ||||
} | } | ||||
/* | /* | ||||
* Perform the same test, with the values swapped. This | * Perform the same test, with the values swapped. This | ||||
* ensures that subsequent tests don't start with the correct | * ensures that subsequent tests don't start with the correct | ||||
* values already written into the scratch registers. | * values already written into the scratch registers. | ||||
*/ | */ | ||||
EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); | EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); | ||||
EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword); | EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); | ||||
EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); | EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); | ||||
EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword); | EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); | ||||
EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword); | EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); | ||||
if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { | if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { | ||||
rc = EIO; | rc = EIO; | ||||
goto fail3; | goto fail3; | ||||
} | } | ||||
EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword); | EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); | ||||
if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { | if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { | ||||
rc = EIO; | rc = EIO; | ||||
goto fail4; | goto fail4; | ||||
} | } | ||||
return (0); | return (0); | ||||
fail4: | fail4: | ||||
EFSYS_PROBE(fail4); | EFSYS_PROBE(fail4); | ||||
fail3: | fail3: | ||||
EFSYS_PROBE(fail3); | EFSYS_PROBE(fail3); | ||||
fail2: | fail2: | ||||
EFSYS_PROBE(fail2); | EFSYS_PROBE(fail2); | ||||
fail1: | fail1: | ||||
EFSYS_PROBE1(fail1, int, rc); | EFSYS_PROBE1(fail1, int, rc); | ||||
return (rc); | return (rc); | ||||
} | } | ||||
#if EFSYS_OPT_FALCON | #if EFSYS_OPT_FALCON | ||||
static efx_nic_ops_t __cs __efx_nic_falcon_ops = { | static efx_nic_ops_t __efx_nic_falcon_ops = { | ||||
falcon_nic_probe, /* eno_probe */ | falcon_nic_probe, /* eno_probe */ | ||||
NULL, /* eno_set_drv_limits */ | |||||
falcon_nic_reset, /* eno_reset */ | falcon_nic_reset, /* eno_reset */ | ||||
falcon_nic_init, /* eno_init */ | falcon_nic_init, /* eno_init */ | ||||
NULL, /* eno_get_vi_pool */ | |||||
NULL, /* eno_get_bar_region */ | |||||
#if EFSYS_OPT_DIAG | #if EFSYS_OPT_DIAG | ||||
falcon_sram_test, /* eno_sram_test */ | falcon_sram_test, /* eno_sram_test */ | ||||
falcon_nic_register_test, /* eno_register_test */ | falcon_nic_register_test, /* eno_register_test */ | ||||
#endif /* EFSYS_OPT_DIAG */ | #endif /* EFSYS_OPT_DIAG */ | ||||
falcon_nic_fini, /* eno_fini */ | falcon_nic_fini, /* eno_fini */ | ||||
falcon_nic_unprobe, /* eno_unprobe */ | falcon_nic_unprobe, /* eno_unprobe */ | ||||
}; | }; | ||||
#endif /* EFSYS_OPT_FALCON */ | #endif /* EFSYS_OPT_FALCON */ | ||||
#if EFSYS_OPT_SIENA | #if EFSYS_OPT_SIENA | ||||
static efx_nic_ops_t __cs __efx_nic_siena_ops = { | static efx_nic_ops_t __efx_nic_siena_ops = { | ||||
siena_nic_probe, /* eno_probe */ | siena_nic_probe, /* eno_probe */ | ||||
NULL, /* eno_set_drv_limits */ | |||||
siena_nic_reset, /* eno_reset */ | siena_nic_reset, /* eno_reset */ | ||||
siena_nic_init, /* eno_init */ | siena_nic_init, /* eno_init */ | ||||
NULL, /* eno_get_vi_pool */ | |||||
NULL, /* eno_get_bar_region */ | |||||
#if EFSYS_OPT_DIAG | #if EFSYS_OPT_DIAG | ||||
siena_sram_test, /* eno_sram_test */ | siena_sram_test, /* eno_sram_test */ | ||||
siena_nic_register_test, /* eno_register_test */ | siena_nic_register_test, /* eno_register_test */ | ||||
#endif /* EFSYS_OPT_DIAG */ | #endif /* EFSYS_OPT_DIAG */ | ||||
siena_nic_fini, /* eno_fini */ | siena_nic_fini, /* eno_fini */ | ||||
siena_nic_unprobe, /* eno_unprobe */ | siena_nic_unprobe, /* eno_unprobe */ | ||||
}; | }; | ||||
#endif /* EFSYS_OPT_SIENA */ | #endif /* EFSYS_OPT_SIENA */ | ||||
#if EFSYS_OPT_HUNTINGTON | |||||
static efx_nic_ops_t __efx_nic_hunt_ops = { | |||||
hunt_nic_probe, /* eno_probe */ | |||||
hunt_nic_set_drv_limits, /* eno_set_drv_limits */ | |||||
hunt_nic_reset, /* eno_reset */ | |||||
hunt_nic_init, /* eno_init */ | |||||
hunt_nic_get_vi_pool, /* eno_get_vi_pool */ | |||||
hunt_nic_get_bar_region, /* eno_get_bar_region */ | |||||
#if EFSYS_OPT_DIAG | |||||
hunt_sram_test, /* eno_sram_test */ | |||||
hunt_nic_register_test, /* eno_register_test */ | |||||
#endif /* EFSYS_OPT_DIAG */ | |||||
hunt_nic_fini, /* eno_fini */ | |||||
hunt_nic_unprobe, /* eno_unprobe */ | |||||
}; | |||||
#endif /* EFSYS_OPT_HUNTINGTON */ | |||||
__checkReturn int | __checkReturn int | ||||
efx_nic_create( | efx_nic_create( | ||||
__in efx_family_t family, | __in efx_family_t family, | ||||
__in efsys_identifier_t *esip, | __in efsys_identifier_t *esip, | ||||
__in efsys_bar_t *esbp, | __in efsys_bar_t *esbp, | ||||
__in efsys_lock_t *eslp, | __in efsys_lock_t *eslp, | ||||
__deref_out efx_nic_t **enpp) | __deref_out efx_nic_t **enpp) | ||||
{ | { | ||||
Show All 27 Lines | case EFX_FAMILY_SIENA: | ||||
enp->en_features = | enp->en_features = | ||||
EFX_FEATURE_IPV6 | | EFX_FEATURE_IPV6 | | ||||
EFX_FEATURE_LFSR_HASH_INSERT | | EFX_FEATURE_LFSR_HASH_INSERT | | ||||
EFX_FEATURE_LINK_EVENTS | | EFX_FEATURE_LINK_EVENTS | | ||||
EFX_FEATURE_PERIODIC_MAC_STATS | | EFX_FEATURE_PERIODIC_MAC_STATS | | ||||
EFX_FEATURE_WOL | | EFX_FEATURE_WOL | | ||||
EFX_FEATURE_MCDI | | EFX_FEATURE_MCDI | | ||||
EFX_FEATURE_LOOKAHEAD_SPLIT | | EFX_FEATURE_LOOKAHEAD_SPLIT | | ||||
EFX_FEATURE_MAC_HEADER_FILTERS; | EFX_FEATURE_MAC_HEADER_FILTERS | | ||||
EFX_FEATURE_TX_SRC_FILTERS; | |||||
break; | break; | ||||
#endif /* EFSYS_OPT_SIENA */ | #endif /* EFSYS_OPT_SIENA */ | ||||
#if EFSYS_OPT_HUNTINGTON | |||||
case EFX_FAMILY_HUNTINGTON: | |||||
enp->en_enop = (efx_nic_ops_t *)&__efx_nic_hunt_ops; | |||||
/* FIXME: Add WOL support */ | |||||
enp->en_features = | |||||
EFX_FEATURE_IPV6 | | |||||
EFX_FEATURE_LINK_EVENTS | | |||||
EFX_FEATURE_PERIODIC_MAC_STATS | | |||||
EFX_FEATURE_MCDI | | |||||
EFX_FEATURE_MAC_HEADER_FILTERS | | |||||
EFX_FEATURE_MCDI_DMA | | |||||
EFX_FEATURE_PIO_BUFFERS | | |||||
EFX_FEATURE_FW_ASSISTED_TSO; | |||||
break; | |||||
#endif /* EFSYS_OPT_HUNTINGTON */ | |||||
default: | default: | ||||
rc = ENOTSUP; | rc = ENOTSUP; | ||||
goto fail2; | goto fail2; | ||||
} | } | ||||
enp->en_family = family; | enp->en_family = family; | ||||
enp->en_esip = esip; | enp->en_esip = esip; | ||||
enp->en_esbp = esbp; | enp->en_esbp = esbp; | ||||
enp->en_eslp = eslp; | enp->en_eslp = eslp; | ||||
*enpp = enp; | *enpp = enp; | ||||
return (0); | return (0); | ||||
fail2: | fail2: | ||||
EFSYS_PROBE(fail3); | EFSYS_PROBE(fail2); | ||||
enp->en_magic = 0; | enp->en_magic = 0; | ||||
/* Free the NIC object */ | /* Free the NIC object */ | ||||
EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); | EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); | ||||
fail1: | fail1: | ||||
EFSYS_PROBE1(fail1, int, rc); | EFSYS_PROBE1(fail1, int, rc); | ||||
return (rc); | return (rc); | ||||
} | } | ||||
__checkReturn int | __checkReturn int | ||||
efx_nic_probe( | efx_nic_probe( | ||||
__in efx_nic_t *enp) | __in efx_nic_t *enp) | ||||
{ | { | ||||
efx_nic_ops_t *enop; | efx_nic_ops_t *enop; | ||||
efx_oword_t oword; | |||||
int rc; | int rc; | ||||
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | ||||
#if EFSYS_OPT_MCDI | #if EFSYS_OPT_MCDI | ||||
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); | ||||
#endif /* EFSYS_OPT_MCDI */ | #endif /* EFSYS_OPT_MCDI */ | ||||
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE)); | EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE)); | ||||
/* Test BIU */ | |||||
if ((rc = efx_nic_biu_test(enp)) != 0) | |||||
goto fail1; | |||||
/* Clear the region register */ | |||||
EFX_POPULATE_OWORD_4(oword, | |||||
FRF_AZ_ADR_REGION0, 0, | |||||
FRF_AZ_ADR_REGION1, (1 << 16), | |||||
FRF_AZ_ADR_REGION2, (2 << 16), | |||||
FRF_AZ_ADR_REGION3, (3 << 16)); | |||||
EFX_BAR_WRITEO(enp, FR_AZ_ADR_REGION_REG, &oword); | |||||
enop = enp->en_enop; | enop = enp->en_enop; | ||||
if ((rc = enop->eno_probe(enp)) != 0) | if ((rc = enop->eno_probe(enp)) != 0) | ||||
goto fail2; | goto fail1; | ||||
if ((rc = efx_phy_probe(enp)) != 0) | if ((rc = efx_phy_probe(enp)) != 0) | ||||
goto fail3; | goto fail2; | ||||
enp->en_mod_flags |= EFX_MOD_PROBE; | enp->en_mod_flags |= EFX_MOD_PROBE; | ||||
return (0); | return (0); | ||||
fail3: | fail2: | ||||
EFSYS_PROBE(fail3); | EFSYS_PROBE(fail2); | ||||
enop->eno_unprobe(enp); | enop->eno_unprobe(enp); | ||||
fail2: | |||||
EFSYS_PROBE(fail2); | |||||
fail1: | fail1: | ||||
EFSYS_PROBE1(fail1, int, rc); | EFSYS_PROBE1(fail1, int, rc); | ||||
return (rc); | return (rc); | ||||
} | } | ||||
#if EFSYS_OPT_PCIE_TUNE | #if EFSYS_OPT_PCIE_TUNE | ||||
Show All 27 Lines | |||||
#endif | #endif | ||||
return (ENOTSUP); | return (ENOTSUP); | ||||
} | } | ||||
#endif /* EFSYS_OPT_PCIE_TUNE */ | #endif /* EFSYS_OPT_PCIE_TUNE */ | ||||
__checkReturn int | __checkReturn int | ||||
efx_nic_set_drv_limits( | |||||
__inout efx_nic_t *enp, | |||||
__in efx_drv_limits_t *edlp) | |||||
{ | |||||
efx_nic_ops_t *enop = enp->en_enop; | |||||
int rc; | |||||
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |||||
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); | |||||
if (enop->eno_set_drv_limits != NULL) { | |||||
if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0) | |||||
goto fail1; | |||||
} | |||||
return (0); | |||||
fail1: | |||||
EFSYS_PROBE1(fail1, int, rc); | |||||
return (rc); | |||||
} | |||||
__checkReturn int | |||||
efx_nic_get_bar_region( | |||||
__in efx_nic_t *enp, | |||||
__in efx_nic_region_t region, | |||||
__out uint32_t *offsetp, | |||||
__out size_t *sizep) | |||||
{ | |||||
efx_nic_ops_t *enop = enp->en_enop; | |||||
int rc; | |||||
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |||||
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); | |||||
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); | |||||
if (enop->eno_get_bar_region == NULL) { | |||||
rc = ENOTSUP; | |||||
goto fail1; | |||||
} | |||||
if ((rc = (enop->eno_get_bar_region)(enp, | |||||
region, offsetp, sizep)) != 0) { | |||||
goto fail2; | |||||
} | |||||
return (0); | |||||
fail2: | |||||
EFSYS_PROBE(fail2); | |||||
fail1: | |||||
EFSYS_PROBE1(fail1, int, rc); | |||||
return (rc); | |||||
} | |||||
__checkReturn int | |||||
efx_nic_get_vi_pool( | |||||
__in efx_nic_t *enp, | |||||
__out uint32_t *evq_countp, | |||||
__out uint32_t *rxq_countp, | |||||
__out uint32_t *txq_countp) | |||||
{ | |||||
efx_nic_ops_t *enop = enp->en_enop; | |||||
efx_nic_cfg_t *encp = &enp->en_nic_cfg; | |||||
int rc; | |||||
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |||||
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); | |||||
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); | |||||
if (enop->eno_get_vi_pool != NULL) { | |||||
uint32_t vi_count = 0; | |||||
if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0) | |||||
goto fail1; | |||||
*evq_countp = vi_count; | |||||
*rxq_countp = vi_count; | |||||
*txq_countp = vi_count; | |||||
} else { | |||||
/* Use NIC limits as default value */ | |||||
*evq_countp = encp->enc_evq_limit; | |||||
*rxq_countp = encp->enc_rxq_limit; | |||||
*txq_countp = encp->enc_txq_limit; | |||||
} | |||||
return (0); | |||||
fail1: | |||||
EFSYS_PROBE1(fail1, int, rc); | |||||
return (rc); | |||||
} | |||||
__checkReturn int | |||||
efx_nic_init( | efx_nic_init( | ||||
__in efx_nic_t *enp) | __in efx_nic_t *enp) | ||||
{ | { | ||||
efx_nic_ops_t *enop = enp->en_enop; | efx_nic_ops_t *enop = enp->en_enop; | ||||
int rc; | int rc; | ||||
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | ||||
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); | ||||
▲ Show 20 Lines • Show All 287 Lines • ▼ Show 20 Lines | |||||
fail1: | fail1: | ||||
EFSYS_PROBE1(fail1, int, rc); | EFSYS_PROBE1(fail1, int, rc); | ||||
return (rc); | return (rc); | ||||
} | } | ||||
#endif /* EFSYS_OPT_DIAG */ | #endif /* EFSYS_OPT_DIAG */ | ||||
#if EFSYS_OPT_LOOPBACK | |||||
extern void | |||||
efx_loopback_mask( | |||||
__in efx_loopback_kind_t loopback_kind, | |||||
__out efx_qword_t *maskp) | |||||
{ | |||||
efx_qword_t mask; | |||||
EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS); | |||||
EFSYS_ASSERT(maskp != NULL); | |||||
/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR == | |||||
EFX_LOOPBACK_XAUI_WS_FAR); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR == | |||||
EFX_LOOPBACK_XAUI_WS_NEAR); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR == | |||||
EFX_LOOPBACK_XFI_WS_FAR); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS == | |||||
EFX_LOOPBACK_PMA_INT_WS); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS == | |||||
EFX_LOOPBACK_SD_FEP2_WS); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS == | |||||
EFX_LOOPBACK_SD_FEP1_5_WS); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS); | |||||
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS); | |||||
/* Build bitmask of possible loopback types */ | |||||
EFX_ZERO_QWORD(mask); | |||||
if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) || | |||||
(loopback_kind == EFX_LOOPBACK_KIND_ALL)) { | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF); | |||||
} | |||||
if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) || | |||||
(loopback_kind == EFX_LOOPBACK_KIND_ALL)) { | |||||
/* | |||||
* The "MAC" grouping has historically been used by drivers to | |||||
* mean loopbacks supported by on-chip hardware. Keep that | |||||
* meaning here, and include on-chip PHY layer loopbacks. | |||||
*/ | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR); | |||||
} | |||||
if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) || | |||||
(loopback_kind == EFX_LOOPBACK_KIND_ALL)) { | |||||
/* | |||||
* The "PHY" grouping has historically been used by drivers to | |||||
* mean loopbacks supported by off-chip hardware. Keep that | |||||
* meaning here. | |||||
*/ | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PHY_XS); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS); | |||||
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD); | |||||
} | |||||
*maskp = mask; | |||||
} | |||||
__checkReturn int | |||||
efx_mcdi_get_loopback_modes( | |||||
__in efx_nic_t *enp) | |||||
{ | |||||
efx_nic_cfg_t *encp = &(enp->en_nic_cfg); | |||||
efx_mcdi_req_t req; | |||||
uint8_t payload[MAX(MC_CMD_GET_LOOPBACK_MODES_IN_LEN, | |||||
MC_CMD_GET_LOOPBACK_MODES_OUT_LEN)]; | |||||
efx_qword_t mask; | |||||
efx_qword_t modes; | |||||
int rc; | |||||
(void) memset(payload, 0, sizeof (payload)); | |||||
req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES; | |||||
req.emr_in_buf = payload; | |||||
req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN; | |||||
req.emr_out_buf = payload; | |||||
req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN; | |||||
efx_mcdi_execute(enp, &req); | |||||
if (req.emr_rc != 0) { | |||||
rc = req.emr_rc; | |||||
goto fail1; | |||||
} | |||||
if (req.emr_out_length_used < | |||||
MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST + | |||||
MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) { | |||||
rc = EMSGSIZE; | |||||
goto fail2; | |||||
} | |||||
/* | |||||
* We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree | |||||
* in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link(). | |||||
*/ | |||||
efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask); | |||||
EFX_AND_QWORD(mask, | |||||
*MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED)); | |||||
modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M); | |||||
EFX_AND_QWORD(modes, mask); | |||||
encp->enc_loopback_types[EFX_LINK_100FDX] = modes; | |||||
modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G); | |||||
EFX_AND_QWORD(modes, mask); | |||||
encp->enc_loopback_types[EFX_LINK_1000FDX] = modes; | |||||
modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G); | |||||
EFX_AND_QWORD(modes, mask); | |||||
encp->enc_loopback_types[EFX_LINK_10000FDX] = modes; | |||||
if (req.emr_out_length_used >= | |||||
MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST + | |||||
MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) { | |||||
/* Response includes 40G loopback modes */ | |||||
modes = | |||||
*MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G); | |||||
EFX_AND_QWORD(modes, mask); | |||||
encp->enc_loopback_types[EFX_LINK_40000FDX] = modes; | |||||
} | |||||
EFX_ZERO_QWORD(modes); | |||||
EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF); | |||||
EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]); | |||||
EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]); | |||||
EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]); | |||||
EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]); | |||||
encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes; | |||||
return (0); | |||||
fail2: | |||||
EFSYS_PROBE(fail2); | |||||
fail1: | |||||
EFSYS_PROBE1(fail1, int, rc); | |||||
return (rc); | |||||
} | |||||
#endif /* EFSYS_OPT_LOOPBACK */ |