xref: /freebsd/sys/dev/sfxge/common/ef10_phy.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1647112a4SAndrew Rybchenko /*-
2929c7febSAndrew Rybchenko  * Copyright (c) 2012-2016 Solarflare Communications Inc.
3647112a4SAndrew Rybchenko  * All rights reserved.
4647112a4SAndrew Rybchenko  *
5647112a4SAndrew Rybchenko  * Redistribution and use in source and binary forms, with or without
6647112a4SAndrew Rybchenko  * modification, are permitted provided that the following conditions are met:
7647112a4SAndrew Rybchenko  *
8647112a4SAndrew Rybchenko  * 1. Redistributions of source code must retain the above copyright notice,
9647112a4SAndrew Rybchenko  *    this list of conditions and the following disclaimer.
10647112a4SAndrew Rybchenko  * 2. Redistributions in binary form must reproduce the above copyright notice,
11647112a4SAndrew Rybchenko  *    this list of conditions and the following disclaimer in the documentation
12647112a4SAndrew Rybchenko  *    and/or other materials provided with the distribution.
13647112a4SAndrew Rybchenko  *
14647112a4SAndrew Rybchenko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15647112a4SAndrew Rybchenko  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16647112a4SAndrew Rybchenko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17647112a4SAndrew Rybchenko  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18647112a4SAndrew Rybchenko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19647112a4SAndrew Rybchenko  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20647112a4SAndrew Rybchenko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21647112a4SAndrew Rybchenko  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22647112a4SAndrew Rybchenko  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23647112a4SAndrew Rybchenko  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24647112a4SAndrew Rybchenko  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25647112a4SAndrew Rybchenko  *
26647112a4SAndrew Rybchenko  * The views and conclusions contained in the software and documentation are
27647112a4SAndrew Rybchenko  * those of the authors and should not be interpreted as representing official
28647112a4SAndrew Rybchenko  * policies, either expressed or implied, of the FreeBSD Project.
29647112a4SAndrew Rybchenko  */
30647112a4SAndrew Rybchenko 
31647112a4SAndrew Rybchenko #include <sys/cdefs.h>
32647112a4SAndrew Rybchenko #include "efx.h"
33647112a4SAndrew Rybchenko #include "efx_impl.h"
34647112a4SAndrew Rybchenko 
3510d4c14dSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
36647112a4SAndrew Rybchenko 
37647112a4SAndrew Rybchenko static			void
mcdi_phy_decode_cap(__in uint32_t mcdi_cap,__out uint32_t * maskp)38647112a4SAndrew Rybchenko mcdi_phy_decode_cap(
39647112a4SAndrew Rybchenko 	__in		uint32_t mcdi_cap,
40647112a4SAndrew Rybchenko 	__out		uint32_t *maskp)
41647112a4SAndrew Rybchenko {
42647112a4SAndrew Rybchenko 	uint32_t mask;
43647112a4SAndrew Rybchenko 
44d81df221SAndrew Rybchenko #define	CHECK_CAP(_cap) \
45d81df221SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_PHY_CAP_##_cap == MC_CMD_PHY_CAP_##_cap##_LBN)
46d81df221SAndrew Rybchenko 
47d81df221SAndrew Rybchenko 	CHECK_CAP(10HDX);
48d81df221SAndrew Rybchenko 	CHECK_CAP(10FDX);
49d81df221SAndrew Rybchenko 	CHECK_CAP(100HDX);
50d81df221SAndrew Rybchenko 	CHECK_CAP(100FDX);
51d81df221SAndrew Rybchenko 	CHECK_CAP(1000HDX);
52d81df221SAndrew Rybchenko 	CHECK_CAP(1000FDX);
53d81df221SAndrew Rybchenko 	CHECK_CAP(10000FDX);
54d81df221SAndrew Rybchenko 	CHECK_CAP(25000FDX);
55d81df221SAndrew Rybchenko 	CHECK_CAP(40000FDX);
56d81df221SAndrew Rybchenko 	CHECK_CAP(50000FDX);
57d81df221SAndrew Rybchenko 	CHECK_CAP(100000FDX);
58d81df221SAndrew Rybchenko 	CHECK_CAP(PAUSE);
59d81df221SAndrew Rybchenko 	CHECK_CAP(ASYM);
60d81df221SAndrew Rybchenko 	CHECK_CAP(AN);
61d81df221SAndrew Rybchenko 	CHECK_CAP(DDM);
62ffde7424SAndrew Rybchenko 	CHECK_CAP(BASER_FEC);
63ffde7424SAndrew Rybchenko 	CHECK_CAP(BASER_FEC_REQUESTED);
64ffde7424SAndrew Rybchenko 	CHECK_CAP(RS_FEC);
65ffde7424SAndrew Rybchenko 	CHECK_CAP(RS_FEC_REQUESTED);
66ffde7424SAndrew Rybchenko 	CHECK_CAP(25G_BASER_FEC);
67ffde7424SAndrew Rybchenko 	CHECK_CAP(25G_BASER_FEC_REQUESTED);
68d81df221SAndrew Rybchenko #undef CHECK_CAP
69d81df221SAndrew Rybchenko 
70647112a4SAndrew Rybchenko 	mask = 0;
71647112a4SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
72647112a4SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_10HDX);
73647112a4SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
74647112a4SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_10FDX);
75647112a4SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
76647112a4SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_100HDX);
77647112a4SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
78647112a4SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_100FDX);
79647112a4SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
80647112a4SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_1000HDX);
81647112a4SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
82647112a4SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_1000FDX);
83647112a4SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
84647112a4SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_10000FDX);
85d81df221SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25000FDX_LBN))
86d81df221SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_25000FDX);
87647112a4SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))
88647112a4SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_40000FDX);
89d81df221SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_50000FDX_LBN))
90d81df221SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_50000FDX);
91d81df221SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100000FDX_LBN))
92d81df221SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_100000FDX);
93d81df221SAndrew Rybchenko 
94647112a4SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
95647112a4SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_PAUSE);
96647112a4SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
97647112a4SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_ASYM);
98647112a4SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
99647112a4SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_AN);
100647112a4SAndrew Rybchenko 
101ffde7424SAndrew Rybchenko 	/* FEC caps (supported on Medford2 and later) */
102ffde7424SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN))
103ffde7424SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_BASER_FEC);
104ffde7424SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_REQUESTED_LBN))
105ffde7424SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_BASER_FEC_REQUESTED);
106ffde7424SAndrew Rybchenko 
107ffde7424SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_LBN))
108ffde7424SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_RS_FEC);
109ffde7424SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_REQUESTED_LBN))
110ffde7424SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_RS_FEC_REQUESTED);
111ffde7424SAndrew Rybchenko 
112ffde7424SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN))
113ffde7424SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_25G_BASER_FEC);
114ffde7424SAndrew Rybchenko 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_REQUESTED_LBN))
115ffde7424SAndrew Rybchenko 		mask |= (1 << EFX_PHY_CAP_25G_BASER_FEC_REQUESTED);
116ffde7424SAndrew Rybchenko 
117647112a4SAndrew Rybchenko 	*maskp = mask;
118647112a4SAndrew Rybchenko }
119647112a4SAndrew Rybchenko 
120647112a4SAndrew Rybchenko static			void
mcdi_phy_decode_link_mode(__in efx_nic_t * enp,__in uint32_t link_flags,__in unsigned int speed,__in unsigned int fcntl,__in uint32_t fec,__out efx_link_mode_t * link_modep,__out unsigned int * fcntlp,__out efx_phy_fec_type_t * fecp)121647112a4SAndrew Rybchenko mcdi_phy_decode_link_mode(
122647112a4SAndrew Rybchenko 	__in		efx_nic_t *enp,
123647112a4SAndrew Rybchenko 	__in		uint32_t link_flags,
124647112a4SAndrew Rybchenko 	__in		unsigned int speed,
125647112a4SAndrew Rybchenko 	__in		unsigned int fcntl,
126a8c1489fSAndrew Rybchenko 	__in		uint32_t fec,
127647112a4SAndrew Rybchenko 	__out		efx_link_mode_t *link_modep,
128a8c1489fSAndrew Rybchenko 	__out		unsigned int *fcntlp,
129a8c1489fSAndrew Rybchenko 	__out		efx_phy_fec_type_t *fecp)
130647112a4SAndrew Rybchenko {
131647112a4SAndrew Rybchenko 	boolean_t fd = !!(link_flags &
132647112a4SAndrew Rybchenko 		    (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
133647112a4SAndrew Rybchenko 	boolean_t up = !!(link_flags &
134647112a4SAndrew Rybchenko 		    (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
135647112a4SAndrew Rybchenko 
136647112a4SAndrew Rybchenko 	_NOTE(ARGUNUSED(enp))
137647112a4SAndrew Rybchenko 
138647112a4SAndrew Rybchenko 	if (!up)
139647112a4SAndrew Rybchenko 		*link_modep = EFX_LINK_DOWN;
140d81df221SAndrew Rybchenko 	else if (speed == 100000 && fd)
141d81df221SAndrew Rybchenko 		*link_modep = EFX_LINK_100000FDX;
142d81df221SAndrew Rybchenko 	else if (speed == 50000 && fd)
143d81df221SAndrew Rybchenko 		*link_modep = EFX_LINK_50000FDX;
144647112a4SAndrew Rybchenko 	else if (speed == 40000 && fd)
145647112a4SAndrew Rybchenko 		*link_modep = EFX_LINK_40000FDX;
146d81df221SAndrew Rybchenko 	else if (speed == 25000 && fd)
147d81df221SAndrew Rybchenko 		*link_modep = EFX_LINK_25000FDX;
148647112a4SAndrew Rybchenko 	else if (speed == 10000 && fd)
149647112a4SAndrew Rybchenko 		*link_modep = EFX_LINK_10000FDX;
150647112a4SAndrew Rybchenko 	else if (speed == 1000)
151647112a4SAndrew Rybchenko 		*link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
152647112a4SAndrew Rybchenko 	else if (speed == 100)
153647112a4SAndrew Rybchenko 		*link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
154647112a4SAndrew Rybchenko 	else if (speed == 10)
155647112a4SAndrew Rybchenko 		*link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
156647112a4SAndrew Rybchenko 	else
157647112a4SAndrew Rybchenko 		*link_modep = EFX_LINK_UNKNOWN;
158647112a4SAndrew Rybchenko 
159647112a4SAndrew Rybchenko 	if (fcntl == MC_CMD_FCNTL_OFF)
160647112a4SAndrew Rybchenko 		*fcntlp = 0;
161647112a4SAndrew Rybchenko 	else if (fcntl == MC_CMD_FCNTL_RESPOND)
162647112a4SAndrew Rybchenko 		*fcntlp = EFX_FCNTL_RESPOND;
163647112a4SAndrew Rybchenko 	else if (fcntl == MC_CMD_FCNTL_GENERATE)
164647112a4SAndrew Rybchenko 		*fcntlp = EFX_FCNTL_GENERATE;
165647112a4SAndrew Rybchenko 	else if (fcntl == MC_CMD_FCNTL_BIDIR)
166647112a4SAndrew Rybchenko 		*fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
167647112a4SAndrew Rybchenko 	else {
168647112a4SAndrew Rybchenko 		EFSYS_PROBE1(mc_pcol_error, int, fcntl);
169647112a4SAndrew Rybchenko 		*fcntlp = 0;
170647112a4SAndrew Rybchenko 	}
171a8c1489fSAndrew Rybchenko 
172a8c1489fSAndrew Rybchenko 	switch (fec) {
173a8c1489fSAndrew Rybchenko 	case MC_CMD_FEC_NONE:
174a8c1489fSAndrew Rybchenko 		*fecp = EFX_PHY_FEC_NONE;
175a8c1489fSAndrew Rybchenko 		break;
176a8c1489fSAndrew Rybchenko 	case MC_CMD_FEC_BASER:
177a8c1489fSAndrew Rybchenko 		*fecp = EFX_PHY_FEC_BASER;
178a8c1489fSAndrew Rybchenko 		break;
179a8c1489fSAndrew Rybchenko 	case MC_CMD_FEC_RS:
180a8c1489fSAndrew Rybchenko 		*fecp = EFX_PHY_FEC_RS;
181a8c1489fSAndrew Rybchenko 		break;
182a8c1489fSAndrew Rybchenko 	default:
183a8c1489fSAndrew Rybchenko 		EFSYS_PROBE1(mc_pcol_error, int, fec);
184a8c1489fSAndrew Rybchenko 		*fecp = EFX_PHY_FEC_NONE;
185a8c1489fSAndrew Rybchenko 		break;
186a8c1489fSAndrew Rybchenko 	}
187647112a4SAndrew Rybchenko }
188647112a4SAndrew Rybchenko 
189647112a4SAndrew Rybchenko 			void
ef10_phy_link_ev(__in efx_nic_t * enp,__in efx_qword_t * eqp,__out efx_link_mode_t * link_modep)190647112a4SAndrew Rybchenko ef10_phy_link_ev(
191647112a4SAndrew Rybchenko 	__in		efx_nic_t *enp,
192647112a4SAndrew Rybchenko 	__in		efx_qword_t *eqp,
193647112a4SAndrew Rybchenko 	__out		efx_link_mode_t *link_modep)
194647112a4SAndrew Rybchenko {
195647112a4SAndrew Rybchenko 	efx_port_t *epp = &(enp->en_port);
196647112a4SAndrew Rybchenko 	unsigned int link_flags;
197647112a4SAndrew Rybchenko 	unsigned int speed;
198647112a4SAndrew Rybchenko 	unsigned int fcntl;
199a8c1489fSAndrew Rybchenko 	efx_phy_fec_type_t fec = MC_CMD_FEC_NONE;
200647112a4SAndrew Rybchenko 	efx_link_mode_t link_mode;
201647112a4SAndrew Rybchenko 	uint32_t lp_cap_mask;
202647112a4SAndrew Rybchenko 
203647112a4SAndrew Rybchenko 	/*
204647112a4SAndrew Rybchenko 	 * Convert the LINKCHANGE speed enumeration into mbit/s, in the
205647112a4SAndrew Rybchenko 	 * same way as GET_LINK encodes the speed
206647112a4SAndrew Rybchenko 	 */
207647112a4SAndrew Rybchenko 	switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) {
208647112a4SAndrew Rybchenko 	case MCDI_EVENT_LINKCHANGE_SPEED_100M:
209647112a4SAndrew Rybchenko 		speed = 100;
210647112a4SAndrew Rybchenko 		break;
211647112a4SAndrew Rybchenko 	case MCDI_EVENT_LINKCHANGE_SPEED_1G:
212647112a4SAndrew Rybchenko 		speed = 1000;
213647112a4SAndrew Rybchenko 		break;
214647112a4SAndrew Rybchenko 	case MCDI_EVENT_LINKCHANGE_SPEED_10G:
215647112a4SAndrew Rybchenko 		speed = 10000;
216647112a4SAndrew Rybchenko 		break;
217f50efe9aSAndrew Rybchenko 	case MCDI_EVENT_LINKCHANGE_SPEED_25G:
218f50efe9aSAndrew Rybchenko 		speed = 25000;
219f50efe9aSAndrew Rybchenko 		break;
220647112a4SAndrew Rybchenko 	case MCDI_EVENT_LINKCHANGE_SPEED_40G:
221647112a4SAndrew Rybchenko 		speed = 40000;
222647112a4SAndrew Rybchenko 		break;
223f50efe9aSAndrew Rybchenko 	case MCDI_EVENT_LINKCHANGE_SPEED_50G:
224f50efe9aSAndrew Rybchenko 		speed = 50000;
225f50efe9aSAndrew Rybchenko 		break;
226f50efe9aSAndrew Rybchenko 	case MCDI_EVENT_LINKCHANGE_SPEED_100G:
227f50efe9aSAndrew Rybchenko 		speed = 100000;
228f50efe9aSAndrew Rybchenko 		break;
229647112a4SAndrew Rybchenko 	default:
230647112a4SAndrew Rybchenko 		speed = 0;
231647112a4SAndrew Rybchenko 		break;
232647112a4SAndrew Rybchenko 	}
233647112a4SAndrew Rybchenko 
234647112a4SAndrew Rybchenko 	link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS);
235647112a4SAndrew Rybchenko 	mcdi_phy_decode_link_mode(enp, link_flags, speed,
236647112a4SAndrew Rybchenko 				    MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL),
237a8c1489fSAndrew Rybchenko 				    MC_CMD_FEC_NONE, &link_mode,
238a8c1489fSAndrew Rybchenko 				    &fcntl, &fec);
239647112a4SAndrew Rybchenko 	mcdi_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP),
240647112a4SAndrew Rybchenko 			    &lp_cap_mask);
241647112a4SAndrew Rybchenko 
242647112a4SAndrew Rybchenko 	/*
243647112a4SAndrew Rybchenko 	 * It's safe to update ep_lp_cap_mask without the driver's port lock
244647112a4SAndrew Rybchenko 	 * because presumably any concurrently running efx_port_poll() is
245647112a4SAndrew Rybchenko 	 * only going to arrive at the same value.
246647112a4SAndrew Rybchenko 	 *
247647112a4SAndrew Rybchenko 	 * ep_fcntl has two meanings. It's either the link common fcntl
248647112a4SAndrew Rybchenko 	 * (if the PHY supports AN), or it's the forced link state. If
249647112a4SAndrew Rybchenko 	 * the former, it's safe to update the value for the same reason as
250647112a4SAndrew Rybchenko 	 * for ep_lp_cap_mask. If the latter, then just ignore the value,
251647112a4SAndrew Rybchenko 	 * because we can race with efx_mac_fcntl_set().
252647112a4SAndrew Rybchenko 	 */
253647112a4SAndrew Rybchenko 	epp->ep_lp_cap_mask = lp_cap_mask;
254647112a4SAndrew Rybchenko 	epp->ep_fcntl = fcntl;
255647112a4SAndrew Rybchenko 
256647112a4SAndrew Rybchenko 	*link_modep = link_mode;
257647112a4SAndrew Rybchenko }
258647112a4SAndrew Rybchenko 
259647112a4SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_phy_power(__in efx_nic_t * enp,__in boolean_t power)260647112a4SAndrew Rybchenko ef10_phy_power(
261647112a4SAndrew Rybchenko 	__in		efx_nic_t *enp,
262647112a4SAndrew Rybchenko 	__in		boolean_t power)
263647112a4SAndrew Rybchenko {
264647112a4SAndrew Rybchenko 	efx_rc_t rc;
265647112a4SAndrew Rybchenko 
266647112a4SAndrew Rybchenko 	if (!power)
267647112a4SAndrew Rybchenko 		return (0);
268647112a4SAndrew Rybchenko 
269647112a4SAndrew Rybchenko 	/* Check if the PHY is a zombie */
270647112a4SAndrew Rybchenko 	if ((rc = ef10_phy_verify(enp)) != 0)
271647112a4SAndrew Rybchenko 		goto fail1;
272647112a4SAndrew Rybchenko 
273647112a4SAndrew Rybchenko 	enp->en_reset_flags |= EFX_RESET_PHY;
274647112a4SAndrew Rybchenko 
275647112a4SAndrew Rybchenko 	return (0);
276647112a4SAndrew Rybchenko 
277647112a4SAndrew Rybchenko fail1:
278647112a4SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
279647112a4SAndrew Rybchenko 
280647112a4SAndrew Rybchenko 	return (rc);
281647112a4SAndrew Rybchenko }
282647112a4SAndrew Rybchenko 
283647112a4SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_phy_get_link(__in efx_nic_t * enp,__out ef10_link_state_t * elsp)284647112a4SAndrew Rybchenko ef10_phy_get_link(
285647112a4SAndrew Rybchenko 	__in		efx_nic_t *enp,
286647112a4SAndrew Rybchenko 	__out		ef10_link_state_t *elsp)
287647112a4SAndrew Rybchenko {
288647112a4SAndrew Rybchenko 	efx_mcdi_req_t req;
289a8c1489fSAndrew Rybchenko 	uint32_t fec;
290315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LINK_IN_LEN,
291a8c1489fSAndrew Rybchenko 		MC_CMD_GET_LINK_OUT_V2_LEN);
292647112a4SAndrew Rybchenko 	efx_rc_t rc;
293647112a4SAndrew Rybchenko 
294647112a4SAndrew Rybchenko 	req.emr_cmd = MC_CMD_GET_LINK;
295647112a4SAndrew Rybchenko 	req.emr_in_buf = payload;
296647112a4SAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
297647112a4SAndrew Rybchenko 	req.emr_out_buf = payload;
298a8c1489fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_LINK_OUT_V2_LEN;
299647112a4SAndrew Rybchenko 
300647112a4SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
301647112a4SAndrew Rybchenko 
302647112a4SAndrew Rybchenko 	if (req.emr_rc != 0) {
303647112a4SAndrew Rybchenko 		rc = req.emr_rc;
304647112a4SAndrew Rybchenko 		goto fail1;
305647112a4SAndrew Rybchenko 	}
306647112a4SAndrew Rybchenko 
307647112a4SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
308647112a4SAndrew Rybchenko 		rc = EMSGSIZE;
309647112a4SAndrew Rybchenko 		goto fail2;
310647112a4SAndrew Rybchenko 	}
311647112a4SAndrew Rybchenko 
312647112a4SAndrew Rybchenko 	mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
313cf94ca37SAndrew Rybchenko 			    &elsp->epls.epls_adv_cap_mask);
314647112a4SAndrew Rybchenko 	mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
315cf94ca37SAndrew Rybchenko 			    &elsp->epls.epls_lp_cap_mask);
316647112a4SAndrew Rybchenko 
317a8c1489fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_V2_LEN)
318a8c1489fSAndrew Rybchenko 		fec = MC_CMD_FEC_NONE;
319a8c1489fSAndrew Rybchenko 	else
320a8c1489fSAndrew Rybchenko 		fec = MCDI_OUT_DWORD(req, GET_LINK_OUT_V2_FEC_TYPE);
321a8c1489fSAndrew Rybchenko 
322647112a4SAndrew Rybchenko 	mcdi_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
323647112a4SAndrew Rybchenko 			    MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
324647112a4SAndrew Rybchenko 			    MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
325cf94ca37SAndrew Rybchenko 			    fec, &elsp->epls.epls_link_mode,
326cf94ca37SAndrew Rybchenko 			    &elsp->epls.epls_fcntl, &elsp->epls.epls_fec);
327cf94ca37SAndrew Rybchenko 
328cf94ca37SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_V2_LEN) {
329cf94ca37SAndrew Rybchenko 		elsp->epls.epls_ld_cap_mask = 0;
330cf94ca37SAndrew Rybchenko 	} else {
331cf94ca37SAndrew Rybchenko 		mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_V2_LD_CAP),
332cf94ca37SAndrew Rybchenko 				    &elsp->epls.epls_ld_cap_mask);
333cf94ca37SAndrew Rybchenko 	}
334cf94ca37SAndrew Rybchenko 
335647112a4SAndrew Rybchenko #if EFSYS_OPT_LOOPBACK
3364add9918SAndrew Rybchenko 	/*
3374add9918SAndrew Rybchenko 	 * MC_CMD_LOOPBACK and EFX_LOOPBACK names are equivalent, so use the
3384add9918SAndrew Rybchenko 	 * MCDI value directly. Agreement is checked in efx_loopback_mask().
3394add9918SAndrew Rybchenko 	 */
340647112a4SAndrew Rybchenko 	elsp->els_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
341647112a4SAndrew Rybchenko #endif	/* EFSYS_OPT_LOOPBACK */
342647112a4SAndrew Rybchenko 
343647112a4SAndrew Rybchenko 	elsp->els_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
344647112a4SAndrew Rybchenko 
345647112a4SAndrew Rybchenko 	return (0);
346647112a4SAndrew Rybchenko 
347647112a4SAndrew Rybchenko fail2:
348647112a4SAndrew Rybchenko 	EFSYS_PROBE(fail2);
349647112a4SAndrew Rybchenko fail1:
350647112a4SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
351647112a4SAndrew Rybchenko 
352647112a4SAndrew Rybchenko 	return (rc);
353647112a4SAndrew Rybchenko }
354647112a4SAndrew Rybchenko 
355647112a4SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_phy_reconfigure(__in efx_nic_t * enp)356647112a4SAndrew Rybchenko ef10_phy_reconfigure(
357647112a4SAndrew Rybchenko 	__in		efx_nic_t *enp)
358647112a4SAndrew Rybchenko {
359647112a4SAndrew Rybchenko 	efx_port_t *epp = &(enp->en_port);
360647112a4SAndrew Rybchenko 	efx_mcdi_req_t req;
361315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SET_LINK_IN_LEN,
362315bbbaaSAndrew Rybchenko 		MC_CMD_SET_LINK_OUT_LEN);
363647112a4SAndrew Rybchenko 	uint32_t cap_mask;
364c68c424cSAndrew Rybchenko #if EFSYS_OPT_PHY_LED_CONTROL
365647112a4SAndrew Rybchenko 	unsigned int led_mode;
366c68c424cSAndrew Rybchenko #endif
367647112a4SAndrew Rybchenko 	unsigned int speed;
3687fb55c62SAndrew Rybchenko 	boolean_t supported;
369647112a4SAndrew Rybchenko 	efx_rc_t rc;
370647112a4SAndrew Rybchenko 
3717fb55c62SAndrew Rybchenko 	if ((rc = efx_mcdi_link_control_supported(enp, &supported)) != 0)
3727fb55c62SAndrew Rybchenko 		goto fail1;
3737fb55c62SAndrew Rybchenko 	if (supported == B_FALSE)
374647112a4SAndrew Rybchenko 		goto out;
375647112a4SAndrew Rybchenko 
376647112a4SAndrew Rybchenko 	req.emr_cmd = MC_CMD_SET_LINK;
377647112a4SAndrew Rybchenko 	req.emr_in_buf = payload;
378647112a4SAndrew Rybchenko 	req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
379647112a4SAndrew Rybchenko 	req.emr_out_buf = payload;
380647112a4SAndrew Rybchenko 	req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;
381647112a4SAndrew Rybchenko 
382647112a4SAndrew Rybchenko 	cap_mask = epp->ep_adv_cap_mask;
383647112a4SAndrew Rybchenko 	MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
384647112a4SAndrew Rybchenko 		PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
385647112a4SAndrew Rybchenko 		PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
386647112a4SAndrew Rybchenko 		PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
387647112a4SAndrew Rybchenko 		PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
388647112a4SAndrew Rybchenko 		PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
389647112a4SAndrew Rybchenko 		PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
390647112a4SAndrew Rybchenko 		PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
391647112a4SAndrew Rybchenko 		PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
392647112a4SAndrew Rybchenko 		PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
393647112a4SAndrew Rybchenko 		PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
394*db739f1cSGordon Bergling 	/* Too many fields for POPULATE macros, so insert this afterwards */
395647112a4SAndrew Rybchenko 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
396d81df221SAndrew Rybchenko 	    PHY_CAP_25000FDX, (cap_mask >> EFX_PHY_CAP_25000FDX) & 0x1);
397d81df221SAndrew Rybchenko 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
398647112a4SAndrew Rybchenko 	    PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1);
399d81df221SAndrew Rybchenko 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
400d81df221SAndrew Rybchenko 	    PHY_CAP_50000FDX, (cap_mask >> EFX_PHY_CAP_50000FDX) & 0x1);
401d81df221SAndrew Rybchenko 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
402d81df221SAndrew Rybchenko 	    PHY_CAP_100000FDX, (cap_mask >> EFX_PHY_CAP_100000FDX) & 0x1);
403647112a4SAndrew Rybchenko 
404ffde7424SAndrew Rybchenko 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
405ffde7424SAndrew Rybchenko 	    PHY_CAP_BASER_FEC, (cap_mask >> EFX_PHY_CAP_BASER_FEC) & 0x1);
406ffde7424SAndrew Rybchenko 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
407ffde7424SAndrew Rybchenko 	    PHY_CAP_BASER_FEC_REQUESTED,
408ffde7424SAndrew Rybchenko 	    (cap_mask >> EFX_PHY_CAP_BASER_FEC_REQUESTED) & 0x1);
409ffde7424SAndrew Rybchenko 
410ffde7424SAndrew Rybchenko 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
411ffde7424SAndrew Rybchenko 	    PHY_CAP_RS_FEC, (cap_mask >> EFX_PHY_CAP_RS_FEC) & 0x1);
412ffde7424SAndrew Rybchenko 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
413ffde7424SAndrew Rybchenko 	    PHY_CAP_RS_FEC_REQUESTED,
414ffde7424SAndrew Rybchenko 	    (cap_mask >> EFX_PHY_CAP_RS_FEC_REQUESTED) & 0x1);
415ffde7424SAndrew Rybchenko 
416ffde7424SAndrew Rybchenko 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
417ffde7424SAndrew Rybchenko 	    PHY_CAP_25G_BASER_FEC,
418ffde7424SAndrew Rybchenko 	    (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC) & 0x1);
419ffde7424SAndrew Rybchenko 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
420ffde7424SAndrew Rybchenko 	    PHY_CAP_25G_BASER_FEC_REQUESTED,
421ffde7424SAndrew Rybchenko 	    (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC_REQUESTED) & 0x1);
422ffde7424SAndrew Rybchenko 
423647112a4SAndrew Rybchenko #if EFSYS_OPT_LOOPBACK
424647112a4SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
425647112a4SAndrew Rybchenko 		    epp->ep_loopback_type);
426647112a4SAndrew Rybchenko 	switch (epp->ep_loopback_link_mode) {
427647112a4SAndrew Rybchenko 	case EFX_LINK_100FDX:
428647112a4SAndrew Rybchenko 		speed = 100;
429647112a4SAndrew Rybchenko 		break;
430647112a4SAndrew Rybchenko 	case EFX_LINK_1000FDX:
431647112a4SAndrew Rybchenko 		speed = 1000;
432647112a4SAndrew Rybchenko 		break;
433647112a4SAndrew Rybchenko 	case EFX_LINK_10000FDX:
434647112a4SAndrew Rybchenko 		speed = 10000;
435647112a4SAndrew Rybchenko 		break;
436d81df221SAndrew Rybchenko 	case EFX_LINK_25000FDX:
437d81df221SAndrew Rybchenko 		speed = 25000;
438d81df221SAndrew Rybchenko 		break;
439647112a4SAndrew Rybchenko 	case EFX_LINK_40000FDX:
440647112a4SAndrew Rybchenko 		speed = 40000;
441647112a4SAndrew Rybchenko 		break;
442d81df221SAndrew Rybchenko 	case EFX_LINK_50000FDX:
443d81df221SAndrew Rybchenko 		speed = 50000;
444d81df221SAndrew Rybchenko 		break;
445d81df221SAndrew Rybchenko 	case EFX_LINK_100000FDX:
446d81df221SAndrew Rybchenko 		speed = 100000;
447d81df221SAndrew Rybchenko 		break;
448647112a4SAndrew Rybchenko 	default:
449647112a4SAndrew Rybchenko 		speed = 0;
450647112a4SAndrew Rybchenko 	}
451647112a4SAndrew Rybchenko #else
452647112a4SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
453647112a4SAndrew Rybchenko 	speed = 0;
454647112a4SAndrew Rybchenko #endif	/* EFSYS_OPT_LOOPBACK */
455647112a4SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
456647112a4SAndrew Rybchenko 
457647112a4SAndrew Rybchenko #if EFSYS_OPT_PHY_FLAGS
458647112a4SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
459647112a4SAndrew Rybchenko #else
460647112a4SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
461647112a4SAndrew Rybchenko #endif	/* EFSYS_OPT_PHY_FLAGS */
462647112a4SAndrew Rybchenko 
463647112a4SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
464647112a4SAndrew Rybchenko 
465647112a4SAndrew Rybchenko 	if (req.emr_rc != 0) {
466647112a4SAndrew Rybchenko 		rc = req.emr_rc;
4677fb55c62SAndrew Rybchenko 		goto fail2;
468647112a4SAndrew Rybchenko 	}
469647112a4SAndrew Rybchenko 
470647112a4SAndrew Rybchenko 	/* And set the blink mode */
471647112a4SAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
472647112a4SAndrew Rybchenko 	req.emr_cmd = MC_CMD_SET_ID_LED;
473647112a4SAndrew Rybchenko 	req.emr_in_buf = payload;
474647112a4SAndrew Rybchenko 	req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
475647112a4SAndrew Rybchenko 	req.emr_out_buf = payload;
476647112a4SAndrew Rybchenko 	req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;
477647112a4SAndrew Rybchenko 
478647112a4SAndrew Rybchenko #if EFSYS_OPT_PHY_LED_CONTROL
479647112a4SAndrew Rybchenko 	switch (epp->ep_phy_led_mode) {
480647112a4SAndrew Rybchenko 	case EFX_PHY_LED_DEFAULT:
481647112a4SAndrew Rybchenko 		led_mode = MC_CMD_LED_DEFAULT;
482647112a4SAndrew Rybchenko 		break;
483647112a4SAndrew Rybchenko 	case EFX_PHY_LED_OFF:
484647112a4SAndrew Rybchenko 		led_mode = MC_CMD_LED_OFF;
485647112a4SAndrew Rybchenko 		break;
486647112a4SAndrew Rybchenko 	case EFX_PHY_LED_ON:
487647112a4SAndrew Rybchenko 		led_mode = MC_CMD_LED_ON;
488647112a4SAndrew Rybchenko 		break;
489647112a4SAndrew Rybchenko 	default:
490647112a4SAndrew Rybchenko 		EFSYS_ASSERT(0);
491647112a4SAndrew Rybchenko 		led_mode = MC_CMD_LED_DEFAULT;
492647112a4SAndrew Rybchenko 	}
493647112a4SAndrew Rybchenko 
494647112a4SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
495647112a4SAndrew Rybchenko #else
496647112a4SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
497647112a4SAndrew Rybchenko #endif	/* EFSYS_OPT_PHY_LED_CONTROL */
498647112a4SAndrew Rybchenko 
499647112a4SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
500647112a4SAndrew Rybchenko 
501647112a4SAndrew Rybchenko 	if (req.emr_rc != 0) {
502647112a4SAndrew Rybchenko 		rc = req.emr_rc;
5037fb55c62SAndrew Rybchenko 		goto fail3;
504647112a4SAndrew Rybchenko 	}
505647112a4SAndrew Rybchenko out:
506647112a4SAndrew Rybchenko 	return (0);
507647112a4SAndrew Rybchenko 
5087fb55c62SAndrew Rybchenko fail3:
5097fb55c62SAndrew Rybchenko 	EFSYS_PROBE(fail3);
510647112a4SAndrew Rybchenko fail2:
511647112a4SAndrew Rybchenko 	EFSYS_PROBE(fail2);
512647112a4SAndrew Rybchenko fail1:
513647112a4SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
514647112a4SAndrew Rybchenko 
515647112a4SAndrew Rybchenko 	return (rc);
516647112a4SAndrew Rybchenko }
517647112a4SAndrew Rybchenko 
518647112a4SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_phy_verify(__in efx_nic_t * enp)519647112a4SAndrew Rybchenko ef10_phy_verify(
520647112a4SAndrew Rybchenko 	__in		efx_nic_t *enp)
521647112a4SAndrew Rybchenko {
522647112a4SAndrew Rybchenko 	efx_mcdi_req_t req;
523315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_STATE_IN_LEN,
524315bbbaaSAndrew Rybchenko 		MC_CMD_GET_PHY_STATE_OUT_LEN);
525647112a4SAndrew Rybchenko 	uint32_t state;
526647112a4SAndrew Rybchenko 	efx_rc_t rc;
527647112a4SAndrew Rybchenko 
528647112a4SAndrew Rybchenko 	req.emr_cmd = MC_CMD_GET_PHY_STATE;
529647112a4SAndrew Rybchenko 	req.emr_in_buf = payload;
530647112a4SAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
531647112a4SAndrew Rybchenko 	req.emr_out_buf = payload;
532647112a4SAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN;
533647112a4SAndrew Rybchenko 
534647112a4SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
535647112a4SAndrew Rybchenko 
536647112a4SAndrew Rybchenko 	if (req.emr_rc != 0) {
537647112a4SAndrew Rybchenko 		rc = req.emr_rc;
538647112a4SAndrew Rybchenko 		goto fail1;
539647112a4SAndrew Rybchenko 	}
540647112a4SAndrew Rybchenko 
541647112a4SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
542647112a4SAndrew Rybchenko 		rc = EMSGSIZE;
543647112a4SAndrew Rybchenko 		goto fail2;
544647112a4SAndrew Rybchenko 	}
545647112a4SAndrew Rybchenko 
546647112a4SAndrew Rybchenko 	state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
547647112a4SAndrew Rybchenko 	if (state != MC_CMD_PHY_STATE_OK) {
548647112a4SAndrew Rybchenko 		if (state != MC_CMD_PHY_STATE_ZOMBIE)
549647112a4SAndrew Rybchenko 			EFSYS_PROBE1(mc_pcol_error, int, state);
550647112a4SAndrew Rybchenko 		rc = ENOTACTIVE;
551647112a4SAndrew Rybchenko 		goto fail3;
552647112a4SAndrew Rybchenko 	}
553647112a4SAndrew Rybchenko 
554647112a4SAndrew Rybchenko 	return (0);
555647112a4SAndrew Rybchenko 
556647112a4SAndrew Rybchenko fail3:
557647112a4SAndrew Rybchenko 	EFSYS_PROBE(fail3);
558647112a4SAndrew Rybchenko fail2:
559647112a4SAndrew Rybchenko 	EFSYS_PROBE(fail2);
560647112a4SAndrew Rybchenko fail1:
561647112a4SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
562647112a4SAndrew Rybchenko 
563647112a4SAndrew Rybchenko 	return (rc);
564647112a4SAndrew Rybchenko }
565647112a4SAndrew Rybchenko 
566647112a4SAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_phy_oui_get(__in efx_nic_t * enp,__out uint32_t * ouip)567647112a4SAndrew Rybchenko ef10_phy_oui_get(
568647112a4SAndrew Rybchenko 	__in		efx_nic_t *enp,
569647112a4SAndrew Rybchenko 	__out		uint32_t *ouip)
570647112a4SAndrew Rybchenko {
571647112a4SAndrew Rybchenko 	_NOTE(ARGUNUSED(enp, ouip))
572647112a4SAndrew Rybchenko 
573647112a4SAndrew Rybchenko 	return (ENOTSUP);
574647112a4SAndrew Rybchenko }
575647112a4SAndrew Rybchenko 
576a8c1489fSAndrew Rybchenko 	__checkReturn	efx_rc_t
ef10_phy_link_state_get(__in efx_nic_t * enp,__out efx_phy_link_state_t * eplsp)577cf94ca37SAndrew Rybchenko ef10_phy_link_state_get(
578a8c1489fSAndrew Rybchenko 	__in		efx_nic_t *enp,
579cf94ca37SAndrew Rybchenko 	__out		efx_phy_link_state_t  *eplsp)
580a8c1489fSAndrew Rybchenko {
581a8c1489fSAndrew Rybchenko 	efx_rc_t rc;
582a8c1489fSAndrew Rybchenko 	ef10_link_state_t els;
583a8c1489fSAndrew Rybchenko 
584cf94ca37SAndrew Rybchenko 	/* Obtain the active link state */
585a8c1489fSAndrew Rybchenko 	if ((rc = ef10_phy_get_link(enp, &els)) != 0)
586a8c1489fSAndrew Rybchenko 		goto fail1;
587a8c1489fSAndrew Rybchenko 
588cf94ca37SAndrew Rybchenko 	*eplsp = els.epls;
589a8c1489fSAndrew Rybchenko 
590a8c1489fSAndrew Rybchenko 	return (0);
591a8c1489fSAndrew Rybchenko 
592a8c1489fSAndrew Rybchenko fail1:
593a8c1489fSAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
594a8c1489fSAndrew Rybchenko 
595a8c1489fSAndrew Rybchenko 	return (rc);
596a8c1489fSAndrew Rybchenko }
597a8c1489fSAndrew Rybchenko 
598647112a4SAndrew Rybchenko #if EFSYS_OPT_PHY_STATS
599647112a4SAndrew Rybchenko 
600647112a4SAndrew Rybchenko 	__checkReturn				efx_rc_t
ef10_phy_stats_update(__in efx_nic_t * enp,__in efsys_mem_t * esmp,__inout_ecount (EFX_PHY_NSTATS)uint32_t * stat)601647112a4SAndrew Rybchenko ef10_phy_stats_update(
602647112a4SAndrew Rybchenko 	__in					efx_nic_t *enp,
603647112a4SAndrew Rybchenko 	__in					efsys_mem_t *esmp,
604647112a4SAndrew Rybchenko 	__inout_ecount(EFX_PHY_NSTATS)		uint32_t *stat)
605647112a4SAndrew Rybchenko {
606647112a4SAndrew Rybchenko 	/* TBD: no stats support in firmware yet */
607647112a4SAndrew Rybchenko 	_NOTE(ARGUNUSED(enp, esmp))
608647112a4SAndrew Rybchenko 	memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat));
609647112a4SAndrew Rybchenko 
610647112a4SAndrew Rybchenko 	return (0);
611647112a4SAndrew Rybchenko }
612647112a4SAndrew Rybchenko 
613647112a4SAndrew Rybchenko #endif	/* EFSYS_OPT_PHY_STATS */
614647112a4SAndrew Rybchenko 
615cc7a82f5SAndrew Rybchenko #if EFSYS_OPT_BIST
616cc7a82f5SAndrew Rybchenko 
617cc7a82f5SAndrew Rybchenko 	__checkReturn		efx_rc_t
ef10_bist_enable_offline(__in efx_nic_t * enp)618cc7a82f5SAndrew Rybchenko ef10_bist_enable_offline(
619cc7a82f5SAndrew Rybchenko 	__in			efx_nic_t *enp)
620cc7a82f5SAndrew Rybchenko {
621cc7a82f5SAndrew Rybchenko 	efx_rc_t rc;
622cc7a82f5SAndrew Rybchenko 
623cc7a82f5SAndrew Rybchenko 	if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0)
624cc7a82f5SAndrew Rybchenko 		goto fail1;
625cc7a82f5SAndrew Rybchenko 
626cc7a82f5SAndrew Rybchenko 	return (0);
627cc7a82f5SAndrew Rybchenko 
628cc7a82f5SAndrew Rybchenko fail1:
629cc7a82f5SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
630cc7a82f5SAndrew Rybchenko 
631cc7a82f5SAndrew Rybchenko 	return (rc);
632cc7a82f5SAndrew Rybchenko }
633cc7a82f5SAndrew Rybchenko 
634cc7a82f5SAndrew Rybchenko 	__checkReturn		efx_rc_t
ef10_bist_start(__in efx_nic_t * enp,__in efx_bist_type_t type)635cc7a82f5SAndrew Rybchenko ef10_bist_start(
636cc7a82f5SAndrew Rybchenko 	__in			efx_nic_t *enp,
637cc7a82f5SAndrew Rybchenko 	__in			efx_bist_type_t type)
638cc7a82f5SAndrew Rybchenko {
639cc7a82f5SAndrew Rybchenko 	efx_rc_t rc;
640cc7a82f5SAndrew Rybchenko 
641cc7a82f5SAndrew Rybchenko 	if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
642cc7a82f5SAndrew Rybchenko 		goto fail1;
643cc7a82f5SAndrew Rybchenko 
644cc7a82f5SAndrew Rybchenko 	return (0);
645cc7a82f5SAndrew Rybchenko 
646cc7a82f5SAndrew Rybchenko fail1:
647cc7a82f5SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
648cc7a82f5SAndrew Rybchenko 
649cc7a82f5SAndrew Rybchenko 	return (rc);
650cc7a82f5SAndrew Rybchenko }
651cc7a82f5SAndrew Rybchenko 
652cc7a82f5SAndrew Rybchenko 	__checkReturn		efx_rc_t
653cc7a82f5SAndrew Rybchenko ef10_bist_poll(
654cc7a82f5SAndrew Rybchenko 	__in			efx_nic_t *enp,
655cc7a82f5SAndrew Rybchenko 	__in			efx_bist_type_t type,
656cc7a82f5SAndrew Rybchenko 	__out			efx_bist_result_t *resultp,
657cc7a82f5SAndrew Rybchenko 	__out_opt __drv_when(count > 0, __notnull)
658cc7a82f5SAndrew Rybchenko 	uint32_t *value_maskp,
659cc7a82f5SAndrew Rybchenko 	__out_ecount_opt(count)	__drv_when(count > 0, __notnull)
660cc7a82f5SAndrew Rybchenko 	unsigned long *valuesp,
661cc7a82f5SAndrew Rybchenko 	__in			size_t count)
662cc7a82f5SAndrew Rybchenko {
6636b231fecSAndrew Rybchenko 	/*
6646b231fecSAndrew Rybchenko 	 * MCDI_CTL_SDU_LEN_MAX_V1 is large enough cover all BIST results,
6656b231fecSAndrew Rybchenko 	 * whilst not wasting stack.
6666b231fecSAndrew Rybchenko 	 */
667315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_POLL_BIST_IN_LEN,
668315bbbaaSAndrew Rybchenko 		MCDI_CTL_SDU_LEN_MAX_V1);
669cc7a82f5SAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
670cc7a82f5SAndrew Rybchenko 	efx_mcdi_req_t req;
671cc7a82f5SAndrew Rybchenko 	uint32_t value_mask = 0;
672cc7a82f5SAndrew Rybchenko 	uint32_t result;
673cc7a82f5SAndrew Rybchenko 	efx_rc_t rc;
674cc7a82f5SAndrew Rybchenko 
6756b231fecSAndrew Rybchenko 	EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_LEN <=
6766b231fecSAndrew Rybchenko 	    MCDI_CTL_SDU_LEN_MAX_V1);
6776b231fecSAndrew Rybchenko 	EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_SFT9001_LEN <=
6786b231fecSAndrew Rybchenko 	    MCDI_CTL_SDU_LEN_MAX_V1);
6796b231fecSAndrew Rybchenko 	EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_MRSFP_LEN <=
6806b231fecSAndrew Rybchenko 	    MCDI_CTL_SDU_LEN_MAX_V1);
6816b231fecSAndrew Rybchenko 	EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_MEM_LEN <=
6826b231fecSAndrew Rybchenko 	    MCDI_CTL_SDU_LEN_MAX_V1);
6836b231fecSAndrew Rybchenko 
684cc7a82f5SAndrew Rybchenko 	_NOTE(ARGUNUSED(type))
685cc7a82f5SAndrew Rybchenko 
686cc7a82f5SAndrew Rybchenko 	req.emr_cmd = MC_CMD_POLL_BIST;
687cc7a82f5SAndrew Rybchenko 	req.emr_in_buf = payload;
688cc7a82f5SAndrew Rybchenko 	req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
689cc7a82f5SAndrew Rybchenko 	req.emr_out_buf = payload;
6906b231fecSAndrew Rybchenko 	req.emr_out_length = MCDI_CTL_SDU_LEN_MAX_V1;
691cc7a82f5SAndrew Rybchenko 
692cc7a82f5SAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
693cc7a82f5SAndrew Rybchenko 
694cc7a82f5SAndrew Rybchenko 	if (req.emr_rc != 0) {
695cc7a82f5SAndrew Rybchenko 		rc = req.emr_rc;
696cc7a82f5SAndrew Rybchenko 		goto fail1;
697cc7a82f5SAndrew Rybchenko 	}
698cc7a82f5SAndrew Rybchenko 
699cc7a82f5SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
700cc7a82f5SAndrew Rybchenko 		rc = EMSGSIZE;
701cc7a82f5SAndrew Rybchenko 		goto fail2;
702cc7a82f5SAndrew Rybchenko 	}
703cc7a82f5SAndrew Rybchenko 
704cc7a82f5SAndrew Rybchenko 	if (count > 0)
705cc7a82f5SAndrew Rybchenko 		(void) memset(valuesp, '\0', count * sizeof (unsigned long));
706cc7a82f5SAndrew Rybchenko 
707cc7a82f5SAndrew Rybchenko 	result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
708cc7a82f5SAndrew Rybchenko 
709cc7a82f5SAndrew Rybchenko 	if (result == MC_CMD_POLL_BIST_FAILED &&
710cc7a82f5SAndrew Rybchenko 	    req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN &&
711cc7a82f5SAndrew Rybchenko 	    count > EFX_BIST_MEM_ECC_FATAL) {
712cc7a82f5SAndrew Rybchenko 		if (valuesp != NULL) {
713cc7a82f5SAndrew Rybchenko 			valuesp[EFX_BIST_MEM_TEST] =
714cc7a82f5SAndrew Rybchenko 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST);
715cc7a82f5SAndrew Rybchenko 			valuesp[EFX_BIST_MEM_ADDR] =
716cc7a82f5SAndrew Rybchenko 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR);
717cc7a82f5SAndrew Rybchenko 			valuesp[EFX_BIST_MEM_BUS] =
718cc7a82f5SAndrew Rybchenko 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS);
719cc7a82f5SAndrew Rybchenko 			valuesp[EFX_BIST_MEM_EXPECT] =
720cc7a82f5SAndrew Rybchenko 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT);
721cc7a82f5SAndrew Rybchenko 			valuesp[EFX_BIST_MEM_ACTUAL] =
722cc7a82f5SAndrew Rybchenko 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL);
723cc7a82f5SAndrew Rybchenko 			valuesp[EFX_BIST_MEM_ECC] =
724cc7a82f5SAndrew Rybchenko 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC);
725cc7a82f5SAndrew Rybchenko 			valuesp[EFX_BIST_MEM_ECC_PARITY] =
726cc7a82f5SAndrew Rybchenko 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY);
727cc7a82f5SAndrew Rybchenko 			valuesp[EFX_BIST_MEM_ECC_FATAL] =
728cc7a82f5SAndrew Rybchenko 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL);
729cc7a82f5SAndrew Rybchenko 		}
730cc7a82f5SAndrew Rybchenko 		value_mask |= (1 << EFX_BIST_MEM_TEST) |
731cc7a82f5SAndrew Rybchenko 		    (1 << EFX_BIST_MEM_ADDR) |
732cc7a82f5SAndrew Rybchenko 		    (1 << EFX_BIST_MEM_BUS) |
733cc7a82f5SAndrew Rybchenko 		    (1 << EFX_BIST_MEM_EXPECT) |
734cc7a82f5SAndrew Rybchenko 		    (1 << EFX_BIST_MEM_ACTUAL) |
735cc7a82f5SAndrew Rybchenko 		    (1 << EFX_BIST_MEM_ECC) |
736cc7a82f5SAndrew Rybchenko 		    (1 << EFX_BIST_MEM_ECC_PARITY) |
737cc7a82f5SAndrew Rybchenko 		    (1 << EFX_BIST_MEM_ECC_FATAL);
738cc7a82f5SAndrew Rybchenko 	} else if (result == MC_CMD_POLL_BIST_FAILED &&
739cc7a82f5SAndrew Rybchenko 	    encp->enc_phy_type == EFX_PHY_XFI_FARMI &&
740cc7a82f5SAndrew Rybchenko 	    req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
741cc7a82f5SAndrew Rybchenko 	    count > EFX_BIST_FAULT_CODE) {
742cc7a82f5SAndrew Rybchenko 		if (valuesp != NULL)
743cc7a82f5SAndrew Rybchenko 			valuesp[EFX_BIST_FAULT_CODE] =
744cc7a82f5SAndrew Rybchenko 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
745cc7a82f5SAndrew Rybchenko 		value_mask |= 1 << EFX_BIST_FAULT_CODE;
746cc7a82f5SAndrew Rybchenko 	}
747cc7a82f5SAndrew Rybchenko 
748cc7a82f5SAndrew Rybchenko 	if (value_maskp != NULL)
749cc7a82f5SAndrew Rybchenko 		*value_maskp = value_mask;
750cc7a82f5SAndrew Rybchenko 
751cc7a82f5SAndrew Rybchenko 	EFSYS_ASSERT(resultp != NULL);
752cc7a82f5SAndrew Rybchenko 	if (result == MC_CMD_POLL_BIST_RUNNING)
753cc7a82f5SAndrew Rybchenko 		*resultp = EFX_BIST_RESULT_RUNNING;
754cc7a82f5SAndrew Rybchenko 	else if (result == MC_CMD_POLL_BIST_PASSED)
755cc7a82f5SAndrew Rybchenko 		*resultp = EFX_BIST_RESULT_PASSED;
756cc7a82f5SAndrew Rybchenko 	else
757cc7a82f5SAndrew Rybchenko 		*resultp = EFX_BIST_RESULT_FAILED;
758cc7a82f5SAndrew Rybchenko 
759cc7a82f5SAndrew Rybchenko 	return (0);
760cc7a82f5SAndrew Rybchenko 
761cc7a82f5SAndrew Rybchenko fail2:
762cc7a82f5SAndrew Rybchenko 	EFSYS_PROBE(fail2);
763cc7a82f5SAndrew Rybchenko fail1:
764cc7a82f5SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
765cc7a82f5SAndrew Rybchenko 
766cc7a82f5SAndrew Rybchenko 	return (rc);
767cc7a82f5SAndrew Rybchenko }
768cc7a82f5SAndrew Rybchenko 
769cc7a82f5SAndrew Rybchenko 			void
ef10_bist_stop(__in efx_nic_t * enp,__in efx_bist_type_t type)770cc7a82f5SAndrew Rybchenko ef10_bist_stop(
771cc7a82f5SAndrew Rybchenko 	__in		efx_nic_t *enp,
772cc7a82f5SAndrew Rybchenko 	__in		efx_bist_type_t type)
773cc7a82f5SAndrew Rybchenko {
774cc7a82f5SAndrew Rybchenko 	/* There is no way to stop BIST on EF10. */
775cc7a82f5SAndrew Rybchenko 	_NOTE(ARGUNUSED(enp, type))
776cc7a82f5SAndrew Rybchenko }
777cc7a82f5SAndrew Rybchenko 
778cc7a82f5SAndrew Rybchenko #endif	/* EFSYS_OPT_BIST */
779cc7a82f5SAndrew Rybchenko 
78010d4c14dSAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
781