From patchwork Tue Nov 29 16:18:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Rybchenko X-Patchwork-Id: 17298 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id BB9AAFA58; Tue, 29 Nov 2016 17:22:02 +0100 (CET) Received: from nbfkord-smmo01.seg.att.com (nbfkord-smmo01.seg.att.com [209.65.160.76]) by dpdk.org (Postfix) with ESMTP id 1632837A8 for ; Tue, 29 Nov 2016 17:20:49 +0100 (CET) Received: from unknown [12.187.104.26] (EHLO nbfkord-smmo01.seg.att.com) by nbfkord-smmo01.seg.att.com(mxl_mta-7.2.4-7) with ESMTP id 2eaad385.2b3e59401940.83553.00-2488.173832.nbfkord-smmo01.seg.att.com (envelope-from ); Tue, 29 Nov 2016 16:20:50 +0000 (UTC) X-MXL-Hash: 583daae23e345924-6386a88d682e5f2153ab738335f7ea9b9462c40e Received: from unknown [12.187.104.26] by nbfkord-smmo01.seg.att.com(mxl_mta-7.2.4-7) with SMTP id 9daad385.0.83400.00-2380.173727.nbfkord-smmo01.seg.att.com (envelope-from ); Tue, 29 Nov 2016 16:20:42 +0000 (UTC) X-MXL-Hash: 583daada235b8554-c364f835f12817b4d4bb14e615fd14739e628d39 Received: from ocex03.SolarFlarecom.com (10.20.40.36) by ocex03.SolarFlarecom.com (10.20.40.36) with Microsoft SMTP Server (TLS) id 15.0.1044.25; Tue, 29 Nov 2016 08:20:25 -0800 Received: from opal.uk.solarflarecom.com (10.17.10.1) by ocex03.SolarFlarecom.com (10.20.40.36) with Microsoft SMTP Server (TLS) id 15.0.1044.25 via Frontend Transport; Tue, 29 Nov 2016 08:20:25 -0800 Received: from uklogin.uk.solarflarecom.com (uklogin.uk.solarflarecom.com [10.17.10.10]) by opal.uk.solarflarecom.com (8.13.8/8.13.8) with ESMTP id uATGKNMS029957; Tue, 29 Nov 2016 16:20:23 GMT Received: from uklogin.uk.solarflarecom.com (localhost.localdomain [127.0.0.1]) by uklogin.uk.solarflarecom.com (8.13.8/8.13.8) with ESMTP id uATGKM1U021233; Tue, 29 Nov 2016 16:20:23 GMT From: Andrew Rybchenko To: CC: Date: Tue, 29 Nov 2016 16:18:54 +0000 Message-ID: <1480436367-20749-23-git-send-email-arybchenko@solarflare.com> X-Mailer: git-send-email 1.8.2.3 In-Reply-To: <1480436367-20749-1-git-send-email-arybchenko@solarflare.com> References: <1479740470-6723-1-git-send-email-arybchenko@solarflare.com> <1480436367-20749-1-git-send-email-arybchenko@solarflare.com> MIME-Version: 1.0 X-AnalysisOut: [v=2.1 cv=UoJlQrEB c=1 sm=1 tr=0 a=8BlWFWvVlq5taO8ncb8nKg==] X-AnalysisOut: [:17 a=L24OOQBejmoA:10 a=zRKbQ67AAAAA:8 a=oRrPKEy2kVU0EK0rN] X-AnalysisOut: [yAA:9 a=TpvnO824xIqVzHSz:21 a=1T35OmQPLf16Dsm5:21 a=laHvG-] X-AnalysisOut: [NHmLIo8LD9:21 a=PA03WX8tBzeizutn5_OT:22] X-Spam: [F=0.4999999996; CM=0.500; S=0.499(2015072901)] X-MAIL-FROM: X-SOURCE-IP: [12.187.104.26] Subject: [dpdk-dev] [PATCH v2 22/55] net/sfc: import libefx loopback control support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" EFSYS_OPT_LOOPBACK should be enabled to use it. From Solarflare Communications Inc. Signed-off-by: Andrew Rybchenko --- drivers/net/sfc/base/ef10_impl.h | 13 +++ drivers/net/sfc/base/ef10_mac.c | 36 ++++++++ drivers/net/sfc/base/ef10_nic.c | 9 ++ drivers/net/sfc/base/ef10_phy.c | 45 +++++++++ drivers/net/sfc/base/efx.h | 74 +++++++++++++++ drivers/net/sfc/base/efx_check.h | 7 ++ drivers/net/sfc/base/efx_impl.h | 8 ++ drivers/net/sfc/base/efx_mac.c | 6 ++ drivers/net/sfc/base/efx_mcdi.h | 6 ++ drivers/net/sfc/base/efx_nic.c | 188 ++++++++++++++++++++++++++++++++++++++ drivers/net/sfc/base/efx_port.c | 101 ++++++++++++++++++++ drivers/net/sfc/base/siena_impl.h | 13 +++ drivers/net/sfc/base/siena_mac.c | 36 ++++++++ drivers/net/sfc/base/siena_nic.c | 9 ++ drivers/net/sfc/base/siena_phy.c | 42 +++++++++ 15 files changed, 593 insertions(+) diff --git a/drivers/net/sfc/base/ef10_impl.h b/drivers/net/sfc/base/ef10_impl.h index 0e5561e..01c48c8 100644 --- a/drivers/net/sfc/base/ef10_impl.h +++ b/drivers/net/sfc/base/ef10_impl.h @@ -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; diff --git a/drivers/net/sfc/base/ef10_mac.c b/drivers/net/sfc/base/ef10_mac.c index 477d0e7..488633f 100644 --- a/drivers/net/sfc/base/ef10_mac.c +++ b/drivers/net/sfc/base/ef10_mac.c @@ -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 diff --git a/drivers/net/sfc/base/ef10_nic.c b/drivers/net/sfc/base/ef10_nic.c index f28edd2..fec6a69 100644 --- a/drivers/net/sfc/base/ef10_nic.c +++ b/drivers/net/sfc/base/ef10_nic.c @@ -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); diff --git a/drivers/net/sfc/base/ef10_phy.c b/drivers/net/sfc/base/ef10_phy.c index cc00250..81309f2 100644 --- a/drivers/net/sfc/base/ef10_phy.c +++ b/drivers/net/sfc/base/ef10_phy.c @@ -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 diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h index f140a89..40a7e56 100644 --- a/drivers/net/sfc/base/efx.h +++ b/drivers/net/sfc/base/efx.h @@ -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 */ diff --git a/drivers/net/sfc/base/efx_check.h b/drivers/net/sfc/base/efx_check.h index ac248b3..22cf892 100644 --- a/drivers/net/sfc/base/efx_check.h +++ b/drivers/net/sfc/base/efx_check.h @@ -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 diff --git a/drivers/net/sfc/base/efx_impl.h b/drivers/net/sfc/base/efx_impl.h index e88e8a9..12a8a4f 100644 --- a/drivers/net/sfc/base/efx_impl.h +++ b/drivers/net/sfc/base/efx_impl.h @@ -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 */ diff --git a/drivers/net/sfc/base/efx_mac.c b/drivers/net/sfc/base/efx_mac.c index 840b7db..c1d81ef 100644 --- a/drivers/net/sfc/base/efx_mac.c +++ b/drivers/net/sfc/base/efx_mac.c @@ -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 */ diff --git a/drivers/net/sfc/base/efx_mcdi.h b/drivers/net/sfc/base/efx_mcdi.h index 6e24313..814f3f4 100644 --- a/drivers/net/sfc/base/efx_mcdi.h +++ b/drivers/net/sfc/base/efx_mcdi.h @@ -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, diff --git a/drivers/net/sfc/base/efx_nic.c b/drivers/net/sfc/base/efx_nic.c index 047d4a0..d4b5d08 100644 --- a/drivers/net/sfc/base/efx_nic.c +++ b/drivers/net/sfc/base/efx_nic.c @@ -775,6 +775,194 @@ efx_nic_test_tables( #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, diff --git a/drivers/net/sfc/base/efx_port.c b/drivers/net/sfc/base/efx_port.c index 291a8e9..518c2a2 100644 --- a/drivers/net/sfc/base/efx_port.c +++ b/drivers/net/sfc/base/efx_port.c @@ -125,6 +125,107 @@ efx_port_poll( 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) diff --git a/drivers/net/sfc/base/siena_impl.h b/drivers/net/sfc/base/siena_impl.h index 98fd2c5..da03098 100644 --- a/drivers/net/sfc/base/siena_impl.h +++ b/drivers/net/sfc/base/siena_impl.h @@ -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 diff --git a/drivers/net/sfc/base/siena_mac.c b/drivers/net/sfc/base/siena_mac.c index dbe9c6f..29bbff8 100644 --- a/drivers/net/sfc/base/siena_mac.c +++ b/drivers/net/sfc/base/siena_mac.c @@ -194,6 +194,42 @@ siena_mac_reconfigure( 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 diff --git a/drivers/net/sfc/base/siena_nic.c b/drivers/net/sfc/base/siena_nic.c index c77393a..d28d1d2 100644 --- a/drivers/net/sfc/base/siena_nic.c +++ b/drivers/net/sfc/base/siena_nic.c @@ -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); diff --git a/drivers/net/sfc/base/siena_phy.c b/drivers/net/sfc/base/siena_phy.c index 9aeef23..b90ccab 100644 --- a/drivers/net/sfc/base/siena_phy.c +++ b/drivers/net/sfc/base/siena_phy.c @@ -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