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