1 /*
2 * Copyright 2007-2013 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 "efsys.h"
27 #include "efx.h"
28 #include "efx_types.h"
29 #include "efx_regs.h"
30 #include "efx_impl.h"
31 #include "xphy.h"
32 #include "qt2022c2.h"
33 #include "qt2022c2_impl.h"
34
35 #if EFSYS_OPT_PHY_QT2022C2
36
37 static __checkReturn int
38 qt2022c2_led_cfg(
39 __in efx_nic_t *enp)
40 {
41 efx_port_t *epp = &(enp->en_port);
42 efx_word_t led1;
43 efx_word_t led2;
44 efx_word_t led3;
45 int rc;
46
47 #if EFSYS_OPT_PHY_LED_CONTROL
48
49 switch (epp->ep_phy_led_mode) {
50 case EFX_PHY_LED_DEFAULT:
51 EFX_POPULATE_WORD_2(led1, PMA_PMD_LED_CFG, LED_CFG_LSA_DECODE,
52 PMA_PMD_LED_PATH, LED_PATH_RX_DECODE);
53 EFX_POPULATE_WORD_2(led2, PMA_PMD_LED_CFG, LED_CFG_LSA_DECODE,
54 PMA_PMD_LED_PATH, LED_PATH_TX_DECODE);
55 EFX_POPULATE_WORD_1(led3, PMA_PMD_LED_CFG, LED_CFG_OFF_DECODE);
56 break;
57
58 case EFX_PHY_LED_OFF:
59 EFX_POPULATE_WORD_1(led1, PMA_PMD_LED_CFG, LED_CFG_OFF_DECODE);
60 EFX_POPULATE_WORD_1(led2, PMA_PMD_LED_CFG, LED_CFG_OFF_DECODE);
61 EFX_POPULATE_WORD_1(led3, PMA_PMD_LED_CFG, LED_CFG_OFF_DECODE);
62 break;
63
64 case EFX_PHY_LED_ON:
65 EFX_POPULATE_WORD_1(led1, PMA_PMD_LED_CFG, LED_CFG_ON_DECODE);
66 EFX_POPULATE_WORD_1(led2, PMA_PMD_LED_CFG, LED_CFG_ON_DECODE);
67 EFX_POPULATE_WORD_1(led3, PMA_PMD_LED_CFG, LED_CFG_ON_DECODE);
68 break;
69
70 default:
71 EFSYS_ASSERT(B_FALSE);
72 break;
73 }
74
75 #else /* EFSYS_OPT_PHY_LED_CONTROL */
76
77 EFX_POPULATE_WORD_2(led1, PMA_PMD_LED_CFG, LED_CFG_LSA_DECODE,
78 PMA_PMD_LED_PATH, LED_PATH_RX_DECODE);
79 EFX_POPULATE_WORD_2(led2, PMA_PMD_LED_CFG, LED_CFG_LSA_DECODE,
80 PMA_PMD_LED_PATH, LED_PATH_TX_DECODE);
81 EFX_POPULATE_WORD_1(led3, PMA_PMD_LED_CFG, LED_CFG_OFF_DECODE);
82
83 #endif /* EFSYS_OPT_PHY_LED_CONTROL */
84
85 if ((rc = falcon_mdio_write(enp, epp->ep_port, PMA_PMD_MMD,
86 PMA_PMD_LED1_REG, &led1)) != 0)
87 goto fail1;
88
89 if ((rc = falcon_mdio_write(enp, epp->ep_port, PMA_PMD_MMD,
90 PMA_PMD_LED2_REG, &led2)) != 0)
91 goto fail2;
92
93 if ((rc = falcon_mdio_write(enp, epp->ep_port, PMA_PMD_MMD,
94 PMA_PMD_LED3_REG, &led3)) != 0)
95 goto fail3;
96
97 return (0);
98
99 fail3:
100 EFSYS_PROBE(fail2);
101 fail2:
102 EFSYS_PROBE(fail2);
103 fail1:
104 EFSYS_PROBE1(fail1, int, rc);
105
106 return (rc);
107 }
108
109 #if EFSYS_OPT_LOOPBACK
110 static __checkReturn int
111 qt2022c2_loopback_cfg(
112 __in efx_nic_t *enp)
113 {
114 efx_port_t *epp = &(enp->en_port);
115 int rc;
116
117 switch (epp->ep_loopback_type) {
118 case EFX_LOOPBACK_PHY_XS: {
119 efx_word_t word;
120
121 if ((rc = falcon_mdio_read(enp, epp->ep_port, PHY_XS_MMD,
122 PHY_XS_VENDOR0_REG, &word)) != 0)
123 goto fail1;
124
125 EFX_SET_WORD_FIELD(word, XAUI_SYSTEM_LOOPBACK, 1);
126
127 if ((rc = falcon_mdio_write(enp, epp->ep_port, PHY_XS_MMD,
128 PHY_XS_VENDOR0_REG, &word)) != 0)
129 goto fail2;
130
131 break;
132 }
133 case EFX_LOOPBACK_PCS:
134 if ((rc = xphy_mmd_loopback_set(enp, epp->ep_port, PCS_MMD,
135 B_TRUE)) != 0)
136 goto fail1;
137
138 break;
139
140 case EFX_LOOPBACK_PMA_PMD:
141 if ((rc = xphy_mmd_loopback_set(enp, epp->ep_port, PMA_PMD_MMD,
142 B_TRUE)) != 0)
143 goto fail1;
144
145 break;
146
147 default:
148 break;
149 }
150
151 return (0);
152
153 fail2:
154 EFSYS_PROBE(fail2);
155 fail1:
156 EFSYS_PROBE1(fail1, int, rc);
157
158 return (rc);
159 }
160 #endif /* EFSYS_OPT_LOOPBACK */
161
162 __checkReturn int
163 qt2022c2_reset(
164 __in efx_nic_t *enp)
165 {
166 /* Pull the external reset line */
167 falcon_nic_phy_reset(enp);
168
169 return (0);
170 }
171
172 __checkReturn int
173 qt2022c2_reconfigure(
174 __in efx_nic_t *enp)
175 {
176 efx_port_t *epp = &(enp->en_port);
177 int rc;
178
179 if ((rc = xphy_pkg_wait(enp, epp->ep_port, QT2022C2_MMD_MASK)) != 0)
180 goto fail1;
181
182 if ((rc = qt2022c2_led_cfg(enp)) != 0)
183 goto fail2;
184
185 EFSYS_ASSERT3U(epp->ep_adv_cap_mask, ==, QT2022C2_ADV_CAP_MASK);
186
187 #if EFSYS_OPT_LOOPBACK
188 if ((rc = qt2022c2_loopback_cfg(enp)) != 0)
189 goto fail3;
190 #endif /* EFSYS_OPT_LOOPBACK */
191
192 return (0);
193
194 #if EFSYS_OPT_LOOPBACK
195 fail3:
196 EFSYS_PROBE(fail3);
197 #endif /* EFSYS_OPT_LOOPBACK */
198
199 fail2:
200 EFSYS_PROBE(fail2);
201 fail1:
202 EFSYS_PROBE1(fail1, int, rc);
203
204 return (rc);
205 }
206
207 __checkReturn int
208 qt2022c2_verify(
209 __in efx_nic_t *enp)
210 {
211 efx_port_t *epp = &(enp->en_port);
212 int rc;
213
214 if ((rc = xphy_pkg_verify(enp, epp->ep_port, QT2022C2_MMD_MASK)) != 0)
215 goto fail1;
216
217 return (0);
218
219 fail1:
220 EFSYS_PROBE1(fail1, int, rc);
221
222 return (rc);
223 }
224
225 __checkReturn int
226 qt2022c2_uplink_check(
227 __in efx_nic_t *enp,
228 __out boolean_t *upp)
229 {
230 efx_port_t *epp = &(enp->en_port);
231 efx_word_t word;
232 int rc;
233
234 if (epp->ep_mac_type != EFX_MAC_FALCON_XMAC) {
235 rc = ENOTSUP;
236 goto fail1;
237 }
238
239 if ((rc = falcon_mdio_read(enp, epp->ep_port, PHY_XS_MMD,
240 PHY_XS_LANE_STATUS_REG, &word)) != 0)
241 goto fail2;
242
243 *upp = ((EFX_WORD_FIELD(word, PHY_XS_ALIGNED) != 0) &&
244 (EFX_WORD_FIELD(word, PHY_XS_LANE0_SYNC) != 0) &&
245 (EFX_WORD_FIELD(word, PHY_XS_LANE1_SYNC) != 0) &&
246 (EFX_WORD_FIELD(word, PHY_XS_LANE2_SYNC) != 0) &&
247 (EFX_WORD_FIELD(word, PHY_XS_LANE3_SYNC) != 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 qt2022c2_downlink_check(
261 __in efx_nic_t *enp,
262 __out efx_link_mode_t *modep,
263 __out unsigned int *fcntlp,
264 __out uint32_t *lp_cap_maskp)
265 {
266 efx_port_t *epp = &(enp->en_port);
267 boolean_t up;
268 int rc;
269
270 #if EFSYS_OPT_LOOPBACK
271 switch (epp->ep_loopback_type) {
272 case EFX_LOOPBACK_PHY_XS:
273 rc = xphy_mmd_fault(enp, epp->ep_port, &up);
274 if (rc != 0)
275 goto fail1;
276
277 *modep = (up) ? EFX_LINK_10000FDX : EFX_LINK_DOWN;
278 goto done;
279
280 case EFX_LOOPBACK_PCS:
281 rc = xphy_mmd_check(enp, epp->ep_port, PHY_XS_MMD, &up);
282 if (rc != 0)
283 goto fail1;
284
285 *modep = (up) ? EFX_LINK_10000FDX : EFX_LINK_DOWN;
286 goto done;
287
288 default:
289 break;
290 }
291 #endif /* EFSYS_OPT_LOOPBACK */
292
293 if ((rc = xphy_mmd_check(enp, epp->ep_port, PCS_MMD, &up)) != 0)
294 goto fail1;
295
296 *modep = (up) ? EFX_LINK_10000FDX : EFX_LINK_DOWN;
297
298 #if EFSYS_OPT_LOOPBACK
299 done:
300 #endif
301 *fcntlp = epp->ep_fcntl;
302 *lp_cap_maskp = epp->ep_lp_cap_mask;
303
304 return (0);
305
306 fail1:
307 EFSYS_PROBE1(fail1, int, rc);
308
309 return (rc);
310 }
311
312 __checkReturn int
313 qt2022c2_oui_get(
314 __in efx_nic_t *enp,
315 __out uint32_t *ouip)
316 {
317 efx_port_t *epp = &(enp->en_port);
318 int rc;
319
320 if ((rc = xphy_mmd_oui_get(enp, epp->ep_port, PMA_PMD_MMD, ouip)) != 0)
321 goto fail1;
322
323 return (0);
324
325 fail1:
326 EFSYS_PROBE1(fail1, int, rc);
327
328 return (rc);
329 }
330
331 #if EFSYS_OPT_PHY_STATS
332
333 #define QT2022C2_STAT_SET(_stat, _mask, _id, _val) \
334 do { \
335 (_mask) |= (1 << (_id)); \
336 (_stat)[_id] = (uint32_t)(_val); \
337 _NOTE(CONSTANTCONDITION) \
338 } while (B_FALSE)
339
340 static __checkReturn int
341 qt2022c2_pma_pmd_stats_update(
342 __in efx_nic_t *enp,
343 __inout uint64_t *maskp,
344 __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat)
345 {
346 efx_port_t *epp = &(enp->en_port);
347 efx_word_t word;
348 int rc;
349
350 if ((rc = falcon_mdio_read(enp, epp->ep_port, PMA_PMD_MMD,
351 PMA_PMD_STATUS1_REG, &word)) != 0)
352 goto fail1;
353
354 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PMA_PMD_LINK_UP,
355 (EFX_WORD_FIELD(word, PMA_PMD_LINK_UP) != 0) ? 1 : 0);
356
357 if ((rc = falcon_mdio_read(enp, epp->ep_port, PMA_PMD_MMD,
358 PMA_PMD_STATUS2_REG, &word)) != 0)
359 goto fail2;
360
361 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PMA_PMD_RX_FAULT,
362 (EFX_WORD_FIELD(word, PMA_PMD_RX_FAULT) != 0) ? 1 : 0);
363 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PMA_PMD_TX_FAULT,
364 (EFX_WORD_FIELD(word, PMA_PMD_TX_FAULT) != 0) ? 1 : 0);
365
366 return (0);
367
368 fail2:
369 EFSYS_PROBE(fail2);
370 fail1:
371 EFSYS_PROBE1(fail1, int, rc);
372
373 return (rc);
374 }
375
376 static __checkReturn int
377 qt2022c2_pcs_stats_update(
378 __in efx_nic_t *enp,
379 __inout uint64_t *maskp,
380 __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat)
381 {
382 efx_port_t *epp = &(enp->en_port);
383 efx_word_t word;
384 int rc;
385
386 if ((rc = falcon_mdio_read(enp, epp->ep_port, PCS_MMD,
387 PCS_STATUS1_REG, &word)) != 0)
388 goto fail1;
389
390 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PCS_LINK_UP,
391 (EFX_WORD_FIELD(word, PCS_LINK_UP) != 0) ? 1 : 0);
392
393 if ((rc = falcon_mdio_read(enp, epp->ep_port, PCS_MMD,
394 PCS_STATUS2_REG, &word)) != 0)
395 goto fail2;
396
397 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PCS_RX_FAULT,
398 (EFX_WORD_FIELD(word, PCS_RX_FAULT) != 0) ? 1 : 0);
399 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PCS_TX_FAULT,
400 (EFX_WORD_FIELD(word, PCS_TX_FAULT) != 0) ? 1 : 0);
401
402 if ((rc = falcon_mdio_read(enp, epp->ep_port, PCS_MMD,
403 PCS_10GBASE_R_STATUS2_REG, &word)) != 0)
404 goto fail3;
405
406 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PCS_BER,
407 EFX_WORD_FIELD(word, PCS_BER));
408 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PCS_BLOCK_ERRORS,
409 EFX_WORD_FIELD(word, PCS_ERR));
410
411 return (0);
412
413 fail3:
414 EFSYS_PROBE(fail3);
415 fail2:
416 EFSYS_PROBE(fail2);
417 fail1:
418 EFSYS_PROBE1(fail1, int, rc);
419
420 return (rc);
421 }
422
423 static __checkReturn int
424 qt2022c2_phy_xs_stats_update(
425 __in efx_nic_t *enp,
426 __inout uint64_t *maskp,
427 __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat)
428 {
429 efx_port_t *epp = &(enp->en_port);
430 efx_word_t word;
431 int rc;
432
433 if ((rc = falcon_mdio_read(enp, epp->ep_port, PHY_XS_MMD,
434 PHY_XS_STATUS1_REG, &word)) != 0)
435 goto fail1;
436
437 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_LINK_UP,
438 (EFX_WORD_FIELD(word, PHY_XS_LINK_UP) != 0) ? 1 : 0);
439
440 if ((rc = falcon_mdio_read(enp, epp->ep_port, PHY_XS_MMD,
441 PHY_XS_STATUS2_REG, &word)) != 0)
442 goto fail2;
443
444 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_RX_FAULT,
445 (EFX_WORD_FIELD(word, PHY_XS_RX_FAULT) != 0) ? 1 : 0);
446 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_TX_FAULT,
447 (EFX_WORD_FIELD(word, PHY_XS_TX_FAULT) != 0) ? 1 : 0);
448
449 if ((rc = falcon_mdio_read(enp, epp->ep_port, PHY_XS_MMD,
450 PHY_XS_LANE_STATUS_REG, &word)) != 0)
451 goto fail3;
452
453 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_ALIGN,
454 (EFX_WORD_FIELD(word, PHY_XS_ALIGNED) != 0) ? 1 : 0);
455 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_SYNC_A,
456 (EFX_WORD_FIELD(word, PHY_XS_LANE0_SYNC) != 0) ? 1 : 0);
457 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_SYNC_B,
458 (EFX_WORD_FIELD(word, PHY_XS_LANE1_SYNC) != 0) ? 1 : 0);
459 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_SYNC_C,
460 (EFX_WORD_FIELD(word, PHY_XS_LANE2_SYNC) != 0) ? 1 : 0);
461 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_SYNC_D,
462 (EFX_WORD_FIELD(word, PHY_XS_LANE3_SYNC) != 0) ? 1 : 0);
463
464 return (0);
465
466 fail3:
467 EFSYS_PROBE(fail3);
468 fail2:
469 EFSYS_PROBE(fail2);
470 fail1:
471 EFSYS_PROBE1(fail1, int, rc);
472
473 return (rc);
474 }
475
476 __checkReturn int
477 qt2022c2_stats_update(
478 __in efx_nic_t *enp,
479 __in efsys_mem_t *esmp,
480 __out_ecount(EFX_PHY_NSTATS) uint32_t *stat)
481 {
482 efx_port_t *epp = &(enp->en_port);
483 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
484 uint32_t oui;
485 uint64_t mask = 0;
486 int rc;
487
488 _NOTE(ARGUNUSED(esmp))
489
490 if ((rc = xphy_mmd_oui_get(enp, epp->ep_port, PMA_PMD_MMD, &oui)) != 0)
491 goto fail1;
492
493 QT2022C2_STAT_SET(stat, mask, EFX_PHY_STAT_OUI, oui);
494
495 if ((rc = qt2022c2_pma_pmd_stats_update(enp, &mask, stat)) != 0)
496 goto fail2;
497
498 if ((rc = qt2022c2_pcs_stats_update(enp, &mask, stat)) != 0)
499 goto fail3;
500
501 if ((rc = qt2022c2_phy_xs_stats_update(enp, &mask, stat)) != 0)
502 goto fail4;
503
504 /* Ensure all the supported statistics are up to date */
505 EFSYS_ASSERT(mask == encp->enc_phy_stat_mask);
506
507 return (0);
508
509 fail4:
510 EFSYS_PROBE(fail4);
511 fail3:
512 EFSYS_PROBE(fail3);
513 fail2:
514 EFSYS_PROBE(fail2);
515 fail1:
516 EFSYS_PROBE1(fail1, int, rc);
517
518 return (rc);
519 }
520 #endif /* EFSYS_OPT_PHY_STATS */
521
522 #if EFSYS_OPT_PHY_PROPS
523
524 #if EFSYS_OPT_NAMES
525 const char __cs *
526 qt2022c2_prop_name(
527 __in efx_nic_t *enp,
528 __in unsigned int id)
529 {
530 _NOTE(ARGUNUSED(enp, id))
531
532 EFSYS_ASSERT(B_FALSE);
533
534 return (NULL);
535 }
536 #endif /* EFSYS_OPT_NAMES */
537
538 __checkReturn int
539 qt2022c2_prop_get(
540 __in efx_nic_t *enp,
541 __in unsigned int id,
542 __in uint32_t flags,
543 __out uint32_t *valp)
544 {
545 _NOTE(ARGUNUSED(enp, id, flags, valp))
546
547 EFSYS_ASSERT(B_FALSE);
548
549 return (ENOTSUP);
550 }
551
552 __checkReturn int
553 qt2022c2_prop_set(
554 __in efx_nic_t *enp,
555 __in unsigned int id,
556 __in uint32_t val)
557 {
558 _NOTE(ARGUNUSED(enp, id, val))
559
560 EFSYS_ASSERT(B_FALSE);
561
562 return (ENOTSUP);
563 }
564 #endif /* EFSYS_OPT_PHY_PROPS */
565
566 #endif /* EFSYS_OPT_PHY_QT2022C2 */