1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2009-2016 Solarflare Communications Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 *    this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 *    this list of conditions and the following disclaimer in the documentation
14 *    and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * The views and conclusions contained in the software and documentation are
29 * those of the authors and should not be interpreted as representing official
30 * policies, either expressed or implied, of the FreeBSD Project.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD$");
35
36#include "efx.h"
37#include "efx_impl.h"
38#include "mcdi_mon.h"
39
40#if EFSYS_OPT_SIENA
41
42#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
43
44static	__checkReturn		efx_rc_t
45siena_nic_get_partn_mask(
46	__in			efx_nic_t *enp,
47	__out			unsigned int *maskp)
48{
49	efx_mcdi_req_t req;
50	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_TYPES_IN_LEN,
51		MC_CMD_NVRAM_TYPES_OUT_LEN);
52	efx_rc_t rc;
53
54	req.emr_cmd = MC_CMD_NVRAM_TYPES;
55	req.emr_in_buf = payload;
56	req.emr_in_length = MC_CMD_NVRAM_TYPES_IN_LEN;
57	req.emr_out_buf = payload;
58	req.emr_out_length = MC_CMD_NVRAM_TYPES_OUT_LEN;
59
60	efx_mcdi_execute(enp, &req);
61
62	if (req.emr_rc != 0) {
63		rc = req.emr_rc;
64		goto fail1;
65	}
66
67	if (req.emr_out_length_used < MC_CMD_NVRAM_TYPES_OUT_LEN) {
68		rc = EMSGSIZE;
69		goto fail2;
70	}
71
72	*maskp = MCDI_OUT_DWORD(req, NVRAM_TYPES_OUT_TYPES);
73
74	return (0);
75
76fail2:
77	EFSYS_PROBE(fail2);
78fail1:
79	EFSYS_PROBE1(fail1, efx_rc_t, rc);
80
81	return (rc);
82}
83
84#endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
85
86static	__checkReturn	efx_rc_t
87siena_board_cfg(
88	__in		efx_nic_t *enp)
89{
90	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
91	uint8_t mac_addr[6];
92	efx_dword_t capabilities;
93	uint32_t board_type;
94	uint32_t nevq, nrxq, ntxq;
95	efx_rc_t rc;
96
97	/* Siena has a fixed 8Kbyte VI window size */
98	EFX_STATIC_ASSERT(1U << EFX_VI_WINDOW_SHIFT_8K	== 8192);
99	encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_8K;
100
101	/* External port identifier using one-based port numbering */
102	encp->enc_external_port = (uint8_t)enp->en_mcdi.em_emip.emi_port;
103
104	/* Board configuration */
105	if ((rc = efx_mcdi_get_board_cfg(enp, &board_type,
106		    &capabilities, mac_addr)) != 0)
107		goto fail1;
108
109	EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr);
110
111	encp->enc_board_type = board_type;
112
113	/*
114	 * There is no possibility to determine the number of PFs on Siena
115	 * by issuing MCDI request, and it is not an easy task to find the
116	 * value based on the board type, so 'enc_hw_pf_count' is set to 1
117	 */
118	encp->enc_hw_pf_count = 1;
119
120	/* Additional capabilities */
121	encp->enc_clk_mult = 1;
122	if (EFX_DWORD_FIELD(capabilities, MC_CMD_CAPABILITIES_TURBO)) {
123		enp->en_features |= EFX_FEATURE_TURBO;
124
125		if (EFX_DWORD_FIELD(capabilities,
126			MC_CMD_CAPABILITIES_TURBO_ACTIVE)) {
127			encp->enc_clk_mult = 2;
128		}
129	}
130
131	encp->enc_evq_timer_quantum_ns =
132		EFX_EVQ_SIENA_TIMER_QUANTUM_NS / encp->enc_clk_mult;
133	encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
134		FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;
135
136	/* When hash header insertion is enabled, Siena inserts 16 bytes */
137	encp->enc_rx_prefix_size = 16;
138
139	/* Alignment for receive packet DMA buffers */
140	encp->enc_rx_buf_align_start = 1;
141	encp->enc_rx_buf_align_end = 1;
142
143	/* Alignment for WPTR updates */
144	encp->enc_rx_push_align = 1;
145
146#if EFSYS_OPT_RX_SCALE
147	/* There is one RSS context per function */
148	encp->enc_rx_scale_max_exclusive_contexts = 1;
149
150	encp->enc_rx_scale_hash_alg_mask |= (1U << EFX_RX_HASHALG_LFSR);
151	encp->enc_rx_scale_hash_alg_mask |= (1U << EFX_RX_HASHALG_TOEPLITZ);
152
153	/*
154	 * It is always possible to use port numbers
155	 * as the input data for hash computation.
156	 */
157	encp->enc_rx_scale_l4_hash_supported = B_TRUE;
158
159	/* There is no support for additional RSS modes */
160	encp->enc_rx_scale_additional_modes_supported = B_FALSE;
161#endif /* EFSYS_OPT_RX_SCALE */
162
163	encp->enc_tx_dma_desc_size_max = EFX_MASK32(FSF_AZ_TX_KER_BYTE_COUNT);
164	/* Fragments must not span 4k boundaries. */
165	encp->enc_tx_dma_desc_boundary = 4096;
166
167	/* Resource limits */
168	rc = efx_mcdi_get_resource_limits(enp, &nevq, &nrxq, &ntxq);
169	if (rc != 0) {
170		if (rc != ENOTSUP)
171			goto fail2;
172
173		nevq = 1024;
174		nrxq = EFX_RXQ_LIMIT_TARGET;
175		ntxq = EFX_TXQ_LIMIT_TARGET;
176	}
177	encp->enc_evq_limit = nevq;
178	encp->enc_rxq_limit = MIN(EFX_RXQ_LIMIT_TARGET, nrxq);
179	encp->enc_txq_limit = MIN(EFX_TXQ_LIMIT_TARGET, ntxq);
180
181	encp->enc_txq_max_ndescs = 4096;
182
183	encp->enc_buftbl_limit = SIENA_SRAM_ROWS -
184	    (encp->enc_txq_limit * EFX_TXQ_DC_NDESCS(EFX_TXQ_DC_SIZE)) -
185	    (encp->enc_rxq_limit * EFX_RXQ_DC_NDESCS(EFX_RXQ_DC_SIZE));
186
187	encp->enc_hw_tx_insert_vlan_enabled = B_FALSE;
188	encp->enc_fw_assisted_tso_enabled = B_FALSE;
189	encp->enc_fw_assisted_tso_v2_enabled = B_FALSE;
190	encp->enc_fw_assisted_tso_v2_n_contexts = 0;
191	encp->enc_allow_set_mac_with_installed_filters = B_TRUE;
192	encp->enc_rx_packed_stream_supported = B_FALSE;
193	encp->enc_rx_var_packed_stream_supported = B_FALSE;
194	encp->enc_rx_es_super_buffer_supported = B_FALSE;
195	encp->enc_fw_subvariant_no_tx_csum_supported = B_FALSE;
196
197	/* Siena supports two 10G ports, and 8 lanes of PCIe Gen2 */
198	encp->enc_required_pcie_bandwidth_mbps = 2 * 10000;
199	encp->enc_max_pcie_link_gen = EFX_PCIE_LINK_SPEED_GEN2;
200
201	encp->enc_nvram_update_verify_result_supported = B_FALSE;
202
203	encp->enc_mac_stats_nstats = MC_CMD_MAC_NSTATS;
204
205	encp->enc_filter_action_flag_supported = B_FALSE;
206	encp->enc_filter_action_mark_supported = B_FALSE;
207	encp->enc_filter_action_mark_max = 0;
208
209	return (0);
210
211fail2:
212	EFSYS_PROBE(fail2);
213fail1:
214	EFSYS_PROBE1(fail1, efx_rc_t, rc);
215
216	return (rc);
217}
218
219static	__checkReturn	efx_rc_t
220siena_phy_cfg(
221	__in		efx_nic_t *enp)
222{
223#if EFSYS_OPT_PHY_STATS
224	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
225#endif	/* EFSYS_OPT_PHY_STATS */
226	efx_rc_t rc;
227
228	/* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */
229	if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0)
230		goto fail1;
231
232#if EFSYS_OPT_PHY_STATS
233	/* Convert the MCDI statistic mask into the EFX_PHY_STAT mask */
234	siena_phy_decode_stats(enp, encp->enc_mcdi_phy_stat_mask,
235			    NULL, &encp->enc_phy_stat_mask, NULL);
236#endif	/* EFSYS_OPT_PHY_STATS */
237
238	return (0);
239
240fail1:
241	EFSYS_PROBE1(fail1, efx_rc_t, rc);
242
243	return (rc);
244}
245
246#define	SIENA_BIU_MAGIC0	0x01234567
247#define	SIENA_BIU_MAGIC1	0xfedcba98
248
249static	__checkReturn	efx_rc_t
250siena_nic_biu_test(
251	__in		efx_nic_t *enp)
252{
253	efx_oword_t oword;
254	efx_rc_t rc;
255
256	/*
257	 * Write magic values to scratch registers 0 and 1, then
258	 * verify that the values were written correctly.  Interleave
259	 * the accesses to ensure that the BIU is not just reading
260	 * back the cached value that was last written.
261	 */
262	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, SIENA_BIU_MAGIC0);
263	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
264
265	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, SIENA_BIU_MAGIC1);
266	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
267
268	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
269	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != SIENA_BIU_MAGIC0) {
270		rc = EIO;
271		goto fail1;
272	}
273
274	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
275	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != SIENA_BIU_MAGIC1) {
276		rc = EIO;
277		goto fail2;
278	}
279
280	/*
281	 * Perform the same test, with the values swapped.  This
282	 * ensures that subsequent tests don't start with the correct
283	 * values already written into the scratch registers.
284	 */
285	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, SIENA_BIU_MAGIC1);
286	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
287
288	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, SIENA_BIU_MAGIC0);
289	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
290
291	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
292	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != SIENA_BIU_MAGIC1) {
293		rc = EIO;
294		goto fail3;
295	}
296
297	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
298	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != SIENA_BIU_MAGIC0) {
299		rc = EIO;
300		goto fail4;
301	}
302
303	return (0);
304
305fail4:
306	EFSYS_PROBE(fail4);
307fail3:
308	EFSYS_PROBE(fail3);
309fail2:
310	EFSYS_PROBE(fail2);
311fail1:
312	EFSYS_PROBE1(fail1, efx_rc_t, rc);
313
314	return (rc);
315}
316
317	__checkReturn	efx_rc_t
318siena_nic_probe(
319	__in		efx_nic_t *enp)
320{
321	efx_port_t *epp = &(enp->en_port);
322	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
323	siena_link_state_t sls;
324	unsigned int mask;
325	efx_oword_t oword;
326	efx_rc_t rc;
327
328	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
329
330	/* Test BIU */
331	if ((rc = siena_nic_biu_test(enp)) != 0)
332		goto fail1;
333
334	/* Clear the region register */
335	EFX_POPULATE_OWORD_4(oword,
336	    FRF_AZ_ADR_REGION0, 0,
337	    FRF_AZ_ADR_REGION1, (1 << 16),
338	    FRF_AZ_ADR_REGION2, (2 << 16),
339	    FRF_AZ_ADR_REGION3, (3 << 16));
340	EFX_BAR_WRITEO(enp, FR_AZ_ADR_REGION_REG, &oword);
341
342	/* Read clear any assertion state */
343	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
344		goto fail2;
345
346	/* Exit the assertion handler */
347	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
348		goto fail3;
349
350	/* Wrestle control from the BMC */
351	if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
352		goto fail4;
353
354	if ((rc = siena_board_cfg(enp)) != 0)
355		goto fail5;
356
357	if ((rc = siena_phy_cfg(enp)) != 0)
358		goto fail6;
359
360	/* Obtain the default PHY advertised capabilities */
361	if ((rc = siena_nic_reset(enp)) != 0)
362		goto fail7;
363	if ((rc = siena_phy_get_link(enp, &sls)) != 0)
364		goto fail8;
365	epp->ep_default_adv_cap_mask = sls.sls_adv_cap_mask;
366	epp->ep_adv_cap_mask = sls.sls_adv_cap_mask;
367
368#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
369	if ((rc = siena_nic_get_partn_mask(enp, &mask)) != 0)
370		goto fail9;
371	enp->en_u.siena.enu_partn_mask = mask;
372#endif
373
374#if EFSYS_OPT_MAC_STATS
375	/* Wipe the MAC statistics */
376	if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
377		goto fail10;
378#endif
379
380#if EFSYS_OPT_LOOPBACK
381	if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
382		goto fail11;
383#endif
384
385#if EFSYS_OPT_MON_STATS
386	if ((rc = mcdi_mon_cfg_build(enp)) != 0)
387		goto fail12;
388#endif
389
390	encp->enc_features = enp->en_features;
391
392	return (0);
393
394#if EFSYS_OPT_MON_STATS
395fail12:
396	EFSYS_PROBE(fail12);
397#endif
398#if EFSYS_OPT_LOOPBACK
399fail11:
400	EFSYS_PROBE(fail11);
401#endif
402#if EFSYS_OPT_MAC_STATS
403fail10:
404	EFSYS_PROBE(fail10);
405#endif
406#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
407fail9:
408	EFSYS_PROBE(fail9);
409#endif
410fail8:
411	EFSYS_PROBE(fail8);
412fail7:
413	EFSYS_PROBE(fail7);
414fail6:
415	EFSYS_PROBE(fail6);
416fail5:
417	EFSYS_PROBE(fail5);
418fail4:
419	EFSYS_PROBE(fail4);
420fail3:
421	EFSYS_PROBE(fail3);
422fail2:
423	EFSYS_PROBE(fail2);
424fail1:
425	EFSYS_PROBE1(fail1, efx_rc_t, rc);
426
427	return (rc);
428}
429
430	__checkReturn	efx_rc_t
431siena_nic_reset(
432	__in		efx_nic_t *enp)
433{
434	efx_mcdi_req_t req;
435	efx_rc_t rc;
436
437	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
438
439	/* siena_nic_reset() is called to recover from BADASSERT failures. */
440	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
441		goto fail1;
442	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
443		goto fail2;
444
445	/*
446	 * Bug24908: ENTITY_RESET_IN_LEN is non zero but zero may be supplied
447	 * for backwards compatibility with PORT_RESET_IN_LEN.
448	 */
449	EFX_STATIC_ASSERT(MC_CMD_ENTITY_RESET_OUT_LEN == 0);
450
451	req.emr_cmd = MC_CMD_ENTITY_RESET;
452	req.emr_in_buf = NULL;
453	req.emr_in_length = 0;
454	req.emr_out_buf = NULL;
455	req.emr_out_length = 0;
456
457	efx_mcdi_execute(enp, &req);
458
459	if (req.emr_rc != 0) {
460		rc = req.emr_rc;
461		goto fail3;
462	}
463
464	return (0);
465
466fail3:
467	EFSYS_PROBE(fail3);
468fail2:
469	EFSYS_PROBE(fail2);
470fail1:
471	EFSYS_PROBE1(fail1, efx_rc_t, rc);
472
473	return (0);
474}
475
476static			void
477siena_nic_rx_cfg(
478	__in		efx_nic_t *enp)
479{
480	efx_oword_t oword;
481
482	/*
483	 * RX_INGR_EN is always enabled on Siena, because we rely on
484	 * the RX parser to be resiliant to missing SOP/EOP.
485	 */
486	EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword);
487	EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_INGR_EN, 1);
488	EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword);
489
490	/* Disable parsing of additional 802.1Q in Q packets */
491	EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
492	EFX_SET_OWORD_FIELD(oword, FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES, 0);
493	EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
494}
495
496static			void
497siena_nic_usrev_dis(
498	__in		efx_nic_t *enp)
499{
500	efx_oword_t	oword;
501
502	EFX_POPULATE_OWORD_1(oword, FRF_CZ_USREV_DIS, 1);
503	EFX_BAR_WRITEO(enp, FR_CZ_USR_EV_CFG, &oword);
504}
505
506	__checkReturn	efx_rc_t
507siena_nic_init(
508	__in		efx_nic_t *enp)
509{
510	efx_rc_t rc;
511
512	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
513
514	/* Enable reporting of some events (e.g. link change) */
515	if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
516		goto fail1;
517
518	siena_sram_init(enp);
519
520	/* Configure Siena's RX block */
521	siena_nic_rx_cfg(enp);
522
523	/* Disable USR_EVents for now */
524	siena_nic_usrev_dis(enp);
525
526	/* bug17057: Ensure set_link is called */
527	if ((rc = siena_phy_reconfigure(enp)) != 0)
528		goto fail2;
529
530	enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V1;
531
532	return (0);
533
534fail2:
535	EFSYS_PROBE(fail2);
536fail1:
537	EFSYS_PROBE1(fail1, efx_rc_t, rc);
538
539	return (rc);
540}
541
542			void
543siena_nic_fini(
544	__in		efx_nic_t *enp)
545{
546	_NOTE(ARGUNUSED(enp))
547}
548
549			void
550siena_nic_unprobe(
551	__in		efx_nic_t *enp)
552{
553#if EFSYS_OPT_MON_STATS
554	mcdi_mon_cfg_free(enp);
555#endif /* EFSYS_OPT_MON_STATS */
556	(void) efx_mcdi_drv_attach(enp, B_FALSE);
557}
558
559#if EFSYS_OPT_DIAG
560
561static siena_register_set_t __siena_registers[] = {
562	{ FR_AZ_ADR_REGION_REG_OFST, 0, 1 },
563	{ FR_CZ_USR_EV_CFG_OFST, 0, 1 },
564	{ FR_AZ_RX_CFG_REG_OFST, 0, 1 },
565	{ FR_AZ_TX_CFG_REG_OFST, 0, 1 },
566	{ FR_AZ_TX_RESERVED_REG_OFST, 0, 1 },
567	{ FR_AZ_SRM_TX_DC_CFG_REG_OFST, 0, 1 },
568	{ FR_AZ_RX_DC_CFG_REG_OFST, 0, 1 },
569	{ FR_AZ_RX_DC_PF_WM_REG_OFST, 0, 1 },
570	{ FR_AZ_DP_CTRL_REG_OFST, 0, 1 },
571	{ FR_BZ_RX_RSS_TKEY_REG_OFST, 0, 1},
572	{ FR_CZ_RX_RSS_IPV6_REG1_OFST, 0, 1},
573	{ FR_CZ_RX_RSS_IPV6_REG2_OFST, 0, 1},
574	{ FR_CZ_RX_RSS_IPV6_REG3_OFST, 0, 1}
575};
576
577static const uint32_t __siena_register_masks[] = {
578	0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF,
579	0x000103FF, 0x00000000, 0x00000000, 0x00000000,
580	0xFFFFFFFE, 0xFFFFFFFF, 0x0003FFFF, 0x00000000,
581	0x7FFF0037, 0xFFFF8000, 0xFFFFFFFF, 0x03FFFFFF,
582	0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF,
583	0x001FFFFF, 0x00000000, 0x00000000, 0x00000000,
584	0x00000003, 0x00000000, 0x00000000, 0x00000000,
585	0x000003FF, 0x00000000, 0x00000000, 0x00000000,
586	0x00000FFF, 0x00000000, 0x00000000, 0x00000000,
587	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
588	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
589	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
590	0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000
591};
592
593static siena_register_set_t __siena_tables[] = {
594	{ FR_AZ_RX_FILTER_TBL0_OFST, FR_AZ_RX_FILTER_TBL0_STEP,
595	    FR_AZ_RX_FILTER_TBL0_ROWS },
596	{ FR_CZ_RX_MAC_FILTER_TBL0_OFST, FR_CZ_RX_MAC_FILTER_TBL0_STEP,
597	    FR_CZ_RX_MAC_FILTER_TBL0_ROWS },
598	{ FR_AZ_RX_DESC_PTR_TBL_OFST,
599	    FR_AZ_RX_DESC_PTR_TBL_STEP, FR_CZ_RX_DESC_PTR_TBL_ROWS },
600	{ FR_AZ_TX_DESC_PTR_TBL_OFST,
601	    FR_AZ_TX_DESC_PTR_TBL_STEP, FR_CZ_TX_DESC_PTR_TBL_ROWS },
602	{ FR_AZ_TIMER_TBL_OFST, FR_AZ_TIMER_TBL_STEP, FR_CZ_TIMER_TBL_ROWS },
603	{ FR_CZ_TX_FILTER_TBL0_OFST,
604	    FR_CZ_TX_FILTER_TBL0_STEP, FR_CZ_TX_FILTER_TBL0_ROWS },
605	{ FR_CZ_TX_MAC_FILTER_TBL0_OFST,
606	    FR_CZ_TX_MAC_FILTER_TBL0_STEP, FR_CZ_TX_MAC_FILTER_TBL0_ROWS }
607};
608
609static const uint32_t __siena_table_masks[] = {
610	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000003FF,
611	0xFFFF0FFF, 0xFFFFFFFF, 0x00000E7F, 0x00000000,
612	0xFFFFFFFE, 0x0FFFFFFF, 0x01800000, 0x00000000,
613	0xFFFFFFFE, 0x0FFFFFFF, 0x0C000000, 0x00000000,
614	0x3FFFFFFF, 0x00000000, 0x00000000, 0x00000000,
615	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000013FF,
616	0xFFFF07FF, 0xFFFFFFFF, 0x0000007F, 0x00000000,
617};
618
619	__checkReturn	efx_rc_t
620siena_nic_test_registers(
621	__in		efx_nic_t *enp,
622	__in		siena_register_set_t *rsp,
623	__in		size_t count)
624{
625	unsigned int bit;
626	efx_oword_t original;
627	efx_oword_t reg;
628	efx_oword_t buf;
629	efx_rc_t rc;
630
631	while (count > 0) {
632		/* This function is only suitable for registers */
633		EFSYS_ASSERT(rsp->rows == 1);
634
635		/* bit sweep on and off */
636		EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original,
637			    B_TRUE);
638		for (bit = 0; bit < 128; bit++) {
639			/* Is this bit in the mask? */
640			if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit))
641				continue;
642
643			/* Test this bit can be set in isolation */
644			reg = original;
645			EFX_AND_OWORD(reg, rsp->mask);
646			EFX_SET_OWORD_BIT(reg, bit);
647
648			EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
649				    B_TRUE);
650			EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
651				    B_TRUE);
652
653			EFX_AND_OWORD(buf, rsp->mask);
654			if (memcmp(&reg, &buf, sizeof (reg))) {
655				rc = EIO;
656				goto fail1;
657			}
658
659			/* Test this bit can be cleared in isolation */
660			EFX_OR_OWORD(reg, rsp->mask);
661			EFX_CLEAR_OWORD_BIT(reg, bit);
662
663			EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
664				    B_TRUE);
665			EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
666				    B_TRUE);
667
668			EFX_AND_OWORD(buf, rsp->mask);
669			if (memcmp(&reg, &buf, sizeof (reg))) {
670				rc = EIO;
671				goto fail2;
672			}
673		}
674
675		/* Restore the old value */
676		EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original,
677			    B_TRUE);
678
679		--count;
680		++rsp;
681	}
682
683	return (0);
684
685fail2:
686	EFSYS_PROBE(fail2);
687fail1:
688	EFSYS_PROBE1(fail1, efx_rc_t, rc);
689
690	/* Restore the old value */
691	EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE);
692
693	return (rc);
694}
695
696	__checkReturn	efx_rc_t
697siena_nic_test_tables(
698	__in		efx_nic_t *enp,
699	__in		siena_register_set_t *rsp,
700	__in		efx_pattern_type_t pattern,
701	__in		size_t count)
702{
703	efx_sram_pattern_fn_t func;
704	unsigned int index;
705	unsigned int address;
706	efx_oword_t reg;
707	efx_oword_t buf;
708	efx_rc_t rc;
709
710	EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES);
711	func = __efx_sram_pattern_fns[pattern];
712
713	while (count > 0) {
714		/* Write */
715		address = rsp->address;
716		for (index = 0; index < rsp->rows; ++index) {
717			func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
718			func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
719			EFX_AND_OWORD(reg, rsp->mask);
720			EFSYS_BAR_WRITEO(enp->en_esbp, address, &reg, B_TRUE);
721
722			address += rsp->step;
723		}
724
725		/* Read */
726		address = rsp->address;
727		for (index = 0; index < rsp->rows; ++index) {
728			func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
729			func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
730			EFX_AND_OWORD(reg, rsp->mask);
731			EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE);
732			if (memcmp(&reg, &buf, sizeof (reg))) {
733				rc = EIO;
734				goto fail1;
735			}
736
737			address += rsp->step;
738		}
739
740		++rsp;
741		--count;
742	}
743
744	return (0);
745
746fail1:
747	EFSYS_PROBE1(fail1, efx_rc_t, rc);
748
749	return (rc);
750}
751
752	__checkReturn	efx_rc_t
753siena_nic_register_test(
754	__in		efx_nic_t *enp)
755{
756	siena_register_set_t *rsp;
757	const uint32_t *dwordp;
758	unsigned int nitems;
759	unsigned int count;
760	efx_rc_t rc;
761
762	/* Fill out the register mask entries */
763	EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_register_masks)
764		    == EFX_ARRAY_SIZE(__siena_registers) * 4);
765
766	nitems = EFX_ARRAY_SIZE(__siena_registers);
767	dwordp = __siena_register_masks;
768	for (count = 0; count < nitems; ++count) {
769		rsp = __siena_registers + count;
770		rsp->mask.eo_u32[0] = *dwordp++;
771		rsp->mask.eo_u32[1] = *dwordp++;
772		rsp->mask.eo_u32[2] = *dwordp++;
773		rsp->mask.eo_u32[3] = *dwordp++;
774	}
775
776	/* Fill out the register table entries */
777	EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_table_masks)
778		    == EFX_ARRAY_SIZE(__siena_tables) * 4);
779
780	nitems = EFX_ARRAY_SIZE(__siena_tables);
781	dwordp = __siena_table_masks;
782	for (count = 0; count < nitems; ++count) {
783		rsp = __siena_tables + count;
784		rsp->mask.eo_u32[0] = *dwordp++;
785		rsp->mask.eo_u32[1] = *dwordp++;
786		rsp->mask.eo_u32[2] = *dwordp++;
787		rsp->mask.eo_u32[3] = *dwordp++;
788	}
789
790	if ((rc = siena_nic_test_registers(enp, __siena_registers,
791	    EFX_ARRAY_SIZE(__siena_registers))) != 0)
792		goto fail1;
793
794	if ((rc = siena_nic_test_tables(enp, __siena_tables,
795	    EFX_PATTERN_BYTE_ALTERNATE,
796	    EFX_ARRAY_SIZE(__siena_tables))) != 0)
797		goto fail2;
798
799	if ((rc = siena_nic_test_tables(enp, __siena_tables,
800	    EFX_PATTERN_BYTE_CHANGING,
801	    EFX_ARRAY_SIZE(__siena_tables))) != 0)
802		goto fail3;
803
804	if ((rc = siena_nic_test_tables(enp, __siena_tables,
805	    EFX_PATTERN_BIT_SWEEP, EFX_ARRAY_SIZE(__siena_tables))) != 0)
806		goto fail4;
807
808	return (0);
809
810fail4:
811	EFSYS_PROBE(fail4);
812fail3:
813	EFSYS_PROBE(fail3);
814fail2:
815	EFSYS_PROBE(fail2);
816fail1:
817	EFSYS_PROBE1(fail1, efx_rc_t, rc);
818
819	return (rc);
820}
821
822#endif	/* EFSYS_OPT_DIAG */
823
824#endif	/* EFSYS_OPT_SIENA */
825