net/sfc/base: fix name of the argument to store RSS flags
[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         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LINK_IN_LEN,
246                 MC_CMD_GET_LINK_OUT_LEN);
247         efx_rc_t rc;
248
249         req.emr_cmd = MC_CMD_GET_LINK;
250         req.emr_in_buf = payload;
251         req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
252         req.emr_out_buf = payload;
253         req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN;
254
255         efx_mcdi_execute(enp, &req);
256
257         if (req.emr_rc != 0) {
258                 rc = req.emr_rc;
259                 goto fail1;
260         }
261
262         if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
263                 rc = EMSGSIZE;
264                 goto fail2;
265         }
266
267         mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
268                             &elsp->els_adv_cap_mask);
269         mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
270                             &elsp->els_lp_cap_mask);
271
272         mcdi_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
273                             MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
274                             MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
275                             &elsp->els_link_mode, &elsp->els_fcntl);
276
277 #if EFSYS_OPT_LOOPBACK
278         /*
279          * MC_CMD_LOOPBACK and EFX_LOOPBACK names are equivalent, so use the
280          * MCDI value directly. Agreement is checked in efx_loopback_mask().
281          */
282         elsp->els_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
283 #endif  /* EFSYS_OPT_LOOPBACK */
284
285         elsp->els_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
286
287         return (0);
288
289 fail2:
290         EFSYS_PROBE(fail2);
291 fail1:
292         EFSYS_PROBE1(fail1, efx_rc_t, rc);
293
294         return (rc);
295 }
296
297         __checkReturn   efx_rc_t
298 ef10_phy_reconfigure(
299         __in            efx_nic_t *enp)
300 {
301         efx_port_t *epp = &(enp->en_port);
302         efx_mcdi_req_t req;
303         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SET_LINK_IN_LEN,
304                 MC_CMD_SET_LINK_OUT_LEN);
305         uint32_t cap_mask;
306 #if EFSYS_OPT_PHY_LED_CONTROL
307         unsigned int led_mode;
308 #endif
309         unsigned int speed;
310         boolean_t supported;
311         efx_rc_t rc;
312
313         if ((rc = efx_mcdi_link_control_supported(enp, &supported)) != 0)
314                 goto fail1;
315         if (supported == B_FALSE)
316                 goto out;
317
318         req.emr_cmd = MC_CMD_SET_LINK;
319         req.emr_in_buf = payload;
320         req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
321         req.emr_out_buf = payload;
322         req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;
323
324         cap_mask = epp->ep_adv_cap_mask;
325         MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
326                 PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
327                 PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
328                 PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
329                 PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
330                 PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
331                 PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
332                 PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
333                 PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
334                 PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
335                 PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
336         /* Too many fields for for POPULATE macros, so insert this afterwards */
337         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
338             PHY_CAP_25000FDX, (cap_mask >> EFX_PHY_CAP_25000FDX) & 0x1);
339         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
340             PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1);
341         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
342             PHY_CAP_50000FDX, (cap_mask >> EFX_PHY_CAP_50000FDX) & 0x1);
343         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
344             PHY_CAP_100000FDX, (cap_mask >> EFX_PHY_CAP_100000FDX) & 0x1);
345
346         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
347             PHY_CAP_BASER_FEC, (cap_mask >> EFX_PHY_CAP_BASER_FEC) & 0x1);
348         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
349             PHY_CAP_BASER_FEC_REQUESTED,
350             (cap_mask >> EFX_PHY_CAP_BASER_FEC_REQUESTED) & 0x1);
351
352         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
353             PHY_CAP_RS_FEC, (cap_mask >> EFX_PHY_CAP_RS_FEC) & 0x1);
354         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
355             PHY_CAP_RS_FEC_REQUESTED,
356             (cap_mask >> EFX_PHY_CAP_RS_FEC_REQUESTED) & 0x1);
357
358         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
359             PHY_CAP_25G_BASER_FEC,
360             (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC) & 0x1);
361         MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
362             PHY_CAP_25G_BASER_FEC_REQUESTED,
363             (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC_REQUESTED) & 0x1);
364
365 #if EFSYS_OPT_LOOPBACK
366         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
367                     epp->ep_loopback_type);
368         switch (epp->ep_loopback_link_mode) {
369         case EFX_LINK_100FDX:
370                 speed = 100;
371                 break;
372         case EFX_LINK_1000FDX:
373                 speed = 1000;
374                 break;
375         case EFX_LINK_10000FDX:
376                 speed = 10000;
377                 break;
378         case EFX_LINK_25000FDX:
379                 speed = 25000;
380                 break;
381         case EFX_LINK_40000FDX:
382                 speed = 40000;
383                 break;
384         case EFX_LINK_50000FDX:
385                 speed = 50000;
386                 break;
387         case EFX_LINK_100000FDX:
388                 speed = 100000;
389                 break;
390         default:
391                 speed = 0;
392         }
393 #else
394         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
395         speed = 0;
396 #endif  /* EFSYS_OPT_LOOPBACK */
397         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
398
399 #if EFSYS_OPT_PHY_FLAGS
400         MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
401 #else
402         MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
403 #endif  /* EFSYS_OPT_PHY_FLAGS */
404
405         efx_mcdi_execute(enp, &req);
406
407         if (req.emr_rc != 0) {
408                 rc = req.emr_rc;
409                 goto fail2;
410         }
411
412         /* And set the blink mode */
413         (void) memset(payload, 0, sizeof (payload));
414         req.emr_cmd = MC_CMD_SET_ID_LED;
415         req.emr_in_buf = payload;
416         req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
417         req.emr_out_buf = payload;
418         req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;
419
420 #if EFSYS_OPT_PHY_LED_CONTROL
421         switch (epp->ep_phy_led_mode) {
422         case EFX_PHY_LED_DEFAULT:
423                 led_mode = MC_CMD_LED_DEFAULT;
424                 break;
425         case EFX_PHY_LED_OFF:
426                 led_mode = MC_CMD_LED_OFF;
427                 break;
428         case EFX_PHY_LED_ON:
429                 led_mode = MC_CMD_LED_ON;
430                 break;
431         default:
432                 EFSYS_ASSERT(0);
433                 led_mode = MC_CMD_LED_DEFAULT;
434         }
435
436         MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
437 #else
438         MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
439 #endif  /* EFSYS_OPT_PHY_LED_CONTROL */
440
441         efx_mcdi_execute(enp, &req);
442
443         if (req.emr_rc != 0) {
444                 rc = req.emr_rc;
445                 goto fail3;
446         }
447 out:
448         return (0);
449
450 fail3:
451         EFSYS_PROBE(fail3);
452 fail2:
453         EFSYS_PROBE(fail2);
454 fail1:
455         EFSYS_PROBE1(fail1, efx_rc_t, rc);
456
457         return (rc);
458 }
459
460         __checkReturn   efx_rc_t
461 ef10_phy_verify(
462         __in            efx_nic_t *enp)
463 {
464         efx_mcdi_req_t req;
465         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_STATE_IN_LEN,
466                 MC_CMD_GET_PHY_STATE_OUT_LEN);
467         uint32_t state;
468         efx_rc_t rc;
469
470         req.emr_cmd = MC_CMD_GET_PHY_STATE;
471         req.emr_in_buf = payload;
472         req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
473         req.emr_out_buf = payload;
474         req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN;
475
476         efx_mcdi_execute(enp, &req);
477
478         if (req.emr_rc != 0) {
479                 rc = req.emr_rc;
480                 goto fail1;
481         }
482
483         if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
484                 rc = EMSGSIZE;
485                 goto fail2;
486         }
487
488         state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
489         if (state != MC_CMD_PHY_STATE_OK) {
490                 if (state != MC_CMD_PHY_STATE_ZOMBIE)
491                         EFSYS_PROBE1(mc_pcol_error, int, state);
492                 rc = ENOTACTIVE;
493                 goto fail3;
494         }
495
496         return (0);
497
498 fail3:
499         EFSYS_PROBE(fail3);
500 fail2:
501         EFSYS_PROBE(fail2);
502 fail1:
503         EFSYS_PROBE1(fail1, efx_rc_t, rc);
504
505         return (rc);
506 }
507
508         __checkReturn   efx_rc_t
509 ef10_phy_oui_get(
510         __in            efx_nic_t *enp,
511         __out           uint32_t *ouip)
512 {
513         _NOTE(ARGUNUSED(enp, ouip))
514
515         return (ENOTSUP);
516 }
517
518 #if EFSYS_OPT_PHY_STATS
519
520         __checkReturn                           efx_rc_t
521 ef10_phy_stats_update(
522         __in                                    efx_nic_t *enp,
523         __in                                    efsys_mem_t *esmp,
524         __inout_ecount(EFX_PHY_NSTATS)          uint32_t *stat)
525 {
526         /* TBD: no stats support in firmware yet */
527         _NOTE(ARGUNUSED(enp, esmp))
528         memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat));
529
530         return (0);
531 }
532
533 #endif  /* EFSYS_OPT_PHY_STATS */
534
535 #if EFSYS_OPT_BIST
536
537         __checkReturn           efx_rc_t
538 ef10_bist_enable_offline(
539         __in                    efx_nic_t *enp)
540 {
541         efx_rc_t rc;
542
543         if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0)
544                 goto fail1;
545
546         return (0);
547
548 fail1:
549         EFSYS_PROBE1(fail1, efx_rc_t, rc);
550
551         return (rc);
552 }
553
554         __checkReturn           efx_rc_t
555 ef10_bist_start(
556         __in                    efx_nic_t *enp,
557         __in                    efx_bist_type_t type)
558 {
559         efx_rc_t rc;
560
561         if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
562                 goto fail1;
563
564         return (0);
565
566 fail1:
567         EFSYS_PROBE1(fail1, efx_rc_t, rc);
568
569         return (rc);
570 }
571
572         __checkReturn           efx_rc_t
573 ef10_bist_poll(
574         __in                    efx_nic_t *enp,
575         __in                    efx_bist_type_t type,
576         __out                   efx_bist_result_t *resultp,
577         __out_opt __drv_when(count > 0, __notnull)
578         uint32_t *value_maskp,
579         __out_ecount_opt(count) __drv_when(count > 0, __notnull)
580         unsigned long *valuesp,
581         __in                    size_t count)
582 {
583         /*
584          * MCDI_CTL_SDU_LEN_MAX_V1 is large enough cover all BIST results,
585          * whilst not wasting stack.
586          */
587         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_POLL_BIST_IN_LEN,
588                 MCDI_CTL_SDU_LEN_MAX_V1);
589         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
590         efx_mcdi_req_t req;
591         uint32_t value_mask = 0;
592         uint32_t result;
593         efx_rc_t rc;
594
595         EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_LEN <=
596             MCDI_CTL_SDU_LEN_MAX_V1);
597         EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_SFT9001_LEN <=
598             MCDI_CTL_SDU_LEN_MAX_V1);
599         EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_MRSFP_LEN <=
600             MCDI_CTL_SDU_LEN_MAX_V1);
601         EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_MEM_LEN <=
602             MCDI_CTL_SDU_LEN_MAX_V1);
603
604         _NOTE(ARGUNUSED(type))
605
606         req.emr_cmd = MC_CMD_POLL_BIST;
607         req.emr_in_buf = payload;
608         req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
609         req.emr_out_buf = payload;
610         req.emr_out_length = MCDI_CTL_SDU_LEN_MAX_V1;
611
612         efx_mcdi_execute(enp, &req);
613
614         if (req.emr_rc != 0) {
615                 rc = req.emr_rc;
616                 goto fail1;
617         }
618
619         if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
620                 rc = EMSGSIZE;
621                 goto fail2;
622         }
623
624         if (count > 0)
625                 (void) memset(valuesp, '\0', count * sizeof (unsigned long));
626
627         result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
628
629         if (result == MC_CMD_POLL_BIST_FAILED &&
630             req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN &&
631             count > EFX_BIST_MEM_ECC_FATAL) {
632                 if (valuesp != NULL) {
633                         valuesp[EFX_BIST_MEM_TEST] =
634                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST);
635                         valuesp[EFX_BIST_MEM_ADDR] =
636                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR);
637                         valuesp[EFX_BIST_MEM_BUS] =
638                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS);
639                         valuesp[EFX_BIST_MEM_EXPECT] =
640                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT);
641                         valuesp[EFX_BIST_MEM_ACTUAL] =
642                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL);
643                         valuesp[EFX_BIST_MEM_ECC] =
644                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC);
645                         valuesp[EFX_BIST_MEM_ECC_PARITY] =
646                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY);
647                         valuesp[EFX_BIST_MEM_ECC_FATAL] =
648                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL);
649                 }
650                 value_mask |= (1 << EFX_BIST_MEM_TEST) |
651                     (1 << EFX_BIST_MEM_ADDR) |
652                     (1 << EFX_BIST_MEM_BUS) |
653                     (1 << EFX_BIST_MEM_EXPECT) |
654                     (1 << EFX_BIST_MEM_ACTUAL) |
655                     (1 << EFX_BIST_MEM_ECC) |
656                     (1 << EFX_BIST_MEM_ECC_PARITY) |
657                     (1 << EFX_BIST_MEM_ECC_FATAL);
658         } else if (result == MC_CMD_POLL_BIST_FAILED &&
659             encp->enc_phy_type == EFX_PHY_XFI_FARMI &&
660             req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
661             count > EFX_BIST_FAULT_CODE) {
662                 if (valuesp != NULL)
663                         valuesp[EFX_BIST_FAULT_CODE] =
664                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
665                 value_mask |= 1 << EFX_BIST_FAULT_CODE;
666         }
667
668         if (value_maskp != NULL)
669                 *value_maskp = value_mask;
670
671         EFSYS_ASSERT(resultp != NULL);
672         if (result == MC_CMD_POLL_BIST_RUNNING)
673                 *resultp = EFX_BIST_RESULT_RUNNING;
674         else if (result == MC_CMD_POLL_BIST_PASSED)
675                 *resultp = EFX_BIST_RESULT_PASSED;
676         else
677                 *resultp = EFX_BIST_RESULT_FAILED;
678
679         return (0);
680
681 fail2:
682         EFSYS_PROBE(fail2);
683 fail1:
684         EFSYS_PROBE1(fail1, efx_rc_t, rc);
685
686         return (rc);
687 }
688
689                         void
690 ef10_bist_stop(
691         __in            efx_nic_t *enp,
692         __in            efx_bist_type_t type)
693 {
694         /* There is no way to stop BIST on EF10. */
695         _NOTE(ARGUNUSED(enp, type))
696 }
697
698 #endif  /* EFSYS_OPT_BIST */
699
700 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */