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