Deleted Added
full compact
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: head/sys/dev/sfxge/common/siena_nic.c 279098 2015-02-21 06:28:31Z arybchik $");
27__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/siena_nic.c 279141 2015-02-22 07:08:57Z arybchik $");
28
29#include "efsys.h"
30#include "efx.h"
31#include "efx_impl.h"
32
33#if EFSYS_OPT_SIENA
34
35static __checkReturn int
36siena_nic_get_partn_mask(
37 __in efx_nic_t *enp,
38 __out unsigned int *maskp)
39{
40 efx_mcdi_req_t req;
41 uint8_t outbuf[MC_CMD_NVRAM_TYPES_OUT_LEN];
42 int rc;
43
44 req.emr_cmd = MC_CMD_NVRAM_TYPES;
45 EFX_STATIC_ASSERT(MC_CMD_NVRAM_TYPES_IN_LEN == 0);
46 req.emr_in_buf = NULL;
47 req.emr_in_length = 0;
48 req.emr_out_buf = outbuf;
49 req.emr_out_length = sizeof (outbuf);
50
51 efx_mcdi_execute(enp, &req);
52
53 if (req.emr_rc != 0) {
54 rc = req.emr_rc;
55 goto fail1;
56 }
57
58 if (req.emr_out_length_used < MC_CMD_NVRAM_TYPES_OUT_LEN) {
59 rc = EMSGSIZE;
60 goto fail2;
61 }
62
63 *maskp = MCDI_OUT_DWORD(req, NVRAM_TYPES_OUT_TYPES);
64
65 return (0);
66
67fail2:
68 EFSYS_PROBE(fail2);
69fail1:
70 EFSYS_PROBE1(fail1, int, rc);
71
72 return (rc);
73}
74
75static __checkReturn int
76siena_nic_exit_assertion_handler(
77 __in efx_nic_t *enp)
78{
79 efx_mcdi_req_t req;
80 uint8_t payload[MC_CMD_REBOOT_IN_LEN];
81 int rc;
82
83 req.emr_cmd = MC_CMD_REBOOT;
84 req.emr_in_buf = payload;
85 req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
86 EFX_STATIC_ASSERT(MC_CMD_REBOOT_OUT_LEN == 0);
87 req.emr_out_buf = NULL;
88 req.emr_out_length = 0;
89
90 MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
91 MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
92
93 efx_mcdi_execute(enp, &req);
94
95 if (req.emr_rc != 0 && req.emr_rc != EIO) {
96 rc = req.emr_rc;
97 goto fail1;
98 }
99
100 return (0);
101
102fail1:
103 EFSYS_PROBE1(fail1, int, rc);
104
105 return (rc);
106}
107
108static __checkReturn int
109siena_nic_read_assertion(
110 __in efx_nic_t *enp)
111{
112 efx_mcdi_req_t req;
113 uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
114 MC_CMD_GET_ASSERTS_OUT_LEN)];
115 const char *reason;
116 unsigned int flags;
117 unsigned int index;
118 unsigned int ofst;
119 int retry;
120 int rc;
121
122 /*
123 * Before we attempt to chat to the MC, we should verify that the MC
124 * isn't in it's assertion handler, either due to a previous reboot,
125 * or because we're reinitializing due to an eec_exception().
126 *
127 * Use GET_ASSERTS to read any assertion state that may be present.
128 * Retry this command twice. Once because a boot-time assertion failure
129 * might cause the 1st MCDI request to fail. And once again because
130 * we might race with siena_nic_exit_assertion_handler() running on the
131 * other port.
132 */
133 retry = 2;
134 do {
135 req.emr_cmd = MC_CMD_GET_ASSERTS;
136 req.emr_in_buf = payload;
137 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
138 req.emr_out_buf = payload;
139 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
140
141 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
142 efx_mcdi_execute(enp, &req);
143
144 } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
145
146 if (req.emr_rc != 0) {
147 rc = req.emr_rc;
148 goto fail1;
149 }
150
151 if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
152 rc = EMSGSIZE;
153 goto fail2;
154 }
155
156 /* Print out any assertion state recorded */
157 flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
158 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
159 return (0);
160
161 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
162 ? "system-level assertion"
163 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
164 ? "thread-level assertion"
165 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
166 ? "watchdog reset"
167 : "unknown assertion";
168 EFSYS_PROBE3(mcpu_assertion,
169 const char *, reason, unsigned int,
170 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
171 unsigned int,
172 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
173
174 /* Print out the registers */
175 ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
176 for (index = 1; index < 32; index++) {
177 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
178 EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
179 EFX_DWORD_0));
180 ofst += sizeof (efx_dword_t);
181 }
182 EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
183
184 return (0);
185
186fail2:
187 EFSYS_PROBE(fail2);
188fail1:
189 EFSYS_PROBE1(fail1, int, rc);
190
191 return (rc);
192}
193
194static __checkReturn int
195siena_nic_attach(
196 __in efx_nic_t *enp,
197 __in boolean_t attach)
198{
199 efx_mcdi_req_t req;
200 uint8_t payload[MC_CMD_DRV_ATTACH_IN_LEN];
201 int rc;
202
203 req.emr_cmd = MC_CMD_DRV_ATTACH;
204 req.emr_in_buf = payload;
205 req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
206 req.emr_out_buf = NULL;
207 req.emr_out_length = 0;
208
209 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0);
210 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
211
212 efx_mcdi_execute(enp, &req);
213
214 if (req.emr_rc != 0) {
215 rc = req.emr_rc;
216 goto fail1;
217 }
218
219 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
220 rc = EMSGSIZE;
221 goto fail2;
222 }
223
224 return (0);
225
226fail2:
227 EFSYS_PROBE(fail2);
228fail1:
229 EFSYS_PROBE1(fail1, int, rc);
230
231 return (rc);
232}
233
234#if EFSYS_OPT_PCIE_TUNE
235
236 __checkReturn int
237siena_nic_pcie_extended_sync(
238 __in efx_nic_t *enp)
239{
240 uint8_t inbuf[MC_CMD_WORKAROUND_IN_LEN];
241 efx_mcdi_req_t req;
242 int rc;
243
244 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
245
246 req.emr_cmd = MC_CMD_WORKAROUND;
247 req.emr_in_buf = inbuf;
248 req.emr_in_length = sizeof (inbuf);
249 EFX_STATIC_ASSERT(MC_CMD_WORKAROUND_OUT_LEN == 0);
250 req.emr_out_buf = NULL;
251 req.emr_out_length = 0;
252
253 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, MC_CMD_WORKAROUND_BUG17230);
254 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, 1);
255
256 efx_mcdi_execute(enp, &req);
257
258 if (req.emr_rc != 0) {
259 rc = req.emr_rc;
260 goto fail1;
261 }
262
263 return (0);
264
265fail1:
266 EFSYS_PROBE1(fail1, int, rc);
267
268 return (rc);
269}
270
271#endif /* EFSYS_OPT_PCIE_TUNE */
272
273static __checkReturn int
274siena_board_cfg(
275 __in efx_nic_t *enp)
276{
277 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
278 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
279 uint8_t outbuf[MAX(MC_CMD_GET_BOARD_CFG_OUT_LENMIN,
280 MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
281 efx_mcdi_req_t req;
282 uint8_t *mac_addr;
283 efx_dword_t *capabilities;
284 int rc;
285
286 /* Board configuration */
287 req.emr_cmd = MC_CMD_GET_BOARD_CFG;
288 EFX_STATIC_ASSERT(MC_CMD_GET_BOARD_CFG_IN_LEN == 0);
289 req.emr_in_buf = NULL;
290 req.emr_in_length = 0;
291 req.emr_out_buf = outbuf;
292 req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
293
294 efx_mcdi_execute(enp, &req);
295
296 if (req.emr_rc != 0) {
297 rc = req.emr_rc;
298 goto fail1;
299 }
300
301 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
302 rc = EMSGSIZE;
303 goto fail2;
304 }
305
306 if (emip->emi_port == 1) {
307 mac_addr = MCDI_OUT2(req, uint8_t,
308 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
309 capabilities = MCDI_OUT2(req, efx_dword_t,
310 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
311 } else {
312 mac_addr = MCDI_OUT2(req, uint8_t,
313 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
314 capabilities = MCDI_OUT2(req, efx_dword_t,
315 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
316 }
317 EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr);
318
319 encp->enc_board_type = MCDI_OUT_DWORD(req,
320 GET_BOARD_CFG_OUT_BOARD_TYPE);
321
322 /* Additional capabilities */
323 encp->enc_clk_mult = 1;
324 if (MCDI_CMD_DWORD_FIELD(capabilities, CAPABILITIES_TURBO)) {
325 enp->en_features |= EFX_FEATURE_TURBO;
326
327 if (MCDI_CMD_DWORD_FIELD(capabilities,
328 CAPABILITIES_TURBO_ACTIVE))
329 encp->enc_clk_mult = 2;
330 }
331
332 encp->enc_evq_moderation_max = EFX_EV_TIMER_QUANTUM <<
333 FRF_AB_TIMER_VAL_WIDTH / encp->enc_clk_mult;
334
335 /* Resource limits */
336 req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
337 EFX_STATIC_ASSERT(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN == 0);
338 req.emr_in_buf = NULL;
339 req.emr_in_length = 0;
340 req.emr_out_buf = outbuf;
341 req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
342
343 efx_mcdi_execute(enp, &req);
344
345 if (req.emr_rc == 0) {
346 if (req.emr_out_length_used <
347 MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
348 rc = EMSGSIZE;
349 goto fail3;
350 }
351
352 encp->enc_evq_limit = MCDI_OUT_DWORD(req,
353 GET_RESOURCE_LIMITS_OUT_EVQ);
354 encp->enc_txq_limit = MIN(EFX_TXQ_LIMIT_TARGET,
355 MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ));
356 encp->enc_rxq_limit = MIN(EFX_RXQ_LIMIT_TARGET,
357 MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ));
358 } else if (req.emr_rc == ENOTSUP) {
359 encp->enc_evq_limit = 1024;
360 encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET;
361 encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET;
362 } else {
363 rc = req.emr_rc;
364 goto fail4;
365 }
366
367 encp->enc_buftbl_limit = SIENA_SRAM_ROWS -
368 (encp->enc_txq_limit * EFX_TXQ_DC_NDESCS(EFX_TXQ_DC_SIZE)) -
369 (encp->enc_rxq_limit * EFX_RXQ_DC_NDESCS(EFX_RXQ_DC_SIZE));
370
371 return (0);
372
373fail4:
374 EFSYS_PROBE(fail4);
375fail3:
376 EFSYS_PROBE(fail3);
377fail2:
378 EFSYS_PROBE(fail2);
379fail1:
380 EFSYS_PROBE1(fail1, int, rc);
381
382 return (rc);
383}
384
385static __checkReturn int
386siena_phy_cfg(
387 __in efx_nic_t *enp)
388{
389 efx_port_t *epp = &(enp->en_port);
390 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
391 efx_mcdi_req_t req;
392 uint8_t outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN];
393 int rc;
394
395 req.emr_cmd = MC_CMD_GET_PHY_CFG;
396 EFX_STATIC_ASSERT(MC_CMD_GET_PHY_CFG_IN_LEN == 0);
397 req.emr_in_buf = NULL;
398 req.emr_in_length = 0;
399 req.emr_out_buf = outbuf;
400 req.emr_out_length = sizeof (outbuf);
401
402 efx_mcdi_execute(enp, &req);
403
404 if (req.emr_rc != 0) {
405 rc = req.emr_rc;
406 goto fail1;
407 }
408
409 if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
410 rc = EMSGSIZE;
411 goto fail2;
412 }
413
414 encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
415#if EFSYS_OPT_NAMES
416 (void) strncpy(encp->enc_phy_name,
417 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
418 MIN(sizeof (encp->enc_phy_name) - 1,
419 MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
420#endif /* EFSYS_OPT_NAMES */
421 (void) memset(encp->enc_phy_revision, 0,
422 sizeof (encp->enc_phy_revision));
423 memcpy(encp->enc_phy_revision,
424 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
425 MIN(sizeof (encp->enc_phy_revision) - 1,
426 MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
427#if EFSYS_OPT_PHY_LED_CONTROL
428 encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
429 (1 << EFX_PHY_LED_OFF) |
430 (1 << EFX_PHY_LED_ON));
431#endif /* EFSYS_OPT_PHY_LED_CONTROL */
432
433#if EFSYS_OPT_PHY_PROPS
434 encp->enc_phy_nprops = 0;
435#endif /* EFSYS_OPT_PHY_PROPS */
436
437 /* Get the media type of the fixed port, if recognised. */
438 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
439 EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
440 EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
441 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
442 EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
443 EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
444 epp->ep_fixed_port_type =
445 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
446 if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
447 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
448
449 epp->ep_phy_cap_mask =
450 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
451#if EFSYS_OPT_PHY_FLAGS
452 encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
453#endif /* EFSYS_OPT_PHY_FLAGS */
454
455 encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
456
457 /* Populate internal state */
458 encp->enc_siena_channel =
459 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
460
461#if EFSYS_OPT_PHY_STATS
462 encp->enc_siena_phy_stat_mask =
463 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
464
465 /* Convert the MCDI statistic mask into the EFX_PHY_STAT mask */
466 siena_phy_decode_stats(enp, encp->enc_siena_phy_stat_mask,
467 NULL, &encp->enc_phy_stat_mask, NULL);
468#endif /* EFSYS_OPT_PHY_STATS */
469
470#if EFSYS_OPT_PHY_BIST
471 encp->enc_bist_mask = 0;
472 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
473 GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
474 encp->enc_bist_mask |= (1 << EFX_PHY_BIST_TYPE_CABLE_SHORT);
475 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
476 GET_PHY_CFG_OUT_BIST_CABLE_LONG))
477 encp->enc_bist_mask |= (1 << EFX_PHY_BIST_TYPE_CABLE_LONG);
478 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
479 GET_PHY_CFG_OUT_BIST))
480 encp->enc_bist_mask |= (1 << EFX_PHY_BIST_TYPE_NORMAL);
481#endif /* EFSYS_OPT_BIST */
481#endif /* EFSYS_OPT_PHY_BIST */
482
483 return (0);
484
485fail2:
486 EFSYS_PROBE(fail2);
487fail1:
488 EFSYS_PROBE1(fail1, int, rc);
489
490 return (rc);
491}
492
493#if EFSYS_OPT_LOOPBACK
494
495static __checkReturn int
496siena_loopback_cfg(
497 __in efx_nic_t *enp)
498{
499 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
500 efx_mcdi_req_t req;
501 uint8_t outbuf[MC_CMD_GET_LOOPBACK_MODES_OUT_LEN];
502 int rc;
503
504 req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES;
505 EFX_STATIC_ASSERT(MC_CMD_GET_LOOPBACK_MODES_IN_LEN == 0);
506 req.emr_in_buf = NULL;
507 req.emr_in_length = 0;
508 req.emr_out_buf = outbuf;
509 req.emr_out_length = sizeof (outbuf);
510
511 efx_mcdi_execute(enp, &req);
512
513 if (req.emr_rc != 0) {
514 rc = req.emr_rc;
515 goto fail1;
516 }
517
518 if (req.emr_out_length_used < MC_CMD_GET_LOOPBACK_MODES_OUT_LEN) {
519 rc = EMSGSIZE;
520 goto fail2;
521 }
522
523 /*
524 * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree
525 * in siena_phy.c:siena_phy_get_link()
526 */
527 encp->enc_loopback_types[EFX_LINK_100FDX] = EFX_LOOPBACK_MASK &
528 MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_100M) &
529 MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_SUGGESTED);
530 encp->enc_loopback_types[EFX_LINK_1000FDX] = EFX_LOOPBACK_MASK &
531 MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_1G) &
532 MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_SUGGESTED);
533 encp->enc_loopback_types[EFX_LINK_10000FDX] = EFX_LOOPBACK_MASK &
534 MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_10G) &
535 MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_SUGGESTED);
536 encp->enc_loopback_types[EFX_LINK_UNKNOWN] =
537 (1 << EFX_LOOPBACK_OFF) |
538 encp->enc_loopback_types[EFX_LINK_100FDX] |
539 encp->enc_loopback_types[EFX_LINK_1000FDX] |
540 encp->enc_loopback_types[EFX_LINK_10000FDX];
541
542 return (0);
543
544fail2:
545 EFSYS_PROBE(fail2);
546fail1:
547 EFSYS_PROBE1(fail1, int, rc);
548
549 return (rc);
550}
551
552#endif /* EFSYS_OPT_LOOPBACK */
553
554#if EFSYS_OPT_MON_STATS
555
556static __checkReturn int
557siena_monitor_cfg(
558 __in efx_nic_t *enp)
559{
560 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
561 efx_mcdi_req_t req;
562 uint8_t outbuf[MCDI_CTL_SDU_LEN_MAX];
563 int rc;
564
565 req.emr_cmd = MC_CMD_SENSOR_INFO;
566 EFX_STATIC_ASSERT(MC_CMD_SENSOR_INFO_IN_LEN == 0);
567 req.emr_in_buf = NULL;
568 req.emr_in_length = 0;
569 req.emr_out_buf = outbuf;
570 req.emr_out_length = sizeof (outbuf);
571
572 efx_mcdi_execute(enp, &req);
573
574 if (req.emr_rc != 0) {
575 rc = req.emr_rc;
576 goto fail1;
577 }
578
579 if (req.emr_out_length_used < MC_CMD_SENSOR_INFO_OUT_MASK_OFST + 4) {
580 rc = EMSGSIZE;
581 goto fail2;
582 }
583
584 encp->enc_siena_mon_stat_mask =
585 MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK);
586 encp->enc_mon_type = EFX_MON_SFC90X0;
587
588 siena_mon_decode_stats(enp, encp->enc_siena_mon_stat_mask,
589 NULL, &(encp->enc_mon_stat_mask), NULL);
590
591 return (0);
592
593fail2:
594 EFSYS_PROBE(fail2);
595fail1:
596 EFSYS_PROBE1(fail1, int, rc);
597
598 return (rc);
599}
600
601#endif /* EFSYS_OPT_MON_STATS */
602
603 __checkReturn int
604siena_nic_probe(
605 __in efx_nic_t *enp)
606{
607 efx_port_t *epp = &(enp->en_port);
608 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
609 siena_link_state_t sls;
610 unsigned int mask;
611 int rc;
612
613 mask = 0; /* XXX: pacify gcc */
613 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
614
615 /* Read clear any assertion state */
616 if ((rc = siena_nic_read_assertion(enp)) != 0)
617 goto fail1;
618
619 /* Exit the assertion handler */
620 if ((rc = siena_nic_exit_assertion_handler(enp)) != 0)
621 goto fail2;
622
623 /* Wrestle control from the BMC */
624 if ((rc = siena_nic_attach(enp, B_TRUE)) != 0)
625 goto fail3;
626
627 if ((rc = siena_board_cfg(enp)) != 0)
628 goto fail4;
629
630 if ((rc = siena_phy_cfg(enp)) != 0)
631 goto fail5;
632
633 /* Obtain the default PHY advertised capabilities */
634 if ((rc = siena_nic_reset(enp)) != 0)
635 goto fail6;
636 if ((rc = siena_phy_get_link(enp, &sls)) != 0)
637 goto fail7;
638 epp->ep_default_adv_cap_mask = sls.sls_adv_cap_mask;
639 epp->ep_adv_cap_mask = sls.sls_adv_cap_mask;
640
641#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
642 if ((rc = siena_nic_get_partn_mask(enp, &mask)) != 0)
643 goto fail8;
644 enp->en_u.siena.enu_partn_mask = mask;
645#endif
646
647#if EFSYS_OPT_MAC_STATS
648 /* Wipe the MAC statistics */
649 if ((rc = siena_mac_stats_clear(enp)) != 0)
650 goto fail9;
651#endif
652
653#if EFSYS_OPT_LOOPBACK
654 if ((rc = siena_loopback_cfg(enp)) != 0)
655 goto fail10;
656#endif
657
658#if EFSYS_OPT_MON_STATS
659 if ((rc = siena_monitor_cfg(enp)) != 0)
660 goto fail11;
661#endif
662
663 encp->enc_features = enp->en_features;
664
665 return (0);
666
667#if EFSYS_OPT_MON_STATS
668fail11:
669 EFSYS_PROBE(fail11);
670#endif
671#if EFSYS_OPT_LOOPBACK
672fail10:
673 EFSYS_PROBE(fail10);
674#endif
675#if EFSYS_OPT_MAC_STATS
676fail9:
677 EFSYS_PROBE(fail9);
678#endif
679#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
680fail8:
681 EFSYS_PROBE(fail8);
682#endif
683fail7:
684 EFSYS_PROBE(fail7);
685fail6:
686 EFSYS_PROBE(fail6);
687fail5:
688 EFSYS_PROBE(fail5);
689fail4:
690 EFSYS_PROBE(fail4);
691fail3:
692 EFSYS_PROBE(fail3);
693fail2:
694 EFSYS_PROBE(fail2);
695fail1:
696 EFSYS_PROBE1(fail1, int, rc);
697
698 return (rc);
699}
700
701 __checkReturn int
702siena_nic_reset(
703 __in efx_nic_t *enp)
704{
705 efx_mcdi_req_t req;
706 int rc;
707
708 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
709
710 /* siena_nic_reset() is called to recover from BADASSERT failures. */
711 if ((rc = siena_nic_read_assertion(enp)) != 0)
712 goto fail1;
713 if ((rc = siena_nic_exit_assertion_handler(enp)) != 0)
714 goto fail2;
715
716 req.emr_cmd = MC_CMD_PORT_RESET;
717 EFX_STATIC_ASSERT(MC_CMD_PORT_RESET_IN_LEN == 0);
718 req.emr_in_buf = NULL;
719 req.emr_in_length = 0;
720 EFX_STATIC_ASSERT(MC_CMD_PORT_RESET_OUT_LEN == 0);
721 req.emr_out_buf = NULL;
722 req.emr_out_length = 0;
723
724 efx_mcdi_execute(enp, &req);
725
726 if (req.emr_rc != 0) {
727 rc = req.emr_rc;
728 goto fail3;
729 }
730
731 return (0);
732
733fail3:
734 EFSYS_PROBE(fail3);
735fail2:
736 EFSYS_PROBE(fail2);
737fail1:
738 EFSYS_PROBE1(fail1, int, rc);
739
740 return (0);
741}
742
743static __checkReturn int
744siena_nic_logging(
745 __in efx_nic_t *enp)
746{
747 efx_mcdi_req_t req;
748 uint8_t payload[MC_CMD_LOG_CTRL_IN_LEN];
749 int rc;
750
751 req.emr_cmd = MC_CMD_LOG_CTRL;
752 req.emr_in_buf = payload;
753 req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
754 EFX_STATIC_ASSERT(MC_CMD_LOG_CTRL_OUT_LEN == 0);
755 req.emr_out_buf = NULL;
756 req.emr_out_length = 0;
757
758 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
759 MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
760 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
761
762 efx_mcdi_execute(enp, &req);
763
764 if (req.emr_rc != 0) {
765 rc = req.emr_rc;
766 goto fail1;
767 }
768
769 return (0);
770
771fail1:
772 EFSYS_PROBE1(fail1, int, rc);
773
774 return (rc);
775}
776
777static void
778siena_nic_rx_cfg(
779 __in efx_nic_t *enp)
780{
781 efx_oword_t oword;
782
783 /*
784 * RX_INGR_EN is always enabled on Siena, because we rely on
785 * the RX parser to be resiliant to missing SOP/EOP.
786 */
787 EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword);
788 EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_INGR_EN, 1);
789 EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword);
790
791 /* Disable parsing of additional 802.1Q in Q packets */
792 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
793 EFX_SET_OWORD_FIELD(oword, FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES, 0);
794 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
795}
796
797static void
798siena_nic_usrev_dis(
799 __in efx_nic_t *enp)
800{
801 efx_oword_t oword;
802
803 EFX_POPULATE_OWORD_1(oword, FRF_CZ_USREV_DIS, 1);
804 EFX_BAR_WRITEO(enp, FR_CZ_USR_EV_CFG, &oword);
805}
806
807 __checkReturn int
808siena_nic_init(
809 __in efx_nic_t *enp)
810{
811 int rc;
812
813 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
814
815 if ((rc = siena_nic_logging(enp)) != 0)
816 goto fail1;
817
818 siena_sram_init(enp);
819
820 /* Configure Siena's RX block */
821 siena_nic_rx_cfg(enp);
822
823 /* Disable USR_EVents for now */
824 siena_nic_usrev_dis(enp);
825
826 /* bug17057: Ensure set_link is called */
827 if ((rc = siena_phy_reconfigure(enp)) != 0)
828 goto fail2;
829
830 return (0);
831
832fail2:
833 EFSYS_PROBE(fail2);
834fail1:
835 EFSYS_PROBE1(fail1, int, rc);
836
837 return (rc);
838}
839
840 void
841siena_nic_fini(
842 __in efx_nic_t *enp)
843{
844 _NOTE(ARGUNUSED(enp))
845}
846
847 void
848siena_nic_unprobe(
849 __in efx_nic_t *enp)
850{
851 (void) siena_nic_attach(enp, B_FALSE);
852}
853
854#if EFSYS_OPT_DIAG
855
856static efx_register_set_t __cs __siena_registers[] = {
857 { FR_AZ_ADR_REGION_REG_OFST, 0, 1 },
858 { FR_CZ_USR_EV_CFG_OFST, 0, 1 },
859 { FR_AZ_RX_CFG_REG_OFST, 0, 1 },
860 { FR_AZ_TX_CFG_REG_OFST, 0, 1 },
861 { FR_AZ_TX_RESERVED_REG_OFST, 0, 1 },
862 { FR_AZ_SRM_TX_DC_CFG_REG_OFST, 0, 1 },
863 { FR_AZ_RX_DC_CFG_REG_OFST, 0, 1 },
864 { FR_AZ_RX_DC_PF_WM_REG_OFST, 0, 1 },
865 { FR_AZ_DP_CTRL_REG_OFST, 0, 1 },
866 { FR_BZ_RX_RSS_TKEY_REG_OFST, 0, 1},
867 { FR_CZ_RX_RSS_IPV6_REG1_OFST, 0, 1},
868 { FR_CZ_RX_RSS_IPV6_REG2_OFST, 0, 1},
869 { FR_CZ_RX_RSS_IPV6_REG3_OFST, 0, 1}
870};
871
872static const uint32_t __cs __siena_register_masks[] = {
873 0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF,
874 0x000103FF, 0x00000000, 0x00000000, 0x00000000,
875 0xFFFFFFFE, 0xFFFFFFFF, 0x0003FFFF, 0x00000000,
876 0x7FFF0037, 0xFFFF8000, 0xFFFFFFFF, 0x03FFFFFF,
877 0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF,
878 0x001FFFFF, 0x00000000, 0x00000000, 0x00000000,
879 0x00000003, 0x00000000, 0x00000000, 0x00000000,
880 0x000003FF, 0x00000000, 0x00000000, 0x00000000,
881 0x00000FFF, 0x00000000, 0x00000000, 0x00000000,
882 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
883 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
884 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
885 0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000
886};
887
888static efx_register_set_t __cs __siena_tables[] = {
889 { FR_AZ_RX_FILTER_TBL0_OFST, FR_AZ_RX_FILTER_TBL0_STEP,
890 FR_AZ_RX_FILTER_TBL0_ROWS },
891 { FR_CZ_RX_MAC_FILTER_TBL0_OFST, FR_CZ_RX_MAC_FILTER_TBL0_STEP,
892 FR_CZ_RX_MAC_FILTER_TBL0_ROWS },
893 { FR_AZ_RX_DESC_PTR_TBL_OFST,
894 FR_AZ_RX_DESC_PTR_TBL_STEP, FR_CZ_RX_DESC_PTR_TBL_ROWS },
895 { FR_AZ_TX_DESC_PTR_TBL_OFST,
896 FR_AZ_TX_DESC_PTR_TBL_STEP, FR_CZ_TX_DESC_PTR_TBL_ROWS },
897 { FR_AZ_TIMER_TBL_OFST, FR_AZ_TIMER_TBL_STEP, FR_CZ_TIMER_TBL_ROWS },
898 { FR_CZ_TX_FILTER_TBL0_OFST,
899 FR_CZ_TX_FILTER_TBL0_STEP, FR_CZ_TX_FILTER_TBL0_ROWS },
900 { FR_CZ_TX_MAC_FILTER_TBL0_OFST,
901 FR_CZ_TX_MAC_FILTER_TBL0_STEP, FR_CZ_TX_MAC_FILTER_TBL0_ROWS }
902};
903
904static const uint32_t __cs __siena_table_masks[] = {
905 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000003FF,
906 0xFFFF0FFF, 0xFFFFFFFF, 0x00000E7F, 0x00000000,
907 0xFFFFFFFE, 0x0FFFFFFF, 0x01800000, 0x00000000,
908 0xFFFFFFFE, 0x0FFFFFFF, 0x0C000000, 0x00000000,
909 0x3FFFFFFF, 0x00000000, 0x00000000, 0x00000000,
910 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000013FF,
911 0xFFFF07FF, 0xFFFFFFFF, 0x0000007F, 0x00000000,
912};
913
914 __checkReturn int
915siena_nic_register_test(
916 __in efx_nic_t *enp)
917{
918 efx_register_set_t *rsp;
919 const uint32_t *dwordp;
920 unsigned int nitems;
921 unsigned int count;
922 int rc;
923
924 /* Fill out the register mask entries */
925 EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_register_masks)
926 == EFX_ARRAY_SIZE(__siena_registers) * 4);
927
928 nitems = EFX_ARRAY_SIZE(__siena_registers);
929 dwordp = __siena_register_masks;
930 for (count = 0; count < nitems; ++count) {
931 rsp = __siena_registers + count;
932 rsp->mask.eo_u32[0] = *dwordp++;
933 rsp->mask.eo_u32[1] = *dwordp++;
934 rsp->mask.eo_u32[2] = *dwordp++;
935 rsp->mask.eo_u32[3] = *dwordp++;
936 }
937
938 /* Fill out the register table entries */
939 EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_table_masks)
940 == EFX_ARRAY_SIZE(__siena_tables) * 4);
941
942 nitems = EFX_ARRAY_SIZE(__siena_tables);
943 dwordp = __siena_table_masks;
944 for (count = 0; count < nitems; ++count) {
945 rsp = __siena_tables + count;
946 rsp->mask.eo_u32[0] = *dwordp++;
947 rsp->mask.eo_u32[1] = *dwordp++;
948 rsp->mask.eo_u32[2] = *dwordp++;
949 rsp->mask.eo_u32[3] = *dwordp++;
950 }
951
952 if ((rc = efx_nic_test_registers(enp, __siena_registers,
953 EFX_ARRAY_SIZE(__siena_registers))) != 0)
954 goto fail1;
955
956 if ((rc = efx_nic_test_tables(enp, __siena_tables,
957 EFX_PATTERN_BYTE_ALTERNATE,
958 EFX_ARRAY_SIZE(__siena_tables))) != 0)
959 goto fail2;
960
961 if ((rc = efx_nic_test_tables(enp, __siena_tables,
962 EFX_PATTERN_BYTE_CHANGING,
963 EFX_ARRAY_SIZE(__siena_tables))) != 0)
964 goto fail3;
965
966 if ((rc = efx_nic_test_tables(enp, __siena_tables,
967 EFX_PATTERN_BIT_SWEEP, EFX_ARRAY_SIZE(__siena_tables))) != 0)
968 goto fail4;
969
970 return (0);
971
972fail4:
973 EFSYS_PROBE(fail4);
974fail3:
975 EFSYS_PROBE(fail3);
976fail2:
977 EFSYS_PROBE(fail2);
978fail1:
979 EFSYS_PROBE1(fail1, int, rc);
980
981 return (rc);
982}
983
984#endif /* EFSYS_OPT_DIAG */
985
986#endif /* EFSYS_OPT_SIENA */