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