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