1 /*
2 * Copyright 2009 Solarflare Communications Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25 #include "efsys.h"
26 #include "efx.h"
27 #include "efx_impl.h"
28
29 #if EFSYS_OPT_SIENA
30
31 static void
32 siena_phy_decode_cap(
33 __in uint32_t mcdi_cap,
34 __out uint32_t *maskp)
35 {
36 uint32_t mask;
37
38 mask = 0;
39 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
40 mask |= (1 << EFX_PHY_CAP_10HDX);
41 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
42 mask |= (1 << EFX_PHY_CAP_10FDX);
43 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
44 mask |= (1 << EFX_PHY_CAP_100HDX);
45 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
46 mask |= (1 << EFX_PHY_CAP_100FDX);
47 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
48 mask |= (1 << EFX_PHY_CAP_1000HDX);
49 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
50 mask |= (1 << EFX_PHY_CAP_1000FDX);
51 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
52 mask |= (1 << EFX_PHY_CAP_10000FDX);
53 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
54 mask |= (1 << EFX_PHY_CAP_PAUSE);
55 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
56 mask |= (1 << EFX_PHY_CAP_ASYM);
57 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
58 mask |= (1 << EFX_PHY_CAP_AN);
59
60 *maskp = mask;
61 }
62
63 static void
64 siena_phy_decode_link_mode(
65 __in efx_nic_t *enp,
66 __in uint32_t link_flags,
67 __in unsigned int speed,
68 __in unsigned int fcntl,
69 __out efx_link_mode_t *link_modep,
70 __out unsigned int *fcntlp)
71 {
72 boolean_t fd = !!(link_flags &
73 (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
74 boolean_t up = !!(link_flags &
75 (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
76
77 _NOTE(ARGUNUSED(enp))
78
79 if (!up)
80 *link_modep = EFX_LINK_DOWN;
81 else if (speed == 10000 && fd)
82 *link_modep = EFX_LINK_10000FDX;
83 else if (speed == 1000)
84 *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
85 else if (speed == 100)
86 *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
87 else if (speed == 10)
88 *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
89 else
90 *link_modep = EFX_LINK_UNKNOWN;
91
92 if (fcntl == MC_CMD_FCNTL_OFF)
93 *fcntlp = 0;
94 else if (fcntl == MC_CMD_FCNTL_RESPOND)
95 *fcntlp = EFX_FCNTL_RESPOND;
96 else if (fcntl == MC_CMD_FCNTL_BIDIR)
97 *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
98 else {
99 EFSYS_PROBE1(mc_pcol_error, int, fcntl);
100 *fcntlp = 0;
101 }
102 }
103
104 void
105 siena_phy_link_ev(
106 __in efx_nic_t *enp,
107 __in efx_qword_t *eqp,
108 __out efx_link_mode_t *link_modep)
109 {
110 efx_port_t *epp = &(enp->en_port);
111 unsigned int link_flags;
112 unsigned int speed;
113 unsigned int fcntl;
114 efx_link_mode_t link_mode;
115 uint32_t lp_cap_mask;
116
117 /*
118 * Convert the LINKCHANGE speed enumeration into mbit/s, in the
119 * same way as GET_LINK encodes the speed
120 */
121 switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) {
122 case MCDI_EVENT_LINKCHANGE_SPEED_100M:
123 speed = 100;
124 break;
125 case MCDI_EVENT_LINKCHANGE_SPEED_1G:
126 speed = 1000;
127 break;
128 case MCDI_EVENT_LINKCHANGE_SPEED_10G:
129 speed = 10000;
130 break;
131 default:
132 speed = 0;
133 break;
134 }
135
136 link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS);
137 siena_phy_decode_link_mode(enp, link_flags, speed,
138 MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL),
139 &link_mode, &fcntl);
140 siena_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP),
141 &lp_cap_mask);
142
143 /*
144 * It's safe to update ep_lp_cap_mask without the driver's port lock
145 * because presumably any concurrently running efx_port_poll() is
146 * only going to arrive at the same value.
147 *
148 * ep_fcntl has two meanings. It's either the link common fcntl
149 * (if the PHY supports AN), or it's the forced link state. If
150 * the former, it's safe to update the value for the same reason as
151 * for ep_lp_cap_mask. If the latter, then just ignore the value,
152 * because we can race with efx_mac_fcntl_set().
153 */
154 epp->ep_lp_cap_mask = lp_cap_mask;
155 if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
156 epp->ep_fcntl = fcntl;
157
158 *link_modep = link_mode;
159 }
160
161 __checkReturn int
162 siena_phy_power(
163 __in efx_nic_t *enp,
164 __in boolean_t power)
165 {
166 int rc;
167
168 if (!power)
169 return (0);
170
171 /* Check if the PHY is a zombie */
172 if ((rc = siena_phy_verify(enp)) != 0)
173 goto fail1;
174
175 enp->en_reset_flags |= EFX_RESET_PHY;
176
177 return (0);
178
179 fail1:
180 EFSYS_PROBE1(fail1, int, rc);
181
182 return (rc);
183 }
184
185 __checkReturn int
186 siena_phy_get_link(
187 __in efx_nic_t *enp,
188 __out siena_link_state_t *slsp)
189 {
190 efx_mcdi_req_t req;
191 uint8_t outbuf[MC_CMD_GET_LINK_OUT_LEN];
192 int rc;
193
194 req.emr_cmd = MC_CMD_GET_LINK;
195 EFX_STATIC_ASSERT(MC_CMD_GET_LINK_IN_LEN == 0);
196 req.emr_in_buf = NULL;
197 req.emr_in_length = 0;
198 req.emr_out_buf = outbuf;
199 req.emr_out_length = sizeof (outbuf);
200
201 efx_mcdi_execute(enp, &req);
202
203 if (req.emr_rc != 0) {
204 rc = req.emr_rc;
205 goto fail1;
206 }
207
208 if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
209 rc = EMSGSIZE;
210 goto fail2;
211 }
212
213 siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
214 &slsp->sls_adv_cap_mask);
215 siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
216 &slsp->sls_lp_cap_mask);
217
218 siena_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
219 MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
220 MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
221 &slsp->sls_link_mode, &slsp->sls_fcntl);
222
223 #if EFSYS_OPT_LOOPBACK
224 /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
225 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
226 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
227 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
228 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
229 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
230 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
231 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
232 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
233 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
234 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
235 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
236 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
237 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
238 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
239 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
240 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
241 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
242 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
243
244 slsp->sls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
245 #endif /* EFSYS_OPT_LOOPBACK */
246
247 slsp->sls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
248
249 return (0);
250
251 fail2:
252 EFSYS_PROBE(fail2);
253 fail1:
254 EFSYS_PROBE1(fail1, int, rc);
255
256 return (rc);
257 }
258
259 __checkReturn int
260 siena_phy_reconfigure(
261 __in efx_nic_t *enp)
262 {
263 efx_port_t *epp = &(enp->en_port);
264 efx_mcdi_req_t req;
265 uint8_t payload[MAX(MC_CMD_SET_ID_LED_IN_LEN,
266 MC_CMD_SET_LINK_IN_LEN)];
267 uint32_t cap_mask;
268 unsigned int led_mode;
269 unsigned int speed;
270 int rc;
271
272 req.emr_cmd = MC_CMD_SET_LINK;
273 req.emr_in_buf = payload;
274 req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
275 EFX_STATIC_ASSERT(MC_CMD_SET_LINK_OUT_LEN == 0);
276 req.emr_out_buf = NULL;
277 req.emr_out_length = 0;
278
279 cap_mask = epp->ep_adv_cap_mask;
280 MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
281 PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
282 PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
283 PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
284 PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
285 PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
286 PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
287 PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
288 PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
289 PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
290 PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
291
292 #if EFSYS_OPT_LOOPBACK
293 MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
294 epp->ep_loopback_type);
295 switch (epp->ep_loopback_link_mode) {
296 case EFX_LINK_100FDX:
297 speed = 100;
298 break;
299 case EFX_LINK_1000FDX:
300 speed = 1000;
301 break;
302 case EFX_LINK_10000FDX:
303 speed = 10000;
304 break;
305 default:
306 speed = 0;
307 }
308 #else
309 MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
310 speed = 0;
311 #endif /* EFSYS_OPT_LOOPBACK */
312 MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
313
314 #if EFSYS_OPT_PHY_FLAGS
315 MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
316 #else
317 MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
318 #endif /* EFSYS_OPT_PHY_FLAGS */
319
320 efx_mcdi_execute(enp, &req);
321
322 if (req.emr_rc != 0) {
323 rc = req.emr_rc;
324 goto fail1;
325 }
326
327 /* And set the blink mode */
328 req.emr_cmd = MC_CMD_SET_ID_LED;
329 req.emr_in_buf = payload;
330 req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
331 EFX_STATIC_ASSERT(MC_CMD_SET_ID_LED_OUT_LEN == 0);
332 req.emr_out_buf = NULL;
333 req.emr_out_length = 0;
334
335 #if EFSYS_OPT_PHY_LED_CONTROL
336 switch (epp->ep_phy_led_mode) {
337 case EFX_PHY_LED_DEFAULT:
338 led_mode = MC_CMD_LED_DEFAULT;
339 break;
340 case EFX_PHY_LED_OFF:
341 led_mode = MC_CMD_LED_OFF;
342 break;
343 case EFX_PHY_LED_ON:
344 led_mode = MC_CMD_LED_ON;
345 break;
346 default:
347 EFSYS_ASSERT(0);
348 led_mode = MC_CMD_LED_DEFAULT;
349 }
350
351 MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
352 #else
353 MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
354 #endif /* EFSYS_OPT_PHY_LED_CONTROL */
355
356 efx_mcdi_execute(enp, &req);
357
358 if (req.emr_rc != 0) {
359 rc = req.emr_rc;
360 goto fail2;
361 }
362
363 return (0);
364
365 fail2:
366 EFSYS_PROBE(fail2);
367 fail1:
368 EFSYS_PROBE1(fail1, int, rc);
369
370 return (rc);
371 }
372
373 __checkReturn int
374 siena_phy_verify(
375 __in efx_nic_t *enp)
376 {
377 efx_mcdi_req_t req;
378 uint8_t outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN];
379 uint32_t state;
380 int rc;
381
382 req.emr_cmd = MC_CMD_GET_PHY_STATE;
383 EFX_STATIC_ASSERT(MC_CMD_GET_PHY_STATE_IN_LEN == 0);
384 req.emr_in_buf = NULL;
385 req.emr_in_length = 0;
386 req.emr_out_buf = outbuf;
387 req.emr_out_length = sizeof (outbuf);
388
389 efx_mcdi_execute(enp, &req);
390
391 if (req.emr_rc != 0) {
392 rc = req.emr_rc;
393 goto fail1;
394 }
395
396 if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
397 rc = EMSGSIZE;
398 goto fail2;
399 }
400
401 state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
402 if (state != MC_CMD_PHY_STATE_OK) {
403 if (state != MC_CMD_PHY_STATE_ZOMBIE)
404 EFSYS_PROBE1(mc_pcol_error, int, state);
405 rc = ENOTACTIVE;
406 goto fail3;
407 }
408
409 return (0);
410
411 fail3:
412 EFSYS_PROBE(fail3);
413 fail2:
414 EFSYS_PROBE(fail2);
415 fail1:
416 EFSYS_PROBE1(fail1, int, rc);
417
418 return (rc);
419 }
420
421 __checkReturn int
422 siena_phy_oui_get(
423 __in efx_nic_t *enp,
424 __out uint32_t *ouip)
425 {
426 _NOTE(ARGUNUSED(enp, ouip))
427
428 return (ENOTSUP);
429 }
430
431 #if EFSYS_OPT_PHY_STATS
432
433 #define SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat, \
434 _mc_record, _efx_record) \
435 if ((_vmask) & (1ULL << (_mc_record))) { \
436 (_smask) |= (1ULL << (_efx_record)); \
437 if ((_stat) != NULL && !EFSYS_MEM_IS_NULL(_esmp)) { \
438 efx_dword_t dword; \
439 EFSYS_MEM_READD(_esmp, (_mc_record) * 4, &dword);\
440 (_stat)[_efx_record] = \
441 EFX_DWORD_FIELD(dword, EFX_DWORD_0); \
442 } \
443 }
444
445 #define SIENA_SIMPLE_STAT_SET2(_vmask, _esmp, _smask, _stat, _record) \
446 SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat, \
447 MC_CMD_ ## _record, \
448 EFX_PHY_STAT_ ## _record)
449
450 void
451 siena_phy_decode_stats(
452 __in efx_nic_t *enp,
453 __in uint32_t vmask,
454 __in_opt efsys_mem_t *esmp,
455 __out_opt uint64_t *smaskp,
456 __out_ecount_opt(EFX_PHY_NSTATS) uint32_t *stat)
457 {
458 uint64_t smask = 0;
459
460 _NOTE(ARGUNUSED(enp))
461
462 SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, OUI);
463 SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_LINK_UP);
464 SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_RX_FAULT);
465 SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_TX_FAULT);
466
467 if (vmask & (1 << MC_CMD_PMA_PMD_SIGNAL)) {
468 smask |= ((1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_A) |
469 (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_B) |
470 (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_C) |
471 (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_D));
472 if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
473 efx_dword_t dword;
474 uint32_t sig;
475 EFSYS_MEM_READD(esmp, 4 * MC_CMD_PMA_PMD_SIGNAL,
476 &dword);
477 sig = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
478 stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_A] = (sig >> 1) & 1;
479 stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_B] = (sig >> 2) & 1;
480 stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_C] = (sig >> 3) & 1;
481 stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_D] = (sig >> 4) & 1;
482 }
483 }
484
485 SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_A,
486 EFX_PHY_STAT_SNR_A);
487 SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_B,
488 EFX_PHY_STAT_SNR_B);
489 SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_C,
490 EFX_PHY_STAT_SNR_C);
491 SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_D,
492 EFX_PHY_STAT_SNR_D);
493
494 SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_LINK_UP);
495 SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_RX_FAULT);
496 SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_TX_FAULT);
497 SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BER);
498 SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BLOCK_ERRORS);
499
500 SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_LINK_UP,
501 EFX_PHY_STAT_PHY_XS_LINK_UP);
502 SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_RX_FAULT,
503 EFX_PHY_STAT_PHY_XS_RX_FAULT);
504 SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_TX_FAULT,
505 EFX_PHY_STAT_PHY_XS_TX_FAULT);
506 SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_ALIGN,
507 EFX_PHY_STAT_PHY_XS_ALIGN);
508
509 if (vmask & (1 << MC_CMD_PHYXS_SYNC)) {
510 smask |= ((1 << EFX_PHY_STAT_PHY_XS_SYNC_A) |
511 (1 << EFX_PHY_STAT_PHY_XS_SYNC_B) |
512 (1 << EFX_PHY_STAT_PHY_XS_SYNC_C) |
513 (1 << EFX_PHY_STAT_PHY_XS_SYNC_D));
514 if (stat != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
515 efx_dword_t dword;
516 uint32_t sync;
517 EFSYS_MEM_READD(esmp, 4 * MC_CMD_PHYXS_SYNC, &dword);
518 sync = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
519 stat[EFX_PHY_STAT_PHY_XS_SYNC_A] = (sync >> 0) & 1;
520 stat[EFX_PHY_STAT_PHY_XS_SYNC_B] = (sync >> 1) & 1;
521 stat[EFX_PHY_STAT_PHY_XS_SYNC_C] = (sync >> 2) & 1;
522 stat[EFX_PHY_STAT_PHY_XS_SYNC_D] = (sync >> 3) & 1;
523 }
524 }
525
526 SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_LINK_UP);
527 SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_COMPLETE);
528
529 SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_CL22_LINK_UP,
530 EFX_PHY_STAT_CL22EXT_LINK_UP);
531
532 if (smaskp != NULL)
533 *smaskp = smask;
534 }
535
536 __checkReturn int
537 siena_phy_stats_update(
538 __in efx_nic_t *enp,
539 __in efsys_mem_t *esmp,
540 __out_ecount(EFX_PHY_NSTATS) uint32_t *stat)
541 {
542 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
543 uint32_t vmask = encp->enc_siena_phy_stat_mask;
544 uint8_t payload[MC_CMD_PHY_STATS_IN_LEN];
545 uint64_t smask;
546 efx_mcdi_req_t req;
547 int rc;
548
549 req.emr_cmd = MC_CMD_PHY_STATS;
550 req.emr_in_buf = payload;
551 req.emr_in_length = sizeof (payload);
552 EFX_STATIC_ASSERT(MC_CMD_PHY_STATS_OUT_DMA_LEN == 0);
553 req.emr_out_buf = NULL;
554 req.emr_out_length = 0;
555
556 MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_LO,
557 EFSYS_MEM_ADDR(esmp) & 0xffffffff);
558 MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_HI,
559 EFSYS_MEM_ADDR(esmp) >> 32);
560
561 efx_mcdi_execute(enp, &req);
562
563 if (req.emr_rc != 0) {
564 rc = req.emr_rc;
565 goto fail1;
566 }
567 EFSYS_ASSERT3U(req.emr_out_length, ==, MC_CMD_PHY_STATS_OUT_DMA_LEN);
568
569 siena_phy_decode_stats(enp, vmask, esmp, &smask, stat);
570 EFSYS_ASSERT(smask == encp->enc_phy_stat_mask);
571
572 return (0);
573
574 fail1:
575 EFSYS_PROBE1(fail1, int, rc);
576
577 return (0);
578 }
579
580 #endif /* EFSYS_OPT_PHY_STATS */
581
582 #if EFSYS_OPT_PHY_PROPS
583
584 #if EFSYS_OPT_NAMES
585
586 extern const char __cs *
587 siena_phy_prop_name(
588 __in efx_nic_t *enp,
589 __in unsigned int id)
590 {
591 _NOTE(ARGUNUSED(enp, id))
592
593 return (NULL);
594 }
595
596 #endif /* EFSYS_OPT_NAMES */
597
598 extern __checkReturn int
599 siena_phy_prop_get(
600 __in efx_nic_t *enp,
601 __in unsigned int id,
602 __in uint32_t flags,
603 __out uint32_t *valp)
604 {
605 _NOTE(ARGUNUSED(enp, id, flags, valp))
606
607 return (ENOTSUP);
608 }
609
610 extern __checkReturn int
611 siena_phy_prop_set(
612 __in efx_nic_t *enp,
613 __in unsigned int id,
614 __in uint32_t val)
615 {
616 _NOTE(ARGUNUSED(enp, id, val))
617
618 return (ENOTSUP);
619 }
620
621 #endif /* EFSYS_OPT_PHY_PROPS */
622
623 #if EFSYS_OPT_PHY_BIST
624
625 __checkReturn int
626 siena_phy_bist_start(
627 __in efx_nic_t *enp,
628 __in efx_phy_bist_type_t type)
629 {
630 uint8_t payload[MC_CMD_START_BIST_IN_LEN];
631 efx_mcdi_req_t req;
632 int rc;
633
634 req.emr_cmd = MC_CMD_START_BIST;
635 req.emr_in_buf = payload;
636 req.emr_in_length = sizeof (payload);
637 EFX_STATIC_ASSERT(MC_CMD_START_BIST_OUT_LEN == 0);
638 req.emr_out_buf = NULL;
639 req.emr_out_length = 0;
640
641 switch (type) {
642 case EFX_PHY_BIST_TYPE_NORMAL:
643 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
644 break;
645 case EFX_PHY_BIST_TYPE_CABLE_SHORT:
646 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
647 MC_CMD_PHY_BIST_CABLE_SHORT);
648 break;
649 case EFX_PHY_BIST_TYPE_CABLE_LONG:
650 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
651 MC_CMD_PHY_BIST_CABLE_LONG);
652 break;
653 default:
654 EFSYS_ASSERT(0);
655 }
656
657 efx_mcdi_execute(enp, &req);
658
659 if (req.emr_rc != 0) {
660 rc = req.emr_rc;
661 goto fail1;
662 }
663
664 return (0);
665
666 fail1:
667 EFSYS_PROBE1(fail1, int, rc);
668
669 return (rc);
670 }
671
672 static __checkReturn unsigned long
673 siena_phy_sft9001_bist_status(
674 __in uint16_t code)
675 {
676 switch (code) {
677 case MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY:
678 return (EFX_PHY_CABLE_STATUS_BUSY);
679 case MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT:
680 return (EFX_PHY_CABLE_STATUS_INTERPAIRSHORT);
681 case MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT:
682 return (EFX_PHY_CABLE_STATUS_INTRAPAIRSHORT);
683 case MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN:
684 return (EFX_PHY_CABLE_STATUS_OPEN);
685 case MC_CMD_POLL_BIST_SFT9001_PAIR_OK:
686 return (EFX_PHY_CABLE_STATUS_OK);
687 default:
688 return (EFX_PHY_CABLE_STATUS_INVALID);
689 }
690 }
691
692 __checkReturn int
693 siena_phy_bist_poll(
694 __in efx_nic_t *enp,
695 __in efx_phy_bist_type_t type,
696 __out efx_phy_bist_result_t *resultp,
697 __out_opt __drv_when(count > 0, __notnull)
698 uint32_t *value_maskp,
699 __out_ecount_opt(count) __drv_when(count > 0, __notnull)
700 unsigned long *valuesp,
701 __in size_t count)
702 {
703 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
704 uint8_t payload[MCDI_CTL_SDU_LEN_MAX];
705 uint32_t value_mask = 0;
706 efx_mcdi_req_t req;
707 uint32_t result;
708 int rc;
709
710 req.emr_cmd = MC_CMD_POLL_BIST;
711 _NOTE(CONSTANTCONDITION)
712 EFSYS_ASSERT(MC_CMD_POLL_BIST_IN_LEN == 0);
713 req.emr_in_buf = NULL;
714 req.emr_in_length = 0;
715 req.emr_out_buf = payload;
716 req.emr_out_length = sizeof (payload);
717
718 efx_mcdi_execute(enp, &req);
719
720 if (req.emr_rc != 0) {
721 rc = req.emr_rc;
722 goto fail1;
723 }
724
725 if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
726 rc = EMSGSIZE;
727 goto fail2;
728 }
729
730 if (count > 0)
731 (void) memset(valuesp, '\0', count * sizeof (unsigned long));
732
733 result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
734
735 /* Extract PHY specific results */
736 if (result == MC_CMD_POLL_BIST_PASSED &&
737 encp->enc_phy_type == EFX_PHY_SFT9001B &&
738 req.emr_out_length_used >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN &&
739 (type == EFX_PHY_BIST_TYPE_CABLE_SHORT ||
740 type == EFX_PHY_BIST_TYPE_CABLE_LONG)) {
741 uint16_t word;
742
743 if (count > EFX_PHY_BIST_CABLE_LENGTH_A) {
744 if (valuesp != NULL)
745 valuesp[EFX_PHY_BIST_CABLE_LENGTH_A] =
746 MCDI_OUT_DWORD(req,
747 POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
748 value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_A);
749 }
750
751 if (count > EFX_PHY_BIST_CABLE_LENGTH_B) {
752 if (valuesp != NULL)
753 valuesp[EFX_PHY_BIST_CABLE_LENGTH_B] =
754 MCDI_OUT_DWORD(req,
755 POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B);
756 value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_B);
757 }
758
759 if (count > EFX_PHY_BIST_CABLE_LENGTH_C) {
760 if (valuesp != NULL)
761 valuesp[EFX_PHY_BIST_CABLE_LENGTH_C] =
762 MCDI_OUT_DWORD(req,
763 POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C);
764 value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_C);
765 }
766
767 if (count > EFX_PHY_BIST_CABLE_LENGTH_D) {
768 if (valuesp != NULL)
769 valuesp[EFX_PHY_BIST_CABLE_LENGTH_D] =
770 MCDI_OUT_DWORD(req,
771 POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D);
772 value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_D);
773 }
774
775 if (count > EFX_PHY_BIST_CABLE_STATUS_A) {
776 if (valuesp != NULL) {
777 word = MCDI_OUT_WORD(req,
778 POLL_BIST_OUT_SFT9001_CABLE_STATUS_A);
779 valuesp[EFX_PHY_BIST_CABLE_STATUS_A] =
780 siena_phy_sft9001_bist_status(word);
781 }
782 value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_A);
783 }
784
785 if (count > EFX_PHY_BIST_CABLE_STATUS_B) {
786 if (valuesp != NULL) {
787 word = MCDI_OUT_WORD(req,
788 POLL_BIST_OUT_SFT9001_CABLE_STATUS_B);
789 valuesp[EFX_PHY_BIST_CABLE_STATUS_B] =
790 siena_phy_sft9001_bist_status(word);
791 }
792 value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_B);
793 }
794
795 if (count > EFX_PHY_BIST_CABLE_STATUS_C) {
796 if (valuesp != NULL) {
797 word = MCDI_OUT_WORD(req,
798 POLL_BIST_OUT_SFT9001_CABLE_STATUS_C);
799 valuesp[EFX_PHY_BIST_CABLE_STATUS_C] =
800 siena_phy_sft9001_bist_status(word);
801 }
802 value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_C);
803 }
804
805 if (count > EFX_PHY_BIST_CABLE_STATUS_D) {
806 if (valuesp != NULL) {
807 word = MCDI_OUT_WORD(req,
808 POLL_BIST_OUT_SFT9001_CABLE_STATUS_D);
809 valuesp[EFX_PHY_BIST_CABLE_STATUS_D] =
810 siena_phy_sft9001_bist_status(word);
811 }
812 value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_D);
813 }
814
815 } else if (result == MC_CMD_POLL_BIST_FAILED &&
816 encp->enc_phy_type == EFX_PHY_QLX111V &&
817 req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
818 count > EFX_PHY_BIST_FAULT_CODE) {
819 if (valuesp != NULL)
820 valuesp[EFX_PHY_BIST_FAULT_CODE] =
821 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
822 value_mask |= 1 << EFX_PHY_BIST_FAULT_CODE;
823 }
824
825 if (value_maskp != NULL)
826 *value_maskp = value_mask;
827
828 EFSYS_ASSERT(resultp != NULL);
829 if (result == MC_CMD_POLL_BIST_RUNNING)
830 *resultp = EFX_PHY_BIST_RESULT_RUNNING;
831 else if (result == MC_CMD_POLL_BIST_PASSED)
832 *resultp = EFX_PHY_BIST_RESULT_PASSED;
833 else
834 *resultp = EFX_PHY_BIST_RESULT_FAILED;
835
836 return (0);
837
838 fail2:
839 EFSYS_PROBE(fail2);
840 fail1:
841 EFSYS_PROBE1(fail1, int, rc);
842
843 return (rc);
844 }
845
846 void
847 siena_phy_bist_stop(
848 __in efx_nic_t *enp,
849 __in efx_phy_bist_type_t type)
850 {
851 /* There is no way to stop BIST on Siena */
852 _NOTE(ARGUNUSED(enp, type))
853 }
854
855 #endif /* EFSYS_OPT_PHY_BIST */
856
857 #endif /* EFSYS_OPT_SIENA */