1227569Sphilip/*-
2301388Sarybchik * Copyright (c) 2007-2016 Solarflare Communications Inc.
3284555Sarybchik * All rights reserved.
4227569Sphilip *
5227569Sphilip * Redistribution and use in source and binary forms, with or without
6284555Sarybchik * modification, are permitted provided that the following conditions are met:
7227569Sphilip *
8284555Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9284555Sarybchik *    this list of conditions and the following disclaimer.
10284555Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11284555Sarybchik *    this list of conditions and the following disclaimer in the documentation
12284555Sarybchik *    and/or other materials provided with the distribution.
13284555Sarybchik *
14284555Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15284555Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16284555Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17284555Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18284555Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19284555Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20284555Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21284555Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22284555Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23284555Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24284555Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25284555Sarybchik *
26284555Sarybchik * The views and conclusions contained in the software and documentation are
27284555Sarybchik * those of the authors and should not be interpreted as representing official
28284555Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29227569Sphilip */
30227569Sphilip
31228078Sphilip#include <sys/cdefs.h>
32228078Sphilip__FBSDID("$FreeBSD$");
33228078Sphilip
34227569Sphilip#include "efx.h"
35227569Sphilip#include "efx_impl.h"
36227569Sphilip
37293927Sarybchik	__checkReturn	efx_rc_t
38227569Sphilipefx_sram_buf_tbl_set(
39227569Sphilip	__in		efx_nic_t *enp,
40227569Sphilip	__in		uint32_t id,
41227569Sphilip	__in		efsys_mem_t *esmp,
42227569Sphilip	__in		size_t n)
43227569Sphilip{
44227569Sphilip	efx_qword_t qword;
45227569Sphilip	uint32_t start = id;
46227569Sphilip	uint32_t stop = start + n;
47227569Sphilip	efsys_dma_addr_t addr;
48227569Sphilip	efx_oword_t oword;
49227569Sphilip	unsigned int count;
50293927Sarybchik	efx_rc_t rc;
51227569Sphilip
52227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
53227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
54227569Sphilip
55293984Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
56293984Sarybchik	if (enp->en_family == EFX_FAMILY_HUNTINGTON ||
57293984Sarybchik	    enp->en_family == EFX_FAMILY_MEDFORD) {
58284555Sarybchik		/*
59284555Sarybchik		 * FIXME: the efx_sram_buf_tbl_*() functionality needs to be
60284555Sarybchik		 * pulled inside the Falcon/Siena queue create/destroy code,
61284555Sarybchik		 * and then the original functions can be removed (see bug30834
62284555Sarybchik		 * comment #1).  But, for now, we just ensure that they are
63293984Sarybchik		 * no-ops for EF10, to allow bringing up existing drivers
64284555Sarybchik		 * without modification.
65284555Sarybchik		 */
66284555Sarybchik
67284555Sarybchik		return (0);
68284555Sarybchik	}
69293984Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
70284555Sarybchik
71227569Sphilip	if (stop >= EFX_BUF_TBL_SIZE) {
72227569Sphilip		rc = EFBIG;
73227569Sphilip		goto fail1;
74227569Sphilip	}
75227569Sphilip
76227569Sphilip	/* Add the entries into the buffer table */
77227569Sphilip	addr = EFSYS_MEM_ADDR(esmp);
78227569Sphilip	for (id = start; id != stop; id++) {
79227569Sphilip		EFX_POPULATE_QWORD_5(qword,
80227569Sphilip		    FRF_AZ_IP_DAT_BUF_SIZE, 0, FRF_AZ_BUF_ADR_REGION, 0,
81227569Sphilip		    FRF_AZ_BUF_ADR_FBUF_DW0,
82227569Sphilip		    (uint32_t)((addr >> 12) & 0xffffffff),
83227569Sphilip		    FRF_AZ_BUF_ADR_FBUF_DW1,
84227569Sphilip		    (uint32_t)((addr >> 12) >> 32),
85227569Sphilip		    FRF_AZ_BUF_OWNER_ID_FBUF, 0);
86227569Sphilip
87227569Sphilip		EFX_BAR_TBL_WRITEQ(enp, FR_AZ_BUF_FULL_TBL,
88227569Sphilip				    id, &qword);
89227569Sphilip
90227569Sphilip		addr += EFX_BUF_SIZE;
91227569Sphilip	}
92227569Sphilip
93227569Sphilip	EFSYS_PROBE2(buf, uint32_t, start, uint32_t, stop - 1);
94227569Sphilip
95227569Sphilip	/* Flush the write buffer */
96227569Sphilip	EFX_POPULATE_OWORD_2(oword, FRF_AZ_BUF_UPD_CMD, 1,
97227569Sphilip	    FRF_AZ_BUF_CLR_CMD, 0);
98227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_UPD_REG, &oword);
99227569Sphilip
100227569Sphilip	/* Poll for the last entry being written to the buffer table */
101227569Sphilip	EFSYS_ASSERT3U(id, ==, stop);
102227569Sphilip	addr -= EFX_BUF_SIZE;
103227569Sphilip
104227569Sphilip	count = 0;
105227569Sphilip	do {
106227569Sphilip		EFSYS_PROBE1(wait, unsigned int, count);
107227569Sphilip
108227569Sphilip		/* Spin for 1 ms */
109227569Sphilip		EFSYS_SPIN(1000);
110227569Sphilip
111227569Sphilip		EFX_BAR_TBL_READQ(enp, FR_AZ_BUF_FULL_TBL,
112227569Sphilip				    id - 1, &qword);
113227569Sphilip
114227569Sphilip		if (EFX_QWORD_FIELD(qword, FRF_AZ_BUF_ADR_FBUF_DW0) ==
115227569Sphilip		    (uint32_t)((addr >> 12) & 0xffffffff) &&
116227569Sphilip		    EFX_QWORD_FIELD(qword, FRF_AZ_BUF_ADR_FBUF_DW1) ==
117227569Sphilip		    (uint32_t)((addr >> 12) >> 32))
118227569Sphilip			goto verify;
119227569Sphilip
120227569Sphilip	} while (++count < 100);
121227569Sphilip
122227569Sphilip	rc = ETIMEDOUT;
123227569Sphilip	goto fail2;
124227569Sphilip
125227569Sphilipverify:
126227569Sphilip	/* Verify the rest of the entries in the buffer table */
127227569Sphilip	while (--id != start) {
128227569Sphilip		addr -= EFX_BUF_SIZE;
129227569Sphilip
130227569Sphilip		/* Read the buffer table entry */
131227569Sphilip		EFX_BAR_TBL_READQ(enp, FR_AZ_BUF_FULL_TBL,
132227569Sphilip				    id - 1, &qword);
133227569Sphilip
134227569Sphilip		if (EFX_QWORD_FIELD(qword, FRF_AZ_BUF_ADR_FBUF_DW0) !=
135227569Sphilip		    (uint32_t)((addr >> 12) & 0xffffffff) ||
136227569Sphilip		    EFX_QWORD_FIELD(qword, FRF_AZ_BUF_ADR_FBUF_DW1) !=
137227569Sphilip		    (uint32_t)((addr >> 12) >> 32)) {
138227569Sphilip			rc = EFAULT;
139227569Sphilip			goto fail3;
140227569Sphilip		}
141227569Sphilip	}
142227569Sphilip
143227569Sphilip	return (0);
144227569Sphilip
145227569Sphilipfail3:
146227569Sphilip	EFSYS_PROBE(fail3);
147227569Sphilip
148227569Sphilip	id = stop;
149227569Sphilip
150227569Sphilipfail2:
151227569Sphilip	EFSYS_PROBE(fail2);
152227569Sphilip
153227569Sphilip	EFX_POPULATE_OWORD_4(oword, FRF_AZ_BUF_UPD_CMD, 0,
154227569Sphilip	    FRF_AZ_BUF_CLR_CMD, 1, FRF_AZ_BUF_CLR_END_ID, id - 1,
155227569Sphilip	    FRF_AZ_BUF_CLR_START_ID, start);
156227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_UPD_REG, &oword);
157227569Sphilip
158227569Sphilipfail1:
159293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
160227569Sphilip
161227569Sphilip	return (rc);
162227569Sphilip}
163227569Sphilip
164227569Sphilip		void
165227569Sphilipefx_sram_buf_tbl_clear(
166227569Sphilip	__in	efx_nic_t *enp,
167227569Sphilip	__in	uint32_t id,
168227569Sphilip	__in	size_t n)
169227569Sphilip{
170227569Sphilip	efx_oword_t oword;
171227569Sphilip	uint32_t start = id;
172227569Sphilip	uint32_t stop = start + n;
173227569Sphilip
174227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
175227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
176227569Sphilip
177293984Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
178293984Sarybchik	if (enp->en_family == EFX_FAMILY_HUNTINGTON ||
179293984Sarybchik	    enp->en_family == EFX_FAMILY_MEDFORD) {
180284555Sarybchik		/*
181284555Sarybchik		 * FIXME: the efx_sram_buf_tbl_*() functionality needs to be
182284555Sarybchik		 * pulled inside the Falcon/Siena queue create/destroy code,
183284555Sarybchik		 * and then the original functions can be removed (see bug30834
184284555Sarybchik		 * comment #1).  But, for now, we just ensure that they are
185293984Sarybchik		 * no-ops for EF10, to allow bringing up existing drivers
186284555Sarybchik		 * without modification.
187284555Sarybchik		 */
188284555Sarybchik
189284555Sarybchik		return;
190284555Sarybchik	}
191293984Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
192284555Sarybchik
193227569Sphilip	EFSYS_ASSERT3U(stop, <, EFX_BUF_TBL_SIZE);
194227569Sphilip
195227569Sphilip	EFSYS_PROBE2(buf, uint32_t, start, uint32_t, stop - 1);
196227569Sphilip
197227569Sphilip	EFX_POPULATE_OWORD_4(oword, FRF_AZ_BUF_UPD_CMD, 0,
198227569Sphilip	    FRF_AZ_BUF_CLR_CMD, 1, FRF_AZ_BUF_CLR_END_ID, stop - 1,
199227569Sphilip	    FRF_AZ_BUF_CLR_START_ID, start);
200227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_UPD_REG, &oword);
201227569Sphilip}
202227569Sphilip
203227569Sphilip
204227569Sphilip#if EFSYS_OPT_DIAG
205227569Sphilip
206227569Sphilipstatic			void
207227569Sphilipefx_sram_byte_increment_set(
208227569Sphilip	__in		size_t row,
209227569Sphilip	__in		boolean_t negate,
210227569Sphilip	__out		efx_qword_t *eqp)
211227569Sphilip{
212227569Sphilip	size_t offset = row * FR_AZ_SRM_DBG_REG_STEP;
213227569Sphilip	unsigned int index;
214227569Sphilip
215227569Sphilip	_NOTE(ARGUNUSED(negate))
216227569Sphilip
217227569Sphilip	for (index = 0; index < sizeof (efx_qword_t); index++)
218227569Sphilip		eqp->eq_u8[index] = offset + index;
219227569Sphilip}
220227569Sphilip
221227569Sphilipstatic			void
222227569Sphilipefx_sram_all_the_same_set(
223227569Sphilip	__in		size_t row,
224227569Sphilip	__in		boolean_t negate,
225227569Sphilip	__out		efx_qword_t *eqp)
226227569Sphilip{
227227569Sphilip	_NOTE(ARGUNUSED(row))
228227569Sphilip
229227569Sphilip	if (negate)
230227569Sphilip		EFX_SET_QWORD(*eqp);
231227569Sphilip	else
232227569Sphilip		EFX_ZERO_QWORD(*eqp);
233227569Sphilip}
234227569Sphilip
235227569Sphilipstatic			void
236227569Sphilipefx_sram_bit_alternate_set(
237227569Sphilip	__in		size_t row,
238227569Sphilip	__in		boolean_t negate,
239227569Sphilip	__out		efx_qword_t *eqp)
240227569Sphilip{
241227569Sphilip	_NOTE(ARGUNUSED(row))
242227569Sphilip
243227569Sphilip	EFX_POPULATE_QWORD_2(*eqp,
244227569Sphilip	    EFX_DWORD_0, (negate) ? 0x55555555 : 0xaaaaaaaa,
245227569Sphilip	    EFX_DWORD_1, (negate) ? 0x55555555 : 0xaaaaaaaa);
246227569Sphilip}
247227569Sphilip
248227569Sphilipstatic			void
249227569Sphilipefx_sram_byte_alternate_set(
250227569Sphilip	__in		size_t row,
251227569Sphilip	__in		boolean_t negate,
252227569Sphilip	__out		efx_qword_t *eqp)
253227569Sphilip{
254227569Sphilip	_NOTE(ARGUNUSED(row))
255227569Sphilip
256227569Sphilip	EFX_POPULATE_QWORD_2(*eqp,
257227569Sphilip	    EFX_DWORD_0, (negate) ? 0x00ff00ff : 0xff00ff00,
258227569Sphilip	    EFX_DWORD_1, (negate) ? 0x00ff00ff : 0xff00ff00);
259227569Sphilip}
260227569Sphilip
261227569Sphilipstatic			void
262227569Sphilipefx_sram_byte_changing_set(
263227569Sphilip	__in		size_t row,
264227569Sphilip	__in		boolean_t negate,
265227569Sphilip	__out		efx_qword_t *eqp)
266227569Sphilip{
267227569Sphilip	size_t offset = row * FR_AZ_SRM_DBG_REG_STEP;
268227569Sphilip	unsigned int index;
269227569Sphilip
270227569Sphilip	for (index = 0; index < sizeof (efx_qword_t); index++) {
271227569Sphilip		uint8_t byte;
272227569Sphilip
273227569Sphilip		if (offset / 256 == 0)
274227569Sphilip			byte = (uint8_t)((offset % 257) % 256);
275227569Sphilip		else
276227569Sphilip			byte = (uint8_t)(~((offset - 8) % 257) % 256);
277227569Sphilip
278227569Sphilip		eqp->eq_u8[index] = (negate) ? ~byte : byte;
279227569Sphilip	}
280227569Sphilip}
281227569Sphilip
282227569Sphilipstatic			void
283227569Sphilipefx_sram_bit_sweep_set(
284227569Sphilip	__in		size_t row,
285227569Sphilip	__in		boolean_t negate,
286227569Sphilip	__out		efx_qword_t *eqp)
287227569Sphilip{
288227569Sphilip	size_t offset = row * FR_AZ_SRM_DBG_REG_STEP;
289227569Sphilip
290227569Sphilip	if (negate) {
291227569Sphilip		EFX_SET_QWORD(*eqp);
292227569Sphilip		EFX_CLEAR_QWORD_BIT(*eqp, (offset / sizeof (efx_qword_t)) % 64);
293227569Sphilip	} else {
294227569Sphilip		EFX_ZERO_QWORD(*eqp);
295227569Sphilip		EFX_SET_QWORD_BIT(*eqp, (offset / sizeof (efx_qword_t)) % 64);
296227569Sphilip	}
297227569Sphilip}
298227569Sphilip
299284555Sarybchikefx_sram_pattern_fn_t	__efx_sram_pattern_fns[] = {
300227569Sphilip	efx_sram_byte_increment_set,
301227569Sphilip	efx_sram_all_the_same_set,
302227569Sphilip	efx_sram_bit_alternate_set,
303227569Sphilip	efx_sram_byte_alternate_set,
304227569Sphilip	efx_sram_byte_changing_set,
305227569Sphilip	efx_sram_bit_sweep_set
306227569Sphilip};
307227569Sphilip
308293927Sarybchik	__checkReturn	efx_rc_t
309227569Sphilipefx_sram_test(
310227569Sphilip	__in		efx_nic_t *enp,
311227569Sphilip	__in		efx_pattern_type_t type)
312227569Sphilip{
313227569Sphilip	efx_sram_pattern_fn_t func;
314227569Sphilip
315227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
316227569Sphilip
317227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
318227569Sphilip
319227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
320227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
321227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
322227569Sphilip
323301336Sarybchik	/* SRAM testing is only available on Siena. */
324301336Sarybchik	if (enp->en_family != EFX_FAMILY_SIENA)
325301336Sarybchik		return (0);
326301336Sarybchik
327227569Sphilip	/* Select pattern generator */
328227569Sphilip	EFSYS_ASSERT3U(type, <, EFX_PATTERN_NTYPES);
329227569Sphilip	func = __efx_sram_pattern_fns[type];
330227569Sphilip
331301336Sarybchik	return (siena_sram_test(enp, func));
332227569Sphilip}
333227569Sphilip
334227569Sphilip#endif	/* EFSYS_OPT_DIAG */
335