]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/dev/sfxge/common/hunt_phy.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / dev / sfxge / common / hunt_phy.c
1 /*-
2  * Copyright (c) 2012-2015 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 "efsys.h"
35 #include "efx.h"
36 #include "efx_impl.h"
37
38 #if EFSYS_OPT_HUNTINGTON
39
40 static                  void
41 hunt_phy_decode_cap(
42         __in            uint32_t mcdi_cap,
43         __out           uint32_t *maskp)
44 {
45         /*
46          * TBD: consider common Siena/Hunt function: Hunt is a superset of
47          * Siena here (adds 40G)
48          */
49
50         uint32_t mask;
51
52         mask = 0;
53         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
54                 mask |= (1 << EFX_PHY_CAP_10HDX);
55         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
56                 mask |= (1 << EFX_PHY_CAP_10FDX);
57         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
58                 mask |= (1 << EFX_PHY_CAP_100HDX);
59         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
60                 mask |= (1 << EFX_PHY_CAP_100FDX);
61         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
62                 mask |= (1 << EFX_PHY_CAP_1000HDX);
63         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
64                 mask |= (1 << EFX_PHY_CAP_1000FDX);
65         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
66                 mask |= (1 << EFX_PHY_CAP_10000FDX);
67         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))
68                 mask |= (1 << EFX_PHY_CAP_40000FDX);
69         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
70                 mask |= (1 << EFX_PHY_CAP_PAUSE);
71         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
72                 mask |= (1 << EFX_PHY_CAP_ASYM);
73         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
74                 mask |= (1 << EFX_PHY_CAP_AN);
75
76         *maskp = mask;
77 }
78
79 static                  void
80 hunt_phy_decode_link_mode(
81         __in            efx_nic_t *enp,
82         __in            uint32_t link_flags,
83         __in            unsigned int speed,
84         __in            unsigned int fcntl,
85         __out           efx_link_mode_t *link_modep,
86         __out           unsigned int *fcntlp)
87 {
88         /*
89          * TBD: consider common Siena/Hunt function: Hunt is a superset of
90          * Siena here (adds 40G and generate-only flow control)
91          */
92
93         boolean_t fd = !!(link_flags &
94                     (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
95         boolean_t up = !!(link_flags &
96                     (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
97
98         _NOTE(ARGUNUSED(enp))
99
100         if (!up)
101                 *link_modep = EFX_LINK_DOWN;
102         else if (speed == 40000 && fd)
103                 *link_modep = EFX_LINK_40000FDX;
104         else if (speed == 10000 && fd)
105                 *link_modep = EFX_LINK_10000FDX;
106         else if (speed == 1000)
107                 *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
108         else if (speed == 100)
109                 *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
110         else if (speed == 10)
111                 *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
112         else
113                 *link_modep = EFX_LINK_UNKNOWN;
114
115         if (fcntl == MC_CMD_FCNTL_OFF)
116                 *fcntlp = 0;
117         else if (fcntl == MC_CMD_FCNTL_RESPOND)
118                 *fcntlp = EFX_FCNTL_RESPOND;
119         else if (fcntl == MC_CMD_FCNTL_GENERATE)
120                 *fcntlp = EFX_FCNTL_GENERATE;
121         else if (fcntl == MC_CMD_FCNTL_BIDIR)
122                 *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
123         else {
124                 EFSYS_PROBE1(mc_pcol_error, int, fcntl);
125                 *fcntlp = 0;
126         }
127 }
128
129
130                         void
131 hunt_phy_link_ev(
132         __in            efx_nic_t *enp,
133         __in            efx_qword_t *eqp,
134         __out           efx_link_mode_t *link_modep)
135 {
136         /*
137          * TBD: consider common Siena/Hunt function: Hunt is a superset of
138          * Siena here (adds 40G)
139          */
140
141         efx_port_t *epp = &(enp->en_port);
142         unsigned int link_flags;
143         unsigned int speed;
144         unsigned int fcntl;
145         efx_link_mode_t link_mode;
146         uint32_t lp_cap_mask;
147
148         /*
149          * Convert the LINKCHANGE speed enumeration into mbit/s, in the
150          * same way as GET_LINK encodes the speed
151          */
152         switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) {
153         case MCDI_EVENT_LINKCHANGE_SPEED_100M:
154                 speed = 100;
155                 break;
156         case MCDI_EVENT_LINKCHANGE_SPEED_1G:
157                 speed = 1000;
158                 break;
159         case MCDI_EVENT_LINKCHANGE_SPEED_10G:
160                 speed = 10000;
161                 break;
162         case MCDI_EVENT_LINKCHANGE_SPEED_40G:
163                 speed = 40000;
164                 break;
165         default:
166                 speed = 0;
167                 break;
168         }
169
170         link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS);
171         hunt_phy_decode_link_mode(enp, link_flags, speed,
172                                     MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL),
173                                     &link_mode, &fcntl);
174         hunt_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP),
175                             &lp_cap_mask);
176
177         /*
178          * It's safe to update ep_lp_cap_mask without the driver's port lock
179          * because presumably any concurrently running efx_port_poll() is
180          * only going to arrive at the same value.
181          *
182          * ep_fcntl has two meanings. It's either the link common fcntl
183          * (if the PHY supports AN), or it's the forced link state. If
184          * the former, it's safe to update the value for the same reason as
185          * for ep_lp_cap_mask. If the latter, then just ignore the value,
186          * because we can race with efx_mac_fcntl_set().
187          */
188         epp->ep_lp_cap_mask = lp_cap_mask;
189         epp->ep_fcntl = fcntl;
190
191         *link_modep = link_mode;
192 }
193
194         __checkReturn   int
195 hunt_phy_power(
196         __in            efx_nic_t *enp,
197         __in            boolean_t power)
198 {
199         /* TBD: consider common Siena/Hunt function: essentially identical */
200
201         int rc;
202
203         if (!power)
204                 return (0);
205
206         /* Check if the PHY is a zombie */
207         if ((rc = hunt_phy_verify(enp)) != 0)
208                 goto fail1;
209
210         enp->en_reset_flags |= EFX_RESET_PHY;
211
212         return (0);
213
214 fail1:
215         EFSYS_PROBE1(fail1, int, rc);
216
217         return (rc);
218 }
219
220         __checkReturn   int
221 hunt_phy_get_link(
222         __in            efx_nic_t *enp,
223         __out           hunt_link_state_t *hlsp)
224 {
225         /*
226          * TBD: consider common Siena/Hunt function: Hunt is very similar
227          * (at least for now; not clear that the loopbacks should necessarily
228          * be quite the same...)
229          */
230
231         efx_mcdi_req_t req;
232         uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN,
233                             MC_CMD_GET_LINK_OUT_LEN)];
234         int rc;
235
236         (void) memset(payload, 0, sizeof (payload));
237         req.emr_cmd = MC_CMD_GET_LINK;
238         req.emr_in_buf = payload;
239         req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
240         req.emr_out_buf = payload;
241         req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN;
242
243         efx_mcdi_execute(enp, &req);
244
245         if (req.emr_rc != 0) {
246                 rc = req.emr_rc;
247                 goto fail1;
248         }
249
250         if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
251                 rc = EMSGSIZE;
252                 goto fail2;
253         }
254
255         hunt_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
256                             &hlsp->hls_adv_cap_mask);
257         hunt_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
258                             &hlsp->hls_lp_cap_mask);
259
260         hunt_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
261                             MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
262                             MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
263                             &hlsp->hls_link_mode, &hlsp->hls_fcntl);
264
265 #if EFSYS_OPT_LOOPBACK
266         /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
267         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
268         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
269         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
270         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
271         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
272         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
273         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
274         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
275         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
276         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
277         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
278         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
279         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
280         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
281         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
282         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
283         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
284         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
285
286         hlsp->hls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
287 #endif  /* EFSYS_OPT_LOOPBACK */
288
289         hlsp->hls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
290
291         return (0);
292
293 fail2:
294         EFSYS_PROBE(fail2);
295 fail1:
296         EFSYS_PROBE1(fail1, int, rc);
297
298         return (rc);
299 }
300
301         __checkReturn   int
302 hunt_phy_reconfigure(
303         __in            efx_nic_t *enp)
304 {
305         /*
306          * TBD: this is a little different for now (no LED support for Hunt
307          * yet), but ultimately should consider common Siena/Hunt function:
308          * Hunt should be a superset of Siena here (adds 40G)
309          */
310
311         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
312         efx_port_t *epp = &(enp->en_port);
313         efx_mcdi_req_t req;
314         uint8_t payload[MAX(MC_CMD_SET_LINK_IN_LEN,
315                             MC_CMD_SET_LINK_OUT_LEN)];
316         uint32_t cap_mask;
317         unsigned int led_mode;
318         unsigned int speed;
319         int rc;
320
321         if (~encp->enc_func_flags & EFX_NIC_FUNC_LINKCTRL)
322                 goto out;
323
324         (void) memset(payload, 0, sizeof (payload));
325         req.emr_cmd = MC_CMD_SET_LINK;
326         req.emr_in_buf = payload;
327         req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
328         req.emr_out_buf = payload;
329         req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;
330
331         cap_mask = epp->ep_adv_cap_mask;
332         MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
333                 PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
334                 PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
335                 PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
336                 PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
337                 PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
338                 PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
339                 PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
340                 PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
341                 PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
342                 PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
343         /* Too many fields for for POPULATE macros, so insert this afterwards */
344         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
345             PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1);
346
347 #if EFSYS_OPT_LOOPBACK
348         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
349                     epp->ep_loopback_type);
350         switch (epp->ep_loopback_link_mode) {
351         case EFX_LINK_100FDX:
352                 speed = 100;
353                 break;
354         case EFX_LINK_1000FDX:
355                 speed = 1000;
356                 break;
357         case EFX_LINK_10000FDX:
358                 speed = 10000;
359                 break;
360         case EFX_LINK_40000FDX:
361                 speed = 40000;
362                 break;
363         default:
364                 speed = 0;
365         }
366 #else
367         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
368         speed = 0;
369 #endif  /* EFSYS_OPT_LOOPBACK */
370         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
371
372 #if EFSYS_OPT_PHY_FLAGS
373         MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
374 #else
375         MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
376 #endif  /* EFSYS_OPT_PHY_FLAGS */
377
378         efx_mcdi_execute(enp, &req);
379
380         if (req.emr_rc != 0) {
381                 rc = req.emr_rc;
382                 goto fail1;
383         }
384
385         /* And set the blink mode */
386         (void) memset(payload, 0, sizeof (payload));
387         req.emr_cmd = MC_CMD_SET_ID_LED;
388         req.emr_in_buf = payload;
389         req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
390         req.emr_out_buf = payload;
391         req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;
392
393 #if EFSYS_OPT_PHY_LED_CONTROL
394         switch (epp->ep_phy_led_mode) {
395         case EFX_PHY_LED_DEFAULT:
396                 led_mode = MC_CMD_LED_DEFAULT;
397                 break;
398         case EFX_PHY_LED_OFF:
399                 led_mode = MC_CMD_LED_OFF;
400                 break;
401         case EFX_PHY_LED_ON:
402                 led_mode = MC_CMD_LED_ON;
403                 break;
404         default:
405                 EFSYS_ASSERT(0);
406                 led_mode = MC_CMD_LED_DEFAULT;
407         }
408
409         MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
410 #else
411         MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
412 #endif  /* EFSYS_OPT_PHY_LED_CONTROL */
413
414         efx_mcdi_execute(enp, &req);
415
416         if (req.emr_rc != 0) {
417                 rc = req.emr_rc;
418                 goto fail2;
419         }
420 out:
421         return (0);
422
423 fail2:
424         EFSYS_PROBE(fail2);
425 fail1:
426         EFSYS_PROBE1(fail1, int, rc);
427
428         return (rc);
429 }
430
431         __checkReturn   int
432 hunt_phy_verify(
433         __in            efx_nic_t *enp)
434 {
435         /* TBD: consider common Siena/Hunt function: essentially identical */
436
437         efx_mcdi_req_t req;
438         uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN,
439                             MC_CMD_GET_PHY_STATE_OUT_LEN)];
440         uint32_t state;
441         int rc;
442
443         (void) memset(payload, 0, sizeof (payload));
444         req.emr_cmd = MC_CMD_GET_PHY_STATE;
445         req.emr_in_buf = payload;
446         req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
447         req.emr_out_buf = payload;
448         req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN;
449
450         efx_mcdi_execute(enp, &req);
451
452         if (req.emr_rc != 0) {
453                 rc = req.emr_rc;
454                 goto fail1;
455         }
456
457         if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
458                 rc = EMSGSIZE;
459                 goto fail2;
460         }
461
462         state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
463         if (state != MC_CMD_PHY_STATE_OK) {
464                 if (state != MC_CMD_PHY_STATE_ZOMBIE)
465                         EFSYS_PROBE1(mc_pcol_error, int, state);
466                 rc = ENOTACTIVE;
467                 goto fail3;
468         }
469
470         return (0);
471
472 fail3:
473         EFSYS_PROBE(fail3);
474 fail2:
475         EFSYS_PROBE(fail2);
476 fail1:
477         EFSYS_PROBE1(fail1, int, rc);
478
479         return (rc);
480 }
481
482         __checkReturn   int
483 hunt_phy_oui_get(
484         __in            efx_nic_t *enp,
485         __out           uint32_t *ouip)
486 {
487         _NOTE(ARGUNUSED(enp, ouip))
488
489         return (ENOTSUP);
490 }
491
492 #if EFSYS_OPT_PHY_STATS
493
494         __checkReturn                           int
495 hunt_phy_stats_update(
496         __in                                    efx_nic_t *enp,
497         __in                                    efsys_mem_t *esmp,
498         __out_ecount(EFX_PHY_NSTATS)            uint32_t *stat)
499 {
500         /* TBD: no stats support in firmware yet */
501         _NOTE(ARGUNUSED(enp, esmp))
502         memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat));
503
504         return (0);
505 }
506
507 #endif  /* EFSYS_OPT_PHY_STATS */
508
509 #if EFSYS_OPT_PHY_PROPS
510
511 #if EFSYS_OPT_NAMES
512
513 extern          const char *
514 hunt_phy_prop_name(
515         __in    efx_nic_t *enp,
516         __in    unsigned int id)
517 {
518         _NOTE(ARGUNUSED(enp, id))
519
520         return (NULL);
521 }
522
523 #endif  /* EFSYS_OPT_NAMES */
524
525 extern  __checkReturn   int
526 hunt_phy_prop_get(
527         __in            efx_nic_t *enp,
528         __in            unsigned int id,
529         __in            uint32_t flags,
530         __out           uint32_t *valp)
531 {
532         _NOTE(ARGUNUSED(enp, id, flags, valp))
533
534         return (ENOTSUP);
535 }
536
537 extern  __checkReturn   int
538 hunt_phy_prop_set(
539         __in            efx_nic_t *enp,
540         __in            unsigned int id,
541         __in            uint32_t val)
542 {
543         _NOTE(ARGUNUSED(enp, id, val))
544
545         return (ENOTSUP);
546 }
547
548 #endif  /* EFSYS_OPT_PHY_PROPS */
549
550 #if EFSYS_OPT_BIST
551
552         __checkReturn           int
553 hunt_bist_enable_offline(
554         __in                    efx_nic_t *enp)
555 {
556         int rc;
557
558         if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0)
559                 goto fail1;
560
561         return (0);
562
563 fail1:
564         EFSYS_PROBE1(fail1, int, rc);
565
566         return (rc);
567 }
568
569         __checkReturn           int
570 hunt_bist_start(
571         __in                    efx_nic_t *enp,
572         __in                    efx_bist_type_t type)
573 {
574         int rc;
575
576         if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
577                 goto fail1;
578
579         return (0);
580
581 fail1:
582         EFSYS_PROBE1(fail1, int, rc);
583
584         return (rc);
585 }
586
587         __checkReturn           int
588 hunt_bist_poll(
589         __in                    efx_nic_t *enp,
590         __in                    efx_bist_type_t type,
591         __out                   efx_bist_result_t *resultp,
592         __out_opt __drv_when(count > 0, __notnull)
593         uint32_t *value_maskp,
594         __out_ecount_opt(count) __drv_when(count > 0, __notnull)
595         unsigned long *valuesp,
596         __in                    size_t count)
597 {
598         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
599         efx_mcdi_req_t req;
600         uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN,
601                             MCDI_CTL_SDU_LEN_MAX)];
602         uint32_t value_mask = 0;
603         uint32_t result;
604         int rc;
605
606         (void) memset(payload, 0, sizeof (payload));
607         req.emr_cmd = MC_CMD_POLL_BIST;
608         req.emr_in_buf = payload;
609         req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
610         req.emr_out_buf = payload;
611         req.emr_out_length = MCDI_CTL_SDU_LEN_MAX;
612
613         efx_mcdi_execute(enp, &req);
614
615         if (req.emr_rc != 0) {
616                 rc = req.emr_rc;
617                 goto fail1;
618         }
619
620         if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
621                 rc = EMSGSIZE;
622                 goto fail2;
623         }
624
625         if (count > 0)
626                 (void) memset(valuesp, '\0', count * sizeof (unsigned long));
627
628         result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
629
630         if (result == MC_CMD_POLL_BIST_FAILED &&
631             req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN &&
632             count > EFX_BIST_MEM_ECC_FATAL) {
633                 if (valuesp != NULL) {
634                         valuesp[EFX_BIST_MEM_TEST] =
635                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST);
636                         valuesp[EFX_BIST_MEM_ADDR] =
637                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR);
638                         valuesp[EFX_BIST_MEM_BUS] =
639                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS);
640                         valuesp[EFX_BIST_MEM_EXPECT] =
641                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT);
642                         valuesp[EFX_BIST_MEM_ACTUAL] =
643                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL);
644                         valuesp[EFX_BIST_MEM_ECC] =
645                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC);
646                         valuesp[EFX_BIST_MEM_ECC_PARITY] =
647                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY);
648                         valuesp[EFX_BIST_MEM_ECC_FATAL] =
649                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL);
650                 }
651                 value_mask |= (1 << EFX_BIST_MEM_TEST) |
652                     (1 << EFX_BIST_MEM_ADDR) |
653                     (1 << EFX_BIST_MEM_BUS) |
654                     (1 << EFX_BIST_MEM_EXPECT) |
655                     (1 << EFX_BIST_MEM_ACTUAL) |
656                     (1 << EFX_BIST_MEM_ECC) |
657                     (1 << EFX_BIST_MEM_ECC_PARITY) |
658                     (1 << EFX_BIST_MEM_ECC_FATAL);
659         } else if (result == MC_CMD_POLL_BIST_FAILED &&
660             encp->enc_phy_type == EFX_PHY_XFI_FARMI &&
661             req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
662             count > EFX_BIST_FAULT_CODE) {
663                 if (valuesp != NULL)
664                         valuesp[EFX_BIST_FAULT_CODE] =
665                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
666                 value_mask |= 1 << EFX_BIST_FAULT_CODE;
667         }
668
669         if (value_maskp != NULL)
670                 *value_maskp = value_mask;
671
672         EFSYS_ASSERT(resultp != NULL);
673         if (result == MC_CMD_POLL_BIST_RUNNING)
674                 *resultp = EFX_BIST_RESULT_RUNNING;
675         else if (result == MC_CMD_POLL_BIST_PASSED)
676                 *resultp = EFX_BIST_RESULT_PASSED;
677         else
678                 *resultp = EFX_BIST_RESULT_FAILED;
679
680         return (0);
681
682 fail2:
683         EFSYS_PROBE(fail2);
684 fail1:
685         EFSYS_PROBE1(fail1, int, rc);
686
687         return (rc);
688 }
689
690                         void
691 hunt_bist_stop(
692         __in            efx_nic_t *enp,
693         __in            efx_bist_type_t type)
694 {
695         /* There is no way to stop BIST on Huntinton. */
696         _NOTE(ARGUNUSED(enp, type))
697 }
698
699 #endif  /* EFSYS_OPT_BIST */
700
701 #endif  /* EFSYS_OPT_HUNTINGTON */