net/sfc/base: import PHY statistics
[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                         void
136 efx_phy_adv_cap_get(
137         __in            efx_nic_t *enp,
138         __in            uint32_t flag,
139         __out           uint32_t *maskp)
140 {
141         efx_port_t *epp = &(enp->en_port);
142
143         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
144         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
145
146         switch (flag) {
147         case EFX_PHY_CAP_CURRENT:
148                 *maskp = epp->ep_adv_cap_mask;
149                 break;
150         case EFX_PHY_CAP_DEFAULT:
151                 *maskp = epp->ep_default_adv_cap_mask;
152                 break;
153         case EFX_PHY_CAP_PERM:
154                 *maskp = epp->ep_phy_cap_mask;
155                 break;
156         default:
157                 EFSYS_ASSERT(B_FALSE);
158                 break;
159         }
160 }
161
162         __checkReturn   efx_rc_t
163 efx_phy_adv_cap_set(
164         __in            efx_nic_t *enp,
165         __in            uint32_t mask)
166 {
167         efx_port_t *epp = &(enp->en_port);
168         const efx_phy_ops_t *epop = epp->ep_epop;
169         uint32_t old_mask;
170         efx_rc_t rc;
171
172         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
173         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
174
175         if ((mask & ~epp->ep_phy_cap_mask) != 0) {
176                 rc = ENOTSUP;
177                 goto fail1;
178         }
179
180         if (epp->ep_adv_cap_mask == mask)
181                 goto done;
182
183         old_mask = epp->ep_adv_cap_mask;
184         epp->ep_adv_cap_mask = mask;
185
186         if ((rc = epop->epo_reconfigure(enp)) != 0)
187                 goto fail2;
188
189 done:
190         return (0);
191
192 fail2:
193         EFSYS_PROBE(fail2);
194
195         epp->ep_adv_cap_mask = old_mask;
196         /* Reconfigure for robustness */
197         if (epop->epo_reconfigure(enp) != 0) {
198                 /*
199                  * We may have an inconsistent view of our advertised speed
200                  * capabilities.
201                  */
202                 EFSYS_ASSERT(0);
203         }
204
205 fail1:
206         EFSYS_PROBE1(fail1, efx_rc_t, rc);
207
208         return (rc);
209 }
210
211         void
212 efx_phy_lp_cap_get(
213         __in            efx_nic_t *enp,
214         __out           uint32_t *maskp)
215 {
216         efx_port_t *epp = &(enp->en_port);
217
218         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
219         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
220
221         *maskp = epp->ep_lp_cap_mask;
222 }
223
224         __checkReturn   efx_rc_t
225 efx_phy_oui_get(
226         __in            efx_nic_t *enp,
227         __out           uint32_t *ouip)
228 {
229         efx_port_t *epp = &(enp->en_port);
230         const efx_phy_ops_t *epop = epp->ep_epop;
231
232         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
233         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
234
235         return (epop->epo_oui_get(enp, ouip));
236 }
237
238                         void
239 efx_phy_media_type_get(
240         __in            efx_nic_t *enp,
241         __out           efx_phy_media_type_t *typep)
242 {
243         efx_port_t *epp = &(enp->en_port);
244
245         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
246         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
247
248         if (epp->ep_module_type != EFX_PHY_MEDIA_INVALID)
249                 *typep = epp->ep_module_type;
250         else
251                 *typep = epp->ep_fixed_port_type;
252 }
253
254         __checkReturn   efx_rc_t
255 efx_phy_module_get_info(
256         __in                    efx_nic_t *enp,
257         __in                    uint8_t dev_addr,
258         __in                    uint8_t offset,
259         __in                    uint8_t len,
260         __out_bcount(len)       uint8_t *data)
261 {
262         efx_rc_t rc;
263
264         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
265         EFSYS_ASSERT(data != NULL);
266
267         if ((uint32_t)offset + len > 0xff) {
268                 rc = EINVAL;
269                 goto fail1;
270         }
271
272         if ((rc = efx_mcdi_phy_module_get_info(enp, dev_addr,
273             offset, len, data)) != 0)
274                 goto fail2;
275
276         return (0);
277
278 fail2:
279         EFSYS_PROBE(fail2);
280 fail1:
281         EFSYS_PROBE1(fail1, efx_rc_t, rc);
282
283         return (rc);
284 }
285
286 #if EFSYS_OPT_PHY_STATS
287
288 #if EFSYS_OPT_NAMES
289
290 /* START MKCONFIG GENERATED PhyStatNamesBlock af9ffa24da3bc100 */
291 static const char * const __efx_phy_stat_name[] = {
292         "oui",
293         "pma_pmd_link_up",
294         "pma_pmd_rx_fault",
295         "pma_pmd_tx_fault",
296         "pma_pmd_rev_a",
297         "pma_pmd_rev_b",
298         "pma_pmd_rev_c",
299         "pma_pmd_rev_d",
300         "pcs_link_up",
301         "pcs_rx_fault",
302         "pcs_tx_fault",
303         "pcs_ber",
304         "pcs_block_errors",
305         "phy_xs_link_up",
306         "phy_xs_rx_fault",
307         "phy_xs_tx_fault",
308         "phy_xs_align",
309         "phy_xs_sync_a",
310         "phy_xs_sync_b",
311         "phy_xs_sync_c",
312         "phy_xs_sync_d",
313         "an_link_up",
314         "an_master",
315         "an_local_rx_ok",
316         "an_remote_rx_ok",
317         "cl22ext_link_up",
318         "snr_a",
319         "snr_b",
320         "snr_c",
321         "snr_d",
322         "pma_pmd_signal_a",
323         "pma_pmd_signal_b",
324         "pma_pmd_signal_c",
325         "pma_pmd_signal_d",
326         "an_complete",
327         "pma_pmd_rev_major",
328         "pma_pmd_rev_minor",
329         "pma_pmd_rev_micro",
330         "pcs_fw_version_0",
331         "pcs_fw_version_1",
332         "pcs_fw_version_2",
333         "pcs_fw_version_3",
334         "pcs_fw_build_yy",
335         "pcs_fw_build_mm",
336         "pcs_fw_build_dd",
337         "pcs_op_mode",
338 };
339
340 /* END MKCONFIG GENERATED PhyStatNamesBlock */
341
342                                         const char *
343 efx_phy_stat_name(
344         __in                            efx_nic_t *enp,
345         __in                            efx_phy_stat_t type)
346 {
347         _NOTE(ARGUNUSED(enp))
348         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
349         EFSYS_ASSERT3U(type, <, EFX_PHY_NSTATS);
350
351         return (__efx_phy_stat_name[type]);
352 }
353
354 #endif  /* EFSYS_OPT_NAMES */
355
356         __checkReturn                   efx_rc_t
357 efx_phy_stats_update(
358         __in                            efx_nic_t *enp,
359         __in                            efsys_mem_t *esmp,
360         __inout_ecount(EFX_PHY_NSTATS)  uint32_t *stat)
361 {
362         efx_port_t *epp = &(enp->en_port);
363         const efx_phy_ops_t *epop = epp->ep_epop;
364
365         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
366         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
367
368         return (epop->epo_stats_update(enp, esmp, stat));
369 }
370
371 #endif  /* EFSYS_OPT_PHY_STATS */
372
373
374 #if EFSYS_OPT_BIST
375
376         __checkReturn           efx_rc_t
377 efx_bist_enable_offline(
378         __in                    efx_nic_t *enp)
379 {
380         efx_port_t *epp = &(enp->en_port);
381         const efx_phy_ops_t *epop = epp->ep_epop;
382         efx_rc_t rc;
383
384         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
385
386         if (epop->epo_bist_enable_offline == NULL) {
387                 rc = ENOTSUP;
388                 goto fail1;
389         }
390
391         if ((rc = epop->epo_bist_enable_offline(enp)) != 0)
392                 goto fail2;
393
394         return (0);
395
396 fail2:
397         EFSYS_PROBE(fail2);
398 fail1:
399         EFSYS_PROBE1(fail1, efx_rc_t, rc);
400
401         return (rc);
402
403 }
404
405         __checkReturn           efx_rc_t
406 efx_bist_start(
407         __in                    efx_nic_t *enp,
408         __in                    efx_bist_type_t type)
409 {
410         efx_port_t *epp = &(enp->en_port);
411         const efx_phy_ops_t *epop = epp->ep_epop;
412         efx_rc_t rc;
413
414         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
415
416         EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
417         EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
418         EFSYS_ASSERT3U(epp->ep_current_bist, ==, EFX_BIST_TYPE_UNKNOWN);
419
420         if (epop->epo_bist_start == NULL) {
421                 rc = ENOTSUP;
422                 goto fail1;
423         }
424
425         if ((rc = epop->epo_bist_start(enp, type)) != 0)
426                 goto fail2;
427
428         epp->ep_current_bist = type;
429
430         return (0);
431
432 fail2:
433         EFSYS_PROBE(fail2);
434 fail1:
435         EFSYS_PROBE1(fail1, efx_rc_t, rc);
436
437         return (rc);
438 }
439
440         __checkReturn           efx_rc_t
441 efx_bist_poll(
442         __in                    efx_nic_t *enp,
443         __in                    efx_bist_type_t type,
444         __out                   efx_bist_result_t *resultp,
445         __out_opt               uint32_t *value_maskp,
446         __out_ecount_opt(count) unsigned long *valuesp,
447         __in                    size_t count)
448 {
449         efx_port_t *epp = &(enp->en_port);
450         const efx_phy_ops_t *epop = epp->ep_epop;
451         efx_rc_t rc;
452
453         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
454
455         EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
456         EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
457         EFSYS_ASSERT3U(epp->ep_current_bist, ==, type);
458
459         EFSYS_ASSERT(epop->epo_bist_poll != NULL);
460         if (epop->epo_bist_poll == NULL) {
461                 rc = ENOTSUP;
462                 goto fail1;
463         }
464
465         if ((rc = epop->epo_bist_poll(enp, type, resultp, value_maskp,
466             valuesp, count)) != 0)
467                 goto fail2;
468
469         return (0);
470
471 fail2:
472         EFSYS_PROBE(fail2);
473 fail1:
474         EFSYS_PROBE1(fail1, efx_rc_t, rc);
475
476         return (rc);
477 }
478
479                         void
480 efx_bist_stop(
481         __in            efx_nic_t *enp,
482         __in            efx_bist_type_t type)
483 {
484         efx_port_t *epp = &(enp->en_port);
485         const efx_phy_ops_t *epop = epp->ep_epop;
486
487         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
488
489         EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
490         EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
491         EFSYS_ASSERT3U(epp->ep_current_bist, ==, type);
492
493         EFSYS_ASSERT(epop->epo_bist_stop != NULL);
494
495         if (epop->epo_bist_stop != NULL)
496                 epop->epo_bist_stop(enp, type);
497
498         epp->ep_current_bist = EFX_BIST_TYPE_UNKNOWN;
499 }
500
501 #endif  /* EFSYS_OPT_BIST */
502                         void
503 efx_phy_unprobe(
504         __in    efx_nic_t *enp)
505 {
506         efx_port_t *epp = &(enp->en_port);
507
508         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
509
510         epp->ep_epop = NULL;
511
512         epp->ep_adv_cap_mask = 0;
513
514         epp->ep_port = 0;
515         epp->ep_phy_type = 0;
516 }