siena_nic.c revision 279048
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 279048 2015-02-20 07:57:59Z 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 * 16) - (encp->enc_rxq_limit * 64);
369
370	return (0);
371
372fail4:
373	EFSYS_PROBE(fail4);
374fail3:
375	EFSYS_PROBE(fail3);
376fail2:
377	EFSYS_PROBE(fail2);
378fail1:
379	EFSYS_PROBE1(fail1, int, rc);
380
381	return (rc);
382}
383
384static	__checkReturn	int
385siena_phy_cfg(
386	__in		efx_nic_t *enp)
387{
388	efx_port_t *epp = &(enp->en_port);
389	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
390	efx_mcdi_req_t req;
391	uint8_t outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN];
392	int rc;
393
394	req.emr_cmd = MC_CMD_GET_PHY_CFG;
395	EFX_STATIC_ASSERT(MC_CMD_GET_PHY_CFG_IN_LEN == 0);
396	req.emr_in_buf = NULL;
397	req.emr_in_length = 0;
398	req.emr_out_buf = outbuf;
399	req.emr_out_length = sizeof (outbuf);
400
401	efx_mcdi_execute(enp, &req);
402
403	if (req.emr_rc != 0) {
404		rc = req.emr_rc;
405		goto fail1;
406	}
407
408	if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
409		rc = EMSGSIZE;
410		goto fail2;
411	}
412
413	encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
414#if EFSYS_OPT_NAMES
415	(void) strncpy(encp->enc_phy_name,
416		MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
417		MIN(sizeof (encp->enc_phy_name) - 1,
418		    MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
419#endif	/* EFSYS_OPT_NAMES */
420	(void) memset(encp->enc_phy_revision, 0,
421	    sizeof (encp->enc_phy_revision));
422	memcpy(encp->enc_phy_revision,
423		MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
424		MIN(sizeof (encp->enc_phy_revision) - 1,
425		    MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
426#if EFSYS_OPT_PHY_LED_CONTROL
427	encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
428			    (1 << EFX_PHY_LED_OFF) |
429			    (1 << EFX_PHY_LED_ON));
430#endif	/* EFSYS_OPT_PHY_LED_CONTROL */
431
432#if EFSYS_OPT_PHY_PROPS
433	encp->enc_phy_nprops  = 0;
434#endif	/* EFSYS_OPT_PHY_PROPS */
435
436	/* Get the media type of the fixed port, if recognised. */
437	EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
438	EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
439	EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
440	EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
441	EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
442	EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
443	epp->ep_fixed_port_type =
444		MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
445	if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
446		epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
447
448	epp->ep_phy_cap_mask =
449		MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
450#if EFSYS_OPT_PHY_FLAGS
451	encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
452#endif	/* EFSYS_OPT_PHY_FLAGS */
453
454	encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
455
456	/* Populate internal state */
457	encp->enc_siena_channel =
458		(uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
459
460#if EFSYS_OPT_PHY_STATS
461	encp->enc_siena_phy_stat_mask =
462		MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
463
464	/* Convert the MCDI statistic mask into the EFX_PHY_STAT mask */
465	siena_phy_decode_stats(enp, encp->enc_siena_phy_stat_mask,
466			    NULL, &encp->enc_phy_stat_mask, NULL);
467#endif	/* EFSYS_OPT_PHY_STATS */
468
469#if EFSYS_OPT_PHY_BIST
470	encp->enc_bist_mask = 0;
471	if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
472	    GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
473		encp->enc_bist_mask |= (1 << EFX_PHY_BIST_TYPE_CABLE_SHORT);
474	if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
475	    GET_PHY_CFG_OUT_BIST_CABLE_LONG))
476		encp->enc_bist_mask |= (1 << EFX_PHY_BIST_TYPE_CABLE_LONG);
477	if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
478	    GET_PHY_CFG_OUT_BIST))
479		encp->enc_bist_mask |= (1 << EFX_PHY_BIST_TYPE_NORMAL);
480#endif	/* EFSYS_OPT_BIST */
481
482	return (0);
483
484fail2:
485	EFSYS_PROBE(fail2);
486fail1:
487	EFSYS_PROBE1(fail1, int, rc);
488
489	return (rc);
490}
491
492#if EFSYS_OPT_LOOPBACK
493
494static	__checkReturn	int
495siena_loopback_cfg(
496	__in		efx_nic_t *enp)
497{
498	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
499	efx_mcdi_req_t req;
500	uint8_t outbuf[MC_CMD_GET_LOOPBACK_MODES_OUT_LEN];
501	int rc;
502
503	req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES;
504	EFX_STATIC_ASSERT(MC_CMD_GET_LOOPBACK_MODES_IN_LEN == 0);
505	req.emr_in_buf = NULL;
506	req.emr_in_length = 0;
507	req.emr_out_buf = outbuf;
508	req.emr_out_length = sizeof (outbuf);
509
510	efx_mcdi_execute(enp, &req);
511
512	if (req.emr_rc != 0) {
513		rc = req.emr_rc;
514		goto fail1;
515	}
516
517	if (req.emr_out_length_used < MC_CMD_GET_LOOPBACK_MODES_OUT_LEN) {
518		rc = EMSGSIZE;
519		goto fail2;
520	}
521
522	/*
523	 * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree
524	 * in siena_phy.c:siena_phy_get_link()
525	 */
526	encp->enc_loopback_types[EFX_LINK_100FDX] = EFX_LOOPBACK_MASK &
527	    MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_100M) &
528	    MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_SUGGESTED);
529	encp->enc_loopback_types[EFX_LINK_1000FDX] = EFX_LOOPBACK_MASK &
530	    MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_1G) &
531	    MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_SUGGESTED);
532	encp->enc_loopback_types[EFX_LINK_10000FDX] = EFX_LOOPBACK_MASK &
533	    MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_10G) &
534	    MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_SUGGESTED);
535	encp->enc_loopback_types[EFX_LINK_UNKNOWN] =
536	    (1 << EFX_LOOPBACK_OFF) |
537	    encp->enc_loopback_types[EFX_LINK_100FDX] |
538	    encp->enc_loopback_types[EFX_LINK_1000FDX] |
539	    encp->enc_loopback_types[EFX_LINK_10000FDX];
540
541	return (0);
542
543fail2:
544	EFSYS_PROBE(fail2);
545fail1:
546	EFSYS_PROBE1(fail1, int, rc);
547
548	return (rc);
549}
550
551#endif	/* EFSYS_OPT_LOOPBACK */
552
553#if EFSYS_OPT_MON_STATS
554
555static	__checkReturn	int
556siena_monitor_cfg(
557	__in		efx_nic_t *enp)
558{
559	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
560	efx_mcdi_req_t req;
561	uint8_t outbuf[MCDI_CTL_SDU_LEN_MAX];
562	int rc;
563
564	req.emr_cmd = MC_CMD_SENSOR_INFO;
565	EFX_STATIC_ASSERT(MC_CMD_SENSOR_INFO_IN_LEN == 0);
566	req.emr_in_buf = NULL;
567	req.emr_in_length = 0;
568	req.emr_out_buf = outbuf;
569	req.emr_out_length = sizeof (outbuf);
570
571	efx_mcdi_execute(enp, &req);
572
573	if (req.emr_rc != 0) {
574		rc = req.emr_rc;
575		goto fail1;
576	}
577
578	if (req.emr_out_length_used < MC_CMD_SENSOR_INFO_OUT_MASK_OFST + 4) {
579		rc = EMSGSIZE;
580		goto fail2;
581	}
582
583	encp->enc_siena_mon_stat_mask =
584		MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK);
585	encp->enc_mon_type = EFX_MON_SFC90X0;
586
587	siena_mon_decode_stats(enp, encp->enc_siena_mon_stat_mask,
588			    NULL, &(encp->enc_mon_stat_mask), NULL);
589
590	return (0);
591
592fail2:
593	EFSYS_PROBE(fail2);
594fail1:
595	EFSYS_PROBE1(fail1, int, rc);
596
597	return (rc);
598}
599
600#endif	/* EFSYS_OPT_MON_STATS */
601
602	__checkReturn	int
603siena_nic_probe(
604	__in		efx_nic_t *enp)
605{
606	efx_port_t *epp = &(enp->en_port);
607	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
608	siena_link_state_t sls;
609	unsigned int mask;
610	int rc;
611
612	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	0xFFFFFFFF, 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 */
987