net/sfc/base: import loopback control

EFSYS_OPT_LOOPBACK should be enabled to use it.

From Solarflare Communications Inc.

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
This commit is contained in:
Andrew Rybchenko 2016-11-29 16:18:54 +00:00 committed by Ferruh Yigit
parent 5935cd8c47
commit 9ee64bd404
15 changed files with 593 additions and 0 deletions

View File

@ -259,6 +259,16 @@ extern void
ef10_mac_filter_default_rxq_clear(
__in efx_nic_t *enp);
#if EFSYS_OPT_LOOPBACK
extern __checkReturn efx_rc_t
ef10_mac_loopback_set(
__in efx_nic_t *enp,
__in efx_link_mode_t link_mode,
__in efx_loopback_type_t loopback_type);
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MAC_STATS
extern __checkReturn efx_rc_t
@ -337,6 +347,9 @@ typedef struct ef10_link_state_s {
uint32_t els_lp_cap_mask;
unsigned int els_fcntl;
efx_link_mode_t els_link_mode;
#if EFSYS_OPT_LOOPBACK
efx_loopback_type_t els_loopback;
#endif
boolean_t els_mac_up;
} ef10_link_state_t;

View File

@ -443,6 +443,42 @@ ef10_mac_filter_default_rxq_clear(
}
#if EFSYS_OPT_LOOPBACK
__checkReturn efx_rc_t
ef10_mac_loopback_set(
__in efx_nic_t *enp,
__in efx_link_mode_t link_mode,
__in efx_loopback_type_t loopback_type)
{
efx_port_t *epp = &(enp->en_port);
const efx_phy_ops_t *epop = epp->ep_epop;
efx_loopback_type_t old_loopback_type;
efx_link_mode_t old_loopback_link_mode;
efx_rc_t rc;
/* The PHY object handles this on EF10 */
old_loopback_type = epp->ep_loopback_type;
old_loopback_link_mode = epp->ep_loopback_link_mode;
epp->ep_loopback_type = loopback_type;
epp->ep_loopback_link_mode = link_mode;
if ((rc = epop->epo_reconfigure(enp)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
epp->ep_loopback_type = old_loopback_type;
epp->ep_loopback_link_mode = old_loopback_link_mode;
return (rc);
}
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MAC_STATS
__checkReturn efx_rc_t

View File

@ -1377,10 +1377,19 @@ ef10_nic_probe(
goto fail5;
#endif
#if EFSYS_OPT_LOOPBACK
if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
goto fail6;
#endif
encp->enc_features = enp->en_features;
return (0);
#if EFSYS_OPT_LOOPBACK
fail6:
EFSYS_PROBE(fail6);
#endif
#if EFSYS_OPT_MAC_STATS
fail5:
EFSYS_PROBE(fail5);

View File

@ -235,6 +235,30 @@ ef10_phy_get_link(
MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
&elsp->els_link_mode, &elsp->els_fcntl);
#if EFSYS_OPT_LOOPBACK
/* 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);
elsp->els_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
#endif /* EFSYS_OPT_LOOPBACK */
elsp->els_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
return (0);
@ -289,8 +313,29 @@ ef10_phy_reconfigure(
MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1);
#if EFSYS_OPT_LOOPBACK
MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
epp->ep_loopback_type);
switch (epp->ep_loopback_link_mode) {
case EFX_LINK_100FDX:
speed = 100;
break;
case EFX_LINK_1000FDX:
speed = 1000;
break;
case EFX_LINK_10000FDX:
speed = 10000;
break;
case EFX_LINK_40000FDX:
speed = 40000;
break;
default:
speed = 0;
}
#else
MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
speed = 0;
#endif /* EFSYS_OPT_LOOPBACK */
MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
#if EFSYS_OPT_PHY_FLAGS

View File

@ -646,6 +646,77 @@ extern __checkReturn efx_rc_t
efx_port_init(
__in efx_nic_t *enp);
#if EFSYS_OPT_LOOPBACK
typedef enum efx_loopback_type_e {
EFX_LOOPBACK_OFF = 0,
EFX_LOOPBACK_DATA = 1,
EFX_LOOPBACK_GMAC = 2,
EFX_LOOPBACK_XGMII = 3,
EFX_LOOPBACK_XGXS = 4,
EFX_LOOPBACK_XAUI = 5,
EFX_LOOPBACK_GMII = 6,
EFX_LOOPBACK_SGMII = 7,
EFX_LOOPBACK_XGBR = 8,
EFX_LOOPBACK_XFI = 9,
EFX_LOOPBACK_XAUI_FAR = 10,
EFX_LOOPBACK_GMII_FAR = 11,
EFX_LOOPBACK_SGMII_FAR = 12,
EFX_LOOPBACK_XFI_FAR = 13,
EFX_LOOPBACK_GPHY = 14,
EFX_LOOPBACK_PHY_XS = 15,
EFX_LOOPBACK_PCS = 16,
EFX_LOOPBACK_PMA_PMD = 17,
EFX_LOOPBACK_XPORT = 18,
EFX_LOOPBACK_XGMII_WS = 19,
EFX_LOOPBACK_XAUI_WS = 20,
EFX_LOOPBACK_XAUI_WS_FAR = 21,
EFX_LOOPBACK_XAUI_WS_NEAR = 22,
EFX_LOOPBACK_GMII_WS = 23,
EFX_LOOPBACK_XFI_WS = 24,
EFX_LOOPBACK_XFI_WS_FAR = 25,
EFX_LOOPBACK_PHYXS_WS = 26,
EFX_LOOPBACK_PMA_INT = 27,
EFX_LOOPBACK_SD_NEAR = 28,
EFX_LOOPBACK_SD_FAR = 29,
EFX_LOOPBACK_PMA_INT_WS = 30,
EFX_LOOPBACK_SD_FEP2_WS = 31,
EFX_LOOPBACK_SD_FEP1_5_WS = 32,
EFX_LOOPBACK_SD_FEP_WS = 33,
EFX_LOOPBACK_SD_FES_WS = 34,
EFX_LOOPBACK_NTYPES
} efx_loopback_type_t;
typedef enum efx_loopback_kind_e {
EFX_LOOPBACK_KIND_OFF = 0,
EFX_LOOPBACK_KIND_ALL,
EFX_LOOPBACK_KIND_MAC,
EFX_LOOPBACK_KIND_PHY,
EFX_LOOPBACK_NKINDS
} efx_loopback_kind_t;
extern void
efx_loopback_mask(
__in efx_loopback_kind_t loopback_kind,
__out efx_qword_t *maskp);
extern __checkReturn efx_rc_t
efx_port_loopback_set(
__in efx_nic_t *enp,
__in efx_link_mode_t link_mode,
__in efx_loopback_type_t type);
#if EFSYS_OPT_NAMES
extern __checkReturn const char *
efx_loopback_type_name(
__in efx_nic_t *enp,
__in efx_loopback_type_t type);
#endif /* EFSYS_OPT_NAMES */
#endif /* EFSYS_OPT_LOOPBACK */
extern __checkReturn efx_rc_t
efx_port_poll(
__in efx_nic_t *enp,
@ -921,6 +992,9 @@ typedef struct efx_nic_cfg_s {
uint32_t enc_rx_prefix_size;
uint32_t enc_rx_buf_align_start;
uint32_t enc_rx_buf_align_end;
#if EFSYS_OPT_LOOPBACK
efx_qword_t enc_loopback_types[EFX_LINK_NMODES];
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_PHY_FLAGS
uint32_t enc_phy_flags_mask;
#endif /* EFSYS_OPT_PHY_FLAGS */

View File

@ -90,6 +90,13 @@
# endif
#endif /* EFSYS_OPT_HUNTINGTON */
#if EFSYS_OPT_LOOPBACK
/* Support hardware loopback modes */
# if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD)
# error "LOOPBACK requires SIENA or HUNTINGTON or MEDFORD"
# endif
#endif /* EFSYS_OPT_LOOPBACK */
#ifdef EFSYS_OPT_MAC_FALCON_GMAC
# error "MAC_FALCON_GMAC is obsolete and is not supported."
#endif

View File

@ -186,6 +186,10 @@ typedef struct efx_mac_ops_s {
efx_rc_t (*emo_filter_default_rxq_set)(efx_nic_t *,
efx_rxq_t *, boolean_t);
void (*emo_filter_default_rxq_clear)(efx_nic_t *);
#if EFSYS_OPT_LOOPBACK
efx_rc_t (*emo_loopback_set)(efx_nic_t *, efx_link_mode_t,
efx_loopback_type_t);
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MAC_STATS
efx_rc_t (*emo_stats_get_mask)(efx_nic_t *, uint32_t *, size_t);
efx_rc_t (*emo_stats_upload)(efx_nic_t *, efsys_mem_t *);
@ -261,6 +265,10 @@ typedef struct efx_port_s {
uint8_t ep_mulcst_addr_list[EFX_MAC_ADDR_LEN *
EFX_MAC_MULTICAST_LIST_MAX];
uint32_t ep_mulcst_addr_count;
#if EFSYS_OPT_LOOPBACK
efx_loopback_type_t ep_loopback_type;
efx_link_mode_t ep_loopback_link_mode;
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_PHY_FLAGS
uint32_t ep_phy_flags;
#endif /* EFSYS_OPT_PHY_FLAGS */

View File

@ -50,6 +50,9 @@ static const efx_mac_ops_t __efx_siena_mac_ops = {
siena_mac_multicast_list_set, /* emo_multicast_list_set */
NULL, /* emo_filter_set_default_rxq */
NULL, /* emo_filter_default_rxq_clear */
#if EFSYS_OPT_LOOPBACK
siena_mac_loopback_set, /* emo_loopback_set */
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MAC_STATS
siena_mac_stats_get_mask, /* emo_stats_get_mask */
efx_mcdi_mac_stats_upload, /* emo_stats_upload */
@ -71,6 +74,9 @@ static const efx_mac_ops_t __efx_ef10_mac_ops = {
ef10_mac_filter_default_rxq_set, /* emo_filter_default_rxq_set */
ef10_mac_filter_default_rxq_clear,
/* emo_filter_default_rxq_clear */
#if EFSYS_OPT_LOOPBACK
ef10_mac_loopback_set, /* emo_loopback_set */
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MAC_STATS
ef10_mac_stats_get_mask, /* emo_stats_get_mask */
efx_mcdi_mac_stats_upload, /* emo_stats_upload */

View File

@ -220,6 +220,12 @@ efx_mcdi_mac_stats_periodic(
__in boolean_t events);
#if EFSYS_OPT_LOOPBACK
extern __checkReturn efx_rc_t
efx_mcdi_get_loopback_modes(
__in efx_nic_t *enp);
#endif /* EFSYS_OPT_LOOPBACK */
extern __checkReturn efx_rc_t
efx_mcdi_phy_module_get_info(
__in efx_nic_t *enp,

View File

@ -775,6 +775,194 @@ fail1:
#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 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;
}
/*
* 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, efx_rc_t, rc);
return (rc);
}
#endif /* EFSYS_OPT_LOOPBACK */
__checkReturn efx_rc_t
efx_nic_calculate_pcie_link_bandwidth(
__in uint32_t pcie_link_width,

View File

@ -125,6 +125,107 @@ fail1:
return (rc);
}
#if EFSYS_OPT_LOOPBACK
__checkReturn efx_rc_t
efx_port_loopback_set(
__in efx_nic_t *enp,
__in efx_link_mode_t link_mode,
__in efx_loopback_type_t loopback_type)
{
efx_port_t *epp = &(enp->en_port);
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
const efx_mac_ops_t *emop = epp->ep_emop;
efx_rc_t rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
EFSYS_ASSERT(emop != NULL);
EFSYS_ASSERT(link_mode < EFX_LINK_NMODES);
if (EFX_TEST_QWORD_BIT(encp->enc_loopback_types[link_mode],
loopback_type) == 0) {
rc = ENOTSUP;
goto fail1;
}
if (epp->ep_loopback_type == loopback_type &&
epp->ep_loopback_link_mode == link_mode)
return (0);
if ((rc = emop->emo_loopback_set(enp, link_mode, loopback_type)) != 0)
goto fail2;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
#if EFSYS_OPT_NAMES
static const char * const __efx_loopback_type_name[] = {
"OFF",
"DATA",
"GMAC",
"XGMII",
"XGXS",
"XAUI",
"GMII",
"SGMII",
"XGBR",
"XFI",
"XAUI_FAR",
"GMII_FAR",
"SGMII_FAR",
"XFI_FAR",
"GPHY",
"PHY_XS",
"PCS",
"PMA_PMD",
"XPORT",
"XGMII_WS",
"XAUI_WS",
"XAUI_WS_FAR",
"XAUI_WS_NEAR",
"GMII_WS",
"XFI_WS",
"XFI_WS_FAR",
"PHYXS_WS",
"PMA_INT",
"SD_NEAR",
"SD_FAR",
"PMA_INT_WS",
"SD_FEP2_WS",
"SD_FEP1_5_WS",
"SD_FEP_WS",
"SD_FES_WS",
};
__checkReturn const char *
efx_loopback_type_name(
__in efx_nic_t *enp,
__in efx_loopback_type_t type)
{
EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__efx_loopback_type_name) ==
EFX_LOOPBACK_NTYPES);
_NOTE(ARGUNUSED(enp))
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(type, <, EFX_LOOPBACK_NTYPES);
return (__efx_loopback_type_name[type]);
}
#endif /* EFSYS_OPT_NAMES */
#endif /* EFSYS_OPT_LOOPBACK */
void
efx_port_fini(
__in efx_nic_t *enp)

View File

@ -138,6 +138,9 @@ typedef struct siena_link_state_s {
uint32_t sls_lp_cap_mask;
unsigned int sls_fcntl;
efx_link_mode_t sls_link_mode;
#if EFSYS_OPT_LOOPBACK
efx_loopback_type_t sls_loopback;
#endif
boolean_t sls_mac_up;
} siena_link_state_t;
@ -232,6 +235,16 @@ siena_mac_pdu_get(
__in efx_nic_t *enp,
__out size_t *pdu);
#if EFSYS_OPT_LOOPBACK
extern __checkReturn efx_rc_t
siena_mac_loopback_set(
__in efx_nic_t *enp,
__in efx_link_mode_t link_mode,
__in efx_loopback_type_t loopback_type);
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MAC_STATS
extern __checkReturn efx_rc_t

View File

@ -194,6 +194,42 @@ fail1:
return (rc);
}
#if EFSYS_OPT_LOOPBACK
__checkReturn efx_rc_t
siena_mac_loopback_set(
__in efx_nic_t *enp,
__in efx_link_mode_t link_mode,
__in efx_loopback_type_t loopback_type)
{
efx_port_t *epp = &(enp->en_port);
const efx_phy_ops_t *epop = epp->ep_epop;
efx_loopback_type_t old_loopback_type;
efx_link_mode_t old_loopback_link_mode;
efx_rc_t rc;
/* The PHY object handles this on Siena */
old_loopback_type = epp->ep_loopback_type;
old_loopback_link_mode = epp->ep_loopback_link_mode;
epp->ep_loopback_type = loopback_type;
epp->ep_loopback_link_mode = link_mode;
if ((rc = epop->epo_reconfigure(enp)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
epp->ep_loopback_type = old_loopback_type;
epp->ep_loopback_link_mode = old_loopback_link_mode;
return (rc);
}
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MAC_STATS
__checkReturn efx_rc_t

View File

@ -216,10 +216,19 @@ siena_nic_probe(
goto fail10;
#endif
#if EFSYS_OPT_LOOPBACK
if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
goto fail11;
#endif
encp->enc_features = enp->en_features;
return (0);
#if EFSYS_OPT_LOOPBACK
fail11:
EFSYS_PROBE(fail11);
#endif
#if EFSYS_OPT_MAC_STATS
fail10:
EFSYS_PROBE(fail10);

View File

@ -226,6 +226,30 @@ siena_phy_get_link(
MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
&slsp->sls_link_mode, &slsp->sls_fcntl);
#if EFSYS_OPT_LOOPBACK
/* 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);
slsp->sls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
#endif /* EFSYS_OPT_LOOPBACK */
slsp->sls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
return (0);
@ -273,8 +297,26 @@ siena_phy_reconfigure(
PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
#if EFSYS_OPT_LOOPBACK
MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
epp->ep_loopback_type);
switch (epp->ep_loopback_link_mode) {
case EFX_LINK_100FDX:
speed = 100;
break;
case EFX_LINK_1000FDX:
speed = 1000;
break;
case EFX_LINK_10000FDX:
speed = 10000;
break;
default:
speed = 0;
}
#else
MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
speed = 0;
#endif /* EFSYS_OPT_LOOPBACK */
MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
#if EFSYS_OPT_PHY_FLAGS