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