xref: /freebsd/sys/dev/sfxge/common/siena_phy.c (revision f05cddf9)
1 /*-
2  * Copyright 2009 Solarflare Communications Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28 
29 #include "efsys.h"
30 #include "efx.h"
31 #include "efx_impl.h"
32 
33 #if EFSYS_OPT_SIENA
34 
35 static			void
36 siena_phy_decode_cap(
37 	__in		uint32_t mcdi_cap,
38 	__out		uint32_t *maskp)
39 {
40 	uint32_t mask;
41 
42 	mask = 0;
43 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
44 		mask |= (1 << EFX_PHY_CAP_10HDX);
45 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
46 		mask |= (1 << EFX_PHY_CAP_10FDX);
47 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
48 		mask |= (1 << EFX_PHY_CAP_100HDX);
49 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
50 		mask |= (1 << EFX_PHY_CAP_100FDX);
51 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
52 		mask |= (1 << EFX_PHY_CAP_1000HDX);
53 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
54 		mask |= (1 << EFX_PHY_CAP_1000FDX);
55 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
56 		mask |= (1 << EFX_PHY_CAP_10000FDX);
57 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
58 		mask |= (1 << EFX_PHY_CAP_PAUSE);
59 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
60 		mask |= (1 << EFX_PHY_CAP_ASYM);
61 	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
62 		mask |= (1 << EFX_PHY_CAP_AN);
63 
64 	*maskp = mask;
65 }
66 
67 static			void
68 siena_phy_decode_link_mode(
69 	__in		efx_nic_t *enp,
70 	__in		uint32_t link_flags,
71 	__in		unsigned int speed,
72 	__in		unsigned int fcntl,
73 	__out		efx_link_mode_t *link_modep,
74 	__out		unsigned int *fcntlp)
75 {
76 	boolean_t fd = !!(link_flags &
77 		    (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
78 	boolean_t up = !!(link_flags &
79 		    (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
80 
81 	_NOTE(ARGUNUSED(enp))
82 
83 	if (!up)
84 		*link_modep = EFX_LINK_DOWN;
85 	else if (speed == 10000 && fd)
86 		*link_modep = EFX_LINK_10000FDX;
87 	else if (speed == 1000)
88 		*link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
89 	else if (speed == 100)
90 		*link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
91 	else if (speed == 10)
92 		*link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
93 	else
94 		*link_modep = EFX_LINK_UNKNOWN;
95 
96 	if (fcntl == MC_CMD_FCNTL_OFF)
97 		*fcntlp = 0;
98 	else if (fcntl == MC_CMD_FCNTL_RESPOND)
99 		*fcntlp = EFX_FCNTL_RESPOND;
100 	else if (fcntl == MC_CMD_FCNTL_BIDIR)
101 		*fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
102 	else {
103 		EFSYS_PROBE1(mc_pcol_error, int, fcntl);
104 		*fcntlp = 0;
105 	}
106 }
107 
108 			void
109 siena_phy_link_ev(
110 	__in		efx_nic_t *enp,
111 	__in		efx_qword_t *eqp,
112 	__out		efx_link_mode_t *link_modep)
113 {
114 	efx_port_t *epp = &(enp->en_port);
115 	unsigned int link_flags;
116 	unsigned int speed;
117 	unsigned int fcntl;
118 	efx_link_mode_t link_mode;
119 	uint32_t lp_cap_mask;
120 
121 	/*
122 	 * Convert the LINKCHANGE speed enumeration into mbit/s, in the
123 	 * same way as GET_LINK encodes the speed
124 	 */
125 	switch (MCDI_EV_FIELD(*eqp, LINKCHANGE_SPEED)) {
126 	case MCDI_EVENT_LINKCHANGE_SPEED_100M:
127 		speed = 100;
128 		break;
129 	case MCDI_EVENT_LINKCHANGE_SPEED_1G:
130 		speed = 1000;
131 		break;
132 	case MCDI_EVENT_LINKCHANGE_SPEED_10G:
133 		speed = 10000;
134 		break;
135 	default:
136 		speed = 0;
137 		break;
138 	}
139 
140 	link_flags = MCDI_EV_FIELD(*eqp, LINKCHANGE_LINK_FLAGS);
141 	siena_phy_decode_link_mode(enp, link_flags, speed,
142 				    MCDI_EV_FIELD(*eqp, LINKCHANGE_FCNTL),
143 				    &link_mode, &fcntl);
144 	siena_phy_decode_cap(MCDI_EV_FIELD(*eqp, LINKCHANGE_LP_CAP),
145 			    &lp_cap_mask);
146 
147 	/*
148 	 * It's safe to update ep_lp_cap_mask without the driver's port lock
149 	 * because presumably any concurrently running efx_port_poll() is
150 	 * only going to arrive at the same value.
151 	 *
152 	 * ep_fcntl has two meanings. It's either the link common fcntl
153 	 * (if the PHY supports AN), or it's the forced link state. If
154 	 * the former, it's safe to update the value for the same reason as
155 	 * for ep_lp_cap_mask. If the latter, then just ignore the value,
156 	 * because we can race with efx_mac_fcntl_set().
157 	 */
158 	epp->ep_lp_cap_mask = lp_cap_mask;
159 	if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
160 		epp->ep_fcntl = fcntl;
161 
162 	*link_modep = link_mode;
163 }
164 
165 	__checkReturn	int
166 siena_phy_power(
167 	__in		efx_nic_t *enp,
168 	__in		boolean_t power)
169 {
170 	int rc;
171 
172 	if (!power)
173 		return (0);
174 
175 	/* Check if the PHY is a zombie */
176 	if ((rc = siena_phy_verify(enp)) != 0)
177 		goto fail1;
178 
179 	enp->en_reset_flags |= EFX_RESET_PHY;
180 
181 	return (0);
182 
183 fail1:
184 	EFSYS_PROBE1(fail1, int, rc);
185 
186 	return (rc);
187 }
188 
189 	__checkReturn	int
190 siena_phy_get_link(
191 	__in		efx_nic_t *enp,
192 	__out		siena_link_state_t *slsp)
193 {
194 	efx_mcdi_req_t req;
195 	uint8_t outbuf[MC_CMD_GET_LINK_OUT_LEN];
196 	int rc;
197 
198 	req.emr_cmd = MC_CMD_GET_LINK;
199 	EFX_STATIC_ASSERT(MC_CMD_GET_LINK_IN_LEN == 0);
200 	req.emr_in_buf = NULL;
201 	req.emr_in_length = 0;
202 	req.emr_out_buf = outbuf;
203 	req.emr_out_length = sizeof (outbuf);
204 
205 	efx_mcdi_execute(enp, &req);
206 
207 	if (req.emr_rc != 0) {
208 		rc = req.emr_rc;
209 		goto fail1;
210 	}
211 
212 	if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
213 		rc = EMSGSIZE;
214 		goto fail2;
215 	}
216 
217 	siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
218 			    &slsp->sls_adv_cap_mask);
219 	siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
220 			    &slsp->sls_lp_cap_mask);
221 
222 	siena_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
223 			    MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
224 			    MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
225 			    &slsp->sls_link_mode, &slsp->sls_fcntl);
226 
227 #if EFSYS_OPT_LOOPBACK
228 	/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
229 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
230 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
231 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
232 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
233 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
234 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
235 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
236 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
237 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
238 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
239 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
240 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
241 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
242 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
243 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
244 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
245 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
246 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
247 
248 	slsp->sls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
249 #endif	/* EFSYS_OPT_LOOPBACK */
250 
251 	slsp->sls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
252 
253 	return (0);
254 
255 fail2:
256 	EFSYS_PROBE(fail2);
257 fail1:
258 	EFSYS_PROBE1(fail1, int, rc);
259 
260 	return (rc);
261 }
262 
263 	__checkReturn	int
264 siena_phy_reconfigure(
265 	__in		efx_nic_t *enp)
266 {
267 	efx_port_t *epp = &(enp->en_port);
268 	efx_mcdi_req_t req;
269 	uint8_t payload[MAX(MC_CMD_SET_ID_LED_IN_LEN,
270 			    MC_CMD_SET_LINK_IN_LEN)];
271 	uint32_t cap_mask;
272 	unsigned int led_mode;
273 	unsigned int speed;
274 	int rc;
275 
276 	req.emr_cmd = MC_CMD_SET_LINK;
277 	req.emr_in_buf = payload;
278 	req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
279 	EFX_STATIC_ASSERT(MC_CMD_SET_LINK_OUT_LEN == 0);
280 	req.emr_out_buf = NULL;
281 	req.emr_out_length = 0;
282 
283 	cap_mask = epp->ep_adv_cap_mask;
284 	MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
285 		PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
286 		PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
287 		PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
288 		PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
289 		PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
290 		PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
291 		PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
292 		PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
293 		PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
294 		PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
295 
296 #if EFSYS_OPT_LOOPBACK
297 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
298 		    epp->ep_loopback_type);
299 	switch (epp->ep_loopback_link_mode) {
300 	case EFX_LINK_100FDX:
301 		speed = 100;
302 		break;
303 	case EFX_LINK_1000FDX:
304 		speed = 1000;
305 		break;
306 	case EFX_LINK_10000FDX:
307 		speed = 10000;
308 		break;
309 	default:
310 		speed = 0;
311 	}
312 #else
313 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
314 	speed = 0;
315 #endif	/* EFSYS_OPT_LOOPBACK */
316 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
317 
318 #if EFSYS_OPT_PHY_FLAGS
319 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
320 #else
321 	MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
322 #endif	/* EFSYS_OPT_PHY_FLAGS */
323 
324 	efx_mcdi_execute(enp, &req);
325 
326 	if (req.emr_rc != 0) {
327 		rc = req.emr_rc;
328 		goto fail1;
329 	}
330 
331 	/* And set the blink mode */
332 	req.emr_cmd = MC_CMD_SET_ID_LED;
333 	req.emr_in_buf = payload;
334 	req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
335 	EFX_STATIC_ASSERT(MC_CMD_SET_ID_LED_OUT_LEN == 0);
336 	req.emr_out_buf = NULL;
337 	req.emr_out_length = 0;
338 
339 #if EFSYS_OPT_PHY_LED_CONTROL
340 	switch (epp->ep_phy_led_mode) {
341 	case EFX_PHY_LED_DEFAULT:
342 		led_mode = MC_CMD_LED_DEFAULT;
343 		break;
344 	case EFX_PHY_LED_OFF:
345 		led_mode = MC_CMD_LED_OFF;
346 		break;
347 	case EFX_PHY_LED_ON:
348 		led_mode = MC_CMD_LED_ON;
349 		break;
350 	default:
351 		EFSYS_ASSERT(0);
352 		led_mode = MC_CMD_LED_DEFAULT;
353 	}
354 
355 	MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
356 #else
357 	MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
358 #endif	/* EFSYS_OPT_PHY_LED_CONTROL */
359 
360 	efx_mcdi_execute(enp, &req);
361 
362 	if (req.emr_rc != 0) {
363 		rc = req.emr_rc;
364 		goto fail2;
365 	}
366 
367 	return (0);
368 
369 fail2:
370 	EFSYS_PROBE(fail2);
371 fail1:
372 	EFSYS_PROBE1(fail1, int, rc);
373 
374 	return (rc);
375 }
376 
377 	__checkReturn	int
378 siena_phy_verify(
379 	__in		efx_nic_t *enp)
380 {
381 	efx_mcdi_req_t req;
382 	uint8_t outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN];
383 	uint32_t state;
384 	int rc;
385 
386 	req.emr_cmd = MC_CMD_GET_PHY_STATE;
387 	EFX_STATIC_ASSERT(MC_CMD_GET_PHY_STATE_IN_LEN == 0);
388 	req.emr_in_buf = NULL;
389 	req.emr_in_length = 0;
390 	req.emr_out_buf = outbuf;
391 	req.emr_out_length = sizeof (outbuf);
392 
393 	efx_mcdi_execute(enp, &req);
394 
395 	if (req.emr_rc != 0) {
396 		rc = req.emr_rc;
397 		goto fail1;
398 	}
399 
400 	if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
401 		rc = EMSGSIZE;
402 		goto fail2;
403 	}
404 
405 	state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
406 	if (state != MC_CMD_PHY_STATE_OK) {
407 		if (state != MC_CMD_PHY_STATE_ZOMBIE)
408 			EFSYS_PROBE1(mc_pcol_error, int, state);
409 		rc = ENOTACTIVE;
410 		goto fail3;
411 	}
412 
413 	return (0);
414 
415 fail3:
416 	EFSYS_PROBE(fail3);
417 fail2:
418 	EFSYS_PROBE(fail2);
419 fail1:
420 	EFSYS_PROBE1(fail1, int, rc);
421 
422 	return (rc);
423 }
424 
425 	__checkReturn	int
426 siena_phy_oui_get(
427 	__in		efx_nic_t *enp,
428 	__out		uint32_t *ouip)
429 {
430 	_NOTE(ARGUNUSED(enp, ouip))
431 
432 	return (ENOTSUP);
433 }
434 
435 #if EFSYS_OPT_PHY_STATS
436 
437 #define	SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat,		\
438 			    _mc_record, _efx_record)			\
439 	if ((_vmask) & (1ULL << (_mc_record))) {			\
440 		(_smask) |= (1ULL << (_efx_record));			\
441 		if ((_stat) != NULL && !EFSYS_MEM_IS_NULL(_esmp)) {	\
442 			efx_dword_t dword;				\
443 			EFSYS_MEM_READD(_esmp, (_mc_record) * 4, &dword);\
444 			(_stat)[_efx_record] =				\
445 				EFX_DWORD_FIELD(dword, EFX_DWORD_0);	\
446 		}							\
447 	}
448 
449 #define	SIENA_SIMPLE_STAT_SET2(_vmask, _esmp, _smask, _stat, _record)	\
450 	SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat, 		\
451 			    MC_CMD_ ## _record,				\
452 			    EFX_PHY_STAT_ ## _record)
453 
454 						void
455 siena_phy_decode_stats(
456 	__in					efx_nic_t *enp,
457 	__in					uint32_t vmask,
458 	__in_opt				efsys_mem_t *esmp,
459 	__out_opt				uint64_t *smaskp,
460 	__out_ecount_opt(EFX_PHY_NSTATS)	uint32_t *stat)
461 {
462 	uint64_t smask = 0;
463 
464 	_NOTE(ARGUNUSED(enp))
465 
466 	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, OUI);
467 	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_LINK_UP);
468 	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_RX_FAULT);
469 	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_TX_FAULT);
470 
471 	if (vmask & (1 << MC_CMD_PMA_PMD_SIGNAL)) {
472 		smask |=   ((1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_A) |
473 			    (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_B) |
474 			    (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_C) |
475 			    (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_D));
476 		if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
477 			efx_dword_t dword;
478 			uint32_t sig;
479 			EFSYS_MEM_READD(esmp, 4 * MC_CMD_PMA_PMD_SIGNAL,
480 					&dword);
481 			sig = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
482 			stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_A] = (sig >> 1) & 1;
483 			stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_B] = (sig >> 2) & 1;
484 			stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_C] = (sig >> 3) & 1;
485 			stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_D] = (sig >> 4) & 1;
486 		}
487 	}
488 
489 	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_A,
490 			    EFX_PHY_STAT_SNR_A);
491 	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_B,
492 			    EFX_PHY_STAT_SNR_B);
493 	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_C,
494 			    EFX_PHY_STAT_SNR_C);
495 	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_D,
496 			    EFX_PHY_STAT_SNR_D);
497 
498 	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_LINK_UP);
499 	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_RX_FAULT);
500 	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_TX_FAULT);
501 	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BER);
502 	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BLOCK_ERRORS);
503 
504 	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_LINK_UP,
505 			    EFX_PHY_STAT_PHY_XS_LINK_UP);
506 	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_RX_FAULT,
507 			    EFX_PHY_STAT_PHY_XS_RX_FAULT);
508 	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_TX_FAULT,
509 			    EFX_PHY_STAT_PHY_XS_TX_FAULT);
510 	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_ALIGN,
511 			    EFX_PHY_STAT_PHY_XS_ALIGN);
512 
513 	if (vmask & (1 << MC_CMD_PHYXS_SYNC)) {
514 		smask |=   ((1 << EFX_PHY_STAT_PHY_XS_SYNC_A) |
515 			    (1 << EFX_PHY_STAT_PHY_XS_SYNC_B) |
516 			    (1 << EFX_PHY_STAT_PHY_XS_SYNC_C) |
517 			    (1 << EFX_PHY_STAT_PHY_XS_SYNC_D));
518 		if (stat != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
519 			efx_dword_t dword;
520 			uint32_t sync;
521 			EFSYS_MEM_READD(esmp, 4 * MC_CMD_PHYXS_SYNC, &dword);
522 			sync = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
523 			stat[EFX_PHY_STAT_PHY_XS_SYNC_A] = (sync >> 0) & 1;
524 			stat[EFX_PHY_STAT_PHY_XS_SYNC_B] = (sync >> 1) & 1;
525 			stat[EFX_PHY_STAT_PHY_XS_SYNC_C] = (sync >> 2) & 1;
526 			stat[EFX_PHY_STAT_PHY_XS_SYNC_D] = (sync >> 3) & 1;
527 		}
528 	}
529 
530 	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_LINK_UP);
531 	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_COMPLETE);
532 
533 	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_CL22_LINK_UP,
534 			    EFX_PHY_STAT_CL22EXT_LINK_UP);
535 
536 	if (smaskp != NULL)
537 		*smaskp = smask;
538 }
539 
540 	__checkReturn				int
541 siena_phy_stats_update(
542 	__in					efx_nic_t *enp,
543 	__in					efsys_mem_t *esmp,
544 	__out_ecount(EFX_PHY_NSTATS)		uint32_t *stat)
545 {
546 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
547 	uint32_t vmask = encp->enc_siena_phy_stat_mask;
548 	uint8_t payload[MC_CMD_PHY_STATS_IN_LEN];
549 	uint64_t smask;
550 	efx_mcdi_req_t req;
551 	int rc;
552 
553 	req.emr_cmd = MC_CMD_PHY_STATS;
554 	req.emr_in_buf = payload;
555 	req.emr_in_length = sizeof (payload);
556 	EFX_STATIC_ASSERT(MC_CMD_PHY_STATS_OUT_DMA_LEN == 0);
557 	req.emr_out_buf = NULL;
558 	req.emr_out_length = 0;
559 
560 	MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_LO,
561 			    EFSYS_MEM_ADDR(esmp) & 0xffffffff);
562 	MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_HI,
563 			    EFSYS_MEM_ADDR(esmp) >> 32);
564 
565 	efx_mcdi_execute(enp, &req);
566 
567 	if (req.emr_rc != 0) {
568 		rc = req.emr_rc;
569 		goto fail1;
570 	}
571 	EFSYS_ASSERT3U(req.emr_out_length, ==, MC_CMD_PHY_STATS_OUT_DMA_LEN);
572 
573 	siena_phy_decode_stats(enp, vmask, esmp, &smask, stat);
574 	EFSYS_ASSERT(smask == encp->enc_phy_stat_mask);
575 
576 	return (0);
577 
578 fail1:
579 	EFSYS_PROBE1(fail1, int, rc);
580 
581 	return (0);
582 }
583 
584 #endif	/* EFSYS_OPT_PHY_STATS */
585 
586 #if EFSYS_OPT_PHY_PROPS
587 
588 #if EFSYS_OPT_NAMES
589 
590 extern		const char __cs *
591 siena_phy_prop_name(
592 	__in	efx_nic_t *enp,
593 	__in	unsigned int id)
594 {
595 	_NOTE(ARGUNUSED(enp, id))
596 
597 	return (NULL);
598 }
599 
600 #endif	/* EFSYS_OPT_NAMES */
601 
602 extern	__checkReturn	int
603 siena_phy_prop_get(
604 	__in		efx_nic_t *enp,
605 	__in		unsigned int id,
606 	__in		uint32_t flags,
607 	__out		uint32_t *valp)
608 {
609 	_NOTE(ARGUNUSED(enp, id, flags, valp))
610 
611 	return (ENOTSUP);
612 }
613 
614 extern	__checkReturn	int
615 siena_phy_prop_set(
616 	__in		efx_nic_t *enp,
617 	__in		unsigned int id,
618 	__in		uint32_t val)
619 {
620 	_NOTE(ARGUNUSED(enp, id, val))
621 
622 	return (ENOTSUP);
623 }
624 
625 #endif	/* EFSYS_OPT_PHY_PROPS */
626 
627 #if EFSYS_OPT_PHY_BIST
628 
629 	__checkReturn		int
630 siena_phy_bist_start(
631 	__in			efx_nic_t *enp,
632 	__in			efx_phy_bist_type_t type)
633 {
634 	uint8_t payload[MC_CMD_START_BIST_IN_LEN];
635 	efx_mcdi_req_t req;
636 	int rc;
637 
638 	req.emr_cmd = MC_CMD_START_BIST;
639 	req.emr_in_buf = payload;
640 	req.emr_in_length = sizeof (payload);
641 	EFX_STATIC_ASSERT(MC_CMD_START_BIST_OUT_LEN == 0);
642 	req.emr_out_buf = NULL;
643 	req.emr_out_length = 0;
644 
645 	switch (type) {
646 	case EFX_PHY_BIST_TYPE_NORMAL:
647 		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
648 		break;
649 	case EFX_PHY_BIST_TYPE_CABLE_SHORT:
650 		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
651 		    MC_CMD_PHY_BIST_CABLE_SHORT);
652 		break;
653 	case EFX_PHY_BIST_TYPE_CABLE_LONG:
654 		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
655 		    MC_CMD_PHY_BIST_CABLE_LONG);
656 		break;
657 	default:
658 		EFSYS_ASSERT(0);
659 	}
660 
661 	efx_mcdi_execute(enp, &req);
662 
663 	if (req.emr_rc != 0) {
664 		rc = req.emr_rc;
665 		goto fail1;
666 	}
667 
668 	return (0);
669 
670 fail1:
671 	EFSYS_PROBE1(fail1, int, rc);
672 
673 	return (rc);
674 }
675 
676 static	__checkReturn		unsigned long
677 siena_phy_sft9001_bist_status(
678 	__in			uint16_t code)
679 {
680 	switch (code) {
681 	case MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY:
682 		return (EFX_PHY_CABLE_STATUS_BUSY);
683 	case MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT:
684 		return (EFX_PHY_CABLE_STATUS_INTERPAIRSHORT);
685 	case MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT:
686 		return (EFX_PHY_CABLE_STATUS_INTRAPAIRSHORT);
687 	case MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN:
688 		return (EFX_PHY_CABLE_STATUS_OPEN);
689 	case MC_CMD_POLL_BIST_SFT9001_PAIR_OK:
690 		return (EFX_PHY_CABLE_STATUS_OK);
691 	default:
692 		return (EFX_PHY_CABLE_STATUS_INVALID);
693 	}
694 }
695 
696 	__checkReturn		int
697 siena_phy_bist_poll(
698 	__in			efx_nic_t *enp,
699 	__in			efx_phy_bist_type_t type,
700 	__out			efx_phy_bist_result_t *resultp,
701 	__out_opt __drv_when(count > 0, __notnull)
702 	uint32_t *value_maskp,
703 	__out_ecount_opt(count)	__drv_when(count > 0, __notnull)
704 	unsigned long *valuesp,
705 	__in			size_t count)
706 {
707 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
708 	uint8_t payload[MCDI_CTL_SDU_LEN_MAX];
709 	uint32_t value_mask = 0;
710 	efx_mcdi_req_t req;
711 	uint32_t result;
712 	int rc;
713 
714 	req.emr_cmd = MC_CMD_POLL_BIST;
715 	_NOTE(CONSTANTCONDITION)
716 	EFSYS_ASSERT(MC_CMD_POLL_BIST_IN_LEN == 0);
717 	req.emr_in_buf = NULL;
718 	req.emr_in_length = 0;
719 	req.emr_out_buf = payload;
720 	req.emr_out_length = sizeof (payload);
721 
722 	efx_mcdi_execute(enp, &req);
723 
724 	if (req.emr_rc != 0) {
725 		rc = req.emr_rc;
726 		goto fail1;
727 	}
728 
729 	if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
730 		rc = EMSGSIZE;
731 		goto fail2;
732 	}
733 
734 	if (count > 0)
735 		(void) memset(valuesp, '\0', count * sizeof (unsigned long));
736 
737 	result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
738 
739 	/* Extract PHY specific results */
740 	if (result == MC_CMD_POLL_BIST_PASSED &&
741 	    encp->enc_phy_type == EFX_PHY_SFT9001B &&
742 	    req.emr_out_length_used >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN &&
743 	    (type == EFX_PHY_BIST_TYPE_CABLE_SHORT ||
744 	    type == EFX_PHY_BIST_TYPE_CABLE_LONG)) {
745 		uint16_t word;
746 
747 		if (count > EFX_PHY_BIST_CABLE_LENGTH_A) {
748 			if (valuesp != NULL)
749 				valuesp[EFX_PHY_BIST_CABLE_LENGTH_A] =
750 				    MCDI_OUT_DWORD(req,
751 				    POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
752 			value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_A);
753 		}
754 
755 		if (count > EFX_PHY_BIST_CABLE_LENGTH_B) {
756 			if (valuesp != NULL)
757 				valuesp[EFX_PHY_BIST_CABLE_LENGTH_B] =
758 				    MCDI_OUT_DWORD(req,
759 				    POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B);
760 			value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_B);
761 		}
762 
763 		if (count > EFX_PHY_BIST_CABLE_LENGTH_C) {
764 			if (valuesp != NULL)
765 				valuesp[EFX_PHY_BIST_CABLE_LENGTH_C] =
766 				    MCDI_OUT_DWORD(req,
767 				    POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C);
768 			value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_C);
769 		}
770 
771 		if (count > EFX_PHY_BIST_CABLE_LENGTH_D) {
772 			if (valuesp != NULL)
773 				valuesp[EFX_PHY_BIST_CABLE_LENGTH_D] =
774 				    MCDI_OUT_DWORD(req,
775 				    POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D);
776 			value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_D);
777 		}
778 
779 		if (count > EFX_PHY_BIST_CABLE_STATUS_A) {
780 			if (valuesp != NULL) {
781 				word = MCDI_OUT_WORD(req,
782 				    POLL_BIST_OUT_SFT9001_CABLE_STATUS_A);
783 				valuesp[EFX_PHY_BIST_CABLE_STATUS_A] =
784 				    siena_phy_sft9001_bist_status(word);
785 			}
786 			value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_A);
787 		}
788 
789 		if (count > EFX_PHY_BIST_CABLE_STATUS_B) {
790 			if (valuesp != NULL) {
791 				word = MCDI_OUT_WORD(req,
792 				    POLL_BIST_OUT_SFT9001_CABLE_STATUS_B);
793 				valuesp[EFX_PHY_BIST_CABLE_STATUS_B] =
794 				    siena_phy_sft9001_bist_status(word);
795 			}
796 			value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_B);
797 		}
798 
799 		if (count > EFX_PHY_BIST_CABLE_STATUS_C) {
800 			if (valuesp != NULL) {
801 				word = MCDI_OUT_WORD(req,
802 				    POLL_BIST_OUT_SFT9001_CABLE_STATUS_C);
803 				valuesp[EFX_PHY_BIST_CABLE_STATUS_C] =
804 				    siena_phy_sft9001_bist_status(word);
805 			}
806 			value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_C);
807 		}
808 
809 		if (count > EFX_PHY_BIST_CABLE_STATUS_D) {
810 			if (valuesp != NULL) {
811 				word = MCDI_OUT_WORD(req,
812 				    POLL_BIST_OUT_SFT9001_CABLE_STATUS_D);
813 				valuesp[EFX_PHY_BIST_CABLE_STATUS_D] =
814 				    siena_phy_sft9001_bist_status(word);
815 			}
816 			value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_D);
817 		}
818 
819 	} else if (result == MC_CMD_POLL_BIST_FAILED &&
820 		    encp->enc_phy_type == EFX_PHY_QLX111V &&
821 		    req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
822 		    count > EFX_PHY_BIST_FAULT_CODE) {
823 		if (valuesp != NULL)
824 			valuesp[EFX_PHY_BIST_FAULT_CODE] =
825 			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
826 		value_mask |= 1 << EFX_PHY_BIST_FAULT_CODE;
827 	}
828 
829 	if (value_maskp != NULL)
830 		*value_maskp = value_mask;
831 
832 	EFSYS_ASSERT(resultp != NULL);
833 	if (result == MC_CMD_POLL_BIST_RUNNING)
834 		*resultp = EFX_PHY_BIST_RESULT_RUNNING;
835 	else if (result == MC_CMD_POLL_BIST_PASSED)
836 		*resultp = EFX_PHY_BIST_RESULT_PASSED;
837 	else
838 		*resultp = EFX_PHY_BIST_RESULT_FAILED;
839 
840 	return (0);
841 
842 fail2:
843 	EFSYS_PROBE(fail2);
844 fail1:
845 	EFSYS_PROBE1(fail1, int, rc);
846 
847 	return (rc);
848 }
849 
850 			void
851 siena_phy_bist_stop(
852 	__in		efx_nic_t *enp,
853 	__in		efx_phy_bist_type_t type)
854 {
855 	/* There is no way to stop BIST on Siena */
856 	_NOTE(ARGUNUSED(enp, type))
857 }
858 
859 #endif	/* EFSYS_OPT_PHY_BIST */
860 
861 #endif	/* EFSYS_OPT_SIENA */
862