New upstream version 18.08
[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         if ((esmp == NULL) || (EFSYS_MEM_SIZE(esmp) < EFX_PHY_STATS_SIZE)) {
538                 rc = EINVAL;
539                 goto fail1;
540         }
541
542         (void) memset(payload, 0, sizeof (payload));
543         req.emr_cmd = MC_CMD_PHY_STATS;
544         req.emr_in_buf = payload;
545         req.emr_in_length = MC_CMD_PHY_STATS_IN_LEN;
546         req.emr_out_buf = payload;
547         req.emr_out_length = MC_CMD_PHY_STATS_OUT_DMA_LEN;
548
549         MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_LO,
550                             EFSYS_MEM_ADDR(esmp) & 0xffffffff);
551         MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_HI,
552                             EFSYS_MEM_ADDR(esmp) >> 32);
553
554         efx_mcdi_execute(enp, &req);
555
556         if (req.emr_rc != 0) {
557                 rc = req.emr_rc;
558                 goto fail2;
559         }
560         EFSYS_ASSERT3U(req.emr_out_length, ==, MC_CMD_PHY_STATS_OUT_DMA_LEN);
561
562         siena_phy_decode_stats(enp, vmask, esmp, &smask, stat);
563         EFSYS_ASSERT(smask == encp->enc_phy_stat_mask);
564
565         return (0);
566
567 fail2:
568         EFSYS_PROBE(fail2);
569 fail1:
570         EFSYS_PROBE1(fail1, efx_rc_t, rc);
571
572         return (0);
573 }
574
575 #endif  /* EFSYS_OPT_PHY_STATS */
576
577 #if EFSYS_OPT_BIST
578
579         __checkReturn           efx_rc_t
580 siena_phy_bist_start(
581         __in                    efx_nic_t *enp,
582         __in                    efx_bist_type_t type)
583 {
584         efx_rc_t rc;
585
586         if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
587                 goto fail1;
588
589         return (0);
590
591 fail1:
592         EFSYS_PROBE1(fail1, efx_rc_t, rc);
593
594         return (rc);
595 }
596
597 static  __checkReturn           unsigned long
598 siena_phy_sft9001_bist_status(
599         __in                    uint16_t code)
600 {
601         switch (code) {
602         case MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY:
603                 return (EFX_PHY_CABLE_STATUS_BUSY);
604         case MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT:
605                 return (EFX_PHY_CABLE_STATUS_INTERPAIRSHORT);
606         case MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT:
607                 return (EFX_PHY_CABLE_STATUS_INTRAPAIRSHORT);
608         case MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN:
609                 return (EFX_PHY_CABLE_STATUS_OPEN);
610         case MC_CMD_POLL_BIST_SFT9001_PAIR_OK:
611                 return (EFX_PHY_CABLE_STATUS_OK);
612         default:
613                 return (EFX_PHY_CABLE_STATUS_INVALID);
614         }
615 }
616
617         __checkReturn           efx_rc_t
618 siena_phy_bist_poll(
619         __in                    efx_nic_t *enp,
620         __in                    efx_bist_type_t type,
621         __out                   efx_bist_result_t *resultp,
622         __out_opt __drv_when(count > 0, __notnull)
623         uint32_t *value_maskp,
624         __out_ecount_opt(count) __drv_when(count > 0, __notnull)
625         unsigned long *valuesp,
626         __in                    size_t count)
627 {
628         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
629         uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN,
630                             MCDI_CTL_SDU_LEN_MAX)];
631         uint32_t value_mask = 0;
632         efx_mcdi_req_t req;
633         uint32_t result;
634         efx_rc_t rc;
635
636         (void) memset(payload, 0, sizeof (payload));
637         req.emr_cmd = MC_CMD_POLL_BIST;
638         req.emr_in_buf = payload;
639         req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
640         req.emr_out_buf = payload;
641         req.emr_out_length = MCDI_CTL_SDU_LEN_MAX;
642
643         efx_mcdi_execute(enp, &req);
644
645         if (req.emr_rc != 0) {
646                 rc = req.emr_rc;
647                 goto fail1;
648         }
649
650         if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
651                 rc = EMSGSIZE;
652                 goto fail2;
653         }
654
655         if (count > 0)
656                 (void) memset(valuesp, '\0', count * sizeof (unsigned long));
657
658         result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
659
660         /* Extract PHY specific results */
661         if (result == MC_CMD_POLL_BIST_PASSED &&
662             encp->enc_phy_type == EFX_PHY_SFT9001B &&
663             req.emr_out_length_used >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN &&
664             (type == EFX_BIST_TYPE_PHY_CABLE_SHORT ||
665             type == EFX_BIST_TYPE_PHY_CABLE_LONG)) {
666                 uint16_t word;
667
668                 if (count > EFX_BIST_PHY_CABLE_LENGTH_A) {
669                         if (valuesp != NULL)
670                                 valuesp[EFX_BIST_PHY_CABLE_LENGTH_A] =
671                                     MCDI_OUT_DWORD(req,
672                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
673                         value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_A);
674                 }
675
676                 if (count > EFX_BIST_PHY_CABLE_LENGTH_B) {
677                         if (valuesp != NULL)
678                                 valuesp[EFX_BIST_PHY_CABLE_LENGTH_B] =
679                                     MCDI_OUT_DWORD(req,
680                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B);
681                         value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_B);
682                 }
683
684                 if (count > EFX_BIST_PHY_CABLE_LENGTH_C) {
685                         if (valuesp != NULL)
686                                 valuesp[EFX_BIST_PHY_CABLE_LENGTH_C] =
687                                     MCDI_OUT_DWORD(req,
688                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C);
689                         value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_C);
690                 }
691
692                 if (count > EFX_BIST_PHY_CABLE_LENGTH_D) {
693                         if (valuesp != NULL)
694                                 valuesp[EFX_BIST_PHY_CABLE_LENGTH_D] =
695                                     MCDI_OUT_DWORD(req,
696                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D);
697                         value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_D);
698                 }
699
700                 if (count > EFX_BIST_PHY_CABLE_STATUS_A) {
701                         if (valuesp != NULL) {
702                                 word = MCDI_OUT_WORD(req,
703                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_A);
704                                 valuesp[EFX_BIST_PHY_CABLE_STATUS_A] =
705                                     siena_phy_sft9001_bist_status(word);
706                         }
707                         value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_A);
708                 }
709
710                 if (count > EFX_BIST_PHY_CABLE_STATUS_B) {
711                         if (valuesp != NULL) {
712                                 word = MCDI_OUT_WORD(req,
713                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_B);
714                                 valuesp[EFX_BIST_PHY_CABLE_STATUS_B] =
715                                     siena_phy_sft9001_bist_status(word);
716                         }
717                         value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_B);
718                 }
719
720                 if (count > EFX_BIST_PHY_CABLE_STATUS_C) {
721                         if (valuesp != NULL) {
722                                 word = MCDI_OUT_WORD(req,
723                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_C);
724                                 valuesp[EFX_BIST_PHY_CABLE_STATUS_C] =
725                                     siena_phy_sft9001_bist_status(word);
726                         }
727                         value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_C);
728                 }
729
730                 if (count > EFX_BIST_PHY_CABLE_STATUS_D) {
731                         if (valuesp != NULL) {
732                                 word = MCDI_OUT_WORD(req,
733                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_D);
734                                 valuesp[EFX_BIST_PHY_CABLE_STATUS_D] =
735                                     siena_phy_sft9001_bist_status(word);
736                         }
737                         value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_D);
738                 }
739
740         } else if (result == MC_CMD_POLL_BIST_FAILED &&
741                     encp->enc_phy_type == EFX_PHY_QLX111V &&
742                     req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
743                     count > EFX_BIST_FAULT_CODE) {
744                 if (valuesp != NULL)
745                         valuesp[EFX_BIST_FAULT_CODE] =
746                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
747                 value_mask |= 1 << EFX_BIST_FAULT_CODE;
748         }
749
750         if (value_maskp != NULL)
751                 *value_maskp = value_mask;
752
753         EFSYS_ASSERT(resultp != NULL);
754         if (result == MC_CMD_POLL_BIST_RUNNING)
755                 *resultp = EFX_BIST_RESULT_RUNNING;
756         else if (result == MC_CMD_POLL_BIST_PASSED)
757                 *resultp = EFX_BIST_RESULT_PASSED;
758         else
759                 *resultp = EFX_BIST_RESULT_FAILED;
760
761         return (0);
762
763 fail2:
764         EFSYS_PROBE(fail2);
765 fail1:
766         EFSYS_PROBE1(fail1, efx_rc_t, rc);
767
768         return (rc);
769 }
770
771                         void
772 siena_phy_bist_stop(
773         __in            efx_nic_t *enp,
774         __in            efx_bist_type_t type)
775 {
776         /* There is no way to stop BIST on Siena */
777         _NOTE(ARGUNUSED(enp, type))
778 }
779
780 #endif  /* EFSYS_OPT_BIST */
781
782 #endif  /* EFSYS_OPT_SIENA */