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