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