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