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