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