diff options
author | arybchik <arybchik@FreeBSD.org> | 2016-06-04 15:24:11 +0000 |
---|---|---|
committer | arybchik <arybchik@FreeBSD.org> | 2016-06-04 15:24:11 +0000 |
commit | 45da1f7e9b0430d2c1b95adb91935570bb94eda2 (patch) | |
tree | 113ca5dd6410c94da9f409d1e61777982256ff7e /sys/dev | |
parent | 3ddc776297ba8bf326cffe45b938dac77506a5a9 (diff) | |
download | FreeBSD-src-45da1f7e9b0430d2c1b95adb91935570bb94eda2.zip FreeBSD-src-45da1f7e9b0430d2c1b95adb91935570bb94eda2.tar.gz |
MFC r299596-r299606, r299681, r299726, r299738
sfxge(4): move ef10_*() functions to ef10_*.c files
Submitted by: Andy Moreton <amoreton at solarflare.com>
Sponsored by: Solarflare Communications, Inc.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/sfxge/common/ef10_ev.c (renamed from sys/dev/sfxge/common/hunt_ev.c) | 4 | ||||
-rw-r--r-- | sys/dev/sfxge/common/ef10_filter.c (renamed from sys/dev/sfxge/common/hunt_filter.c) | 4 | ||||
-rw-r--r-- | sys/dev/sfxge/common/ef10_intr.c (renamed from sys/dev/sfxge/common/hunt_intr.c) | 4 | ||||
-rw-r--r-- | sys/dev/sfxge/common/ef10_mac.c (renamed from sys/dev/sfxge/common/hunt_mac.c) | 4 | ||||
-rw-r--r-- | sys/dev/sfxge/common/ef10_mcdi.c (renamed from sys/dev/sfxge/common/hunt_mcdi.c) | 0 | ||||
-rw-r--r-- | sys/dev/sfxge/common/ef10_nic.c | 1616 | ||||
-rw-r--r-- | sys/dev/sfxge/common/ef10_nvram.c (renamed from sys/dev/sfxge/common/hunt_nvram.c) | 6 | ||||
-rw-r--r-- | sys/dev/sfxge/common/ef10_phy.c | 518 | ||||
-rw-r--r-- | sys/dev/sfxge/common/ef10_rx.c (renamed from sys/dev/sfxge/common/hunt_rx.c) | 4 | ||||
-rwxr-xr-x | sys/dev/sfxge/common/ef10_tx.c (renamed from sys/dev/sfxge/common/hunt_tx.c) | 6 | ||||
-rw-r--r-- | sys/dev/sfxge/common/ef10_vpd.c (renamed from sys/dev/sfxge/common/hunt_vpd.c) | 4 | ||||
-rw-r--r-- | sys/dev/sfxge/common/efx_tx.c | 2 | ||||
-rw-r--r-- | sys/dev/sfxge/common/hunt_impl.h | 2 | ||||
-rw-r--r-- | sys/dev/sfxge/common/hunt_nic.c | 1573 | ||||
-rw-r--r-- | sys/dev/sfxge/common/hunt_phy.c | 479 |
15 files changed, 2154 insertions, 2072 deletions
diff --git a/sys/dev/sfxge/common/hunt_ev.c b/sys/dev/sfxge/common/ef10_ev.c index 1a41b49..0110c86 100644 --- a/sys/dev/sfxge/common/hunt_ev.c +++ b/sys/dev/sfxge/common/ef10_ev.c @@ -37,7 +37,7 @@ __FBSDID("$FreeBSD$"); #include "mcdi_mon.h" #endif -#if EFSYS_OPT_HUNTINGTON +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD #if EFSYS_OPT_QSTATS #define EFX_EV_QSTAT_INCR(_eep, _stat) \ @@ -985,4 +985,4 @@ ef10_ev_rxlabel_fini( eersp->eers_rx_mask = 0; } -#endif /* EFSYS_OPT_HUNTINGTON */ +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ diff --git a/sys/dev/sfxge/common/hunt_filter.c b/sys/dev/sfxge/common/ef10_filter.c index 57c9630..3795142 100644 --- a/sys/dev/sfxge/common/hunt_filter.c +++ b/sys/dev/sfxge/common/ef10_filter.c @@ -34,7 +34,7 @@ __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" -#if EFSYS_OPT_HUNTINGTON +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD #if EFSYS_OPT_FILTER @@ -1479,4 +1479,4 @@ ef10_filter_default_rxq_clear( #endif /* EFSYS_OPT_FILTER */ -#endif /* EFSYS_OPT_HUNTINGTON */ +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ diff --git a/sys/dev/sfxge/common/hunt_intr.c b/sys/dev/sfxge/common/ef10_intr.c index 7a4293c..5a91fe1 100644 --- a/sys/dev/sfxge/common/hunt_intr.c +++ b/sys/dev/sfxge/common/ef10_intr.c @@ -35,7 +35,7 @@ __FBSDID("$FreeBSD$"); #include "efx_impl.h" -#if EFSYS_OPT_HUNTINGTON +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD __checkReturn efx_rc_t ef10_intr_init( @@ -197,4 +197,4 @@ ef10_intr_fini( _NOTE(ARGUNUSED(enp)) } -#endif /* EFSYS_OPT_HUNTINGTON */ +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ diff --git a/sys/dev/sfxge/common/hunt_mac.c b/sys/dev/sfxge/common/ef10_mac.c index 267be0c..6546ef1 100644 --- a/sys/dev/sfxge/common/hunt_mac.c +++ b/sys/dev/sfxge/common/ef10_mac.c @@ -35,7 +35,7 @@ __FBSDID("$FreeBSD$"); #include "efx_impl.h" -#if EFSYS_OPT_HUNTINGTON +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD __checkReturn efx_rc_t ef10_mac_poll( @@ -749,4 +749,4 @@ ef10_mac_stats_update( #endif /* EFSYS_OPT_MAC_STATS */ -#endif /* EFSYS_OPT_HUNTINGTON */ +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ diff --git a/sys/dev/sfxge/common/hunt_mcdi.c b/sys/dev/sfxge/common/ef10_mcdi.c index f39e977..f39e977 100644 --- a/sys/dev/sfxge/common/hunt_mcdi.c +++ b/sys/dev/sfxge/common/ef10_mcdi.c diff --git a/sys/dev/sfxge/common/ef10_nic.c b/sys/dev/sfxge/common/ef10_nic.c new file mode 100644 index 0000000..493f4a0 --- /dev/null +++ b/sys/dev/sfxge/common/ef10_nic.c @@ -0,0 +1,1616 @@ +/*- + * Copyright (c) 2012-2015 Solarflare Communications Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" +#if EFSYS_OPT_MON_MCDI +#include "mcdi_mon.h" +#endif + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + +#include "ef10_tlv_layout.h" + + __checkReturn efx_rc_t +efx_mcdi_get_port_assignment( + __in efx_nic_t *enp, + __out uint32_t *portp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN, + MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN)]; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_PORT_ASSIGNMENT; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_PORT_ASSIGNMENT_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_PORT_ASSIGNMENT_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + *portp = MCDI_OUT_DWORD(req, GET_PORT_ASSIGNMENT_OUT_PORT); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +efx_mcdi_get_port_modes( + __in efx_nic_t *enp, + __out uint32_t *modesp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_PORT_MODES_IN_LEN, + MC_CMD_GET_PORT_MODES_OUT_LEN)]; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_PORT_MODES; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN; + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + /* + * Require only Modes and DefaultMode fields. + * (CurrentMode field was added for Medford) + */ + if (req.emr_out_length_used < + MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) { + rc = EMSGSIZE; + goto fail2; + } + + *modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + +static __checkReturn efx_rc_t +efx_mcdi_vadaptor_alloc( + __in efx_nic_t *enp, + __in uint32_t port_id) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_VADAPTOR_ALLOC_IN_LEN, + MC_CMD_VADAPTOR_ALLOC_OUT_LEN)]; + efx_rc_t rc; + + EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_VADAPTOR_ALLOC; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN; + + MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); + MCDI_IN_POPULATE_DWORD_1(req, VADAPTOR_ALLOC_IN_FLAGS, + VADAPTOR_ALLOC_IN_FLAG_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED, + enp->en_nic_cfg.enc_allow_set_mac_with_installed_filters ? 1 : 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); +} + +static __checkReturn efx_rc_t +efx_mcdi_vadaptor_free( + __in efx_nic_t *enp, + __in uint32_t port_id) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_VADAPTOR_FREE_IN_LEN, + MC_CMD_VADAPTOR_FREE_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_VADAPTOR_FREE; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN; + + MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); + + 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); +} + + __checkReturn efx_rc_t +efx_mcdi_get_mac_address_pf( + __in efx_nic_t *enp, + __out_ecount_opt(6) uint8_t mac_addrp[6]) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_MAC_ADDRESSES_IN_LEN, + MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)]; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_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_MAC_ADDRESSES_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) { + rc = ENOENT; + goto fail3; + } + + if (mac_addrp != NULL) { + uint8_t *addrp; + + addrp = MCDI_OUT2(req, uint8_t, + GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE); + + EFX_MAC_ADDR_COPY(mac_addrp, addrp); + } + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +efx_mcdi_get_mac_address_vf( + __in efx_nic_t *enp, + __out_ecount_opt(6) uint8_t mac_addrp[6]) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN, + MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX)]; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX; + + MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID, + EVB_PORT_ID_ASSIGNED); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < + MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) { + rc = EMSGSIZE; + goto fail2; + } + + if (MCDI_OUT_DWORD(req, + VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) { + rc = ENOENT; + goto fail3; + } + + if (mac_addrp != NULL) { + uint8_t *addrp; + + addrp = MCDI_OUT2(req, uint8_t, + VPORT_GET_MAC_ADDRESSES_OUT_MACADDR); + + EFX_MAC_ADDR_COPY(mac_addrp, addrp); + } + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +efx_mcdi_get_clock( + __in efx_nic_t *enp, + __out uint32_t *sys_freqp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_CLOCK_IN_LEN, + MC_CMD_GET_CLOCK_OUT_LEN)]; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_CLOCK; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_CLOCK_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_CLOCK_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + *sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ); + if (*sys_freqp == 0) { + rc = EINVAL; + goto fail3; + } + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +efx_mcdi_get_vector_cfg( + __in efx_nic_t *enp, + __out_opt uint32_t *vec_basep, + __out_opt uint32_t *pf_nvecp, + __out_opt uint32_t *vf_nvecp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_VECTOR_CFG_IN_LEN, + MC_CMD_GET_VECTOR_CFG_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_VECTOR_CFG; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_VECTOR_CFG_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_VECTOR_CFG_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + if (vec_basep != NULL) + *vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE); + if (pf_nvecp != NULL) + *pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF); + if (vf_nvecp != NULL) + *vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +efx_mcdi_get_capabilities( + __in efx_nic_t *enp, + __out uint32_t *flagsp, + __out uint32_t *flags2p) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN, + MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_CAPABILITIES; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_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_CAPABILITIES_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1); + + if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN) + *flags2p = 0; + else + *flags2p = MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + +static __checkReturn efx_rc_t +efx_mcdi_alloc_vis( + __in efx_nic_t *enp, + __in uint32_t min_vi_count, + __in uint32_t max_vi_count, + __out uint32_t *vi_basep, + __out uint32_t *vi_countp, + __out uint32_t *vi_shiftp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_ALLOC_VIS_IN_LEN, + MC_CMD_ALLOC_VIS_OUT_LEN)]; + efx_rc_t rc; + + if (vi_countp == NULL) { + rc = EINVAL; + goto fail1; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_ALLOC_VIS; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_ALLOC_VIS_OUT_LEN; + + MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count); + MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) { + rc = EMSGSIZE; + goto fail3; + } + + *vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE); + *vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT); + + /* Report VI_SHIFT if available (always zero for Huntington) */ + if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_EXT_OUT_LEN) + *vi_shiftp = 0; + else + *vi_shiftp = MCDI_OUT_DWORD(req, ALLOC_VIS_EXT_OUT_VI_SHIFT); + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + +static __checkReturn efx_rc_t +efx_mcdi_free_vis( + __in efx_nic_t *enp) +{ + efx_mcdi_req_t req; + efx_rc_t rc; + + EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0); + EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0); + + req.emr_cmd = MC_CMD_FREE_VIS; + req.emr_in_buf = NULL; + req.emr_in_length = 0; + req.emr_out_buf = NULL; + req.emr_out_length = 0; + + efx_mcdi_execute_quiet(enp, &req); + + /* Ignore ELREADY (no allocated VIs, so nothing to free) */ + if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + +static __checkReturn efx_rc_t +efx_mcdi_alloc_piobuf( + __in efx_nic_t *enp, + __out efx_piobuf_handle_t *handlep) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_ALLOC_PIOBUF_IN_LEN, + MC_CMD_ALLOC_PIOBUF_OUT_LEN)]; + efx_rc_t rc; + + if (handlep == NULL) { + rc = EINVAL; + goto fail1; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_ALLOC_PIOBUF; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN; + + efx_mcdi_execute_quiet(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) { + rc = EMSGSIZE; + goto fail3; + } + + *handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE); + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +efx_mcdi_free_piobuf( + __in efx_nic_t *enp, + __in efx_piobuf_handle_t handle) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_FREE_PIOBUF_IN_LEN, + MC_CMD_FREE_PIOBUF_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_FREE_PIOBUF; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN; + + MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle); + + efx_mcdi_execute_quiet(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); +} + +static __checkReturn efx_rc_t +efx_mcdi_link_piobuf( + __in efx_nic_t *enp, + __in uint32_t vi_index, + __in efx_piobuf_handle_t handle) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_LINK_PIOBUF_IN_LEN, + MC_CMD_LINK_PIOBUF_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_LINK_PIOBUF; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN; + + MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle); + MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); + + 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); +} + +static __checkReturn efx_rc_t +efx_mcdi_unlink_piobuf( + __in efx_nic_t *enp, + __in uint32_t vi_index) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_UNLINK_PIOBUF_IN_LEN, + MC_CMD_UNLINK_PIOBUF_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_UNLINK_PIOBUF; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN; + + MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); + + 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); +} + +static void +ef10_nic_alloc_piobufs( + __in efx_nic_t *enp, + __in uint32_t max_piobuf_count) +{ + efx_piobuf_handle_t *handlep; + unsigned int i; + efx_rc_t rc; + + EFSYS_ASSERT3U(max_piobuf_count, <=, + EFX_ARRAY_SIZE(enp->en_arch.ef10.ena_piobuf_handle)); + + enp->en_arch.ef10.ena_piobuf_count = 0; + + for (i = 0; i < max_piobuf_count; i++) { + handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; + + if ((rc = efx_mcdi_alloc_piobuf(enp, handlep)) != 0) + goto fail1; + + enp->en_arch.ef10.ena_pio_alloc_map[i] = 0; + enp->en_arch.ef10.ena_piobuf_count++; + } + + return; + +fail1: + for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { + handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; + + efx_mcdi_free_piobuf(enp, *handlep); + *handlep = EFX_PIOBUF_HANDLE_INVALID; + } + enp->en_arch.ef10.ena_piobuf_count = 0; +} + + +static void +ef10_nic_free_piobufs( + __in efx_nic_t *enp) +{ + efx_piobuf_handle_t *handlep; + unsigned int i; + + for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { + handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; + + efx_mcdi_free_piobuf(enp, *handlep); + *handlep = EFX_PIOBUF_HANDLE_INVALID; + } + enp->en_arch.ef10.ena_piobuf_count = 0; +} + +/* Sub-allocate a block from a piobuf */ + __checkReturn efx_rc_t +ef10_nic_pio_alloc( + __inout efx_nic_t *enp, + __out uint32_t *bufnump, + __out efx_piobuf_handle_t *handlep, + __out uint32_t *blknump, + __out uint32_t *offsetp, + __out size_t *sizep) +{ + efx_nic_cfg_t *encp = &enp->en_nic_cfg; + efx_drv_cfg_t *edcp = &enp->en_drv_cfg; + uint32_t blk_per_buf; + uint32_t buf, blk; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + EFSYS_ASSERT(bufnump); + EFSYS_ASSERT(handlep); + EFSYS_ASSERT(blknump); + EFSYS_ASSERT(offsetp); + EFSYS_ASSERT(sizep); + + if ((edcp->edc_pio_alloc_size == 0) || + (enp->en_arch.ef10.ena_piobuf_count == 0)) { + rc = ENOMEM; + goto fail1; + } + blk_per_buf = encp->enc_piobuf_size / edcp->edc_pio_alloc_size; + + for (buf = 0; buf < enp->en_arch.ef10.ena_piobuf_count; buf++) { + uint32_t *map = &enp->en_arch.ef10.ena_pio_alloc_map[buf]; + + if (~(*map) == 0) + continue; + + EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map))); + for (blk = 0; blk < blk_per_buf; blk++) { + if ((*map & (1u << blk)) == 0) { + *map |= (1u << blk); + goto done; + } + } + } + rc = ENOMEM; + goto fail2; + +done: + *handlep = enp->en_arch.ef10.ena_piobuf_handle[buf]; + *bufnump = buf; + *blknump = blk; + *sizep = edcp->edc_pio_alloc_size; + *offsetp = blk * (*sizep); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* Free a piobuf sub-allocated block */ + __checkReturn efx_rc_t +ef10_nic_pio_free( + __inout efx_nic_t *enp, + __in uint32_t bufnum, + __in uint32_t blknum) +{ + uint32_t *map; + efx_rc_t rc; + + if ((bufnum >= enp->en_arch.ef10.ena_piobuf_count) || + (blknum >= (8 * sizeof (*map)))) { + rc = EINVAL; + goto fail1; + } + + map = &enp->en_arch.ef10.ena_pio_alloc_map[bufnum]; + if ((*map & (1u << blknum)) == 0) { + rc = ENOENT; + goto fail2; + } + *map &= ~(1u << blknum); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nic_pio_link( + __inout efx_nic_t *enp, + __in uint32_t vi_index, + __in efx_piobuf_handle_t handle) +{ + return (efx_mcdi_link_piobuf(enp, vi_index, handle)); +} + + __checkReturn efx_rc_t +ef10_nic_pio_unlink( + __inout efx_nic_t *enp, + __in uint32_t vi_index) +{ + return (efx_mcdi_unlink_piobuf(enp, vi_index)); +} + + __checkReturn efx_rc_t +ef10_get_datapath_caps( + __in efx_nic_t *enp) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + uint32_t flags; + uint32_t flags2; + efx_rc_t rc; + + if ((rc = efx_mcdi_get_capabilities(enp, &flags, &flags2)) != 0) + goto fail1; + +#define CAP_FLAG(flags1, field) \ + ((flags1) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN))) + +#define CAP_FLAG2(flags2, field) \ + ((flags2) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN))) + + /* + * Huntington RXDP firmware inserts a 0 or 14 byte prefix. + * We only support the 14 byte prefix here. + */ + if (CAP_FLAG(flags, RX_PREFIX_LEN_14) == 0) { + rc = ENOTSUP; + goto fail2; + } + encp->enc_rx_prefix_size = 14; + + /* Check if the firmware supports TSO */ + encp->enc_fw_assisted_tso_enabled = + CAP_FLAG(flags, TX_TSO) ? B_TRUE : B_FALSE; + + /* Check if the firmware supports FATSOv2 */ + encp->enc_fw_assisted_tso_v2_enabled = + CAP_FLAG2(flags2, TX_TSO_V2) ? B_TRUE : B_FALSE; + + /* Check if the firmware has vadapter/vport/vswitch support */ + encp->enc_datapath_cap_evb = + CAP_FLAG(flags, EVB) ? B_TRUE : B_FALSE; + + /* Check if the firmware supports VLAN insertion */ + encp->enc_hw_tx_insert_vlan_enabled = + CAP_FLAG(flags, TX_VLAN_INSERTION) ? B_TRUE : B_FALSE; + + /* Check if the firmware supports RX event batching */ + encp->enc_rx_batching_enabled = + CAP_FLAG(flags, RX_BATCHING) ? B_TRUE : B_FALSE; + + if (encp->enc_rx_batching_enabled) + encp->enc_rx_batch_max = 16; + + /* Check if the firmware supports disabling scatter on RXQs */ + encp->enc_rx_disable_scatter_supported = + CAP_FLAG(flags, RX_DISABLE_SCATTER) ? B_TRUE : B_FALSE; + + /* Check if the firmware supports set mac with running filters */ + encp->enc_allow_set_mac_with_installed_filters = + CAP_FLAG(flags, VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED) ? + B_TRUE : B_FALSE; + + /* + * Check if firmware supports the extended MC_CMD_SET_MAC, which allows + * specifying which parameters to configure. + */ + encp->enc_enhanced_set_mac_supported = + CAP_FLAG(flags, SET_MAC_ENHANCED) ? B_TRUE : B_FALSE; + +#undef CAP_FLAG +#undef CAP_FLAG2 + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + + __checkReturn efx_rc_t +ef10_get_privilege_mask( + __in efx_nic_t *enp, + __out uint32_t *maskp) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + uint32_t mask; + efx_rc_t rc; + + if ((rc = efx_mcdi_privilege_mask(enp, encp->enc_pf, encp->enc_vf, + &mask)) != 0) { + if (rc != ENOTSUP) + goto fail1; + + /* Fallback for old firmware without privilege mask support */ + if (EFX_PCI_FUNCTION_IS_PF(encp)) { + /* Assume PF has admin privilege */ + mask = EF10_LEGACY_PF_PRIVILEGE_MASK; + } else { + /* VF is always unprivileged by default */ + mask = EF10_LEGACY_VF_PRIVILEGE_MASK; + } + } + + *maskp = mask; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + +/* + * The external port mapping is a one-based numbering of the external + * connectors on the board. It does not distinguish off-board separated + * outputs such as multi-headed cables. + * The number of ports that map to each external port connector + * on the board is determined by the chip family and the port modes to + * which the NIC can be configured. The mapping table lists modes with + * port numbering requirements in increasing order. + */ +static struct { + efx_family_t family; + uint32_t modes_mask; + uint32_t stride; +} __ef10_external_port_mappings[] = { + /* Supported modes requiring 1 output per port */ + { + EFX_FAMILY_HUNTINGTON, + (1 << TLV_PORT_MODE_10G) | + (1 << TLV_PORT_MODE_10G_10G) | + (1 << TLV_PORT_MODE_10G_10G_10G_10G), + 1 + }, + { + EFX_FAMILY_MEDFORD, + (1 << TLV_PORT_MODE_10G) | + (1 << TLV_PORT_MODE_10G_10G) | + (1 << TLV_PORT_MODE_10G_10G_10G_10G), + 1 + }, + /* Supported modes requiring 2 outputs per port */ + { + EFX_FAMILY_HUNTINGTON, + (1 << TLV_PORT_MODE_40G) | + (1 << TLV_PORT_MODE_40G_40G) | + (1 << TLV_PORT_MODE_40G_10G_10G) | + (1 << TLV_PORT_MODE_10G_10G_40G), + 2 + }, + { + EFX_FAMILY_MEDFORD, + (1 << TLV_PORT_MODE_40G) | + (1 << TLV_PORT_MODE_40G_40G) | + (1 << TLV_PORT_MODE_40G_10G_10G) | + (1 << TLV_PORT_MODE_10G_10G_40G), + 2 + }, + /* Supported modes requiring 4 outputs per port */ + { + EFX_FAMILY_MEDFORD, + (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q) | + (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q2), + 4 + }, +}; + + __checkReturn efx_rc_t +ef10_external_port_mapping( + __in efx_nic_t *enp, + __in uint32_t port, + __out uint8_t *external_portp) +{ + efx_rc_t rc; + int i; + uint32_t port_modes; + uint32_t matches; + uint32_t stride = 1; /* default 1-1 mapping */ + + if ((rc = efx_mcdi_get_port_modes(enp, &port_modes)) != 0) { + /* No port mode information available - use default mapping */ + goto out; + } + + /* + * Infer the internal port -> external port mapping from + * the possible port modes for this NIC. + */ + for (i = 0; i < EFX_ARRAY_SIZE(__ef10_external_port_mappings); ++i) { + if (__ef10_external_port_mappings[i].family != + enp->en_family) + continue; + matches = (__ef10_external_port_mappings[i].modes_mask & + port_modes); + if (matches != 0) { + stride = __ef10_external_port_mappings[i].stride; + port_modes &= ~matches; + } + } + + if (port_modes != 0) { + /* Some advertised modes are not supported */ + rc = ENOTSUP; + goto fail1; + } + +out: + /* + * Scale as required by last matched mode and then convert to + * one-based numbering + */ + *external_portp = (uint8_t)(port / stride) + 1; + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + + __checkReturn efx_rc_t +ef10_nic_probe( + __in efx_nic_t *enp) +{ + const efx_nic_ops_t *enop = enp->en_enop; + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* Read and clear any assertion state */ + if ((rc = efx_mcdi_read_assertion(enp)) != 0) + goto fail1; + + /* Exit the assertion handler */ + if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) + if (rc != EACCES) + goto fail2; + + if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0) + goto fail3; + + if ((rc = enop->eno_board_cfg(enp)) != 0) + if (rc != EACCES) + goto fail4; + + /* + * Set default driver config limits (based on board config). + * + * FIXME: For now allocate a fixed number of VIs which is likely to be + * sufficient and small enough to allow multiple functions on the same + * port. + */ + edcp->edc_min_vi_count = edcp->edc_max_vi_count = + MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit)); + + /* The client driver must configure and enable PIO buffer support */ + edcp->edc_max_piobuf_count = 0; + edcp->edc_pio_alloc_size = 0; + +#if EFSYS_OPT_MAC_STATS + /* Wipe the MAC statistics */ + if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0) + goto fail5; +#endif + +#if EFSYS_OPT_LOOPBACK + if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0) + goto fail6; +#endif + +#if EFSYS_OPT_MON_STATS + if ((rc = mcdi_mon_cfg_build(enp)) != 0) { + /* Unprivileged functions do not have access to sensors */ + if (rc != EACCES) + goto fail7; + } +#endif + + encp->enc_features = enp->en_features; + + return (0); + +#if EFSYS_OPT_MON_STATS +fail7: + EFSYS_PROBE(fail7); +#endif +#if EFSYS_OPT_LOOPBACK +fail6: + EFSYS_PROBE(fail6); +#endif +#if EFSYS_OPT_MAC_STATS +fail5: + EFSYS_PROBE(fail5); +#endif +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nic_set_drv_limits( + __inout efx_nic_t *enp, + __in efx_drv_limits_t *edlp) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); + uint32_t min_evq_count, max_evq_count; + uint32_t min_rxq_count, max_rxq_count; + uint32_t min_txq_count, max_txq_count; + efx_rc_t rc; + + if (edlp == NULL) { + rc = EINVAL; + goto fail1; + } + + /* Get minimum required and maximum usable VI limits */ + min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit); + min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit); + min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit); + + edcp->edc_min_vi_count = + MAX(min_evq_count, MAX(min_rxq_count, min_txq_count)); + + max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit); + max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit); + max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit); + + edcp->edc_max_vi_count = + MAX(max_evq_count, MAX(max_rxq_count, max_txq_count)); + + /* + * Check limits for sub-allocated piobuf blocks. + * PIO is optional, so don't fail if the limits are incorrect. + */ + if ((encp->enc_piobuf_size == 0) || + (encp->enc_piobuf_limit == 0) || + (edlp->edl_min_pio_alloc_size == 0) || + (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) { + /* Disable PIO */ + edcp->edc_max_piobuf_count = 0; + edcp->edc_pio_alloc_size = 0; + } else { + uint32_t blk_size, blk_count, blks_per_piobuf; + + blk_size = + MAX(edlp->edl_min_pio_alloc_size, + encp->enc_piobuf_min_alloc_size); + + blks_per_piobuf = encp->enc_piobuf_size / blk_size; + EFSYS_ASSERT3U(blks_per_piobuf, <=, 32); + + blk_count = (encp->enc_piobuf_limit * blks_per_piobuf); + + /* A zero max pio alloc count means unlimited */ + if ((edlp->edl_max_pio_alloc_count > 0) && + (edlp->edl_max_pio_alloc_count < blk_count)) { + blk_count = edlp->edl_max_pio_alloc_count; + } + + edcp->edc_pio_alloc_size = blk_size; + edcp->edc_max_piobuf_count = + (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + + __checkReturn efx_rc_t +ef10_nic_reset( + __in efx_nic_t *enp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN, + MC_CMD_ENTITY_RESET_OUT_LEN)]; + efx_rc_t rc; + + /* ef10_nic_reset() is called to recover from BADASSERT failures. */ + if ((rc = efx_mcdi_read_assertion(enp)) != 0) + goto fail1; + if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) + goto fail2; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_ENTITY_RESET; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN; + + MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG, + ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail3; + } + + /* Clear RX/TX DMA queue errors */ + enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR); + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nic_init( + __in efx_nic_t *enp) +{ + efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); + uint32_t min_vi_count, max_vi_count; + uint32_t vi_count, vi_base, vi_shift; + uint32_t i; + uint32_t retry; + uint32_t delay_us; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* Enable reporting of some events (e.g. link change) */ + if ((rc = efx_mcdi_log_ctrl(enp)) != 0) + goto fail1; + + /* Allocate (optional) on-chip PIO buffers */ + ef10_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count); + + /* + * For best performance, PIO writes should use a write-combined + * (WC) memory mapping. Using a separate WC mapping for the PIO + * aperture of each VI would be a burden to drivers (and not + * possible if the host page size is >4Kbyte). + * + * To avoid this we use a single uncached (UC) mapping for VI + * register access, and a single WC mapping for extra VIs used + * for PIO writes. + * + * Each piobuf must be linked to a VI in the WC mapping, and to + * each VI that is using a sub-allocated block from the piobuf. + */ + min_vi_count = edcp->edc_min_vi_count; + max_vi_count = + edcp->edc_max_vi_count + enp->en_arch.ef10.ena_piobuf_count; + + /* Ensure that the previously attached driver's VIs are freed */ + if ((rc = efx_mcdi_free_vis(enp)) != 0) + goto fail2; + + /* + * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this + * fails then retrying the request for fewer VI resources may succeed. + */ + vi_count = 0; + if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count, + &vi_base, &vi_count, &vi_shift)) != 0) + goto fail3; + + EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count); + + if (vi_count < min_vi_count) { + rc = ENOMEM; + goto fail4; + } + + enp->en_arch.ef10.ena_vi_base = vi_base; + enp->en_arch.ef10.ena_vi_count = vi_count; + enp->en_arch.ef10.ena_vi_shift = vi_shift; + + if (vi_count < min_vi_count + enp->en_arch.ef10.ena_piobuf_count) { + /* Not enough extra VIs to map piobufs */ + ef10_nic_free_piobufs(enp); + } + + enp->en_arch.ef10.ena_pio_write_vi_base = + vi_count - enp->en_arch.ef10.ena_piobuf_count; + + /* Save UC memory mapping details */ + enp->en_arch.ef10.ena_uc_mem_map_offset = 0; + if (enp->en_arch.ef10.ena_piobuf_count > 0) { + enp->en_arch.ef10.ena_uc_mem_map_size = + (ER_DZ_TX_PIOBUF_STEP * + enp->en_arch.ef10.ena_pio_write_vi_base); + } else { + enp->en_arch.ef10.ena_uc_mem_map_size = + (ER_DZ_TX_PIOBUF_STEP * + enp->en_arch.ef10.ena_vi_count); + } + + /* Save WC memory mapping details */ + enp->en_arch.ef10.ena_wc_mem_map_offset = + enp->en_arch.ef10.ena_uc_mem_map_offset + + enp->en_arch.ef10.ena_uc_mem_map_size; + + enp->en_arch.ef10.ena_wc_mem_map_size = + (ER_DZ_TX_PIOBUF_STEP * + enp->en_arch.ef10.ena_piobuf_count); + + /* Link piobufs to extra VIs in WC mapping */ + if (enp->en_arch.ef10.ena_piobuf_count > 0) { + for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { + rc = efx_mcdi_link_piobuf(enp, + enp->en_arch.ef10.ena_pio_write_vi_base + i, + enp->en_arch.ef10.ena_piobuf_handle[i]); + if (rc != 0) + break; + } + } + + /* + * Allocate a vAdaptor attached to our upstream vPort/pPort. + * + * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF + * driver has yet to bring up the EVB port. See bug 56147. In this case, + * retry the request several times after waiting a while. The wait time + * between retries starts small (10ms) and exponentially increases. + * Total wait time is a little over two seconds. Retry logic in the + * client driver may mean this whole loop is repeated if it continues to + * fail. + */ + retry = 0; + delay_us = 10000; + while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) { + if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) || + (rc != ENOENT)) { + /* + * Do not retry alloc for PF, or for other errors on + * a VF. + */ + goto fail5; + } + + /* VF startup before PF is ready. Retry allocation. */ + if (retry > 5) { + /* Too many attempts */ + rc = EINVAL; + goto fail6; + } + EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry); + EFSYS_SLEEP(delay_us); + retry++; + if (delay_us < 500000) + delay_us <<= 2; + } + + enp->en_vport_id = EVB_PORT_ID_ASSIGNED; + enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V2; + + return (0); + +fail6: + EFSYS_PROBE(fail6); +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); + + ef10_nic_free_piobufs(enp); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nic_get_vi_pool( + __in efx_nic_t *enp, + __out uint32_t *vi_countp) +{ + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* + * Report VIs that the client driver can use. + * Do not include VIs used for PIO buffer writes. + */ + *vi_countp = enp->en_arch.ef10.ena_pio_write_vi_base; + + return (0); +} + + __checkReturn efx_rc_t +ef10_nic_get_bar_region( + __in efx_nic_t *enp, + __in efx_nic_region_t region, + __out uint32_t *offsetp, + __out size_t *sizep) +{ + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* + * TODO: Specify host memory mapping alignment and granularity + * in efx_drv_limits_t so that they can be taken into account + * when allocating extra VIs for PIO writes. + */ + switch (region) { + case EFX_REGION_VI: + /* UC mapped memory BAR region for VI registers */ + *offsetp = enp->en_arch.ef10.ena_uc_mem_map_offset; + *sizep = enp->en_arch.ef10.ena_uc_mem_map_size; + break; + + case EFX_REGION_PIO_WRITE_VI: + /* WC mapped memory BAR region for piobuf writes */ + *offsetp = enp->en_arch.ef10.ena_wc_mem_map_offset; + *sizep = enp->en_arch.ef10.ena_wc_mem_map_size; + break; + + default: + rc = EINVAL; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_nic_fini( + __in efx_nic_t *enp) +{ + uint32_t i; + efx_rc_t rc; + + (void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id); + enp->en_vport_id = 0; + + /* Unlink piobufs from extra VIs in WC mapping */ + if (enp->en_arch.ef10.ena_piobuf_count > 0) { + for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { + rc = efx_mcdi_unlink_piobuf(enp, + enp->en_arch.ef10.ena_pio_write_vi_base + i); + if (rc != 0) + break; + } + } + + ef10_nic_free_piobufs(enp); + + (void) efx_mcdi_free_vis(enp); + enp->en_arch.ef10.ena_vi_count = 0; +} + + void +ef10_nic_unprobe( + __in efx_nic_t *enp) +{ +#if EFSYS_OPT_MON_STATS + mcdi_mon_cfg_free(enp); +#endif /* EFSYS_OPT_MON_STATS */ + (void) efx_mcdi_drv_attach(enp, B_FALSE); +} + +#if EFSYS_OPT_DIAG + + __checkReturn efx_rc_t +ef10_nic_register_test( + __in efx_nic_t *enp) +{ + efx_rc_t rc; + + /* FIXME */ + _NOTE(ARGUNUSED(enp)) + if (B_FALSE) { + rc = ENOTSUP; + goto fail1; + } + /* FIXME */ + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +#endif /* EFSYS_OPT_DIAG */ + + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ diff --git a/sys/dev/sfxge/common/hunt_nvram.c b/sys/dev/sfxge/common/ef10_nvram.c index 0e19e7b..e63ba87 100644 --- a/sys/dev/sfxge/common/hunt_nvram.c +++ b/sys/dev/sfxge/common/ef10_nvram.c @@ -34,7 +34,7 @@ __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" -#if EFSYS_OPT_HUNTINGTON +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM @@ -1654,7 +1654,7 @@ ef10_nvram_segment_write_tlv( * Read the segment from NVRAM into the segment_data buffer and validate * it, returning if it does not validate. This is not a failure unless * this is the first segment in a partition. In this case the caller - * must propogate the error. + * must propagate the error. */ status = ef10_nvram_read_tlv_segment(enp, partn, *partn_offsetp, *seg_datap, *src_remain_lenp); @@ -2330,4 +2330,4 @@ ef10_nvram_partn_rw_finish( #endif /* EFSYS_OPT_NVRAM */ -#endif /* EFSYS_OPT_HUNTINGTON */ +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ diff --git a/sys/dev/sfxge/common/ef10_phy.c b/sys/dev/sfxge/common/ef10_phy.c new file mode 100644 index 0000000..9241297 --- /dev/null +++ b/sys/dev/sfxge/common/ef10_phy.c @@ -0,0 +1,518 @@ +/*- + * Copyright (c) 2012-2015 Solarflare Communications Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + +static void +mcdi_phy_decode_cap( + __in uint32_t mcdi_cap, + __out uint32_t *maskp) +{ + uint32_t mask; + + mask = 0; + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) + mask |= (1 << EFX_PHY_CAP_10HDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) + mask |= (1 << EFX_PHY_CAP_10FDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) + mask |= (1 << EFX_PHY_CAP_100HDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) + mask |= (1 << EFX_PHY_CAP_100FDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) + mask |= (1 << EFX_PHY_CAP_1000HDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) + mask |= (1 << EFX_PHY_CAP_1000FDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) + mask |= (1 << EFX_PHY_CAP_10000FDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) + mask |= (1 << EFX_PHY_CAP_40000FDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) + mask |= (1 << EFX_PHY_CAP_PAUSE); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) + mask |= (1 << EFX_PHY_CAP_ASYM); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) + mask |= (1 << EFX_PHY_CAP_AN); + + *maskp = mask; +} + +static void +mcdi_phy_decode_link_mode( + __in efx_nic_t *enp, + __in uint32_t link_flags, + __in unsigned int speed, + __in unsigned int fcntl, + __out efx_link_mode_t *link_modep, + __out unsigned int *fcntlp) +{ + boolean_t fd = !!(link_flags & + (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN)); + boolean_t up = !!(link_flags & + (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN)); + + _NOTE(ARGUNUSED(enp)) + + if (!up) + *link_modep = EFX_LINK_DOWN; + else if (speed == 40000 && fd) + *link_modep = EFX_LINK_40000FDX; + else if (speed == 10000 && fd) + *link_modep = EFX_LINK_10000FDX; + else if (speed == 1000) + *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX; + else if (speed == 100) + *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX; + else if (speed == 10) + *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX; + else + *link_modep = EFX_LINK_UNKNOWN; + + if (fcntl == MC_CMD_FCNTL_OFF) + *fcntlp = 0; + else if (fcntl == MC_CMD_FCNTL_RESPOND) + *fcntlp = EFX_FCNTL_RESPOND; + else if (fcntl == MC_CMD_FCNTL_GENERATE) + *fcntlp = EFX_FCNTL_GENERATE; + else if (fcntl == MC_CMD_FCNTL_BIDIR) + *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE; + else { + EFSYS_PROBE1(mc_pcol_error, int, fcntl); + *fcntlp = 0; + } +} + + + void +ef10_phy_link_ev( + __in efx_nic_t *enp, + __in efx_qword_t *eqp, + __out efx_link_mode_t *link_modep) +{ + efx_port_t *epp = &(enp->en_port); + unsigned int link_flags; + unsigned int speed; + unsigned int fcntl; + efx_link_mode_t link_mode; + uint32_t lp_cap_mask; + + /* + * Convert the LINKCHANGE speed enumeration into mbit/s, in the + * same way as GET_LINK encodes the speed + */ + switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) { + case MCDI_EVENT_LINKCHANGE_SPEED_100M: + speed = 100; + break; + case MCDI_EVENT_LINKCHANGE_SPEED_1G: + speed = 1000; + break; + case MCDI_EVENT_LINKCHANGE_SPEED_10G: + speed = 10000; + break; + case MCDI_EVENT_LINKCHANGE_SPEED_40G: + speed = 40000; + break; + default: + speed = 0; + break; + } + + link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS); + mcdi_phy_decode_link_mode(enp, link_flags, speed, + MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL), + &link_mode, &fcntl); + mcdi_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP), + &lp_cap_mask); + + /* + * It's safe to update ep_lp_cap_mask without the driver's port lock + * because presumably any concurrently running efx_port_poll() is + * only going to arrive at the same value. + * + * ep_fcntl has two meanings. It's either the link common fcntl + * (if the PHY supports AN), or it's the forced link state. If + * the former, it's safe to update the value for the same reason as + * for ep_lp_cap_mask. If the latter, then just ignore the value, + * because we can race with efx_mac_fcntl_set(). + */ + epp->ep_lp_cap_mask = lp_cap_mask; + epp->ep_fcntl = fcntl; + + *link_modep = link_mode; +} + + __checkReturn efx_rc_t +ef10_phy_power( + __in efx_nic_t *enp, + __in boolean_t power) +{ + efx_rc_t rc; + + if (!power) + return (0); + + /* Check if the PHY is a zombie */ + if ((rc = ef10_phy_verify(enp)) != 0) + goto fail1; + + enp->en_reset_flags |= EFX_RESET_PHY; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_phy_get_link( + __in efx_nic_t *enp, + __out ef10_link_state_t *elsp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN, + MC_CMD_GET_LINK_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_LINK; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_LINK_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_LINK_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_LINK_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP), + &elsp->els_adv_cap_mask); + mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP), + &elsp->els_lp_cap_mask); + + mcdi_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS), + MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED), + 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); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_phy_reconfigure( + __in efx_nic_t *enp) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + efx_port_t *epp = &(enp->en_port); + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_SET_LINK_IN_LEN, + MC_CMD_SET_LINK_OUT_LEN)]; + uint32_t cap_mask; + unsigned int led_mode; + unsigned int speed; + efx_rc_t rc; + + if (~encp->enc_func_flags & EFX_NIC_FUNC_LINKCTRL) + goto out; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_SET_LINK; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_SET_LINK_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN; + + cap_mask = epp->ep_adv_cap_mask; + MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP, + PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1, + PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1, + PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1, + PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1, + PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1, + PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1, + PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1, + PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1, + PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1, + PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1); + /* Too many fields for for POPULATE macros, so insert this afterwards */ + 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 + MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags); +#else + MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0); +#endif /* EFSYS_OPT_PHY_FLAGS */ + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + /* And set the blink mode */ + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_SET_ID_LED; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN; + +#if EFSYS_OPT_PHY_LED_CONTROL + switch (epp->ep_phy_led_mode) { + case EFX_PHY_LED_DEFAULT: + led_mode = MC_CMD_LED_DEFAULT; + break; + case EFX_PHY_LED_OFF: + led_mode = MC_CMD_LED_OFF; + break; + case EFX_PHY_LED_ON: + led_mode = MC_CMD_LED_ON; + break; + default: + EFSYS_ASSERT(0); + led_mode = MC_CMD_LED_DEFAULT; + } + + MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode); +#else + MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT); +#endif /* EFSYS_OPT_PHY_LED_CONTROL */ + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } +out: + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_phy_verify( + __in efx_nic_t *enp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN, + MC_CMD_GET_PHY_STATE_OUT_LEN)]; + uint32_t state; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_PHY_STATE; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_PHY_STATE_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_PHY_STATE_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE); + if (state != MC_CMD_PHY_STATE_OK) { + if (state != MC_CMD_PHY_STATE_ZOMBIE) + EFSYS_PROBE1(mc_pcol_error, int, state); + rc = ENOTACTIVE; + goto fail3; + } + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_phy_oui_get( + __in efx_nic_t *enp, + __out uint32_t *ouip) +{ + _NOTE(ARGUNUSED(enp, ouip)) + + return (ENOTSUP); +} + +#if EFSYS_OPT_PHY_STATS + + __checkReturn efx_rc_t +ef10_phy_stats_update( + __in efx_nic_t *enp, + __in efsys_mem_t *esmp, + __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) +{ + /* TBD: no stats support in firmware yet */ + _NOTE(ARGUNUSED(enp, esmp)) + memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat)); + + return (0); +} + +#endif /* EFSYS_OPT_PHY_STATS */ + +#if EFSYS_OPT_PHY_PROPS + +#if EFSYS_OPT_NAMES + + const char * +ef10_phy_prop_name( + __in efx_nic_t *enp, + __in unsigned int id) +{ + _NOTE(ARGUNUSED(enp, id)) + + return (NULL); +} + +#endif /* EFSYS_OPT_NAMES */ + + __checkReturn efx_rc_t +ef10_phy_prop_get( + __in efx_nic_t *enp, + __in unsigned int id, + __in uint32_t flags, + __out uint32_t *valp) +{ + _NOTE(ARGUNUSED(enp, id, flags, valp)) + + return (ENOTSUP); +} + + __checkReturn efx_rc_t +ef10_phy_prop_set( + __in efx_nic_t *enp, + __in unsigned int id, + __in uint32_t val) +{ + _NOTE(ARGUNUSED(enp, id, val)) + + return (ENOTSUP); +} + +#endif /* EFSYS_OPT_PHY_PROPS */ + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ diff --git a/sys/dev/sfxge/common/hunt_rx.c b/sys/dev/sfxge/common/ef10_rx.c index 984d48d..278a0a1 100644 --- a/sys/dev/sfxge/common/hunt_rx.c +++ b/sys/dev/sfxge/common/ef10_rx.c @@ -35,7 +35,7 @@ __FBSDID("$FreeBSD$"); #include "efx_impl.h" -#if EFSYS_OPT_HUNTINGTON +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD static __checkReturn efx_rc_t @@ -823,4 +823,4 @@ ef10_rx_fini( #endif /* EFSYS_OPT_RX_SCALE */ } -#endif /* EFSYS_OPT_HUNTINGTON */ +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ diff --git a/sys/dev/sfxge/common/hunt_tx.c b/sys/dev/sfxge/common/ef10_tx.c index baa7444..2922371 100755 --- a/sys/dev/sfxge/common/hunt_tx.c +++ b/sys/dev/sfxge/common/ef10_tx.c @@ -35,7 +35,7 @@ __FBSDID("$FreeBSD$"); #include "efx_impl.h" -#if EFSYS_OPT_HUNTINGTON +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD #if EFSYS_OPT_QSTATS #define EFX_TX_QSTAT_INCR(_etp, _stat) \ @@ -569,7 +569,7 @@ ef10_tx_qdesc_dma_create( } void -hunt_tx_qdesc_tso_create( +ef10_tx_qdesc_tso_create( __in efx_txq_t *etp, __in uint16_t ipv4_id, __in uint32_t tcp_seq, @@ -707,4 +707,4 @@ ef10_tx_qstats_update( #endif /* EFSYS_OPT_QSTATS */ -#endif /* EFSYS_OPT_HUNTINGTON */ +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ diff --git a/sys/dev/sfxge/common/hunt_vpd.c b/sys/dev/sfxge/common/ef10_vpd.c index b4c6d26..8eef3ad 100644 --- a/sys/dev/sfxge/common/hunt_vpd.c +++ b/sys/dev/sfxge/common/ef10_vpd.c @@ -37,7 +37,7 @@ __FBSDID("$FreeBSD$"); #if EFSYS_OPT_VPD -#if EFSYS_OPT_HUNTINGTON +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD #include "ef10_tlv_layout.h" @@ -458,6 +458,6 @@ ef10_vpd_fini( } } -#endif /* EFSYS_OPT_HUNTINGTON */ +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ #endif /* EFSYS_OPT_VPD */ diff --git a/sys/dev/sfxge/common/efx_tx.c b/sys/dev/sfxge/common/efx_tx.c index 811530d..ceace71 100644 --- a/sys/dev/sfxge/common/efx_tx.c +++ b/sys/dev/sfxge/common/efx_tx.c @@ -167,7 +167,7 @@ static const efx_tx_ops_t __efx_tx_hunt_ops = { ef10_tx_qpio_post, /* etxo_qpio_post */ ef10_tx_qdesc_post, /* etxo_qdesc_post */ ef10_tx_qdesc_dma_create, /* etxo_qdesc_dma_create */ - hunt_tx_qdesc_tso_create, /* etxo_qdesc_tso_create */ + ef10_tx_qdesc_tso_create, /* etxo_qdesc_tso_create */ ef10_tx_qdesc_tso2_create, /* etxo_qdesc_tso2_create */ ef10_tx_qdesc_vlantci_create, /* etxo_qdesc_vlantci_create */ #if EFSYS_OPT_QSTATS diff --git a/sys/dev/sfxge/common/hunt_impl.h b/sys/dev/sfxge/common/hunt_impl.h index ece1e6a..2653fe2 100644 --- a/sys/dev/sfxge/common/hunt_impl.h +++ b/sys/dev/sfxge/common/hunt_impl.h @@ -746,7 +746,7 @@ ef10_tx_qdesc_dma_create( __out efx_desc_t *edp); extern void -hunt_tx_qdesc_tso_create( +ef10_tx_qdesc_tso_create( __in efx_txq_t *etp, __in uint16_t ipv4_id, __in uint32_t tcp_seq, diff --git a/sys/dev/sfxge/common/hunt_nic.c b/sys/dev/sfxge/common/hunt_nic.c index d268e7b..44ddab7 100644 --- a/sys/dev/sfxge/common/hunt_nic.c +++ b/sys/dev/sfxge/common/hunt_nic.c @@ -39,1081 +39,6 @@ __FBSDID("$FreeBSD$"); #if EFSYS_OPT_HUNTINGTON -#include "ef10_tlv_layout.h" - - __checkReturn efx_rc_t -efx_mcdi_get_port_assignment( - __in efx_nic_t *enp, - __out uint32_t *portp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN, - MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN)]; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_PORT_ASSIGNMENT; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_PORT_ASSIGNMENT_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_PORT_ASSIGNMENT_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - *portp = MCDI_OUT_DWORD(req, GET_PORT_ASSIGNMENT_OUT_PORT); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -efx_mcdi_get_port_modes( - __in efx_nic_t *enp, - __out uint32_t *modesp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_PORT_MODES_IN_LEN, - MC_CMD_GET_PORT_MODES_OUT_LEN)]; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_PORT_MODES; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN; - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - /* - * Require only Modes and DefaultMode fields. - * (CurrentMode field was added for Medford) - */ - if (req.emr_out_length_used < - MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) { - rc = EMSGSIZE; - goto fail2; - } - - *modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - -static __checkReturn efx_rc_t -efx_mcdi_vadaptor_alloc( - __in efx_nic_t *enp, - __in uint32_t port_id) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_VADAPTOR_ALLOC_IN_LEN, - MC_CMD_VADAPTOR_ALLOC_OUT_LEN)]; - efx_rc_t rc; - - EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_VADAPTOR_ALLOC; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN; - - MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); - MCDI_IN_POPULATE_DWORD_1(req, VADAPTOR_ALLOC_IN_FLAGS, - VADAPTOR_ALLOC_IN_FLAG_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED, - enp->en_nic_cfg.enc_allow_set_mac_with_installed_filters ? 1 : 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); -} - -static __checkReturn efx_rc_t -efx_mcdi_vadaptor_free( - __in efx_nic_t *enp, - __in uint32_t port_id) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_VADAPTOR_FREE_IN_LEN, - MC_CMD_VADAPTOR_FREE_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_VADAPTOR_FREE; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN; - - MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); - - 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); -} - - __checkReturn efx_rc_t -efx_mcdi_get_mac_address_pf( - __in efx_nic_t *enp, - __out_ecount_opt(6) uint8_t mac_addrp[6]) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_MAC_ADDRESSES_IN_LEN, - MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)]; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_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_MAC_ADDRESSES_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) { - rc = ENOENT; - goto fail3; - } - - if (mac_addrp != NULL) { - uint8_t *addrp; - - addrp = MCDI_OUT2(req, uint8_t, - GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE); - - EFX_MAC_ADDR_COPY(mac_addrp, addrp); - } - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -efx_mcdi_get_mac_address_vf( - __in efx_nic_t *enp, - __out_ecount_opt(6) uint8_t mac_addrp[6]) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN, - MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX)]; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX; - - MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID, - EVB_PORT_ID_ASSIGNED); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - if (req.emr_out_length_used < - MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) { - rc = EMSGSIZE; - goto fail2; - } - - if (MCDI_OUT_DWORD(req, - VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) { - rc = ENOENT; - goto fail3; - } - - if (mac_addrp != NULL) { - uint8_t *addrp; - - addrp = MCDI_OUT2(req, uint8_t, - VPORT_GET_MAC_ADDRESSES_OUT_MACADDR); - - EFX_MAC_ADDR_COPY(mac_addrp, addrp); - } - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -efx_mcdi_get_clock( - __in efx_nic_t *enp, - __out uint32_t *sys_freqp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_CLOCK_IN_LEN, - MC_CMD_GET_CLOCK_OUT_LEN)]; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_CLOCK; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_CLOCK_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_CLOCK_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - *sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ); - if (*sys_freqp == 0) { - rc = EINVAL; - goto fail3; - } - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -efx_mcdi_get_vector_cfg( - __in efx_nic_t *enp, - __out_opt uint32_t *vec_basep, - __out_opt uint32_t *pf_nvecp, - __out_opt uint32_t *vf_nvecp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_VECTOR_CFG_IN_LEN, - MC_CMD_GET_VECTOR_CFG_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_VECTOR_CFG; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_VECTOR_CFG_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_VECTOR_CFG_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - if (vec_basep != NULL) - *vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE); - if (pf_nvecp != NULL) - *pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF); - if (vf_nvecp != NULL) - *vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -efx_mcdi_get_capabilities( - __in efx_nic_t *enp, - __out uint32_t *flagsp, - __out uint32_t *flags2p) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN, - MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_CAPABILITIES; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_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_CAPABILITIES_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1); - - if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN) - *flags2p = 0; - else - *flags2p = MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - -static __checkReturn efx_rc_t -efx_mcdi_alloc_vis( - __in efx_nic_t *enp, - __in uint32_t min_vi_count, - __in uint32_t max_vi_count, - __out uint32_t *vi_basep, - __out uint32_t *vi_countp, - __out uint32_t *vi_shiftp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_ALLOC_VIS_IN_LEN, - MC_CMD_ALLOC_VIS_OUT_LEN)]; - efx_rc_t rc; - - if (vi_countp == NULL) { - rc = EINVAL; - goto fail1; - } - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_ALLOC_VIS; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_ALLOC_VIS_OUT_LEN; - - MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count); - MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } - - if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) { - rc = EMSGSIZE; - goto fail3; - } - - *vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE); - *vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT); - - /* Report VI_SHIFT if available (always zero for Huntington) */ - if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_EXT_OUT_LEN) - *vi_shiftp = 0; - else - *vi_shiftp = MCDI_OUT_DWORD(req, ALLOC_VIS_EXT_OUT_VI_SHIFT); - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - -static __checkReturn efx_rc_t -efx_mcdi_free_vis( - __in efx_nic_t *enp) -{ - efx_mcdi_req_t req; - efx_rc_t rc; - - EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0); - EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0); - - req.emr_cmd = MC_CMD_FREE_VIS; - req.emr_in_buf = NULL; - req.emr_in_length = 0; - req.emr_out_buf = NULL; - req.emr_out_length = 0; - - efx_mcdi_execute_quiet(enp, &req); - - /* Ignore ELREADY (no allocated VIs, so nothing to free) */ - if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - -static __checkReturn efx_rc_t -efx_mcdi_alloc_piobuf( - __in efx_nic_t *enp, - __out efx_piobuf_handle_t *handlep) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_ALLOC_PIOBUF_IN_LEN, - MC_CMD_ALLOC_PIOBUF_OUT_LEN)]; - efx_rc_t rc; - - if (handlep == NULL) { - rc = EINVAL; - goto fail1; - } - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_ALLOC_PIOBUF; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN; - - efx_mcdi_execute_quiet(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } - - if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) { - rc = EMSGSIZE; - goto fail3; - } - - *handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE); - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -efx_mcdi_free_piobuf( - __in efx_nic_t *enp, - __in efx_piobuf_handle_t handle) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_FREE_PIOBUF_IN_LEN, - MC_CMD_FREE_PIOBUF_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_FREE_PIOBUF; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN; - - MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle); - - efx_mcdi_execute_quiet(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); -} - -static __checkReturn efx_rc_t -efx_mcdi_link_piobuf( - __in efx_nic_t *enp, - __in uint32_t vi_index, - __in efx_piobuf_handle_t handle) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_LINK_PIOBUF_IN_LEN, - MC_CMD_LINK_PIOBUF_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_LINK_PIOBUF; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN; - - MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle); - MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); - - 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); -} - -static __checkReturn efx_rc_t -efx_mcdi_unlink_piobuf( - __in efx_nic_t *enp, - __in uint32_t vi_index) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_UNLINK_PIOBUF_IN_LEN, - MC_CMD_UNLINK_PIOBUF_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_UNLINK_PIOBUF; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN; - - MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); - - 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); -} - -static void -ef10_nic_alloc_piobufs( - __in efx_nic_t *enp, - __in uint32_t max_piobuf_count) -{ - efx_piobuf_handle_t *handlep; - unsigned int i; - efx_rc_t rc; - - EFSYS_ASSERT3U(max_piobuf_count, <=, - EFX_ARRAY_SIZE(enp->en_arch.ef10.ena_piobuf_handle)); - - enp->en_arch.ef10.ena_piobuf_count = 0; - - for (i = 0; i < max_piobuf_count; i++) { - handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; - - if ((rc = efx_mcdi_alloc_piobuf(enp, handlep)) != 0) - goto fail1; - - enp->en_arch.ef10.ena_pio_alloc_map[i] = 0; - enp->en_arch.ef10.ena_piobuf_count++; - } - - return; - -fail1: - for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { - handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; - - efx_mcdi_free_piobuf(enp, *handlep); - *handlep = EFX_PIOBUF_HANDLE_INVALID; - } - enp->en_arch.ef10.ena_piobuf_count = 0; -} - - -static void -ef10_nic_free_piobufs( - __in efx_nic_t *enp) -{ - efx_piobuf_handle_t *handlep; - unsigned int i; - - for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { - handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; - - efx_mcdi_free_piobuf(enp, *handlep); - *handlep = EFX_PIOBUF_HANDLE_INVALID; - } - enp->en_arch.ef10.ena_piobuf_count = 0; -} - -/* Sub-allocate a block from a piobuf */ - __checkReturn efx_rc_t -ef10_nic_pio_alloc( - __inout efx_nic_t *enp, - __out uint32_t *bufnump, - __out efx_piobuf_handle_t *handlep, - __out uint32_t *blknump, - __out uint32_t *offsetp, - __out size_t *sizep) -{ - efx_nic_cfg_t *encp = &enp->en_nic_cfg; - efx_drv_cfg_t *edcp = &enp->en_drv_cfg; - uint32_t blk_per_buf; - uint32_t buf, blk; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - EFSYS_ASSERT(bufnump); - EFSYS_ASSERT(handlep); - EFSYS_ASSERT(blknump); - EFSYS_ASSERT(offsetp); - EFSYS_ASSERT(sizep); - - if ((edcp->edc_pio_alloc_size == 0) || - (enp->en_arch.ef10.ena_piobuf_count == 0)) { - rc = ENOMEM; - goto fail1; - } - blk_per_buf = encp->enc_piobuf_size / edcp->edc_pio_alloc_size; - - for (buf = 0; buf < enp->en_arch.ef10.ena_piobuf_count; buf++) { - uint32_t *map = &enp->en_arch.ef10.ena_pio_alloc_map[buf]; - - if (~(*map) == 0) - continue; - - EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map))); - for (blk = 0; blk < blk_per_buf; blk++) { - if ((*map & (1u << blk)) == 0) { - *map |= (1u << blk); - goto done; - } - } - } - rc = ENOMEM; - goto fail2; - -done: - *handlep = enp->en_arch.ef10.ena_piobuf_handle[buf]; - *bufnump = buf; - *blknump = blk; - *sizep = edcp->edc_pio_alloc_size; - *offsetp = blk * (*sizep); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* Free a piobuf sub-allocated block */ - __checkReturn efx_rc_t -ef10_nic_pio_free( - __inout efx_nic_t *enp, - __in uint32_t bufnum, - __in uint32_t blknum) -{ - uint32_t *map; - efx_rc_t rc; - - if ((bufnum >= enp->en_arch.ef10.ena_piobuf_count) || - (blknum >= (8 * sizeof (*map)))) { - rc = EINVAL; - goto fail1; - } - - map = &enp->en_arch.ef10.ena_pio_alloc_map[bufnum]; - if ((*map & (1u << blknum)) == 0) { - rc = ENOENT; - goto fail2; - } - *map &= ~(1u << blknum); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nic_pio_link( - __inout efx_nic_t *enp, - __in uint32_t vi_index, - __in efx_piobuf_handle_t handle) -{ - return (efx_mcdi_link_piobuf(enp, vi_index, handle)); -} - - __checkReturn efx_rc_t -ef10_nic_pio_unlink( - __inout efx_nic_t *enp, - __in uint32_t vi_index) -{ - return (efx_mcdi_unlink_piobuf(enp, vi_index)); -} - - __checkReturn efx_rc_t -ef10_get_datapath_caps( - __in efx_nic_t *enp) -{ - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - uint32_t flags; - uint32_t flags2; - efx_rc_t rc; - - if ((rc = efx_mcdi_get_capabilities(enp, &flags, &flags2)) != 0) - goto fail1; - -#define CAP_FLAG(flags1, field) \ - ((flags1) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN))) - -#define CAP_FLAG2(flags2, field) \ - ((flags2) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN))) - - /* - * Huntington RXDP firmware inserts a 0 or 14 byte prefix. - * We only support the 14 byte prefix here. - */ - if (CAP_FLAG(flags, RX_PREFIX_LEN_14) == 0) { - rc = ENOTSUP; - goto fail2; - } - encp->enc_rx_prefix_size = 14; - - /* Check if the firmware supports TSO */ - encp->enc_fw_assisted_tso_enabled = - CAP_FLAG(flags, TX_TSO) ? B_TRUE : B_FALSE; - - /* Check if the firmware supports FATSOv2 */ - encp->enc_fw_assisted_tso_v2_enabled = - CAP_FLAG2(flags2, TX_TSO_V2) ? B_TRUE : B_FALSE; - - /* Check if the firmware has vadapter/vport/vswitch support */ - encp->enc_datapath_cap_evb = - CAP_FLAG(flags, EVB) ? B_TRUE : B_FALSE; - - /* Check if the firmware supports VLAN insertion */ - encp->enc_hw_tx_insert_vlan_enabled = - CAP_FLAG(flags, TX_VLAN_INSERTION) ? B_TRUE : B_FALSE; - - /* Check if the firmware supports RX event batching */ - encp->enc_rx_batching_enabled = - CAP_FLAG(flags, RX_BATCHING) ? B_TRUE : B_FALSE; - - if (encp->enc_rx_batching_enabled) - encp->enc_rx_batch_max = 16; - - /* Check if the firmware supports disabling scatter on RXQs */ - encp->enc_rx_disable_scatter_supported = - CAP_FLAG(flags, RX_DISABLE_SCATTER) ? B_TRUE : B_FALSE; - - /* Check if the firmware supports set mac with running filters */ - encp->enc_allow_set_mac_with_installed_filters = - CAP_FLAG(flags, VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED) ? - B_TRUE : B_FALSE; - - /* - * Check if firmware supports the extended MC_CMD_SET_MAC, which allows - * specifying which parameters to configure. - */ - encp->enc_enhanced_set_mac_supported = - CAP_FLAG(flags, SET_MAC_ENHANCED) ? B_TRUE : B_FALSE; - -#undef CAP_FLAG -#undef CAP_FLAG2 - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - - __checkReturn efx_rc_t -ef10_get_privilege_mask( - __in efx_nic_t *enp, - __out uint32_t *maskp) -{ - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - uint32_t mask; - efx_rc_t rc; - - if ((rc = efx_mcdi_privilege_mask(enp, encp->enc_pf, encp->enc_vf, - &mask)) != 0) { - if (rc != ENOTSUP) - goto fail1; - - /* Fallback for old firmware without privilege mask support */ - if (EFX_PCI_FUNCTION_IS_PF(encp)) { - /* Assume PF has admin privilege */ - mask = EF10_LEGACY_PF_PRIVILEGE_MASK; - } else { - /* VF is always unprivileged by default */ - mask = EF10_LEGACY_VF_PRIVILEGE_MASK; - } - } - - *maskp = mask; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - -/* - * The external port mapping is a one-based numbering of the external - * connectors on the board. It does not distinguish off-board separated - * outputs such as multi-headed cables. - * The number of ports that map to each external port connector - * on the board is determined by the chip family and the port modes to - * which the NIC can be configured. The mapping table lists modes with - * port numbering requirements in increasing order. - */ -static struct { - efx_family_t family; - uint32_t modes_mask; - uint32_t stride; -} __ef10_external_port_mappings[] = { - /* Supported modes requiring 1 output per port */ - { - EFX_FAMILY_HUNTINGTON, - (1 << TLV_PORT_MODE_10G) | - (1 << TLV_PORT_MODE_10G_10G) | - (1 << TLV_PORT_MODE_10G_10G_10G_10G), - 1 - }, - { - EFX_FAMILY_MEDFORD, - (1 << TLV_PORT_MODE_10G) | - (1 << TLV_PORT_MODE_10G_10G) | - (1 << TLV_PORT_MODE_10G_10G_10G_10G), - 1 - }, - /* Supported modes requiring 2 outputs per port */ - { - EFX_FAMILY_HUNTINGTON, - (1 << TLV_PORT_MODE_40G) | - (1 << TLV_PORT_MODE_40G_40G) | - (1 << TLV_PORT_MODE_40G_10G_10G) | - (1 << TLV_PORT_MODE_10G_10G_40G), - 2 - }, - { - EFX_FAMILY_MEDFORD, - (1 << TLV_PORT_MODE_40G) | - (1 << TLV_PORT_MODE_40G_40G) | - (1 << TLV_PORT_MODE_40G_10G_10G) | - (1 << TLV_PORT_MODE_10G_10G_40G), - 2 - }, - /* Supported modes requiring 4 outputs per port */ - { - EFX_FAMILY_MEDFORD, - (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q) | - (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q2), - 4 - }, -}; - - __checkReturn efx_rc_t -ef10_external_port_mapping( - __in efx_nic_t *enp, - __in uint32_t port, - __out uint8_t *external_portp) -{ - efx_rc_t rc; - int i; - uint32_t port_modes; - uint32_t matches; - uint32_t stride = 1; /* default 1-1 mapping */ - - if ((rc = efx_mcdi_get_port_modes(enp, &port_modes)) != 0) { - /* No port mode information available - use default mapping */ - goto out; - } - - /* - * Infer the internal port -> external port mapping from - * the possible port modes for this NIC. - */ - for (i = 0; i < EFX_ARRAY_SIZE(__ef10_external_port_mappings); ++i) { - if (__ef10_external_port_mappings[i].family != - enp->en_family) - continue; - matches = (__ef10_external_port_mappings[i].modes_mask & - port_modes); - if (matches != 0) { - stride = __ef10_external_port_mappings[i].stride; - port_modes &= ~matches; - } - } - - if (port_modes != 0) { - /* Some advertised modes are not supported */ - rc = ENOTSUP; - goto fail1; - } - -out: - /* - * Scale as required by last matched mode and then convert to - * one-based numbering - */ - *external_portp = (uint8_t)(port / stride) + 1; - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} __checkReturn efx_rc_t hunt_board_cfg( @@ -1396,502 +321,4 @@ fail1: } - __checkReturn efx_rc_t -ef10_nic_probe( - __in efx_nic_t *enp) -{ - const efx_nic_ops_t *enop = enp->en_enop; - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* Read and clear any assertion state */ - if ((rc = efx_mcdi_read_assertion(enp)) != 0) - goto fail1; - - /* Exit the assertion handler */ - if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) - if (rc != EACCES) - goto fail2; - - if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0) - goto fail3; - - if ((rc = enop->eno_board_cfg(enp)) != 0) - if (rc != EACCES) - goto fail4; - - /* - * Set default driver config limits (based on board config). - * - * FIXME: For now allocate a fixed number of VIs which is likely to be - * sufficient and small enough to allow multiple functions on the same - * port. - */ - edcp->edc_min_vi_count = edcp->edc_max_vi_count = - MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit)); - - /* The client driver must configure and enable PIO buffer support */ - edcp->edc_max_piobuf_count = 0; - edcp->edc_pio_alloc_size = 0; - -#if EFSYS_OPT_MAC_STATS - /* Wipe the MAC statistics */ - if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0) - goto fail5; -#endif - -#if EFSYS_OPT_LOOPBACK - if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0) - goto fail6; -#endif - -#if EFSYS_OPT_MON_STATS - if ((rc = mcdi_mon_cfg_build(enp)) != 0) { - /* Unprivileged functions do not have access to sensors */ - if (rc != EACCES) - goto fail7; - } -#endif - - encp->enc_features = enp->en_features; - - return (0); - -#if EFSYS_OPT_MON_STATS -fail7: - EFSYS_PROBE(fail7); -#endif -#if EFSYS_OPT_LOOPBACK -fail6: - EFSYS_PROBE(fail6); -#endif -#if EFSYS_OPT_MAC_STATS -fail5: - EFSYS_PROBE(fail5); -#endif -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nic_set_drv_limits( - __inout efx_nic_t *enp, - __in efx_drv_limits_t *edlp) -{ - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); - uint32_t min_evq_count, max_evq_count; - uint32_t min_rxq_count, max_rxq_count; - uint32_t min_txq_count, max_txq_count; - efx_rc_t rc; - - if (edlp == NULL) { - rc = EINVAL; - goto fail1; - } - - /* Get minimum required and maximum usable VI limits */ - min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit); - min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit); - min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit); - - edcp->edc_min_vi_count = - MAX(min_evq_count, MAX(min_rxq_count, min_txq_count)); - - max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit); - max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit); - max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit); - - edcp->edc_max_vi_count = - MAX(max_evq_count, MAX(max_rxq_count, max_txq_count)); - - /* - * Check limits for sub-allocated piobuf blocks. - * PIO is optional, so don't fail if the limits are incorrect. - */ - if ((encp->enc_piobuf_size == 0) || - (encp->enc_piobuf_limit == 0) || - (edlp->edl_min_pio_alloc_size == 0) || - (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) { - /* Disable PIO */ - edcp->edc_max_piobuf_count = 0; - edcp->edc_pio_alloc_size = 0; - } else { - uint32_t blk_size, blk_count, blks_per_piobuf; - - blk_size = - MAX(edlp->edl_min_pio_alloc_size, - encp->enc_piobuf_min_alloc_size); - - blks_per_piobuf = encp->enc_piobuf_size / blk_size; - EFSYS_ASSERT3U(blks_per_piobuf, <=, 32); - - blk_count = (encp->enc_piobuf_limit * blks_per_piobuf); - - /* A zero max pio alloc count means unlimited */ - if ((edlp->edl_max_pio_alloc_count > 0) && - (edlp->edl_max_pio_alloc_count < blk_count)) { - blk_count = edlp->edl_max_pio_alloc_count; - } - - edcp->edc_pio_alloc_size = blk_size; - edcp->edc_max_piobuf_count = - (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - - __checkReturn efx_rc_t -ef10_nic_reset( - __in efx_nic_t *enp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN, - MC_CMD_ENTITY_RESET_OUT_LEN)]; - efx_rc_t rc; - - /* ef10_nic_reset() is called to recover from BADASSERT failures. */ - if ((rc = efx_mcdi_read_assertion(enp)) != 0) - goto fail1; - if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) - goto fail2; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_ENTITY_RESET; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN; - - MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG, - ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail3; - } - - /* Clear RX/TX DMA queue errors */ - enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR); - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nic_init( - __in efx_nic_t *enp) -{ - efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); - uint32_t min_vi_count, max_vi_count; - uint32_t vi_count, vi_base, vi_shift; - uint32_t i; - uint32_t retry; - uint32_t delay_us; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* Enable reporting of some events (e.g. link change) */ - if ((rc = efx_mcdi_log_ctrl(enp)) != 0) - goto fail1; - - /* Allocate (optional) on-chip PIO buffers */ - ef10_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count); - - /* - * For best performance, PIO writes should use a write-combined - * (WC) memory mapping. Using a separate WC mapping for the PIO - * aperture of each VI would be a burden to drivers (and not - * possible if the host page size is >4Kbyte). - * - * To avoid this we use a single uncached (UC) mapping for VI - * register access, and a single WC mapping for extra VIs used - * for PIO writes. - * - * Each piobuf must be linked to a VI in the WC mapping, and to - * each VI that is using a sub-allocated block from the piobuf. - */ - min_vi_count = edcp->edc_min_vi_count; - max_vi_count = - edcp->edc_max_vi_count + enp->en_arch.ef10.ena_piobuf_count; - - /* Ensure that the previously attached driver's VIs are freed */ - if ((rc = efx_mcdi_free_vis(enp)) != 0) - goto fail2; - - /* - * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this - * fails then retrying the request for fewer VI resources may succeed. - */ - vi_count = 0; - if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count, - &vi_base, &vi_count, &vi_shift)) != 0) - goto fail3; - - EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count); - - if (vi_count < min_vi_count) { - rc = ENOMEM; - goto fail4; - } - - enp->en_arch.ef10.ena_vi_base = vi_base; - enp->en_arch.ef10.ena_vi_count = vi_count; - enp->en_arch.ef10.ena_vi_shift = vi_shift; - - if (vi_count < min_vi_count + enp->en_arch.ef10.ena_piobuf_count) { - /* Not enough extra VIs to map piobufs */ - ef10_nic_free_piobufs(enp); - } - - enp->en_arch.ef10.ena_pio_write_vi_base = - vi_count - enp->en_arch.ef10.ena_piobuf_count; - - /* Save UC memory mapping details */ - enp->en_arch.ef10.ena_uc_mem_map_offset = 0; - if (enp->en_arch.ef10.ena_piobuf_count > 0) { - enp->en_arch.ef10.ena_uc_mem_map_size = - (ER_DZ_TX_PIOBUF_STEP * - enp->en_arch.ef10.ena_pio_write_vi_base); - } else { - enp->en_arch.ef10.ena_uc_mem_map_size = - (ER_DZ_TX_PIOBUF_STEP * - enp->en_arch.ef10.ena_vi_count); - } - - /* Save WC memory mapping details */ - enp->en_arch.ef10.ena_wc_mem_map_offset = - enp->en_arch.ef10.ena_uc_mem_map_offset + - enp->en_arch.ef10.ena_uc_mem_map_size; - - enp->en_arch.ef10.ena_wc_mem_map_size = - (ER_DZ_TX_PIOBUF_STEP * - enp->en_arch.ef10.ena_piobuf_count); - - /* Link piobufs to extra VIs in WC mapping */ - if (enp->en_arch.ef10.ena_piobuf_count > 0) { - for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { - rc = efx_mcdi_link_piobuf(enp, - enp->en_arch.ef10.ena_pio_write_vi_base + i, - enp->en_arch.ef10.ena_piobuf_handle[i]); - if (rc != 0) - break; - } - } - - /* - * Allocate a vAdaptor attached to our upstream vPort/pPort. - * - * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF - * driver has yet to bring up the EVB port. See bug 56147. In this case, - * retry the request several times after waiting a while. The wait time - * between retries starts small (10ms) and exponentially increases. - * Total wait time is a little over two seconds. Retry logic in the - * client driver may mean this whole loop is repeated if it continues to - * fail. - */ - retry = 0; - delay_us = 10000; - while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) { - if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) || - (rc != ENOENT)) { - /* - * Do not retry alloc for PF, or for other errors on - * a VF. - */ - goto fail5; - } - - /* VF startup before PF is ready. Retry allocation. */ - if (retry > 5) { - /* Too many attempts */ - rc = EINVAL; - goto fail6; - } - EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry); - EFSYS_SLEEP(delay_us); - retry++; - if (delay_us < 500000) - delay_us <<= 2; - } - - enp->en_vport_id = EVB_PORT_ID_ASSIGNED; - enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V2; - - return (0); - -fail6: - EFSYS_PROBE(fail6); -fail5: - EFSYS_PROBE(fail5); -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); - - ef10_nic_free_piobufs(enp); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nic_get_vi_pool( - __in efx_nic_t *enp, - __out uint32_t *vi_countp) -{ - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* - * Report VIs that the client driver can use. - * Do not include VIs used for PIO buffer writes. - */ - *vi_countp = enp->en_arch.ef10.ena_pio_write_vi_base; - - return (0); -} - - __checkReturn efx_rc_t -ef10_nic_get_bar_region( - __in efx_nic_t *enp, - __in efx_nic_region_t region, - __out uint32_t *offsetp, - __out size_t *sizep) -{ - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* - * TODO: Specify host memory mapping alignment and granularity - * in efx_drv_limits_t so that they can be taken into account - * when allocating extra VIs for PIO writes. - */ - switch (region) { - case EFX_REGION_VI: - /* UC mapped memory BAR region for VI registers */ - *offsetp = enp->en_arch.ef10.ena_uc_mem_map_offset; - *sizep = enp->en_arch.ef10.ena_uc_mem_map_size; - break; - - case EFX_REGION_PIO_WRITE_VI: - /* WC mapped memory BAR region for piobuf writes */ - *offsetp = enp->en_arch.ef10.ena_wc_mem_map_offset; - *sizep = enp->en_arch.ef10.ena_wc_mem_map_size; - break; - - default: - rc = EINVAL; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_nic_fini( - __in efx_nic_t *enp) -{ - uint32_t i; - efx_rc_t rc; - - (void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id); - enp->en_vport_id = 0; - - /* Unlink piobufs from extra VIs in WC mapping */ - if (enp->en_arch.ef10.ena_piobuf_count > 0) { - for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { - rc = efx_mcdi_unlink_piobuf(enp, - enp->en_arch.ef10.ena_pio_write_vi_base + i); - if (rc != 0) - break; - } - } - - ef10_nic_free_piobufs(enp); - - (void) efx_mcdi_free_vis(enp); - enp->en_arch.ef10.ena_vi_count = 0; -} - - void -ef10_nic_unprobe( - __in efx_nic_t *enp) -{ -#if EFSYS_OPT_MON_STATS - mcdi_mon_cfg_free(enp); -#endif /* EFSYS_OPT_MON_STATS */ - (void) efx_mcdi_drv_attach(enp, B_FALSE); -} - -#if EFSYS_OPT_DIAG - - __checkReturn efx_rc_t -ef10_nic_register_test( - __in efx_nic_t *enp) -{ - efx_rc_t rc; - - /* FIXME */ - _NOTE(ARGUNUSED(enp)) - if (B_FALSE) { - rc = ENOTSUP; - goto fail1; - } - /* FIXME */ - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -#endif /* EFSYS_OPT_DIAG */ - - - #endif /* EFSYS_OPT_HUNTINGTON */ diff --git a/sys/dev/sfxge/common/hunt_phy.c b/sys/dev/sfxge/common/hunt_phy.c index a6b7faa..0f54b57 100644 --- a/sys/dev/sfxge/common/hunt_phy.c +++ b/sys/dev/sfxge/common/hunt_phy.c @@ -36,485 +36,6 @@ __FBSDID("$FreeBSD$"); #if EFSYS_OPT_HUNTINGTON -static void -mcdi_phy_decode_cap( - __in uint32_t mcdi_cap, - __out uint32_t *maskp) -{ - uint32_t mask; - - mask = 0; - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) - mask |= (1 << EFX_PHY_CAP_10HDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) - mask |= (1 << EFX_PHY_CAP_10FDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) - mask |= (1 << EFX_PHY_CAP_100HDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) - mask |= (1 << EFX_PHY_CAP_100FDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) - mask |= (1 << EFX_PHY_CAP_1000HDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) - mask |= (1 << EFX_PHY_CAP_1000FDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) - mask |= (1 << EFX_PHY_CAP_10000FDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) - mask |= (1 << EFX_PHY_CAP_40000FDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) - mask |= (1 << EFX_PHY_CAP_PAUSE); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) - mask |= (1 << EFX_PHY_CAP_ASYM); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) - mask |= (1 << EFX_PHY_CAP_AN); - - *maskp = mask; -} - -static void -mcdi_phy_decode_link_mode( - __in efx_nic_t *enp, - __in uint32_t link_flags, - __in unsigned int speed, - __in unsigned int fcntl, - __out efx_link_mode_t *link_modep, - __out unsigned int *fcntlp) -{ - boolean_t fd = !!(link_flags & - (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN)); - boolean_t up = !!(link_flags & - (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN)); - - _NOTE(ARGUNUSED(enp)) - - if (!up) - *link_modep = EFX_LINK_DOWN; - else if (speed == 40000 && fd) - *link_modep = EFX_LINK_40000FDX; - else if (speed == 10000 && fd) - *link_modep = EFX_LINK_10000FDX; - else if (speed == 1000) - *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX; - else if (speed == 100) - *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX; - else if (speed == 10) - *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX; - else - *link_modep = EFX_LINK_UNKNOWN; - - if (fcntl == MC_CMD_FCNTL_OFF) - *fcntlp = 0; - else if (fcntl == MC_CMD_FCNTL_RESPOND) - *fcntlp = EFX_FCNTL_RESPOND; - else if (fcntl == MC_CMD_FCNTL_GENERATE) - *fcntlp = EFX_FCNTL_GENERATE; - else if (fcntl == MC_CMD_FCNTL_BIDIR) - *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE; - else { - EFSYS_PROBE1(mc_pcol_error, int, fcntl); - *fcntlp = 0; - } -} - - - void -ef10_phy_link_ev( - __in efx_nic_t *enp, - __in efx_qword_t *eqp, - __out efx_link_mode_t *link_modep) -{ - efx_port_t *epp = &(enp->en_port); - unsigned int link_flags; - unsigned int speed; - unsigned int fcntl; - efx_link_mode_t link_mode; - uint32_t lp_cap_mask; - - /* - * Convert the LINKCHANGE speed enumeration into mbit/s, in the - * same way as GET_LINK encodes the speed - */ - switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) { - case MCDI_EVENT_LINKCHANGE_SPEED_100M: - speed = 100; - break; - case MCDI_EVENT_LINKCHANGE_SPEED_1G: - speed = 1000; - break; - case MCDI_EVENT_LINKCHANGE_SPEED_10G: - speed = 10000; - break; - case MCDI_EVENT_LINKCHANGE_SPEED_40G: - speed = 40000; - break; - default: - speed = 0; - break; - } - - link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS); - mcdi_phy_decode_link_mode(enp, link_flags, speed, - MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL), - &link_mode, &fcntl); - mcdi_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP), - &lp_cap_mask); - - /* - * It's safe to update ep_lp_cap_mask without the driver's port lock - * because presumably any concurrently running efx_port_poll() is - * only going to arrive at the same value. - * - * ep_fcntl has two meanings. It's either the link common fcntl - * (if the PHY supports AN), or it's the forced link state. If - * the former, it's safe to update the value for the same reason as - * for ep_lp_cap_mask. If the latter, then just ignore the value, - * because we can race with efx_mac_fcntl_set(). - */ - epp->ep_lp_cap_mask = lp_cap_mask; - epp->ep_fcntl = fcntl; - - *link_modep = link_mode; -} - - __checkReturn efx_rc_t -ef10_phy_power( - __in efx_nic_t *enp, - __in boolean_t power) -{ - efx_rc_t rc; - - if (!power) - return (0); - - /* Check if the PHY is a zombie */ - if ((rc = ef10_phy_verify(enp)) != 0) - goto fail1; - - enp->en_reset_flags |= EFX_RESET_PHY; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_phy_get_link( - __in efx_nic_t *enp, - __out ef10_link_state_t *elsp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN, - MC_CMD_GET_LINK_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_LINK; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_LINK_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_LINK_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_LINK_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP), - &elsp->els_adv_cap_mask); - mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP), - &elsp->els_lp_cap_mask); - - mcdi_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS), - MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED), - 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); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_phy_reconfigure( - __in efx_nic_t *enp) -{ - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - efx_port_t *epp = &(enp->en_port); - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_SET_LINK_IN_LEN, - MC_CMD_SET_LINK_OUT_LEN)]; - uint32_t cap_mask; - unsigned int led_mode; - unsigned int speed; - efx_rc_t rc; - - if (~encp->enc_func_flags & EFX_NIC_FUNC_LINKCTRL) - goto out; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_SET_LINK; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_SET_LINK_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN; - - cap_mask = epp->ep_adv_cap_mask; - MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP, - PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1, - PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1, - PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1, - PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1, - PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1, - PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1, - PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1, - PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1, - PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1, - PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1); - /* Too many fields for for POPULATE macros, so insert this afterwards */ - 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 - MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags); -#else - MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0); -#endif /* EFSYS_OPT_PHY_FLAGS */ - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - /* And set the blink mode */ - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_SET_ID_LED; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN; - -#if EFSYS_OPT_PHY_LED_CONTROL - switch (epp->ep_phy_led_mode) { - case EFX_PHY_LED_DEFAULT: - led_mode = MC_CMD_LED_DEFAULT; - break; - case EFX_PHY_LED_OFF: - led_mode = MC_CMD_LED_OFF; - break; - case EFX_PHY_LED_ON: - led_mode = MC_CMD_LED_ON; - break; - default: - EFSYS_ASSERT(0); - led_mode = MC_CMD_LED_DEFAULT; - } - - MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode); -#else - MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT); -#endif /* EFSYS_OPT_PHY_LED_CONTROL */ - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } -out: - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_phy_verify( - __in efx_nic_t *enp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN, - MC_CMD_GET_PHY_STATE_OUT_LEN)]; - uint32_t state; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_PHY_STATE; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_PHY_STATE_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_PHY_STATE_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE); - if (state != MC_CMD_PHY_STATE_OK) { - if (state != MC_CMD_PHY_STATE_ZOMBIE) - EFSYS_PROBE1(mc_pcol_error, int, state); - rc = ENOTACTIVE; - goto fail3; - } - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_phy_oui_get( - __in efx_nic_t *enp, - __out uint32_t *ouip) -{ - _NOTE(ARGUNUSED(enp, ouip)) - - return (ENOTSUP); -} - -#if EFSYS_OPT_PHY_STATS - - __checkReturn efx_rc_t -ef10_phy_stats_update( - __in efx_nic_t *enp, - __in efsys_mem_t *esmp, - __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) -{ - /* TBD: no stats support in firmware yet */ - _NOTE(ARGUNUSED(enp, esmp)) - memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat)); - - return (0); -} - -#endif /* EFSYS_OPT_PHY_STATS */ - -#if EFSYS_OPT_PHY_PROPS - -#if EFSYS_OPT_NAMES - - const char * -ef10_phy_prop_name( - __in efx_nic_t *enp, - __in unsigned int id) -{ - _NOTE(ARGUNUSED(enp, id)) - - return (NULL); -} - -#endif /* EFSYS_OPT_NAMES */ - - __checkReturn efx_rc_t -ef10_phy_prop_get( - __in efx_nic_t *enp, - __in unsigned int id, - __in uint32_t flags, - __out uint32_t *valp) -{ - _NOTE(ARGUNUSED(enp, id, flags, valp)) - - return (ENOTSUP); -} - - __checkReturn efx_rc_t -ef10_phy_prop_set( - __in efx_nic_t *enp, - __in unsigned int id, - __in uint32_t val) -{ - _NOTE(ARGUNUSED(enp, id, val)) - - return (ENOTSUP); -} - -#endif /* EFSYS_OPT_PHY_PROPS */ - #if EFSYS_OPT_BIST __checkReturn efx_rc_t |