]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/sfxge/common/efx_phy.c
MFC r340765
[FreeBSD/stable/10.git] / sys / dev / sfxge / common / efx_phy.c
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         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
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
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
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
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
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
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
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
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
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 > 0xff) {
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 *
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
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
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
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
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
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
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 }