xref: /freebsd/sys/dev/sfxge/common/ef10_nic.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
131bf5f03SAndrew Rybchenko /*-
2929c7febSAndrew Rybchenko  * Copyright (c) 2012-2016 Solarflare Communications Inc.
331bf5f03SAndrew Rybchenko  * All rights reserved.
431bf5f03SAndrew Rybchenko  *
531bf5f03SAndrew Rybchenko  * Redistribution and use in source and binary forms, with or without
631bf5f03SAndrew Rybchenko  * modification, are permitted provided that the following conditions are met:
731bf5f03SAndrew Rybchenko  *
831bf5f03SAndrew Rybchenko  * 1. Redistributions of source code must retain the above copyright notice,
931bf5f03SAndrew Rybchenko  *    this list of conditions and the following disclaimer.
1031bf5f03SAndrew Rybchenko  * 2. Redistributions in binary form must reproduce the above copyright notice,
1131bf5f03SAndrew Rybchenko  *    this list of conditions and the following disclaimer in the documentation
1231bf5f03SAndrew Rybchenko  *    and/or other materials provided with the distribution.
1331bf5f03SAndrew Rybchenko  *
1431bf5f03SAndrew Rybchenko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1531bf5f03SAndrew Rybchenko  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1631bf5f03SAndrew Rybchenko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1731bf5f03SAndrew Rybchenko  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
1831bf5f03SAndrew Rybchenko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
1931bf5f03SAndrew Rybchenko  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2031bf5f03SAndrew Rybchenko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2131bf5f03SAndrew Rybchenko  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2231bf5f03SAndrew Rybchenko  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2331bf5f03SAndrew Rybchenko  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
2431bf5f03SAndrew Rybchenko  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2531bf5f03SAndrew Rybchenko  *
2631bf5f03SAndrew Rybchenko  * The views and conclusions contained in the software and documentation are
2731bf5f03SAndrew Rybchenko  * those of the authors and should not be interpreted as representing official
2831bf5f03SAndrew Rybchenko  * policies, either expressed or implied, of the FreeBSD Project.
2931bf5f03SAndrew Rybchenko  */
3031bf5f03SAndrew Rybchenko 
3131bf5f03SAndrew Rybchenko #include <sys/cdefs.h>
3231bf5f03SAndrew Rybchenko #include "efx.h"
3331bf5f03SAndrew Rybchenko #include "efx_impl.h"
3431bf5f03SAndrew Rybchenko #if EFSYS_OPT_MON_MCDI
3531bf5f03SAndrew Rybchenko #include "mcdi_mon.h"
3631bf5f03SAndrew Rybchenko #endif
3731bf5f03SAndrew Rybchenko 
38ae64ac93SAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
3931bf5f03SAndrew Rybchenko 
4031bf5f03SAndrew Rybchenko #include "ef10_tlv_layout.h"
4131bf5f03SAndrew Rybchenko 
4231bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_mcdi_get_port_assignment(__in efx_nic_t * enp,__out uint32_t * portp)4331bf5f03SAndrew Rybchenko efx_mcdi_get_port_assignment(
4431bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
4531bf5f03SAndrew Rybchenko 	__out		uint32_t *portp)
4631bf5f03SAndrew Rybchenko {
4731bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
48315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN,
49315bbbaaSAndrew Rybchenko 		MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN);
5031bf5f03SAndrew Rybchenko 	efx_rc_t rc;
5131bf5f03SAndrew Rybchenko 
5231bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
53ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD ||
54ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD2);
5531bf5f03SAndrew Rybchenko 
5631bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_GET_PORT_ASSIGNMENT;
5731bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
5831bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN;
5931bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
6031bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN;
6131bf5f03SAndrew Rybchenko 
6231bf5f03SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
6331bf5f03SAndrew Rybchenko 
6431bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
6531bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
6631bf5f03SAndrew Rybchenko 		goto fail1;
6731bf5f03SAndrew Rybchenko 	}
6831bf5f03SAndrew Rybchenko 
6931bf5f03SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN) {
7031bf5f03SAndrew Rybchenko 		rc = EMSGSIZE;
7131bf5f03SAndrew Rybchenko 		goto fail2;
7231bf5f03SAndrew Rybchenko 	}
7331bf5f03SAndrew Rybchenko 
7431bf5f03SAndrew Rybchenko 	*portp = MCDI_OUT_DWORD(req, GET_PORT_ASSIGNMENT_OUT_PORT);
7531bf5f03SAndrew Rybchenko 
7631bf5f03SAndrew Rybchenko 	return (0);
7731bf5f03SAndrew Rybchenko 
7831bf5f03SAndrew Rybchenko fail2:
7931bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
8031bf5f03SAndrew Rybchenko fail1:
8131bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
8231bf5f03SAndrew Rybchenko 
8331bf5f03SAndrew Rybchenko 	return (rc);
8431bf5f03SAndrew Rybchenko }
8531bf5f03SAndrew Rybchenko 
8631bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_mcdi_get_port_modes(__in efx_nic_t * enp,__out uint32_t * modesp,__out_opt uint32_t * current_modep,__out_opt uint32_t * default_modep)8731bf5f03SAndrew Rybchenko efx_mcdi_get_port_modes(
8831bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
89f6d61784SAndrew Rybchenko 	__out		uint32_t *modesp,
90cd5e3371SAndrew Rybchenko 	__out_opt	uint32_t *current_modep,
91cd5e3371SAndrew Rybchenko 	__out_opt	uint32_t *default_modep)
9231bf5f03SAndrew Rybchenko {
9331bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
94315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PORT_MODES_IN_LEN,
95315bbbaaSAndrew Rybchenko 		MC_CMD_GET_PORT_MODES_OUT_LEN);
9631bf5f03SAndrew Rybchenko 	efx_rc_t rc;
9731bf5f03SAndrew Rybchenko 
9831bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
99ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD ||
100ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD2);
10131bf5f03SAndrew Rybchenko 
10231bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_GET_PORT_MODES;
10331bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
10431bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN;
10531bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
10631bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN;
10731bf5f03SAndrew Rybchenko 
10831bf5f03SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
10931bf5f03SAndrew Rybchenko 
11031bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
11131bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
11231bf5f03SAndrew Rybchenko 		goto fail1;
11331bf5f03SAndrew Rybchenko 	}
11431bf5f03SAndrew Rybchenko 
11531bf5f03SAndrew Rybchenko 	/*
116f6d61784SAndrew Rybchenko 	 * Require only Modes and DefaultMode fields, unless the current mode
117f6d61784SAndrew Rybchenko 	 * was requested (CurrentMode field was added for Medford).
11831bf5f03SAndrew Rybchenko 	 */
11931bf5f03SAndrew Rybchenko 	if (req.emr_out_length_used <
12031bf5f03SAndrew Rybchenko 	    MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) {
12131bf5f03SAndrew Rybchenko 		rc = EMSGSIZE;
12231bf5f03SAndrew Rybchenko 		goto fail2;
12331bf5f03SAndrew Rybchenko 	}
124f6d61784SAndrew Rybchenko 	if ((current_modep != NULL) && (req.emr_out_length_used <
125f6d61784SAndrew Rybchenko 	    MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST + 4)) {
126f6d61784SAndrew Rybchenko 		rc = EMSGSIZE;
127f6d61784SAndrew Rybchenko 		goto fail3;
128f6d61784SAndrew Rybchenko 	}
12931bf5f03SAndrew Rybchenko 
13031bf5f03SAndrew Rybchenko 	*modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES);
13131bf5f03SAndrew Rybchenko 
132f6d61784SAndrew Rybchenko 	if (current_modep != NULL) {
133f6d61784SAndrew Rybchenko 		*current_modep = MCDI_OUT_DWORD(req,
134f6d61784SAndrew Rybchenko 					    GET_PORT_MODES_OUT_CURRENT_MODE);
135f6d61784SAndrew Rybchenko 	}
136f6d61784SAndrew Rybchenko 
137cd5e3371SAndrew Rybchenko 	if (default_modep != NULL) {
138cd5e3371SAndrew Rybchenko 		*default_modep = MCDI_OUT_DWORD(req,
139cd5e3371SAndrew Rybchenko 					    GET_PORT_MODES_OUT_DEFAULT_MODE);
140cd5e3371SAndrew Rybchenko 	}
141cd5e3371SAndrew Rybchenko 
14231bf5f03SAndrew Rybchenko 	return (0);
14331bf5f03SAndrew Rybchenko 
144f6d61784SAndrew Rybchenko fail3:
145f6d61784SAndrew Rybchenko 	EFSYS_PROBE(fail3);
14631bf5f03SAndrew Rybchenko fail2:
14731bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
14831bf5f03SAndrew Rybchenko fail1:
14931bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
15031bf5f03SAndrew Rybchenko 
15131bf5f03SAndrew Rybchenko 	return (rc);
15231bf5f03SAndrew Rybchenko }
15331bf5f03SAndrew Rybchenko 
154f6d61784SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_nic_get_port_mode_bandwidth(__in efx_nic_t * enp,__out uint32_t * bandwidth_mbpsp)155f6d61784SAndrew Rybchenko ef10_nic_get_port_mode_bandwidth(
156c42b6a35SAndrew Rybchenko 	__in		efx_nic_t *enp,
157f6d61784SAndrew Rybchenko 	__out		uint32_t *bandwidth_mbpsp)
158f6d61784SAndrew Rybchenko {
159c42b6a35SAndrew Rybchenko 	uint32_t port_modes;
160c42b6a35SAndrew Rybchenko 	uint32_t current_mode;
161109f5727SAndrew Rybchenko 	efx_port_t *epp = &(enp->en_port);
162109f5727SAndrew Rybchenko 
163109f5727SAndrew Rybchenko 	uint32_t single_lane;
164109f5727SAndrew Rybchenko 	uint32_t dual_lane;
165109f5727SAndrew Rybchenko 	uint32_t quad_lane;
166f6d61784SAndrew Rybchenko 	uint32_t bandwidth;
167f6d61784SAndrew Rybchenko 	efx_rc_t rc;
168f6d61784SAndrew Rybchenko 
169c42b6a35SAndrew Rybchenko 	if ((rc = efx_mcdi_get_port_modes(enp, &port_modes,
170c42b6a35SAndrew Rybchenko 				    &current_mode, NULL)) != 0) {
171c42b6a35SAndrew Rybchenko 		/* No port mode info available. */
172c42b6a35SAndrew Rybchenko 		goto fail1;
173c42b6a35SAndrew Rybchenko 	}
174c42b6a35SAndrew Rybchenko 
175109f5727SAndrew Rybchenko 	if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_25000FDX))
176109f5727SAndrew Rybchenko 		single_lane = 25000;
177109f5727SAndrew Rybchenko 	else
178109f5727SAndrew Rybchenko 		single_lane = 10000;
179109f5727SAndrew Rybchenko 
180109f5727SAndrew Rybchenko 	if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_50000FDX))
181109f5727SAndrew Rybchenko 		dual_lane = 50000;
182109f5727SAndrew Rybchenko 	else
183109f5727SAndrew Rybchenko 		dual_lane = 20000;
184109f5727SAndrew Rybchenko 
185109f5727SAndrew Rybchenko 	if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_100000FDX))
186109f5727SAndrew Rybchenko 		quad_lane = 100000;
187109f5727SAndrew Rybchenko 	else
188109f5727SAndrew Rybchenko 		quad_lane = 40000;
189109f5727SAndrew Rybchenko 
190c42b6a35SAndrew Rybchenko 	switch (current_mode) {
191e12a751bSAndrew Rybchenko 	case TLV_PORT_MODE_1x1_NA:			/* mode 0 */
1927e370b0eSAndrew Rybchenko 		bandwidth = single_lane;
1937e370b0eSAndrew Rybchenko 		break;
1947e370b0eSAndrew Rybchenko 	case TLV_PORT_MODE_1x2_NA:			/* mode 10 */
1957e370b0eSAndrew Rybchenko 	case TLV_PORT_MODE_NA_1x2:			/* mode 11 */
1967e370b0eSAndrew Rybchenko 		bandwidth = dual_lane;
197f6d61784SAndrew Rybchenko 		break;
198e12a751bSAndrew Rybchenko 	case TLV_PORT_MODE_1x1_1x1:			/* mode 2 */
1997e370b0eSAndrew Rybchenko 		bandwidth = single_lane + single_lane;
200f6d61784SAndrew Rybchenko 		break;
201e12a751bSAndrew Rybchenko 	case TLV_PORT_MODE_4x1_NA:			/* mode 4 */
202e12a751bSAndrew Rybchenko 	case TLV_PORT_MODE_NA_4x1:			/* mode 8 */
2037e370b0eSAndrew Rybchenko 		bandwidth = 4 * single_lane;
2047e370b0eSAndrew Rybchenko 		break;
2057e370b0eSAndrew Rybchenko 	case TLV_PORT_MODE_2x1_2x1:			/* mode 5 */
2067e370b0eSAndrew Rybchenko 		bandwidth = (2 * single_lane) + (2 * single_lane);
2077e370b0eSAndrew Rybchenko 		break;
2087e370b0eSAndrew Rybchenko 	case TLV_PORT_MODE_1x2_1x2:			/* mode 12 */
2097e370b0eSAndrew Rybchenko 		bandwidth = dual_lane + dual_lane;
2107e370b0eSAndrew Rybchenko 		break;
2117e370b0eSAndrew Rybchenko 	case TLV_PORT_MODE_1x2_2x1:			/* mode 17 */
2127e370b0eSAndrew Rybchenko 	case TLV_PORT_MODE_2x1_1x2:			/* mode 18 */
2137e370b0eSAndrew Rybchenko 		bandwidth = dual_lane + (2 * single_lane);
214f6d61784SAndrew Rybchenko 		break;
215e12a751bSAndrew Rybchenko 	/* Legacy Medford-only mode. Do not use (see bug63270) */
216e12a751bSAndrew Rybchenko 	case TLV_PORT_MODE_10G_10G_10G_10G_Q1_Q2:	/* mode 9 */
2177e370b0eSAndrew Rybchenko 		bandwidth = 4 * single_lane;
218e12a751bSAndrew Rybchenko 		break;
219e12a751bSAndrew Rybchenko 	case TLV_PORT_MODE_1x4_NA:			/* mode 1 */
2207e370b0eSAndrew Rybchenko 	case TLV_PORT_MODE_NA_1x4:			/* mode 22 */
2217e370b0eSAndrew Rybchenko 		bandwidth = quad_lane;
222f6d61784SAndrew Rybchenko 		break;
2237e370b0eSAndrew Rybchenko 	case TLV_PORT_MODE_2x2_NA:			/* mode 13 */
2247e370b0eSAndrew Rybchenko 	case TLV_PORT_MODE_NA_2x2:			/* mode 14 */
2257e370b0eSAndrew Rybchenko 		bandwidth = 2 * dual_lane;
226f6d61784SAndrew Rybchenko 		break;
227e12a751bSAndrew Rybchenko 	case TLV_PORT_MODE_1x4_2x1:			/* mode 6 */
228e12a751bSAndrew Rybchenko 	case TLV_PORT_MODE_2x1_1x4:			/* mode 7 */
2297e370b0eSAndrew Rybchenko 		bandwidth = quad_lane + (2 * single_lane);
2307e370b0eSAndrew Rybchenko 		break;
2317e370b0eSAndrew Rybchenko 	case TLV_PORT_MODE_1x4_1x2:			/* mode 15 */
2327e370b0eSAndrew Rybchenko 	case TLV_PORT_MODE_1x2_1x4:			/* mode 16 */
2337e370b0eSAndrew Rybchenko 		bandwidth = quad_lane + dual_lane;
2347e370b0eSAndrew Rybchenko 		break;
2357e370b0eSAndrew Rybchenko 	case TLV_PORT_MODE_1x4_1x4:			/* mode 3 */
2367e370b0eSAndrew Rybchenko 		bandwidth = quad_lane + quad_lane;
237f6d61784SAndrew Rybchenko 		break;
238f6d61784SAndrew Rybchenko 	default:
239f6d61784SAndrew Rybchenko 		rc = EINVAL;
240c42b6a35SAndrew Rybchenko 		goto fail2;
241f6d61784SAndrew Rybchenko 	}
242f6d61784SAndrew Rybchenko 
243f6d61784SAndrew Rybchenko 	*bandwidth_mbpsp = bandwidth;
244f6d61784SAndrew Rybchenko 
245f6d61784SAndrew Rybchenko 	return (0);
246f6d61784SAndrew Rybchenko 
247c42b6a35SAndrew Rybchenko fail2:
248c42b6a35SAndrew Rybchenko 	EFSYS_PROBE(fail2);
249f6d61784SAndrew Rybchenko fail1:
250f6d61784SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
251f6d61784SAndrew Rybchenko 
252f6d61784SAndrew Rybchenko 	return (rc);
253f6d61784SAndrew Rybchenko }
25431bf5f03SAndrew Rybchenko 
25531bf5f03SAndrew Rybchenko static	__checkReturn		efx_rc_t
efx_mcdi_vadaptor_alloc(__in efx_nic_t * enp,__in uint32_t port_id)25631bf5f03SAndrew Rybchenko efx_mcdi_vadaptor_alloc(
25731bf5f03SAndrew Rybchenko 	__in			efx_nic_t *enp,
25831bf5f03SAndrew Rybchenko 	__in			uint32_t port_id)
25931bf5f03SAndrew Rybchenko {
26031bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
261315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VADAPTOR_ALLOC_IN_LEN,
262315bbbaaSAndrew Rybchenko 		MC_CMD_VADAPTOR_ALLOC_OUT_LEN);
26331bf5f03SAndrew Rybchenko 	efx_rc_t rc;
26431bf5f03SAndrew Rybchenko 
26531bf5f03SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL);
26631bf5f03SAndrew Rybchenko 
26731bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_VADAPTOR_ALLOC;
26831bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
26931bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN;
27031bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
27131bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN;
27231bf5f03SAndrew Rybchenko 
27331bf5f03SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id);
27431bf5f03SAndrew Rybchenko 	MCDI_IN_POPULATE_DWORD_1(req, VADAPTOR_ALLOC_IN_FLAGS,
27531bf5f03SAndrew Rybchenko 	    VADAPTOR_ALLOC_IN_FLAG_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED,
27631bf5f03SAndrew Rybchenko 	    enp->en_nic_cfg.enc_allow_set_mac_with_installed_filters ? 1 : 0);
27731bf5f03SAndrew Rybchenko 
27831bf5f03SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
27931bf5f03SAndrew Rybchenko 
28031bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
28131bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
28231bf5f03SAndrew Rybchenko 		goto fail1;
28331bf5f03SAndrew Rybchenko 	}
28431bf5f03SAndrew Rybchenko 
28531bf5f03SAndrew Rybchenko 	return (0);
28631bf5f03SAndrew Rybchenko 
28731bf5f03SAndrew Rybchenko fail1:
28831bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
28931bf5f03SAndrew Rybchenko 
29031bf5f03SAndrew Rybchenko 	return (rc);
29131bf5f03SAndrew Rybchenko }
29231bf5f03SAndrew Rybchenko 
29331bf5f03SAndrew Rybchenko static	__checkReturn		efx_rc_t
efx_mcdi_vadaptor_free(__in efx_nic_t * enp,__in uint32_t port_id)29431bf5f03SAndrew Rybchenko efx_mcdi_vadaptor_free(
29531bf5f03SAndrew Rybchenko 	__in			efx_nic_t *enp,
29631bf5f03SAndrew Rybchenko 	__in			uint32_t port_id)
29731bf5f03SAndrew Rybchenko {
29831bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
299315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VADAPTOR_FREE_IN_LEN,
300315bbbaaSAndrew Rybchenko 		MC_CMD_VADAPTOR_FREE_OUT_LEN);
30131bf5f03SAndrew Rybchenko 	efx_rc_t rc;
30231bf5f03SAndrew Rybchenko 
30331bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_VADAPTOR_FREE;
30431bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
30531bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN;
30631bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
30731bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN;
30831bf5f03SAndrew Rybchenko 
30931bf5f03SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id);
31031bf5f03SAndrew Rybchenko 
31131bf5f03SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
31231bf5f03SAndrew Rybchenko 
31331bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
31431bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
31531bf5f03SAndrew Rybchenko 		goto fail1;
31631bf5f03SAndrew Rybchenko 	}
31731bf5f03SAndrew Rybchenko 
31831bf5f03SAndrew Rybchenko 	return (0);
31931bf5f03SAndrew Rybchenko 
32031bf5f03SAndrew Rybchenko fail1:
32131bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
32231bf5f03SAndrew Rybchenko 
32331bf5f03SAndrew Rybchenko 	return (rc);
32431bf5f03SAndrew Rybchenko }
32531bf5f03SAndrew Rybchenko 
32631bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
32731bf5f03SAndrew Rybchenko efx_mcdi_get_mac_address_pf(
32831bf5f03SAndrew Rybchenko 	__in			efx_nic_t *enp,
32931bf5f03SAndrew Rybchenko 	__out_ecount_opt(6)	uint8_t mac_addrp[6])
33031bf5f03SAndrew Rybchenko {
33131bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
332315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_MAC_ADDRESSES_IN_LEN,
333315bbbaaSAndrew Rybchenko 		MC_CMD_GET_MAC_ADDRESSES_OUT_LEN);
33431bf5f03SAndrew Rybchenko 	efx_rc_t rc;
33531bf5f03SAndrew Rybchenko 
33631bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
337ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD ||
338ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD2);
33931bf5f03SAndrew Rybchenko 
34031bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES;
34131bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
34231bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN;
34331bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
34431bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_OUT_LEN;
34531bf5f03SAndrew Rybchenko 
34631bf5f03SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
34731bf5f03SAndrew Rybchenko 
34831bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
34931bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
35031bf5f03SAndrew Rybchenko 		goto fail1;
35131bf5f03SAndrew Rybchenko 	}
35231bf5f03SAndrew Rybchenko 
35331bf5f03SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) {
35431bf5f03SAndrew Rybchenko 		rc = EMSGSIZE;
35531bf5f03SAndrew Rybchenko 		goto fail2;
35631bf5f03SAndrew Rybchenko 	}
35731bf5f03SAndrew Rybchenko 
35831bf5f03SAndrew Rybchenko 	if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) {
35931bf5f03SAndrew Rybchenko 		rc = ENOENT;
36031bf5f03SAndrew Rybchenko 		goto fail3;
36131bf5f03SAndrew Rybchenko 	}
36231bf5f03SAndrew Rybchenko 
36331bf5f03SAndrew Rybchenko 	if (mac_addrp != NULL) {
36431bf5f03SAndrew Rybchenko 		uint8_t *addrp;
36531bf5f03SAndrew Rybchenko 
36631bf5f03SAndrew Rybchenko 		addrp = MCDI_OUT2(req, uint8_t,
36731bf5f03SAndrew Rybchenko 		    GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE);
36831bf5f03SAndrew Rybchenko 
36931bf5f03SAndrew Rybchenko 		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
37031bf5f03SAndrew Rybchenko 	}
37131bf5f03SAndrew Rybchenko 
37231bf5f03SAndrew Rybchenko 	return (0);
37331bf5f03SAndrew Rybchenko 
37431bf5f03SAndrew Rybchenko fail3:
37531bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail3);
37631bf5f03SAndrew Rybchenko fail2:
37731bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
37831bf5f03SAndrew Rybchenko fail1:
37931bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
38031bf5f03SAndrew Rybchenko 
38131bf5f03SAndrew Rybchenko 	return (rc);
38231bf5f03SAndrew Rybchenko }
38331bf5f03SAndrew Rybchenko 
38431bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
38531bf5f03SAndrew Rybchenko efx_mcdi_get_mac_address_vf(
38631bf5f03SAndrew Rybchenko 	__in			efx_nic_t *enp,
38731bf5f03SAndrew Rybchenko 	__out_ecount_opt(6)	uint8_t mac_addrp[6])
38831bf5f03SAndrew Rybchenko {
38931bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
390315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN,
391315bbbaaSAndrew Rybchenko 		MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX);
39231bf5f03SAndrew Rybchenko 	efx_rc_t rc;
39331bf5f03SAndrew Rybchenko 
39431bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
395ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD ||
396ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD2);
39731bf5f03SAndrew Rybchenko 
39831bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES;
39931bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
40031bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN;
40131bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
40231bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX;
40331bf5f03SAndrew Rybchenko 
40431bf5f03SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID,
40531bf5f03SAndrew Rybchenko 	    EVB_PORT_ID_ASSIGNED);
40631bf5f03SAndrew Rybchenko 
40731bf5f03SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
40831bf5f03SAndrew Rybchenko 
40931bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
41031bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
41131bf5f03SAndrew Rybchenko 		goto fail1;
41231bf5f03SAndrew Rybchenko 	}
41331bf5f03SAndrew Rybchenko 
41431bf5f03SAndrew Rybchenko 	if (req.emr_out_length_used <
41531bf5f03SAndrew Rybchenko 	    MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) {
41631bf5f03SAndrew Rybchenko 		rc = EMSGSIZE;
41731bf5f03SAndrew Rybchenko 		goto fail2;
41831bf5f03SAndrew Rybchenko 	}
41931bf5f03SAndrew Rybchenko 
42031bf5f03SAndrew Rybchenko 	if (MCDI_OUT_DWORD(req,
42131bf5f03SAndrew Rybchenko 		VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) {
42231bf5f03SAndrew Rybchenko 		rc = ENOENT;
42331bf5f03SAndrew Rybchenko 		goto fail3;
42431bf5f03SAndrew Rybchenko 	}
42531bf5f03SAndrew Rybchenko 
42631bf5f03SAndrew Rybchenko 	if (mac_addrp != NULL) {
42731bf5f03SAndrew Rybchenko 		uint8_t *addrp;
42831bf5f03SAndrew Rybchenko 
42931bf5f03SAndrew Rybchenko 		addrp = MCDI_OUT2(req, uint8_t,
43031bf5f03SAndrew Rybchenko 		    VPORT_GET_MAC_ADDRESSES_OUT_MACADDR);
43131bf5f03SAndrew Rybchenko 
43231bf5f03SAndrew Rybchenko 		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
43331bf5f03SAndrew Rybchenko 	}
43431bf5f03SAndrew Rybchenko 
43531bf5f03SAndrew Rybchenko 	return (0);
43631bf5f03SAndrew Rybchenko 
43731bf5f03SAndrew Rybchenko fail3:
43831bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail3);
43931bf5f03SAndrew Rybchenko fail2:
44031bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
44131bf5f03SAndrew Rybchenko fail1:
44231bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
44331bf5f03SAndrew Rybchenko 
44431bf5f03SAndrew Rybchenko 	return (rc);
44531bf5f03SAndrew Rybchenko }
44631bf5f03SAndrew Rybchenko 
44731bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_mcdi_get_clock(__in efx_nic_t * enp,__out uint32_t * sys_freqp,__out uint32_t * dpcpu_freqp)44831bf5f03SAndrew Rybchenko efx_mcdi_get_clock(
44931bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
45078e5c87cSAndrew Rybchenko 	__out		uint32_t *sys_freqp,
45178e5c87cSAndrew Rybchenko 	__out		uint32_t *dpcpu_freqp)
45231bf5f03SAndrew Rybchenko {
45331bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
454315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_CLOCK_IN_LEN,
455315bbbaaSAndrew Rybchenko 		MC_CMD_GET_CLOCK_OUT_LEN);
45631bf5f03SAndrew Rybchenko 	efx_rc_t rc;
45731bf5f03SAndrew Rybchenko 
45831bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
459ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD ||
460ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD2);
46131bf5f03SAndrew Rybchenko 
46231bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_GET_CLOCK;
46331bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
46431bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN;
46531bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
46631bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_CLOCK_OUT_LEN;
46731bf5f03SAndrew Rybchenko 
46831bf5f03SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
46931bf5f03SAndrew Rybchenko 
47031bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
47131bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
47231bf5f03SAndrew Rybchenko 		goto fail1;
47331bf5f03SAndrew Rybchenko 	}
47431bf5f03SAndrew Rybchenko 
47531bf5f03SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_GET_CLOCK_OUT_LEN) {
47631bf5f03SAndrew Rybchenko 		rc = EMSGSIZE;
47731bf5f03SAndrew Rybchenko 		goto fail2;
47831bf5f03SAndrew Rybchenko 	}
47931bf5f03SAndrew Rybchenko 
48031bf5f03SAndrew Rybchenko 	*sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ);
48131bf5f03SAndrew Rybchenko 	if (*sys_freqp == 0) {
48231bf5f03SAndrew Rybchenko 		rc = EINVAL;
48331bf5f03SAndrew Rybchenko 		goto fail3;
48431bf5f03SAndrew Rybchenko 	}
48578e5c87cSAndrew Rybchenko 	*dpcpu_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_DPCPU_FREQ);
48678e5c87cSAndrew Rybchenko 	if (*dpcpu_freqp == 0) {
48778e5c87cSAndrew Rybchenko 		rc = EINVAL;
48878e5c87cSAndrew Rybchenko 		goto fail4;
48978e5c87cSAndrew Rybchenko 	}
49031bf5f03SAndrew Rybchenko 
49131bf5f03SAndrew Rybchenko 	return (0);
49231bf5f03SAndrew Rybchenko 
49378e5c87cSAndrew Rybchenko fail4:
49478e5c87cSAndrew Rybchenko 	EFSYS_PROBE(fail4);
49531bf5f03SAndrew Rybchenko fail3:
49631bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail3);
49731bf5f03SAndrew Rybchenko fail2:
49831bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
49931bf5f03SAndrew Rybchenko fail1:
50031bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
50131bf5f03SAndrew Rybchenko 
50231bf5f03SAndrew Rybchenko 	return (rc);
50331bf5f03SAndrew Rybchenko }
50431bf5f03SAndrew Rybchenko 
50531bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_mcdi_get_rxdp_config(__in efx_nic_t * enp,__out uint32_t * end_paddingp)50645becd76SAndrew Rybchenko efx_mcdi_get_rxdp_config(
50745becd76SAndrew Rybchenko 	__in		efx_nic_t *enp,
50845becd76SAndrew Rybchenko 	__out		uint32_t *end_paddingp)
50945becd76SAndrew Rybchenko {
51045becd76SAndrew Rybchenko 	efx_mcdi_req_t req;
511315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_RXDP_CONFIG_IN_LEN,
512315bbbaaSAndrew Rybchenko 		MC_CMD_GET_RXDP_CONFIG_OUT_LEN);
51345becd76SAndrew Rybchenko 	uint32_t end_padding;
51445becd76SAndrew Rybchenko 	efx_rc_t rc;
51545becd76SAndrew Rybchenko 
51645becd76SAndrew Rybchenko 	req.emr_cmd = MC_CMD_GET_RXDP_CONFIG;
51745becd76SAndrew Rybchenko 	req.emr_in_buf = payload;
51845becd76SAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_RXDP_CONFIG_IN_LEN;
51945becd76SAndrew Rybchenko 	req.emr_out_buf = payload;
52045becd76SAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_RXDP_CONFIG_OUT_LEN;
52145becd76SAndrew Rybchenko 
52245becd76SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
52345becd76SAndrew Rybchenko 	if (req.emr_rc != 0) {
52445becd76SAndrew Rybchenko 		rc = req.emr_rc;
52545becd76SAndrew Rybchenko 		goto fail1;
52645becd76SAndrew Rybchenko 	}
52745becd76SAndrew Rybchenko 
52845becd76SAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, GET_RXDP_CONFIG_OUT_DATA,
52945becd76SAndrew Rybchenko 				    GET_RXDP_CONFIG_OUT_PAD_HOST_DMA) == 0) {
53045becd76SAndrew Rybchenko 		/* RX DMA end padding is disabled */
53145becd76SAndrew Rybchenko 		end_padding = 0;
53245becd76SAndrew Rybchenko 	} else {
53345becd76SAndrew Rybchenko 		switch (MCDI_OUT_DWORD_FIELD(req, GET_RXDP_CONFIG_OUT_DATA,
53445becd76SAndrew Rybchenko 					    GET_RXDP_CONFIG_OUT_PAD_HOST_LEN)) {
53545becd76SAndrew Rybchenko 		case MC_CMD_SET_RXDP_CONFIG_IN_PAD_HOST_64:
53645becd76SAndrew Rybchenko 			end_padding = 64;
53745becd76SAndrew Rybchenko 			break;
53845becd76SAndrew Rybchenko 		case MC_CMD_SET_RXDP_CONFIG_IN_PAD_HOST_128:
53945becd76SAndrew Rybchenko 			end_padding = 128;
54045becd76SAndrew Rybchenko 			break;
54145becd76SAndrew Rybchenko 		case MC_CMD_SET_RXDP_CONFIG_IN_PAD_HOST_256:
54245becd76SAndrew Rybchenko 			end_padding = 256;
54345becd76SAndrew Rybchenko 			break;
54445becd76SAndrew Rybchenko 		default:
54545becd76SAndrew Rybchenko 			rc = ENOTSUP;
54645becd76SAndrew Rybchenko 			goto fail2;
54745becd76SAndrew Rybchenko 		}
54845becd76SAndrew Rybchenko 	}
54945becd76SAndrew Rybchenko 
55045becd76SAndrew Rybchenko 	*end_paddingp = end_padding;
55145becd76SAndrew Rybchenko 
55245becd76SAndrew Rybchenko 	return (0);
55345becd76SAndrew Rybchenko 
55445becd76SAndrew Rybchenko fail2:
55545becd76SAndrew Rybchenko 	EFSYS_PROBE(fail2);
55645becd76SAndrew Rybchenko fail1:
55745becd76SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
55845becd76SAndrew Rybchenko 
55945becd76SAndrew Rybchenko 	return (rc);
56045becd76SAndrew Rybchenko }
56145becd76SAndrew Rybchenko 
56245becd76SAndrew Rybchenko 	__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)56331bf5f03SAndrew Rybchenko efx_mcdi_get_vector_cfg(
56431bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
56531bf5f03SAndrew Rybchenko 	__out_opt	uint32_t *vec_basep,
56631bf5f03SAndrew Rybchenko 	__out_opt	uint32_t *pf_nvecp,
56731bf5f03SAndrew Rybchenko 	__out_opt	uint32_t *vf_nvecp)
56831bf5f03SAndrew Rybchenko {
56931bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
570315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_VECTOR_CFG_IN_LEN,
571315bbbaaSAndrew Rybchenko 		MC_CMD_GET_VECTOR_CFG_OUT_LEN);
57231bf5f03SAndrew Rybchenko 	efx_rc_t rc;
57331bf5f03SAndrew Rybchenko 
57431bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_GET_VECTOR_CFG;
57531bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
57631bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN;
57731bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
57831bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_VECTOR_CFG_OUT_LEN;
57931bf5f03SAndrew Rybchenko 
58031bf5f03SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
58131bf5f03SAndrew Rybchenko 
58231bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
58331bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
58431bf5f03SAndrew Rybchenko 		goto fail1;
58531bf5f03SAndrew Rybchenko 	}
58631bf5f03SAndrew Rybchenko 
58731bf5f03SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_GET_VECTOR_CFG_OUT_LEN) {
58831bf5f03SAndrew Rybchenko 		rc = EMSGSIZE;
58931bf5f03SAndrew Rybchenko 		goto fail2;
59031bf5f03SAndrew Rybchenko 	}
59131bf5f03SAndrew Rybchenko 
59231bf5f03SAndrew Rybchenko 	if (vec_basep != NULL)
59331bf5f03SAndrew Rybchenko 		*vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE);
59431bf5f03SAndrew Rybchenko 	if (pf_nvecp != NULL)
59531bf5f03SAndrew Rybchenko 		*pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF);
59631bf5f03SAndrew Rybchenko 	if (vf_nvecp != NULL)
59731bf5f03SAndrew Rybchenko 		*vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF);
59831bf5f03SAndrew Rybchenko 
59931bf5f03SAndrew Rybchenko 	return (0);
60031bf5f03SAndrew Rybchenko 
60131bf5f03SAndrew Rybchenko fail2:
60231bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
60331bf5f03SAndrew Rybchenko fail1:
60431bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
60531bf5f03SAndrew Rybchenko 
60631bf5f03SAndrew Rybchenko 	return (rc);
60731bf5f03SAndrew Rybchenko }
60831bf5f03SAndrew Rybchenko 
60931bf5f03SAndrew Rybchenko 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)61031bf5f03SAndrew Rybchenko efx_mcdi_alloc_vis(
61131bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
61231bf5f03SAndrew Rybchenko 	__in		uint32_t min_vi_count,
61331bf5f03SAndrew Rybchenko 	__in		uint32_t max_vi_count,
61431bf5f03SAndrew Rybchenko 	__out		uint32_t *vi_basep,
61531bf5f03SAndrew Rybchenko 	__out		uint32_t *vi_countp,
61631bf5f03SAndrew Rybchenko 	__out		uint32_t *vi_shiftp)
61731bf5f03SAndrew Rybchenko {
61831bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
619315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_ALLOC_VIS_IN_LEN,
620315bbbaaSAndrew Rybchenko 		MC_CMD_ALLOC_VIS_EXT_OUT_LEN);
62131bf5f03SAndrew Rybchenko 	efx_rc_t rc;
62231bf5f03SAndrew Rybchenko 
62331bf5f03SAndrew Rybchenko 	if (vi_countp == NULL) {
62431bf5f03SAndrew Rybchenko 		rc = EINVAL;
62531bf5f03SAndrew Rybchenko 		goto fail1;
62631bf5f03SAndrew Rybchenko 	}
62731bf5f03SAndrew Rybchenko 
62831bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_ALLOC_VIS;
62931bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
63031bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN;
63131bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
632454502b9SAndrew Rybchenko 	req.emr_out_length = MC_CMD_ALLOC_VIS_EXT_OUT_LEN;
63331bf5f03SAndrew Rybchenko 
63431bf5f03SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count);
63531bf5f03SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count);
63631bf5f03SAndrew Rybchenko 
63731bf5f03SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
63831bf5f03SAndrew Rybchenko 
63931bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
64031bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
64131bf5f03SAndrew Rybchenko 		goto fail2;
64231bf5f03SAndrew Rybchenko 	}
64331bf5f03SAndrew Rybchenko 
64431bf5f03SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) {
64531bf5f03SAndrew Rybchenko 		rc = EMSGSIZE;
64631bf5f03SAndrew Rybchenko 		goto fail3;
64731bf5f03SAndrew Rybchenko 	}
64831bf5f03SAndrew Rybchenko 
64931bf5f03SAndrew Rybchenko 	*vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE);
65031bf5f03SAndrew Rybchenko 	*vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT);
65131bf5f03SAndrew Rybchenko 
65231bf5f03SAndrew Rybchenko 	/* Report VI_SHIFT if available (always zero for Huntington) */
65331bf5f03SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_EXT_OUT_LEN)
65431bf5f03SAndrew Rybchenko 		*vi_shiftp = 0;
65531bf5f03SAndrew Rybchenko 	else
65631bf5f03SAndrew Rybchenko 		*vi_shiftp = MCDI_OUT_DWORD(req, ALLOC_VIS_EXT_OUT_VI_SHIFT);
65731bf5f03SAndrew Rybchenko 
65831bf5f03SAndrew Rybchenko 	return (0);
65931bf5f03SAndrew Rybchenko 
66031bf5f03SAndrew Rybchenko fail3:
66131bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail3);
66231bf5f03SAndrew Rybchenko fail2:
66331bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
66431bf5f03SAndrew Rybchenko fail1:
66531bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
66631bf5f03SAndrew Rybchenko 
66731bf5f03SAndrew Rybchenko 	return (rc);
66831bf5f03SAndrew Rybchenko }
66931bf5f03SAndrew Rybchenko 
67031bf5f03SAndrew Rybchenko static	__checkReturn	efx_rc_t
efx_mcdi_free_vis(__in efx_nic_t * enp)67131bf5f03SAndrew Rybchenko efx_mcdi_free_vis(
67231bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp)
67331bf5f03SAndrew Rybchenko {
67431bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
67531bf5f03SAndrew Rybchenko 	efx_rc_t rc;
67631bf5f03SAndrew Rybchenko 
67731bf5f03SAndrew Rybchenko 	EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0);
67831bf5f03SAndrew Rybchenko 	EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0);
67931bf5f03SAndrew Rybchenko 
68031bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_FREE_VIS;
68131bf5f03SAndrew Rybchenko 	req.emr_in_buf = NULL;
68231bf5f03SAndrew Rybchenko 	req.emr_in_length = 0;
68331bf5f03SAndrew Rybchenko 	req.emr_out_buf = NULL;
68431bf5f03SAndrew Rybchenko 	req.emr_out_length = 0;
68531bf5f03SAndrew Rybchenko 
68631bf5f03SAndrew Rybchenko 	efx_mcdi_execute_quiet(enp, &req);
68731bf5f03SAndrew Rybchenko 
68831bf5f03SAndrew Rybchenko 	/* Ignore ELREADY (no allocated VIs, so nothing to free) */
68931bf5f03SAndrew Rybchenko 	if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) {
69031bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
69131bf5f03SAndrew Rybchenko 		goto fail1;
69231bf5f03SAndrew Rybchenko 	}
69331bf5f03SAndrew Rybchenko 
69431bf5f03SAndrew Rybchenko 	return (0);
69531bf5f03SAndrew Rybchenko 
69631bf5f03SAndrew Rybchenko fail1:
69731bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
69831bf5f03SAndrew Rybchenko 
69931bf5f03SAndrew Rybchenko 	return (rc);
70031bf5f03SAndrew Rybchenko }
70131bf5f03SAndrew Rybchenko 
70231bf5f03SAndrew Rybchenko static	__checkReturn	efx_rc_t
efx_mcdi_alloc_piobuf(__in efx_nic_t * enp,__out efx_piobuf_handle_t * handlep)70331bf5f03SAndrew Rybchenko efx_mcdi_alloc_piobuf(
70431bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
70531bf5f03SAndrew Rybchenko 	__out		efx_piobuf_handle_t *handlep)
70631bf5f03SAndrew Rybchenko {
70731bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
708315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_ALLOC_PIOBUF_IN_LEN,
709315bbbaaSAndrew Rybchenko 		MC_CMD_ALLOC_PIOBUF_OUT_LEN);
71031bf5f03SAndrew Rybchenko 	efx_rc_t rc;
71131bf5f03SAndrew Rybchenko 
71231bf5f03SAndrew Rybchenko 	if (handlep == NULL) {
71331bf5f03SAndrew Rybchenko 		rc = EINVAL;
71431bf5f03SAndrew Rybchenko 		goto fail1;
71531bf5f03SAndrew Rybchenko 	}
71631bf5f03SAndrew Rybchenko 
71731bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_ALLOC_PIOBUF;
71831bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
71931bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN;
72031bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
72131bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN;
72231bf5f03SAndrew Rybchenko 
72331bf5f03SAndrew Rybchenko 	efx_mcdi_execute_quiet(enp, &req);
72431bf5f03SAndrew Rybchenko 
72531bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
72631bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
72731bf5f03SAndrew Rybchenko 		goto fail2;
72831bf5f03SAndrew Rybchenko 	}
72931bf5f03SAndrew Rybchenko 
73031bf5f03SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) {
73131bf5f03SAndrew Rybchenko 		rc = EMSGSIZE;
73231bf5f03SAndrew Rybchenko 		goto fail3;
73331bf5f03SAndrew Rybchenko 	}
73431bf5f03SAndrew Rybchenko 
73531bf5f03SAndrew Rybchenko 	*handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE);
73631bf5f03SAndrew Rybchenko 
73731bf5f03SAndrew Rybchenko 	return (0);
73831bf5f03SAndrew Rybchenko 
73931bf5f03SAndrew Rybchenko fail3:
74031bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail3);
74131bf5f03SAndrew Rybchenko fail2:
74231bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
74331bf5f03SAndrew Rybchenko fail1:
74431bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
74531bf5f03SAndrew Rybchenko 
74631bf5f03SAndrew Rybchenko 	return (rc);
74731bf5f03SAndrew Rybchenko }
74831bf5f03SAndrew Rybchenko 
74931bf5f03SAndrew Rybchenko static	__checkReturn	efx_rc_t
efx_mcdi_free_piobuf(__in efx_nic_t * enp,__in efx_piobuf_handle_t handle)75031bf5f03SAndrew Rybchenko efx_mcdi_free_piobuf(
75131bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
75231bf5f03SAndrew Rybchenko 	__in		efx_piobuf_handle_t handle)
75331bf5f03SAndrew Rybchenko {
75431bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
755315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FREE_PIOBUF_IN_LEN,
756315bbbaaSAndrew Rybchenko 		MC_CMD_FREE_PIOBUF_OUT_LEN);
75731bf5f03SAndrew Rybchenko 	efx_rc_t rc;
75831bf5f03SAndrew Rybchenko 
75931bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_FREE_PIOBUF;
76031bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
76131bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN;
76231bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
76331bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN;
76431bf5f03SAndrew Rybchenko 
76531bf5f03SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle);
76631bf5f03SAndrew Rybchenko 
76731bf5f03SAndrew Rybchenko 	efx_mcdi_execute_quiet(enp, &req);
76831bf5f03SAndrew Rybchenko 
76931bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
77031bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
77131bf5f03SAndrew Rybchenko 		goto fail1;
77231bf5f03SAndrew Rybchenko 	}
77331bf5f03SAndrew Rybchenko 
77431bf5f03SAndrew Rybchenko 	return (0);
77531bf5f03SAndrew Rybchenko 
77631bf5f03SAndrew Rybchenko fail1:
77731bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
77831bf5f03SAndrew Rybchenko 
77931bf5f03SAndrew Rybchenko 	return (rc);
78031bf5f03SAndrew Rybchenko }
78131bf5f03SAndrew Rybchenko 
78231bf5f03SAndrew Rybchenko 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)78331bf5f03SAndrew Rybchenko efx_mcdi_link_piobuf(
78431bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
78531bf5f03SAndrew Rybchenko 	__in		uint32_t vi_index,
78631bf5f03SAndrew Rybchenko 	__in		efx_piobuf_handle_t handle)
78731bf5f03SAndrew Rybchenko {
78831bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
789315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LINK_PIOBUF_IN_LEN,
790315bbbaaSAndrew Rybchenko 		MC_CMD_LINK_PIOBUF_OUT_LEN);
79131bf5f03SAndrew Rybchenko 	efx_rc_t rc;
79231bf5f03SAndrew Rybchenko 
79331bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_LINK_PIOBUF;
79431bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
79531bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN;
79631bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
79731bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN;
79831bf5f03SAndrew Rybchenko 
79931bf5f03SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle);
80031bf5f03SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index);
80131bf5f03SAndrew Rybchenko 
80231bf5f03SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
80331bf5f03SAndrew Rybchenko 
80431bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
80531bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
80631bf5f03SAndrew Rybchenko 		goto fail1;
80731bf5f03SAndrew Rybchenko 	}
80831bf5f03SAndrew Rybchenko 
80931bf5f03SAndrew Rybchenko 	return (0);
81031bf5f03SAndrew Rybchenko 
81131bf5f03SAndrew Rybchenko fail1:
81231bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
81331bf5f03SAndrew Rybchenko 
81431bf5f03SAndrew Rybchenko 	return (rc);
81531bf5f03SAndrew Rybchenko }
81631bf5f03SAndrew Rybchenko 
81731bf5f03SAndrew Rybchenko static	__checkReturn	efx_rc_t
efx_mcdi_unlink_piobuf(__in efx_nic_t * enp,__in uint32_t vi_index)81831bf5f03SAndrew Rybchenko efx_mcdi_unlink_piobuf(
81931bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
82031bf5f03SAndrew Rybchenko 	__in		uint32_t vi_index)
82131bf5f03SAndrew Rybchenko {
82231bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
823315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_UNLINK_PIOBUF_IN_LEN,
824315bbbaaSAndrew Rybchenko 		MC_CMD_UNLINK_PIOBUF_OUT_LEN);
82531bf5f03SAndrew Rybchenko 	efx_rc_t rc;
82631bf5f03SAndrew Rybchenko 
82731bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_UNLINK_PIOBUF;
82831bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
82931bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN;
83031bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
83131bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN;
83231bf5f03SAndrew Rybchenko 
83331bf5f03SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index);
83431bf5f03SAndrew Rybchenko 
835bba8dcbcSAndrew Rybchenko 	efx_mcdi_execute_quiet(enp, &req);
83631bf5f03SAndrew Rybchenko 
83731bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
83831bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
83931bf5f03SAndrew Rybchenko 		goto fail1;
84031bf5f03SAndrew Rybchenko 	}
84131bf5f03SAndrew Rybchenko 
84231bf5f03SAndrew Rybchenko 	return (0);
84331bf5f03SAndrew Rybchenko 
84431bf5f03SAndrew Rybchenko fail1:
84531bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
84631bf5f03SAndrew Rybchenko 
84731bf5f03SAndrew Rybchenko 	return (rc);
84831bf5f03SAndrew Rybchenko }
84931bf5f03SAndrew Rybchenko 
85031bf5f03SAndrew Rybchenko static			void
ef10_nic_alloc_piobufs(__in efx_nic_t * enp,__in uint32_t max_piobuf_count)85131bf5f03SAndrew Rybchenko ef10_nic_alloc_piobufs(
85231bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
85331bf5f03SAndrew Rybchenko 	__in		uint32_t max_piobuf_count)
85431bf5f03SAndrew Rybchenko {
85531bf5f03SAndrew Rybchenko 	efx_piobuf_handle_t *handlep;
85631bf5f03SAndrew Rybchenko 	unsigned int i;
85731bf5f03SAndrew Rybchenko 
85831bf5f03SAndrew Rybchenko 	EFSYS_ASSERT3U(max_piobuf_count, <=,
85931bf5f03SAndrew Rybchenko 	    EFX_ARRAY_SIZE(enp->en_arch.ef10.ena_piobuf_handle));
86031bf5f03SAndrew Rybchenko 
86131bf5f03SAndrew Rybchenko 	enp->en_arch.ef10.ena_piobuf_count = 0;
86231bf5f03SAndrew Rybchenko 
86331bf5f03SAndrew Rybchenko 	for (i = 0; i < max_piobuf_count; i++) {
86431bf5f03SAndrew Rybchenko 		handlep = &enp->en_arch.ef10.ena_piobuf_handle[i];
86531bf5f03SAndrew Rybchenko 
866647a7e8fSAndrew Rybchenko 		if (efx_mcdi_alloc_piobuf(enp, handlep) != 0)
86731bf5f03SAndrew Rybchenko 			goto fail1;
86831bf5f03SAndrew Rybchenko 
86931bf5f03SAndrew Rybchenko 		enp->en_arch.ef10.ena_pio_alloc_map[i] = 0;
87031bf5f03SAndrew Rybchenko 		enp->en_arch.ef10.ena_piobuf_count++;
87131bf5f03SAndrew Rybchenko 	}
87231bf5f03SAndrew Rybchenko 
87331bf5f03SAndrew Rybchenko 	return;
87431bf5f03SAndrew Rybchenko 
87531bf5f03SAndrew Rybchenko fail1:
87631bf5f03SAndrew Rybchenko 	for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
87731bf5f03SAndrew Rybchenko 		handlep = &enp->en_arch.ef10.ena_piobuf_handle[i];
87831bf5f03SAndrew Rybchenko 
879e4ddd4ccSAndrew Rybchenko 		(void) efx_mcdi_free_piobuf(enp, *handlep);
88031bf5f03SAndrew Rybchenko 		*handlep = EFX_PIOBUF_HANDLE_INVALID;
88131bf5f03SAndrew Rybchenko 	}
88231bf5f03SAndrew Rybchenko 	enp->en_arch.ef10.ena_piobuf_count = 0;
88331bf5f03SAndrew Rybchenko }
88431bf5f03SAndrew Rybchenko 
88531bf5f03SAndrew Rybchenko static			void
ef10_nic_free_piobufs(__in efx_nic_t * enp)88631bf5f03SAndrew Rybchenko ef10_nic_free_piobufs(
88731bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp)
88831bf5f03SAndrew Rybchenko {
88931bf5f03SAndrew Rybchenko 	efx_piobuf_handle_t *handlep;
89031bf5f03SAndrew Rybchenko 	unsigned int i;
89131bf5f03SAndrew Rybchenko 
89231bf5f03SAndrew Rybchenko 	for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
89331bf5f03SAndrew Rybchenko 		handlep = &enp->en_arch.ef10.ena_piobuf_handle[i];
89431bf5f03SAndrew Rybchenko 
895e4ddd4ccSAndrew Rybchenko 		(void) efx_mcdi_free_piobuf(enp, *handlep);
89631bf5f03SAndrew Rybchenko 		*handlep = EFX_PIOBUF_HANDLE_INVALID;
89731bf5f03SAndrew Rybchenko 	}
89831bf5f03SAndrew Rybchenko 	enp->en_arch.ef10.ena_piobuf_count = 0;
89931bf5f03SAndrew Rybchenko }
90031bf5f03SAndrew Rybchenko 
90131bf5f03SAndrew Rybchenko /* Sub-allocate a block from a piobuf */
90231bf5f03SAndrew Rybchenko 	__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)90331bf5f03SAndrew Rybchenko ef10_nic_pio_alloc(
90431bf5f03SAndrew Rybchenko 	__inout		efx_nic_t *enp,
90531bf5f03SAndrew Rybchenko 	__out		uint32_t *bufnump,
90631bf5f03SAndrew Rybchenko 	__out		efx_piobuf_handle_t *handlep,
90731bf5f03SAndrew Rybchenko 	__out		uint32_t *blknump,
90831bf5f03SAndrew Rybchenko 	__out		uint32_t *offsetp,
90931bf5f03SAndrew Rybchenko 	__out		size_t *sizep)
91031bf5f03SAndrew Rybchenko {
91131bf5f03SAndrew Rybchenko 	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
91231bf5f03SAndrew Rybchenko 	efx_drv_cfg_t *edcp = &enp->en_drv_cfg;
91331bf5f03SAndrew Rybchenko 	uint32_t blk_per_buf;
91431bf5f03SAndrew Rybchenko 	uint32_t buf, blk;
91531bf5f03SAndrew Rybchenko 	efx_rc_t rc;
91631bf5f03SAndrew Rybchenko 
91731bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
918ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD ||
919ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD2);
92031bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(bufnump);
92131bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(handlep);
92231bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(blknump);
92331bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(offsetp);
92431bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(sizep);
92531bf5f03SAndrew Rybchenko 
92631bf5f03SAndrew Rybchenko 	if ((edcp->edc_pio_alloc_size == 0) ||
92731bf5f03SAndrew Rybchenko 	    (enp->en_arch.ef10.ena_piobuf_count == 0)) {
92831bf5f03SAndrew Rybchenko 		rc = ENOMEM;
92931bf5f03SAndrew Rybchenko 		goto fail1;
93031bf5f03SAndrew Rybchenko 	}
93131bf5f03SAndrew Rybchenko 	blk_per_buf = encp->enc_piobuf_size / edcp->edc_pio_alloc_size;
93231bf5f03SAndrew Rybchenko 
93331bf5f03SAndrew Rybchenko 	for (buf = 0; buf < enp->en_arch.ef10.ena_piobuf_count; buf++) {
93431bf5f03SAndrew Rybchenko 		uint32_t *map = &enp->en_arch.ef10.ena_pio_alloc_map[buf];
93531bf5f03SAndrew Rybchenko 
93631bf5f03SAndrew Rybchenko 		if (~(*map) == 0)
93731bf5f03SAndrew Rybchenko 			continue;
93831bf5f03SAndrew Rybchenko 
93931bf5f03SAndrew Rybchenko 		EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map)));
94031bf5f03SAndrew Rybchenko 		for (blk = 0; blk < blk_per_buf; blk++) {
94131bf5f03SAndrew Rybchenko 			if ((*map & (1u << blk)) == 0) {
94231bf5f03SAndrew Rybchenko 				*map |= (1u << blk);
94331bf5f03SAndrew Rybchenko 				goto done;
94431bf5f03SAndrew Rybchenko 			}
94531bf5f03SAndrew Rybchenko 		}
94631bf5f03SAndrew Rybchenko 	}
94731bf5f03SAndrew Rybchenko 	rc = ENOMEM;
94831bf5f03SAndrew Rybchenko 	goto fail2;
94931bf5f03SAndrew Rybchenko 
95031bf5f03SAndrew Rybchenko done:
95131bf5f03SAndrew Rybchenko 	*handlep = enp->en_arch.ef10.ena_piobuf_handle[buf];
95231bf5f03SAndrew Rybchenko 	*bufnump = buf;
95331bf5f03SAndrew Rybchenko 	*blknump = blk;
95431bf5f03SAndrew Rybchenko 	*sizep = edcp->edc_pio_alloc_size;
95531bf5f03SAndrew Rybchenko 	*offsetp = blk * (*sizep);
95631bf5f03SAndrew Rybchenko 
95731bf5f03SAndrew Rybchenko 	return (0);
95831bf5f03SAndrew Rybchenko 
95931bf5f03SAndrew Rybchenko fail2:
96031bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
96131bf5f03SAndrew Rybchenko fail1:
96231bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
96331bf5f03SAndrew Rybchenko 
96431bf5f03SAndrew Rybchenko 	return (rc);
96531bf5f03SAndrew Rybchenko }
96631bf5f03SAndrew Rybchenko 
96731bf5f03SAndrew Rybchenko /* Free a piobuf sub-allocated block */
96831bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_nic_pio_free(__inout efx_nic_t * enp,__in uint32_t bufnum,__in uint32_t blknum)96931bf5f03SAndrew Rybchenko ef10_nic_pio_free(
97031bf5f03SAndrew Rybchenko 	__inout		efx_nic_t *enp,
97131bf5f03SAndrew Rybchenko 	__in		uint32_t bufnum,
97231bf5f03SAndrew Rybchenko 	__in		uint32_t blknum)
97331bf5f03SAndrew Rybchenko {
97431bf5f03SAndrew Rybchenko 	uint32_t *map;
97531bf5f03SAndrew Rybchenko 	efx_rc_t rc;
97631bf5f03SAndrew Rybchenko 
97731bf5f03SAndrew Rybchenko 	if ((bufnum >= enp->en_arch.ef10.ena_piobuf_count) ||
97831bf5f03SAndrew Rybchenko 	    (blknum >= (8 * sizeof (*map)))) {
97931bf5f03SAndrew Rybchenko 		rc = EINVAL;
98031bf5f03SAndrew Rybchenko 		goto fail1;
98131bf5f03SAndrew Rybchenko 	}
98231bf5f03SAndrew Rybchenko 
98331bf5f03SAndrew Rybchenko 	map = &enp->en_arch.ef10.ena_pio_alloc_map[bufnum];
98431bf5f03SAndrew Rybchenko 	if ((*map & (1u << blknum)) == 0) {
98531bf5f03SAndrew Rybchenko 		rc = ENOENT;
98631bf5f03SAndrew Rybchenko 		goto fail2;
98731bf5f03SAndrew Rybchenko 	}
98831bf5f03SAndrew Rybchenko 	*map &= ~(1u << blknum);
98931bf5f03SAndrew Rybchenko 
99031bf5f03SAndrew Rybchenko 	return (0);
99131bf5f03SAndrew Rybchenko 
99231bf5f03SAndrew Rybchenko fail2:
99331bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
99431bf5f03SAndrew Rybchenko fail1:
99531bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
99631bf5f03SAndrew Rybchenko 
99731bf5f03SAndrew Rybchenko 	return (rc);
99831bf5f03SAndrew Rybchenko }
99931bf5f03SAndrew Rybchenko 
100031bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_nic_pio_link(__inout efx_nic_t * enp,__in uint32_t vi_index,__in efx_piobuf_handle_t handle)100131bf5f03SAndrew Rybchenko ef10_nic_pio_link(
100231bf5f03SAndrew Rybchenko 	__inout		efx_nic_t *enp,
100331bf5f03SAndrew Rybchenko 	__in		uint32_t vi_index,
100431bf5f03SAndrew Rybchenko 	__in		efx_piobuf_handle_t handle)
100531bf5f03SAndrew Rybchenko {
100631bf5f03SAndrew Rybchenko 	return (efx_mcdi_link_piobuf(enp, vi_index, handle));
100731bf5f03SAndrew Rybchenko }
100831bf5f03SAndrew Rybchenko 
100931bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_nic_pio_unlink(__inout efx_nic_t * enp,__in uint32_t vi_index)101031bf5f03SAndrew Rybchenko ef10_nic_pio_unlink(
101131bf5f03SAndrew Rybchenko 	__inout		efx_nic_t *enp,
101231bf5f03SAndrew Rybchenko 	__in		uint32_t vi_index)
101331bf5f03SAndrew Rybchenko {
101431bf5f03SAndrew Rybchenko 	return (efx_mcdi_unlink_piobuf(enp, vi_index));
101531bf5f03SAndrew Rybchenko }
101631bf5f03SAndrew Rybchenko 
1017b422f949SAndrew Rybchenko static	__checkReturn	efx_rc_t
ef10_mcdi_get_pf_count(__in efx_nic_t * enp,__out uint32_t * pf_countp)1018b422f949SAndrew Rybchenko ef10_mcdi_get_pf_count(
1019b422f949SAndrew Rybchenko 	__in		efx_nic_t *enp,
1020b422f949SAndrew Rybchenko 	__out		uint32_t *pf_countp)
1021b422f949SAndrew Rybchenko {
1022b422f949SAndrew Rybchenko 	efx_mcdi_req_t req;
1023315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PF_COUNT_IN_LEN,
1024315bbbaaSAndrew Rybchenko 		MC_CMD_GET_PF_COUNT_OUT_LEN);
1025b422f949SAndrew Rybchenko 	efx_rc_t rc;
1026b422f949SAndrew Rybchenko 
1027b422f949SAndrew Rybchenko 	req.emr_cmd = MC_CMD_GET_PF_COUNT;
1028b422f949SAndrew Rybchenko 	req.emr_in_buf = payload;
1029b422f949SAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_PF_COUNT_IN_LEN;
1030b422f949SAndrew Rybchenko 	req.emr_out_buf = payload;
1031b422f949SAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_PF_COUNT_OUT_LEN;
1032b422f949SAndrew Rybchenko 
1033b422f949SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
1034b422f949SAndrew Rybchenko 
1035b422f949SAndrew Rybchenko 	if (req.emr_rc != 0) {
1036b422f949SAndrew Rybchenko 		rc = req.emr_rc;
1037b422f949SAndrew Rybchenko 		goto fail1;
1038b422f949SAndrew Rybchenko 	}
1039b422f949SAndrew Rybchenko 
1040b422f949SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_GET_PF_COUNT_OUT_LEN) {
1041b422f949SAndrew Rybchenko 		rc = EMSGSIZE;
1042b422f949SAndrew Rybchenko 		goto fail2;
1043b422f949SAndrew Rybchenko 	}
1044b422f949SAndrew Rybchenko 
1045b422f949SAndrew Rybchenko 	*pf_countp = *MCDI_OUT(req, uint8_t,
1046b422f949SAndrew Rybchenko 				MC_CMD_GET_PF_COUNT_OUT_PF_COUNT_OFST);
1047b422f949SAndrew Rybchenko 
1048b422f949SAndrew Rybchenko 	EFSYS_ASSERT(*pf_countp != 0);
1049b422f949SAndrew Rybchenko 
1050b422f949SAndrew Rybchenko 	return (0);
1051b422f949SAndrew Rybchenko 
1052b422f949SAndrew Rybchenko fail2:
1053b422f949SAndrew Rybchenko 	EFSYS_PROBE(fail2);
1054b422f949SAndrew Rybchenko fail1:
1055b422f949SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1056b422f949SAndrew Rybchenko 
1057b422f949SAndrew Rybchenko 	return (rc);
1058b422f949SAndrew Rybchenko }
1059b422f949SAndrew Rybchenko 
1060deeaf87fSAndrew Rybchenko static	__checkReturn	efx_rc_t
ef10_get_datapath_caps(__in efx_nic_t * enp)106131bf5f03SAndrew Rybchenko ef10_get_datapath_caps(
106231bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp)
106331bf5f03SAndrew Rybchenko {
106431bf5f03SAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1065016941e3SAndrew Rybchenko 	efx_mcdi_req_t req;
1066315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_CAPABILITIES_IN_LEN,
1067315bbbaaSAndrew Rybchenko 		MC_CMD_GET_CAPABILITIES_V5_OUT_LEN);
106831bf5f03SAndrew Rybchenko 	efx_rc_t rc;
106931bf5f03SAndrew Rybchenko 
1070b422f949SAndrew Rybchenko 	if ((rc = ef10_mcdi_get_pf_count(enp, &encp->enc_hw_pf_count)) != 0)
1071b422f949SAndrew Rybchenko 		goto fail1;
1072b422f949SAndrew Rybchenko 
1073016941e3SAndrew Rybchenko 	req.emr_cmd = MC_CMD_GET_CAPABILITIES;
1074016941e3SAndrew Rybchenko 	req.emr_in_buf = payload;
1075016941e3SAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN;
1076016941e3SAndrew Rybchenko 	req.emr_out_buf = payload;
10775c2f9d6aSAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_CAPABILITIES_V5_OUT_LEN;
1078016941e3SAndrew Rybchenko 
1079016941e3SAndrew Rybchenko 	efx_mcdi_execute_quiet(enp, &req);
1080016941e3SAndrew Rybchenko 
1081016941e3SAndrew Rybchenko 	if (req.emr_rc != 0) {
1082016941e3SAndrew Rybchenko 		rc = req.emr_rc;
1083016941e3SAndrew Rybchenko 		goto fail2;
1084016941e3SAndrew Rybchenko 	}
1085016941e3SAndrew Rybchenko 
1086016941e3SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) {
1087016941e3SAndrew Rybchenko 		rc = EMSGSIZE;
1088016941e3SAndrew Rybchenko 		goto fail3;
1089016941e3SAndrew Rybchenko 	}
1090016941e3SAndrew Rybchenko 
1091016941e3SAndrew Rybchenko #define	CAP_FLAGS1(_req, _flag)						\
1092016941e3SAndrew Rybchenko 	(MCDI_OUT_DWORD((_req), GET_CAPABILITIES_OUT_FLAGS1) &		\
1093016941e3SAndrew Rybchenko 	(1u << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## _flag ## _LBN)))
1094016941e3SAndrew Rybchenko 
1095016941e3SAndrew Rybchenko #define	CAP_FLAGS2(_req, _flag)						\
1096016941e3SAndrew Rybchenko 	(((_req).emr_out_length_used >= MC_CMD_GET_CAPABILITIES_V2_OUT_LEN) && \
1097016941e3SAndrew Rybchenko 	    (MCDI_OUT_DWORD((_req), GET_CAPABILITIES_V2_OUT_FLAGS2) &	\
1098016941e3SAndrew Rybchenko 	    (1u << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## _flag ## _LBN))))
109931bf5f03SAndrew Rybchenko 
110031bf5f03SAndrew Rybchenko 	/*
110131bf5f03SAndrew Rybchenko 	 * Huntington RXDP firmware inserts a 0 or 14 byte prefix.
110231bf5f03SAndrew Rybchenko 	 * We only support the 14 byte prefix here.
110331bf5f03SAndrew Rybchenko 	 */
1104016941e3SAndrew Rybchenko 	if (CAP_FLAGS1(req, RX_PREFIX_LEN_14) == 0) {
110531bf5f03SAndrew Rybchenko 		rc = ENOTSUP;
1106016941e3SAndrew Rybchenko 		goto fail4;
110731bf5f03SAndrew Rybchenko 	}
110831bf5f03SAndrew Rybchenko 	encp->enc_rx_prefix_size = 14;
110931bf5f03SAndrew Rybchenko 
11105a51b32eSAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
1111fd962dffSAndrew Rybchenko 	/* Check if the firmware supports additional RSS modes */
1112fd962dffSAndrew Rybchenko 	if (CAP_FLAGS1(req, ADDITIONAL_RSS_MODES))
1113fd962dffSAndrew Rybchenko 		encp->enc_rx_scale_additional_modes_supported = B_TRUE;
1114fd962dffSAndrew Rybchenko 	else
1115fd962dffSAndrew Rybchenko 		encp->enc_rx_scale_additional_modes_supported = B_FALSE;
11165a51b32eSAndrew Rybchenko #endif /* EFSYS_OPT_RX_SCALE */
1117fd962dffSAndrew Rybchenko 
111831bf5f03SAndrew Rybchenko 	/* Check if the firmware supports TSO */
1119016941e3SAndrew Rybchenko 	if (CAP_FLAGS1(req, TX_TSO))
1120016941e3SAndrew Rybchenko 		encp->enc_fw_assisted_tso_enabled = B_TRUE;
1121016941e3SAndrew Rybchenko 	else
1122016941e3SAndrew Rybchenko 		encp->enc_fw_assisted_tso_enabled = B_FALSE;
112331bf5f03SAndrew Rybchenko 
112431bf5f03SAndrew Rybchenko 	/* Check if the firmware supports FATSOv2 */
1125016941e3SAndrew Rybchenko 	if (CAP_FLAGS2(req, TX_TSO_V2)) {
1126016941e3SAndrew Rybchenko 		encp->enc_fw_assisted_tso_v2_enabled = B_TRUE;
1127016941e3SAndrew Rybchenko 		encp->enc_fw_assisted_tso_v2_n_contexts = MCDI_OUT_WORD(req,
1128016941e3SAndrew Rybchenko 		    GET_CAPABILITIES_V2_OUT_TX_TSO_V2_N_CONTEXTS);
1129016941e3SAndrew Rybchenko 	} else {
1130016941e3SAndrew Rybchenko 		encp->enc_fw_assisted_tso_v2_enabled = B_FALSE;
1131016941e3SAndrew Rybchenko 		encp->enc_fw_assisted_tso_v2_n_contexts = 0;
1132016941e3SAndrew Rybchenko 	}
11339933eabbSAndrew Rybchenko 
1134357c2ebbSAndrew Rybchenko 	/* Check if the firmware supports FATSOv2 encap */
1135357c2ebbSAndrew Rybchenko 	if (CAP_FLAGS2(req, TX_TSO_V2_ENCAP))
1136357c2ebbSAndrew Rybchenko 		encp->enc_fw_assisted_tso_v2_encap_enabled = B_TRUE;
1137357c2ebbSAndrew Rybchenko 	else
1138357c2ebbSAndrew Rybchenko 		encp->enc_fw_assisted_tso_v2_encap_enabled = B_FALSE;
1139357c2ebbSAndrew Rybchenko 
114031bf5f03SAndrew Rybchenko 	/* Check if the firmware has vadapter/vport/vswitch support */
1141016941e3SAndrew Rybchenko 	if (CAP_FLAGS1(req, EVB))
1142016941e3SAndrew Rybchenko 		encp->enc_datapath_cap_evb = B_TRUE;
1143016941e3SAndrew Rybchenko 	else
1144016941e3SAndrew Rybchenko 		encp->enc_datapath_cap_evb = B_FALSE;
114531bf5f03SAndrew Rybchenko 
114631bf5f03SAndrew Rybchenko 	/* Check if the firmware supports VLAN insertion */
1147016941e3SAndrew Rybchenko 	if (CAP_FLAGS1(req, TX_VLAN_INSERTION))
1148016941e3SAndrew Rybchenko 		encp->enc_hw_tx_insert_vlan_enabled = B_TRUE;
1149016941e3SAndrew Rybchenko 	else
1150016941e3SAndrew Rybchenko 		encp->enc_hw_tx_insert_vlan_enabled = B_FALSE;
115131bf5f03SAndrew Rybchenko 
115231bf5f03SAndrew Rybchenko 	/* Check if the firmware supports RX event batching */
1153016941e3SAndrew Rybchenko 	if (CAP_FLAGS1(req, RX_BATCHING))
1154016941e3SAndrew Rybchenko 		encp->enc_rx_batching_enabled = B_TRUE;
1155016941e3SAndrew Rybchenko 	else
1156016941e3SAndrew Rybchenko 		encp->enc_rx_batching_enabled = B_FALSE;
115731bf5f03SAndrew Rybchenko 
1158095bde93SAndrew Rybchenko 	/*
1159095bde93SAndrew Rybchenko 	 * Even if batching isn't reported as supported, we may still get
1160095bde93SAndrew Rybchenko 	 * batched events.
1161095bde93SAndrew Rybchenko 	 */
116231bf5f03SAndrew Rybchenko 	encp->enc_rx_batch_max = 16;
116331bf5f03SAndrew Rybchenko 
116431bf5f03SAndrew Rybchenko 	/* Check if the firmware supports disabling scatter on RXQs */
1165016941e3SAndrew Rybchenko 	if (CAP_FLAGS1(req, RX_DISABLE_SCATTER))
1166016941e3SAndrew Rybchenko 		encp->enc_rx_disable_scatter_supported = B_TRUE;
1167016941e3SAndrew Rybchenko 	else
1168016941e3SAndrew Rybchenko 		encp->enc_rx_disable_scatter_supported = B_FALSE;
116931bf5f03SAndrew Rybchenko 
11708e0c4827SAndrew Rybchenko 	/* Check if the firmware supports packed stream mode */
1171016941e3SAndrew Rybchenko 	if (CAP_FLAGS1(req, RX_PACKED_STREAM))
1172016941e3SAndrew Rybchenko 		encp->enc_rx_packed_stream_supported = B_TRUE;
1173016941e3SAndrew Rybchenko 	else
1174016941e3SAndrew Rybchenko 		encp->enc_rx_packed_stream_supported = B_FALSE;
11758e0c4827SAndrew Rybchenko 
11768e0c4827SAndrew Rybchenko 	/*
11778e0c4827SAndrew Rybchenko 	 * Check if the firmware supports configurable buffer sizes
11788e0c4827SAndrew Rybchenko 	 * for packed stream mode (otherwise buffer size is 1Mbyte)
11798e0c4827SAndrew Rybchenko 	 */
1180016941e3SAndrew Rybchenko 	if (CAP_FLAGS1(req, RX_PACKED_STREAM_VAR_BUFFERS))
1181016941e3SAndrew Rybchenko 		encp->enc_rx_var_packed_stream_supported = B_TRUE;
1182016941e3SAndrew Rybchenko 	else
1183016941e3SAndrew Rybchenko 		encp->enc_rx_var_packed_stream_supported = B_FALSE;
11848e0c4827SAndrew Rybchenko 
1185ceeff9b1SAndrew Rybchenko 	/* Check if the firmware supports equal stride super-buffer mode */
1186ceeff9b1SAndrew Rybchenko 	if (CAP_FLAGS2(req, EQUAL_STRIDE_SUPER_BUFFER))
1187ceeff9b1SAndrew Rybchenko 		encp->enc_rx_es_super_buffer_supported = B_TRUE;
1188ceeff9b1SAndrew Rybchenko 	else
1189ceeff9b1SAndrew Rybchenko 		encp->enc_rx_es_super_buffer_supported = B_FALSE;
1190ceeff9b1SAndrew Rybchenko 
11913f8f5495SAndrew Rybchenko 	/* Check if the firmware supports FW subvariant w/o Tx checksumming */
11923f8f5495SAndrew Rybchenko 	if (CAP_FLAGS2(req, FW_SUBVARIANT_NO_TX_CSUM))
11933f8f5495SAndrew Rybchenko 		encp->enc_fw_subvariant_no_tx_csum_supported = B_TRUE;
11943f8f5495SAndrew Rybchenko 	else
11953f8f5495SAndrew Rybchenko 		encp->enc_fw_subvariant_no_tx_csum_supported = B_FALSE;
11963f8f5495SAndrew Rybchenko 
119731bf5f03SAndrew Rybchenko 	/* Check if the firmware supports set mac with running filters */
1198016941e3SAndrew Rybchenko 	if (CAP_FLAGS1(req, VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED))
1199016941e3SAndrew Rybchenko 		encp->enc_allow_set_mac_with_installed_filters = B_TRUE;
1200016941e3SAndrew Rybchenko 	else
1201016941e3SAndrew Rybchenko 		encp->enc_allow_set_mac_with_installed_filters = B_FALSE;
120231bf5f03SAndrew Rybchenko 
120331bf5f03SAndrew Rybchenko 	/*
120431bf5f03SAndrew Rybchenko 	 * Check if firmware supports the extended MC_CMD_SET_MAC, which allows
120531bf5f03SAndrew Rybchenko 	 * specifying which parameters to configure.
120631bf5f03SAndrew Rybchenko 	 */
1207016941e3SAndrew Rybchenko 	if (CAP_FLAGS1(req, SET_MAC_ENHANCED))
1208016941e3SAndrew Rybchenko 		encp->enc_enhanced_set_mac_supported = B_TRUE;
1209016941e3SAndrew Rybchenko 	else
1210016941e3SAndrew Rybchenko 		encp->enc_enhanced_set_mac_supported = B_FALSE;
121131bf5f03SAndrew Rybchenko 
1212995a3bf4SAndrew Rybchenko 	/*
1213995a3bf4SAndrew Rybchenko 	 * Check if firmware supports version 2 of MC_CMD_INIT_EVQ, which allows
1214995a3bf4SAndrew Rybchenko 	 * us to let the firmware choose the settings to use on an EVQ.
1215995a3bf4SAndrew Rybchenko 	 */
1216016941e3SAndrew Rybchenko 	if (CAP_FLAGS2(req, INIT_EVQ_V2))
1217016941e3SAndrew Rybchenko 		encp->enc_init_evq_v2_supported = B_TRUE;
1218016941e3SAndrew Rybchenko 	else
1219016941e3SAndrew Rybchenko 		encp->enc_init_evq_v2_supported = B_FALSE;
1220995a3bf4SAndrew Rybchenko 
122158a72cb2SAndrew Rybchenko 	/*
1222621cf621SAndrew Rybchenko 	 * Check if firmware-verified NVRAM updates must be used.
1223621cf621SAndrew Rybchenko 	 *
1224621cf621SAndrew Rybchenko 	 * The firmware trusted installer requires all NVRAM updates to use
1225621cf621SAndrew Rybchenko 	 * version 2 of MC_CMD_NVRAM_UPDATE_START (to enable verified update)
1226621cf621SAndrew Rybchenko 	 * and version 2 of MC_CMD_NVRAM_UPDATE_FINISH (to verify the updated
1227621cf621SAndrew Rybchenko 	 * partition and report the result).
1228621cf621SAndrew Rybchenko 	 */
1229016941e3SAndrew Rybchenko 	if (CAP_FLAGS2(req, NVRAM_UPDATE_REPORT_VERIFY_RESULT))
1230016941e3SAndrew Rybchenko 		encp->enc_nvram_update_verify_result_supported = B_TRUE;
1231016941e3SAndrew Rybchenko 	else
1232016941e3SAndrew Rybchenko 		encp->enc_nvram_update_verify_result_supported = B_FALSE;
1233621cf621SAndrew Rybchenko 
1234621cf621SAndrew Rybchenko 	/*
123558a72cb2SAndrew Rybchenko 	 * Check if firmware provides packet memory and Rx datapath
123658a72cb2SAndrew Rybchenko 	 * counters.
123758a72cb2SAndrew Rybchenko 	 */
1238016941e3SAndrew Rybchenko 	if (CAP_FLAGS1(req, PM_AND_RXDP_COUNTERS))
1239016941e3SAndrew Rybchenko 		encp->enc_pm_and_rxdp_counters = B_TRUE;
1240016941e3SAndrew Rybchenko 	else
1241016941e3SAndrew Rybchenko 		encp->enc_pm_and_rxdp_counters = B_FALSE;
124258a72cb2SAndrew Rybchenko 
124358a72cb2SAndrew Rybchenko 	/*
124458a72cb2SAndrew Rybchenko 	 * Check if the 40G MAC hardware is capable of reporting
124558a72cb2SAndrew Rybchenko 	 * statistics for Tx size bins.
124658a72cb2SAndrew Rybchenko 	 */
1247016941e3SAndrew Rybchenko 	if (CAP_FLAGS2(req, MAC_STATS_40G_TX_SIZE_BINS))
1248016941e3SAndrew Rybchenko 		encp->enc_mac_stats_40g_tx_size_bins = B_TRUE;
1249016941e3SAndrew Rybchenko 	else
1250016941e3SAndrew Rybchenko 		encp->enc_mac_stats_40g_tx_size_bins = B_FALSE;
125158a72cb2SAndrew Rybchenko 
1252799fadbeSAndrew Rybchenko 	/*
1253799fadbeSAndrew Rybchenko 	 * Check if firmware supports VXLAN and NVGRE tunnels.
1254799fadbeSAndrew Rybchenko 	 * The capability indicates Geneve protocol support as well.
1255799fadbeSAndrew Rybchenko 	 */
1256016941e3SAndrew Rybchenko 	if (CAP_FLAGS1(req, VXLAN_NVGRE)) {
1257799fadbeSAndrew Rybchenko 		encp->enc_tunnel_encapsulations_supported =
1258799fadbeSAndrew Rybchenko 		    (1u << EFX_TUNNEL_PROTOCOL_VXLAN) |
1259799fadbeSAndrew Rybchenko 		    (1u << EFX_TUNNEL_PROTOCOL_GENEVE) |
1260799fadbeSAndrew Rybchenko 		    (1u << EFX_TUNNEL_PROTOCOL_NVGRE);
1261799fadbeSAndrew Rybchenko 
1262fdbe38cfSAndrew Rybchenko 		EFX_STATIC_ASSERT(EFX_TUNNEL_MAXNENTRIES ==
1263fdbe38cfSAndrew Rybchenko 		    MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES_MAXNUM);
1264fdbe38cfSAndrew Rybchenko 		encp->enc_tunnel_config_udp_entries_max =
1265fdbe38cfSAndrew Rybchenko 		    EFX_TUNNEL_MAXNENTRIES;
1266fdbe38cfSAndrew Rybchenko 	} else {
1267fdbe38cfSAndrew Rybchenko 		encp->enc_tunnel_config_udp_entries_max = 0;
1268fdbe38cfSAndrew Rybchenko 	}
1269fdbe38cfSAndrew Rybchenko 
127076ecd4a3SAndrew Rybchenko 	/*
127176ecd4a3SAndrew Rybchenko 	 * Check if firmware reports the VI window mode.
127276ecd4a3SAndrew Rybchenko 	 * Medford2 has a variable VI window size (8K, 16K or 64K).
127376ecd4a3SAndrew Rybchenko 	 * Medford and Huntington have a fixed 8K VI window size.
127476ecd4a3SAndrew Rybchenko 	 */
127576ecd4a3SAndrew Rybchenko 	if (req.emr_out_length_used >= MC_CMD_GET_CAPABILITIES_V3_OUT_LEN) {
127676ecd4a3SAndrew Rybchenko 		uint8_t mode =
127776ecd4a3SAndrew Rybchenko 		    MCDI_OUT_BYTE(req, GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE);
127876ecd4a3SAndrew Rybchenko 
127976ecd4a3SAndrew Rybchenko 		switch (mode) {
128076ecd4a3SAndrew Rybchenko 		case MC_CMD_GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE_8K:
128176ecd4a3SAndrew Rybchenko 			encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_8K;
128276ecd4a3SAndrew Rybchenko 			break;
128376ecd4a3SAndrew Rybchenko 		case MC_CMD_GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE_16K:
128476ecd4a3SAndrew Rybchenko 			encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_16K;
128576ecd4a3SAndrew Rybchenko 			break;
128676ecd4a3SAndrew Rybchenko 		case MC_CMD_GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE_64K:
128776ecd4a3SAndrew Rybchenko 			encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_64K;
128876ecd4a3SAndrew Rybchenko 			break;
128976ecd4a3SAndrew Rybchenko 		default:
129076ecd4a3SAndrew Rybchenko 			encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_INVALID;
129176ecd4a3SAndrew Rybchenko 			break;
129276ecd4a3SAndrew Rybchenko 		}
129376ecd4a3SAndrew Rybchenko 	} else if ((enp->en_family == EFX_FAMILY_HUNTINGTON) ||
129476ecd4a3SAndrew Rybchenko 		    (enp->en_family == EFX_FAMILY_MEDFORD)) {
129576ecd4a3SAndrew Rybchenko 		/* Huntington and Medford have fixed 8K window size */
129676ecd4a3SAndrew Rybchenko 		encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_8K;
129776ecd4a3SAndrew Rybchenko 	} else {
129876ecd4a3SAndrew Rybchenko 		encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_INVALID;
129976ecd4a3SAndrew Rybchenko 	}
130076ecd4a3SAndrew Rybchenko 
1301807145d9SAndrew Rybchenko 	/* Check if firmware supports extended MAC stats. */
1302807145d9SAndrew Rybchenko 	if (req.emr_out_length_used >= MC_CMD_GET_CAPABILITIES_V4_OUT_LEN) {
1303807145d9SAndrew Rybchenko 		/* Extended stats buffer supported */
1304807145d9SAndrew Rybchenko 		encp->enc_mac_stats_nstats = MCDI_OUT_WORD(req,
1305807145d9SAndrew Rybchenko 		    GET_CAPABILITIES_V4_OUT_MAC_STATS_NUM_STATS);
1306807145d9SAndrew Rybchenko 	} else {
1307807145d9SAndrew Rybchenko 		/* Use Siena-compatible legacy MAC stats */
1308807145d9SAndrew Rybchenko 		encp->enc_mac_stats_nstats = MC_CMD_MAC_NSTATS;
1309807145d9SAndrew Rybchenko 	}
1310807145d9SAndrew Rybchenko 
1311747819d2SAndrew Rybchenko 	if (encp->enc_mac_stats_nstats >= MC_CMD_MAC_NSTATS_V2)
1312747819d2SAndrew Rybchenko 		encp->enc_fec_counters = B_TRUE;
1313747819d2SAndrew Rybchenko 	else
1314747819d2SAndrew Rybchenko 		encp->enc_fec_counters = B_FALSE;
1315747819d2SAndrew Rybchenko 
1316aea9d093SAndrew Rybchenko 	/* Check if the firmware provides head-of-line blocking counters */
1317aea9d093SAndrew Rybchenko 	if (CAP_FLAGS2(req, RXDP_HLB_IDLE))
1318aea9d093SAndrew Rybchenko 		encp->enc_hlb_counters = B_TRUE;
1319aea9d093SAndrew Rybchenko 	else
1320aea9d093SAndrew Rybchenko 		encp->enc_hlb_counters = B_FALSE;
1321aea9d093SAndrew Rybchenko 
13225a51b32eSAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
1323fcfb73b8SAndrew Rybchenko 	if (CAP_FLAGS1(req, RX_RSS_LIMITED)) {
1324fcfb73b8SAndrew Rybchenko 		/* Only one exclusive RSS context is available per port. */
1325fcfb73b8SAndrew Rybchenko 		encp->enc_rx_scale_max_exclusive_contexts = 1;
1326fcfb73b8SAndrew Rybchenko 
1327fcfb73b8SAndrew Rybchenko 		switch (enp->en_family) {
1328fcfb73b8SAndrew Rybchenko 		case EFX_FAMILY_MEDFORD2:
1329fcfb73b8SAndrew Rybchenko 			encp->enc_rx_scale_hash_alg_mask =
1330fcfb73b8SAndrew Rybchenko 			    (1U << EFX_RX_HASHALG_TOEPLITZ);
1331fcfb73b8SAndrew Rybchenko 			break;
1332fcfb73b8SAndrew Rybchenko 
1333fcfb73b8SAndrew Rybchenko 		case EFX_FAMILY_MEDFORD:
1334fcfb73b8SAndrew Rybchenko 		case EFX_FAMILY_HUNTINGTON:
1335fcfb73b8SAndrew Rybchenko 			/*
1336fcfb73b8SAndrew Rybchenko 			 * Packed stream firmware variant maintains a
1337fcfb73b8SAndrew Rybchenko 			 * non-standard algorithm for hash computation.
1338fcfb73b8SAndrew Rybchenko 			 * It implies explicit XORing together
1339fcfb73b8SAndrew Rybchenko 			 * source + destination IP addresses (or last
1340fcfb73b8SAndrew Rybchenko 			 * four bytes in the case of IPv6) and using the
1341fcfb73b8SAndrew Rybchenko 			 * resulting value as the input to a Toeplitz hash.
1342fcfb73b8SAndrew Rybchenko 			 */
1343fcfb73b8SAndrew Rybchenko 			encp->enc_rx_scale_hash_alg_mask =
1344fcfb73b8SAndrew Rybchenko 			    (1U << EFX_RX_HASHALG_PACKED_STREAM);
1345fcfb73b8SAndrew Rybchenko 			break;
1346fcfb73b8SAndrew Rybchenko 
1347fcfb73b8SAndrew Rybchenko 		default:
1348fcfb73b8SAndrew Rybchenko 			rc = EINVAL;
1349fcfb73b8SAndrew Rybchenko 			goto fail5;
1350fcfb73b8SAndrew Rybchenko 		}
1351fcfb73b8SAndrew Rybchenko 
1352fcfb73b8SAndrew Rybchenko 		/* Port numbers cannot contribute to the hash value */
1353fcfb73b8SAndrew Rybchenko 		encp->enc_rx_scale_l4_hash_supported = B_FALSE;
1354fcfb73b8SAndrew Rybchenko 	} else {
1355fcfb73b8SAndrew Rybchenko 		/*
1356fcfb73b8SAndrew Rybchenko 		 * Maximum number of exclusive RSS contexts.
1357fcfb73b8SAndrew Rybchenko 		 * EF10 hardware supports 64 in total, but 6 are reserved
1358fcfb73b8SAndrew Rybchenko 		 * for shared contexts. They are a global resource so
1359fcfb73b8SAndrew Rybchenko 		 * not all may be available.
1360fcfb73b8SAndrew Rybchenko 		 */
1361fcfb73b8SAndrew Rybchenko 		encp->enc_rx_scale_max_exclusive_contexts = 64 - 6;
1362fcfb73b8SAndrew Rybchenko 
1363fcfb73b8SAndrew Rybchenko 		encp->enc_rx_scale_hash_alg_mask =
1364fcfb73b8SAndrew Rybchenko 		    (1U << EFX_RX_HASHALG_TOEPLITZ);
1365fcfb73b8SAndrew Rybchenko 
1366fcfb73b8SAndrew Rybchenko 		/*
1367fcfb73b8SAndrew Rybchenko 		 * It is possible to use port numbers as
1368fcfb73b8SAndrew Rybchenko 		 * the input data for hash computation.
1369fcfb73b8SAndrew Rybchenko 		 */
1370fcfb73b8SAndrew Rybchenko 		encp->enc_rx_scale_l4_hash_supported = B_TRUE;
1371fcfb73b8SAndrew Rybchenko 	}
13725a51b32eSAndrew Rybchenko #endif /* EFSYS_OPT_RX_SCALE */
13735a51b32eSAndrew Rybchenko 
13746e1ebbe9SAndrew Rybchenko 	/* Check if the firmware supports "FLAG" and "MARK" filter actions */
13756e1ebbe9SAndrew Rybchenko 	if (CAP_FLAGS2(req, FILTER_ACTION_FLAG))
13766e1ebbe9SAndrew Rybchenko 		encp->enc_filter_action_flag_supported = B_TRUE;
13776e1ebbe9SAndrew Rybchenko 	else
13786e1ebbe9SAndrew Rybchenko 		encp->enc_filter_action_flag_supported = B_FALSE;
13796e1ebbe9SAndrew Rybchenko 
13806e1ebbe9SAndrew Rybchenko 	if (CAP_FLAGS2(req, FILTER_ACTION_MARK))
13816e1ebbe9SAndrew Rybchenko 		encp->enc_filter_action_mark_supported = B_TRUE;
13826e1ebbe9SAndrew Rybchenko 	else
13836e1ebbe9SAndrew Rybchenko 		encp->enc_filter_action_mark_supported = B_FALSE;
1384fcfb73b8SAndrew Rybchenko 
13855c2f9d6aSAndrew Rybchenko 	/* Get maximum supported value for "MARK" filter action */
13865c2f9d6aSAndrew Rybchenko 	if (req.emr_out_length_used >= MC_CMD_GET_CAPABILITIES_V5_OUT_LEN)
13875c2f9d6aSAndrew Rybchenko 		encp->enc_filter_action_mark_max = MCDI_OUT_DWORD(req,
13885c2f9d6aSAndrew Rybchenko 		    GET_CAPABILITIES_V5_OUT_FILTER_ACTION_MARK_MAX);
13895c2f9d6aSAndrew Rybchenko 	else
13905c2f9d6aSAndrew Rybchenko 		encp->enc_filter_action_mark_max = 0;
13915c2f9d6aSAndrew Rybchenko 
1392016941e3SAndrew Rybchenko #undef CAP_FLAGS1
1393016941e3SAndrew Rybchenko #undef CAP_FLAGS2
139431bf5f03SAndrew Rybchenko 
139531bf5f03SAndrew Rybchenko 	return (0);
139631bf5f03SAndrew Rybchenko 
13975a51b32eSAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
1398fcfb73b8SAndrew Rybchenko fail5:
1399fcfb73b8SAndrew Rybchenko 	EFSYS_PROBE(fail5);
14005a51b32eSAndrew Rybchenko #endif /* EFSYS_OPT_RX_SCALE */
1401016941e3SAndrew Rybchenko fail4:
1402016941e3SAndrew Rybchenko 	EFSYS_PROBE(fail4);
1403016941e3SAndrew Rybchenko fail3:
1404016941e3SAndrew Rybchenko 	EFSYS_PROBE(fail3);
140531bf5f03SAndrew Rybchenko fail2:
140631bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
140731bf5f03SAndrew Rybchenko fail1:
140831bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
140931bf5f03SAndrew Rybchenko 
141031bf5f03SAndrew Rybchenko 	return (rc);
141131bf5f03SAndrew Rybchenko }
141231bf5f03SAndrew Rybchenko 
1413d5bd0d6bSAndrew Rybchenko #define	EF10_LEGACY_PF_PRIVILEGE_MASK					\
1414d5bd0d6bSAndrew Rybchenko 	(MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN			|	\
1415d5bd0d6bSAndrew Rybchenko 	MC_CMD_PRIVILEGE_MASK_IN_GRP_LINK			|	\
1416d5bd0d6bSAndrew Rybchenko 	MC_CMD_PRIVILEGE_MASK_IN_GRP_ONLOAD			|	\
1417d5bd0d6bSAndrew Rybchenko 	MC_CMD_PRIVILEGE_MASK_IN_GRP_PTP			|	\
1418d5bd0d6bSAndrew Rybchenko 	MC_CMD_PRIVILEGE_MASK_IN_GRP_INSECURE_FILTERS		|	\
1419d5bd0d6bSAndrew Rybchenko 	MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING		|	\
1420d5bd0d6bSAndrew Rybchenko 	MC_CMD_PRIVILEGE_MASK_IN_GRP_UNICAST			|	\
1421d5bd0d6bSAndrew Rybchenko 	MC_CMD_PRIVILEGE_MASK_IN_GRP_MULTICAST			|	\
1422d5bd0d6bSAndrew Rybchenko 	MC_CMD_PRIVILEGE_MASK_IN_GRP_BROADCAST			|	\
1423d5bd0d6bSAndrew Rybchenko 	MC_CMD_PRIVILEGE_MASK_IN_GRP_ALL_MULTICAST		|	\
1424d5bd0d6bSAndrew Rybchenko 	MC_CMD_PRIVILEGE_MASK_IN_GRP_PROMISCUOUS)
1425d5bd0d6bSAndrew Rybchenko 
1426d5bd0d6bSAndrew Rybchenko #define	EF10_LEGACY_VF_PRIVILEGE_MASK	0
1427d5bd0d6bSAndrew Rybchenko 
142831bf5f03SAndrew Rybchenko 	__checkReturn		efx_rc_t
ef10_get_privilege_mask(__in efx_nic_t * enp,__out uint32_t * maskp)142931bf5f03SAndrew Rybchenko ef10_get_privilege_mask(
143031bf5f03SAndrew Rybchenko 	__in			efx_nic_t *enp,
143131bf5f03SAndrew Rybchenko 	__out			uint32_t *maskp)
143231bf5f03SAndrew Rybchenko {
143331bf5f03SAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
143431bf5f03SAndrew Rybchenko 	uint32_t mask;
143531bf5f03SAndrew Rybchenko 	efx_rc_t rc;
143631bf5f03SAndrew Rybchenko 
143731bf5f03SAndrew Rybchenko 	if ((rc = efx_mcdi_privilege_mask(enp, encp->enc_pf, encp->enc_vf,
143831bf5f03SAndrew Rybchenko 					    &mask)) != 0) {
143931bf5f03SAndrew Rybchenko 		if (rc != ENOTSUP)
144031bf5f03SAndrew Rybchenko 			goto fail1;
144131bf5f03SAndrew Rybchenko 
144231bf5f03SAndrew Rybchenko 		/* Fallback for old firmware without privilege mask support */
144331bf5f03SAndrew Rybchenko 		if (EFX_PCI_FUNCTION_IS_PF(encp)) {
144431bf5f03SAndrew Rybchenko 			/* Assume PF has admin privilege */
144531bf5f03SAndrew Rybchenko 			mask = EF10_LEGACY_PF_PRIVILEGE_MASK;
144631bf5f03SAndrew Rybchenko 		} else {
144731bf5f03SAndrew Rybchenko 			/* VF is always unprivileged by default */
144831bf5f03SAndrew Rybchenko 			mask = EF10_LEGACY_VF_PRIVILEGE_MASK;
144931bf5f03SAndrew Rybchenko 		}
145031bf5f03SAndrew Rybchenko 	}
145131bf5f03SAndrew Rybchenko 
145231bf5f03SAndrew Rybchenko 	*maskp = mask;
145331bf5f03SAndrew Rybchenko 
145431bf5f03SAndrew Rybchenko 	return (0);
145531bf5f03SAndrew Rybchenko 
145631bf5f03SAndrew Rybchenko fail1:
145731bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
145831bf5f03SAndrew Rybchenko 
145931bf5f03SAndrew Rybchenko 	return (rc);
146031bf5f03SAndrew Rybchenko }
146131bf5f03SAndrew Rybchenko 
1462*f0a2945dSAndrew Rybchenko #define	EFX_EXT_PORT_MAX	4
1463*f0a2945dSAndrew Rybchenko #define	EFX_EXT_PORT_NA		0xFF
1464*f0a2945dSAndrew Rybchenko 
146531bf5f03SAndrew Rybchenko /*
14668da3f86bSAndrew Rybchenko  * Table of mapping schemes from port number to external number.
1467b36a7ad2SAndrew Rybchenko  *
14688da3f86bSAndrew Rybchenko  * Each port number ultimately corresponds to a connector: either as part of
14698da3f86bSAndrew Rybchenko  * a cable assembly attached to a module inserted in an SFP+/QSFP+ cage on
14708da3f86bSAndrew Rybchenko  * the board, or fixed to the board (e.g. 10GBASE-T magjack on SFN5121T
14718da3f86bSAndrew Rybchenko  * "Salina"). In general:
14728da3f86bSAndrew Rybchenko  *
14738da3f86bSAndrew Rybchenko  * Port number (0-based)
14748da3f86bSAndrew Rybchenko  *     |
14758da3f86bSAndrew Rybchenko  *   port mapping (n:1)
14768da3f86bSAndrew Rybchenko  *     |
14778da3f86bSAndrew Rybchenko  *     v
1478*f0a2945dSAndrew Rybchenko  * External port number (1-based)
14798da3f86bSAndrew Rybchenko  *     |
14808da3f86bSAndrew Rybchenko  *   fixed (1:1) or cable assembly (1:m)
14818da3f86bSAndrew Rybchenko  *     |
14828da3f86bSAndrew Rybchenko  *     v
14838da3f86bSAndrew Rybchenko  * Connector
14848da3f86bSAndrew Rybchenko  *
14858da3f86bSAndrew Rybchenko  * The external numbering refers to the cages or magjacks on the board,
14868da3f86bSAndrew Rybchenko  * as visibly annotated on the board or back panel. This table describes
14878da3f86bSAndrew Rybchenko  * how to determine which external cage/magjack corresponds to the port
14888da3f86bSAndrew Rybchenko  * numbers used by the driver.
14898da3f86bSAndrew Rybchenko  *
1490*f0a2945dSAndrew Rybchenko  * The count of consecutive port numbers that map to each external number,
1491*f0a2945dSAndrew Rybchenko  * is determined by the chip family and the current port mode.
1492b36a7ad2SAndrew Rybchenko  *
1493b36a7ad2SAndrew Rybchenko  * For the Huntington family, the current port mode cannot be discovered,
14948da3f86bSAndrew Rybchenko  * but a single mapping is used by all modes for a given chip variant,
1495b36a7ad2SAndrew Rybchenko  * so the mapping used is instead the last match in the table to the full
1496b36a7ad2SAndrew Rybchenko  * set of port modes to which the NIC can be configured. Therefore the
14978da3f86bSAndrew Rybchenko  * ordering of entries in the mapping table is significant.
149831bf5f03SAndrew Rybchenko  */
14998da3f86bSAndrew Rybchenko static struct ef10_external_port_map_s {
150031bf5f03SAndrew Rybchenko 	efx_family_t	family;
150131bf5f03SAndrew Rybchenko 	uint32_t	modes_mask;
1502*f0a2945dSAndrew Rybchenko 	uint8_t		base_port[EFX_EXT_PORT_MAX];
150331bf5f03SAndrew Rybchenko }	__ef10_external_port_mappings[] = {
15048da3f86bSAndrew Rybchenko 	/*
15058da3f86bSAndrew Rybchenko 	 * Modes used by Huntington family controllers where each port
15068da3f86bSAndrew Rybchenko 	 * number maps to a separate cage.
15078da3f86bSAndrew Rybchenko 	 * SFN7x22F (Torino):
15088da3f86bSAndrew Rybchenko 	 *	port 0 -> cage 1
15098da3f86bSAndrew Rybchenko 	 *	port 1 -> cage 2
15108da3f86bSAndrew Rybchenko 	 * SFN7xx4F (Pavia):
15118da3f86bSAndrew Rybchenko 	 *	port 0 -> cage 1
15128da3f86bSAndrew Rybchenko 	 *	port 1 -> cage 2
15138da3f86bSAndrew Rybchenko 	 *	port 2 -> cage 3
15148da3f86bSAndrew Rybchenko 	 *	port 3 -> cage 4
15158da3f86bSAndrew Rybchenko 	 */
151631bf5f03SAndrew Rybchenko 	{
151731bf5f03SAndrew Rybchenko 		EFX_FAMILY_HUNTINGTON,
1518b14569a4SAndrew Rybchenko 		(1U << TLV_PORT_MODE_10G) |			/* mode 0 */
1519b14569a4SAndrew Rybchenko 		(1U << TLV_PORT_MODE_10G_10G) |			/* mode 2 */
1520b14569a4SAndrew Rybchenko 		(1U << TLV_PORT_MODE_10G_10G_10G_10G),		/* mode 4 */
1521*f0a2945dSAndrew Rybchenko 		{ 0, 1, 2, 3 }
152231bf5f03SAndrew Rybchenko 	},
15238da3f86bSAndrew Rybchenko 	/*
15248da3f86bSAndrew Rybchenko 	 * Modes which for Huntington identify a chip variant where 2
15258da3f86bSAndrew Rybchenko 	 * adjacent port numbers map to each cage.
15268da3f86bSAndrew Rybchenko 	 * SFN7x42Q (Monza):
15278da3f86bSAndrew Rybchenko 	 *	port 0 -> cage 1
15288da3f86bSAndrew Rybchenko 	 *	port 1 -> cage 1
15298da3f86bSAndrew Rybchenko 	 *	port 2 -> cage 2
15308da3f86bSAndrew Rybchenko 	 *	port 3 -> cage 2
15318da3f86bSAndrew Rybchenko 	 */
153231bf5f03SAndrew Rybchenko 	{
153331bf5f03SAndrew Rybchenko 		EFX_FAMILY_HUNTINGTON,
1534b14569a4SAndrew Rybchenko 		(1U << TLV_PORT_MODE_40G) |			/* mode 1 */
1535b14569a4SAndrew Rybchenko 		(1U << TLV_PORT_MODE_40G_40G) |			/* mode 3 */
1536b14569a4SAndrew Rybchenko 		(1U << TLV_PORT_MODE_40G_10G_10G) |		/* mode 6 */
1537b14569a4SAndrew Rybchenko 		(1U << TLV_PORT_MODE_10G_10G_40G),		/* mode 7 */
1538*f0a2945dSAndrew Rybchenko 		{ 0, 2, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA }
153931bf5f03SAndrew Rybchenko 	},
15408da3f86bSAndrew Rybchenko 	/*
1541259a7b37SAndrew Rybchenko 	 * Modes that on Medford allocate each port number to a separate
1542259a7b37SAndrew Rybchenko 	 * cage.
1543259a7b37SAndrew Rybchenko 	 *	port 0 -> cage 1
1544259a7b37SAndrew Rybchenko 	 *	port 1 -> cage 2
1545259a7b37SAndrew Rybchenko 	 *	port 2 -> cage 3
1546259a7b37SAndrew Rybchenko 	 *	port 3 -> cage 4
1547259a7b37SAndrew Rybchenko 	 */
1548259a7b37SAndrew Rybchenko 	{
1549259a7b37SAndrew Rybchenko 		EFX_FAMILY_MEDFORD,
1550e12a751bSAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x1_NA) |			/* mode 0 */
1551e12a751bSAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x1_1x1),			/* mode 2 */
1552*f0a2945dSAndrew Rybchenko 		{ 0, 1, 2, 3 }
1553259a7b37SAndrew Rybchenko 	},
1554259a7b37SAndrew Rybchenko 	/*
15558da3f86bSAndrew Rybchenko 	 * Modes that on Medford allocate 2 adjacent port numbers to each
15568da3f86bSAndrew Rybchenko 	 * cage.
15578da3f86bSAndrew Rybchenko 	 *	port 0 -> cage 1
15588da3f86bSAndrew Rybchenko 	 *	port 1 -> cage 1
15598da3f86bSAndrew Rybchenko 	 *	port 2 -> cage 2
15608da3f86bSAndrew Rybchenko 	 *	port 3 -> cage 2
15618da3f86bSAndrew Rybchenko 	 */
156231bf5f03SAndrew Rybchenko 	{
156331bf5f03SAndrew Rybchenko 		EFX_FAMILY_MEDFORD,
1564e12a751bSAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x4_NA) |			/* mode 1 */
1565e12a751bSAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x4_1x4) |			/* mode 3 */
1566e12a751bSAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x4_2x1) |			/* mode 6 */
1567e12a751bSAndrew Rybchenko 		(1U << TLV_PORT_MODE_2x1_1x4) |			/* mode 7 */
1568b14569a4SAndrew Rybchenko 		/* Do not use 10G_10G_10G_10G_Q1_Q2 (see bug63270) */
1569b14569a4SAndrew Rybchenko 		(1U << TLV_PORT_MODE_10G_10G_10G_10G_Q1_Q2),	/* mode 9 */
1570*f0a2945dSAndrew Rybchenko 		{ 0, 2, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA }
157131bf5f03SAndrew Rybchenko 	},
15728da3f86bSAndrew Rybchenko 	/*
15738da3f86bSAndrew Rybchenko 	 * Modes that on Medford allocate 4 adjacent port numbers to each
15748da3f86bSAndrew Rybchenko 	 * connector, starting on cage 1.
15758da3f86bSAndrew Rybchenko 	 *	port 0 -> cage 1
15768da3f86bSAndrew Rybchenko 	 *	port 1 -> cage 1
15778da3f86bSAndrew Rybchenko 	 *	port 2 -> cage 1
15788da3f86bSAndrew Rybchenko 	 *	port 3 -> cage 1
15798da3f86bSAndrew Rybchenko 	 */
158031bf5f03SAndrew Rybchenko 	{
158131bf5f03SAndrew Rybchenko 		EFX_FAMILY_MEDFORD,
1582e12a751bSAndrew Rybchenko 		(1U << TLV_PORT_MODE_2x1_2x1) |			/* mode 5 */
1583b14569a4SAndrew Rybchenko 		/* Do not use 10G_10G_10G_10G_Q1 (see bug63270) */
1584e12a751bSAndrew Rybchenko 		(1U << TLV_PORT_MODE_4x1_NA),			/* mode 4 */
1585*f0a2945dSAndrew Rybchenko 		{ 0, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA }
1586b36a7ad2SAndrew Rybchenko 	},
15878da3f86bSAndrew Rybchenko 	/*
15888da3f86bSAndrew Rybchenko 	 * Modes that on Medford allocate 4 adjacent port numbers to each
15898da3f86bSAndrew Rybchenko 	 * connector, starting on cage 2.
15908da3f86bSAndrew Rybchenko 	 *	port 0 -> cage 2
15918da3f86bSAndrew Rybchenko 	 *	port 1 -> cage 2
15928da3f86bSAndrew Rybchenko 	 *	port 2 -> cage 2
15938da3f86bSAndrew Rybchenko 	 *	port 3 -> cage 2
15948da3f86bSAndrew Rybchenko 	 */
1595b36a7ad2SAndrew Rybchenko 	{
1596b36a7ad2SAndrew Rybchenko 		EFX_FAMILY_MEDFORD,
1597e12a751bSAndrew Rybchenko 		(1U << TLV_PORT_MODE_NA_4x1),			/* mode 8 */
1598*f0a2945dSAndrew Rybchenko 		{ EFX_EXT_PORT_NA, 0, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA }
159931bf5f03SAndrew Rybchenko 	},
1600f83ec516SAndrew Rybchenko 	/*
1601f83ec516SAndrew Rybchenko 	 * Modes that on Medford2 allocate each port number to a separate
1602f83ec516SAndrew Rybchenko 	 * cage.
1603f83ec516SAndrew Rybchenko 	 *	port 0 -> cage 1
1604f83ec516SAndrew Rybchenko 	 *	port 1 -> cage 2
1605f83ec516SAndrew Rybchenko 	 *	port 2 -> cage 3
1606f83ec516SAndrew Rybchenko 	 *	port 3 -> cage 4
1607f83ec516SAndrew Rybchenko 	 */
1608f83ec516SAndrew Rybchenko 	{
1609f83ec516SAndrew Rybchenko 		EFX_FAMILY_MEDFORD2,
1610f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x1_NA) |			/* mode 0 */
1611f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x4_NA) |			/* mode 1 */
1612f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x1_1x1) |			/* mode 2 */
1613f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x2_NA) |			/* mode 10 */
1614f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x2_1x2) |			/* mode 12 */
1615f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x4_1x2) |			/* mode 15 */
1616f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x2_1x4),			/* mode 16 */
1617*f0a2945dSAndrew Rybchenko 		{ 0, 1, 2, 3 }
1618f83ec516SAndrew Rybchenko 	},
1619f83ec516SAndrew Rybchenko 	/*
1620*f0a2945dSAndrew Rybchenko 	 * Modes that on Medford2 allocate 1 port to cage 1 and the rest
1621*f0a2945dSAndrew Rybchenko 	 * to cage 2.
1622f83ec516SAndrew Rybchenko 	 *	port 0 -> cage 1
1623f83ec516SAndrew Rybchenko 	 *	port 1 -> cage 2
1624f83ec516SAndrew Rybchenko 	 *	port 2 -> cage 2
1625f83ec516SAndrew Rybchenko 	 */
1626*f0a2945dSAndrew Rybchenko 	{
1627*f0a2945dSAndrew Rybchenko 		EFX_FAMILY_MEDFORD2,
1628*f0a2945dSAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x2_2x1) |			/* mode 17 */
1629*f0a2945dSAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x4_2x1),			/* mode 6 */
1630*f0a2945dSAndrew Rybchenko 		{ 0, 1, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA }
1631*f0a2945dSAndrew Rybchenko 	},
1632f83ec516SAndrew Rybchenko 	/*
1633f83ec516SAndrew Rybchenko 	 * Modes that on Medford2 allocate 2 adjacent port numbers to each
1634f83ec516SAndrew Rybchenko 	 * cage, starting on cage 1.
1635f83ec516SAndrew Rybchenko 	 *	port 0 -> cage 1
1636f83ec516SAndrew Rybchenko 	 *	port 1 -> cage 1
1637f83ec516SAndrew Rybchenko 	 *	port 2 -> cage 2
1638f83ec516SAndrew Rybchenko 	 *	port 3 -> cage 2
1639f83ec516SAndrew Rybchenko 	 */
1640f83ec516SAndrew Rybchenko 	{
1641f83ec516SAndrew Rybchenko 		EFX_FAMILY_MEDFORD2,
1642f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x4_1x4) |			/* mode 3 */
1643f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_2x1_2x1) |			/* mode 4 */
1644f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_1x4_2x1) |			/* mode 6 */
1645f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_2x1_1x4) |			/* mode 7 */
1646f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_2x2_NA) |			/* mode 13 */
1647f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_2x1_1x2),			/* mode 18 */
1648*f0a2945dSAndrew Rybchenko 		{ 0, 2, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA }
1649f83ec516SAndrew Rybchenko 	},
1650f83ec516SAndrew Rybchenko 	/*
1651f83ec516SAndrew Rybchenko 	 * Modes that on Medford2 allocate 2 adjacent port numbers to each
1652f83ec516SAndrew Rybchenko 	 * cage, starting on cage 2.
1653f83ec516SAndrew Rybchenko 	 *	port 0 -> cage 2
1654f83ec516SAndrew Rybchenko 	 *	port 1 -> cage 2
1655f83ec516SAndrew Rybchenko 	 */
1656f83ec516SAndrew Rybchenko 	{
1657f83ec516SAndrew Rybchenko 		EFX_FAMILY_MEDFORD2,
1658f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_NA_2x2),			/* mode 14 */
1659*f0a2945dSAndrew Rybchenko 		{ EFX_EXT_PORT_NA, 0, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA }
1660f83ec516SAndrew Rybchenko 	},
1661f83ec516SAndrew Rybchenko 	/*
1662f83ec516SAndrew Rybchenko 	 * Modes that on Medford2 allocate 4 adjacent port numbers to each
1663f83ec516SAndrew Rybchenko 	 * connector, starting on cage 1.
1664f83ec516SAndrew Rybchenko 	 *	port 0 -> cage 1
1665f83ec516SAndrew Rybchenko 	 *	port 1 -> cage 1
1666f83ec516SAndrew Rybchenko 	 *	port 2 -> cage 1
1667f83ec516SAndrew Rybchenko 	 *	port 3 -> cage 1
1668f83ec516SAndrew Rybchenko 	 */
1669f83ec516SAndrew Rybchenko 	{
1670f83ec516SAndrew Rybchenko 		EFX_FAMILY_MEDFORD2,
1671f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_4x1_NA),			/* mode 5 */
1672*f0a2945dSAndrew Rybchenko 		{ 0, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA }
1673f83ec516SAndrew Rybchenko 	},
1674f83ec516SAndrew Rybchenko 	/*
1675f83ec516SAndrew Rybchenko 	 * Modes that on Medford2 allocate 4 adjacent port numbers to each
1676f83ec516SAndrew Rybchenko 	 * connector, starting on cage 2.
1677f83ec516SAndrew Rybchenko 	 *	port 0 -> cage 2
1678f83ec516SAndrew Rybchenko 	 *	port 1 -> cage 2
1679f83ec516SAndrew Rybchenko 	 *	port 2 -> cage 2
1680f83ec516SAndrew Rybchenko 	 *	port 3 -> cage 2
1681f83ec516SAndrew Rybchenko 	 */
1682f83ec516SAndrew Rybchenko 	{
1683f83ec516SAndrew Rybchenko 		EFX_FAMILY_MEDFORD2,
1684f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_NA_4x1) |			/* mode 8 */
1685f83ec516SAndrew Rybchenko 		(1U << TLV_PORT_MODE_NA_1x2),			/* mode 11 */
1686*f0a2945dSAndrew Rybchenko 		{ EFX_EXT_PORT_NA, 0, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA }
1687f83ec516SAndrew Rybchenko 	},
168831bf5f03SAndrew Rybchenko };
168931bf5f03SAndrew Rybchenko 
169009eac957SAndrew Rybchenko static	__checkReturn	efx_rc_t
ef10_external_port_mapping(__in efx_nic_t * enp,__in uint32_t port,__out uint8_t * external_portp)169131bf5f03SAndrew Rybchenko ef10_external_port_mapping(
169231bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
169331bf5f03SAndrew Rybchenko 	__in		uint32_t port,
169431bf5f03SAndrew Rybchenko 	__out		uint8_t *external_portp)
169531bf5f03SAndrew Rybchenko {
169631bf5f03SAndrew Rybchenko 	efx_rc_t rc;
169731bf5f03SAndrew Rybchenko 	int i;
169831bf5f03SAndrew Rybchenko 	uint32_t port_modes;
169931bf5f03SAndrew Rybchenko 	uint32_t matches;
1700b36a7ad2SAndrew Rybchenko 	uint32_t current;
1701*f0a2945dSAndrew Rybchenko 	struct ef10_external_port_map_s *mapp = NULL;
1702*f0a2945dSAndrew Rybchenko 	int ext_index = port; /* Default 1-1 mapping */
170331bf5f03SAndrew Rybchenko 
1704cd5e3371SAndrew Rybchenko 	if ((rc = efx_mcdi_get_port_modes(enp, &port_modes, &current,
1705cd5e3371SAndrew Rybchenko 		    NULL)) != 0) {
1706b36a7ad2SAndrew Rybchenko 		/*
17078da3f86bSAndrew Rybchenko 		 * No current port mode information (i.e. Huntington)
1708b36a7ad2SAndrew Rybchenko 		 * - infer mapping from available modes
1709b36a7ad2SAndrew Rybchenko 		 */
1710b36a7ad2SAndrew Rybchenko 		if ((rc = efx_mcdi_get_port_modes(enp,
1711cd5e3371SAndrew Rybchenko 			    &port_modes, NULL, NULL)) != 0) {
1712b36a7ad2SAndrew Rybchenko 			/*
1713b36a7ad2SAndrew Rybchenko 			 * No port mode information available
1714b36a7ad2SAndrew Rybchenko 			 * - use default mapping
1715b36a7ad2SAndrew Rybchenko 			 */
171631bf5f03SAndrew Rybchenko 			goto out;
171731bf5f03SAndrew Rybchenko 		}
1718b36a7ad2SAndrew Rybchenko 	} else {
1719b36a7ad2SAndrew Rybchenko 		/* Only need to scan the current mode */
1720b36a7ad2SAndrew Rybchenko 		port_modes = 1 << current;
1721b36a7ad2SAndrew Rybchenko 	}
172231bf5f03SAndrew Rybchenko 
172331bf5f03SAndrew Rybchenko 	/*
17248da3f86bSAndrew Rybchenko 	 * Infer the internal port -> external number mapping from
172531bf5f03SAndrew Rybchenko 	 * the possible port modes for this NIC.
172631bf5f03SAndrew Rybchenko 	 */
172731bf5f03SAndrew Rybchenko 	for (i = 0; i < EFX_ARRAY_SIZE(__ef10_external_port_mappings); ++i) {
17288da3f86bSAndrew Rybchenko 		struct ef10_external_port_map_s *eepmp =
17298da3f86bSAndrew Rybchenko 		    &__ef10_external_port_mappings[i];
17308da3f86bSAndrew Rybchenko 		if (eepmp->family != enp->en_family)
173131bf5f03SAndrew Rybchenko 			continue;
17328da3f86bSAndrew Rybchenko 		matches = (eepmp->modes_mask & port_modes);
173331bf5f03SAndrew Rybchenko 		if (matches != 0) {
17348da3f86bSAndrew Rybchenko 			/*
17358da3f86bSAndrew Rybchenko 			 * Some modes match. For some Huntington boards
17368da3f86bSAndrew Rybchenko 			 * there will be multiple matches. The mapping on the
17378da3f86bSAndrew Rybchenko 			 * last match is used.
17388da3f86bSAndrew Rybchenko 			 */
1739*f0a2945dSAndrew Rybchenko 			mapp = eepmp;
174031bf5f03SAndrew Rybchenko 			port_modes &= ~matches;
174131bf5f03SAndrew Rybchenko 		}
174231bf5f03SAndrew Rybchenko 	}
174331bf5f03SAndrew Rybchenko 
174431bf5f03SAndrew Rybchenko 	if (port_modes != 0) {
174531bf5f03SAndrew Rybchenko 		/* Some advertised modes are not supported */
174631bf5f03SAndrew Rybchenko 		rc = ENOTSUP;
174731bf5f03SAndrew Rybchenko 		goto fail1;
174831bf5f03SAndrew Rybchenko 	}
174931bf5f03SAndrew Rybchenko 
175031bf5f03SAndrew Rybchenko out:
1751*f0a2945dSAndrew Rybchenko 	if (mapp != NULL) {
175231bf5f03SAndrew Rybchenko 		/*
1753*f0a2945dSAndrew Rybchenko 		 * External ports are assigned a sequence of consecutive
1754*f0a2945dSAndrew Rybchenko 		 * port numbers, so find the one with the closest base_port.
175531bf5f03SAndrew Rybchenko 		 */
1756*f0a2945dSAndrew Rybchenko 		uint32_t delta = EFX_EXT_PORT_NA;
1757*f0a2945dSAndrew Rybchenko 
1758*f0a2945dSAndrew Rybchenko 		for (i = 0; i < EFX_EXT_PORT_MAX; i++) {
1759*f0a2945dSAndrew Rybchenko 			uint32_t base = mapp->base_port[i];
1760*f0a2945dSAndrew Rybchenko 			if ((base != EFX_EXT_PORT_NA) && (base <= port)) {
1761*f0a2945dSAndrew Rybchenko 				if ((port - base) < delta) {
1762*f0a2945dSAndrew Rybchenko 					delta = (port - base);
1763*f0a2945dSAndrew Rybchenko 					ext_index = i;
1764*f0a2945dSAndrew Rybchenko 				}
1765*f0a2945dSAndrew Rybchenko 			}
1766*f0a2945dSAndrew Rybchenko 		}
1767*f0a2945dSAndrew Rybchenko 	}
1768*f0a2945dSAndrew Rybchenko 	*external_portp = (uint8_t)(ext_index + 1);
1769*f0a2945dSAndrew Rybchenko 
177031bf5f03SAndrew Rybchenko 	return (0);
177131bf5f03SAndrew Rybchenko 
177231bf5f03SAndrew Rybchenko fail1:
177331bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
177431bf5f03SAndrew Rybchenko 
177531bf5f03SAndrew Rybchenko 	return (rc);
177631bf5f03SAndrew Rybchenko }
177731bf5f03SAndrew Rybchenko 
177848194339SAndrew Rybchenko static	__checkReturn	efx_rc_t
ef10_nic_board_cfg(__in efx_nic_t * enp)177948194339SAndrew Rybchenko ef10_nic_board_cfg(
178048194339SAndrew Rybchenko 	__in		efx_nic_t *enp)
178148194339SAndrew Rybchenko {
178248194339SAndrew Rybchenko 	const efx_nic_ops_t *enop = enp->en_enop;
178309eac957SAndrew Rybchenko 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
178409eac957SAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1785e5f6f32fSAndrew Rybchenko 	ef10_link_state_t els;
1786e5f6f32fSAndrew Rybchenko 	efx_port_t *epp = &(enp->en_port);
1787233c1e5eSAndrew Rybchenko 	uint32_t board_type = 0;
178861e0c16dSAndrew Rybchenko 	uint32_t base, nvec;
178909eac957SAndrew Rybchenko 	uint32_t port;
179026fcca57SAndrew Rybchenko 	uint32_t mask;
179117f272e7SAndrew Rybchenko 	uint32_t pf;
179217f272e7SAndrew Rybchenko 	uint32_t vf;
1793d36ea92cSAndrew Rybchenko 	uint8_t mac_addr[6] = { 0 };
179448194339SAndrew Rybchenko 	efx_rc_t rc;
179548194339SAndrew Rybchenko 
179609eac957SAndrew Rybchenko 	/* Get the (zero-based) MCDI port number */
179709eac957SAndrew Rybchenko 	if ((rc = efx_mcdi_get_port_assignment(enp, &port)) != 0)
179809eac957SAndrew Rybchenko 		goto fail1;
179909eac957SAndrew Rybchenko 
180009eac957SAndrew Rybchenko 	/* EFX MCDI interface uses one-based port numbers */
180109eac957SAndrew Rybchenko 	emip->emi_port = port + 1;
180209eac957SAndrew Rybchenko 
180309eac957SAndrew Rybchenko 	if ((rc = ef10_external_port_mapping(enp, port,
180409eac957SAndrew Rybchenko 		    &encp->enc_external_port)) != 0)
180509eac957SAndrew Rybchenko 		goto fail2;
180609eac957SAndrew Rybchenko 
180717f272e7SAndrew Rybchenko 	/*
180817f272e7SAndrew Rybchenko 	 * Get PCIe function number from firmware (used for
180917f272e7SAndrew Rybchenko 	 * per-function privilege and dynamic config info).
181017f272e7SAndrew Rybchenko 	 *  - PCIe PF: pf = PF number, vf = 0xffff.
181117f272e7SAndrew Rybchenko 	 *  - PCIe VF: pf = parent PF, vf = VF number.
181217f272e7SAndrew Rybchenko 	 */
181317f272e7SAndrew Rybchenko 	if ((rc = efx_mcdi_get_function_info(enp, &pf, &vf)) != 0)
181417f272e7SAndrew Rybchenko 		goto fail3;
181517f272e7SAndrew Rybchenko 
181617f272e7SAndrew Rybchenko 	encp->enc_pf = pf;
181717f272e7SAndrew Rybchenko 	encp->enc_vf = vf;
181817f272e7SAndrew Rybchenko 
1819d36ea92cSAndrew Rybchenko 	/* MAC address for this function */
1820d36ea92cSAndrew Rybchenko 	if (EFX_PCI_FUNCTION_IS_PF(encp)) {
1821d36ea92cSAndrew Rybchenko 		rc = efx_mcdi_get_mac_address_pf(enp, mac_addr);
1822d36ea92cSAndrew Rybchenko #if EFSYS_OPT_ALLOW_UNCONFIGURED_NIC
1823d36ea92cSAndrew Rybchenko 		/*
1824d36ea92cSAndrew Rybchenko 		 * Disable static config checking, ONLY for manufacturing test
1825d36ea92cSAndrew Rybchenko 		 * and setup at the factory, to allow the static config to be
1826d36ea92cSAndrew Rybchenko 		 * installed.
1827d36ea92cSAndrew Rybchenko 		 */
1828d36ea92cSAndrew Rybchenko #else /* EFSYS_OPT_ALLOW_UNCONFIGURED_NIC */
1829d36ea92cSAndrew Rybchenko 		if ((rc == 0) && (mac_addr[0] & 0x02)) {
1830d36ea92cSAndrew Rybchenko 			/*
1831d36ea92cSAndrew Rybchenko 			 * If the static config does not include a global MAC
1832d36ea92cSAndrew Rybchenko 			 * address pool then the board may return a locally
1833d36ea92cSAndrew Rybchenko 			 * administered MAC address (this should only happen on
1834d36ea92cSAndrew Rybchenko 			 * incorrectly programmed boards).
1835d36ea92cSAndrew Rybchenko 			 */
1836d36ea92cSAndrew Rybchenko 			rc = EINVAL;
1837d36ea92cSAndrew Rybchenko 		}
1838d36ea92cSAndrew Rybchenko #endif /* EFSYS_OPT_ALLOW_UNCONFIGURED_NIC */
1839d36ea92cSAndrew Rybchenko 	} else {
1840d36ea92cSAndrew Rybchenko 		rc = efx_mcdi_get_mac_address_vf(enp, mac_addr);
1841d36ea92cSAndrew Rybchenko 	}
1842d36ea92cSAndrew Rybchenko 	if (rc != 0)
1843d36ea92cSAndrew Rybchenko 		goto fail4;
1844d36ea92cSAndrew Rybchenko 
1845d36ea92cSAndrew Rybchenko 	EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr);
1846d36ea92cSAndrew Rybchenko 
1847233c1e5eSAndrew Rybchenko 	/* Board configuration (legacy) */
1848233c1e5eSAndrew Rybchenko 	rc = efx_mcdi_get_board_cfg(enp, &board_type, NULL, NULL);
1849233c1e5eSAndrew Rybchenko 	if (rc != 0) {
1850233c1e5eSAndrew Rybchenko 		/* Unprivileged functions may not be able to read board cfg */
1851233c1e5eSAndrew Rybchenko 		if (rc == EACCES)
1852233c1e5eSAndrew Rybchenko 			board_type = 0;
1853233c1e5eSAndrew Rybchenko 		else
1854233c1e5eSAndrew Rybchenko 			goto fail5;
1855233c1e5eSAndrew Rybchenko 	}
1856233c1e5eSAndrew Rybchenko 
1857233c1e5eSAndrew Rybchenko 	encp->enc_board_type = board_type;
1858233c1e5eSAndrew Rybchenko 	encp->enc_clk_mult = 1; /* not used for EF10 */
1859233c1e5eSAndrew Rybchenko 
1860e5f6f32fSAndrew Rybchenko 	/* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */
1861e5f6f32fSAndrew Rybchenko 	if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0)
1862e5f6f32fSAndrew Rybchenko 		goto fail6;
1863e5f6f32fSAndrew Rybchenko 
18643f3f5d85SAndrew Rybchenko 	/*
18653f3f5d85SAndrew Rybchenko 	 * Firmware with support for *_FEC capability bits does not
18663f3f5d85SAndrew Rybchenko 	 * report that the corresponding *_FEC_REQUESTED bits are supported.
18673f3f5d85SAndrew Rybchenko 	 * Add them here so that drivers understand that they are supported.
18683f3f5d85SAndrew Rybchenko 	 */
18693f3f5d85SAndrew Rybchenko 	if (epp->ep_phy_cap_mask & (1u << EFX_PHY_CAP_BASER_FEC))
18703f3f5d85SAndrew Rybchenko 		epp->ep_phy_cap_mask |=
18713f3f5d85SAndrew Rybchenko 		    (1u << EFX_PHY_CAP_BASER_FEC_REQUESTED);
18723f3f5d85SAndrew Rybchenko 	if (epp->ep_phy_cap_mask & (1u << EFX_PHY_CAP_RS_FEC))
18733f3f5d85SAndrew Rybchenko 		epp->ep_phy_cap_mask |=
18743f3f5d85SAndrew Rybchenko 		    (1u << EFX_PHY_CAP_RS_FEC_REQUESTED);
18753f3f5d85SAndrew Rybchenko 	if (epp->ep_phy_cap_mask & (1u << EFX_PHY_CAP_25G_BASER_FEC))
18763f3f5d85SAndrew Rybchenko 		epp->ep_phy_cap_mask |=
18773f3f5d85SAndrew Rybchenko 		    (1u << EFX_PHY_CAP_25G_BASER_FEC_REQUESTED);
18783f3f5d85SAndrew Rybchenko 
1879e5f6f32fSAndrew Rybchenko 	/* Obtain the default PHY advertised capabilities */
1880e5f6f32fSAndrew Rybchenko 	if ((rc = ef10_phy_get_link(enp, &els)) != 0)
1881e5f6f32fSAndrew Rybchenko 		goto fail7;
1882cf94ca37SAndrew Rybchenko 	epp->ep_default_adv_cap_mask = els.epls.epls_adv_cap_mask;
1883cf94ca37SAndrew Rybchenko 	epp->ep_adv_cap_mask = els.epls.epls_adv_cap_mask;
1884e5f6f32fSAndrew Rybchenko 
1885deeaf87fSAndrew Rybchenko 	/* Check capabilities of running datapath firmware */
1886deeaf87fSAndrew Rybchenko 	if ((rc = ef10_get_datapath_caps(enp)) != 0)
1887deeaf87fSAndrew Rybchenko 		goto fail8;
1888deeaf87fSAndrew Rybchenko 
188969aff9bbSAndrew Rybchenko 	/* Alignment for WPTR updates */
189069aff9bbSAndrew Rybchenko 	encp->enc_rx_push_align = EF10_RX_WPTR_ALIGN;
189169aff9bbSAndrew Rybchenko 
189240f5e54cSAndrew Rybchenko 	encp->enc_tx_dma_desc_size_max = EFX_MASK32(ESF_DZ_RX_KER_BYTE_CNT);
189340f5e54cSAndrew Rybchenko 	/* No boundary crossing limits */
189440f5e54cSAndrew Rybchenko 	encp->enc_tx_dma_desc_boundary = 0;
189540f5e54cSAndrew Rybchenko 
189640f5e54cSAndrew Rybchenko 	/*
189740f5e54cSAndrew Rybchenko 	 * Maximum number of bytes into the frame the TCP header can start for
189840f5e54cSAndrew Rybchenko 	 * firmware assisted TSO to work.
189940f5e54cSAndrew Rybchenko 	 */
190040f5e54cSAndrew Rybchenko 	encp->enc_tx_tso_tcp_header_offset_limit = EF10_TCP_HEADER_OFFSET_LIMIT;
190140f5e54cSAndrew Rybchenko 
1902ff8ff866SAndrew Rybchenko 	/*
1903ff8ff866SAndrew Rybchenko 	 * Set resource limits for MC_CMD_ALLOC_VIS. Note that we cannot use
1904ff8ff866SAndrew Rybchenko 	 * MC_CMD_GET_RESOURCE_LIMITS here as that reports the available
1905ff8ff866SAndrew Rybchenko 	 * resources (allocated to this PCIe function), which is zero until
1906ff8ff866SAndrew Rybchenko 	 * after we have allocated VIs.
1907ff8ff866SAndrew Rybchenko 	 */
1908ff8ff866SAndrew Rybchenko 	encp->enc_evq_limit = 1024;
1909ff8ff866SAndrew Rybchenko 	encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET;
1910ff8ff866SAndrew Rybchenko 	encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET;
1911ff8ff866SAndrew Rybchenko 
1912ff8ff866SAndrew Rybchenko 	encp->enc_buftbl_limit = 0xFFFFFFFF;
191369aff9bbSAndrew Rybchenko 
191461e0c16dSAndrew Rybchenko 	/* Get interrupt vector limits */
191561e0c16dSAndrew Rybchenko 	if ((rc = efx_mcdi_get_vector_cfg(enp, &base, &nvec, NULL)) != 0) {
191661e0c16dSAndrew Rybchenko 		if (EFX_PCI_FUNCTION_IS_PF(encp))
191761e0c16dSAndrew Rybchenko 			goto fail9;
191861e0c16dSAndrew Rybchenko 
191961e0c16dSAndrew Rybchenko 		/* Ignore error (cannot query vector limits from a VF). */
192061e0c16dSAndrew Rybchenko 		base = 0;
192161e0c16dSAndrew Rybchenko 		nvec = 1024;
192261e0c16dSAndrew Rybchenko 	}
192361e0c16dSAndrew Rybchenko 	encp->enc_intr_vec_base = base;
192461e0c16dSAndrew Rybchenko 	encp->enc_intr_limit = nvec;
192561e0c16dSAndrew Rybchenko 
192626fcca57SAndrew Rybchenko 	/*
192726fcca57SAndrew Rybchenko 	 * Get the current privilege mask. Note that this may be modified
192826fcca57SAndrew Rybchenko 	 * dynamically, so this value is informational only. DO NOT use
192926fcca57SAndrew Rybchenko 	 * the privilege mask to check for sufficient privileges, as that
193026fcca57SAndrew Rybchenko 	 * can result in time-of-check/time-of-use bugs.
193126fcca57SAndrew Rybchenko 	 */
193226fcca57SAndrew Rybchenko 	if ((rc = ef10_get_privilege_mask(enp, &mask)) != 0)
193326fcca57SAndrew Rybchenko 		goto fail10;
193426fcca57SAndrew Rybchenko 	encp->enc_privilege_mask = mask;
193526fcca57SAndrew Rybchenko 
193609eac957SAndrew Rybchenko 	/* Get remaining controller-specific board config */
193748194339SAndrew Rybchenko 	if ((rc = enop->eno_board_cfg(enp)) != 0)
193848194339SAndrew Rybchenko 		if (rc != EACCES)
193926fcca57SAndrew Rybchenko 			goto fail11;
194048194339SAndrew Rybchenko 
194148194339SAndrew Rybchenko 	return (0);
194248194339SAndrew Rybchenko 
194326fcca57SAndrew Rybchenko fail11:
194426fcca57SAndrew Rybchenko 	EFSYS_PROBE(fail11);
194561e0c16dSAndrew Rybchenko fail10:
194661e0c16dSAndrew Rybchenko 	EFSYS_PROBE(fail10);
1947deeaf87fSAndrew Rybchenko fail9:
1948deeaf87fSAndrew Rybchenko 	EFSYS_PROBE(fail9);
1949e5f6f32fSAndrew Rybchenko fail8:
1950e5f6f32fSAndrew Rybchenko 	EFSYS_PROBE(fail8);
1951e5f6f32fSAndrew Rybchenko fail7:
1952e5f6f32fSAndrew Rybchenko 	EFSYS_PROBE(fail7);
1953233c1e5eSAndrew Rybchenko fail6:
1954233c1e5eSAndrew Rybchenko 	EFSYS_PROBE(fail6);
1955d36ea92cSAndrew Rybchenko fail5:
1956d36ea92cSAndrew Rybchenko 	EFSYS_PROBE(fail5);
195717f272e7SAndrew Rybchenko fail4:
195817f272e7SAndrew Rybchenko 	EFSYS_PROBE(fail4);
195909eac957SAndrew Rybchenko fail3:
196009eac957SAndrew Rybchenko 	EFSYS_PROBE(fail3);
196109eac957SAndrew Rybchenko fail2:
196209eac957SAndrew Rybchenko 	EFSYS_PROBE(fail2);
196348194339SAndrew Rybchenko fail1:
196448194339SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
196548194339SAndrew Rybchenko 
196648194339SAndrew Rybchenko 	return (rc);
196748194339SAndrew Rybchenko }
196831bf5f03SAndrew Rybchenko 
196931bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_nic_probe(__in efx_nic_t * enp)197031bf5f03SAndrew Rybchenko ef10_nic_probe(
197131bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp)
197231bf5f03SAndrew Rybchenko {
197331bf5f03SAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
197431bf5f03SAndrew Rybchenko 	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
197531bf5f03SAndrew Rybchenko 	efx_rc_t rc;
197631bf5f03SAndrew Rybchenko 
197731bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1978ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD ||
1979ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD2);
198031bf5f03SAndrew Rybchenko 
198131bf5f03SAndrew Rybchenko 	/* Read and clear any assertion state */
198231bf5f03SAndrew Rybchenko 	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
198331bf5f03SAndrew Rybchenko 		goto fail1;
198431bf5f03SAndrew Rybchenko 
198531bf5f03SAndrew Rybchenko 	/* Exit the assertion handler */
198631bf5f03SAndrew Rybchenko 	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
198731bf5f03SAndrew Rybchenko 		if (rc != EACCES)
198831bf5f03SAndrew Rybchenko 			goto fail2;
198931bf5f03SAndrew Rybchenko 
199031bf5f03SAndrew Rybchenko 	if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
199131bf5f03SAndrew Rybchenko 		goto fail3;
199231bf5f03SAndrew Rybchenko 
199348194339SAndrew Rybchenko 	if ((rc = ef10_nic_board_cfg(enp)) != 0)
199431bf5f03SAndrew Rybchenko 		goto fail4;
199531bf5f03SAndrew Rybchenko 
199631bf5f03SAndrew Rybchenko 	/*
199731bf5f03SAndrew Rybchenko 	 * Set default driver config limits (based on board config).
199831bf5f03SAndrew Rybchenko 	 *
199931bf5f03SAndrew Rybchenko 	 * FIXME: For now allocate a fixed number of VIs which is likely to be
200031bf5f03SAndrew Rybchenko 	 * sufficient and small enough to allow multiple functions on the same
200131bf5f03SAndrew Rybchenko 	 * port.
200231bf5f03SAndrew Rybchenko 	 */
200331bf5f03SAndrew Rybchenko 	edcp->edc_min_vi_count = edcp->edc_max_vi_count =
200431bf5f03SAndrew Rybchenko 	    MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit));
200531bf5f03SAndrew Rybchenko 
200631bf5f03SAndrew Rybchenko 	/* The client driver must configure and enable PIO buffer support */
200731bf5f03SAndrew Rybchenko 	edcp->edc_max_piobuf_count = 0;
200831bf5f03SAndrew Rybchenko 	edcp->edc_pio_alloc_size = 0;
200931bf5f03SAndrew Rybchenko 
201031bf5f03SAndrew Rybchenko #if EFSYS_OPT_MAC_STATS
201131bf5f03SAndrew Rybchenko 	/* Wipe the MAC statistics */
201231bf5f03SAndrew Rybchenko 	if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
201331bf5f03SAndrew Rybchenko 		goto fail5;
201431bf5f03SAndrew Rybchenko #endif
201531bf5f03SAndrew Rybchenko 
201631bf5f03SAndrew Rybchenko #if EFSYS_OPT_LOOPBACK
201731bf5f03SAndrew Rybchenko 	if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
201831bf5f03SAndrew Rybchenko 		goto fail6;
201931bf5f03SAndrew Rybchenko #endif
202031bf5f03SAndrew Rybchenko 
202131bf5f03SAndrew Rybchenko #if EFSYS_OPT_MON_STATS
202231bf5f03SAndrew Rybchenko 	if ((rc = mcdi_mon_cfg_build(enp)) != 0) {
202331bf5f03SAndrew Rybchenko 		/* Unprivileged functions do not have access to sensors */
202431bf5f03SAndrew Rybchenko 		if (rc != EACCES)
202531bf5f03SAndrew Rybchenko 			goto fail7;
202631bf5f03SAndrew Rybchenko 	}
202731bf5f03SAndrew Rybchenko #endif
202831bf5f03SAndrew Rybchenko 
202931bf5f03SAndrew Rybchenko 	encp->enc_features = enp->en_features;
203031bf5f03SAndrew Rybchenko 
203131bf5f03SAndrew Rybchenko 	return (0);
203231bf5f03SAndrew Rybchenko 
203331bf5f03SAndrew Rybchenko #if EFSYS_OPT_MON_STATS
203431bf5f03SAndrew Rybchenko fail7:
203531bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail7);
203631bf5f03SAndrew Rybchenko #endif
203731bf5f03SAndrew Rybchenko #if EFSYS_OPT_LOOPBACK
203831bf5f03SAndrew Rybchenko fail6:
203931bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail6);
204031bf5f03SAndrew Rybchenko #endif
204131bf5f03SAndrew Rybchenko #if EFSYS_OPT_MAC_STATS
204231bf5f03SAndrew Rybchenko fail5:
204331bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail5);
204431bf5f03SAndrew Rybchenko #endif
204531bf5f03SAndrew Rybchenko fail4:
204631bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail4);
204731bf5f03SAndrew Rybchenko fail3:
204831bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail3);
204931bf5f03SAndrew Rybchenko fail2:
205031bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
205131bf5f03SAndrew Rybchenko fail1:
205231bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
205331bf5f03SAndrew Rybchenko 
205431bf5f03SAndrew Rybchenko 	return (rc);
205531bf5f03SAndrew Rybchenko }
205631bf5f03SAndrew Rybchenko 
205731bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_nic_set_drv_limits(__inout efx_nic_t * enp,__in efx_drv_limits_t * edlp)205831bf5f03SAndrew Rybchenko ef10_nic_set_drv_limits(
205931bf5f03SAndrew Rybchenko 	__inout		efx_nic_t *enp,
206031bf5f03SAndrew Rybchenko 	__in		efx_drv_limits_t *edlp)
206131bf5f03SAndrew Rybchenko {
206231bf5f03SAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
206331bf5f03SAndrew Rybchenko 	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
206431bf5f03SAndrew Rybchenko 	uint32_t min_evq_count, max_evq_count;
206531bf5f03SAndrew Rybchenko 	uint32_t min_rxq_count, max_rxq_count;
206631bf5f03SAndrew Rybchenko 	uint32_t min_txq_count, max_txq_count;
206731bf5f03SAndrew Rybchenko 	efx_rc_t rc;
206831bf5f03SAndrew Rybchenko 
206931bf5f03SAndrew Rybchenko 	if (edlp == NULL) {
207031bf5f03SAndrew Rybchenko 		rc = EINVAL;
207131bf5f03SAndrew Rybchenko 		goto fail1;
207231bf5f03SAndrew Rybchenko 	}
207331bf5f03SAndrew Rybchenko 
207431bf5f03SAndrew Rybchenko 	/* Get minimum required and maximum usable VI limits */
207531bf5f03SAndrew Rybchenko 	min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit);
207631bf5f03SAndrew Rybchenko 	min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit);
207731bf5f03SAndrew Rybchenko 	min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit);
207831bf5f03SAndrew Rybchenko 
207931bf5f03SAndrew Rybchenko 	edcp->edc_min_vi_count =
208031bf5f03SAndrew Rybchenko 	    MAX(min_evq_count, MAX(min_rxq_count, min_txq_count));
208131bf5f03SAndrew Rybchenko 
208231bf5f03SAndrew Rybchenko 	max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit);
208331bf5f03SAndrew Rybchenko 	max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit);
208431bf5f03SAndrew Rybchenko 	max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit);
208531bf5f03SAndrew Rybchenko 
208631bf5f03SAndrew Rybchenko 	edcp->edc_max_vi_count =
208731bf5f03SAndrew Rybchenko 	    MAX(max_evq_count, MAX(max_rxq_count, max_txq_count));
208831bf5f03SAndrew Rybchenko 
208931bf5f03SAndrew Rybchenko 	/*
209031bf5f03SAndrew Rybchenko 	 * Check limits for sub-allocated piobuf blocks.
209131bf5f03SAndrew Rybchenko 	 * PIO is optional, so don't fail if the limits are incorrect.
209231bf5f03SAndrew Rybchenko 	 */
209331bf5f03SAndrew Rybchenko 	if ((encp->enc_piobuf_size == 0) ||
209431bf5f03SAndrew Rybchenko 	    (encp->enc_piobuf_limit == 0) ||
209531bf5f03SAndrew Rybchenko 	    (edlp->edl_min_pio_alloc_size == 0) ||
209631bf5f03SAndrew Rybchenko 	    (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) {
209731bf5f03SAndrew Rybchenko 		/* Disable PIO */
209831bf5f03SAndrew Rybchenko 		edcp->edc_max_piobuf_count = 0;
209931bf5f03SAndrew Rybchenko 		edcp->edc_pio_alloc_size = 0;
210031bf5f03SAndrew Rybchenko 	} else {
210131bf5f03SAndrew Rybchenko 		uint32_t blk_size, blk_count, blks_per_piobuf;
210231bf5f03SAndrew Rybchenko 
210331bf5f03SAndrew Rybchenko 		blk_size =
210431bf5f03SAndrew Rybchenko 		    MAX(edlp->edl_min_pio_alloc_size,
210531bf5f03SAndrew Rybchenko 			    encp->enc_piobuf_min_alloc_size);
210631bf5f03SAndrew Rybchenko 
210731bf5f03SAndrew Rybchenko 		blks_per_piobuf = encp->enc_piobuf_size / blk_size;
210831bf5f03SAndrew Rybchenko 		EFSYS_ASSERT3U(blks_per_piobuf, <=, 32);
210931bf5f03SAndrew Rybchenko 
211031bf5f03SAndrew Rybchenko 		blk_count = (encp->enc_piobuf_limit * blks_per_piobuf);
211131bf5f03SAndrew Rybchenko 
211231bf5f03SAndrew Rybchenko 		/* A zero max pio alloc count means unlimited */
211331bf5f03SAndrew Rybchenko 		if ((edlp->edl_max_pio_alloc_count > 0) &&
211431bf5f03SAndrew Rybchenko 		    (edlp->edl_max_pio_alloc_count < blk_count)) {
211531bf5f03SAndrew Rybchenko 			blk_count = edlp->edl_max_pio_alloc_count;
211631bf5f03SAndrew Rybchenko 		}
211731bf5f03SAndrew Rybchenko 
211831bf5f03SAndrew Rybchenko 		edcp->edc_pio_alloc_size = blk_size;
211931bf5f03SAndrew Rybchenko 		edcp->edc_max_piobuf_count =
212031bf5f03SAndrew Rybchenko 		    (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf;
212131bf5f03SAndrew Rybchenko 	}
212231bf5f03SAndrew Rybchenko 
212331bf5f03SAndrew Rybchenko 	return (0);
212431bf5f03SAndrew Rybchenko 
212531bf5f03SAndrew Rybchenko fail1:
212631bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
212731bf5f03SAndrew Rybchenko 
212831bf5f03SAndrew Rybchenko 	return (rc);
212931bf5f03SAndrew Rybchenko }
213031bf5f03SAndrew Rybchenko 
213131bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_nic_reset(__in efx_nic_t * enp)213231bf5f03SAndrew Rybchenko ef10_nic_reset(
213331bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp)
213431bf5f03SAndrew Rybchenko {
213531bf5f03SAndrew Rybchenko 	efx_mcdi_req_t req;
2136315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_ENTITY_RESET_IN_LEN,
2137315bbbaaSAndrew Rybchenko 		MC_CMD_ENTITY_RESET_OUT_LEN);
213831bf5f03SAndrew Rybchenko 	efx_rc_t rc;
213931bf5f03SAndrew Rybchenko 
214031bf5f03SAndrew Rybchenko 	/* ef10_nic_reset() is called to recover from BADASSERT failures. */
214131bf5f03SAndrew Rybchenko 	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
214231bf5f03SAndrew Rybchenko 		goto fail1;
214331bf5f03SAndrew Rybchenko 	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
214431bf5f03SAndrew Rybchenko 		goto fail2;
214531bf5f03SAndrew Rybchenko 
214631bf5f03SAndrew Rybchenko 	req.emr_cmd = MC_CMD_ENTITY_RESET;
214731bf5f03SAndrew Rybchenko 	req.emr_in_buf = payload;
214831bf5f03SAndrew Rybchenko 	req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN;
214931bf5f03SAndrew Rybchenko 	req.emr_out_buf = payload;
215031bf5f03SAndrew Rybchenko 	req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN;
215131bf5f03SAndrew Rybchenko 
215231bf5f03SAndrew Rybchenko 	MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG,
215331bf5f03SAndrew Rybchenko 	    ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1);
215431bf5f03SAndrew Rybchenko 
215531bf5f03SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
215631bf5f03SAndrew Rybchenko 
215731bf5f03SAndrew Rybchenko 	if (req.emr_rc != 0) {
215831bf5f03SAndrew Rybchenko 		rc = req.emr_rc;
215931bf5f03SAndrew Rybchenko 		goto fail3;
216031bf5f03SAndrew Rybchenko 	}
216131bf5f03SAndrew Rybchenko 
216231bf5f03SAndrew Rybchenko 	/* Clear RX/TX DMA queue errors */
216331bf5f03SAndrew Rybchenko 	enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR);
216431bf5f03SAndrew Rybchenko 
216531bf5f03SAndrew Rybchenko 	return (0);
216631bf5f03SAndrew Rybchenko 
216731bf5f03SAndrew Rybchenko fail3:
216831bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail3);
216931bf5f03SAndrew Rybchenko fail2:
217031bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
217131bf5f03SAndrew Rybchenko fail1:
217231bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
217331bf5f03SAndrew Rybchenko 
217431bf5f03SAndrew Rybchenko 	return (rc);
217531bf5f03SAndrew Rybchenko }
217631bf5f03SAndrew Rybchenko 
217731bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_nic_init(__in efx_nic_t * enp)217831bf5f03SAndrew Rybchenko ef10_nic_init(
217931bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp)
218031bf5f03SAndrew Rybchenko {
218131bf5f03SAndrew Rybchenko 	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
218231bf5f03SAndrew Rybchenko 	uint32_t min_vi_count, max_vi_count;
218331bf5f03SAndrew Rybchenko 	uint32_t vi_count, vi_base, vi_shift;
218431bf5f03SAndrew Rybchenko 	uint32_t i;
218531bf5f03SAndrew Rybchenko 	uint32_t retry;
218631bf5f03SAndrew Rybchenko 	uint32_t delay_us;
2187c63c8369SAndrew Rybchenko 	uint32_t vi_window_size;
218831bf5f03SAndrew Rybchenko 	efx_rc_t rc;
218931bf5f03SAndrew Rybchenko 
219031bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
2191ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD ||
2192ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD2);
219331bf5f03SAndrew Rybchenko 
219431bf5f03SAndrew Rybchenko 	/* Enable reporting of some events (e.g. link change) */
219531bf5f03SAndrew Rybchenko 	if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
219631bf5f03SAndrew Rybchenko 		goto fail1;
219731bf5f03SAndrew Rybchenko 
219831bf5f03SAndrew Rybchenko 	/* Allocate (optional) on-chip PIO buffers */
219931bf5f03SAndrew Rybchenko 	ef10_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count);
220031bf5f03SAndrew Rybchenko 
220131bf5f03SAndrew Rybchenko 	/*
220231bf5f03SAndrew Rybchenko 	 * For best performance, PIO writes should use a write-combined
220331bf5f03SAndrew Rybchenko 	 * (WC) memory mapping. Using a separate WC mapping for the PIO
220431bf5f03SAndrew Rybchenko 	 * aperture of each VI would be a burden to drivers (and not
220531bf5f03SAndrew Rybchenko 	 * possible if the host page size is >4Kbyte).
220631bf5f03SAndrew Rybchenko 	 *
220731bf5f03SAndrew Rybchenko 	 * To avoid this we use a single uncached (UC) mapping for VI
220831bf5f03SAndrew Rybchenko 	 * register access, and a single WC mapping for extra VIs used
220931bf5f03SAndrew Rybchenko 	 * for PIO writes.
221031bf5f03SAndrew Rybchenko 	 *
221131bf5f03SAndrew Rybchenko 	 * Each piobuf must be linked to a VI in the WC mapping, and to
221231bf5f03SAndrew Rybchenko 	 * each VI that is using a sub-allocated block from the piobuf.
221331bf5f03SAndrew Rybchenko 	 */
221431bf5f03SAndrew Rybchenko 	min_vi_count = edcp->edc_min_vi_count;
221531bf5f03SAndrew Rybchenko 	max_vi_count =
221631bf5f03SAndrew Rybchenko 	    edcp->edc_max_vi_count + enp->en_arch.ef10.ena_piobuf_count;
221731bf5f03SAndrew Rybchenko 
221831bf5f03SAndrew Rybchenko 	/* Ensure that the previously attached driver's VIs are freed */
221931bf5f03SAndrew Rybchenko 	if ((rc = efx_mcdi_free_vis(enp)) != 0)
222031bf5f03SAndrew Rybchenko 		goto fail2;
222131bf5f03SAndrew Rybchenko 
222231bf5f03SAndrew Rybchenko 	/*
222331bf5f03SAndrew Rybchenko 	 * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this
222431bf5f03SAndrew Rybchenko 	 * fails then retrying the request for fewer VI resources may succeed.
222531bf5f03SAndrew Rybchenko 	 */
222631bf5f03SAndrew Rybchenko 	vi_count = 0;
222731bf5f03SAndrew Rybchenko 	if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count,
222831bf5f03SAndrew Rybchenko 		    &vi_base, &vi_count, &vi_shift)) != 0)
222931bf5f03SAndrew Rybchenko 		goto fail3;
223031bf5f03SAndrew Rybchenko 
223131bf5f03SAndrew Rybchenko 	EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count);
223231bf5f03SAndrew Rybchenko 
223331bf5f03SAndrew Rybchenko 	if (vi_count < min_vi_count) {
223431bf5f03SAndrew Rybchenko 		rc = ENOMEM;
223531bf5f03SAndrew Rybchenko 		goto fail4;
223631bf5f03SAndrew Rybchenko 	}
223731bf5f03SAndrew Rybchenko 
223831bf5f03SAndrew Rybchenko 	enp->en_arch.ef10.ena_vi_base = vi_base;
223931bf5f03SAndrew Rybchenko 	enp->en_arch.ef10.ena_vi_count = vi_count;
224031bf5f03SAndrew Rybchenko 	enp->en_arch.ef10.ena_vi_shift = vi_shift;
224131bf5f03SAndrew Rybchenko 
224231bf5f03SAndrew Rybchenko 	if (vi_count < min_vi_count + enp->en_arch.ef10.ena_piobuf_count) {
224331bf5f03SAndrew Rybchenko 		/* Not enough extra VIs to map piobufs */
224431bf5f03SAndrew Rybchenko 		ef10_nic_free_piobufs(enp);
224531bf5f03SAndrew Rybchenko 	}
224631bf5f03SAndrew Rybchenko 
224731bf5f03SAndrew Rybchenko 	enp->en_arch.ef10.ena_pio_write_vi_base =
224831bf5f03SAndrew Rybchenko 	    vi_count - enp->en_arch.ef10.ena_piobuf_count;
224931bf5f03SAndrew Rybchenko 
2250c63c8369SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nic_cfg.enc_vi_window_shift, !=,
2251c63c8369SAndrew Rybchenko 	    EFX_VI_WINDOW_SHIFT_INVALID);
2252c63c8369SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nic_cfg.enc_vi_window_shift, <=,
2253c63c8369SAndrew Rybchenko 	    EFX_VI_WINDOW_SHIFT_64K);
2254c63c8369SAndrew Rybchenko 	vi_window_size = 1U << enp->en_nic_cfg.enc_vi_window_shift;
2255c63c8369SAndrew Rybchenko 
225631bf5f03SAndrew Rybchenko 	/* Save UC memory mapping details */
225731bf5f03SAndrew Rybchenko 	enp->en_arch.ef10.ena_uc_mem_map_offset = 0;
225831bf5f03SAndrew Rybchenko 	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
225931bf5f03SAndrew Rybchenko 		enp->en_arch.ef10.ena_uc_mem_map_size =
2260c63c8369SAndrew Rybchenko 		    (vi_window_size *
226131bf5f03SAndrew Rybchenko 		    enp->en_arch.ef10.ena_pio_write_vi_base);
226231bf5f03SAndrew Rybchenko 	} else {
226331bf5f03SAndrew Rybchenko 		enp->en_arch.ef10.ena_uc_mem_map_size =
2264c63c8369SAndrew Rybchenko 		    (vi_window_size *
226531bf5f03SAndrew Rybchenko 		    enp->en_arch.ef10.ena_vi_count);
226631bf5f03SAndrew Rybchenko 	}
226731bf5f03SAndrew Rybchenko 
226831bf5f03SAndrew Rybchenko 	/* Save WC memory mapping details */
226931bf5f03SAndrew Rybchenko 	enp->en_arch.ef10.ena_wc_mem_map_offset =
227031bf5f03SAndrew Rybchenko 	    enp->en_arch.ef10.ena_uc_mem_map_offset +
227131bf5f03SAndrew Rybchenko 	    enp->en_arch.ef10.ena_uc_mem_map_size;
227231bf5f03SAndrew Rybchenko 
227331bf5f03SAndrew Rybchenko 	enp->en_arch.ef10.ena_wc_mem_map_size =
2274c63c8369SAndrew Rybchenko 	    (vi_window_size *
227531bf5f03SAndrew Rybchenko 	    enp->en_arch.ef10.ena_piobuf_count);
227631bf5f03SAndrew Rybchenko 
227731bf5f03SAndrew Rybchenko 	/* Link piobufs to extra VIs in WC mapping */
227831bf5f03SAndrew Rybchenko 	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
227931bf5f03SAndrew Rybchenko 		for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
228031bf5f03SAndrew Rybchenko 			rc = efx_mcdi_link_piobuf(enp,
228131bf5f03SAndrew Rybchenko 			    enp->en_arch.ef10.ena_pio_write_vi_base + i,
228231bf5f03SAndrew Rybchenko 			    enp->en_arch.ef10.ena_piobuf_handle[i]);
228331bf5f03SAndrew Rybchenko 			if (rc != 0)
228431bf5f03SAndrew Rybchenko 				break;
228531bf5f03SAndrew Rybchenko 		}
228631bf5f03SAndrew Rybchenko 	}
228731bf5f03SAndrew Rybchenko 
228831bf5f03SAndrew Rybchenko 	/*
228931bf5f03SAndrew Rybchenko 	 * Allocate a vAdaptor attached to our upstream vPort/pPort.
229031bf5f03SAndrew Rybchenko 	 *
229131bf5f03SAndrew Rybchenko 	 * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF
229231bf5f03SAndrew Rybchenko 	 * driver has yet to bring up the EVB port. See bug 56147. In this case,
229331bf5f03SAndrew Rybchenko 	 * retry the request several times after waiting a while. The wait time
229431bf5f03SAndrew Rybchenko 	 * between retries starts small (10ms) and exponentially increases.
229531bf5f03SAndrew Rybchenko 	 * Total wait time is a little over two seconds. Retry logic in the
229631bf5f03SAndrew Rybchenko 	 * client driver may mean this whole loop is repeated if it continues to
229731bf5f03SAndrew Rybchenko 	 * fail.
229831bf5f03SAndrew Rybchenko 	 */
229931bf5f03SAndrew Rybchenko 	retry = 0;
230031bf5f03SAndrew Rybchenko 	delay_us = 10000;
230131bf5f03SAndrew Rybchenko 	while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) {
230231bf5f03SAndrew Rybchenko 		if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) ||
230331bf5f03SAndrew Rybchenko 		    (rc != ENOENT)) {
230431bf5f03SAndrew Rybchenko 			/*
230531bf5f03SAndrew Rybchenko 			 * Do not retry alloc for PF, or for other errors on
230631bf5f03SAndrew Rybchenko 			 * a VF.
230731bf5f03SAndrew Rybchenko 			 */
230831bf5f03SAndrew Rybchenko 			goto fail5;
230931bf5f03SAndrew Rybchenko 		}
231031bf5f03SAndrew Rybchenko 
231131bf5f03SAndrew Rybchenko 		/* VF startup before PF is ready. Retry allocation. */
231231bf5f03SAndrew Rybchenko 		if (retry > 5) {
231331bf5f03SAndrew Rybchenko 			/* Too many attempts */
231431bf5f03SAndrew Rybchenko 			rc = EINVAL;
231531bf5f03SAndrew Rybchenko 			goto fail6;
231631bf5f03SAndrew Rybchenko 		}
231731bf5f03SAndrew Rybchenko 		EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry);
231831bf5f03SAndrew Rybchenko 		EFSYS_SLEEP(delay_us);
231931bf5f03SAndrew Rybchenko 		retry++;
232031bf5f03SAndrew Rybchenko 		if (delay_us < 500000)
232131bf5f03SAndrew Rybchenko 			delay_us <<= 2;
232231bf5f03SAndrew Rybchenko 	}
232331bf5f03SAndrew Rybchenko 
232431bf5f03SAndrew Rybchenko 	enp->en_vport_id = EVB_PORT_ID_ASSIGNED;
232531bf5f03SAndrew Rybchenko 	enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V2;
232631bf5f03SAndrew Rybchenko 
232731bf5f03SAndrew Rybchenko 	return (0);
232831bf5f03SAndrew Rybchenko 
232931bf5f03SAndrew Rybchenko fail6:
233031bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail6);
233131bf5f03SAndrew Rybchenko fail5:
233231bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail5);
233331bf5f03SAndrew Rybchenko fail4:
233431bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail4);
233531bf5f03SAndrew Rybchenko fail3:
233631bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail3);
233731bf5f03SAndrew Rybchenko fail2:
233831bf5f03SAndrew Rybchenko 	EFSYS_PROBE(fail2);
233931bf5f03SAndrew Rybchenko 
234031bf5f03SAndrew Rybchenko 	ef10_nic_free_piobufs(enp);
234131bf5f03SAndrew Rybchenko 
234231bf5f03SAndrew Rybchenko fail1:
234331bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
234431bf5f03SAndrew Rybchenko 
234531bf5f03SAndrew Rybchenko 	return (rc);
234631bf5f03SAndrew Rybchenko }
234731bf5f03SAndrew Rybchenko 
234831bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_nic_get_vi_pool(__in efx_nic_t * enp,__out uint32_t * vi_countp)234931bf5f03SAndrew Rybchenko ef10_nic_get_vi_pool(
235031bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
235131bf5f03SAndrew Rybchenko 	__out		uint32_t *vi_countp)
235231bf5f03SAndrew Rybchenko {
235331bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
2354ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD ||
2355ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD2);
235631bf5f03SAndrew Rybchenko 
235731bf5f03SAndrew Rybchenko 	/*
235831bf5f03SAndrew Rybchenko 	 * Report VIs that the client driver can use.
235931bf5f03SAndrew Rybchenko 	 * Do not include VIs used for PIO buffer writes.
236031bf5f03SAndrew Rybchenko 	 */
236131bf5f03SAndrew Rybchenko 	*vi_countp = enp->en_arch.ef10.ena_pio_write_vi_base;
236231bf5f03SAndrew Rybchenko 
236331bf5f03SAndrew Rybchenko 	return (0);
236431bf5f03SAndrew Rybchenko }
236531bf5f03SAndrew Rybchenko 
236631bf5f03SAndrew Rybchenko 	__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)236731bf5f03SAndrew Rybchenko ef10_nic_get_bar_region(
236831bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp,
236931bf5f03SAndrew Rybchenko 	__in		efx_nic_region_t region,
237031bf5f03SAndrew Rybchenko 	__out		uint32_t *offsetp,
237131bf5f03SAndrew Rybchenko 	__out		size_t *sizep)
237231bf5f03SAndrew Rybchenko {
237331bf5f03SAndrew Rybchenko 	efx_rc_t rc;
237431bf5f03SAndrew Rybchenko 
237531bf5f03SAndrew Rybchenko 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
2376ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD ||
2377ae64ac93SAndrew Rybchenko 	    enp->en_family == EFX_FAMILY_MEDFORD2);
237831bf5f03SAndrew Rybchenko 
237931bf5f03SAndrew Rybchenko 	/*
238031bf5f03SAndrew Rybchenko 	 * TODO: Specify host memory mapping alignment and granularity
238131bf5f03SAndrew Rybchenko 	 * in efx_drv_limits_t so that they can be taken into account
238231bf5f03SAndrew Rybchenko 	 * when allocating extra VIs for PIO writes.
238331bf5f03SAndrew Rybchenko 	 */
238431bf5f03SAndrew Rybchenko 	switch (region) {
238531bf5f03SAndrew Rybchenko 	case EFX_REGION_VI:
238631bf5f03SAndrew Rybchenko 		/* UC mapped memory BAR region for VI registers */
238731bf5f03SAndrew Rybchenko 		*offsetp = enp->en_arch.ef10.ena_uc_mem_map_offset;
238831bf5f03SAndrew Rybchenko 		*sizep = enp->en_arch.ef10.ena_uc_mem_map_size;
238931bf5f03SAndrew Rybchenko 		break;
239031bf5f03SAndrew Rybchenko 
239131bf5f03SAndrew Rybchenko 	case EFX_REGION_PIO_WRITE_VI:
239231bf5f03SAndrew Rybchenko 		/* WC mapped memory BAR region for piobuf writes */
239331bf5f03SAndrew Rybchenko 		*offsetp = enp->en_arch.ef10.ena_wc_mem_map_offset;
239431bf5f03SAndrew Rybchenko 		*sizep = enp->en_arch.ef10.ena_wc_mem_map_size;
239531bf5f03SAndrew Rybchenko 		break;
239631bf5f03SAndrew Rybchenko 
239731bf5f03SAndrew Rybchenko 	default:
239831bf5f03SAndrew Rybchenko 		rc = EINVAL;
239931bf5f03SAndrew Rybchenko 		goto fail1;
240031bf5f03SAndrew Rybchenko 	}
240131bf5f03SAndrew Rybchenko 
240231bf5f03SAndrew Rybchenko 	return (0);
240331bf5f03SAndrew Rybchenko 
240431bf5f03SAndrew Rybchenko fail1:
240531bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
240631bf5f03SAndrew Rybchenko 
240731bf5f03SAndrew Rybchenko 	return (rc);
240831bf5f03SAndrew Rybchenko }
240931bf5f03SAndrew Rybchenko 
2410c6d5e85dSAndrew Rybchenko 	__checkReturn	boolean_t
ef10_nic_hw_unavailable(__in efx_nic_t * enp)2411c6d5e85dSAndrew Rybchenko ef10_nic_hw_unavailable(
2412c6d5e85dSAndrew Rybchenko 	__in		efx_nic_t *enp)
2413c6d5e85dSAndrew Rybchenko {
2414c6d5e85dSAndrew Rybchenko 	efx_dword_t dword;
2415c6d5e85dSAndrew Rybchenko 
2416c6d5e85dSAndrew Rybchenko 	if (enp->en_reset_flags & EFX_RESET_HW_UNAVAIL)
2417c6d5e85dSAndrew Rybchenko 		return (B_TRUE);
2418c6d5e85dSAndrew Rybchenko 
2419c6d5e85dSAndrew Rybchenko 	EFX_BAR_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, &dword, B_FALSE);
2420c6d5e85dSAndrew Rybchenko 	if (EFX_DWORD_FIELD(dword, EFX_DWORD_0) == 0xffffffff)
2421c6d5e85dSAndrew Rybchenko 		goto unavail;
2422c6d5e85dSAndrew Rybchenko 
2423c6d5e85dSAndrew Rybchenko 	return (B_FALSE);
2424c6d5e85dSAndrew Rybchenko 
2425c6d5e85dSAndrew Rybchenko unavail:
2426b2053d80SAndrew Rybchenko 	ef10_nic_set_hw_unavailable(enp);
2427c6d5e85dSAndrew Rybchenko 
2428c6d5e85dSAndrew Rybchenko 	return (B_TRUE);
2429c6d5e85dSAndrew Rybchenko }
2430c6d5e85dSAndrew Rybchenko 
243131bf5f03SAndrew Rybchenko 			void
ef10_nic_set_hw_unavailable(__in efx_nic_t * enp)2432b2053d80SAndrew Rybchenko ef10_nic_set_hw_unavailable(
2433b2053d80SAndrew Rybchenko 	__in		efx_nic_t *enp)
2434b2053d80SAndrew Rybchenko {
2435b2053d80SAndrew Rybchenko 	EFSYS_PROBE(hw_unavail);
2436b2053d80SAndrew Rybchenko 	enp->en_reset_flags |= EFX_RESET_HW_UNAVAIL;
2437b2053d80SAndrew Rybchenko }
2438b2053d80SAndrew Rybchenko 
2439b2053d80SAndrew Rybchenko 			void
ef10_nic_fini(__in efx_nic_t * enp)244031bf5f03SAndrew Rybchenko ef10_nic_fini(
244131bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp)
244231bf5f03SAndrew Rybchenko {
244331bf5f03SAndrew Rybchenko 	uint32_t i;
244431bf5f03SAndrew Rybchenko 	efx_rc_t rc;
244531bf5f03SAndrew Rybchenko 
244631bf5f03SAndrew Rybchenko 	(void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id);
244731bf5f03SAndrew Rybchenko 	enp->en_vport_id = 0;
244831bf5f03SAndrew Rybchenko 
244931bf5f03SAndrew Rybchenko 	/* Unlink piobufs from extra VIs in WC mapping */
245031bf5f03SAndrew Rybchenko 	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
245131bf5f03SAndrew Rybchenko 		for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
245231bf5f03SAndrew Rybchenko 			rc = efx_mcdi_unlink_piobuf(enp,
245331bf5f03SAndrew Rybchenko 			    enp->en_arch.ef10.ena_pio_write_vi_base + i);
245431bf5f03SAndrew Rybchenko 			if (rc != 0)
245531bf5f03SAndrew Rybchenko 				break;
245631bf5f03SAndrew Rybchenko 		}
245731bf5f03SAndrew Rybchenko 	}
245831bf5f03SAndrew Rybchenko 
245931bf5f03SAndrew Rybchenko 	ef10_nic_free_piobufs(enp);
246031bf5f03SAndrew Rybchenko 
246131bf5f03SAndrew Rybchenko 	(void) efx_mcdi_free_vis(enp);
246231bf5f03SAndrew Rybchenko 	enp->en_arch.ef10.ena_vi_count = 0;
246331bf5f03SAndrew Rybchenko }
246431bf5f03SAndrew Rybchenko 
246531bf5f03SAndrew Rybchenko 			void
ef10_nic_unprobe(__in efx_nic_t * enp)246631bf5f03SAndrew Rybchenko ef10_nic_unprobe(
246731bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp)
246831bf5f03SAndrew Rybchenko {
246931bf5f03SAndrew Rybchenko #if EFSYS_OPT_MON_STATS
247031bf5f03SAndrew Rybchenko 	mcdi_mon_cfg_free(enp);
247131bf5f03SAndrew Rybchenko #endif /* EFSYS_OPT_MON_STATS */
247231bf5f03SAndrew Rybchenko 	(void) efx_mcdi_drv_attach(enp, B_FALSE);
247331bf5f03SAndrew Rybchenko }
247431bf5f03SAndrew Rybchenko 
247531bf5f03SAndrew Rybchenko #if EFSYS_OPT_DIAG
247631bf5f03SAndrew Rybchenko 
247731bf5f03SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_nic_register_test(__in efx_nic_t * enp)247831bf5f03SAndrew Rybchenko ef10_nic_register_test(
247931bf5f03SAndrew Rybchenko 	__in		efx_nic_t *enp)
248031bf5f03SAndrew Rybchenko {
248131bf5f03SAndrew Rybchenko 	efx_rc_t rc;
248231bf5f03SAndrew Rybchenko 
248331bf5f03SAndrew Rybchenko 	/* FIXME */
248431bf5f03SAndrew Rybchenko 	_NOTE(ARGUNUSED(enp))
24855e951ea7SAndrew Rybchenko 	_NOTE(CONSTANTCONDITION)
248631bf5f03SAndrew Rybchenko 	if (B_FALSE) {
248731bf5f03SAndrew Rybchenko 		rc = ENOTSUP;
248831bf5f03SAndrew Rybchenko 		goto fail1;
248931bf5f03SAndrew Rybchenko 	}
249031bf5f03SAndrew Rybchenko 	/* FIXME */
249131bf5f03SAndrew Rybchenko 
249231bf5f03SAndrew Rybchenko 	return (0);
249331bf5f03SAndrew Rybchenko 
249431bf5f03SAndrew Rybchenko fail1:
249531bf5f03SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
249631bf5f03SAndrew Rybchenko 
249731bf5f03SAndrew Rybchenko 	return (rc);
249831bf5f03SAndrew Rybchenko }
249931bf5f03SAndrew Rybchenko 
250031bf5f03SAndrew Rybchenko #endif	/* EFSYS_OPT_DIAG */
250131bf5f03SAndrew Rybchenko 
250217bcc056SAndrew Rybchenko #if EFSYS_OPT_FW_SUBVARIANT_AWARE
250317bcc056SAndrew Rybchenko 
250417bcc056SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_mcdi_get_nic_global(__in efx_nic_t * enp,__in uint32_t key,__out uint32_t * valuep)250517bcc056SAndrew Rybchenko efx_mcdi_get_nic_global(
250617bcc056SAndrew Rybchenko 	__in		efx_nic_t *enp,
250717bcc056SAndrew Rybchenko 	__in		uint32_t key,
250817bcc056SAndrew Rybchenko 	__out		uint32_t *valuep)
250917bcc056SAndrew Rybchenko {
251017bcc056SAndrew Rybchenko 	efx_mcdi_req_t req;
2511315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_NIC_GLOBAL_IN_LEN,
2512315bbbaaSAndrew Rybchenko 		MC_CMD_GET_NIC_GLOBAL_OUT_LEN);
251317bcc056SAndrew Rybchenko 	efx_rc_t rc;
251417bcc056SAndrew Rybchenko 
251517bcc056SAndrew Rybchenko 	req.emr_cmd = MC_CMD_GET_NIC_GLOBAL;
251617bcc056SAndrew Rybchenko 	req.emr_in_buf = payload;
251717bcc056SAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_NIC_GLOBAL_IN_LEN;
251817bcc056SAndrew Rybchenko 	req.emr_out_buf = payload;
251917bcc056SAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_NIC_GLOBAL_OUT_LEN;
252017bcc056SAndrew Rybchenko 
252117bcc056SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, GET_NIC_GLOBAL_IN_KEY, key);
252217bcc056SAndrew Rybchenko 
252317bcc056SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
252417bcc056SAndrew Rybchenko 
252517bcc056SAndrew Rybchenko 	if (req.emr_rc != 0) {
252617bcc056SAndrew Rybchenko 		rc = req.emr_rc;
252717bcc056SAndrew Rybchenko 		goto fail1;
252817bcc056SAndrew Rybchenko 	}
252917bcc056SAndrew Rybchenko 
253017bcc056SAndrew Rybchenko 	if (req.emr_out_length_used != MC_CMD_GET_NIC_GLOBAL_OUT_LEN) {
253117bcc056SAndrew Rybchenko 		rc = EMSGSIZE;
253217bcc056SAndrew Rybchenko 		goto fail2;
253317bcc056SAndrew Rybchenko 	}
253417bcc056SAndrew Rybchenko 
253517bcc056SAndrew Rybchenko 	*valuep = MCDI_OUT_DWORD(req, GET_NIC_GLOBAL_OUT_VALUE);
253617bcc056SAndrew Rybchenko 
253717bcc056SAndrew Rybchenko 	return (0);
253817bcc056SAndrew Rybchenko 
253917bcc056SAndrew Rybchenko fail2:
254017bcc056SAndrew Rybchenko 	EFSYS_PROBE(fail2);
254117bcc056SAndrew Rybchenko fail1:
254217bcc056SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
254317bcc056SAndrew Rybchenko 
254417bcc056SAndrew Rybchenko 	return (rc);
254517bcc056SAndrew Rybchenko }
254617bcc056SAndrew Rybchenko 
254717bcc056SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_mcdi_set_nic_global(__in efx_nic_t * enp,__in uint32_t key,__in uint32_t value)254817bcc056SAndrew Rybchenko efx_mcdi_set_nic_global(
254917bcc056SAndrew Rybchenko 	__in		efx_nic_t *enp,
255017bcc056SAndrew Rybchenko 	__in		uint32_t key,
255117bcc056SAndrew Rybchenko 	__in		uint32_t value)
255217bcc056SAndrew Rybchenko {
255317bcc056SAndrew Rybchenko 	efx_mcdi_req_t req;
2554315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SET_NIC_GLOBAL_IN_LEN, 0);
255517bcc056SAndrew Rybchenko 	efx_rc_t rc;
255617bcc056SAndrew Rybchenko 
255717bcc056SAndrew Rybchenko 	req.emr_cmd = MC_CMD_SET_NIC_GLOBAL;
255817bcc056SAndrew Rybchenko 	req.emr_in_buf = payload;
255917bcc056SAndrew Rybchenko 	req.emr_in_length = MC_CMD_SET_NIC_GLOBAL_IN_LEN;
256017bcc056SAndrew Rybchenko 	req.emr_out_buf = NULL;
256117bcc056SAndrew Rybchenko 	req.emr_out_length = 0;
256217bcc056SAndrew Rybchenko 
256317bcc056SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, SET_NIC_GLOBAL_IN_KEY, key);
256417bcc056SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, SET_NIC_GLOBAL_IN_VALUE, value);
256517bcc056SAndrew Rybchenko 
256617bcc056SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
256717bcc056SAndrew Rybchenko 
256817bcc056SAndrew Rybchenko 	if (req.emr_rc != 0) {
256917bcc056SAndrew Rybchenko 		rc = req.emr_rc;
257017bcc056SAndrew Rybchenko 		goto fail1;
257117bcc056SAndrew Rybchenko 	}
257217bcc056SAndrew Rybchenko 
257317bcc056SAndrew Rybchenko 	return (0);
257417bcc056SAndrew Rybchenko 
257517bcc056SAndrew Rybchenko fail1:
257617bcc056SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
257717bcc056SAndrew Rybchenko 
257817bcc056SAndrew Rybchenko 	return (rc);
257917bcc056SAndrew Rybchenko }
258017bcc056SAndrew Rybchenko 
258117bcc056SAndrew Rybchenko #endif	/* EFSYS_OPT_FW_SUBVARIANT_AWARE */
258231bf5f03SAndrew Rybchenko 
2583ae64ac93SAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
2584