xref: /freebsd/sys/dev/sfxge/common/ef10_phy.c (revision 069ac184)
1 /*-
2  * Copyright (c) 2012-2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30 
31 #include <sys/cdefs.h>
32 #include "efx.h"
33 #include "efx_impl.h"
34 
35 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
36 
37 static			void
38 mcdi_phy_decode_cap(
39 	__in		uint32_t mcdi_cap,
40 	__out		uint32_t *maskp)
41 {
42 	uint32_t mask;
43 
44 #define	CHECK_CAP(_cap) \
45 	EFX_STATIC_ASSERT(EFX_PHY_CAP_##_cap == MC_CMD_PHY_CAP_##_cap##_LBN)
46 
47 	CHECK_CAP(10HDX);
48 	CHECK_CAP(10FDX);
49 	CHECK_CAP(100HDX);
50 	CHECK_CAP(100FDX);
51 	CHECK_CAP(1000HDX);
52 	CHECK_CAP(1000FDX);
53 	CHECK_CAP(10000FDX);
54 	CHECK_CAP(25000FDX);
55 	CHECK_CAP(40000FDX);
56 	CHECK_CAP(50000FDX);
57 	CHECK_CAP(100000FDX);
58 	CHECK_CAP(PAUSE);
59 	CHECK_CAP(ASYM);
60 	CHECK_CAP(AN);
61 	CHECK_CAP(DDM);
62 	CHECK_CAP(BASER_FEC);
63 	CHECK_CAP(BASER_FEC_REQUESTED);
64 	CHECK_CAP(RS_FEC);
65 	CHECK_CAP(RS_FEC_REQUESTED);
66 	CHECK_CAP(25G_BASER_FEC);
67 	CHECK_CAP(25G_BASER_FEC_REQUESTED);
68 #undef CHECK_CAP
69 
70 	mask = 0;
71 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
72 		mask |= (1 << EFX_PHY_CAP_10HDX);
73 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
74 		mask |= (1 << EFX_PHY_CAP_10FDX);
75 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
76 		mask |= (1 << EFX_PHY_CAP_100HDX);
77 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
78 		mask |= (1 << EFX_PHY_CAP_100FDX);
79 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
80 		mask |= (1 << EFX_PHY_CAP_1000HDX);
81 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
82 		mask |= (1 << EFX_PHY_CAP_1000FDX);
83 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
84 		mask |= (1 << EFX_PHY_CAP_10000FDX);
85 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25000FDX_LBN))
86 		mask |= (1 << EFX_PHY_CAP_25000FDX);
87 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))
88 		mask |= (1 << EFX_PHY_CAP_40000FDX);
89 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_50000FDX_LBN))
90 		mask |= (1 << EFX_PHY_CAP_50000FDX);
91 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100000FDX_LBN))
92 		mask |= (1 << EFX_PHY_CAP_100000FDX);
93 
94 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
95 		mask |= (1 << EFX_PHY_CAP_PAUSE);
96 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
97 		mask |= (1 << EFX_PHY_CAP_ASYM);
98 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
99 		mask |= (1 << EFX_PHY_CAP_AN);
100 
101 	/* FEC caps (supported on Medford2 and later) */
102 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN))
103 		mask |= (1 << EFX_PHY_CAP_BASER_FEC);
104 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_REQUESTED_LBN))
105 		mask |= (1 << EFX_PHY_CAP_BASER_FEC_REQUESTED);
106 
107 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_LBN))
108 		mask |= (1 << EFX_PHY_CAP_RS_FEC);
109 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_REQUESTED_LBN))
110 		mask |= (1 << EFX_PHY_CAP_RS_FEC_REQUESTED);
111 
112 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN))
113 		mask |= (1 << EFX_PHY_CAP_25G_BASER_FEC);
114 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_REQUESTED_LBN))
115 		mask |= (1 << EFX_PHY_CAP_25G_BASER_FEC_REQUESTED);
116 
117 	*maskp = mask;
118 }
119 
120 static			void
121 mcdi_phy_decode_link_mode(
122 	__in		efx_nic_t *enp,
123 	__in		uint32_t link_flags,
124 	__in		unsigned int speed,
125 	__in		unsigned int fcntl,
126 	__in		uint32_t fec,
127 	__out		efx_link_mode_t *link_modep,
128 	__out		unsigned int *fcntlp,
129 	__out		efx_phy_fec_type_t *fecp)
130 {
131 	boolean_t fd = !!(link_flags &
132 		    (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
133 	boolean_t up = !!(link_flags &
134 		    (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
135 
136 	_NOTE(ARGUNUSED(enp))
137 
138 	if (!up)
139 		*link_modep = EFX_LINK_DOWN;
140 	else if (speed == 100000 && fd)
141 		*link_modep = EFX_LINK_100000FDX;
142 	else if (speed == 50000 && fd)
143 		*link_modep = EFX_LINK_50000FDX;
144 	else if (speed == 40000 && fd)
145 		*link_modep = EFX_LINK_40000FDX;
146 	else if (speed == 25000 && fd)
147 		*link_modep = EFX_LINK_25000FDX;
148 	else if (speed == 10000 && fd)
149 		*link_modep = EFX_LINK_10000FDX;
150 	else if (speed == 1000)
151 		*link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
152 	else if (speed == 100)
153 		*link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
154 	else if (speed == 10)
155 		*link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
156 	else
157 		*link_modep = EFX_LINK_UNKNOWN;
158 
159 	if (fcntl == MC_CMD_FCNTL_OFF)
160 		*fcntlp = 0;
161 	else if (fcntl == MC_CMD_FCNTL_RESPOND)
162 		*fcntlp = EFX_FCNTL_RESPOND;
163 	else if (fcntl == MC_CMD_FCNTL_GENERATE)
164 		*fcntlp = EFX_FCNTL_GENERATE;
165 	else if (fcntl == MC_CMD_FCNTL_BIDIR)
166 		*fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
167 	else {
168 		EFSYS_PROBE1(mc_pcol_error, int, fcntl);
169 		*fcntlp = 0;
170 	}
171 
172 	switch (fec) {
173 	case MC_CMD_FEC_NONE:
174 		*fecp = EFX_PHY_FEC_NONE;
175 		break;
176 	case MC_CMD_FEC_BASER:
177 		*fecp = EFX_PHY_FEC_BASER;
178 		break;
179 	case MC_CMD_FEC_RS:
180 		*fecp = EFX_PHY_FEC_RS;
181 		break;
182 	default:
183 		EFSYS_PROBE1(mc_pcol_error, int, fec);
184 		*fecp = EFX_PHY_FEC_NONE;
185 		break;
186 	}
187 }
188 
189 			void
190 ef10_phy_link_ev(
191 	__in		efx_nic_t *enp,
192 	__in		efx_qword_t *eqp,
193 	__out		efx_link_mode_t *link_modep)
194 {
195 	efx_port_t *epp = &(enp->en_port);
196 	unsigned int link_flags;
197 	unsigned int speed;
198 	unsigned int fcntl;
199 	efx_phy_fec_type_t fec = MC_CMD_FEC_NONE;
200 	efx_link_mode_t link_mode;
201 	uint32_t lp_cap_mask;
202 
203 	/*
204 	 * Convert the LINKCHANGE speed enumeration into mbit/s, in the
205 	 * same way as GET_LINK encodes the speed
206 	 */
207 	switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) {
208 	case MCDI_EVENT_LINKCHANGE_SPEED_100M:
209 		speed = 100;
210 		break;
211 	case MCDI_EVENT_LINKCHANGE_SPEED_1G:
212 		speed = 1000;
213 		break;
214 	case MCDI_EVENT_LINKCHANGE_SPEED_10G:
215 		speed = 10000;
216 		break;
217 	case MCDI_EVENT_LINKCHANGE_SPEED_25G:
218 		speed = 25000;
219 		break;
220 	case MCDI_EVENT_LINKCHANGE_SPEED_40G:
221 		speed = 40000;
222 		break;
223 	case MCDI_EVENT_LINKCHANGE_SPEED_50G:
224 		speed = 50000;
225 		break;
226 	case MCDI_EVENT_LINKCHANGE_SPEED_100G:
227 		speed = 100000;
228 		break;
229 	default:
230 		speed = 0;
231 		break;
232 	}
233 
234 	link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS);
235 	mcdi_phy_decode_link_mode(enp, link_flags, speed,
236 				    MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL),
237 				    MC_CMD_FEC_NONE, &link_mode,
238 				    &fcntl, &fec);
239 	mcdi_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP),
240 			    &lp_cap_mask);
241 
242 	/*
243 	 * It's safe to update ep_lp_cap_mask without the driver's port lock
244 	 * because presumably any concurrently running efx_port_poll() is
245 	 * only going to arrive at the same value.
246 	 *
247 	 * ep_fcntl has two meanings. It's either the link common fcntl
248 	 * (if the PHY supports AN), or it's the forced link state. If
249 	 * the former, it's safe to update the value for the same reason as
250 	 * for ep_lp_cap_mask. If the latter, then just ignore the value,
251 	 * because we can race with efx_mac_fcntl_set().
252 	 */
253 	epp->ep_lp_cap_mask = lp_cap_mask;
254 	epp->ep_fcntl = fcntl;
255 
256 	*link_modep = link_mode;
257 }
258 
259 	__checkReturn	efx_rc_t
260 ef10_phy_power(
261 	__in		efx_nic_t *enp,
262 	__in		boolean_t power)
263 {
264 	efx_rc_t rc;
265 
266 	if (!power)
267 		return (0);
268 
269 	/* Check if the PHY is a zombie */
270 	if ((rc = ef10_phy_verify(enp)) != 0)
271 		goto fail1;
272 
273 	enp->en_reset_flags |= EFX_RESET_PHY;
274 
275 	return (0);
276 
277 fail1:
278 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
279 
280 	return (rc);
281 }
282 
283 	__checkReturn	efx_rc_t
284 ef10_phy_get_link(
285 	__in		efx_nic_t *enp,
286 	__out		ef10_link_state_t *elsp)
287 {
288 	efx_mcdi_req_t req;
289 	uint32_t fec;
290 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LINK_IN_LEN,
291 		MC_CMD_GET_LINK_OUT_V2_LEN);
292 	efx_rc_t rc;
293 
294 	req.emr_cmd = MC_CMD_GET_LINK;
295 	req.emr_in_buf = payload;
296 	req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
297 	req.emr_out_buf = payload;
298 	req.emr_out_length = MC_CMD_GET_LINK_OUT_V2_LEN;
299 
300 	efx_mcdi_execute(enp, &req);
301 
302 	if (req.emr_rc != 0) {
303 		rc = req.emr_rc;
304 		goto fail1;
305 	}
306 
307 	if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
308 		rc = EMSGSIZE;
309 		goto fail2;
310 	}
311 
312 	mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
313 			    &elsp->epls.epls_adv_cap_mask);
314 	mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
315 			    &elsp->epls.epls_lp_cap_mask);
316 
317 	if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_V2_LEN)
318 		fec = MC_CMD_FEC_NONE;
319 	else
320 		fec = MCDI_OUT_DWORD(req, GET_LINK_OUT_V2_FEC_TYPE);
321 
322 	mcdi_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
323 			    MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
324 			    MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
325 			    fec, &elsp->epls.epls_link_mode,
326 			    &elsp->epls.epls_fcntl, &elsp->epls.epls_fec);
327 
328 	if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_V2_LEN) {
329 		elsp->epls.epls_ld_cap_mask = 0;
330 	} else {
331 		mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_V2_LD_CAP),
332 				    &elsp->epls.epls_ld_cap_mask);
333 	}
334 
335 #if EFSYS_OPT_LOOPBACK
336 	/*
337 	 * MC_CMD_LOOPBACK and EFX_LOOPBACK names are equivalent, so use the
338 	 * MCDI value directly. Agreement is checked in efx_loopback_mask().
339 	 */
340 	elsp->els_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
341 #endif	/* EFSYS_OPT_LOOPBACK */
342 
343 	elsp->els_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
344 
345 	return (0);
346 
347 fail2:
348 	EFSYS_PROBE(fail2);
349 fail1:
350 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
351 
352 	return (rc);
353 }
354 
355 	__checkReturn	efx_rc_t
356 ef10_phy_reconfigure(
357 	__in		efx_nic_t *enp)
358 {
359 	efx_port_t *epp = &(enp->en_port);
360 	efx_mcdi_req_t req;
361 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SET_LINK_IN_LEN,
362 		MC_CMD_SET_LINK_OUT_LEN);
363 	uint32_t cap_mask;
364 #if EFSYS_OPT_PHY_LED_CONTROL
365 	unsigned int led_mode;
366 #endif
367 	unsigned int speed;
368 	boolean_t supported;
369 	efx_rc_t rc;
370 
371 	if ((rc = efx_mcdi_link_control_supported(enp, &supported)) != 0)
372 		goto fail1;
373 	if (supported == B_FALSE)
374 		goto out;
375 
376 	req.emr_cmd = MC_CMD_SET_LINK;
377 	req.emr_in_buf = payload;
378 	req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
379 	req.emr_out_buf = payload;
380 	req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;
381 
382 	cap_mask = epp->ep_adv_cap_mask;
383 	MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
384 		PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
385 		PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
386 		PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
387 		PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
388 		PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
389 		PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
390 		PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
391 		PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
392 		PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
393 		PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
394 	/* Too many fields for POPULATE macros, so insert this afterwards */
395 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
396 	    PHY_CAP_25000FDX, (cap_mask >> EFX_PHY_CAP_25000FDX) & 0x1);
397 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
398 	    PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1);
399 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
400 	    PHY_CAP_50000FDX, (cap_mask >> EFX_PHY_CAP_50000FDX) & 0x1);
401 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
402 	    PHY_CAP_100000FDX, (cap_mask >> EFX_PHY_CAP_100000FDX) & 0x1);
403 
404 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
405 	    PHY_CAP_BASER_FEC, (cap_mask >> EFX_PHY_CAP_BASER_FEC) & 0x1);
406 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
407 	    PHY_CAP_BASER_FEC_REQUESTED,
408 	    (cap_mask >> EFX_PHY_CAP_BASER_FEC_REQUESTED) & 0x1);
409 
410 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
411 	    PHY_CAP_RS_FEC, (cap_mask >> EFX_PHY_CAP_RS_FEC) & 0x1);
412 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
413 	    PHY_CAP_RS_FEC_REQUESTED,
414 	    (cap_mask >> EFX_PHY_CAP_RS_FEC_REQUESTED) & 0x1);
415 
416 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
417 	    PHY_CAP_25G_BASER_FEC,
418 	    (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC) & 0x1);
419 	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
420 	    PHY_CAP_25G_BASER_FEC_REQUESTED,
421 	    (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC_REQUESTED) & 0x1);
422 
423 #if EFSYS_OPT_LOOPBACK
424 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
425 		    epp->ep_loopback_type);
426 	switch (epp->ep_loopback_link_mode) {
427 	case EFX_LINK_100FDX:
428 		speed = 100;
429 		break;
430 	case EFX_LINK_1000FDX:
431 		speed = 1000;
432 		break;
433 	case EFX_LINK_10000FDX:
434 		speed = 10000;
435 		break;
436 	case EFX_LINK_25000FDX:
437 		speed = 25000;
438 		break;
439 	case EFX_LINK_40000FDX:
440 		speed = 40000;
441 		break;
442 	case EFX_LINK_50000FDX:
443 		speed = 50000;
444 		break;
445 	case EFX_LINK_100000FDX:
446 		speed = 100000;
447 		break;
448 	default:
449 		speed = 0;
450 	}
451 #else
452 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
453 	speed = 0;
454 #endif	/* EFSYS_OPT_LOOPBACK */
455 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
456 
457 #if EFSYS_OPT_PHY_FLAGS
458 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
459 #else
460 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
461 #endif	/* EFSYS_OPT_PHY_FLAGS */
462 
463 	efx_mcdi_execute(enp, &req);
464 
465 	if (req.emr_rc != 0) {
466 		rc = req.emr_rc;
467 		goto fail2;
468 	}
469 
470 	/* And set the blink mode */
471 	(void) memset(payload, 0, sizeof (payload));
472 	req.emr_cmd = MC_CMD_SET_ID_LED;
473 	req.emr_in_buf = payload;
474 	req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
475 	req.emr_out_buf = payload;
476 	req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;
477 
478 #if EFSYS_OPT_PHY_LED_CONTROL
479 	switch (epp->ep_phy_led_mode) {
480 	case EFX_PHY_LED_DEFAULT:
481 		led_mode = MC_CMD_LED_DEFAULT;
482 		break;
483 	case EFX_PHY_LED_OFF:
484 		led_mode = MC_CMD_LED_OFF;
485 		break;
486 	case EFX_PHY_LED_ON:
487 		led_mode = MC_CMD_LED_ON;
488 		break;
489 	default:
490 		EFSYS_ASSERT(0);
491 		led_mode = MC_CMD_LED_DEFAULT;
492 	}
493 
494 	MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
495 #else
496 	MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
497 #endif	/* EFSYS_OPT_PHY_LED_CONTROL */
498 
499 	efx_mcdi_execute(enp, &req);
500 
501 	if (req.emr_rc != 0) {
502 		rc = req.emr_rc;
503 		goto fail3;
504 	}
505 out:
506 	return (0);
507 
508 fail3:
509 	EFSYS_PROBE(fail3);
510 fail2:
511 	EFSYS_PROBE(fail2);
512 fail1:
513 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
514 
515 	return (rc);
516 }
517 
518 	__checkReturn	efx_rc_t
519 ef10_phy_verify(
520 	__in		efx_nic_t *enp)
521 {
522 	efx_mcdi_req_t req;
523 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_STATE_IN_LEN,
524 		MC_CMD_GET_PHY_STATE_OUT_LEN);
525 	uint32_t state;
526 	efx_rc_t rc;
527 
528 	req.emr_cmd = MC_CMD_GET_PHY_STATE;
529 	req.emr_in_buf = payload;
530 	req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
531 	req.emr_out_buf = payload;
532 	req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN;
533 
534 	efx_mcdi_execute(enp, &req);
535 
536 	if (req.emr_rc != 0) {
537 		rc = req.emr_rc;
538 		goto fail1;
539 	}
540 
541 	if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
542 		rc = EMSGSIZE;
543 		goto fail2;
544 	}
545 
546 	state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
547 	if (state != MC_CMD_PHY_STATE_OK) {
548 		if (state != MC_CMD_PHY_STATE_ZOMBIE)
549 			EFSYS_PROBE1(mc_pcol_error, int, state);
550 		rc = ENOTACTIVE;
551 		goto fail3;
552 	}
553 
554 	return (0);
555 
556 fail3:
557 	EFSYS_PROBE(fail3);
558 fail2:
559 	EFSYS_PROBE(fail2);
560 fail1:
561 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
562 
563 	return (rc);
564 }
565 
566 	__checkReturn	efx_rc_t
567 ef10_phy_oui_get(
568 	__in		efx_nic_t *enp,
569 	__out		uint32_t *ouip)
570 {
571 	_NOTE(ARGUNUSED(enp, ouip))
572 
573 	return (ENOTSUP);
574 }
575 
576 	__checkReturn	efx_rc_t
577 ef10_phy_link_state_get(
578 	__in		efx_nic_t *enp,
579 	__out		efx_phy_link_state_t  *eplsp)
580 {
581 	efx_rc_t rc;
582 	ef10_link_state_t els;
583 
584 	/* Obtain the active link state */
585 	if ((rc = ef10_phy_get_link(enp, &els)) != 0)
586 		goto fail1;
587 
588 	*eplsp = els.epls;
589 
590 	return (0);
591 
592 fail1:
593 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
594 
595 	return (rc);
596 }
597 
598 #if EFSYS_OPT_PHY_STATS
599 
600 	__checkReturn				efx_rc_t
601 ef10_phy_stats_update(
602 	__in					efx_nic_t *enp,
603 	__in					efsys_mem_t *esmp,
604 	__inout_ecount(EFX_PHY_NSTATS)		uint32_t *stat)
605 {
606 	/* TBD: no stats support in firmware yet */
607 	_NOTE(ARGUNUSED(enp, esmp))
608 	memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat));
609 
610 	return (0);
611 }
612 
613 #endif	/* EFSYS_OPT_PHY_STATS */
614 
615 #if EFSYS_OPT_BIST
616 
617 	__checkReturn		efx_rc_t
618 ef10_bist_enable_offline(
619 	__in			efx_nic_t *enp)
620 {
621 	efx_rc_t rc;
622 
623 	if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0)
624 		goto fail1;
625 
626 	return (0);
627 
628 fail1:
629 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
630 
631 	return (rc);
632 }
633 
634 	__checkReturn		efx_rc_t
635 ef10_bist_start(
636 	__in			efx_nic_t *enp,
637 	__in			efx_bist_type_t type)
638 {
639 	efx_rc_t rc;
640 
641 	if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
642 		goto fail1;
643 
644 	return (0);
645 
646 fail1:
647 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
648 
649 	return (rc);
650 }
651 
652 	__checkReturn		efx_rc_t
653 ef10_bist_poll(
654 	__in			efx_nic_t *enp,
655 	__in			efx_bist_type_t type,
656 	__out			efx_bist_result_t *resultp,
657 	__out_opt __drv_when(count > 0, __notnull)
658 	uint32_t *value_maskp,
659 	__out_ecount_opt(count)	__drv_when(count > 0, __notnull)
660 	unsigned long *valuesp,
661 	__in			size_t count)
662 {
663 	/*
664 	 * MCDI_CTL_SDU_LEN_MAX_V1 is large enough cover all BIST results,
665 	 * whilst not wasting stack.
666 	 */
667 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_POLL_BIST_IN_LEN,
668 		MCDI_CTL_SDU_LEN_MAX_V1);
669 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
670 	efx_mcdi_req_t req;
671 	uint32_t value_mask = 0;
672 	uint32_t result;
673 	efx_rc_t rc;
674 
675 	EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_LEN <=
676 	    MCDI_CTL_SDU_LEN_MAX_V1);
677 	EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_SFT9001_LEN <=
678 	    MCDI_CTL_SDU_LEN_MAX_V1);
679 	EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_MRSFP_LEN <=
680 	    MCDI_CTL_SDU_LEN_MAX_V1);
681 	EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_MEM_LEN <=
682 	    MCDI_CTL_SDU_LEN_MAX_V1);
683 
684 	_NOTE(ARGUNUSED(type))
685 
686 	req.emr_cmd = MC_CMD_POLL_BIST;
687 	req.emr_in_buf = payload;
688 	req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
689 	req.emr_out_buf = payload;
690 	req.emr_out_length = MCDI_CTL_SDU_LEN_MAX_V1;
691 
692 	efx_mcdi_execute(enp, &req);
693 
694 	if (req.emr_rc != 0) {
695 		rc = req.emr_rc;
696 		goto fail1;
697 	}
698 
699 	if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
700 		rc = EMSGSIZE;
701 		goto fail2;
702 	}
703 
704 	if (count > 0)
705 		(void) memset(valuesp, '\0', count * sizeof (unsigned long));
706 
707 	result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
708 
709 	if (result == MC_CMD_POLL_BIST_FAILED &&
710 	    req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN &&
711 	    count > EFX_BIST_MEM_ECC_FATAL) {
712 		if (valuesp != NULL) {
713 			valuesp[EFX_BIST_MEM_TEST] =
714 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST);
715 			valuesp[EFX_BIST_MEM_ADDR] =
716 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR);
717 			valuesp[EFX_BIST_MEM_BUS] =
718 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS);
719 			valuesp[EFX_BIST_MEM_EXPECT] =
720 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT);
721 			valuesp[EFX_BIST_MEM_ACTUAL] =
722 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL);
723 			valuesp[EFX_BIST_MEM_ECC] =
724 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC);
725 			valuesp[EFX_BIST_MEM_ECC_PARITY] =
726 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY);
727 			valuesp[EFX_BIST_MEM_ECC_FATAL] =
728 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL);
729 		}
730 		value_mask |= (1 << EFX_BIST_MEM_TEST) |
731 		    (1 << EFX_BIST_MEM_ADDR) |
732 		    (1 << EFX_BIST_MEM_BUS) |
733 		    (1 << EFX_BIST_MEM_EXPECT) |
734 		    (1 << EFX_BIST_MEM_ACTUAL) |
735 		    (1 << EFX_BIST_MEM_ECC) |
736 		    (1 << EFX_BIST_MEM_ECC_PARITY) |
737 		    (1 << EFX_BIST_MEM_ECC_FATAL);
738 	} else if (result == MC_CMD_POLL_BIST_FAILED &&
739 	    encp->enc_phy_type == EFX_PHY_XFI_FARMI &&
740 	    req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
741 	    count > EFX_BIST_FAULT_CODE) {
742 		if (valuesp != NULL)
743 			valuesp[EFX_BIST_FAULT_CODE] =
744 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
745 		value_mask |= 1 << EFX_BIST_FAULT_CODE;
746 	}
747 
748 	if (value_maskp != NULL)
749 		*value_maskp = value_mask;
750 
751 	EFSYS_ASSERT(resultp != NULL);
752 	if (result == MC_CMD_POLL_BIST_RUNNING)
753 		*resultp = EFX_BIST_RESULT_RUNNING;
754 	else if (result == MC_CMD_POLL_BIST_PASSED)
755 		*resultp = EFX_BIST_RESULT_PASSED;
756 	else
757 		*resultp = EFX_BIST_RESULT_FAILED;
758 
759 	return (0);
760 
761 fail2:
762 	EFSYS_PROBE(fail2);
763 fail1:
764 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
765 
766 	return (rc);
767 }
768 
769 			void
770 ef10_bist_stop(
771 	__in		efx_nic_t *enp,
772 	__in		efx_bist_type_t type)
773 {
774 	/* There is no way to stop BIST on EF10. */
775 	_NOTE(ARGUNUSED(enp, type))
776 }
777 
778 #endif	/* EFSYS_OPT_BIST */
779 
780 #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
781