xref: /freebsd/sys/dev/sfxge/common/efx_phy.c (revision 1d386b48)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2007-2016 Solarflare Communications Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  *    this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * The views and conclusions contained in the software and documentation are
29  * those of the authors and should not be interpreted as representing official
30  * policies, either expressed or implied, of the FreeBSD Project.
31  */
32 
33 #include <sys/cdefs.h>
34 #include "efx.h"
35 #include "efx_impl.h"
36 
37 #if EFSYS_OPT_SIENA
38 static const efx_phy_ops_t	__efx_phy_siena_ops = {
39 	siena_phy_power,		/* epo_power */
40 	NULL,				/* epo_reset */
41 	siena_phy_reconfigure,		/* epo_reconfigure */
42 	siena_phy_verify,		/* epo_verify */
43 	siena_phy_oui_get,		/* epo_oui_get */
44 	NULL,				/* epo_link_state_get */
45 #if EFSYS_OPT_PHY_STATS
46 	siena_phy_stats_update,		/* epo_stats_update */
47 #endif	/* EFSYS_OPT_PHY_STATS */
48 #if EFSYS_OPT_BIST
49 	NULL,				/* epo_bist_enable_offline */
50 	siena_phy_bist_start,		/* epo_bist_start */
51 	siena_phy_bist_poll,		/* epo_bist_poll */
52 	siena_phy_bist_stop,		/* epo_bist_stop */
53 #endif	/* EFSYS_OPT_BIST */
54 };
55 #endif	/* EFSYS_OPT_SIENA */
56 
57 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
58 static const efx_phy_ops_t	__efx_phy_ef10_ops = {
59 	ef10_phy_power,			/* epo_power */
60 	NULL,				/* epo_reset */
61 	ef10_phy_reconfigure,		/* epo_reconfigure */
62 	ef10_phy_verify,		/* epo_verify */
63 	ef10_phy_oui_get,		/* epo_oui_get */
64 	ef10_phy_link_state_get,	/* epo_link_state_get */
65 #if EFSYS_OPT_PHY_STATS
66 	ef10_phy_stats_update,		/* epo_stats_update */
67 #endif	/* EFSYS_OPT_PHY_STATS */
68 #if EFSYS_OPT_BIST
69 	ef10_bist_enable_offline,	/* epo_bist_enable_offline */
70 	ef10_bist_start,		/* epo_bist_start */
71 	ef10_bist_poll,			/* epo_bist_poll */
72 	ef10_bist_stop,			/* epo_bist_stop */
73 #endif	/* EFSYS_OPT_BIST */
74 };
75 #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
76 
77 	__checkReturn	efx_rc_t
78 efx_phy_probe(
79 	__in		efx_nic_t *enp)
80 {
81 	efx_port_t *epp = &(enp->en_port);
82 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
83 	const efx_phy_ops_t *epop;
84 	efx_rc_t rc;
85 
86 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
87 
88 	epp->ep_port = encp->enc_port;
89 	epp->ep_phy_type = encp->enc_phy_type;
90 
91 	/* Hook in operations structure */
92 	switch (enp->en_family) {
93 #if EFSYS_OPT_SIENA
94 	case EFX_FAMILY_SIENA:
95 		epop = &__efx_phy_siena_ops;
96 		break;
97 #endif	/* EFSYS_OPT_SIENA */
98 
99 #if EFSYS_OPT_HUNTINGTON
100 	case EFX_FAMILY_HUNTINGTON:
101 		epop = &__efx_phy_ef10_ops;
102 		break;
103 #endif	/* EFSYS_OPT_HUNTINGTON */
104 
105 #if EFSYS_OPT_MEDFORD
106 	case EFX_FAMILY_MEDFORD:
107 		epop = &__efx_phy_ef10_ops;
108 		break;
109 #endif	/* EFSYS_OPT_MEDFORD */
110 
111 #if EFSYS_OPT_MEDFORD2
112 	case EFX_FAMILY_MEDFORD2:
113 		epop = &__efx_phy_ef10_ops;
114 		break;
115 #endif	/* EFSYS_OPT_MEDFORD2 */
116 
117 	default:
118 		rc = ENOTSUP;
119 		goto fail1;
120 	}
121 
122 	epp->ep_epop = epop;
123 
124 	return (0);
125 
126 fail1:
127 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
128 
129 	epp->ep_port = 0;
130 	epp->ep_phy_type = 0;
131 
132 	return (rc);
133 }
134 
135 	__checkReturn	efx_rc_t
136 efx_phy_verify(
137 	__in		efx_nic_t *enp)
138 {
139 	efx_port_t *epp = &(enp->en_port);
140 	const efx_phy_ops_t *epop = epp->ep_epop;
141 
142 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
143 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
144 
145 	return (epop->epo_verify(enp));
146 }
147 
148 #if EFSYS_OPT_PHY_LED_CONTROL
149 
150 	__checkReturn	efx_rc_t
151 efx_phy_led_set(
152 	__in		efx_nic_t *enp,
153 	__in		efx_phy_led_mode_t mode)
154 {
155 	efx_nic_cfg_t *encp = (&enp->en_nic_cfg);
156 	efx_port_t *epp = &(enp->en_port);
157 	const efx_phy_ops_t *epop = epp->ep_epop;
158 	uint32_t mask;
159 	efx_rc_t rc;
160 
161 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
162 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
163 
164 	if (epp->ep_phy_led_mode == mode)
165 		goto done;
166 
167 	mask = (1 << EFX_PHY_LED_DEFAULT);
168 	mask |= encp->enc_led_mask;
169 
170 	if (!((1 << mode) & mask)) {
171 		rc = ENOTSUP;
172 		goto fail1;
173 	}
174 
175 	EFSYS_ASSERT3U(mode, <, EFX_PHY_LED_NMODES);
176 	epp->ep_phy_led_mode = mode;
177 
178 	if ((rc = epop->epo_reconfigure(enp)) != 0)
179 		goto fail2;
180 
181 done:
182 	return (0);
183 
184 fail2:
185 	EFSYS_PROBE(fail2);
186 fail1:
187 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
188 
189 	return (rc);
190 }
191 #endif	/* EFSYS_OPT_PHY_LED_CONTROL */
192 
193 			void
194 efx_phy_adv_cap_get(
195 	__in		efx_nic_t *enp,
196 	__in		uint32_t flag,
197 	__out		uint32_t *maskp)
198 {
199 	efx_port_t *epp = &(enp->en_port);
200 
201 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
202 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
203 
204 	switch (flag) {
205 	case EFX_PHY_CAP_CURRENT:
206 		*maskp = epp->ep_adv_cap_mask;
207 		break;
208 	case EFX_PHY_CAP_DEFAULT:
209 		*maskp = epp->ep_default_adv_cap_mask;
210 		break;
211 	case EFX_PHY_CAP_PERM:
212 		*maskp = epp->ep_phy_cap_mask;
213 		break;
214 	default:
215 		EFSYS_ASSERT(B_FALSE);
216 		*maskp = 0;
217 		break;
218 	}
219 }
220 
221 	__checkReturn	efx_rc_t
222 efx_phy_adv_cap_set(
223 	__in		efx_nic_t *enp,
224 	__in		uint32_t mask)
225 {
226 	efx_port_t *epp = &(enp->en_port);
227 	const efx_phy_ops_t *epop = epp->ep_epop;
228 	uint32_t old_mask;
229 	efx_rc_t rc;
230 
231 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
232 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
233 
234 	if ((mask & ~epp->ep_phy_cap_mask) != 0) {
235 		rc = ENOTSUP;
236 		goto fail1;
237 	}
238 
239 	if (epp->ep_adv_cap_mask == mask)
240 		goto done;
241 
242 	old_mask = epp->ep_adv_cap_mask;
243 	epp->ep_adv_cap_mask = mask;
244 
245 	if ((rc = epop->epo_reconfigure(enp)) != 0)
246 		goto fail2;
247 
248 done:
249 	return (0);
250 
251 fail2:
252 	EFSYS_PROBE(fail2);
253 
254 	epp->ep_adv_cap_mask = old_mask;
255 	/* Reconfigure for robustness */
256 	if (epop->epo_reconfigure(enp) != 0) {
257 		/*
258 		 * We may have an inconsistent view of our advertised speed
259 		 * capabilities.
260 		 */
261 		EFSYS_ASSERT(0);
262 	}
263 
264 fail1:
265 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
266 
267 	return (rc);
268 }
269 
270 	void
271 efx_phy_lp_cap_get(
272 	__in		efx_nic_t *enp,
273 	__out		uint32_t *maskp)
274 {
275 	efx_port_t *epp = &(enp->en_port);
276 
277 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
278 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
279 
280 	*maskp = epp->ep_lp_cap_mask;
281 }
282 
283 	__checkReturn	efx_rc_t
284 efx_phy_oui_get(
285 	__in		efx_nic_t *enp,
286 	__out		uint32_t *ouip)
287 {
288 	efx_port_t *epp = &(enp->en_port);
289 	const efx_phy_ops_t *epop = epp->ep_epop;
290 
291 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
292 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
293 
294 	return (epop->epo_oui_get(enp, ouip));
295 }
296 
297 			void
298 efx_phy_media_type_get(
299 	__in		efx_nic_t *enp,
300 	__out		efx_phy_media_type_t *typep)
301 {
302 	efx_port_t *epp = &(enp->en_port);
303 
304 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
305 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
306 
307 	if (epp->ep_module_type != EFX_PHY_MEDIA_INVALID)
308 		*typep = epp->ep_module_type;
309 	else
310 		*typep = epp->ep_fixed_port_type;
311 }
312 
313 	__checkReturn		efx_rc_t
314 efx_phy_module_get_info(
315 	__in			efx_nic_t *enp,
316 	__in			uint8_t dev_addr,
317 	__in			size_t offset,
318 	__in			size_t len,
319 	__out_bcount(len)	uint8_t *data)
320 {
321 	efx_rc_t rc;
322 
323 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
324 	EFSYS_ASSERT(data != NULL);
325 
326 	if ((offset > EFX_PHY_MEDIA_INFO_MAX_OFFSET) ||
327 	    ((offset + len) > EFX_PHY_MEDIA_INFO_MAX_OFFSET)) {
328 		rc = EINVAL;
329 		goto fail1;
330 	}
331 
332 	if ((rc = efx_mcdi_phy_module_get_info(enp, dev_addr,
333 	    offset, len, data)) != 0)
334 		goto fail2;
335 
336 	return (0);
337 
338 fail2:
339 	EFSYS_PROBE(fail2);
340 fail1:
341 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
342 
343 	return (rc);
344 }
345 
346 	__checkReturn		efx_rc_t
347 efx_phy_fec_type_get(
348 	__in		efx_nic_t *enp,
349 	__out		efx_phy_fec_type_t *typep)
350 {
351 	efx_rc_t rc;
352 	efx_phy_link_state_t epls;
353 
354 	if ((rc = efx_phy_link_state_get(enp, &epls)) != 0)
355 		goto fail1;
356 
357 	*typep = epls.epls_fec;
358 
359 	return (0);
360 
361 fail1:
362 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
363 
364 	return (rc);
365 }
366 
367 	__checkReturn		efx_rc_t
368 efx_phy_link_state_get(
369 	__in		efx_nic_t *enp,
370 	__out		efx_phy_link_state_t *eplsp)
371 {
372 	efx_port_t *epp = &(enp->en_port);
373 	const efx_phy_ops_t *epop = epp->ep_epop;
374 	efx_rc_t rc;
375 
376 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
377 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
378 
379 	if (epop->epo_link_state_get == NULL) {
380 		rc = ENOTSUP;
381 		goto fail1;
382 	}
383 
384 	if ((rc = epop->epo_link_state_get(enp, eplsp)) != 0)
385 		goto fail2;
386 
387 	return (0);
388 
389 fail2:
390 	EFSYS_PROBE(fail2);
391 fail1:
392 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
393 
394 	return (rc);
395 }
396 
397 #if EFSYS_OPT_PHY_STATS
398 
399 #if EFSYS_OPT_NAMES
400 
401 /* START MKCONFIG GENERATED PhyStatNamesBlock af9ffa24da3bc100 */
402 static const char * const __efx_phy_stat_name[] = {
403 	"oui",
404 	"pma_pmd_link_up",
405 	"pma_pmd_rx_fault",
406 	"pma_pmd_tx_fault",
407 	"pma_pmd_rev_a",
408 	"pma_pmd_rev_b",
409 	"pma_pmd_rev_c",
410 	"pma_pmd_rev_d",
411 	"pcs_link_up",
412 	"pcs_rx_fault",
413 	"pcs_tx_fault",
414 	"pcs_ber",
415 	"pcs_block_errors",
416 	"phy_xs_link_up",
417 	"phy_xs_rx_fault",
418 	"phy_xs_tx_fault",
419 	"phy_xs_align",
420 	"phy_xs_sync_a",
421 	"phy_xs_sync_b",
422 	"phy_xs_sync_c",
423 	"phy_xs_sync_d",
424 	"an_link_up",
425 	"an_master",
426 	"an_local_rx_ok",
427 	"an_remote_rx_ok",
428 	"cl22ext_link_up",
429 	"snr_a",
430 	"snr_b",
431 	"snr_c",
432 	"snr_d",
433 	"pma_pmd_signal_a",
434 	"pma_pmd_signal_b",
435 	"pma_pmd_signal_c",
436 	"pma_pmd_signal_d",
437 	"an_complete",
438 	"pma_pmd_rev_major",
439 	"pma_pmd_rev_minor",
440 	"pma_pmd_rev_micro",
441 	"pcs_fw_version_0",
442 	"pcs_fw_version_1",
443 	"pcs_fw_version_2",
444 	"pcs_fw_version_3",
445 	"pcs_fw_build_yy",
446 	"pcs_fw_build_mm",
447 	"pcs_fw_build_dd",
448 	"pcs_op_mode",
449 };
450 
451 /* END MKCONFIG GENERATED PhyStatNamesBlock */
452 
453 					const char *
454 efx_phy_stat_name(
455 	__in				efx_nic_t *enp,
456 	__in				efx_phy_stat_t type)
457 {
458 	_NOTE(ARGUNUSED(enp))
459 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
460 	EFSYS_ASSERT3U(type, <, EFX_PHY_NSTATS);
461 
462 	return (__efx_phy_stat_name[type]);
463 }
464 
465 #endif	/* EFSYS_OPT_NAMES */
466 
467 	__checkReturn			efx_rc_t
468 efx_phy_stats_update(
469 	__in				efx_nic_t *enp,
470 	__in				efsys_mem_t *esmp,
471 	__inout_ecount(EFX_PHY_NSTATS)	uint32_t *stat)
472 {
473 	efx_port_t *epp = &(enp->en_port);
474 	const efx_phy_ops_t *epop = epp->ep_epop;
475 
476 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
477 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
478 
479 	return (epop->epo_stats_update(enp, esmp, stat));
480 }
481 
482 #endif	/* EFSYS_OPT_PHY_STATS */
483 
484 #if EFSYS_OPT_BIST
485 
486 	__checkReturn		efx_rc_t
487 efx_bist_enable_offline(
488 	__in			efx_nic_t *enp)
489 {
490 	efx_port_t *epp = &(enp->en_port);
491 	const efx_phy_ops_t *epop = epp->ep_epop;
492 	efx_rc_t rc;
493 
494 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
495 
496 	if (epop->epo_bist_enable_offline == NULL) {
497 		rc = ENOTSUP;
498 		goto fail1;
499 	}
500 
501 	if ((rc = epop->epo_bist_enable_offline(enp)) != 0)
502 		goto fail2;
503 
504 	return (0);
505 
506 fail2:
507 	EFSYS_PROBE(fail2);
508 fail1:
509 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
510 
511 	return (rc);
512 
513 }
514 
515 	__checkReturn		efx_rc_t
516 efx_bist_start(
517 	__in			efx_nic_t *enp,
518 	__in			efx_bist_type_t type)
519 {
520 	efx_port_t *epp = &(enp->en_port);
521 	const efx_phy_ops_t *epop = epp->ep_epop;
522 	efx_rc_t rc;
523 
524 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
525 
526 	EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
527 	EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
528 	EFSYS_ASSERT3U(epp->ep_current_bist, ==, EFX_BIST_TYPE_UNKNOWN);
529 
530 	if (epop->epo_bist_start == NULL) {
531 		rc = ENOTSUP;
532 		goto fail1;
533 	}
534 
535 	if ((rc = epop->epo_bist_start(enp, type)) != 0)
536 		goto fail2;
537 
538 	epp->ep_current_bist = type;
539 
540 	return (0);
541 
542 fail2:
543 	EFSYS_PROBE(fail2);
544 fail1:
545 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
546 
547 	return (rc);
548 }
549 
550 	__checkReturn		efx_rc_t
551 efx_bist_poll(
552 	__in			efx_nic_t *enp,
553 	__in			efx_bist_type_t type,
554 	__out			efx_bist_result_t *resultp,
555 	__out_opt		uint32_t *value_maskp,
556 	__out_ecount_opt(count)	unsigned long *valuesp,
557 	__in			size_t count)
558 {
559 	efx_port_t *epp = &(enp->en_port);
560 	const efx_phy_ops_t *epop = epp->ep_epop;
561 	efx_rc_t rc;
562 
563 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
564 
565 	EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
566 	EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
567 	EFSYS_ASSERT3U(epp->ep_current_bist, ==, type);
568 
569 	EFSYS_ASSERT(epop->epo_bist_poll != NULL);
570 	if (epop->epo_bist_poll == NULL) {
571 		rc = ENOTSUP;
572 		goto fail1;
573 	}
574 
575 	if ((rc = epop->epo_bist_poll(enp, type, resultp, value_maskp,
576 	    valuesp, count)) != 0)
577 		goto fail2;
578 
579 	return (0);
580 
581 fail2:
582 	EFSYS_PROBE(fail2);
583 fail1:
584 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
585 
586 	return (rc);
587 }
588 
589 			void
590 efx_bist_stop(
591 	__in		efx_nic_t *enp,
592 	__in		efx_bist_type_t type)
593 {
594 	efx_port_t *epp = &(enp->en_port);
595 	const efx_phy_ops_t *epop = epp->ep_epop;
596 
597 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
598 
599 	EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
600 	EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
601 	EFSYS_ASSERT3U(epp->ep_current_bist, ==, type);
602 
603 	EFSYS_ASSERT(epop->epo_bist_stop != NULL);
604 
605 	if (epop->epo_bist_stop != NULL)
606 		epop->epo_bist_stop(enp, type);
607 
608 	epp->ep_current_bist = EFX_BIST_TYPE_UNKNOWN;
609 }
610 
611 #endif	/* EFSYS_OPT_BIST */
612 			void
613 efx_phy_unprobe(
614 	__in	efx_nic_t *enp)
615 {
616 	efx_port_t *epp = &(enp->en_port);
617 
618 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
619 
620 	epp->ep_epop = NULL;
621 
622 	epp->ep_adv_cap_mask = 0;
623 
624 	epp->ep_port = 0;
625 	epp->ep_phy_type = 0;
626 }
627