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 #include "efx.h"
33 #include "efx_impl.h"
34
35 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
36
37 static void
mcdi_phy_decode_cap(__in uint32_t mcdi_cap,__out uint32_t * maskp)38 mcdi_phy_decode_cap(
39 __in uint32_t mcdi_cap,
40 __out uint32_t *maskp)
41 {
42 uint32_t mask;
43
44 #define CHECK_CAP(_cap) \
45 EFX_STATIC_ASSERT(EFX_PHY_CAP_##_cap == MC_CMD_PHY_CAP_##_cap##_LBN)
46
47 CHECK_CAP(10HDX);
48 CHECK_CAP(10FDX);
49 CHECK_CAP(100HDX);
50 CHECK_CAP(100FDX);
51 CHECK_CAP(1000HDX);
52 CHECK_CAP(1000FDX);
53 CHECK_CAP(10000FDX);
54 CHECK_CAP(25000FDX);
55 CHECK_CAP(40000FDX);
56 CHECK_CAP(50000FDX);
57 CHECK_CAP(100000FDX);
58 CHECK_CAP(PAUSE);
59 CHECK_CAP(ASYM);
60 CHECK_CAP(AN);
61 CHECK_CAP(DDM);
62 CHECK_CAP(BASER_FEC);
63 CHECK_CAP(BASER_FEC_REQUESTED);
64 CHECK_CAP(RS_FEC);
65 CHECK_CAP(RS_FEC_REQUESTED);
66 CHECK_CAP(25G_BASER_FEC);
67 CHECK_CAP(25G_BASER_FEC_REQUESTED);
68 #undef CHECK_CAP
69
70 mask = 0;
71 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
72 mask |= (1 << EFX_PHY_CAP_10HDX);
73 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
74 mask |= (1 << EFX_PHY_CAP_10FDX);
75 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
76 mask |= (1 << EFX_PHY_CAP_100HDX);
77 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
78 mask |= (1 << EFX_PHY_CAP_100FDX);
79 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
80 mask |= (1 << EFX_PHY_CAP_1000HDX);
81 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
82 mask |= (1 << EFX_PHY_CAP_1000FDX);
83 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
84 mask |= (1 << EFX_PHY_CAP_10000FDX);
85 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25000FDX_LBN))
86 mask |= (1 << EFX_PHY_CAP_25000FDX);
87 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))
88 mask |= (1 << EFX_PHY_CAP_40000FDX);
89 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_50000FDX_LBN))
90 mask |= (1 << EFX_PHY_CAP_50000FDX);
91 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100000FDX_LBN))
92 mask |= (1 << EFX_PHY_CAP_100000FDX);
93
94 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
95 mask |= (1 << EFX_PHY_CAP_PAUSE);
96 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
97 mask |= (1 << EFX_PHY_CAP_ASYM);
98 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
99 mask |= (1 << EFX_PHY_CAP_AN);
100
101 /* FEC caps (supported on Medford2 and later) */
102 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN))
103 mask |= (1 << EFX_PHY_CAP_BASER_FEC);
104 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_REQUESTED_LBN))
105 mask |= (1 << EFX_PHY_CAP_BASER_FEC_REQUESTED);
106
107 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_LBN))
108 mask |= (1 << EFX_PHY_CAP_RS_FEC);
109 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_REQUESTED_LBN))
110 mask |= (1 << EFX_PHY_CAP_RS_FEC_REQUESTED);
111
112 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN))
113 mask |= (1 << EFX_PHY_CAP_25G_BASER_FEC);
114 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_REQUESTED_LBN))
115 mask |= (1 << EFX_PHY_CAP_25G_BASER_FEC_REQUESTED);
116
117 *maskp = mask;
118 }
119
120 static void
mcdi_phy_decode_link_mode(__in efx_nic_t * enp,__in uint32_t link_flags,__in unsigned int speed,__in unsigned int fcntl,__in uint32_t fec,__out efx_link_mode_t * link_modep,__out unsigned int * fcntlp,__out efx_phy_fec_type_t * fecp)121 mcdi_phy_decode_link_mode(
122 __in efx_nic_t *enp,
123 __in uint32_t link_flags,
124 __in unsigned int speed,
125 __in unsigned int fcntl,
126 __in uint32_t fec,
127 __out efx_link_mode_t *link_modep,
128 __out unsigned int *fcntlp,
129 __out efx_phy_fec_type_t *fecp)
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 switch (fec) {
173 case MC_CMD_FEC_NONE:
174 *fecp = EFX_PHY_FEC_NONE;
175 break;
176 case MC_CMD_FEC_BASER:
177 *fecp = EFX_PHY_FEC_BASER;
178 break;
179 case MC_CMD_FEC_RS:
180 *fecp = EFX_PHY_FEC_RS;
181 break;
182 default:
183 EFSYS_PROBE1(mc_pcol_error, int, fec);
184 *fecp = EFX_PHY_FEC_NONE;
185 break;
186 }
187 }
188
189 void
ef10_phy_link_ev(__in efx_nic_t * enp,__in efx_qword_t * eqp,__out efx_link_mode_t * link_modep)190 ef10_phy_link_ev(
191 __in efx_nic_t *enp,
192 __in efx_qword_t *eqp,
193 __out efx_link_mode_t *link_modep)
194 {
195 efx_port_t *epp = &(enp->en_port);
196 unsigned int link_flags;
197 unsigned int speed;
198 unsigned int fcntl;
199 efx_phy_fec_type_t fec = MC_CMD_FEC_NONE;
200 efx_link_mode_t link_mode;
201 uint32_t lp_cap_mask;
202
203 /*
204 * Convert the LINKCHANGE speed enumeration into mbit/s, in the
205 * same way as GET_LINK encodes the speed
206 */
207 switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) {
208 case MCDI_EVENT_LINKCHANGE_SPEED_100M:
209 speed = 100;
210 break;
211 case MCDI_EVENT_LINKCHANGE_SPEED_1G:
212 speed = 1000;
213 break;
214 case MCDI_EVENT_LINKCHANGE_SPEED_10G:
215 speed = 10000;
216 break;
217 case MCDI_EVENT_LINKCHANGE_SPEED_25G:
218 speed = 25000;
219 break;
220 case MCDI_EVENT_LINKCHANGE_SPEED_40G:
221 speed = 40000;
222 break;
223 case MCDI_EVENT_LINKCHANGE_SPEED_50G:
224 speed = 50000;
225 break;
226 case MCDI_EVENT_LINKCHANGE_SPEED_100G:
227 speed = 100000;
228 break;
229 default:
230 speed = 0;
231 break;
232 }
233
234 link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS);
235 mcdi_phy_decode_link_mode(enp, link_flags, speed,
236 MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL),
237 MC_CMD_FEC_NONE, &link_mode,
238 &fcntl, &fec);
239 mcdi_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP),
240 &lp_cap_mask);
241
242 /*
243 * It's safe to update ep_lp_cap_mask without the driver's port lock
244 * because presumably any concurrently running efx_port_poll() is
245 * only going to arrive at the same value.
246 *
247 * ep_fcntl has two meanings. It's either the link common fcntl
248 * (if the PHY supports AN), or it's the forced link state. If
249 * the former, it's safe to update the value for the same reason as
250 * for ep_lp_cap_mask. If the latter, then just ignore the value,
251 * because we can race with efx_mac_fcntl_set().
252 */
253 epp->ep_lp_cap_mask = lp_cap_mask;
254 epp->ep_fcntl = fcntl;
255
256 *link_modep = link_mode;
257 }
258
259 __checkReturn efx_rc_t
ef10_phy_power(__in efx_nic_t * enp,__in boolean_t power)260 ef10_phy_power(
261 __in efx_nic_t *enp,
262 __in boolean_t power)
263 {
264 efx_rc_t rc;
265
266 if (!power)
267 return (0);
268
269 /* Check if the PHY is a zombie */
270 if ((rc = ef10_phy_verify(enp)) != 0)
271 goto fail1;
272
273 enp->en_reset_flags |= EFX_RESET_PHY;
274
275 return (0);
276
277 fail1:
278 EFSYS_PROBE1(fail1, efx_rc_t, rc);
279
280 return (rc);
281 }
282
283 __checkReturn efx_rc_t
ef10_phy_get_link(__in efx_nic_t * enp,__out ef10_link_state_t * elsp)284 ef10_phy_get_link(
285 __in efx_nic_t *enp,
286 __out ef10_link_state_t *elsp)
287 {
288 efx_mcdi_req_t req;
289 uint32_t fec;
290 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LINK_IN_LEN,
291 MC_CMD_GET_LINK_OUT_V2_LEN);
292 efx_rc_t rc;
293
294 req.emr_cmd = MC_CMD_GET_LINK;
295 req.emr_in_buf = payload;
296 req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
297 req.emr_out_buf = payload;
298 req.emr_out_length = MC_CMD_GET_LINK_OUT_V2_LEN;
299
300 efx_mcdi_execute(enp, &req);
301
302 if (req.emr_rc != 0) {
303 rc = req.emr_rc;
304 goto fail1;
305 }
306
307 if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
308 rc = EMSGSIZE;
309 goto fail2;
310 }
311
312 mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
313 &elsp->epls.epls_adv_cap_mask);
314 mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
315 &elsp->epls.epls_lp_cap_mask);
316
317 if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_V2_LEN)
318 fec = MC_CMD_FEC_NONE;
319 else
320 fec = MCDI_OUT_DWORD(req, GET_LINK_OUT_V2_FEC_TYPE);
321
322 mcdi_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
323 MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
324 MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
325 fec, &elsp->epls.epls_link_mode,
326 &elsp->epls.epls_fcntl, &elsp->epls.epls_fec);
327
328 if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_V2_LEN) {
329 elsp->epls.epls_ld_cap_mask = 0;
330 } else {
331 mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_V2_LD_CAP),
332 &elsp->epls.epls_ld_cap_mask);
333 }
334
335 #if EFSYS_OPT_LOOPBACK
336 /*
337 * MC_CMD_LOOPBACK and EFX_LOOPBACK names are equivalent, so use the
338 * MCDI value directly. Agreement is checked in efx_loopback_mask().
339 */
340 elsp->els_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
341 #endif /* EFSYS_OPT_LOOPBACK */
342
343 elsp->els_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
344
345 return (0);
346
347 fail2:
348 EFSYS_PROBE(fail2);
349 fail1:
350 EFSYS_PROBE1(fail1, efx_rc_t, rc);
351
352 return (rc);
353 }
354
355 __checkReturn efx_rc_t
ef10_phy_reconfigure(__in efx_nic_t * enp)356 ef10_phy_reconfigure(
357 __in efx_nic_t *enp)
358 {
359 efx_port_t *epp = &(enp->en_port);
360 efx_mcdi_req_t req;
361 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SET_LINK_IN_LEN,
362 MC_CMD_SET_LINK_OUT_LEN);
363 uint32_t cap_mask;
364 #if EFSYS_OPT_PHY_LED_CONTROL
365 unsigned int led_mode;
366 #endif
367 unsigned int speed;
368 boolean_t supported;
369 efx_rc_t rc;
370
371 if ((rc = efx_mcdi_link_control_supported(enp, &supported)) != 0)
372 goto fail1;
373 if (supported == B_FALSE)
374 goto out;
375
376 req.emr_cmd = MC_CMD_SET_LINK;
377 req.emr_in_buf = payload;
378 req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
379 req.emr_out_buf = payload;
380 req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;
381
382 cap_mask = epp->ep_adv_cap_mask;
383 MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
384 PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
385 PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
386 PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
387 PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
388 PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
389 PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
390 PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
391 PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
392 PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
393 PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
394 /* Too many fields for POPULATE macros, so insert this afterwards */
395 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
396 PHY_CAP_25000FDX, (cap_mask >> EFX_PHY_CAP_25000FDX) & 0x1);
397 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
398 PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1);
399 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
400 PHY_CAP_50000FDX, (cap_mask >> EFX_PHY_CAP_50000FDX) & 0x1);
401 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
402 PHY_CAP_100000FDX, (cap_mask >> EFX_PHY_CAP_100000FDX) & 0x1);
403
404 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
405 PHY_CAP_BASER_FEC, (cap_mask >> EFX_PHY_CAP_BASER_FEC) & 0x1);
406 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
407 PHY_CAP_BASER_FEC_REQUESTED,
408 (cap_mask >> EFX_PHY_CAP_BASER_FEC_REQUESTED) & 0x1);
409
410 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
411 PHY_CAP_RS_FEC, (cap_mask >> EFX_PHY_CAP_RS_FEC) & 0x1);
412 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
413 PHY_CAP_RS_FEC_REQUESTED,
414 (cap_mask >> EFX_PHY_CAP_RS_FEC_REQUESTED) & 0x1);
415
416 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
417 PHY_CAP_25G_BASER_FEC,
418 (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC) & 0x1);
419 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
420 PHY_CAP_25G_BASER_FEC_REQUESTED,
421 (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC_REQUESTED) & 0x1);
422
423 #if EFSYS_OPT_LOOPBACK
424 MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
425 epp->ep_loopback_type);
426 switch (epp->ep_loopback_link_mode) {
427 case EFX_LINK_100FDX:
428 speed = 100;
429 break;
430 case EFX_LINK_1000FDX:
431 speed = 1000;
432 break;
433 case EFX_LINK_10000FDX:
434 speed = 10000;
435 break;
436 case EFX_LINK_25000FDX:
437 speed = 25000;
438 break;
439 case EFX_LINK_40000FDX:
440 speed = 40000;
441 break;
442 case EFX_LINK_50000FDX:
443 speed = 50000;
444 break;
445 case EFX_LINK_100000FDX:
446 speed = 100000;
447 break;
448 default:
449 speed = 0;
450 }
451 #else
452 MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
453 speed = 0;
454 #endif /* EFSYS_OPT_LOOPBACK */
455 MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
456
457 #if EFSYS_OPT_PHY_FLAGS
458 MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
459 #else
460 MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
461 #endif /* EFSYS_OPT_PHY_FLAGS */
462
463 efx_mcdi_execute(enp, &req);
464
465 if (req.emr_rc != 0) {
466 rc = req.emr_rc;
467 goto fail2;
468 }
469
470 /* And set the blink mode */
471 (void) memset(payload, 0, sizeof (payload));
472 req.emr_cmd = MC_CMD_SET_ID_LED;
473 req.emr_in_buf = payload;
474 req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
475 req.emr_out_buf = payload;
476 req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;
477
478 #if EFSYS_OPT_PHY_LED_CONTROL
479 switch (epp->ep_phy_led_mode) {
480 case EFX_PHY_LED_DEFAULT:
481 led_mode = MC_CMD_LED_DEFAULT;
482 break;
483 case EFX_PHY_LED_OFF:
484 led_mode = MC_CMD_LED_OFF;
485 break;
486 case EFX_PHY_LED_ON:
487 led_mode = MC_CMD_LED_ON;
488 break;
489 default:
490 EFSYS_ASSERT(0);
491 led_mode = MC_CMD_LED_DEFAULT;
492 }
493
494 MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
495 #else
496 MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
497 #endif /* EFSYS_OPT_PHY_LED_CONTROL */
498
499 efx_mcdi_execute(enp, &req);
500
501 if (req.emr_rc != 0) {
502 rc = req.emr_rc;
503 goto fail3;
504 }
505 out:
506 return (0);
507
508 fail3:
509 EFSYS_PROBE(fail3);
510 fail2:
511 EFSYS_PROBE(fail2);
512 fail1:
513 EFSYS_PROBE1(fail1, efx_rc_t, rc);
514
515 return (rc);
516 }
517
518 __checkReturn efx_rc_t
ef10_phy_verify(__in efx_nic_t * enp)519 ef10_phy_verify(
520 __in efx_nic_t *enp)
521 {
522 efx_mcdi_req_t req;
523 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_STATE_IN_LEN,
524 MC_CMD_GET_PHY_STATE_OUT_LEN);
525 uint32_t state;
526 efx_rc_t rc;
527
528 req.emr_cmd = MC_CMD_GET_PHY_STATE;
529 req.emr_in_buf = payload;
530 req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
531 req.emr_out_buf = payload;
532 req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN;
533
534 efx_mcdi_execute(enp, &req);
535
536 if (req.emr_rc != 0) {
537 rc = req.emr_rc;
538 goto fail1;
539 }
540
541 if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
542 rc = EMSGSIZE;
543 goto fail2;
544 }
545
546 state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
547 if (state != MC_CMD_PHY_STATE_OK) {
548 if (state != MC_CMD_PHY_STATE_ZOMBIE)
549 EFSYS_PROBE1(mc_pcol_error, int, state);
550 rc = ENOTACTIVE;
551 goto fail3;
552 }
553
554 return (0);
555
556 fail3:
557 EFSYS_PROBE(fail3);
558 fail2:
559 EFSYS_PROBE(fail2);
560 fail1:
561 EFSYS_PROBE1(fail1, efx_rc_t, rc);
562
563 return (rc);
564 }
565
566 __checkReturn efx_rc_t
ef10_phy_oui_get(__in efx_nic_t * enp,__out uint32_t * ouip)567 ef10_phy_oui_get(
568 __in efx_nic_t *enp,
569 __out uint32_t *ouip)
570 {
571 _NOTE(ARGUNUSED(enp, ouip))
572
573 return (ENOTSUP);
574 }
575
576 __checkReturn efx_rc_t
ef10_phy_link_state_get(__in efx_nic_t * enp,__out efx_phy_link_state_t * eplsp)577 ef10_phy_link_state_get(
578 __in efx_nic_t *enp,
579 __out efx_phy_link_state_t *eplsp)
580 {
581 efx_rc_t rc;
582 ef10_link_state_t els;
583
584 /* Obtain the active link state */
585 if ((rc = ef10_phy_get_link(enp, &els)) != 0)
586 goto fail1;
587
588 *eplsp = els.epls;
589
590 return (0);
591
592 fail1:
593 EFSYS_PROBE1(fail1, efx_rc_t, rc);
594
595 return (rc);
596 }
597
598 #if EFSYS_OPT_PHY_STATS
599
600 __checkReturn efx_rc_t
ef10_phy_stats_update(__in efx_nic_t * enp,__in efsys_mem_t * esmp,__inout_ecount (EFX_PHY_NSTATS)uint32_t * stat)601 ef10_phy_stats_update(
602 __in efx_nic_t *enp,
603 __in efsys_mem_t *esmp,
604 __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat)
605 {
606 /* TBD: no stats support in firmware yet */
607 _NOTE(ARGUNUSED(enp, esmp))
608 memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat));
609
610 return (0);
611 }
612
613 #endif /* EFSYS_OPT_PHY_STATS */
614
615 #if EFSYS_OPT_BIST
616
617 __checkReturn efx_rc_t
ef10_bist_enable_offline(__in efx_nic_t * enp)618 ef10_bist_enable_offline(
619 __in efx_nic_t *enp)
620 {
621 efx_rc_t rc;
622
623 if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0)
624 goto fail1;
625
626 return (0);
627
628 fail1:
629 EFSYS_PROBE1(fail1, efx_rc_t, rc);
630
631 return (rc);
632 }
633
634 __checkReturn efx_rc_t
ef10_bist_start(__in efx_nic_t * enp,__in efx_bist_type_t type)635 ef10_bist_start(
636 __in efx_nic_t *enp,
637 __in efx_bist_type_t type)
638 {
639 efx_rc_t rc;
640
641 if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
642 goto fail1;
643
644 return (0);
645
646 fail1:
647 EFSYS_PROBE1(fail1, efx_rc_t, rc);
648
649 return (rc);
650 }
651
652 __checkReturn efx_rc_t
653 ef10_bist_poll(
654 __in efx_nic_t *enp,
655 __in efx_bist_type_t type,
656 __out efx_bist_result_t *resultp,
657 __out_opt __drv_when(count > 0, __notnull)
658 uint32_t *value_maskp,
659 __out_ecount_opt(count) __drv_when(count > 0, __notnull)
660 unsigned long *valuesp,
661 __in size_t count)
662 {
663 /*
664 * MCDI_CTL_SDU_LEN_MAX_V1 is large enough cover all BIST results,
665 * whilst not wasting stack.
666 */
667 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_POLL_BIST_IN_LEN,
668 MCDI_CTL_SDU_LEN_MAX_V1);
669 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
670 efx_mcdi_req_t req;
671 uint32_t value_mask = 0;
672 uint32_t result;
673 efx_rc_t rc;
674
675 EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_LEN <=
676 MCDI_CTL_SDU_LEN_MAX_V1);
677 EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_SFT9001_LEN <=
678 MCDI_CTL_SDU_LEN_MAX_V1);
679 EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_MRSFP_LEN <=
680 MCDI_CTL_SDU_LEN_MAX_V1);
681 EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_MEM_LEN <=
682 MCDI_CTL_SDU_LEN_MAX_V1);
683
684 _NOTE(ARGUNUSED(type))
685
686 req.emr_cmd = MC_CMD_POLL_BIST;
687 req.emr_in_buf = payload;
688 req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
689 req.emr_out_buf = payload;
690 req.emr_out_length = MCDI_CTL_SDU_LEN_MAX_V1;
691
692 efx_mcdi_execute(enp, &req);
693
694 if (req.emr_rc != 0) {
695 rc = req.emr_rc;
696 goto fail1;
697 }
698
699 if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
700 rc = EMSGSIZE;
701 goto fail2;
702 }
703
704 if (count > 0)
705 (void) memset(valuesp, '\0', count * sizeof (unsigned long));
706
707 result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
708
709 if (result == MC_CMD_POLL_BIST_FAILED &&
710 req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN &&
711 count > EFX_BIST_MEM_ECC_FATAL) {
712 if (valuesp != NULL) {
713 valuesp[EFX_BIST_MEM_TEST] =
714 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST);
715 valuesp[EFX_BIST_MEM_ADDR] =
716 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR);
717 valuesp[EFX_BIST_MEM_BUS] =
718 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS);
719 valuesp[EFX_BIST_MEM_EXPECT] =
720 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT);
721 valuesp[EFX_BIST_MEM_ACTUAL] =
722 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL);
723 valuesp[EFX_BIST_MEM_ECC] =
724 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC);
725 valuesp[EFX_BIST_MEM_ECC_PARITY] =
726 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY);
727 valuesp[EFX_BIST_MEM_ECC_FATAL] =
728 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL);
729 }
730 value_mask |= (1 << EFX_BIST_MEM_TEST) |
731 (1 << EFX_BIST_MEM_ADDR) |
732 (1 << EFX_BIST_MEM_BUS) |
733 (1 << EFX_BIST_MEM_EXPECT) |
734 (1 << EFX_BIST_MEM_ACTUAL) |
735 (1 << EFX_BIST_MEM_ECC) |
736 (1 << EFX_BIST_MEM_ECC_PARITY) |
737 (1 << EFX_BIST_MEM_ECC_FATAL);
738 } else if (result == MC_CMD_POLL_BIST_FAILED &&
739 encp->enc_phy_type == EFX_PHY_XFI_FARMI &&
740 req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
741 count > EFX_BIST_FAULT_CODE) {
742 if (valuesp != NULL)
743 valuesp[EFX_BIST_FAULT_CODE] =
744 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
745 value_mask |= 1 << EFX_BIST_FAULT_CODE;
746 }
747
748 if (value_maskp != NULL)
749 *value_maskp = value_mask;
750
751 EFSYS_ASSERT(resultp != NULL);
752 if (result == MC_CMD_POLL_BIST_RUNNING)
753 *resultp = EFX_BIST_RESULT_RUNNING;
754 else if (result == MC_CMD_POLL_BIST_PASSED)
755 *resultp = EFX_BIST_RESULT_PASSED;
756 else
757 *resultp = EFX_BIST_RESULT_FAILED;
758
759 return (0);
760
761 fail2:
762 EFSYS_PROBE(fail2);
763 fail1:
764 EFSYS_PROBE1(fail1, efx_rc_t, rc);
765
766 return (rc);
767 }
768
769 void
ef10_bist_stop(__in efx_nic_t * enp,__in efx_bist_type_t type)770 ef10_bist_stop(
771 __in efx_nic_t *enp,
772 __in efx_bist_type_t type)
773 {
774 /* There is no way to stop BIST on EF10. */
775 _NOTE(ARGUNUSED(enp, type))
776 }
777
778 #endif /* EFSYS_OPT_BIST */
779
780 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
781