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