xref: /illumos-gate/usr/src/uts/common/io/sfxge/common/efx_phy.c (revision 49ef7e0638c8b771d8a136eae78b1c0f99acc8e0)
1 /*
2  * Copyright (c) 2007-2015 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 "efx.h"
32 #include "efx_impl.h"
33 
34 
35 #if EFSYS_OPT_SIENA
36 static const efx_phy_ops_t	__efx_phy_siena_ops = {
37 	siena_phy_power,		/* epo_power */
38 	NULL,				/* epo_reset */
39 	siena_phy_reconfigure,		/* epo_reconfigure */
40 	siena_phy_verify,		/* epo_verify */
41 	siena_phy_oui_get,		/* epo_oui_get */
42 #if EFSYS_OPT_PHY_STATS
43 	siena_phy_stats_update,		/* epo_stats_update */
44 #endif	/* EFSYS_OPT_PHY_STATS */
45 #if EFSYS_OPT_BIST
46 	NULL,				/* epo_bist_enable_offline */
47 	siena_phy_bist_start, 		/* epo_bist_start */
48 	siena_phy_bist_poll,		/* epo_bist_poll */
49 	siena_phy_bist_stop,		/* epo_bist_stop */
50 #endif	/* EFSYS_OPT_BIST */
51 };
52 #endif	/* EFSYS_OPT_SIENA */
53 
54 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
55 static const efx_phy_ops_t	__efx_phy_ef10_ops = {
56 	ef10_phy_power,			/* epo_power */
57 	NULL,				/* epo_reset */
58 	ef10_phy_reconfigure,		/* epo_reconfigure */
59 	ef10_phy_verify,		/* epo_verify */
60 	ef10_phy_oui_get,		/* epo_oui_get */
61 #if EFSYS_OPT_PHY_STATS
62 	ef10_phy_stats_update,		/* epo_stats_update */
63 #endif	/* EFSYS_OPT_PHY_STATS */
64 #if EFSYS_OPT_BIST
65 	/* FIXME: Are these BIST methods appropriate for Medford? */
66 	hunt_bist_enable_offline,	/* epo_bist_enable_offline */
67 	hunt_bist_start,		/* epo_bist_start */
68 	hunt_bist_poll,			/* epo_bist_poll */
69 	hunt_bist_stop,			/* epo_bist_stop */
70 #endif	/* EFSYS_OPT_BIST */
71 };
72 #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
73 
74 	__checkReturn	efx_rc_t
75 efx_phy_probe(
76 	__in		efx_nic_t *enp)
77 {
78 	efx_port_t *epp = &(enp->en_port);
79 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
80 	const efx_phy_ops_t *epop;
81 	efx_rc_t rc;
82 
83 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
84 
85 	epp->ep_port = encp->enc_port;
86 	epp->ep_phy_type = encp->enc_phy_type;
87 
88 	/* Hook in operations structure */
89 	switch (enp->en_family) {
90 #if EFSYS_OPT_SIENA
91 	case EFX_FAMILY_SIENA:
92 		epop = &__efx_phy_siena_ops;
93 		break;
94 #endif	/* EFSYS_OPT_SIENA */
95 #if EFSYS_OPT_HUNTINGTON
96 	case EFX_FAMILY_HUNTINGTON:
97 		epop = &__efx_phy_ef10_ops;
98 		break;
99 #endif	/* EFSYS_OPT_HUNTINGTON */
100 #if EFSYS_OPT_MEDFORD
101 	case EFX_FAMILY_MEDFORD:
102 		epop = &__efx_phy_ef10_ops;
103 		break;
104 #endif	/* EFSYS_OPT_MEDFORD */
105 	default:
106 		rc = ENOTSUP;
107 		goto fail1;
108 	}
109 
110 	epp->ep_epop = epop;
111 
112 	return (0);
113 
114 fail1:
115 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
116 
117 	epp->ep_port = 0;
118 	epp->ep_phy_type = 0;
119 
120 	return (rc);
121 }
122 
123 	__checkReturn	efx_rc_t
124 efx_phy_verify(
125 	__in		efx_nic_t *enp)
126 {
127 	efx_port_t *epp = &(enp->en_port);
128 	const efx_phy_ops_t *epop = epp->ep_epop;
129 
130 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
131 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
132 
133 	return (epop->epo_verify(enp));
134 }
135 
136 #if EFSYS_OPT_PHY_LED_CONTROL
137 
138 	__checkReturn	efx_rc_t
139 efx_phy_led_set(
140 	__in		efx_nic_t *enp,
141 	__in		efx_phy_led_mode_t mode)
142 {
143 	efx_nic_cfg_t *encp = (&enp->en_nic_cfg);
144 	efx_port_t *epp = &(enp->en_port);
145 	const efx_phy_ops_t *epop = epp->ep_epop;
146 	uint32_t mask;
147 	efx_rc_t rc;
148 
149 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
150 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
151 
152 	if (epp->ep_phy_led_mode == mode)
153 		goto done;
154 
155 	mask = (1 << EFX_PHY_LED_DEFAULT);
156 	mask |= encp->enc_led_mask;
157 
158 	if (!((1 << mode) & mask)) {
159 		rc = ENOTSUP;
160 		goto fail1;
161 	}
162 
163 	EFSYS_ASSERT3U(mode, <, EFX_PHY_LED_NMODES);
164 	epp->ep_phy_led_mode = mode;
165 
166 	if ((rc = epop->epo_reconfigure(enp)) != 0)
167 		goto fail2;
168 
169 done:
170 	return (0);
171 
172 fail2:
173 	EFSYS_PROBE(fail2);
174 fail1:
175 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
176 
177 	return (rc);
178 }
179 #endif	/* EFSYS_OPT_PHY_LED_CONTROL */
180 
181 			void
182 efx_phy_adv_cap_get(
183 	__in		efx_nic_t *enp,
184 	__in		uint32_t flag,
185 	__out		uint32_t *maskp)
186 {
187 	efx_port_t *epp = &(enp->en_port);
188 
189 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
190 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
191 
192 	switch (flag) {
193 	case EFX_PHY_CAP_CURRENT:
194 		*maskp = epp->ep_adv_cap_mask;
195 		break;
196 	case EFX_PHY_CAP_DEFAULT:
197 		*maskp = epp->ep_default_adv_cap_mask;
198 		break;
199 	case EFX_PHY_CAP_PERM:
200 		*maskp = epp->ep_phy_cap_mask;
201 		break;
202 	default:
203 		EFSYS_ASSERT(B_FALSE);
204 		break;
205 	}
206 }
207 
208 	__checkReturn	efx_rc_t
209 efx_phy_adv_cap_set(
210 	__in		efx_nic_t *enp,
211 	__in		uint32_t mask)
212 {
213 	efx_port_t *epp = &(enp->en_port);
214 	const efx_phy_ops_t *epop = epp->ep_epop;
215 	uint32_t old_mask;
216 	efx_rc_t rc;
217 
218 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
219 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
220 
221 	if ((mask & ~epp->ep_phy_cap_mask) != 0) {
222 		rc = ENOTSUP;
223 		goto fail1;
224 	}
225 
226 	if (epp->ep_adv_cap_mask == mask)
227 		goto done;
228 
229 	old_mask = epp->ep_adv_cap_mask;
230 	epp->ep_adv_cap_mask = mask;
231 
232 	if ((rc = epop->epo_reconfigure(enp)) != 0)
233 		goto fail2;
234 
235 done:
236 	return (0);
237 
238 fail2:
239 	EFSYS_PROBE(fail2);
240 
241 	epp->ep_adv_cap_mask = old_mask;
242 	/* Reconfigure for robustness */
243 	if (epop->epo_reconfigure(enp) != 0) {
244 		/*
245 		 * We may have an inconsistent view of our advertised speed
246 		 * capabilities.
247 		 */
248 		EFSYS_ASSERT(0);
249 	}
250 
251 fail1:
252 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
253 
254 	return (rc);
255 }
256 
257 	void
258 efx_phy_lp_cap_get(
259 	__in		efx_nic_t *enp,
260 	__out		uint32_t *maskp)
261 {
262 	efx_port_t *epp = &(enp->en_port);
263 
264 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
265 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
266 
267 	*maskp = epp->ep_lp_cap_mask;
268 }
269 
270 	__checkReturn	efx_rc_t
271 efx_phy_oui_get(
272 	__in		efx_nic_t *enp,
273 	__out		uint32_t *ouip)
274 {
275 	efx_port_t *epp = &(enp->en_port);
276 	const efx_phy_ops_t *epop = epp->ep_epop;
277 
278 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
279 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
280 
281 	return (epop->epo_oui_get(enp, ouip));
282 }
283 
284 			void
285 efx_phy_media_type_get(
286 	__in		efx_nic_t *enp,
287 	__out		efx_phy_media_type_t *typep)
288 {
289 	efx_port_t *epp = &(enp->en_port);
290 
291 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
292 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
293 
294 	if (epp->ep_module_type != EFX_PHY_MEDIA_INVALID)
295 		*typep = epp->ep_module_type;
296 	else
297 		*typep = epp->ep_fixed_port_type;
298 }
299 
300 	__checkReturn	efx_rc_t
301 efx_phy_module_get_info(
302 	__in			efx_nic_t *enp,
303 	__in			uint8_t dev_addr,
304 	__in			uint8_t offset,
305 	__in			uint8_t len,
306 	__out_bcount(len)	uint8_t *data)
307 {
308 	efx_rc_t rc;
309 
310 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
311 	EFSYS_ASSERT(data != NULL);
312 
313 	if ((uint32_t)offset + len > 0xff) {
314 		rc = EINVAL;
315 		goto fail1;
316 	}
317 
318 	if ((rc = efx_mcdi_phy_module_get_info(enp, dev_addr,
319 	    offset, len, data)) != 0)
320 		goto fail2;
321 
322 	return (0);
323 
324 fail2:
325 	EFSYS_PROBE(fail2);
326 fail1:
327 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
328 
329 	return (rc);
330 }
331 
332 #if EFSYS_OPT_PHY_STATS
333 
334 #if EFSYS_OPT_NAMES
335 
336 /* START MKCONFIG GENERATED PhyStatNamesBlock d5f79b4bc2c050fe */
337 static const char 	*__efx_phy_stat_name[] = {
338 	"oui",
339 	"pma_pmd_link_up",
340 	"pma_pmd_rx_fault",
341 	"pma_pmd_tx_fault",
342 	"pma_pmd_rev_a",
343 	"pma_pmd_rev_b",
344 	"pma_pmd_rev_c",
345 	"pma_pmd_rev_d",
346 	"pcs_link_up",
347 	"pcs_rx_fault",
348 	"pcs_tx_fault",
349 	"pcs_ber",
350 	"pcs_block_errors",
351 	"phy_xs_link_up",
352 	"phy_xs_rx_fault",
353 	"phy_xs_tx_fault",
354 	"phy_xs_align",
355 	"phy_xs_sync_a",
356 	"phy_xs_sync_b",
357 	"phy_xs_sync_c",
358 	"phy_xs_sync_d",
359 	"an_link_up",
360 	"an_master",
361 	"an_local_rx_ok",
362 	"an_remote_rx_ok",
363 	"cl22ext_link_up",
364 	"snr_a",
365 	"snr_b",
366 	"snr_c",
367 	"snr_d",
368 	"pma_pmd_signal_a",
369 	"pma_pmd_signal_b",
370 	"pma_pmd_signal_c",
371 	"pma_pmd_signal_d",
372 	"an_complete",
373 	"pma_pmd_rev_major",
374 	"pma_pmd_rev_minor",
375 	"pma_pmd_rev_micro",
376 	"pcs_fw_version_0",
377 	"pcs_fw_version_1",
378 	"pcs_fw_version_2",
379 	"pcs_fw_version_3",
380 	"pcs_fw_build_yy",
381 	"pcs_fw_build_mm",
382 	"pcs_fw_build_dd",
383 	"pcs_op_mode",
384 };
385 
386 /* END MKCONFIG GENERATED PhyStatNamesBlock */
387 
388 					const char *
389 efx_phy_stat_name(
390 	__in				efx_nic_t *enp,
391 	__in				efx_phy_stat_t type)
392 {
393 	_NOTE(ARGUNUSED(enp))
394 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
395 	EFSYS_ASSERT3U(type, <, EFX_PHY_NSTATS);
396 
397 	return (__efx_phy_stat_name[type]);
398 }
399 
400 #endif	/* EFSYS_OPT_NAMES */
401 
402 	__checkReturn			efx_rc_t
403 efx_phy_stats_update(
404 	__in				efx_nic_t *enp,
405 	__in				efsys_mem_t *esmp,
406 	__inout_ecount(EFX_PHY_NSTATS)	uint32_t *stat)
407 {
408 	efx_port_t *epp = &(enp->en_port);
409 	const efx_phy_ops_t *epop = epp->ep_epop;
410 
411 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
412 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
413 
414 	return (epop->epo_stats_update(enp, esmp, stat));
415 }
416 
417 #endif	/* EFSYS_OPT_PHY_STATS */
418 
419 
420 #if EFSYS_OPT_BIST
421 
422 	__checkReturn		efx_rc_t
423 efx_bist_enable_offline(
424 	__in			efx_nic_t *enp)
425 {
426 	efx_port_t *epp = &(enp->en_port);
427 	const efx_phy_ops_t *epop = epp->ep_epop;
428 	efx_rc_t rc;
429 
430 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
431 
432 	if (epop->epo_bist_enable_offline == NULL) {
433 		rc = ENOTSUP;
434 		goto fail1;
435 	}
436 
437 	if ((rc = epop->epo_bist_enable_offline(enp)) != 0)
438 		goto fail2;
439 
440 	return (0);
441 
442 fail2:
443 	EFSYS_PROBE(fail2);
444 fail1:
445 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
446 
447 	return (rc);
448 
449 }
450 
451 	__checkReturn		efx_rc_t
452 efx_bist_start(
453 	__in			efx_nic_t *enp,
454 	__in			efx_bist_type_t type)
455 {
456 	efx_port_t *epp = &(enp->en_port);
457 	const efx_phy_ops_t *epop = epp->ep_epop;
458 	efx_rc_t rc;
459 
460 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
461 
462 	EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
463 	EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
464 	EFSYS_ASSERT3U(epp->ep_current_bist, ==, EFX_BIST_TYPE_UNKNOWN);
465 
466 	if (epop->epo_bist_start == NULL) {
467 		rc = ENOTSUP;
468 		goto fail1;
469 	}
470 
471 	if ((rc = epop->epo_bist_start(enp, type)) != 0)
472 		goto fail2;
473 
474 	epp->ep_current_bist = type;
475 
476 	return (0);
477 
478 fail2:
479 	EFSYS_PROBE(fail2);
480 fail1:
481 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
482 
483 	return (rc);
484 }
485 
486 	__checkReturn		efx_rc_t
487 efx_bist_poll(
488 	__in			efx_nic_t *enp,
489 	__in			efx_bist_type_t type,
490 	__out			efx_bist_result_t *resultp,
491 	__out_opt		uint32_t *value_maskp,
492 	__out_ecount_opt(count)	unsigned long *valuesp,
493 	__in			size_t count)
494 {
495 	efx_port_t *epp = &(enp->en_port);
496 	const efx_phy_ops_t *epop = epp->ep_epop;
497 	efx_rc_t rc;
498 
499 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
500 
501 	EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
502 	EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
503 	EFSYS_ASSERT3U(epp->ep_current_bist, ==, type);
504 
505 	EFSYS_ASSERT(epop->epo_bist_poll != NULL);
506 	if (epop->epo_bist_poll == NULL) {
507 		rc = ENOTSUP;
508 		goto fail1;
509 	}
510 
511 	if ((rc = epop->epo_bist_poll(enp, type, resultp, value_maskp,
512 	    valuesp, count)) != 0)
513 		goto fail2;
514 
515 	return (0);
516 
517 fail2:
518 	EFSYS_PROBE(fail2);
519 fail1:
520 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
521 
522 	return (rc);
523 }
524 
525 			void
526 efx_bist_stop(
527 	__in		efx_nic_t *enp,
528 	__in		efx_bist_type_t type)
529 {
530 	efx_port_t *epp = &(enp->en_port);
531 	const efx_phy_ops_t *epop = epp->ep_epop;
532 
533 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
534 
535 	EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
536 	EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
537 	EFSYS_ASSERT3U(epp->ep_current_bist, ==, type);
538 
539 	EFSYS_ASSERT(epop->epo_bist_stop != NULL);
540 
541 	if (epop->epo_bist_stop != NULL)
542 		epop->epo_bist_stop(enp, type);
543 
544 	epp->ep_current_bist = EFX_BIST_TYPE_UNKNOWN;
545 }
546 
547 #endif	/* EFSYS_OPT_BIST */
548 			void
549 efx_phy_unprobe(
550 	__in	efx_nic_t *enp)
551 {
552 	efx_port_t *epp = &(enp->en_port);
553 
554 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
555 
556 	epp->ep_epop = NULL;
557 
558 	epp->ep_adv_cap_mask = 0;
559 
560 	epp->ep_port = 0;
561 	epp->ep_phy_type = 0;
562 }
563