From patchwork Tue Nov 29 16:18:45 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Rybchenko X-Patchwork-Id: 17295 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 A07EBFA47; Tue, 29 Nov 2016 17:21:55 +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 51F70376D 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 1eaad385.2b3e7f63e940.83546.00-2487.173808.nbfkord-smmo01.seg.att.com (envelope-from ); Tue, 29 Nov 2016 16:20:49 +0000 (UTC) X-MXL-Hash: 583daae115aeaca8-a16f32a1a98b1d40e1383a458007a101cb616322 Received: from unknown [12.187.104.26] by nbfkord-smmo01.seg.att.com(mxl_mta-7.2.4-7) with SMTP id 5daad385.0.83424.00-2366.173633.nbfkord-smmo01.seg.att.com (envelope-from ); Tue, 29 Nov 2016 16:20:39 +0000 (UTC) X-MXL-Hash: 583daad75d335440-5ff1d640f51c3eee7438aee55b51f8987acd023f 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:24 -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 uATGKNJ3029928; 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 uATGKM1L021233; Tue, 29 Nov 2016 16:20:23 GMT From: Andrew Rybchenko To: CC: Date: Tue, 29 Nov 2016 16:18:45 +0000 Message-ID: <1480436367-20749-14-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=rQE43JCDXAeR0Fs_g] X-AnalysisOut: [E0A:9 a=_Drj-NbpIfy4YIO8:21 a=YMvQ95k1-b8KWrBF:21 a=IpA2b6] X-AnalysisOut: [oPnhgDVG3_:21 a=PA03WX8tBzeizutn5_OT:22] X-Spam: [F=0.5007121426; CM=0.500; S=0.500(2015072901)] X-MAIL-FROM: X-SOURCE-IP: [12.187.104.26] Subject: [dpdk-dev] [PATCH v2 13/55] net/sfc: import libefx built-in selftest 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_BIST should be enabled to use it. From Solarflare Communications Inc. Signed-off-by: Andrew Rybchenko --- drivers/net/sfc/base/ef10_impl.h | 29 ++++++ drivers/net/sfc/base/ef10_phy.c | 153 ++++++++++++++++++++++++++++ drivers/net/sfc/base/efx.h | 80 +++++++++++++++ drivers/net/sfc/base/efx_check.h | 7 ++ drivers/net/sfc/base/efx_impl.h | 11 ++ drivers/net/sfc/base/efx_mcdi.c | 115 +++++++++++++++++++++ drivers/net/sfc/base/efx_mcdi.h | 12 +++ drivers/net/sfc/base/efx_phy.c | 140 ++++++++++++++++++++++++++ drivers/net/sfc/base/siena_impl.h | 25 +++++ drivers/net/sfc/base/siena_phy.c | 205 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 777 insertions(+) diff --git a/drivers/net/sfc/base/ef10_impl.h b/drivers/net/sfc/base/ef10_impl.h index 6afe0bc..1cc6a72 100644 --- a/drivers/net/sfc/base/ef10_impl.h +++ b/drivers/net/sfc/base/ef10_impl.h @@ -345,6 +345,35 @@ ef10_phy_oui_get( __in efx_nic_t *enp, __out uint32_t *ouip); +#if EFSYS_OPT_BIST + +extern __checkReturn efx_rc_t +ef10_bist_enable_offline( + __in efx_nic_t *enp); + +extern __checkReturn efx_rc_t +ef10_bist_start( + __in efx_nic_t *enp, + __in efx_bist_type_t type); + +extern __checkReturn efx_rc_t +ef10_bist_poll( + __in efx_nic_t *enp, + __in efx_bist_type_t type, + __out efx_bist_result_t *resultp, + __out_opt __drv_when(count > 0, __notnull) + uint32_t *value_maskp, + __out_ecount_opt(count) __drv_when(count > 0, __notnull) + unsigned long *valuesp, + __in size_t count); + +extern void +ef10_bist_stop( + __in efx_nic_t *enp, + __in efx_bist_type_t type); + +#endif /* EFSYS_OPT_BIST */ + /* TX */ extern __checkReturn efx_rc_t diff --git a/drivers/net/sfc/base/ef10_phy.c b/drivers/net/sfc/base/ef10_phy.c index 36e2603..9e1b9c2 100644 --- a/drivers/net/sfc/base/ef10_phy.c +++ b/drivers/net/sfc/base/ef10_phy.c @@ -390,4 +390,157 @@ ef10_phy_oui_get( return (ENOTSUP); } +#if EFSYS_OPT_BIST + + __checkReturn efx_rc_t +ef10_bist_enable_offline( + __in efx_nic_t *enp) +{ + efx_rc_t rc; + + if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_bist_start( + __in efx_nic_t *enp, + __in efx_bist_type_t type) +{ + efx_rc_t rc; + + if ((rc = efx_mcdi_bist_start(enp, type)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_bist_poll( + __in efx_nic_t *enp, + __in efx_bist_type_t type, + __out efx_bist_result_t *resultp, + __out_opt __drv_when(count > 0, __notnull) + uint32_t *value_maskp, + __out_ecount_opt(count) __drv_when(count > 0, __notnull) + unsigned long *valuesp, + __in size_t count) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN, + MCDI_CTL_SDU_LEN_MAX)]; + uint32_t value_mask = 0; + uint32_t result; + efx_rc_t rc; + + _NOTE(ARGUNUSED(type)) + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_POLL_BIST; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MCDI_CTL_SDU_LEN_MAX; + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) { + rc = EMSGSIZE; + goto fail2; + } + + if (count > 0) + (void) memset(valuesp, '\0', count * sizeof (unsigned long)); + + result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT); + + if (result == MC_CMD_POLL_BIST_FAILED && + req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN && + count > EFX_BIST_MEM_ECC_FATAL) { + if (valuesp != NULL) { + valuesp[EFX_BIST_MEM_TEST] = + MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST); + valuesp[EFX_BIST_MEM_ADDR] = + MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR); + valuesp[EFX_BIST_MEM_BUS] = + MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS); + valuesp[EFX_BIST_MEM_EXPECT] = + MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT); + valuesp[EFX_BIST_MEM_ACTUAL] = + MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL); + valuesp[EFX_BIST_MEM_ECC] = + MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC); + valuesp[EFX_BIST_MEM_ECC_PARITY] = + MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY); + valuesp[EFX_BIST_MEM_ECC_FATAL] = + MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL); + } + value_mask |= (1 << EFX_BIST_MEM_TEST) | + (1 << EFX_BIST_MEM_ADDR) | + (1 << EFX_BIST_MEM_BUS) | + (1 << EFX_BIST_MEM_EXPECT) | + (1 << EFX_BIST_MEM_ACTUAL) | + (1 << EFX_BIST_MEM_ECC) | + (1 << EFX_BIST_MEM_ECC_PARITY) | + (1 << EFX_BIST_MEM_ECC_FATAL); + } else if (result == MC_CMD_POLL_BIST_FAILED && + encp->enc_phy_type == EFX_PHY_XFI_FARMI && + req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN && + count > EFX_BIST_FAULT_CODE) { + if (valuesp != NULL) + valuesp[EFX_BIST_FAULT_CODE] = + MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST); + value_mask |= 1 << EFX_BIST_FAULT_CODE; + } + + if (value_maskp != NULL) + *value_maskp = value_mask; + + EFSYS_ASSERT(resultp != NULL); + if (result == MC_CMD_POLL_BIST_RUNNING) + *resultp = EFX_BIST_RESULT_RUNNING; + else if (result == MC_CMD_POLL_BIST_PASSED) + *resultp = EFX_BIST_RESULT_PASSED; + else + *resultp = EFX_BIST_RESULT_FAILED; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_bist_stop( + __in efx_nic_t *enp, + __in efx_bist_type_t type) +{ + /* There is no way to stop BIST on EF10. */ + _NOTE(ARGUNUSED(enp, type)) +} + +#endif /* EFSYS_OPT_BIST */ + #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h index c7108a9..84d60b6 100644 --- a/drivers/net/sfc/base/efx.h +++ b/drivers/net/sfc/base/efx.h @@ -549,6 +549,83 @@ efx_phy_module_get_info( __out_bcount(len) uint8_t *data); +#if EFSYS_OPT_BIST + +typedef enum efx_bist_type_e { + EFX_BIST_TYPE_UNKNOWN, + EFX_BIST_TYPE_PHY_NORMAL, + EFX_BIST_TYPE_PHY_CABLE_SHORT, + EFX_BIST_TYPE_PHY_CABLE_LONG, + EFX_BIST_TYPE_MC_MEM, /* Test the MC DMEM and IMEM */ + EFX_BIST_TYPE_SAT_MEM, /* Test the DMEM and IMEM of satellite cpus*/ + EFX_BIST_TYPE_REG, /* Test the register memories */ + EFX_BIST_TYPE_NTYPES, +} efx_bist_type_t; + +typedef enum efx_bist_result_e { + EFX_BIST_RESULT_UNKNOWN, + EFX_BIST_RESULT_RUNNING, + EFX_BIST_RESULT_PASSED, + EFX_BIST_RESULT_FAILED, +} efx_bist_result_t; + +typedef enum efx_phy_cable_status_e { + EFX_PHY_CABLE_STATUS_OK, + EFX_PHY_CABLE_STATUS_INVALID, + EFX_PHY_CABLE_STATUS_OPEN, + EFX_PHY_CABLE_STATUS_INTRAPAIRSHORT, + EFX_PHY_CABLE_STATUS_INTERPAIRSHORT, + EFX_PHY_CABLE_STATUS_BUSY, +} efx_phy_cable_status_t; + +typedef enum efx_bist_value_e { + EFX_BIST_PHY_CABLE_LENGTH_A, + EFX_BIST_PHY_CABLE_LENGTH_B, + EFX_BIST_PHY_CABLE_LENGTH_C, + EFX_BIST_PHY_CABLE_LENGTH_D, + EFX_BIST_PHY_CABLE_STATUS_A, + EFX_BIST_PHY_CABLE_STATUS_B, + EFX_BIST_PHY_CABLE_STATUS_C, + EFX_BIST_PHY_CABLE_STATUS_D, + EFX_BIST_FAULT_CODE, + /* Memory BIST specific values. These match to the MC_CMD_BIST_POLL + * response. */ + EFX_BIST_MEM_TEST, + EFX_BIST_MEM_ADDR, + EFX_BIST_MEM_BUS, + EFX_BIST_MEM_EXPECT, + EFX_BIST_MEM_ACTUAL, + EFX_BIST_MEM_ECC, + EFX_BIST_MEM_ECC_PARITY, + EFX_BIST_MEM_ECC_FATAL, + EFX_BIST_NVALUES, +} efx_bist_value_t; + +extern __checkReturn efx_rc_t +efx_bist_enable_offline( + __in efx_nic_t *enp); + +extern __checkReturn efx_rc_t +efx_bist_start( + __in efx_nic_t *enp, + __in efx_bist_type_t type); + +extern __checkReturn efx_rc_t +efx_bist_poll( + __in efx_nic_t *enp, + __in efx_bist_type_t type, + __out efx_bist_result_t *resultp, + __out_opt uint32_t *value_maskp, + __out_ecount_opt(count) unsigned long *valuesp, + __in size_t count); + +extern void +efx_bist_stop( + __in efx_nic_t *enp, + __in efx_bist_type_t type); + +#endif /* EFSYS_OPT_BIST */ + #define EFX_FEATURE_IPV6 0x00000001 #define EFX_FEATURE_LFSR_HASH_INSERT 0x00000002 #define EFX_FEATURE_LINK_EVENTS 0x00000004 @@ -594,6 +671,9 @@ typedef struct efx_nic_cfg_s { #if EFSYS_OPT_MCDI uint8_t enc_mcdi_mdio_channel; #endif /* EFSYS_OPT_MCDI */ +#if EFSYS_OPT_BIST + uint32_t enc_bist_mask; +#endif /* EFSYS_OPT_BIST */ #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD uint32_t enc_pf; uint32_t enc_vf; diff --git a/drivers/net/sfc/base/efx_check.h b/drivers/net/sfc/base/efx_check.h index feaccd0..c78c5b6 100644 --- a/drivers/net/sfc/base/efx_check.h +++ b/drivers/net/sfc/base/efx_check.h @@ -214,6 +214,13 @@ # error "MCAST_FILTER_LIST is obsolete and is not supported" #endif +#if EFSYS_OPT_BIST +/* Support BIST */ +# if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) +# error "BIST requires SIENA or HUNTINGTON or MEDFORD" +# endif +#endif /* EFSYS_OPT_BIST */ + #if EFSYS_OPT_ALLOW_UNCONFIGURED_NIC /* Support adapters with missing static config (for factory use only) */ # if !EFSYS_OPT_MEDFORD diff --git a/drivers/net/sfc/base/efx_impl.h b/drivers/net/sfc/base/efx_impl.h index a7c6b29..a6853b3 100644 --- a/drivers/net/sfc/base/efx_impl.h +++ b/drivers/net/sfc/base/efx_impl.h @@ -175,6 +175,14 @@ typedef struct efx_phy_ops_s { efx_rc_t (*epo_reconfigure)(efx_nic_t *); efx_rc_t (*epo_verify)(efx_nic_t *); efx_rc_t (*epo_oui_get)(efx_nic_t *, uint32_t *); +#if EFSYS_OPT_BIST + efx_rc_t (*epo_bist_enable_offline)(efx_nic_t *); + efx_rc_t (*epo_bist_start)(efx_nic_t *, efx_bist_type_t); + efx_rc_t (*epo_bist_poll)(efx_nic_t *, efx_bist_type_t, + efx_bist_result_t *, uint32_t *, + unsigned long *, size_t); + void (*epo_bist_stop)(efx_nic_t *, efx_bist_type_t); +#endif /* EFSYS_OPT_BIST */ } efx_phy_ops_t; #if EFSYS_OPT_FILTER @@ -230,6 +238,9 @@ typedef struct efx_port_s { uint32_t ep_phy_cap_mask; boolean_t ep_mac_drain; boolean_t ep_mac_stats_pending; +#if EFSYS_OPT_BIST + efx_bist_type_t ep_current_bist; +#endif const efx_mac_ops_t *ep_emop; const efx_phy_ops_t *ep_epop; } efx_port_t; diff --git a/drivers/net/sfc/base/efx_mcdi.c b/drivers/net/sfc/base/efx_mcdi.c index 8d91812..b14cba1 100644 --- a/drivers/net/sfc/base/efx_mcdi.c +++ b/drivers/net/sfc/base/efx_mcdi.c @@ -1432,6 +1432,19 @@ efx_mcdi_get_phy_cfg( encp->enc_mcdi_mdio_channel = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL); +#if EFSYS_OPT_BIST + encp->enc_bist_mask = 0; + if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, + GET_PHY_CFG_OUT_BIST_CABLE_SHORT)) + encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT); + if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, + GET_PHY_CFG_OUT_BIST_CABLE_LONG)) + encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG); + if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, + GET_PHY_CFG_OUT_BIST)) + encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL); +#endif /* EFSYS_OPT_BIST */ + return (0); fail2: @@ -1542,6 +1555,108 @@ efx_mcdi_mac_spoofing_supported( return (rc); } +#if EFSYS_OPT_BIST + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD +/* + * Enter bist offline mode. This is a fw mode which puts the NIC into a state + * where memory BIST tests can be run and not much else can interfere or happen. + * A reboot is required to exit this mode. + */ + __checkReturn efx_rc_t +efx_mcdi_bist_enable_offline( + __in efx_nic_t *enp) +{ + efx_mcdi_req_t req; + efx_rc_t rc; + + EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0); + EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0); + + req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST; + req.emr_in_buf = NULL; + req.emr_in_length = 0; + req.emr_out_buf = NULL; + req.emr_out_length = 0; + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ + + __checkReturn efx_rc_t +efx_mcdi_bist_start( + __in efx_nic_t *enp, + __in efx_bist_type_t type) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN, + MC_CMD_START_BIST_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_START_BIST; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_START_BIST_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_START_BIST_OUT_LEN; + + switch (type) { + case EFX_BIST_TYPE_PHY_NORMAL: + MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST); + break; + case EFX_BIST_TYPE_PHY_CABLE_SHORT: + MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, + MC_CMD_PHY_BIST_CABLE_SHORT); + break; + case EFX_BIST_TYPE_PHY_CABLE_LONG: + MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, + MC_CMD_PHY_BIST_CABLE_LONG); + break; + case EFX_BIST_TYPE_MC_MEM: + MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, + MC_CMD_MC_MEM_BIST); + break; + case EFX_BIST_TYPE_SAT_MEM: + MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, + MC_CMD_PORT_MEM_BIST); + break; + case EFX_BIST_TYPE_REG: + MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, + MC_CMD_REG_BIST); + break; + default: + EFSYS_ASSERT(0); + } + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +#endif /* EFSYS_OPT_BIST */ + /* Enable logging of some events (e.g. link state changes) */ __checkReturn efx_rc_t diff --git a/drivers/net/sfc/base/efx_mcdi.h b/drivers/net/sfc/base/efx_mcdi.h index a62e921..6e24313 100644 --- a/drivers/net/sfc/base/efx_mcdi.h +++ b/drivers/net/sfc/base/efx_mcdi.h @@ -180,6 +180,18 @@ efx_mcdi_mac_spoofing_supported( __out boolean_t *supportedp); +#if EFSYS_OPT_BIST +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD +extern __checkReturn efx_rc_t +efx_mcdi_bist_enable_offline( + __in efx_nic_t *enp); +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ +extern __checkReturn efx_rc_t +efx_mcdi_bist_start( + __in efx_nic_t *enp, + __in efx_bist_type_t type); +#endif /* EFSYS_OPT_BIST */ + extern __checkReturn efx_rc_t efx_mcdi_get_resource_limits( __in efx_nic_t *enp, diff --git a/drivers/net/sfc/base/efx_phy.c b/drivers/net/sfc/base/efx_phy.c index e7e915e..f07f127 100644 --- a/drivers/net/sfc/base/efx_phy.c +++ b/drivers/net/sfc/base/efx_phy.c @@ -39,6 +39,12 @@ static const efx_phy_ops_t __efx_phy_siena_ops = { siena_phy_reconfigure, /* epo_reconfigure */ siena_phy_verify, /* epo_verify */ siena_phy_oui_get, /* epo_oui_get */ +#if EFSYS_OPT_BIST + NULL, /* epo_bist_enable_offline */ + siena_phy_bist_start, /* epo_bist_start */ + siena_phy_bist_poll, /* epo_bist_poll */ + siena_phy_bist_stop, /* epo_bist_stop */ +#endif /* EFSYS_OPT_BIST */ }; #endif /* EFSYS_OPT_SIENA */ @@ -49,6 +55,12 @@ static const efx_phy_ops_t __efx_phy_ef10_ops = { ef10_phy_reconfigure, /* epo_reconfigure */ ef10_phy_verify, /* epo_verify */ ef10_phy_oui_get, /* epo_oui_get */ +#if EFSYS_OPT_BIST + ef10_bist_enable_offline, /* epo_bist_enable_offline */ + ef10_bist_start, /* epo_bist_start */ + ef10_bist_poll, /* epo_bist_poll */ + ef10_bist_stop, /* epo_bist_stop */ +#endif /* EFSYS_OPT_BIST */ }; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ @@ -266,6 +278,134 @@ efx_phy_module_get_info( } +#if EFSYS_OPT_BIST + + __checkReturn efx_rc_t +efx_bist_enable_offline( + __in efx_nic_t *enp) +{ + efx_port_t *epp = &(enp->en_port); + const efx_phy_ops_t *epop = epp->ep_epop; + efx_rc_t rc; + + EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); + + if (epop->epo_bist_enable_offline == NULL) { + rc = ENOTSUP; + goto fail1; + } + + if ((rc = epop->epo_bist_enable_offline(enp)) != 0) + goto fail2; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); + +} + + __checkReturn efx_rc_t +efx_bist_start( + __in efx_nic_t *enp, + __in efx_bist_type_t type) +{ + efx_port_t *epp = &(enp->en_port); + const efx_phy_ops_t *epop = epp->ep_epop; + efx_rc_t rc; + + EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); + + EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN); + EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES); + EFSYS_ASSERT3U(epp->ep_current_bist, ==, EFX_BIST_TYPE_UNKNOWN); + + if (epop->epo_bist_start == NULL) { + rc = ENOTSUP; + goto fail1; + } + + if ((rc = epop->epo_bist_start(enp, type)) != 0) + goto fail2; + + epp->ep_current_bist = type; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +efx_bist_poll( + __in efx_nic_t *enp, + __in efx_bist_type_t type, + __out efx_bist_result_t *resultp, + __out_opt uint32_t *value_maskp, + __out_ecount_opt(count) unsigned long *valuesp, + __in size_t count) +{ + efx_port_t *epp = &(enp->en_port); + const efx_phy_ops_t *epop = epp->ep_epop; + efx_rc_t rc; + + EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); + + EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN); + EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES); + EFSYS_ASSERT3U(epp->ep_current_bist, ==, type); + + EFSYS_ASSERT(epop->epo_bist_poll != NULL); + if (epop->epo_bist_poll == NULL) { + rc = ENOTSUP; + goto fail1; + } + + if ((rc = epop->epo_bist_poll(enp, type, resultp, value_maskp, + valuesp, count)) != 0) + goto fail2; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +efx_bist_stop( + __in efx_nic_t *enp, + __in efx_bist_type_t type) +{ + efx_port_t *epp = &(enp->en_port); + const efx_phy_ops_t *epop = epp->ep_epop; + + EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); + + EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN); + EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES); + EFSYS_ASSERT3U(epp->ep_current_bist, ==, type); + + EFSYS_ASSERT(epop->epo_bist_stop != NULL); + + if (epop->epo_bist_stop != NULL) + epop->epo_bist_stop(enp, type); + + epp->ep_current_bist = EFX_BIST_TYPE_UNKNOWN; +} + +#endif /* EFSYS_OPT_BIST */ void efx_phy_unprobe( __in efx_nic_t *enp) diff --git a/drivers/net/sfc/base/siena_impl.h b/drivers/net/sfc/base/siena_impl.h index c316867..bdaa4a3 100644 --- a/drivers/net/sfc/base/siena_impl.h +++ b/drivers/net/sfc/base/siena_impl.h @@ -170,6 +170,31 @@ siena_phy_oui_get( __in efx_nic_t *enp, __out uint32_t *ouip); +#if EFSYS_OPT_BIST + +extern __checkReturn efx_rc_t +siena_phy_bist_start( + __in efx_nic_t *enp, + __in efx_bist_type_t type); + +extern __checkReturn efx_rc_t +siena_phy_bist_poll( + __in efx_nic_t *enp, + __in efx_bist_type_t type, + __out efx_bist_result_t *resultp, + __out_opt __drv_when(count > 0, __notnull) + uint32_t *value_maskp, + __out_ecount_opt(count) __drv_when(count > 0, __notnull) + unsigned long *valuesp, + __in size_t count); + +extern void +siena_phy_bist_stop( + __in efx_nic_t *enp, + __in efx_bist_type_t type); + +#endif /* EFSYS_OPT_BIST */ + extern __checkReturn efx_rc_t siena_mac_poll( __in efx_nic_t *enp, diff --git a/drivers/net/sfc/base/siena_phy.c b/drivers/net/sfc/base/siena_phy.c index 0e3fc34..d7e7d77 100644 --- a/drivers/net/sfc/base/siena_phy.c +++ b/drivers/net/sfc/base/siena_phy.c @@ -372,4 +372,209 @@ siena_phy_oui_get( return (ENOTSUP); } +#if EFSYS_OPT_BIST + + __checkReturn efx_rc_t +siena_phy_bist_start( + __in efx_nic_t *enp, + __in efx_bist_type_t type) +{ + efx_rc_t rc; + + if ((rc = efx_mcdi_bist_start(enp, type)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn unsigned long +siena_phy_sft9001_bist_status( + __in uint16_t code) +{ + switch (code) { + case MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY: + return (EFX_PHY_CABLE_STATUS_BUSY); + case MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT: + return (EFX_PHY_CABLE_STATUS_INTERPAIRSHORT); + case MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT: + return (EFX_PHY_CABLE_STATUS_INTRAPAIRSHORT); + case MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN: + return (EFX_PHY_CABLE_STATUS_OPEN); + case MC_CMD_POLL_BIST_SFT9001_PAIR_OK: + return (EFX_PHY_CABLE_STATUS_OK); + default: + return (EFX_PHY_CABLE_STATUS_INVALID); + } +} + + __checkReturn efx_rc_t +siena_phy_bist_poll( + __in efx_nic_t *enp, + __in efx_bist_type_t type, + __out efx_bist_result_t *resultp, + __out_opt __drv_when(count > 0, __notnull) + uint32_t *value_maskp, + __out_ecount_opt(count) __drv_when(count > 0, __notnull) + unsigned long *valuesp, + __in size_t count) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN, + MCDI_CTL_SDU_LEN_MAX)]; + uint32_t value_mask = 0; + efx_mcdi_req_t req; + uint32_t result; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_POLL_BIST; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MCDI_CTL_SDU_LEN_MAX; + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) { + rc = EMSGSIZE; + goto fail2; + } + + if (count > 0) + (void) memset(valuesp, '\0', count * sizeof (unsigned long)); + + result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT); + + /* Extract PHY specific results */ + if (result == MC_CMD_POLL_BIST_PASSED && + encp->enc_phy_type == EFX_PHY_SFT9001B && + req.emr_out_length_used >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN && + (type == EFX_BIST_TYPE_PHY_CABLE_SHORT || + type == EFX_BIST_TYPE_PHY_CABLE_LONG)) { + uint16_t word; + + if (count > EFX_BIST_PHY_CABLE_LENGTH_A) { + if (valuesp != NULL) + valuesp[EFX_BIST_PHY_CABLE_LENGTH_A] = + MCDI_OUT_DWORD(req, + POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A); + value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_A); + } + + if (count > EFX_BIST_PHY_CABLE_LENGTH_B) { + if (valuesp != NULL) + valuesp[EFX_BIST_PHY_CABLE_LENGTH_B] = + MCDI_OUT_DWORD(req, + POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B); + value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_B); + } + + if (count > EFX_BIST_PHY_CABLE_LENGTH_C) { + if (valuesp != NULL) + valuesp[EFX_BIST_PHY_CABLE_LENGTH_C] = + MCDI_OUT_DWORD(req, + POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C); + value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_C); + } + + if (count > EFX_BIST_PHY_CABLE_LENGTH_D) { + if (valuesp != NULL) + valuesp[EFX_BIST_PHY_CABLE_LENGTH_D] = + MCDI_OUT_DWORD(req, + POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D); + value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_D); + } + + if (count > EFX_BIST_PHY_CABLE_STATUS_A) { + if (valuesp != NULL) { + word = MCDI_OUT_WORD(req, + POLL_BIST_OUT_SFT9001_CABLE_STATUS_A); + valuesp[EFX_BIST_PHY_CABLE_STATUS_A] = + siena_phy_sft9001_bist_status(word); + } + value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_A); + } + + if (count > EFX_BIST_PHY_CABLE_STATUS_B) { + if (valuesp != NULL) { + word = MCDI_OUT_WORD(req, + POLL_BIST_OUT_SFT9001_CABLE_STATUS_B); + valuesp[EFX_BIST_PHY_CABLE_STATUS_B] = + siena_phy_sft9001_bist_status(word); + } + value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_B); + } + + if (count > EFX_BIST_PHY_CABLE_STATUS_C) { + if (valuesp != NULL) { + word = MCDI_OUT_WORD(req, + POLL_BIST_OUT_SFT9001_CABLE_STATUS_C); + valuesp[EFX_BIST_PHY_CABLE_STATUS_C] = + siena_phy_sft9001_bist_status(word); + } + value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_C); + } + + if (count > EFX_BIST_PHY_CABLE_STATUS_D) { + if (valuesp != NULL) { + word = MCDI_OUT_WORD(req, + POLL_BIST_OUT_SFT9001_CABLE_STATUS_D); + valuesp[EFX_BIST_PHY_CABLE_STATUS_D] = + siena_phy_sft9001_bist_status(word); + } + value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_D); + } + + } else if (result == MC_CMD_POLL_BIST_FAILED && + encp->enc_phy_type == EFX_PHY_QLX111V && + req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN && + count > EFX_BIST_FAULT_CODE) { + if (valuesp != NULL) + valuesp[EFX_BIST_FAULT_CODE] = + MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST); + value_mask |= 1 << EFX_BIST_FAULT_CODE; + } + + if (value_maskp != NULL) + *value_maskp = value_mask; + + EFSYS_ASSERT(resultp != NULL); + if (result == MC_CMD_POLL_BIST_RUNNING) + *resultp = EFX_BIST_RESULT_RUNNING; + else if (result == MC_CMD_POLL_BIST_PASSED) + *resultp = EFX_BIST_RESULT_PASSED; + else + *resultp = EFX_BIST_RESULT_FAILED; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +siena_phy_bist_stop( + __in efx_nic_t *enp, + __in efx_bist_type_t type) +{ + /* There is no way to stop BIST on Siena */ + _NOTE(ARGUNUSED(enp, type)) +} + +#endif /* EFSYS_OPT_BIST */ + #endif /* EFSYS_OPT_SIENA */