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