1227569Sphilip/*-
2227569Sphilip * Copyright 2007-2009 Solarflare Communications Inc.  All rights reserved.
3227569Sphilip *
4227569Sphilip * Redistribution and use in source and binary forms, with or without
5227569Sphilip * modification, are permitted provided that the following conditions
6227569Sphilip * are met:
7227569Sphilip * 1. Redistributions of source code must retain the above copyright
8227569Sphilip *    notice, this list of conditions and the following disclaimer.
9227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright
10227569Sphilip *    notice, this list of conditions and the following disclaimer in the
11227569Sphilip *    documentation and/or other materials provided with the distribution.
12227569Sphilip *
13227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16227569Sphilip * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23227569Sphilip * SUCH DAMAGE.
24227569Sphilip */
25227569Sphilip
26228100Sphilip#include <sys/cdefs.h>
27228100Sphilip__FBSDID("$FreeBSD$");
28228100Sphilip
29227569Sphilip#include "efsys.h"
30227569Sphilip#include "efx.h"
31227569Sphilip#include "efx_types.h"
32227569Sphilip#include "efx_regs.h"
33227569Sphilip#include "efx_impl.h"
34227569Sphilip
35227569Sphilip	__checkReturn	int
36227569Sphilipefx_family(
37227569Sphilip	__in		uint16_t venid,
38227569Sphilip	__in		uint16_t devid,
39227569Sphilip	__out		efx_family_t *efp)
40227569Sphilip{
41227569Sphilip#if EFSYS_OPT_FALCON
42227569Sphilip	if (venid == EFX_PCI_VENID_SFC && devid == EFX_PCI_DEVID_FALCON) {
43227569Sphilip		*efp = EFX_FAMILY_FALCON;
44227569Sphilip		return (0);
45227569Sphilip	}
46227569Sphilip#endif
47227569Sphilip#if EFSYS_OPT_SIENA
48227569Sphilip	if (venid == EFX_PCI_VENID_SFC && devid == EFX_PCI_DEVID_BETHPAGE) {
49227569Sphilip		*efp = EFX_FAMILY_SIENA;
50227569Sphilip		return (0);
51227569Sphilip	}
52227569Sphilip	if (venid == EFX_PCI_VENID_SFC && devid == EFX_PCI_DEVID_SIENA) {
53227569Sphilip		*efp = EFX_FAMILY_SIENA;
54227569Sphilip		return (0);
55227569Sphilip	}
56227569Sphilip	if (venid == EFX_PCI_VENID_SFC &&
57227569Sphilip	    devid == EFX_PCI_DEVID_SIENA_F1_UNINIT) {
58227569Sphilip		*efp = EFX_FAMILY_SIENA;
59227569Sphilip		return (0);
60227569Sphilip	}
61227569Sphilip#endif
62227569Sphilip	return (ENOTSUP);
63227569Sphilip}
64227569Sphilip
65227569Sphilip/*
66227569Sphilip * To support clients which aren't provided with any PCI context infer
67227569Sphilip * the hardware family by inspecting the hardware. Obviously the caller
68227569Sphilip * must be damn sure they're really talking to a supported device.
69227569Sphilip */
70227569Sphilip	__checkReturn	int
71227569Sphilipefx_infer_family(
72227569Sphilip	__in		efsys_bar_t *esbp,
73227569Sphilip	__out		efx_family_t *efp)
74227569Sphilip{
75227569Sphilip	efx_family_t family;
76227569Sphilip	efx_oword_t oword;
77227569Sphilip	unsigned int portnum;
78227569Sphilip	int rc;
79227569Sphilip
80227569Sphilip	EFSYS_BAR_READO(esbp, FR_AZ_CS_DEBUG_REG_OFST, &oword, B_TRUE);
81227569Sphilip	portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM);
82227569Sphilip	switch (portnum) {
83227569Sphilip#if EFSYS_OPT_FALCON
84227569Sphilip	case 0:
85227569Sphilip		family = EFX_FAMILY_FALCON;
86227569Sphilip		break;
87227569Sphilip#endif
88227569Sphilip#if EFSYS_OPT_SIENA
89227569Sphilip	case 1:
90227569Sphilip	case 2:
91227569Sphilip		family = EFX_FAMILY_SIENA;
92227569Sphilip		break;
93227569Sphilip#endif
94227569Sphilip	default:
95227569Sphilip		rc = ENOTSUP;
96227569Sphilip		goto fail1;
97227569Sphilip	}
98227569Sphilip
99227569Sphilip	if (efp != NULL)
100227569Sphilip		*efp = family;
101227569Sphilip	return (0);
102227569Sphilip
103227569Sphilipfail1:
104227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
105227569Sphilip
106227569Sphilip	return (rc);
107227569Sphilip}
108227569Sphilip
109227569Sphilip/*
110227569Sphilip * The built-in default value device id for port 1 of Siena is 0x0810.
111227569Sphilip * manftest needs to be able to cope with that.
112227569Sphilip */
113227569Sphilip
114227569Sphilip#define	EFX_BIU_MAGIC0	0x01234567
115227569Sphilip#define	EFX_BIU_MAGIC1	0xfedcba98
116227569Sphilip
117227569Sphilipstatic	__checkReturn	int
118227569Sphilipefx_nic_biu_test(
119227569Sphilip	__in		efx_nic_t *enp)
120227569Sphilip{
121227569Sphilip	efx_oword_t oword;
122227569Sphilip	int rc;
123227569Sphilip
124227569Sphilip	/*
125227569Sphilip	 * Write magic values to scratch registers 0 and 1, then
126227569Sphilip	 * verify that the values were written correctly.  Interleave
127227569Sphilip	 * the accesses to ensure that the BIU is not just reading
128227569Sphilip	 * back the cached value that was last written.
129227569Sphilip	 */
130227569Sphilip	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
131227569Sphilip	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword);
132227569Sphilip
133227569Sphilip	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
134227569Sphilip	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword);
135227569Sphilip
136227569Sphilip	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword);
137227569Sphilip	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) {
138227569Sphilip		rc = EIO;
139227569Sphilip		goto fail1;
140227569Sphilip	}
141227569Sphilip
142227569Sphilip	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword);
143227569Sphilip	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) {
144227569Sphilip		rc = EIO;
145227569Sphilip		goto fail2;
146227569Sphilip	}
147227569Sphilip
148227569Sphilip	/*
149227569Sphilip	 * Perform the same test, with the values swapped.  This
150227569Sphilip	 * ensures that subsequent tests don't start with the correct
151227569Sphilip	 * values already written into the scratch registers.
152227569Sphilip	 */
153227569Sphilip	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
154227569Sphilip	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword);
155227569Sphilip
156227569Sphilip	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
157227569Sphilip	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword);
158227569Sphilip
159227569Sphilip	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword);
160227569Sphilip	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) {
161227569Sphilip		rc = EIO;
162227569Sphilip		goto fail3;
163227569Sphilip	}
164227569Sphilip
165227569Sphilip	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword);
166227569Sphilip	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) {
167227569Sphilip		rc = EIO;
168227569Sphilip		goto fail4;
169227569Sphilip	}
170227569Sphilip
171227569Sphilip	return (0);
172227569Sphilip
173227569Sphilipfail4:
174227569Sphilip	EFSYS_PROBE(fail4);
175227569Sphilipfail3:
176227569Sphilip	EFSYS_PROBE(fail3);
177227569Sphilipfail2:
178227569Sphilip	EFSYS_PROBE(fail2);
179227569Sphilipfail1:
180227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
181227569Sphilip
182227569Sphilip	return (rc);
183227569Sphilip}
184227569Sphilip
185227569Sphilip#if EFSYS_OPT_FALCON
186227569Sphilip
187227569Sphilipstatic efx_nic_ops_t	__cs __efx_nic_falcon_ops = {
188227569Sphilip	falcon_nic_probe,		/* eno_probe */
189227569Sphilip	falcon_nic_reset,		/* eno_reset */
190227569Sphilip	falcon_nic_init,		/* eno_init */
191227569Sphilip#if EFSYS_OPT_DIAG
192227569Sphilip	falcon_sram_test,		/* eno_sram_test */
193227569Sphilip	falcon_nic_register_test,	/* eno_register_test */
194227569Sphilip#endif	/* EFSYS_OPT_DIAG */
195227569Sphilip	falcon_nic_fini,		/* eno_fini */
196227569Sphilip	falcon_nic_unprobe,		/* eno_unprobe */
197227569Sphilip};
198227569Sphilip
199227569Sphilip#endif	/* EFSYS_OPT_FALCON */
200227569Sphilip
201227569Sphilip#if EFSYS_OPT_SIENA
202227569Sphilip
203227569Sphilipstatic efx_nic_ops_t	__cs __efx_nic_siena_ops = {
204227569Sphilip	siena_nic_probe,		/* eno_probe */
205227569Sphilip	siena_nic_reset,		/* eno_reset */
206227569Sphilip	siena_nic_init,			/* eno_init */
207227569Sphilip#if EFSYS_OPT_DIAG
208227569Sphilip	siena_sram_test,		/* eno_sram_test */
209227569Sphilip	siena_nic_register_test,	/* eno_register_test */
210227569Sphilip#endif	/* EFSYS_OPT_DIAG */
211227569Sphilip	siena_nic_fini,			/* eno_fini */
212227569Sphilip	siena_nic_unprobe,		/* eno_unprobe */
213227569Sphilip};
214227569Sphilip
215227569Sphilip#endif	/* EFSYS_OPT_SIENA */
216227569Sphilip
217227569Sphilip	__checkReturn	int
218227569Sphilipefx_nic_create(
219227569Sphilip	__in		efx_family_t family,
220227569Sphilip	__in		efsys_identifier_t *esip,
221227569Sphilip	__in		efsys_bar_t *esbp,
222227569Sphilip	__in		efsys_lock_t *eslp,
223227569Sphilip	__deref_out	efx_nic_t **enpp)
224227569Sphilip{
225227569Sphilip	efx_nic_t *enp;
226227569Sphilip	int rc;
227227569Sphilip
228227569Sphilip	EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID);
229227569Sphilip	EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES);
230227569Sphilip
231227569Sphilip	/* Allocate a NIC object */
232227569Sphilip	EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp);
233227569Sphilip
234227569Sphilip	if (enp == NULL) {
235227569Sphilip		rc = ENOMEM;
236227569Sphilip		goto fail1;
237227569Sphilip	}
238227569Sphilip
239227569Sphilip	enp->en_magic = EFX_NIC_MAGIC;
240227569Sphilip
241227569Sphilip	switch (family) {
242227569Sphilip#if EFSYS_OPT_FALCON
243227569Sphilip	case EFX_FAMILY_FALCON:
244227569Sphilip		enp->en_enop = (efx_nic_ops_t *)&__efx_nic_falcon_ops;
245227569Sphilip		enp->en_features = 0;
246227569Sphilip		break;
247227569Sphilip#endif	/* EFSYS_OPT_FALCON */
248227569Sphilip
249227569Sphilip#if EFSYS_OPT_SIENA
250227569Sphilip	case EFX_FAMILY_SIENA:
251227569Sphilip		enp->en_enop = (efx_nic_ops_t *)&__efx_nic_siena_ops;
252227569Sphilip		enp->en_features = EFX_FEATURE_IPV6 |
253227569Sphilip		    EFX_FEATURE_LFSR_HASH_INSERT |
254227569Sphilip		    EFX_FEATURE_LINK_EVENTS | EFX_FEATURE_PERIODIC_MAC_STATS |
255227569Sphilip		    EFX_FEATURE_WOL | EFX_FEATURE_MCDI |
256227569Sphilip		    EFX_FEATURE_LOOKAHEAD_SPLIT | EFX_FEATURE_MAC_HEADER_FILTERS;
257227569Sphilip		break;
258227569Sphilip#endif	/* EFSYS_OPT_SIENA */
259227569Sphilip
260227569Sphilip	default:
261227569Sphilip		rc = ENOTSUP;
262227569Sphilip		goto fail2;
263227569Sphilip	}
264227569Sphilip
265227569Sphilip	enp->en_family = family;
266227569Sphilip	enp->en_esip = esip;
267227569Sphilip	enp->en_esbp = esbp;
268227569Sphilip	enp->en_eslp = eslp;
269227569Sphilip
270227569Sphilip	*enpp = enp;
271227569Sphilip
272227569Sphilip	return (0);
273227569Sphilip
274227569Sphilipfail2:
275227569Sphilip	EFSYS_PROBE(fail3);
276227569Sphilip
277227569Sphilip	enp->en_magic = 0;
278227569Sphilip
279227569Sphilip	/* Free the NIC object */
280227569Sphilip	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
281227569Sphilip
282227569Sphilipfail1:
283227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
284227569Sphilip
285227569Sphilip	return (rc);
286227569Sphilip}
287227569Sphilip
288227569Sphilip	__checkReturn	int
289227569Sphilipefx_nic_probe(
290227569Sphilip	__in		efx_nic_t *enp)
291227569Sphilip{
292227569Sphilip	efx_nic_ops_t *enop;
293227569Sphilip	efx_oword_t oword;
294227569Sphilip	int rc;
295227569Sphilip
296227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
297227569Sphilip#if EFSYS_OPT_MCDI
298227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
299227569Sphilip#endif	/* EFSYS_OPT_MCDI */
300227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE));
301227569Sphilip
302227569Sphilip	/* Test BIU */
303227569Sphilip	if ((rc = efx_nic_biu_test(enp)) != 0)
304227569Sphilip		goto fail1;
305227569Sphilip
306227569Sphilip	/* Clear the region register */
307227569Sphilip	EFX_POPULATE_OWORD_4(oword,
308227569Sphilip	    FRF_AZ_ADR_REGION0, 0,
309227569Sphilip	    FRF_AZ_ADR_REGION1, (1 << 16),
310227569Sphilip	    FRF_AZ_ADR_REGION2, (2 << 16),
311227569Sphilip	    FRF_AZ_ADR_REGION3, (3 << 16));
312227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_ADR_REGION_REG, &oword);
313227569Sphilip
314227569Sphilip	enop = enp->en_enop;
315227569Sphilip	if ((rc = enop->eno_probe(enp)) != 0)
316227569Sphilip		goto fail2;
317227569Sphilip
318227569Sphilip	if ((rc = efx_phy_probe(enp)) != 0)
319227569Sphilip		goto fail3;
320227569Sphilip
321227569Sphilip	enp->en_mod_flags |= EFX_MOD_PROBE;
322227569Sphilip
323227569Sphilip	return (0);
324227569Sphilip
325227569Sphilipfail3:
326227569Sphilip	EFSYS_PROBE(fail3);
327227569Sphilip
328227569Sphilip	enop->eno_unprobe(enp);
329227569Sphilip
330227569Sphilipfail2:
331227569Sphilip	EFSYS_PROBE(fail2);
332227569Sphilipfail1:
333227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
334227569Sphilip
335227569Sphilip	return (rc);
336227569Sphilip}
337227569Sphilip
338227569Sphilip#if EFSYS_OPT_PCIE_TUNE
339227569Sphilip
340227569Sphilip	__checkReturn	int
341227569Sphilipefx_nic_pcie_tune(
342227569Sphilip	__in		efx_nic_t *enp,
343227569Sphilip	unsigned int	nlanes)
344227569Sphilip{
345227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
346227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
347227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
348227569Sphilip
349227569Sphilip#if EFSYS_OPT_FALCON
350227569Sphilip	if (enp->en_family == EFX_FAMILY_FALCON)
351227569Sphilip		return (falcon_nic_pcie_tune(enp, nlanes));
352227569Sphilip#endif
353227569Sphilip	return (ENOTSUP);
354227569Sphilip}
355227569Sphilip
356227569Sphilip	__checkReturn	int
357227569Sphilipefx_nic_pcie_extended_sync(
358227569Sphilip	__in		efx_nic_t *enp)
359227569Sphilip{
360227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
361227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
362227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
363227569Sphilip
364227569Sphilip#if EFSYS_OPT_SIENA
365227569Sphilip	if (enp->en_family == EFX_FAMILY_SIENA)
366227569Sphilip		return (siena_nic_pcie_extended_sync(enp));
367227569Sphilip#endif
368227569Sphilip
369227569Sphilip	return (ENOTSUP);
370227569Sphilip}
371227569Sphilip
372227569Sphilip#endif	/* EFSYS_OPT_PCIE_TUNE */
373227569Sphilip
374227569Sphilip	__checkReturn	int
375227569Sphilipefx_nic_init(
376227569Sphilip	__in		efx_nic_t *enp)
377227569Sphilip{
378227569Sphilip	efx_nic_ops_t *enop = enp->en_enop;
379227569Sphilip	int rc;
380227569Sphilip
381227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
382227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
383227569Sphilip
384227569Sphilip	if (enp->en_mod_flags & EFX_MOD_NIC) {
385227569Sphilip		rc = EINVAL;
386227569Sphilip		goto fail1;
387227569Sphilip	}
388227569Sphilip
389227569Sphilip	if ((rc = enop->eno_init(enp)) != 0)
390227569Sphilip		goto fail2;
391227569Sphilip
392227569Sphilip	enp->en_mod_flags |= EFX_MOD_NIC;
393227569Sphilip
394227569Sphilip	return (0);
395227569Sphilip
396227569Sphilipfail2:
397227569Sphilip	EFSYS_PROBE(fail2);
398227569Sphilipfail1:
399227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
400227569Sphilip
401227569Sphilip	return (rc);
402227569Sphilip}
403227569Sphilip
404227569Sphilip			void
405227569Sphilipefx_nic_fini(
406227569Sphilip	__in		efx_nic_t *enp)
407227569Sphilip{
408227569Sphilip	efx_nic_ops_t *enop = enp->en_enop;
409227569Sphilip
410227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
411227569Sphilip	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
412227569Sphilip	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC);
413227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
414227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
415227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
416227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
417227569Sphilip
418227569Sphilip	enop->eno_fini(enp);
419227569Sphilip
420227569Sphilip	enp->en_mod_flags &= ~EFX_MOD_NIC;
421227569Sphilip}
422227569Sphilip
423227569Sphilip			void
424227569Sphilipefx_nic_unprobe(
425227569Sphilip	__in		efx_nic_t *enp)
426227569Sphilip{
427227569Sphilip	efx_nic_ops_t *enop = enp->en_enop;
428227569Sphilip
429227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
430227569Sphilip#if EFSYS_OPT_MCDI
431227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
432227569Sphilip#endif	/* EFSYS_OPT_MCDI */
433227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
434227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
435227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
436227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
437227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
438227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
439227569Sphilip
440227569Sphilip	efx_phy_unprobe(enp);
441227569Sphilip
442227569Sphilip	enop->eno_unprobe(enp);
443227569Sphilip
444227569Sphilip	enp->en_mod_flags &= ~EFX_MOD_PROBE;
445227569Sphilip}
446227569Sphilip
447227569Sphilip			void
448227569Sphilipefx_nic_destroy(
449227569Sphilip	__in	efx_nic_t *enp)
450227569Sphilip{
451227569Sphilip	efsys_identifier_t *esip = enp->en_esip;
452227569Sphilip
453227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
454227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
455227569Sphilip
456227569Sphilip	enp->en_family = 0;
457227569Sphilip	enp->en_esip = NULL;
458227569Sphilip	enp->en_esbp = NULL;
459227569Sphilip	enp->en_eslp = NULL;
460227569Sphilip
461227569Sphilip	enp->en_enop = NULL;
462227569Sphilip
463227569Sphilip	enp->en_magic = 0;
464227569Sphilip
465227569Sphilip	/* Free the NIC object */
466227569Sphilip	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
467227569Sphilip}
468227569Sphilip
469227569Sphilip	__checkReturn	int
470227569Sphilipefx_nic_reset(
471227569Sphilip	__in		efx_nic_t *enp)
472227569Sphilip{
473227569Sphilip	efx_nic_ops_t *enop = enp->en_enop;
474227569Sphilip	unsigned int mod_flags;
475227569Sphilip	int rc;
476227569Sphilip
477227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
478227569Sphilip	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
479227569Sphilip	/*
480227569Sphilip	 * All modules except the MCDI, PROBE, NVRAM, VPD, MON (which we
481227569Sphilip	 * do not reset here) must have been shut down or never initialized.
482227569Sphilip	 *
483227569Sphilip	 * A rule of thumb here is: If the controller or MC reboots, is *any*
484227569Sphilip	 * state lost. If it's lost and needs reapplying, then the module
485227569Sphilip	 * *must* not be initialised during the reset.
486227569Sphilip	 */
487227569Sphilip	mod_flags = enp->en_mod_flags;
488227569Sphilip	mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM |
489227569Sphilip		    EFX_MOD_VPD | EFX_MOD_MON);
490227569Sphilip	EFSYS_ASSERT3U(mod_flags, ==, 0);
491227569Sphilip	if (mod_flags != 0) {
492227569Sphilip		rc = EINVAL;
493227569Sphilip		goto fail1;
494227569Sphilip	}
495227569Sphilip
496227569Sphilip	if ((rc = enop->eno_reset(enp)) != 0)
497227569Sphilip		goto fail2;
498227569Sphilip
499227569Sphilip	enp->en_reset_flags |= EFX_RESET_MAC;
500227569Sphilip
501227569Sphilip	return (0);
502227569Sphilip
503227569Sphilipfail2:
504227569Sphilip	EFSYS_PROBE(fail2);
505227569Sphilipfail1:
506227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
507227569Sphilip
508227569Sphilip	return (rc);
509227569Sphilip}
510227569Sphilip
511227569Sphilip			const efx_nic_cfg_t *
512227569Sphilipefx_nic_cfg_get(
513227569Sphilip	__in		efx_nic_t *enp)
514227569Sphilip{
515227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
516227569Sphilip
517227569Sphilip	return (&(enp->en_nic_cfg));
518227569Sphilip}
519227569Sphilip
520227569Sphilip#if EFSYS_OPT_DIAG
521227569Sphilip
522227569Sphilip	__checkReturn	int
523227569Sphilipefx_nic_register_test(
524227569Sphilip	__in		efx_nic_t *enp)
525227569Sphilip{
526227569Sphilip	efx_nic_ops_t *enop = enp->en_enop;
527227569Sphilip	int rc;
528227569Sphilip
529227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
530227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
531227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
532227569Sphilip
533227569Sphilip	if ((rc = enop->eno_register_test(enp)) != 0)
534227569Sphilip		goto fail1;
535227569Sphilip
536227569Sphilip	return (0);
537227569Sphilip
538227569Sphilipfail1:
539227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
540227569Sphilip
541227569Sphilip	return (rc);
542227569Sphilip}
543227569Sphilip
544227569Sphilip	__checkReturn	int
545227569Sphilipefx_nic_test_registers(
546227569Sphilip	__in		efx_nic_t *enp,
547227569Sphilip	__in		efx_register_set_t *rsp,
548227569Sphilip	__in		size_t count)
549227569Sphilip{
550227569Sphilip	unsigned int bit;
551227569Sphilip	efx_oword_t original;
552227569Sphilip	efx_oword_t reg;
553227569Sphilip	efx_oword_t buf;
554227569Sphilip	int rc;
555227569Sphilip
556227569Sphilip	while (count > 0) {
557227569Sphilip		/* This function is only suitable for registers */
558227569Sphilip		EFSYS_ASSERT(rsp->rows == 1);
559227569Sphilip
560227569Sphilip		/* bit sweep on and off */
561227569Sphilip		EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original,
562227569Sphilip			    B_TRUE);
563227569Sphilip		for (bit = 0; bit < 128; bit++) {
564227569Sphilip			/* Is this bit in the mask? */
565227569Sphilip			if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit))
566227569Sphilip				continue;
567227569Sphilip
568227569Sphilip			/* Test this bit can be set in isolation */
569227569Sphilip			reg = original;
570227569Sphilip			EFX_AND_OWORD(reg, rsp->mask);
571227569Sphilip			EFX_SET_OWORD_BIT(reg, bit);
572227569Sphilip
573227569Sphilip			EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
574227569Sphilip				    B_TRUE);
575227569Sphilip			EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
576227569Sphilip				    B_TRUE);
577227569Sphilip
578227569Sphilip			EFX_AND_OWORD(buf, rsp->mask);
579227569Sphilip			if (memcmp(&reg, &buf, sizeof (reg))) {
580227569Sphilip				rc = EIO;
581227569Sphilip				goto fail1;
582227569Sphilip			}
583227569Sphilip
584227569Sphilip			/* Test this bit can be cleared in isolation */
585227569Sphilip			EFX_OR_OWORD(reg, rsp->mask);
586227569Sphilip			EFX_CLEAR_OWORD_BIT(reg, bit);
587227569Sphilip
588227569Sphilip			EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
589227569Sphilip				    B_TRUE);
590227569Sphilip			EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
591227569Sphilip				    B_TRUE);
592227569Sphilip
593227569Sphilip			EFX_AND_OWORD(buf, rsp->mask);
594227569Sphilip			if (memcmp(&reg, &buf, sizeof (reg))) {
595227569Sphilip				rc = EIO;
596227569Sphilip				goto fail2;
597227569Sphilip			}
598227569Sphilip		}
599227569Sphilip
600227569Sphilip		/* Restore the old value */
601227569Sphilip		EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original,
602227569Sphilip			    B_TRUE);
603227569Sphilip
604227569Sphilip		--count;
605227569Sphilip		++rsp;
606227569Sphilip	}
607227569Sphilip
608227569Sphilip	return (0);
609227569Sphilip
610227569Sphilipfail2:
611227569Sphilip	EFSYS_PROBE(fail2);
612227569Sphilipfail1:
613227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
614227569Sphilip
615227569Sphilip	/* Restore the old value */
616227569Sphilip	EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE);
617227569Sphilip
618227569Sphilip	return (rc);
619227569Sphilip}
620227569Sphilip
621227569Sphilip	__checkReturn	int
622227569Sphilipefx_nic_test_tables(
623227569Sphilip	__in		efx_nic_t *enp,
624227569Sphilip	__in		efx_register_set_t *rsp,
625227569Sphilip	__in		efx_pattern_type_t pattern,
626227569Sphilip	__in		size_t count)
627227569Sphilip{
628227569Sphilip	efx_sram_pattern_fn_t func;
629227569Sphilip	unsigned int index;
630227569Sphilip	unsigned int address;
631227569Sphilip	efx_oword_t reg;
632227569Sphilip	efx_oword_t buf;
633227569Sphilip	int rc;
634227569Sphilip
635227569Sphilip	EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES);
636227569Sphilip	func = __efx_sram_pattern_fns[pattern];
637227569Sphilip
638227569Sphilip	while (count > 0) {
639227569Sphilip		/* Write */
640227569Sphilip		address = rsp->address;
641227569Sphilip		for (index = 0; index < rsp->rows; ++index) {
642227569Sphilip			func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
643227569Sphilip			func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
644227569Sphilip			EFX_AND_OWORD(reg, rsp->mask);
645227569Sphilip			EFSYS_BAR_WRITEO(enp->en_esbp, address, &reg, B_TRUE);
646227569Sphilip
647227569Sphilip			address += rsp->step;
648227569Sphilip		}
649227569Sphilip
650227569Sphilip		/* Read */
651227569Sphilip		address = rsp->address;
652227569Sphilip		for (index = 0; index < rsp->rows; ++index) {
653227569Sphilip			func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
654227569Sphilip			func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
655227569Sphilip			EFX_AND_OWORD(reg, rsp->mask);
656227569Sphilip			EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE);
657227569Sphilip			if (memcmp(&reg, &buf, sizeof (reg))) {
658227569Sphilip				rc = EIO;
659227569Sphilip				goto fail1;
660227569Sphilip			}
661227569Sphilip
662227569Sphilip			address += rsp->step;
663227569Sphilip		}
664227569Sphilip
665227569Sphilip		++rsp;
666227569Sphilip		--count;
667227569Sphilip	}
668227569Sphilip
669227569Sphilip	return (0);
670227569Sphilip
671227569Sphilipfail1:
672227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
673227569Sphilip
674227569Sphilip	return (rc);
675227569Sphilip}
676227569Sphilip
677227569Sphilip#endif	/* EFSYS_OPT_DIAG */
678