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
37static			void
38mcdi_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
120static			void
121mcdi_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
190ef10_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
260ef10_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
277fail1:
278	EFSYS_PROBE1(fail1, efx_rc_t, rc);
279
280	return (rc);
281}
282
283	__checkReturn	efx_rc_t
284ef10_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
347fail2:
348	EFSYS_PROBE(fail2);
349fail1:
350	EFSYS_PROBE1(fail1, efx_rc_t, rc);
351
352	return (rc);
353}
354
355	__checkReturn	efx_rc_t
356ef10_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	}
505out:
506	return (0);
507
508fail3:
509	EFSYS_PROBE(fail3);
510fail2:
511	EFSYS_PROBE(fail2);
512fail1:
513	EFSYS_PROBE1(fail1, efx_rc_t, rc);
514
515	return (rc);
516}
517
518	__checkReturn	efx_rc_t
519ef10_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
556fail3:
557	EFSYS_PROBE(fail3);
558fail2:
559	EFSYS_PROBE(fail2);
560fail1:
561	EFSYS_PROBE1(fail1, efx_rc_t, rc);
562
563	return (rc);
564}
565
566	__checkReturn	efx_rc_t
567ef10_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
577ef10_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
592fail1:
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
601ef10_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
618ef10_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
628fail1:
629	EFSYS_PROBE1(fail1, efx_rc_t, rc);
630
631	return (rc);
632}
633
634	__checkReturn		efx_rc_t
635ef10_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
646fail1:
647	EFSYS_PROBE1(fail1, efx_rc_t, rc);
648
649	return (rc);
650}
651
652	__checkReturn		efx_rc_t
653ef10_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
761fail2:
762	EFSYS_PROBE(fail2);
763fail1:
764	EFSYS_PROBE1(fail1, efx_rc_t, rc);
765
766	return (rc);
767}
768
769			void
770ef10_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