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