net/sfc/base: import built-in selftest
[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_BIST
43         NULL,                           /* epo_bist_enable_offline */
44         siena_phy_bist_start,           /* epo_bist_start */
45         siena_phy_bist_poll,            /* epo_bist_poll */
46         siena_phy_bist_stop,            /* epo_bist_stop */
47 #endif  /* EFSYS_OPT_BIST */
48 };
49 #endif  /* EFSYS_OPT_SIENA */
50
51 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
52 static const efx_phy_ops_t      __efx_phy_ef10_ops = {
53         ef10_phy_power,                 /* epo_power */
54         NULL,                           /* epo_reset */
55         ef10_phy_reconfigure,           /* epo_reconfigure */
56         ef10_phy_verify,                /* epo_verify */
57         ef10_phy_oui_get,               /* epo_oui_get */
58 #if EFSYS_OPT_BIST
59         ef10_bist_enable_offline,       /* epo_bist_enable_offline */
60         ef10_bist_start,                /* epo_bist_start */
61         ef10_bist_poll,                 /* epo_bist_poll */
62         ef10_bist_stop,                 /* epo_bist_stop */
63 #endif  /* EFSYS_OPT_BIST */
64 };
65 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
66
67         __checkReturn   efx_rc_t
68 efx_phy_probe(
69         __in            efx_nic_t *enp)
70 {
71         efx_port_t *epp = &(enp->en_port);
72         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
73         const efx_phy_ops_t *epop;
74         efx_rc_t rc;
75
76         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
77
78         epp->ep_port = encp->enc_port;
79         epp->ep_phy_type = encp->enc_phy_type;
80
81         /* Hook in operations structure */
82         switch (enp->en_family) {
83 #if EFSYS_OPT_SIENA
84         case EFX_FAMILY_SIENA:
85                 epop = &__efx_phy_siena_ops;
86                 break;
87 #endif  /* EFSYS_OPT_SIENA */
88 #if EFSYS_OPT_HUNTINGTON
89         case EFX_FAMILY_HUNTINGTON:
90                 epop = &__efx_phy_ef10_ops;
91                 break;
92 #endif  /* EFSYS_OPT_HUNTINGTON */
93 #if EFSYS_OPT_MEDFORD
94         case EFX_FAMILY_MEDFORD:
95                 epop = &__efx_phy_ef10_ops;
96                 break;
97 #endif  /* EFSYS_OPT_MEDFORD */
98         default:
99                 rc = ENOTSUP;
100                 goto fail1;
101         }
102
103         epp->ep_epop = epop;
104
105         return (0);
106
107 fail1:
108         EFSYS_PROBE1(fail1, efx_rc_t, rc);
109
110         epp->ep_port = 0;
111         epp->ep_phy_type = 0;
112
113         return (rc);
114 }
115
116         __checkReturn   efx_rc_t
117 efx_phy_verify(
118         __in            efx_nic_t *enp)
119 {
120         efx_port_t *epp = &(enp->en_port);
121         const efx_phy_ops_t *epop = epp->ep_epop;
122
123         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
124         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
125
126         return (epop->epo_verify(enp));
127 }
128
129                         void
130 efx_phy_adv_cap_get(
131         __in            efx_nic_t *enp,
132         __in            uint32_t flag,
133         __out           uint32_t *maskp)
134 {
135         efx_port_t *epp = &(enp->en_port);
136
137         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
138         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
139
140         switch (flag) {
141         case EFX_PHY_CAP_CURRENT:
142                 *maskp = epp->ep_adv_cap_mask;
143                 break;
144         case EFX_PHY_CAP_DEFAULT:
145                 *maskp = epp->ep_default_adv_cap_mask;
146                 break;
147         case EFX_PHY_CAP_PERM:
148                 *maskp = epp->ep_phy_cap_mask;
149                 break;
150         default:
151                 EFSYS_ASSERT(B_FALSE);
152                 break;
153         }
154 }
155
156         __checkReturn   efx_rc_t
157 efx_phy_adv_cap_set(
158         __in            efx_nic_t *enp,
159         __in            uint32_t mask)
160 {
161         efx_port_t *epp = &(enp->en_port);
162         const efx_phy_ops_t *epop = epp->ep_epop;
163         uint32_t old_mask;
164         efx_rc_t rc;
165
166         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
167         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
168
169         if ((mask & ~epp->ep_phy_cap_mask) != 0) {
170                 rc = ENOTSUP;
171                 goto fail1;
172         }
173
174         if (epp->ep_adv_cap_mask == mask)
175                 goto done;
176
177         old_mask = epp->ep_adv_cap_mask;
178         epp->ep_adv_cap_mask = mask;
179
180         if ((rc = epop->epo_reconfigure(enp)) != 0)
181                 goto fail2;
182
183 done:
184         return (0);
185
186 fail2:
187         EFSYS_PROBE(fail2);
188
189         epp->ep_adv_cap_mask = old_mask;
190         /* Reconfigure for robustness */
191         if (epop->epo_reconfigure(enp) != 0) {
192                 /*
193                  * We may have an inconsistent view of our advertised speed
194                  * capabilities.
195                  */
196                 EFSYS_ASSERT(0);
197         }
198
199 fail1:
200         EFSYS_PROBE1(fail1, efx_rc_t, rc);
201
202         return (rc);
203 }
204
205         void
206 efx_phy_lp_cap_get(
207         __in            efx_nic_t *enp,
208         __out           uint32_t *maskp)
209 {
210         efx_port_t *epp = &(enp->en_port);
211
212         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
213         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
214
215         *maskp = epp->ep_lp_cap_mask;
216 }
217
218         __checkReturn   efx_rc_t
219 efx_phy_oui_get(
220         __in            efx_nic_t *enp,
221         __out           uint32_t *ouip)
222 {
223         efx_port_t *epp = &(enp->en_port);
224         const efx_phy_ops_t *epop = epp->ep_epop;
225
226         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
227         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
228
229         return (epop->epo_oui_get(enp, ouip));
230 }
231
232                         void
233 efx_phy_media_type_get(
234         __in            efx_nic_t *enp,
235         __out           efx_phy_media_type_t *typep)
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         if (epp->ep_module_type != EFX_PHY_MEDIA_INVALID)
243                 *typep = epp->ep_module_type;
244         else
245                 *typep = epp->ep_fixed_port_type;
246 }
247
248         __checkReturn   efx_rc_t
249 efx_phy_module_get_info(
250         __in                    efx_nic_t *enp,
251         __in                    uint8_t dev_addr,
252         __in                    uint8_t offset,
253         __in                    uint8_t len,
254         __out_bcount(len)       uint8_t *data)
255 {
256         efx_rc_t rc;
257
258         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
259         EFSYS_ASSERT(data != NULL);
260
261         if ((uint32_t)offset + len > 0xff) {
262                 rc = EINVAL;
263                 goto fail1;
264         }
265
266         if ((rc = efx_mcdi_phy_module_get_info(enp, dev_addr,
267             offset, len, data)) != 0)
268                 goto fail2;
269
270         return (0);
271
272 fail2:
273         EFSYS_PROBE(fail2);
274 fail1:
275         EFSYS_PROBE1(fail1, efx_rc_t, rc);
276
277         return (rc);
278 }
279
280
281 #if EFSYS_OPT_BIST
282
283         __checkReturn           efx_rc_t
284 efx_bist_enable_offline(
285         __in                    efx_nic_t *enp)
286 {
287         efx_port_t *epp = &(enp->en_port);
288         const efx_phy_ops_t *epop = epp->ep_epop;
289         efx_rc_t rc;
290
291         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
292
293         if (epop->epo_bist_enable_offline == NULL) {
294                 rc = ENOTSUP;
295                 goto fail1;
296         }
297
298         if ((rc = epop->epo_bist_enable_offline(enp)) != 0)
299                 goto fail2;
300
301         return (0);
302
303 fail2:
304         EFSYS_PROBE(fail2);
305 fail1:
306         EFSYS_PROBE1(fail1, efx_rc_t, rc);
307
308         return (rc);
309
310 }
311
312         __checkReturn           efx_rc_t
313 efx_bist_start(
314         __in                    efx_nic_t *enp,
315         __in                    efx_bist_type_t type)
316 {
317         efx_port_t *epp = &(enp->en_port);
318         const efx_phy_ops_t *epop = epp->ep_epop;
319         efx_rc_t rc;
320
321         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
322
323         EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
324         EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
325         EFSYS_ASSERT3U(epp->ep_current_bist, ==, EFX_BIST_TYPE_UNKNOWN);
326
327         if (epop->epo_bist_start == NULL) {
328                 rc = ENOTSUP;
329                 goto fail1;
330         }
331
332         if ((rc = epop->epo_bist_start(enp, type)) != 0)
333                 goto fail2;
334
335         epp->ep_current_bist = type;
336
337         return (0);
338
339 fail2:
340         EFSYS_PROBE(fail2);
341 fail1:
342         EFSYS_PROBE1(fail1, efx_rc_t, rc);
343
344         return (rc);
345 }
346
347         __checkReturn           efx_rc_t
348 efx_bist_poll(
349         __in                    efx_nic_t *enp,
350         __in                    efx_bist_type_t type,
351         __out                   efx_bist_result_t *resultp,
352         __out_opt               uint32_t *value_maskp,
353         __out_ecount_opt(count) unsigned long *valuesp,
354         __in                    size_t count)
355 {
356         efx_port_t *epp = &(enp->en_port);
357         const efx_phy_ops_t *epop = epp->ep_epop;
358         efx_rc_t rc;
359
360         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
361
362         EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
363         EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
364         EFSYS_ASSERT3U(epp->ep_current_bist, ==, type);
365
366         EFSYS_ASSERT(epop->epo_bist_poll != NULL);
367         if (epop->epo_bist_poll == NULL) {
368                 rc = ENOTSUP;
369                 goto fail1;
370         }
371
372         if ((rc = epop->epo_bist_poll(enp, type, resultp, value_maskp,
373             valuesp, count)) != 0)
374                 goto fail2;
375
376         return (0);
377
378 fail2:
379         EFSYS_PROBE(fail2);
380 fail1:
381         EFSYS_PROBE1(fail1, efx_rc_t, rc);
382
383         return (rc);
384 }
385
386                         void
387 efx_bist_stop(
388         __in            efx_nic_t *enp,
389         __in            efx_bist_type_t type)
390 {
391         efx_port_t *epp = &(enp->en_port);
392         const efx_phy_ops_t *epop = epp->ep_epop;
393
394         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
395
396         EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
397         EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
398         EFSYS_ASSERT3U(epp->ep_current_bist, ==, type);
399
400         EFSYS_ASSERT(epop->epo_bist_stop != NULL);
401
402         if (epop->epo_bist_stop != NULL)
403                 epop->epo_bist_stop(enp, type);
404
405         epp->ep_current_bist = EFX_BIST_TYPE_UNKNOWN;
406 }
407
408 #endif  /* EFSYS_OPT_BIST */
409                         void
410 efx_phy_unprobe(
411         __in    efx_nic_t *enp)
412 {
413         efx_port_t *epp = &(enp->en_port);
414
415         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
416
417         epp->ep_epop = NULL;
418
419         epp->ep_adv_cap_mask = 0;
420
421         epp->ep_port = 0;
422         epp->ep_phy_type = 0;
423 }