]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/sfxge/common/siena_phy.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / sfxge / common / siena_phy.c
1 /*-
2  * Copyright 2009 Solarflare Communications Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include "efsys.h"
30 #include "efx.h"
31 #include "efx_impl.h"
32
33 #if EFSYS_OPT_SIENA
34
35 static                  void
36 siena_phy_decode_cap(
37         __in            uint32_t mcdi_cap,
38         __out           uint32_t *maskp)
39 {
40         uint32_t mask;
41
42         mask = 0;
43         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
44                 mask |= (1 << EFX_PHY_CAP_10HDX);
45         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
46                 mask |= (1 << EFX_PHY_CAP_10FDX);
47         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
48                 mask |= (1 << EFX_PHY_CAP_100HDX);
49         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
50                 mask |= (1 << EFX_PHY_CAP_100FDX);
51         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
52                 mask |= (1 << EFX_PHY_CAP_1000HDX);
53         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
54                 mask |= (1 << EFX_PHY_CAP_1000FDX);
55         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
56                 mask |= (1 << EFX_PHY_CAP_10000FDX);
57         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
58                 mask |= (1 << EFX_PHY_CAP_PAUSE);
59         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
60                 mask |= (1 << EFX_PHY_CAP_ASYM);
61         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
62                 mask |= (1 << EFX_PHY_CAP_AN);
63
64         *maskp = mask;
65 }
66
67 static                  void
68 siena_phy_decode_link_mode(
69         __in            efx_nic_t *enp,
70         __in            uint32_t link_flags,
71         __in            unsigned int speed,
72         __in            unsigned int fcntl,
73         __out           efx_link_mode_t *link_modep,
74         __out           unsigned int *fcntlp)
75 {
76         boolean_t fd = !!(link_flags &
77                     (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
78         boolean_t up = !!(link_flags &
79                     (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
80
81         _NOTE(ARGUNUSED(enp))
82
83         if (!up)
84                 *link_modep = EFX_LINK_DOWN;
85         else if (speed == 10000 && fd)
86                 *link_modep = EFX_LINK_10000FDX;
87         else if (speed == 1000)
88                 *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
89         else if (speed == 100)
90                 *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
91         else if (speed == 10)
92                 *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
93         else
94                 *link_modep = EFX_LINK_UNKNOWN;
95
96         if (fcntl == MC_CMD_FCNTL_OFF)
97                 *fcntlp = 0;
98         else if (fcntl == MC_CMD_FCNTL_RESPOND)
99                 *fcntlp = EFX_FCNTL_RESPOND;
100         else if (fcntl == MC_CMD_FCNTL_BIDIR)
101                 *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
102         else {
103                 EFSYS_PROBE1(mc_pcol_error, int, fcntl);
104                 *fcntlp = 0;
105         }
106 }
107
108                         void
109 siena_phy_link_ev(
110         __in            efx_nic_t *enp,
111         __in            efx_qword_t *eqp,
112         __out           efx_link_mode_t *link_modep)
113 {
114         efx_port_t *epp = &(enp->en_port);
115         unsigned int link_flags;
116         unsigned int speed;
117         unsigned int fcntl;
118         efx_link_mode_t link_mode;
119         uint32_t lp_cap_mask;
120
121         /*
122          * Convert the LINKCHANGE speed enumeration into mbit/s, in the
123          * same way as GET_LINK encodes the speed
124          */
125         switch (MCDI_EV_FIELD(*eqp, LINKCHANGE_SPEED)) {
126         case MCDI_EVENT_LINKCHANGE_SPEED_100M:
127                 speed = 100;
128                 break;
129         case MCDI_EVENT_LINKCHANGE_SPEED_1G:
130                 speed = 1000;
131                 break;
132         case MCDI_EVENT_LINKCHANGE_SPEED_10G:
133                 speed = 10000;
134                 break;
135         default:
136                 speed = 0;
137                 break;
138         }
139
140         link_flags = MCDI_EV_FIELD(*eqp, LINKCHANGE_LINK_FLAGS);
141         siena_phy_decode_link_mode(enp, link_flags, speed,
142                                     MCDI_EV_FIELD(*eqp, LINKCHANGE_FCNTL),
143                                     &link_mode, &fcntl);
144         siena_phy_decode_cap(MCDI_EV_FIELD(*eqp, LINKCHANGE_LP_CAP),
145                             &lp_cap_mask);
146
147         /*
148          * It's safe to update ep_lp_cap_mask without the driver's port lock
149          * because presumably any concurrently running efx_port_poll() is
150          * only going to arrive at the same value.
151          *
152          * ep_fcntl has two meanings. It's either the link common fcntl
153          * (if the PHY supports AN), or it's the forced link state. If
154          * the former, it's safe to update the value for the same reason as
155          * for ep_lp_cap_mask. If the latter, then just ignore the value,
156          * because we can race with efx_mac_fcntl_set().
157          */
158         epp->ep_lp_cap_mask = lp_cap_mask;
159         if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
160                 epp->ep_fcntl = fcntl;
161
162         *link_modep = link_mode;
163 }
164
165         __checkReturn   int
166 siena_phy_power(
167         __in            efx_nic_t *enp,
168         __in            boolean_t power)
169 {
170         int rc;
171
172         if (!power)
173                 return (0);
174
175         /* Check if the PHY is a zombie */
176         if ((rc = siena_phy_verify(enp)) != 0)
177                 goto fail1;
178
179         enp->en_reset_flags |= EFX_RESET_PHY;
180
181         return (0);
182
183 fail1:
184         EFSYS_PROBE1(fail1, int, rc);
185
186         return (rc);
187 }
188
189         __checkReturn   int
190 siena_phy_get_link(
191         __in            efx_nic_t *enp,
192         __out           siena_link_state_t *slsp)
193 {
194         efx_mcdi_req_t req;
195         uint8_t outbuf[MC_CMD_GET_LINK_OUT_LEN];
196         int rc;
197
198         req.emr_cmd = MC_CMD_GET_LINK;
199         EFX_STATIC_ASSERT(MC_CMD_GET_LINK_IN_LEN == 0);
200         req.emr_in_buf = NULL;
201         req.emr_in_length = 0;
202         req.emr_out_buf = outbuf;
203         req.emr_out_length = sizeof (outbuf);
204
205         efx_mcdi_execute(enp, &req);
206
207         if (req.emr_rc != 0) {
208                 rc = req.emr_rc;
209                 goto fail1;
210         }
211
212         if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
213                 rc = EMSGSIZE;
214                 goto fail2;
215         }
216
217         siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
218                             &slsp->sls_adv_cap_mask);
219         siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
220                             &slsp->sls_lp_cap_mask);
221
222         siena_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
223                             MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
224                             MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
225                             &slsp->sls_link_mode, &slsp->sls_fcntl);
226
227 #if EFSYS_OPT_LOOPBACK
228         /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
229         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
230         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
231         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
232         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
233         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
234         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
235         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
236         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
237         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
238         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
239         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
240         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
241         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
242         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
243         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
244         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
245         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
246         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
247
248         slsp->sls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
249 #endif  /* EFSYS_OPT_LOOPBACK */
250
251         slsp->sls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
252
253         return (0);
254
255 fail2:
256         EFSYS_PROBE(fail2);
257 fail1:
258         EFSYS_PROBE1(fail1, int, rc);
259
260         return (rc);
261 }
262
263         __checkReturn   int
264 siena_phy_reconfigure(
265         __in            efx_nic_t *enp)
266 {
267         efx_port_t *epp = &(enp->en_port);
268         efx_mcdi_req_t req;
269         uint8_t payload[MAX(MC_CMD_SET_ID_LED_IN_LEN,
270                             MC_CMD_SET_LINK_IN_LEN)];
271         uint32_t cap_mask;
272         unsigned int led_mode;
273         unsigned int speed;
274         int rc;
275
276         req.emr_cmd = MC_CMD_SET_LINK;
277         req.emr_in_buf = payload;
278         req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
279         EFX_STATIC_ASSERT(MC_CMD_SET_LINK_OUT_LEN == 0);
280         req.emr_out_buf = NULL;
281         req.emr_out_length = 0;
282
283         cap_mask = epp->ep_adv_cap_mask;
284         MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
285                 PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
286                 PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
287                 PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
288                 PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
289                 PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
290                 PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
291                 PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
292                 PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
293                 PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
294                 PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
295
296 #if EFSYS_OPT_LOOPBACK
297         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
298                     epp->ep_loopback_type);
299         switch (epp->ep_loopback_link_mode) {
300         case EFX_LINK_100FDX:
301                 speed = 100;
302                 break;
303         case EFX_LINK_1000FDX:
304                 speed = 1000;
305                 break;
306         case EFX_LINK_10000FDX:
307                 speed = 10000;
308                 break;
309         default:
310                 speed = 0;
311         }
312 #else
313         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
314         speed = 0;
315 #endif  /* EFSYS_OPT_LOOPBACK */
316         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
317
318 #if EFSYS_OPT_PHY_FLAGS
319         MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
320 #else
321         MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
322 #endif  /* EFSYS_OPT_PHY_FLAGS */
323
324         efx_mcdi_execute(enp, &req);
325
326         if (req.emr_rc != 0) {
327                 rc = req.emr_rc;
328                 goto fail1;
329         }
330
331         /* And set the blink mode */
332         req.emr_cmd = MC_CMD_SET_ID_LED;
333         req.emr_in_buf = payload;
334         req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
335         EFX_STATIC_ASSERT(MC_CMD_SET_ID_LED_OUT_LEN == 0);
336         req.emr_out_buf = NULL;
337         req.emr_out_length = 0;
338
339 #if EFSYS_OPT_PHY_LED_CONTROL
340         switch (epp->ep_phy_led_mode) {
341         case EFX_PHY_LED_DEFAULT:
342                 led_mode = MC_CMD_LED_DEFAULT;
343                 break;
344         case EFX_PHY_LED_OFF:
345                 led_mode = MC_CMD_LED_OFF;
346                 break;
347         case EFX_PHY_LED_ON:
348                 led_mode = MC_CMD_LED_ON;
349                 break;
350         default:
351                 EFSYS_ASSERT(0);
352                 led_mode = MC_CMD_LED_DEFAULT;
353         }
354
355         MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
356 #else
357         MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
358 #endif  /* EFSYS_OPT_PHY_LED_CONTROL */
359
360         efx_mcdi_execute(enp, &req);
361
362         if (req.emr_rc != 0) {
363                 rc = req.emr_rc;
364                 goto fail2;
365         }
366
367         return (0);
368
369 fail2:
370         EFSYS_PROBE(fail2);
371 fail1:
372         EFSYS_PROBE1(fail1, int, rc);
373
374         return (rc);
375 }
376
377         __checkReturn   int
378 siena_phy_verify(
379         __in            efx_nic_t *enp)
380 {
381         efx_mcdi_req_t req;
382         uint8_t outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN];
383         uint32_t state;
384         int rc;
385
386         req.emr_cmd = MC_CMD_GET_PHY_STATE;
387         EFX_STATIC_ASSERT(MC_CMD_GET_PHY_STATE_IN_LEN == 0);
388         req.emr_in_buf = NULL;
389         req.emr_in_length = 0;
390         req.emr_out_buf = outbuf;
391         req.emr_out_length = sizeof (outbuf);
392
393         efx_mcdi_execute(enp, &req);
394
395         if (req.emr_rc != 0) {
396                 rc = req.emr_rc;
397                 goto fail1;
398         }
399
400         if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
401                 rc = EMSGSIZE;
402                 goto fail2;
403         }
404
405         state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
406         if (state != MC_CMD_PHY_STATE_OK) {
407                 if (state != MC_CMD_PHY_STATE_ZOMBIE)
408                         EFSYS_PROBE1(mc_pcol_error, int, state);
409                 rc = ENOTACTIVE;
410                 goto fail3;
411         }
412
413         return (0);
414
415 fail3:
416         EFSYS_PROBE(fail3);
417 fail2:
418         EFSYS_PROBE(fail2);
419 fail1:
420         EFSYS_PROBE1(fail1, int, rc);
421
422         return (rc);
423 }
424
425         __checkReturn   int
426 siena_phy_oui_get(
427         __in            efx_nic_t *enp,
428         __out           uint32_t *ouip)
429 {
430         _NOTE(ARGUNUSED(enp, ouip))
431
432         return (ENOTSUP);
433 }
434
435 #if EFSYS_OPT_PHY_STATS
436
437 #define SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat,             \
438                             _mc_record, _efx_record)                    \
439         if ((_vmask) & (1ULL << (_mc_record))) {                        \
440                 (_smask) |= (1ULL << (_efx_record));                    \
441                 if ((_stat) != NULL && !EFSYS_MEM_IS_NULL(_esmp)) {     \
442                         efx_dword_t dword;                              \
443                         EFSYS_MEM_READD(_esmp, (_mc_record) * 4, &dword);\
444                         (_stat)[_efx_record] =                          \
445                                 EFX_DWORD_FIELD(dword, EFX_DWORD_0);    \
446                 }                                                       \
447         }
448
449 #define SIENA_SIMPLE_STAT_SET2(_vmask, _esmp, _smask, _stat, _record)   \
450         SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat,             \
451                             MC_CMD_ ## _record,                         \
452                             EFX_PHY_STAT_ ## _record)
453
454                                                 void
455 siena_phy_decode_stats(
456         __in                                    efx_nic_t *enp,
457         __in                                    uint32_t vmask,
458         __in_opt                                efsys_mem_t *esmp,
459         __out_opt                               uint64_t *smaskp,
460         __out_ecount_opt(EFX_PHY_NSTATS)        uint32_t *stat)
461 {
462         uint64_t smask = 0;
463
464         _NOTE(ARGUNUSED(enp))
465
466         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, OUI);
467         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_LINK_UP);
468         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_RX_FAULT);
469         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_TX_FAULT);
470
471         if (vmask & (1 << MC_CMD_PMA_PMD_SIGNAL)) {
472                 smask |=   ((1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_A) |
473                             (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_B) |
474                             (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_C) |
475                             (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_D));
476                 if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
477                         efx_dword_t dword;
478                         uint32_t sig;
479                         EFSYS_MEM_READD(esmp, 4 * MC_CMD_PMA_PMD_SIGNAL,
480                                         &dword);
481                         sig = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
482                         stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_A] = (sig >> 1) & 1;
483                         stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_B] = (sig >> 2) & 1;
484                         stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_C] = (sig >> 3) & 1;
485                         stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_D] = (sig >> 4) & 1;
486                 }
487         }
488
489         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_A,
490                             EFX_PHY_STAT_SNR_A);
491         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_B,
492                             EFX_PHY_STAT_SNR_B);
493         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_C,
494                             EFX_PHY_STAT_SNR_C);
495         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_D,
496                             EFX_PHY_STAT_SNR_D);
497
498         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_LINK_UP);
499         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_RX_FAULT);
500         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_TX_FAULT);
501         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BER);
502         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BLOCK_ERRORS);
503
504         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_LINK_UP,
505                             EFX_PHY_STAT_PHY_XS_LINK_UP);
506         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_RX_FAULT,
507                             EFX_PHY_STAT_PHY_XS_RX_FAULT);
508         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_TX_FAULT,
509                             EFX_PHY_STAT_PHY_XS_TX_FAULT);
510         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_ALIGN,
511                             EFX_PHY_STAT_PHY_XS_ALIGN);
512
513         if (vmask & (1 << MC_CMD_PHYXS_SYNC)) {
514                 smask |=   ((1 << EFX_PHY_STAT_PHY_XS_SYNC_A) |
515                             (1 << EFX_PHY_STAT_PHY_XS_SYNC_B) |
516                             (1 << EFX_PHY_STAT_PHY_XS_SYNC_C) |
517                             (1 << EFX_PHY_STAT_PHY_XS_SYNC_D));
518                 if (stat != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
519                         efx_dword_t dword;
520                         uint32_t sync;
521                         EFSYS_MEM_READD(esmp, 4 * MC_CMD_PHYXS_SYNC, &dword);
522                         sync = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
523                         stat[EFX_PHY_STAT_PHY_XS_SYNC_A] = (sync >> 0) & 1;
524                         stat[EFX_PHY_STAT_PHY_XS_SYNC_B] = (sync >> 1) & 1;
525                         stat[EFX_PHY_STAT_PHY_XS_SYNC_C] = (sync >> 2) & 1;
526                         stat[EFX_PHY_STAT_PHY_XS_SYNC_D] = (sync >> 3) & 1;
527                 }
528         }
529
530         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_LINK_UP);
531         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_COMPLETE);
532
533         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_CL22_LINK_UP,
534                             EFX_PHY_STAT_CL22EXT_LINK_UP);
535
536         if (smaskp != NULL)
537                 *smaskp = smask;
538 }
539
540         __checkReturn                           int
541 siena_phy_stats_update(
542         __in                                    efx_nic_t *enp,
543         __in                                    efsys_mem_t *esmp,
544         __out_ecount(EFX_PHY_NSTATS)            uint32_t *stat)
545 {
546         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
547         uint32_t vmask = encp->enc_siena_phy_stat_mask;
548         uint8_t payload[MC_CMD_PHY_STATS_IN_LEN];
549         uint64_t smask;
550         efx_mcdi_req_t req;
551         int rc;
552
553         req.emr_cmd = MC_CMD_PHY_STATS;
554         req.emr_in_buf = payload;
555         req.emr_in_length = sizeof (payload);
556         EFX_STATIC_ASSERT(MC_CMD_PHY_STATS_OUT_DMA_LEN == 0);
557         req.emr_out_buf = NULL;
558         req.emr_out_length = 0;
559
560         MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_LO,
561                             EFSYS_MEM_ADDR(esmp) & 0xffffffff);
562         MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_HI,
563                             EFSYS_MEM_ADDR(esmp) >> 32);
564
565         efx_mcdi_execute(enp, &req);
566
567         if (req.emr_rc != 0) {
568                 rc = req.emr_rc;
569                 goto fail1;
570         }
571         EFSYS_ASSERT3U(req.emr_out_length, ==, MC_CMD_PHY_STATS_OUT_DMA_LEN);
572
573         siena_phy_decode_stats(enp, vmask, esmp, &smask, stat);
574         EFSYS_ASSERT(smask == encp->enc_phy_stat_mask);
575
576         return (0);
577
578 fail1:
579         EFSYS_PROBE1(fail1, int, rc);
580
581         return (0);
582 }
583
584 #endif  /* EFSYS_OPT_PHY_STATS */
585
586 #if EFSYS_OPT_PHY_PROPS
587
588 #if EFSYS_OPT_NAMES
589
590 extern          const char __cs *
591 siena_phy_prop_name(
592         __in    efx_nic_t *enp,
593         __in    unsigned int id)
594 {
595         _NOTE(ARGUNUSED(enp, id))
596
597         return (NULL);
598 }
599
600 #endif  /* EFSYS_OPT_NAMES */
601
602 extern  __checkReturn   int
603 siena_phy_prop_get(
604         __in            efx_nic_t *enp,
605         __in            unsigned int id,
606         __in            uint32_t flags,
607         __out           uint32_t *valp)
608 {
609         _NOTE(ARGUNUSED(enp, id, flags, valp))
610
611         return (ENOTSUP);
612 }
613
614 extern  __checkReturn   int
615 siena_phy_prop_set(
616         __in            efx_nic_t *enp,
617         __in            unsigned int id,
618         __in            uint32_t val)
619 {
620         _NOTE(ARGUNUSED(enp, id, val))
621
622         return (ENOTSUP);
623 }
624
625 #endif  /* EFSYS_OPT_PHY_PROPS */
626
627 #if EFSYS_OPT_PHY_BIST
628
629         __checkReturn           int
630 siena_phy_bist_start(
631         __in                    efx_nic_t *enp,
632         __in                    efx_phy_bist_type_t type)
633 {
634         uint8_t payload[MC_CMD_START_BIST_IN_LEN];
635         efx_mcdi_req_t req;
636         int rc;
637
638         req.emr_cmd = MC_CMD_START_BIST;
639         req.emr_in_buf = payload;
640         req.emr_in_length = sizeof (payload);
641         EFX_STATIC_ASSERT(MC_CMD_START_BIST_OUT_LEN == 0);
642         req.emr_out_buf = NULL;
643         req.emr_out_length = 0;
644
645         switch (type) {
646         case EFX_PHY_BIST_TYPE_NORMAL:
647                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
648                 break;
649         case EFX_PHY_BIST_TYPE_CABLE_SHORT:
650                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
651                     MC_CMD_PHY_BIST_CABLE_SHORT);
652                 break;
653         case EFX_PHY_BIST_TYPE_CABLE_LONG:
654                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
655                     MC_CMD_PHY_BIST_CABLE_LONG);
656                 break;
657         default:
658                 EFSYS_ASSERT(0);
659         }
660
661         efx_mcdi_execute(enp, &req);
662
663         if (req.emr_rc != 0) {
664                 rc = req.emr_rc;
665                 goto fail1;
666         }
667
668         return (0);
669
670 fail1:
671         EFSYS_PROBE1(fail1, int, rc);
672
673         return (rc);
674 }
675
676 static  __checkReturn           unsigned long
677 siena_phy_sft9001_bist_status(
678         __in                    uint16_t code)
679 {
680         switch (code) {
681         case MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY:
682                 return (EFX_PHY_CABLE_STATUS_BUSY);
683         case MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT:
684                 return (EFX_PHY_CABLE_STATUS_INTERPAIRSHORT);
685         case MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT:
686                 return (EFX_PHY_CABLE_STATUS_INTRAPAIRSHORT);
687         case MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN:
688                 return (EFX_PHY_CABLE_STATUS_OPEN);
689         case MC_CMD_POLL_BIST_SFT9001_PAIR_OK:
690                 return (EFX_PHY_CABLE_STATUS_OK);
691         default:
692                 return (EFX_PHY_CABLE_STATUS_INVALID);
693         }
694 }
695
696         __checkReturn           int
697 siena_phy_bist_poll(
698         __in                    efx_nic_t *enp,
699         __in                    efx_phy_bist_type_t type,
700         __out                   efx_phy_bist_result_t *resultp,
701         __out_opt __drv_when(count > 0, __notnull)
702         uint32_t *value_maskp,
703         __out_ecount_opt(count) __drv_when(count > 0, __notnull)
704         unsigned long *valuesp,
705         __in                    size_t count)
706 {
707         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
708         uint8_t payload[MCDI_CTL_SDU_LEN_MAX];
709         uint32_t value_mask = 0;
710         efx_mcdi_req_t req;
711         uint32_t result;
712         int rc;
713
714         req.emr_cmd = MC_CMD_POLL_BIST;
715         _NOTE(CONSTANTCONDITION)
716         EFSYS_ASSERT(MC_CMD_POLL_BIST_IN_LEN == 0);
717         req.emr_in_buf = NULL;
718         req.emr_in_length = 0;
719         req.emr_out_buf = payload;
720         req.emr_out_length = sizeof (payload);
721
722         efx_mcdi_execute(enp, &req);
723
724         if (req.emr_rc != 0) {
725                 rc = req.emr_rc;
726                 goto fail1;
727         }
728
729         if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
730                 rc = EMSGSIZE;
731                 goto fail2;
732         }
733
734         if (count > 0)
735                 (void) memset(valuesp, '\0', count * sizeof (unsigned long));
736
737         result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
738
739         /* Extract PHY specific results */
740         if (result == MC_CMD_POLL_BIST_PASSED &&
741             encp->enc_phy_type == EFX_PHY_SFT9001B &&
742             req.emr_out_length_used >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN &&
743             (type == EFX_PHY_BIST_TYPE_CABLE_SHORT ||
744             type == EFX_PHY_BIST_TYPE_CABLE_LONG)) {
745                 uint16_t word;
746
747                 if (count > EFX_PHY_BIST_CABLE_LENGTH_A) {
748                         if (valuesp != NULL)
749                                 valuesp[EFX_PHY_BIST_CABLE_LENGTH_A] =
750                                     MCDI_OUT_DWORD(req,
751                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
752                         value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_A);
753                 }
754
755                 if (count > EFX_PHY_BIST_CABLE_LENGTH_B) {
756                         if (valuesp != NULL)
757                                 valuesp[EFX_PHY_BIST_CABLE_LENGTH_B] =
758                                     MCDI_OUT_DWORD(req,
759                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B);
760                         value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_B);
761                 }
762
763                 if (count > EFX_PHY_BIST_CABLE_LENGTH_C) {
764                         if (valuesp != NULL)
765                                 valuesp[EFX_PHY_BIST_CABLE_LENGTH_C] =
766                                     MCDI_OUT_DWORD(req,
767                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C);
768                         value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_C);
769                 }
770
771                 if (count > EFX_PHY_BIST_CABLE_LENGTH_D) {
772                         if (valuesp != NULL)
773                                 valuesp[EFX_PHY_BIST_CABLE_LENGTH_D] =
774                                     MCDI_OUT_DWORD(req,
775                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D);
776                         value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_D);
777                 }
778
779                 if (count > EFX_PHY_BIST_CABLE_STATUS_A) {
780                         if (valuesp != NULL) {
781                                 word = MCDI_OUT_WORD(req,
782                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_A);
783                                 valuesp[EFX_PHY_BIST_CABLE_STATUS_A] =
784                                     siena_phy_sft9001_bist_status(word);
785                         }
786                         value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_A);
787                 }
788
789                 if (count > EFX_PHY_BIST_CABLE_STATUS_B) {
790                         if (valuesp != NULL) {
791                                 word = MCDI_OUT_WORD(req,
792                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_B);
793                                 valuesp[EFX_PHY_BIST_CABLE_STATUS_B] =
794                                     siena_phy_sft9001_bist_status(word);
795                         }
796                         value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_B);
797                 }
798
799                 if (count > EFX_PHY_BIST_CABLE_STATUS_C) {
800                         if (valuesp != NULL) {
801                                 word = MCDI_OUT_WORD(req,
802                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_C);
803                                 valuesp[EFX_PHY_BIST_CABLE_STATUS_C] =
804                                     siena_phy_sft9001_bist_status(word);
805                         }
806                         value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_C);
807                 }
808
809                 if (count > EFX_PHY_BIST_CABLE_STATUS_D) {
810                         if (valuesp != NULL) {
811                                 word = MCDI_OUT_WORD(req,
812                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_D);
813                                 valuesp[EFX_PHY_BIST_CABLE_STATUS_D] =
814                                     siena_phy_sft9001_bist_status(word);
815                         }
816                         value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_D);
817                 }
818
819         } else if (result == MC_CMD_POLL_BIST_FAILED &&
820                     encp->enc_phy_type == EFX_PHY_QLX111V &&
821                     req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
822                     count > EFX_PHY_BIST_FAULT_CODE) {
823                 if (valuesp != NULL)
824                         valuesp[EFX_PHY_BIST_FAULT_CODE] =
825                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
826                 value_mask |= 1 << EFX_PHY_BIST_FAULT_CODE;
827         }
828
829         if (value_maskp != NULL)
830                 *value_maskp = value_mask;
831
832         EFSYS_ASSERT(resultp != NULL);
833         if (result == MC_CMD_POLL_BIST_RUNNING)
834                 *resultp = EFX_PHY_BIST_RESULT_RUNNING;
835         else if (result == MC_CMD_POLL_BIST_PASSED)
836                 *resultp = EFX_PHY_BIST_RESULT_PASSED;
837         else
838                 *resultp = EFX_PHY_BIST_RESULT_FAILED;
839
840         return (0);
841
842 fail2:
843         EFSYS_PROBE(fail2);
844 fail1:
845         EFSYS_PROBE1(fail1, int, rc);
846
847         return (rc);
848 }
849
850                         void
851 siena_phy_bist_stop(
852         __in            efx_nic_t *enp,
853         __in            efx_phy_bist_type_t type)
854 {
855         /* There is no way to stop BIST on Siena */
856         _NOTE(ARGUNUSED(enp, type))
857 }
858
859 #endif  /* EFSYS_OPT_PHY_BIST */
860
861 #endif  /* EFSYS_OPT_SIENA */