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