New upstream version 18.11-rc1
[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         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LINK_IN_LEN,
173                 MC_CMD_GET_LINK_OUT_LEN);
174         efx_rc_t rc;
175
176         req.emr_cmd = MC_CMD_GET_LINK;
177         req.emr_in_buf = payload;
178         req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
179         req.emr_out_buf = payload;
180         req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN;
181
182         efx_mcdi_execute(enp, &req);
183
184         if (req.emr_rc != 0) {
185                 rc = req.emr_rc;
186                 goto fail1;
187         }
188
189         if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
190                 rc = EMSGSIZE;
191                 goto fail2;
192         }
193
194         siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
195                             &slsp->sls_adv_cap_mask);
196         siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
197                             &slsp->sls_lp_cap_mask);
198
199         siena_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
200                             MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
201                             MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
202                             &slsp->sls_link_mode, &slsp->sls_fcntl);
203
204 #if EFSYS_OPT_LOOPBACK
205         /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
206         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
207         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
208         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
209         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
210         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
211         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
212         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
213         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
214         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
215         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
216         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
217         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
218         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
219         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
220         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
221         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
222         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
223         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
224
225         slsp->sls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
226 #endif  /* EFSYS_OPT_LOOPBACK */
227
228         slsp->sls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
229
230         return (0);
231
232 fail2:
233         EFSYS_PROBE(fail2);
234 fail1:
235         EFSYS_PROBE1(fail1, efx_rc_t, rc);
236
237         return (rc);
238 }
239
240         __checkReturn   efx_rc_t
241 siena_phy_reconfigure(
242         __in            efx_nic_t *enp)
243 {
244         efx_port_t *epp = &(enp->en_port);
245         efx_mcdi_req_t req;
246         EFX_MCDI_DECLARE_BUF(payload,
247                 MAX(MC_CMD_SET_ID_LED_IN_LEN, MC_CMD_SET_LINK_IN_LEN),
248                 MAX(MC_CMD_SET_ID_LED_OUT_LEN, MC_CMD_SET_LINK_OUT_LEN));
249         uint32_t cap_mask;
250 #if EFSYS_OPT_PHY_LED_CONTROL
251         unsigned int led_mode;
252 #endif
253         unsigned int speed;
254         efx_rc_t rc;
255
256         req.emr_cmd = MC_CMD_SET_LINK;
257         req.emr_in_buf = payload;
258         req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
259         req.emr_out_buf = payload;
260         req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;
261
262         cap_mask = epp->ep_adv_cap_mask;
263         MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
264                 PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
265                 PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
266                 PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
267                 PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
268                 PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
269                 PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
270                 PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
271                 PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
272                 PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
273                 PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
274
275 #if EFSYS_OPT_LOOPBACK
276         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
277                     epp->ep_loopback_type);
278         switch (epp->ep_loopback_link_mode) {
279         case EFX_LINK_100FDX:
280                 speed = 100;
281                 break;
282         case EFX_LINK_1000FDX:
283                 speed = 1000;
284                 break;
285         case EFX_LINK_10000FDX:
286                 speed = 10000;
287                 break;
288         default:
289                 speed = 0;
290         }
291 #else
292         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
293         speed = 0;
294 #endif  /* EFSYS_OPT_LOOPBACK */
295         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
296
297 #if EFSYS_OPT_PHY_FLAGS
298         MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
299 #else
300         MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
301 #endif  /* EFSYS_OPT_PHY_FLAGS */
302
303         efx_mcdi_execute(enp, &req);
304
305         if (req.emr_rc != 0) {
306                 rc = req.emr_rc;
307                 goto fail1;
308         }
309
310         /* And set the blink mode */
311         (void) memset(payload, 0, sizeof (payload));
312         req.emr_cmd = MC_CMD_SET_ID_LED;
313         req.emr_in_buf = payload;
314         req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
315         req.emr_out_buf = payload;
316         req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;
317
318 #if EFSYS_OPT_PHY_LED_CONTROL
319         switch (epp->ep_phy_led_mode) {
320         case EFX_PHY_LED_DEFAULT:
321                 led_mode = MC_CMD_LED_DEFAULT;
322                 break;
323         case EFX_PHY_LED_OFF:
324                 led_mode = MC_CMD_LED_OFF;
325                 break;
326         case EFX_PHY_LED_ON:
327                 led_mode = MC_CMD_LED_ON;
328                 break;
329         default:
330                 EFSYS_ASSERT(0);
331                 led_mode = MC_CMD_LED_DEFAULT;
332         }
333
334         MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
335 #else
336         MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
337 #endif  /* EFSYS_OPT_PHY_LED_CONTROL */
338
339         efx_mcdi_execute(enp, &req);
340
341         if (req.emr_rc != 0) {
342                 rc = req.emr_rc;
343                 goto fail2;
344         }
345
346         return (0);
347
348 fail2:
349         EFSYS_PROBE(fail2);
350 fail1:
351         EFSYS_PROBE1(fail1, efx_rc_t, rc);
352
353         return (rc);
354 }
355
356         __checkReturn   efx_rc_t
357 siena_phy_verify(
358         __in            efx_nic_t *enp)
359 {
360         efx_mcdi_req_t req;
361         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_STATE_IN_LEN,
362                 MC_CMD_GET_PHY_STATE_OUT_LEN);
363         uint32_t state;
364         efx_rc_t rc;
365
366         req.emr_cmd = MC_CMD_GET_PHY_STATE;
367         req.emr_in_buf = payload;
368         req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
369         req.emr_out_buf = payload;
370         req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN;
371
372         efx_mcdi_execute(enp, &req);
373
374         if (req.emr_rc != 0) {
375                 rc = req.emr_rc;
376                 goto fail1;
377         }
378
379         if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
380                 rc = EMSGSIZE;
381                 goto fail2;
382         }
383
384         state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
385         if (state != MC_CMD_PHY_STATE_OK) {
386                 if (state != MC_CMD_PHY_STATE_ZOMBIE)
387                         EFSYS_PROBE1(mc_pcol_error, int, state);
388                 rc = ENOTACTIVE;
389                 goto fail3;
390         }
391
392         return (0);
393
394 fail3:
395         EFSYS_PROBE(fail3);
396 fail2:
397         EFSYS_PROBE(fail2);
398 fail1:
399         EFSYS_PROBE1(fail1, efx_rc_t, rc);
400
401         return (rc);
402 }
403
404         __checkReturn   efx_rc_t
405 siena_phy_oui_get(
406         __in            efx_nic_t *enp,
407         __out           uint32_t *ouip)
408 {
409         _NOTE(ARGUNUSED(enp, ouip))
410
411         return (ENOTSUP);
412 }
413
414 #if EFSYS_OPT_PHY_STATS
415
416 #define SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat,             \
417                             _mc_record, _efx_record)                    \
418         if ((_vmask) & (1ULL << (_mc_record))) {                        \
419                 (_smask) |= (1ULL << (_efx_record));                    \
420                 if ((_stat) != NULL && !EFSYS_MEM_IS_NULL(_esmp)) {     \
421                         efx_dword_t dword;                              \
422                         EFSYS_MEM_READD(_esmp, (_mc_record) * 4, &dword);\
423                         (_stat)[_efx_record] =                          \
424                                 EFX_DWORD_FIELD(dword, EFX_DWORD_0);    \
425                 }                                                       \
426         }
427
428 #define SIENA_SIMPLE_STAT_SET2(_vmask, _esmp, _smask, _stat, _record)   \
429         SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat,             \
430                             MC_CMD_ ## _record,                         \
431                             EFX_PHY_STAT_ ## _record)
432
433                                                 void
434 siena_phy_decode_stats(
435         __in                                    efx_nic_t *enp,
436         __in                                    uint32_t vmask,
437         __in_opt                                efsys_mem_t *esmp,
438         __out_opt                               uint64_t *smaskp,
439         __inout_ecount_opt(EFX_PHY_NSTATS)      uint32_t *stat)
440 {
441         uint64_t smask = 0;
442
443         _NOTE(ARGUNUSED(enp))
444
445         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, OUI);
446         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_LINK_UP);
447         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_RX_FAULT);
448         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_TX_FAULT);
449
450         if (vmask & (1 << MC_CMD_PMA_PMD_SIGNAL)) {
451                 smask |=   ((1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_A) |
452                             (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_B) |
453                             (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_C) |
454                             (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_D));
455                 if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
456                         efx_dword_t dword;
457                         uint32_t sig;
458                         EFSYS_MEM_READD(esmp, 4 * MC_CMD_PMA_PMD_SIGNAL,
459                                         &dword);
460                         sig = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
461                         stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_A] = (sig >> 1) & 1;
462                         stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_B] = (sig >> 2) & 1;
463                         stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_C] = (sig >> 3) & 1;
464                         stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_D] = (sig >> 4) & 1;
465                 }
466         }
467
468         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_A,
469                             EFX_PHY_STAT_SNR_A);
470         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_B,
471                             EFX_PHY_STAT_SNR_B);
472         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_C,
473                             EFX_PHY_STAT_SNR_C);
474         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_D,
475                             EFX_PHY_STAT_SNR_D);
476
477         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_LINK_UP);
478         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_RX_FAULT);
479         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_TX_FAULT);
480         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BER);
481         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BLOCK_ERRORS);
482
483         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_LINK_UP,
484                             EFX_PHY_STAT_PHY_XS_LINK_UP);
485         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_RX_FAULT,
486                             EFX_PHY_STAT_PHY_XS_RX_FAULT);
487         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_TX_FAULT,
488                             EFX_PHY_STAT_PHY_XS_TX_FAULT);
489         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_ALIGN,
490                             EFX_PHY_STAT_PHY_XS_ALIGN);
491
492         if (vmask & (1 << MC_CMD_PHYXS_SYNC)) {
493                 smask |=   ((1 << EFX_PHY_STAT_PHY_XS_SYNC_A) |
494                             (1 << EFX_PHY_STAT_PHY_XS_SYNC_B) |
495                             (1 << EFX_PHY_STAT_PHY_XS_SYNC_C) |
496                             (1 << EFX_PHY_STAT_PHY_XS_SYNC_D));
497                 if (stat != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
498                         efx_dword_t dword;
499                         uint32_t sync;
500                         EFSYS_MEM_READD(esmp, 4 * MC_CMD_PHYXS_SYNC, &dword);
501                         sync = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
502                         stat[EFX_PHY_STAT_PHY_XS_SYNC_A] = (sync >> 0) & 1;
503                         stat[EFX_PHY_STAT_PHY_XS_SYNC_B] = (sync >> 1) & 1;
504                         stat[EFX_PHY_STAT_PHY_XS_SYNC_C] = (sync >> 2) & 1;
505                         stat[EFX_PHY_STAT_PHY_XS_SYNC_D] = (sync >> 3) & 1;
506                 }
507         }
508
509         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_LINK_UP);
510         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_COMPLETE);
511
512         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_CL22_LINK_UP,
513                             EFX_PHY_STAT_CL22EXT_LINK_UP);
514
515         if (smaskp != NULL)
516                 *smaskp = smask;
517 }
518
519         __checkReturn                           efx_rc_t
520 siena_phy_stats_update(
521         __in                                    efx_nic_t *enp,
522         __in                                    efsys_mem_t *esmp,
523         __inout_ecount(EFX_PHY_NSTATS)          uint32_t *stat)
524 {
525         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
526         uint32_t vmask = encp->enc_mcdi_phy_stat_mask;
527         uint64_t smask;
528         efx_mcdi_req_t req;
529         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_PHY_STATS_IN_LEN,
530                 MC_CMD_PHY_STATS_OUT_DMA_LEN);
531         efx_rc_t rc;
532
533         if ((esmp == NULL) || (EFSYS_MEM_SIZE(esmp) < EFX_PHY_STATS_SIZE)) {
534                 rc = EINVAL;
535                 goto fail1;
536         }
537
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 fail2;
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 fail2:
563         EFSYS_PROBE(fail2);
564 fail1:
565         EFSYS_PROBE1(fail1, efx_rc_t, rc);
566
567         return (0);
568 }
569
570 #endif  /* EFSYS_OPT_PHY_STATS */
571
572 #if EFSYS_OPT_BIST
573
574         __checkReturn           efx_rc_t
575 siena_phy_bist_start(
576         __in                    efx_nic_t *enp,
577         __in                    efx_bist_type_t type)
578 {
579         efx_rc_t rc;
580
581         if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
582                 goto fail1;
583
584         return (0);
585
586 fail1:
587         EFSYS_PROBE1(fail1, efx_rc_t, rc);
588
589         return (rc);
590 }
591
592 static  __checkReturn           unsigned long
593 siena_phy_sft9001_bist_status(
594         __in                    uint16_t code)
595 {
596         switch (code) {
597         case MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY:
598                 return (EFX_PHY_CABLE_STATUS_BUSY);
599         case MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT:
600                 return (EFX_PHY_CABLE_STATUS_INTERPAIRSHORT);
601         case MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT:
602                 return (EFX_PHY_CABLE_STATUS_INTRAPAIRSHORT);
603         case MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN:
604                 return (EFX_PHY_CABLE_STATUS_OPEN);
605         case MC_CMD_POLL_BIST_SFT9001_PAIR_OK:
606                 return (EFX_PHY_CABLE_STATUS_OK);
607         default:
608                 return (EFX_PHY_CABLE_STATUS_INVALID);
609         }
610 }
611
612         __checkReturn           efx_rc_t
613 siena_phy_bist_poll(
614         __in                    efx_nic_t *enp,
615         __in                    efx_bist_type_t type,
616         __out                   efx_bist_result_t *resultp,
617         __out_opt __drv_when(count > 0, __notnull)
618         uint32_t *value_maskp,
619         __out_ecount_opt(count) __drv_when(count > 0, __notnull)
620         unsigned long *valuesp,
621         __in                    size_t count)
622 {
623         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
624         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_POLL_BIST_IN_LEN,
625                 MCDI_CTL_SDU_LEN_MAX);
626         uint32_t value_mask = 0;
627         efx_mcdi_req_t req;
628         uint32_t result;
629         efx_rc_t rc;
630
631         req.emr_cmd = MC_CMD_POLL_BIST;
632         req.emr_in_buf = payload;
633         req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
634         req.emr_out_buf = payload;
635         req.emr_out_length = MCDI_CTL_SDU_LEN_MAX;
636
637         efx_mcdi_execute(enp, &req);
638
639         if (req.emr_rc != 0) {
640                 rc = req.emr_rc;
641                 goto fail1;
642         }
643
644         if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
645                 rc = EMSGSIZE;
646                 goto fail2;
647         }
648
649         if (count > 0)
650                 (void) memset(valuesp, '\0', count * sizeof (unsigned long));
651
652         result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
653
654         /* Extract PHY specific results */
655         if (result == MC_CMD_POLL_BIST_PASSED &&
656             encp->enc_phy_type == EFX_PHY_SFT9001B &&
657             req.emr_out_length_used >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN &&
658             (type == EFX_BIST_TYPE_PHY_CABLE_SHORT ||
659             type == EFX_BIST_TYPE_PHY_CABLE_LONG)) {
660                 uint16_t word;
661
662                 if (count > EFX_BIST_PHY_CABLE_LENGTH_A) {
663                         if (valuesp != NULL)
664                                 valuesp[EFX_BIST_PHY_CABLE_LENGTH_A] =
665                                     MCDI_OUT_DWORD(req,
666                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
667                         value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_A);
668                 }
669
670                 if (count > EFX_BIST_PHY_CABLE_LENGTH_B) {
671                         if (valuesp != NULL)
672                                 valuesp[EFX_BIST_PHY_CABLE_LENGTH_B] =
673                                     MCDI_OUT_DWORD(req,
674                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B);
675                         value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_B);
676                 }
677
678                 if (count > EFX_BIST_PHY_CABLE_LENGTH_C) {
679                         if (valuesp != NULL)
680                                 valuesp[EFX_BIST_PHY_CABLE_LENGTH_C] =
681                                     MCDI_OUT_DWORD(req,
682                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C);
683                         value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_C);
684                 }
685
686                 if (count > EFX_BIST_PHY_CABLE_LENGTH_D) {
687                         if (valuesp != NULL)
688                                 valuesp[EFX_BIST_PHY_CABLE_LENGTH_D] =
689                                     MCDI_OUT_DWORD(req,
690                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D);
691                         value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_D);
692                 }
693
694                 if (count > EFX_BIST_PHY_CABLE_STATUS_A) {
695                         if (valuesp != NULL) {
696                                 word = MCDI_OUT_WORD(req,
697                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_A);
698                                 valuesp[EFX_BIST_PHY_CABLE_STATUS_A] =
699                                     siena_phy_sft9001_bist_status(word);
700                         }
701                         value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_A);
702                 }
703
704                 if (count > EFX_BIST_PHY_CABLE_STATUS_B) {
705                         if (valuesp != NULL) {
706                                 word = MCDI_OUT_WORD(req,
707                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_B);
708                                 valuesp[EFX_BIST_PHY_CABLE_STATUS_B] =
709                                     siena_phy_sft9001_bist_status(word);
710                         }
711                         value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_B);
712                 }
713
714                 if (count > EFX_BIST_PHY_CABLE_STATUS_C) {
715                         if (valuesp != NULL) {
716                                 word = MCDI_OUT_WORD(req,
717                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_C);
718                                 valuesp[EFX_BIST_PHY_CABLE_STATUS_C] =
719                                     siena_phy_sft9001_bist_status(word);
720                         }
721                         value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_C);
722                 }
723
724                 if (count > EFX_BIST_PHY_CABLE_STATUS_D) {
725                         if (valuesp != NULL) {
726                                 word = MCDI_OUT_WORD(req,
727                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_D);
728                                 valuesp[EFX_BIST_PHY_CABLE_STATUS_D] =
729                                     siena_phy_sft9001_bist_status(word);
730                         }
731                         value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_D);
732                 }
733
734         } else if (result == MC_CMD_POLL_BIST_FAILED &&
735                     encp->enc_phy_type == EFX_PHY_QLX111V &&
736                     req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
737                     count > EFX_BIST_FAULT_CODE) {
738                 if (valuesp != NULL)
739                         valuesp[EFX_BIST_FAULT_CODE] =
740                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
741                 value_mask |= 1 << EFX_BIST_FAULT_CODE;
742         }
743
744         if (value_maskp != NULL)
745                 *value_maskp = value_mask;
746
747         EFSYS_ASSERT(resultp != NULL);
748         if (result == MC_CMD_POLL_BIST_RUNNING)
749                 *resultp = EFX_BIST_RESULT_RUNNING;
750         else if (result == MC_CMD_POLL_BIST_PASSED)
751                 *resultp = EFX_BIST_RESULT_PASSED;
752         else
753                 *resultp = EFX_BIST_RESULT_FAILED;
754
755         return (0);
756
757 fail2:
758         EFSYS_PROBE(fail2);
759 fail1:
760         EFSYS_PROBE1(fail1, efx_rc_t, rc);
761
762         return (rc);
763 }
764
765                         void
766 siena_phy_bist_stop(
767         __in            efx_nic_t *enp,
768         __in            efx_bist_type_t type)
769 {
770         /* There is no way to stop BIST on Siena */
771         _NOTE(ARGUNUSED(enp, type))
772 }
773
774 #endif  /* EFSYS_OPT_BIST */
775
776 #endif  /* EFSYS_OPT_SIENA */