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