]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/sfxge/common/ef10_phy.c
sfxge(4): support FEC mode settings
[FreeBSD/FreeBSD.git] / sys / dev / sfxge / common / ef10_phy.c
1 /*-
2  * Copyright (c) 2012-2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include "efx.h"
35 #include "efx_impl.h"
36
37 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
38
39 static                  void
40 mcdi_phy_decode_cap(
41         __in            uint32_t mcdi_cap,
42         __out           uint32_t *maskp)
43 {
44         uint32_t mask;
45
46 #define CHECK_CAP(_cap) \
47         EFX_STATIC_ASSERT(EFX_PHY_CAP_##_cap == MC_CMD_PHY_CAP_##_cap##_LBN)
48
49         CHECK_CAP(10HDX);
50         CHECK_CAP(10FDX);
51         CHECK_CAP(100HDX);
52         CHECK_CAP(100FDX);
53         CHECK_CAP(1000HDX);
54         CHECK_CAP(1000FDX);
55         CHECK_CAP(10000FDX);
56         CHECK_CAP(25000FDX);
57         CHECK_CAP(40000FDX);
58         CHECK_CAP(50000FDX);
59         CHECK_CAP(100000FDX);
60         CHECK_CAP(PAUSE);
61         CHECK_CAP(ASYM);
62         CHECK_CAP(AN);
63         CHECK_CAP(DDM);
64         CHECK_CAP(BASER_FEC);
65         CHECK_CAP(BASER_FEC_REQUESTED);
66         CHECK_CAP(RS_FEC);
67         CHECK_CAP(RS_FEC_REQUESTED);
68         CHECK_CAP(25G_BASER_FEC);
69         CHECK_CAP(25G_BASER_FEC_REQUESTED);
70 #undef CHECK_CAP
71
72         mask = 0;
73         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
74                 mask |= (1 << EFX_PHY_CAP_10HDX);
75         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
76                 mask |= (1 << EFX_PHY_CAP_10FDX);
77         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
78                 mask |= (1 << EFX_PHY_CAP_100HDX);
79         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
80                 mask |= (1 << EFX_PHY_CAP_100FDX);
81         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
82                 mask |= (1 << EFX_PHY_CAP_1000HDX);
83         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
84                 mask |= (1 << EFX_PHY_CAP_1000FDX);
85         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
86                 mask |= (1 << EFX_PHY_CAP_10000FDX);
87         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25000FDX_LBN))
88                 mask |= (1 << EFX_PHY_CAP_25000FDX);
89         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))
90                 mask |= (1 << EFX_PHY_CAP_40000FDX);
91         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_50000FDX_LBN))
92                 mask |= (1 << EFX_PHY_CAP_50000FDX);
93         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100000FDX_LBN))
94                 mask |= (1 << EFX_PHY_CAP_100000FDX);
95
96         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
97                 mask |= (1 << EFX_PHY_CAP_PAUSE);
98         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
99                 mask |= (1 << EFX_PHY_CAP_ASYM);
100         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
101                 mask |= (1 << EFX_PHY_CAP_AN);
102
103         /* FEC caps (supported on Medford2 and later) */
104         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN))
105                 mask |= (1 << EFX_PHY_CAP_BASER_FEC);
106         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_REQUESTED_LBN))
107                 mask |= (1 << EFX_PHY_CAP_BASER_FEC_REQUESTED);
108
109         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_LBN))
110                 mask |= (1 << EFX_PHY_CAP_RS_FEC);
111         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_REQUESTED_LBN))
112                 mask |= (1 << EFX_PHY_CAP_RS_FEC_REQUESTED);
113
114         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN))
115                 mask |= (1 << EFX_PHY_CAP_25G_BASER_FEC);
116         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_REQUESTED_LBN))
117                 mask |= (1 << EFX_PHY_CAP_25G_BASER_FEC_REQUESTED);
118
119         *maskp = mask;
120 }
121
122 static                  void
123 mcdi_phy_decode_link_mode(
124         __in            efx_nic_t *enp,
125         __in            uint32_t link_flags,
126         __in            unsigned int speed,
127         __in            unsigned int fcntl,
128         __out           efx_link_mode_t *link_modep,
129         __out           unsigned int *fcntlp)
130 {
131         boolean_t fd = !!(link_flags &
132                     (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
133         boolean_t up = !!(link_flags &
134                     (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
135
136         _NOTE(ARGUNUSED(enp))
137
138         if (!up)
139                 *link_modep = EFX_LINK_DOWN;
140         else if (speed == 100000 && fd)
141                 *link_modep = EFX_LINK_100000FDX;
142         else if (speed == 50000 && fd)
143                 *link_modep = EFX_LINK_50000FDX;
144         else if (speed == 40000 && fd)
145                 *link_modep = EFX_LINK_40000FDX;
146         else if (speed == 25000 && fd)
147                 *link_modep = EFX_LINK_25000FDX;
148         else if (speed == 10000 && fd)
149                 *link_modep = EFX_LINK_10000FDX;
150         else if (speed == 1000)
151                 *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
152         else if (speed == 100)
153                 *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
154         else if (speed == 10)
155                 *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
156         else
157                 *link_modep = EFX_LINK_UNKNOWN;
158
159         if (fcntl == MC_CMD_FCNTL_OFF)
160                 *fcntlp = 0;
161         else if (fcntl == MC_CMD_FCNTL_RESPOND)
162                 *fcntlp = EFX_FCNTL_RESPOND;
163         else if (fcntl == MC_CMD_FCNTL_GENERATE)
164                 *fcntlp = EFX_FCNTL_GENERATE;
165         else if (fcntl == MC_CMD_FCNTL_BIDIR)
166                 *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
167         else {
168                 EFSYS_PROBE1(mc_pcol_error, int, fcntl);
169                 *fcntlp = 0;
170         }
171 }
172
173
174                         void
175 ef10_phy_link_ev(
176         __in            efx_nic_t *enp,
177         __in            efx_qword_t *eqp,
178         __out           efx_link_mode_t *link_modep)
179 {
180         efx_port_t *epp = &(enp->en_port);
181         unsigned int link_flags;
182         unsigned int speed;
183         unsigned int fcntl;
184         efx_link_mode_t link_mode;
185         uint32_t lp_cap_mask;
186
187         /*
188          * Convert the LINKCHANGE speed enumeration into mbit/s, in the
189          * same way as GET_LINK encodes the speed
190          */
191         switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) {
192         case MCDI_EVENT_LINKCHANGE_SPEED_100M:
193                 speed = 100;
194                 break;
195         case MCDI_EVENT_LINKCHANGE_SPEED_1G:
196                 speed = 1000;
197                 break;
198         case MCDI_EVENT_LINKCHANGE_SPEED_10G:
199                 speed = 10000;
200                 break;
201         case MCDI_EVENT_LINKCHANGE_SPEED_25G:
202                 speed = 25000;
203                 break;
204         case MCDI_EVENT_LINKCHANGE_SPEED_40G:
205                 speed = 40000;
206                 break;
207         case MCDI_EVENT_LINKCHANGE_SPEED_50G:
208                 speed = 50000;
209                 break;
210         case MCDI_EVENT_LINKCHANGE_SPEED_100G:
211                 speed = 100000;
212                 break;
213         default:
214                 speed = 0;
215                 break;
216         }
217
218         link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS);
219         mcdi_phy_decode_link_mode(enp, link_flags, speed,
220                                     MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL),
221                                     &link_mode, &fcntl);
222         mcdi_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP),
223                             &lp_cap_mask);
224
225         /*
226          * It's safe to update ep_lp_cap_mask without the driver's port lock
227          * because presumably any concurrently running efx_port_poll() is
228          * only going to arrive at the same value.
229          *
230          * ep_fcntl has two meanings. It's either the link common fcntl
231          * (if the PHY supports AN), or it's the forced link state. If
232          * the former, it's safe to update the value for the same reason as
233          * for ep_lp_cap_mask. If the latter, then just ignore the value,
234          * because we can race with efx_mac_fcntl_set().
235          */
236         epp->ep_lp_cap_mask = lp_cap_mask;
237         epp->ep_fcntl = fcntl;
238
239         *link_modep = link_mode;
240 }
241
242         __checkReturn   efx_rc_t
243 ef10_phy_power(
244         __in            efx_nic_t *enp,
245         __in            boolean_t power)
246 {
247         efx_rc_t rc;
248
249         if (!power)
250                 return (0);
251
252         /* Check if the PHY is a zombie */
253         if ((rc = ef10_phy_verify(enp)) != 0)
254                 goto fail1;
255
256         enp->en_reset_flags |= EFX_RESET_PHY;
257
258         return (0);
259
260 fail1:
261         EFSYS_PROBE1(fail1, efx_rc_t, rc);
262
263         return (rc);
264 }
265
266         __checkReturn   efx_rc_t
267 ef10_phy_get_link(
268         __in            efx_nic_t *enp,
269         __out           ef10_link_state_t *elsp)
270 {
271         efx_mcdi_req_t req;
272         uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN,
273                             MC_CMD_GET_LINK_OUT_LEN)];
274         efx_rc_t rc;
275
276         (void) memset(payload, 0, sizeof (payload));
277         req.emr_cmd = MC_CMD_GET_LINK;
278         req.emr_in_buf = payload;
279         req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
280         req.emr_out_buf = payload;
281         req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN;
282
283         efx_mcdi_execute(enp, &req);
284
285         if (req.emr_rc != 0) {
286                 rc = req.emr_rc;
287                 goto fail1;
288         }
289
290         if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
291                 rc = EMSGSIZE;
292                 goto fail2;
293         }
294
295         mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
296                             &elsp->els_adv_cap_mask);
297         mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
298                             &elsp->els_lp_cap_mask);
299
300         mcdi_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
301                             MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
302                             MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
303                             &elsp->els_link_mode, &elsp->els_fcntl);
304
305 #if EFSYS_OPT_LOOPBACK
306         /*
307          * MC_CMD_LOOPBACK and EFX_LOOPBACK names are equivalent, so use the
308          * MCDI value directly. Agreement is checked in efx_loopback_mask().
309          */
310         elsp->els_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
311 #endif  /* EFSYS_OPT_LOOPBACK */
312
313         elsp->els_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
314
315         return (0);
316
317 fail2:
318         EFSYS_PROBE(fail2);
319 fail1:
320         EFSYS_PROBE1(fail1, efx_rc_t, rc);
321
322         return (rc);
323 }
324
325         __checkReturn   efx_rc_t
326 ef10_phy_reconfigure(
327         __in            efx_nic_t *enp)
328 {
329         efx_port_t *epp = &(enp->en_port);
330         efx_mcdi_req_t req;
331         uint8_t payload[MAX(MC_CMD_SET_LINK_IN_LEN,
332                             MC_CMD_SET_LINK_OUT_LEN)];
333         uint32_t cap_mask;
334 #if EFSYS_OPT_PHY_LED_CONTROL
335         unsigned int led_mode;
336 #endif
337         unsigned int speed;
338         boolean_t supported;
339         efx_rc_t rc;
340
341         if ((rc = efx_mcdi_link_control_supported(enp, &supported)) != 0)
342                 goto fail1;
343         if (supported == B_FALSE)
344                 goto out;
345
346         (void) memset(payload, 0, sizeof (payload));
347         req.emr_cmd = MC_CMD_SET_LINK;
348         req.emr_in_buf = payload;
349         req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
350         req.emr_out_buf = payload;
351         req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;
352
353         cap_mask = epp->ep_adv_cap_mask;
354         MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
355                 PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
356                 PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
357                 PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
358                 PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
359                 PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
360                 PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
361                 PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
362                 PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
363                 PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
364                 PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
365         /* Too many fields for for POPULATE macros, so insert this afterwards */
366         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
367             PHY_CAP_25000FDX, (cap_mask >> EFX_PHY_CAP_25000FDX) & 0x1);
368         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
369             PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1);
370         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
371             PHY_CAP_50000FDX, (cap_mask >> EFX_PHY_CAP_50000FDX) & 0x1);
372         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
373             PHY_CAP_100000FDX, (cap_mask >> EFX_PHY_CAP_100000FDX) & 0x1);
374
375         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
376             PHY_CAP_BASER_FEC, (cap_mask >> EFX_PHY_CAP_BASER_FEC) & 0x1);
377         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
378             PHY_CAP_BASER_FEC_REQUESTED,
379             (cap_mask >> EFX_PHY_CAP_BASER_FEC_REQUESTED) & 0x1);
380
381         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
382             PHY_CAP_RS_FEC, (cap_mask >> EFX_PHY_CAP_RS_FEC) & 0x1);
383         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
384             PHY_CAP_RS_FEC_REQUESTED,
385             (cap_mask >> EFX_PHY_CAP_RS_FEC_REQUESTED) & 0x1);
386
387         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
388             PHY_CAP_25G_BASER_FEC,
389             (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC) & 0x1);
390         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
391             PHY_CAP_25G_BASER_FEC_REQUESTED,
392             (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC_REQUESTED) & 0x1);
393
394 #if EFSYS_OPT_LOOPBACK
395         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
396                     epp->ep_loopback_type);
397         switch (epp->ep_loopback_link_mode) {
398         case EFX_LINK_100FDX:
399                 speed = 100;
400                 break;
401         case EFX_LINK_1000FDX:
402                 speed = 1000;
403                 break;
404         case EFX_LINK_10000FDX:
405                 speed = 10000;
406                 break;
407         case EFX_LINK_25000FDX:
408                 speed = 25000;
409                 break;
410         case EFX_LINK_40000FDX:
411                 speed = 40000;
412                 break;
413         case EFX_LINK_50000FDX:
414                 speed = 50000;
415                 break;
416         case EFX_LINK_100000FDX:
417                 speed = 100000;
418                 break;
419         default:
420                 speed = 0;
421         }
422 #else
423         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
424         speed = 0;
425 #endif  /* EFSYS_OPT_LOOPBACK */
426         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
427
428 #if EFSYS_OPT_PHY_FLAGS
429         MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
430 #else
431         MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
432 #endif  /* EFSYS_OPT_PHY_FLAGS */
433
434         efx_mcdi_execute(enp, &req);
435
436         if (req.emr_rc != 0) {
437                 rc = req.emr_rc;
438                 goto fail2;
439         }
440
441         /* And set the blink mode */
442         (void) memset(payload, 0, sizeof (payload));
443         req.emr_cmd = MC_CMD_SET_ID_LED;
444         req.emr_in_buf = payload;
445         req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
446         req.emr_out_buf = payload;
447         req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;
448
449 #if EFSYS_OPT_PHY_LED_CONTROL
450         switch (epp->ep_phy_led_mode) {
451         case EFX_PHY_LED_DEFAULT:
452                 led_mode = MC_CMD_LED_DEFAULT;
453                 break;
454         case EFX_PHY_LED_OFF:
455                 led_mode = MC_CMD_LED_OFF;
456                 break;
457         case EFX_PHY_LED_ON:
458                 led_mode = MC_CMD_LED_ON;
459                 break;
460         default:
461                 EFSYS_ASSERT(0);
462                 led_mode = MC_CMD_LED_DEFAULT;
463         }
464
465         MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
466 #else
467         MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
468 #endif  /* EFSYS_OPT_PHY_LED_CONTROL */
469
470         efx_mcdi_execute(enp, &req);
471
472         if (req.emr_rc != 0) {
473                 rc = req.emr_rc;
474                 goto fail3;
475         }
476 out:
477         return (0);
478
479 fail3:
480         EFSYS_PROBE(fail3);
481 fail2:
482         EFSYS_PROBE(fail2);
483 fail1:
484         EFSYS_PROBE1(fail1, efx_rc_t, rc);
485
486         return (rc);
487 }
488
489         __checkReturn   efx_rc_t
490 ef10_phy_verify(
491         __in            efx_nic_t *enp)
492 {
493         efx_mcdi_req_t req;
494         uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN,
495                             MC_CMD_GET_PHY_STATE_OUT_LEN)];
496         uint32_t state;
497         efx_rc_t rc;
498
499         (void) memset(payload, 0, sizeof (payload));
500         req.emr_cmd = MC_CMD_GET_PHY_STATE;
501         req.emr_in_buf = payload;
502         req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
503         req.emr_out_buf = payload;
504         req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN;
505
506         efx_mcdi_execute(enp, &req);
507
508         if (req.emr_rc != 0) {
509                 rc = req.emr_rc;
510                 goto fail1;
511         }
512
513         if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
514                 rc = EMSGSIZE;
515                 goto fail2;
516         }
517
518         state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
519         if (state != MC_CMD_PHY_STATE_OK) {
520                 if (state != MC_CMD_PHY_STATE_ZOMBIE)
521                         EFSYS_PROBE1(mc_pcol_error, int, state);
522                 rc = ENOTACTIVE;
523                 goto fail3;
524         }
525
526         return (0);
527
528 fail3:
529         EFSYS_PROBE(fail3);
530 fail2:
531         EFSYS_PROBE(fail2);
532 fail1:
533         EFSYS_PROBE1(fail1, efx_rc_t, rc);
534
535         return (rc);
536 }
537
538         __checkReturn   efx_rc_t
539 ef10_phy_oui_get(
540         __in            efx_nic_t *enp,
541         __out           uint32_t *ouip)
542 {
543         _NOTE(ARGUNUSED(enp, ouip))
544
545         return (ENOTSUP);
546 }
547
548 #if EFSYS_OPT_PHY_STATS
549
550         __checkReturn                           efx_rc_t
551 ef10_phy_stats_update(
552         __in                                    efx_nic_t *enp,
553         __in                                    efsys_mem_t *esmp,
554         __inout_ecount(EFX_PHY_NSTATS)          uint32_t *stat)
555 {
556         /* TBD: no stats support in firmware yet */
557         _NOTE(ARGUNUSED(enp, esmp))
558         memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat));
559
560         return (0);
561 }
562
563 #endif  /* EFSYS_OPT_PHY_STATS */
564
565 #if EFSYS_OPT_BIST
566
567         __checkReturn           efx_rc_t
568 ef10_bist_enable_offline(
569         __in                    efx_nic_t *enp)
570 {
571         efx_rc_t rc;
572
573         if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0)
574                 goto fail1;
575
576         return (0);
577
578 fail1:
579         EFSYS_PROBE1(fail1, efx_rc_t, rc);
580
581         return (rc);
582 }
583
584         __checkReturn           efx_rc_t
585 ef10_bist_start(
586         __in                    efx_nic_t *enp,
587         __in                    efx_bist_type_t type)
588 {
589         efx_rc_t rc;
590
591         if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
592                 goto fail1;
593
594         return (0);
595
596 fail1:
597         EFSYS_PROBE1(fail1, efx_rc_t, rc);
598
599         return (rc);
600 }
601
602         __checkReturn           efx_rc_t
603 ef10_bist_poll(
604         __in                    efx_nic_t *enp,
605         __in                    efx_bist_type_t type,
606         __out                   efx_bist_result_t *resultp,
607         __out_opt __drv_when(count > 0, __notnull)
608         uint32_t *value_maskp,
609         __out_ecount_opt(count) __drv_when(count > 0, __notnull)
610         unsigned long *valuesp,
611         __in                    size_t count)
612 {
613         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
614         efx_mcdi_req_t req;
615         uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN,
616                             MCDI_CTL_SDU_LEN_MAX)];
617         uint32_t value_mask = 0;
618         uint32_t result;
619         efx_rc_t rc;
620
621         _NOTE(ARGUNUSED(type))
622
623         (void) memset(payload, 0, sizeof (payload));
624         req.emr_cmd = MC_CMD_POLL_BIST;
625         req.emr_in_buf = payload;
626         req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
627         req.emr_out_buf = payload;
628         req.emr_out_length = MCDI_CTL_SDU_LEN_MAX;
629
630         efx_mcdi_execute(enp, &req);
631
632         if (req.emr_rc != 0) {
633                 rc = req.emr_rc;
634                 goto fail1;
635         }
636
637         if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
638                 rc = EMSGSIZE;
639                 goto fail2;
640         }
641
642         if (count > 0)
643                 (void) memset(valuesp, '\0', count * sizeof (unsigned long));
644
645         result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
646
647         if (result == MC_CMD_POLL_BIST_FAILED &&
648             req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN &&
649             count > EFX_BIST_MEM_ECC_FATAL) {
650                 if (valuesp != NULL) {
651                         valuesp[EFX_BIST_MEM_TEST] =
652                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST);
653                         valuesp[EFX_BIST_MEM_ADDR] =
654                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR);
655                         valuesp[EFX_BIST_MEM_BUS] =
656                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS);
657                         valuesp[EFX_BIST_MEM_EXPECT] =
658                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT);
659                         valuesp[EFX_BIST_MEM_ACTUAL] =
660                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL);
661                         valuesp[EFX_BIST_MEM_ECC] =
662                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC);
663                         valuesp[EFX_BIST_MEM_ECC_PARITY] =
664                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY);
665                         valuesp[EFX_BIST_MEM_ECC_FATAL] =
666                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL);
667                 }
668                 value_mask |= (1 << EFX_BIST_MEM_TEST) |
669                     (1 << EFX_BIST_MEM_ADDR) |
670                     (1 << EFX_BIST_MEM_BUS) |
671                     (1 << EFX_BIST_MEM_EXPECT) |
672                     (1 << EFX_BIST_MEM_ACTUAL) |
673                     (1 << EFX_BIST_MEM_ECC) |
674                     (1 << EFX_BIST_MEM_ECC_PARITY) |
675                     (1 << EFX_BIST_MEM_ECC_FATAL);
676         } else if (result == MC_CMD_POLL_BIST_FAILED &&
677             encp->enc_phy_type == EFX_PHY_XFI_FARMI &&
678             req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
679             count > EFX_BIST_FAULT_CODE) {
680                 if (valuesp != NULL)
681                         valuesp[EFX_BIST_FAULT_CODE] =
682                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
683                 value_mask |= 1 << EFX_BIST_FAULT_CODE;
684         }
685
686         if (value_maskp != NULL)
687                 *value_maskp = value_mask;
688
689         EFSYS_ASSERT(resultp != NULL);
690         if (result == MC_CMD_POLL_BIST_RUNNING)
691                 *resultp = EFX_BIST_RESULT_RUNNING;
692         else if (result == MC_CMD_POLL_BIST_PASSED)
693                 *resultp = EFX_BIST_RESULT_PASSED;
694         else
695                 *resultp = EFX_BIST_RESULT_FAILED;
696
697         return (0);
698
699 fail2:
700         EFSYS_PROBE(fail2);
701 fail1:
702         EFSYS_PROBE1(fail1, efx_rc_t, rc);
703
704         return (rc);
705 }
706
707                         void
708 ef10_bist_stop(
709         __in            efx_nic_t *enp,
710         __in            efx_bist_type_t type)
711 {
712         /* There is no way to stop BIST on EF10. */
713         _NOTE(ARGUNUSED(enp, type))
714 }
715
716 #endif  /* EFSYS_OPT_BIST */
717
718 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */