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	/* External port identifier using one-based port numbering */
98	encp->enc_external_port = (uint8_t)enp->en_mcdi.em_emip.emi_port;
99
100	/* Board configuration */
101	if ((rc = efx_mcdi_get_board_cfg(enp, &board_type,
102		    &capabilities, mac_addr)) != 0)
103		goto fail1;
104
105	EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr);
106
107	encp->enc_board_type = board_type;
108
109	/*
110	 * There is no possibility to determine the number of PFs on Siena
111	 * by issuing MCDI request, and it is not an easy task to find the
112	 * value based on the board type, so 'enc_hw_pf_count' is set to 1
113	 */
114	encp->enc_hw_pf_count = 1;
115
116	/* Additional capabilities */
117	encp->enc_clk_mult = 1;
118	if (EFX_DWORD_FIELD(capabilities, MC_CMD_CAPABILITIES_TURBO)) {
119		enp->en_features |= EFX_FEATURE_TURBO;
120
121		if (EFX_DWORD_FIELD(capabilities,
122			MC_CMD_CAPABILITIES_TURBO_ACTIVE)) {
123			encp->enc_clk_mult = 2;
124		}
125	}
126
127	encp->enc_evq_timer_quantum_ns =
128		EFX_EVQ_SIENA_TIMER_QUANTUM_NS / encp->enc_clk_mult;
129	encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
130		FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;
131
132	/* When hash header insertion is enabled, Siena inserts 16 bytes */
133	encp->enc_rx_prefix_size = 16;
134
135	/* Alignment for receive packet DMA buffers */
136	encp->enc_rx_buf_align_start = 1;
137	encp->enc_rx_buf_align_end = 1;
138
139	/* Alignment for WPTR updates */
140	encp->enc_rx_push_align = 1;
141
142	encp->enc_tx_dma_desc_size_max = EFX_MASK32(FSF_AZ_TX_KER_BYTE_COUNT);
143	/* Fragments must not span 4k boundaries. */
144	encp->enc_tx_dma_desc_boundary = 4096;
145
146	/* Resource limits */
147	rc = efx_mcdi_get_resource_limits(enp, &nevq, &nrxq, &ntxq);
148	if (rc != 0) {
149		if (rc != ENOTSUP)
150			goto fail2;
151
152		nevq = 1024;
153		nrxq = EFX_RXQ_LIMIT_TARGET;
154		ntxq = EFX_TXQ_LIMIT_TARGET;
155	}
156	encp->enc_evq_limit = nevq;
157	encp->enc_rxq_limit = MIN(EFX_RXQ_LIMIT_TARGET, nrxq);
158	encp->enc_txq_limit = MIN(EFX_TXQ_LIMIT_TARGET, ntxq);
159
160	encp->enc_txq_max_ndescs = 4096;
161
162	encp->enc_buftbl_limit = SIENA_SRAM_ROWS -
163	    (encp->enc_txq_limit * EFX_TXQ_DC_NDESCS(EFX_TXQ_DC_SIZE)) -
164	    (encp->enc_rxq_limit * EFX_RXQ_DC_NDESCS(EFX_RXQ_DC_SIZE));
165
166	encp->enc_hw_tx_insert_vlan_enabled = B_FALSE;
167	encp->enc_fw_assisted_tso_enabled = B_FALSE;
168	encp->enc_fw_assisted_tso_v2_enabled = B_FALSE;
169	encp->enc_fw_assisted_tso_v2_n_contexts = 0;
170	encp->enc_allow_set_mac_with_installed_filters = B_TRUE;
171
172	/* Siena supports two 10G ports, and 8 lanes of PCIe Gen2 */
173	encp->enc_required_pcie_bandwidth_mbps = 2 * 10000;
174	encp->enc_max_pcie_link_gen = EFX_PCIE_LINK_SPEED_GEN2;
175
176	encp->enc_fw_verified_nvram_update_required = B_FALSE;
177
178	return (0);
179
180fail2:
181	EFSYS_PROBE(fail2);
182fail1:
183	EFSYS_PROBE1(fail1, efx_rc_t, rc);
184
185	return (rc);
186}
187
188static	__checkReturn	efx_rc_t
189siena_phy_cfg(
190	__in		efx_nic_t *enp)
191{
192#if EFSYS_OPT_PHY_STATS
193	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
194#endif	/* EFSYS_OPT_PHY_STATS */
195	efx_rc_t rc;
196
197	/* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */
198	if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0)
199		goto fail1;
200
201#if EFSYS_OPT_PHY_STATS
202	/* Convert the MCDI statistic mask into the EFX_PHY_STAT mask */
203	siena_phy_decode_stats(enp, encp->enc_mcdi_phy_stat_mask,
204			    NULL, &encp->enc_phy_stat_mask, NULL);
205#endif	/* EFSYS_OPT_PHY_STATS */
206
207	return (0);
208
209fail1:
210	EFSYS_PROBE1(fail1, efx_rc_t, rc);
211
212	return (rc);
213}
214
215#define	SIENA_BIU_MAGIC0	0x01234567
216#define	SIENA_BIU_MAGIC1	0xfedcba98
217
218static	__checkReturn	efx_rc_t
219siena_nic_biu_test(
220	__in		efx_nic_t *enp)
221{
222	efx_oword_t oword;
223	efx_rc_t rc;
224
225	/*
226	 * Write magic values to scratch registers 0 and 1, then
227	 * verify that the values were written correctly.  Interleave
228	 * the accesses to ensure that the BIU is not just reading
229	 * back the cached value that was last written.
230	 */
231	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, SIENA_BIU_MAGIC0);
232	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
233
234	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, SIENA_BIU_MAGIC1);
235	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
236
237	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
238	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != SIENA_BIU_MAGIC0) {
239		rc = EIO;
240		goto fail1;
241	}
242
243	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
244	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != SIENA_BIU_MAGIC1) {
245		rc = EIO;
246		goto fail2;
247	}
248
249	/*
250	 * Perform the same test, with the values swapped.  This
251	 * ensures that subsequent tests don't start with the correct
252	 * values already written into the scratch registers.
253	 */
254	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, SIENA_BIU_MAGIC1);
255	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
256
257	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, SIENA_BIU_MAGIC0);
258	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
259
260	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
261	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != SIENA_BIU_MAGIC1) {
262		rc = EIO;
263		goto fail3;
264	}
265
266	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
267	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != SIENA_BIU_MAGIC0) {
268		rc = EIO;
269		goto fail4;
270	}
271
272	return (0);
273
274fail4:
275	EFSYS_PROBE(fail4);
276fail3:
277	EFSYS_PROBE(fail3);
278fail2:
279	EFSYS_PROBE(fail2);
280fail1:
281	EFSYS_PROBE1(fail1, efx_rc_t, rc);
282
283	return (rc);
284}
285
286	__checkReturn	efx_rc_t
287siena_nic_probe(
288	__in		efx_nic_t *enp)
289{
290	efx_port_t *epp = &(enp->en_port);
291	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
292	siena_link_state_t sls;
293	unsigned int mask;
294	efx_oword_t oword;
295	efx_rc_t rc;
296
297	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
298
299	/* Test BIU */
300	if ((rc = siena_nic_biu_test(enp)) != 0)
301		goto fail1;
302
303	/* Clear the region register */
304	EFX_POPULATE_OWORD_4(oword,
305	    FRF_AZ_ADR_REGION0, 0,
306	    FRF_AZ_ADR_REGION1, (1 << 16),
307	    FRF_AZ_ADR_REGION2, (2 << 16),
308	    FRF_AZ_ADR_REGION3, (3 << 16));
309	EFX_BAR_WRITEO(enp, FR_AZ_ADR_REGION_REG, &oword);
310
311	/* Read clear any assertion state */
312	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
313		goto fail2;
314
315	/* Exit the assertion handler */
316	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
317		goto fail3;
318
319	/* Wrestle control from the BMC */
320	if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
321		goto fail4;
322
323	if ((rc = siena_board_cfg(enp)) != 0)
324		goto fail5;
325
326	if ((rc = siena_phy_cfg(enp)) != 0)
327		goto fail6;
328
329	/* Obtain the default PHY advertised capabilities */
330	if ((rc = siena_nic_reset(enp)) != 0)
331		goto fail7;
332	if ((rc = siena_phy_get_link(enp, &sls)) != 0)
333		goto fail8;
334	epp->ep_default_adv_cap_mask = sls.sls_adv_cap_mask;
335	epp->ep_adv_cap_mask = sls.sls_adv_cap_mask;
336
337#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
338	if ((rc = siena_nic_get_partn_mask(enp, &mask)) != 0)
339		goto fail9;
340	enp->en_u.siena.enu_partn_mask = mask;
341#endif
342
343#if EFSYS_OPT_MAC_STATS
344	/* Wipe the MAC statistics */
345	if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
346		goto fail10;
347#endif
348
349#if EFSYS_OPT_LOOPBACK
350	if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
351		goto fail11;
352#endif
353
354#if EFSYS_OPT_MON_STATS
355	if ((rc = mcdi_mon_cfg_build(enp)) != 0)
356		goto fail12;
357#endif
358
359	encp->enc_features = enp->en_features;
360
361	return (0);
362
363#if EFSYS_OPT_MON_STATS
364fail12:
365	EFSYS_PROBE(fail12);
366#endif
367#if EFSYS_OPT_LOOPBACK
368fail11:
369	EFSYS_PROBE(fail11);
370#endif
371#if EFSYS_OPT_MAC_STATS
372fail10:
373	EFSYS_PROBE(fail10);
374#endif
375#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
376fail9:
377	EFSYS_PROBE(fail9);
378#endif
379fail8:
380	EFSYS_PROBE(fail8);
381fail7:
382	EFSYS_PROBE(fail7);
383fail6:
384	EFSYS_PROBE(fail6);
385fail5:
386	EFSYS_PROBE(fail5);
387fail4:
388	EFSYS_PROBE(fail4);
389fail3:
390	EFSYS_PROBE(fail3);
391fail2:
392	EFSYS_PROBE(fail2);
393fail1:
394	EFSYS_PROBE1(fail1, efx_rc_t, rc);
395
396	return (rc);
397}
398
399	__checkReturn	efx_rc_t
400siena_nic_reset(
401	__in		efx_nic_t *enp)
402{
403	efx_mcdi_req_t req;
404	efx_rc_t rc;
405
406	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
407
408	/* siena_nic_reset() is called to recover from BADASSERT failures. */
409	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
410		goto fail1;
411	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
412		goto fail2;
413
414	/*
415	 * Bug24908: ENTITY_RESET_IN_LEN is non zero but zero may be supplied
416	 * for backwards compatibility with PORT_RESET_IN_LEN.
417	 */
418	EFX_STATIC_ASSERT(MC_CMD_ENTITY_RESET_OUT_LEN == 0);
419
420	req.emr_cmd = MC_CMD_ENTITY_RESET;
421	req.emr_in_buf = NULL;
422	req.emr_in_length = 0;
423	req.emr_out_buf = NULL;
424	req.emr_out_length = 0;
425
426	efx_mcdi_execute(enp, &req);
427
428	if (req.emr_rc != 0) {
429		rc = req.emr_rc;
430		goto fail3;
431	}
432
433	return (0);
434
435fail3:
436	EFSYS_PROBE(fail3);
437fail2:
438	EFSYS_PROBE(fail2);
439fail1:
440	EFSYS_PROBE1(fail1, efx_rc_t, rc);
441
442	return (0);
443}
444
445static			void
446siena_nic_rx_cfg(
447	__in		efx_nic_t *enp)
448{
449	efx_oword_t oword;
450
451	/*
452	 * RX_INGR_EN is always enabled on Siena, because we rely on
453	 * the RX parser to be resiliant to missing SOP/EOP.
454	 */
455	EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword);
456	EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_INGR_EN, 1);
457	EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword);
458
459	/* Disable parsing of additional 802.1Q in Q packets */
460	EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
461	EFX_SET_OWORD_FIELD(oword, FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES, 0);
462	EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
463}
464
465static			void
466siena_nic_usrev_dis(
467	__in		efx_nic_t *enp)
468{
469	efx_oword_t	oword;
470
471	EFX_POPULATE_OWORD_1(oword, FRF_CZ_USREV_DIS, 1);
472	EFX_BAR_WRITEO(enp, FR_CZ_USR_EV_CFG, &oword);
473}
474
475	__checkReturn	efx_rc_t
476siena_nic_init(
477	__in		efx_nic_t *enp)
478{
479	efx_rc_t rc;
480
481	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
482
483	/* Enable reporting of some events (e.g. link change) */
484	if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
485		goto fail1;
486
487	siena_sram_init(enp);
488
489	/* Configure Siena's RX block */
490	siena_nic_rx_cfg(enp);
491
492	/* Disable USR_EVents for now */
493	siena_nic_usrev_dis(enp);
494
495	/* bug17057: Ensure set_link is called */
496	if ((rc = siena_phy_reconfigure(enp)) != 0)
497		goto fail2;
498
499	enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V1;
500
501	return (0);
502
503fail2:
504	EFSYS_PROBE(fail2);
505fail1:
506	EFSYS_PROBE1(fail1, efx_rc_t, rc);
507
508	return (rc);
509}
510
511			void
512siena_nic_fini(
513	__in		efx_nic_t *enp)
514{
515	_NOTE(ARGUNUSED(enp))
516}
517
518			void
519siena_nic_unprobe(
520	__in		efx_nic_t *enp)
521{
522#if EFSYS_OPT_MON_STATS
523	mcdi_mon_cfg_free(enp);
524#endif /* EFSYS_OPT_MON_STATS */
525	(void) efx_mcdi_drv_attach(enp, B_FALSE);
526}
527
528#if EFSYS_OPT_DIAG
529
530static siena_register_set_t __siena_registers[] = {
531	{ FR_AZ_ADR_REGION_REG_OFST, 0, 1 },
532	{ FR_CZ_USR_EV_CFG_OFST, 0, 1 },
533	{ FR_AZ_RX_CFG_REG_OFST, 0, 1 },
534	{ FR_AZ_TX_CFG_REG_OFST, 0, 1 },
535	{ FR_AZ_TX_RESERVED_REG_OFST, 0, 1 },
536	{ FR_AZ_SRM_TX_DC_CFG_REG_OFST, 0, 1 },
537	{ FR_AZ_RX_DC_CFG_REG_OFST, 0, 1 },
538	{ FR_AZ_RX_DC_PF_WM_REG_OFST, 0, 1 },
539	{ FR_AZ_DP_CTRL_REG_OFST, 0, 1 },
540	{ FR_BZ_RX_RSS_TKEY_REG_OFST, 0, 1},
541	{ FR_CZ_RX_RSS_IPV6_REG1_OFST, 0, 1},
542	{ FR_CZ_RX_RSS_IPV6_REG2_OFST, 0, 1},
543	{ FR_CZ_RX_RSS_IPV6_REG3_OFST, 0, 1}
544};
545
546static const uint32_t __siena_register_masks[] = {
547	0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF,
548	0x000103FF, 0x00000000, 0x00000000, 0x00000000,
549	0xFFFFFFFE, 0xFFFFFFFF, 0x0003FFFF, 0x00000000,
550	0x7FFF0037, 0xFFFF8000, 0xFFFFFFFF, 0x03FFFFFF,
551	0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF,
552	0x001FFFFF, 0x00000000, 0x00000000, 0x00000000,
553	0x00000003, 0x00000000, 0x00000000, 0x00000000,
554	0x000003FF, 0x00000000, 0x00000000, 0x00000000,
555	0x00000FFF, 0x00000000, 0x00000000, 0x00000000,
556	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
557	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
558	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
559	0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000
560};
561
562static siena_register_set_t __siena_tables[] = {
563	{ FR_AZ_RX_FILTER_TBL0_OFST, FR_AZ_RX_FILTER_TBL0_STEP,
564	    FR_AZ_RX_FILTER_TBL0_ROWS },
565	{ FR_CZ_RX_MAC_FILTER_TBL0_OFST, FR_CZ_RX_MAC_FILTER_TBL0_STEP,
566	    FR_CZ_RX_MAC_FILTER_TBL0_ROWS },
567	{ FR_AZ_RX_DESC_PTR_TBL_OFST,
568	    FR_AZ_RX_DESC_PTR_TBL_STEP, FR_CZ_RX_DESC_PTR_TBL_ROWS },
569	{ FR_AZ_TX_DESC_PTR_TBL_OFST,
570	    FR_AZ_TX_DESC_PTR_TBL_STEP, FR_CZ_TX_DESC_PTR_TBL_ROWS },
571	{ FR_AZ_TIMER_TBL_OFST, FR_AZ_TIMER_TBL_STEP, FR_CZ_TIMER_TBL_ROWS },
572	{ FR_CZ_TX_FILTER_TBL0_OFST,
573	    FR_CZ_TX_FILTER_TBL0_STEP, FR_CZ_TX_FILTER_TBL0_ROWS },
574	{ FR_CZ_TX_MAC_FILTER_TBL0_OFST,
575	    FR_CZ_TX_MAC_FILTER_TBL0_STEP, FR_CZ_TX_MAC_FILTER_TBL0_ROWS }
576};
577
578static const uint32_t __siena_table_masks[] = {
579	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000003FF,
580	0xFFFF0FFF, 0xFFFFFFFF, 0x00000E7F, 0x00000000,
581	0xFFFFFFFE, 0x0FFFFFFF, 0x01800000, 0x00000000,
582	0xFFFFFFFE, 0x0FFFFFFF, 0x0C000000, 0x00000000,
583	0x3FFFFFFF, 0x00000000, 0x00000000, 0x00000000,
584	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000013FF,
585	0xFFFF07FF, 0xFFFFFFFF, 0x0000007F, 0x00000000,
586};
587
588	__checkReturn	efx_rc_t
589siena_nic_test_registers(
590	__in		efx_nic_t *enp,
591	__in		siena_register_set_t *rsp,
592	__in		size_t count)
593{
594	unsigned int bit;
595	efx_oword_t original;
596	efx_oword_t reg;
597	efx_oword_t buf;
598	efx_rc_t rc;
599
600	while (count > 0) {
601		/* This function is only suitable for registers */
602		EFSYS_ASSERT(rsp->rows == 1);
603
604		/* bit sweep on and off */
605		EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original,
606			    B_TRUE);
607		for (bit = 0; bit < 128; bit++) {
608			/* Is this bit in the mask? */
609			if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit))
610				continue;
611
612			/* Test this bit can be set in isolation */
613			reg = original;
614			EFX_AND_OWORD(reg, rsp->mask);
615			EFX_SET_OWORD_BIT(reg, bit);
616
617			EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
618				    B_TRUE);
619			EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
620				    B_TRUE);
621
622			EFX_AND_OWORD(buf, rsp->mask);
623			if (memcmp(&reg, &buf, sizeof (reg))) {
624				rc = EIO;
625				goto fail1;
626			}
627
628			/* Test this bit can be cleared in isolation */
629			EFX_OR_OWORD(reg, rsp->mask);
630			EFX_CLEAR_OWORD_BIT(reg, bit);
631
632			EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
633				    B_TRUE);
634			EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
635				    B_TRUE);
636
637			EFX_AND_OWORD(buf, rsp->mask);
638			if (memcmp(&reg, &buf, sizeof (reg))) {
639				rc = EIO;
640				goto fail2;
641			}
642		}
643
644		/* Restore the old value */
645		EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original,
646			    B_TRUE);
647
648		--count;
649		++rsp;
650	}
651
652	return (0);
653
654fail2:
655	EFSYS_PROBE(fail2);
656fail1:
657	EFSYS_PROBE1(fail1, efx_rc_t, rc);
658
659	/* Restore the old value */
660	EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE);
661
662	return (rc);
663}
664
665	__checkReturn	efx_rc_t
666siena_nic_test_tables(
667	__in		efx_nic_t *enp,
668	__in		siena_register_set_t *rsp,
669	__in		efx_pattern_type_t pattern,
670	__in		size_t count)
671{
672	efx_sram_pattern_fn_t func;
673	unsigned int index;
674	unsigned int address;
675	efx_oword_t reg;
676	efx_oword_t buf;
677	efx_rc_t rc;
678
679	EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES);
680	func = __efx_sram_pattern_fns[pattern];
681
682	while (count > 0) {
683		/* Write */
684		address = rsp->address;
685		for (index = 0; index < rsp->rows; ++index) {
686			func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
687			func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
688			EFX_AND_OWORD(reg, rsp->mask);
689			EFSYS_BAR_WRITEO(enp->en_esbp, address, &reg, B_TRUE);
690
691			address += rsp->step;
692		}
693
694		/* Read */
695		address = rsp->address;
696		for (index = 0; index < rsp->rows; ++index) {
697			func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
698			func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
699			EFX_AND_OWORD(reg, rsp->mask);
700			EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE);
701			if (memcmp(&reg, &buf, sizeof (reg))) {
702				rc = EIO;
703				goto fail1;
704			}
705
706			address += rsp->step;
707		}
708
709		++rsp;
710		--count;
711	}
712
713	return (0);
714
715fail1:
716	EFSYS_PROBE1(fail1, efx_rc_t, rc);
717
718	return (rc);
719}
720
721
722	__checkReturn	efx_rc_t
723siena_nic_register_test(
724	__in		efx_nic_t *enp)
725{
726	siena_register_set_t *rsp;
727	const uint32_t *dwordp;
728	unsigned int nitems;
729	unsigned int count;
730	efx_rc_t rc;
731
732	/* Fill out the register mask entries */
733	EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_register_masks)
734		    == EFX_ARRAY_SIZE(__siena_registers) * 4);
735
736	nitems = EFX_ARRAY_SIZE(__siena_registers);
737	dwordp = __siena_register_masks;
738	for (count = 0; count < nitems; ++count) {
739		rsp = __siena_registers + count;
740		rsp->mask.eo_u32[0] = *dwordp++;
741		rsp->mask.eo_u32[1] = *dwordp++;
742		rsp->mask.eo_u32[2] = *dwordp++;
743		rsp->mask.eo_u32[3] = *dwordp++;
744	}
745
746	/* Fill out the register table entries */
747	EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_table_masks)
748		    == EFX_ARRAY_SIZE(__siena_tables) * 4);
749
750	nitems = EFX_ARRAY_SIZE(__siena_tables);
751	dwordp = __siena_table_masks;
752	for (count = 0; count < nitems; ++count) {
753		rsp = __siena_tables + count;
754		rsp->mask.eo_u32[0] = *dwordp++;
755		rsp->mask.eo_u32[1] = *dwordp++;
756		rsp->mask.eo_u32[2] = *dwordp++;
757		rsp->mask.eo_u32[3] = *dwordp++;
758	}
759
760	if ((rc = siena_nic_test_registers(enp, __siena_registers,
761	    EFX_ARRAY_SIZE(__siena_registers))) != 0)
762		goto fail1;
763
764	if ((rc = siena_nic_test_tables(enp, __siena_tables,
765	    EFX_PATTERN_BYTE_ALTERNATE,
766	    EFX_ARRAY_SIZE(__siena_tables))) != 0)
767		goto fail2;
768
769	if ((rc = siena_nic_test_tables(enp, __siena_tables,
770	    EFX_PATTERN_BYTE_CHANGING,
771	    EFX_ARRAY_SIZE(__siena_tables))) != 0)
772		goto fail3;
773
774	if ((rc = siena_nic_test_tables(enp, __siena_tables,
775	    EFX_PATTERN_BIT_SWEEP, EFX_ARRAY_SIZE(__siena_tables))) != 0)
776		goto fail4;
777
778	return (0);
779
780fail4:
781	EFSYS_PROBE(fail4);
782fail3:
783	EFSYS_PROBE(fail3);
784fail2:
785	EFSYS_PROBE(fail2);
786fail1:
787	EFSYS_PROBE1(fail1, efx_rc_t, rc);
788
789	return (rc);
790}
791
792#endif	/* EFSYS_OPT_DIAG */
793
794#endif	/* EFSYS_OPT_SIENA */
795