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