#include "efx.h"
#include "efx_impl.h"
__checkReturn efx_rc_t
efx_family(
__in uint16_t venid,
__in uint16_t devid,
__out efx_family_t *efp)
{
if (venid == EFX_PCI_VENID_SFC) {
switch (devid) {
#if EFSYS_OPT_SIENA
case EFX_PCI_DEVID_SIENA_F1_UNINIT:
*efp = EFX_FAMILY_SIENA;
return (0);
case EFX_PCI_DEVID_BETHPAGE:
case EFX_PCI_DEVID_SIENA:
*efp = EFX_FAMILY_SIENA;
return (0);
#endif
#if EFSYS_OPT_HUNTINGTON
case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT:
*efp = EFX_FAMILY_HUNTINGTON;
return (0);
case EFX_PCI_DEVID_FARMINGDALE:
case EFX_PCI_DEVID_GREENPORT:
*efp = EFX_FAMILY_HUNTINGTON;
return (0);
case EFX_PCI_DEVID_FARMINGDALE_VF:
case EFX_PCI_DEVID_GREENPORT_VF:
*efp = EFX_FAMILY_HUNTINGTON;
return (0);
#endif
#if EFSYS_OPT_MEDFORD
case EFX_PCI_DEVID_MEDFORD_PF_UNINIT:
*efp = EFX_FAMILY_MEDFORD;
return (0);
case EFX_PCI_DEVID_MEDFORD:
*efp = EFX_FAMILY_MEDFORD;
return (0);
case EFX_PCI_DEVID_MEDFORD_VF:
*efp = EFX_FAMILY_MEDFORD;
return (0);
#endif
case EFX_PCI_DEVID_FALCON:
default:
break;
}
}
*efp = EFX_FAMILY_INVALID;
return (ENOTSUP);
}
#define EFX_BIU_MAGIC0 0x01234567
#define EFX_BIU_MAGIC1 0xfedcba98
__checkReturn efx_rc_t
efx_nic_biu_test(
__in efx_nic_t *enp)
{
efx_oword_t oword;
efx_rc_t rc;
EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
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_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
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) {
rc = EIO;
goto fail1;
}
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) {
rc = EIO;
goto fail2;
}
EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
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_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
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) {
rc = EIO;
goto fail3;
}
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) {
rc = EIO;
goto fail4;
}
return (0);
fail4:
EFSYS_PROBE(fail4);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
#if EFSYS_OPT_SIENA
static const efx_nic_ops_t __efx_nic_siena_ops = {
siena_nic_probe,
NULL,
NULL,
siena_nic_reset,
siena_nic_init,
NULL,
NULL,
#if EFSYS_OPT_DIAG
siena_nic_register_test,
#endif
siena_nic_fini,
siena_nic_unprobe,
};
#endif
#if EFSYS_OPT_HUNTINGTON
static const efx_nic_ops_t __efx_nic_hunt_ops = {
ef10_nic_probe,
hunt_board_cfg,
ef10_nic_set_drv_limits,
ef10_nic_reset,
ef10_nic_init,
ef10_nic_get_vi_pool,
ef10_nic_get_bar_region,
#if EFSYS_OPT_DIAG
ef10_nic_register_test,
#endif
ef10_nic_fini,
ef10_nic_unprobe,
};
#endif
#if EFSYS_OPT_MEDFORD
static const efx_nic_ops_t __efx_nic_medford_ops = {
ef10_nic_probe,
medford_board_cfg,
ef10_nic_set_drv_limits,
ef10_nic_reset,
ef10_nic_init,
ef10_nic_get_vi_pool,
ef10_nic_get_bar_region,
#if EFSYS_OPT_DIAG
ef10_nic_register_test,
#endif
ef10_nic_fini,
ef10_nic_unprobe,
};
#endif
__checkReturn efx_rc_t
efx_nic_create(
__in efx_family_t family,
__in efsys_identifier_t *esip,
__in efsys_bar_t *esbp,
__in efsys_lock_t *eslp,
__deref_out efx_nic_t **enpp)
{
efx_nic_t *enp;
efx_rc_t rc;
EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID);
EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES);
EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp);
if (enp == NULL) {
rc = ENOMEM;
goto fail1;
}
enp->en_magic = EFX_NIC_MAGIC;
switch (family) {
#if EFSYS_OPT_SIENA
case EFX_FAMILY_SIENA:
enp->en_enop = &__efx_nic_siena_ops;
enp->en_features =
EFX_FEATURE_IPV6 |
EFX_FEATURE_LFSR_HASH_INSERT |
EFX_FEATURE_LINK_EVENTS |
EFX_FEATURE_PERIODIC_MAC_STATS |
EFX_FEATURE_WOL |
EFX_FEATURE_MCDI |
EFX_FEATURE_LOOKAHEAD_SPLIT |
EFX_FEATURE_MAC_HEADER_FILTERS |
EFX_FEATURE_TX_SRC_FILTERS;
break;
#endif
#if EFSYS_OPT_HUNTINGTON
case EFX_FAMILY_HUNTINGTON:
enp->en_enop = &__efx_nic_hunt_ops;
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 |
EFX_FEATURE_FW_ASSISTED_TSO_V2;
break;
#endif
#if EFSYS_OPT_MEDFORD
case EFX_FAMILY_MEDFORD:
enp->en_enop = &__efx_nic_medford_ops;
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;
break;
#endif
default:
rc = ENOTSUP;
goto fail2;
}
enp->en_family = family;
enp->en_esip = esip;
enp->en_esbp = esbp;
enp->en_eslp = eslp;
*enpp = enp;
return (0);
fail2:
EFSYS_PROBE(fail2);
enp->en_magic = 0;
EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
__checkReturn efx_rc_t
efx_nic_probe(
__in efx_nic_t *enp)
{
const efx_nic_ops_t *enop;
efx_rc_t rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
#if EFSYS_OPT_MCDI
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
#endif
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE));
enop = enp->en_enop;
if ((rc = enop->eno_probe(enp)) != 0)
goto fail1;
if ((rc = efx_phy_probe(enp)) != 0)
goto fail2;
enp->en_mod_flags |= EFX_MOD_PROBE;
return (0);
fail2:
EFSYS_PROBE(fail2);
enop->eno_unprobe(enp);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
__checkReturn efx_rc_t
efx_nic_set_drv_limits(
__inout efx_nic_t *enp,
__in efx_drv_limits_t *edlp)
{
const efx_nic_ops_t *enop = enp->en_enop;
efx_rc_t 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, efx_rc_t, rc);
return (rc);
}
__checkReturn efx_rc_t
efx_nic_get_bar_region(
__in efx_nic_t *enp,
__in efx_nic_region_t region,
__out uint32_t *offsetp,
__out size_t *sizep)
{
const efx_nic_ops_t *enop = enp->en_enop;
efx_rc_t 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, efx_rc_t, rc);
return (rc);
}
__checkReturn efx_rc_t
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)
{
const efx_nic_ops_t *enop = enp->en_enop;
efx_nic_cfg_t *encp = &enp->en_nic_cfg;
efx_rc_t 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 {
*evq_countp = encp->enc_evq_limit;
*rxq_countp = encp->enc_rxq_limit;
*txq_countp = encp->enc_txq_limit;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
__checkReturn efx_rc_t
efx_nic_init(
__in efx_nic_t *enp)
{
const efx_nic_ops_t *enop = enp->en_enop;
efx_rc_t rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
if (enp->en_mod_flags & EFX_MOD_NIC) {
rc = EINVAL;
goto fail1;
}
if ((rc = enop->eno_init(enp)) != 0)
goto fail2;
enp->en_mod_flags |= EFX_MOD_NIC;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
void
efx_nic_fini(
__in efx_nic_t *enp)
{
const efx_nic_ops_t *enop = enp->en_enop;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC);
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
enop->eno_fini(enp);
enp->en_mod_flags &= ~EFX_MOD_NIC;
}
void
efx_nic_unprobe(
__in efx_nic_t *enp)
{
const efx_nic_ops_t *enop = enp->en_enop;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
#if EFSYS_OPT_MCDI
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
#endif
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
efx_phy_unprobe(enp);
enop->eno_unprobe(enp);
enp->en_mod_flags &= ~EFX_MOD_PROBE;
}
void
efx_nic_destroy(
__in efx_nic_t *enp)
{
efsys_identifier_t *esip = enp->en_esip;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
enp->en_family = 0;
enp->en_esip = NULL;
enp->en_esbp = NULL;
enp->en_eslp = NULL;
enp->en_enop = NULL;
enp->en_magic = 0;
EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
}
__checkReturn efx_rc_t
efx_nic_reset(
__in efx_nic_t *enp)
{
const efx_nic_ops_t *enop = enp->en_enop;
unsigned int mod_flags;
efx_rc_t rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
mod_flags = enp->en_mod_flags;
mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM |
EFX_MOD_VPD | EFX_MOD_MON | EFX_MOD_LIC);
EFSYS_ASSERT3U(mod_flags, ==, 0);
if (mod_flags != 0) {
rc = EINVAL;
goto fail1;
}
if ((rc = enop->eno_reset(enp)) != 0)
goto fail2;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
const efx_nic_cfg_t *
efx_nic_cfg_get(
__in efx_nic_t *enp)
{
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
return (&(enp->en_nic_cfg));
}
#if EFSYS_OPT_DIAG
__checkReturn efx_rc_t
efx_nic_register_test(
__in efx_nic_t *enp)
{
const efx_nic_ops_t *enop = enp->en_enop;
efx_rc_t rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
if ((rc = enop->eno_register_test(enp)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
__checkReturn efx_rc_t
efx_nic_test_registers(
__in efx_nic_t *enp,
__in efx_register_set_t *rsp,
__in size_t count)
{
unsigned int bit;
efx_oword_t original;
efx_oword_t reg;
efx_oword_t buf;
efx_rc_t rc;
while (count > 0) {
EFSYS_ASSERT(rsp->rows == 1);
EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original,
B_TRUE);
for (bit = 0; bit < 128; bit++) {
if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit))
continue;
reg = original;
EFX_AND_OWORD(reg, rsp->mask);
EFX_SET_OWORD_BIT(reg, bit);
EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, ®,
B_TRUE);
EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
B_TRUE);
EFX_AND_OWORD(buf, rsp->mask);
if (memcmp(®, &buf, sizeof (reg))) {
rc = EIO;
goto fail1;
}
EFX_OR_OWORD(reg, rsp->mask);
EFX_CLEAR_OWORD_BIT(reg, bit);
EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, ®,
B_TRUE);
EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
B_TRUE);
EFX_AND_OWORD(buf, rsp->mask);
if (memcmp(®, &buf, sizeof (reg))) {
rc = EIO;
goto fail2;
}
}
EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original,
B_TRUE);
--count;
++rsp;
}
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE);
return (rc);
}
__checkReturn efx_rc_t
efx_nic_test_tables(
__in efx_nic_t *enp,
__in efx_register_set_t *rsp,
__in efx_pattern_type_t pattern,
__in size_t count)
{
efx_sram_pattern_fn_t func;
unsigned int index;
unsigned int address;
efx_oword_t reg;
efx_oword_t buf;
efx_rc_t rc;
EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES);
func = __efx_sram_pattern_fns[pattern];
while (count > 0) {
address = rsp->address;
for (index = 0; index < rsp->rows; ++index) {
func(2 * index + 0, B_FALSE, ®.eo_qword[0]);
func(2 * index + 1, B_FALSE, ®.eo_qword[1]);
EFX_AND_OWORD(reg, rsp->mask);
EFSYS_BAR_WRITEO(enp->en_esbp, address, ®, B_TRUE);
address += rsp->step;
}
address = rsp->address;
for (index = 0; index < rsp->rows; ++index) {
func(2 * index + 0, B_FALSE, ®.eo_qword[0]);
func(2 * index + 1, B_FALSE, ®.eo_qword[1]);
EFX_AND_OWORD(reg, rsp->mask);
EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE);
if (memcmp(®, &buf, sizeof (reg))) {
rc = EIO;
goto fail1;
}
address += rsp->step;
}
++rsp;
--count;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
#endif
#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);
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);
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)) {
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)) {
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 efx_rc_t
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;
efx_rc_t 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;
}
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) {
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, efx_rc_t, rc);
return (rc);
}
#endif