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