1*49ef7e06SGarrett D'Amore /*
2*49ef7e06SGarrett D'Amore  * Copyright (c) 2007-2015 Solarflare Communications Inc.
3*49ef7e06SGarrett D'Amore  * All rights reserved.
4*49ef7e06SGarrett D'Amore  *
5*49ef7e06SGarrett D'Amore  * Redistribution and use in source and binary forms, with or without
6*49ef7e06SGarrett D'Amore  * modification, are permitted provided that the following conditions are met:
7*49ef7e06SGarrett D'Amore  *
8*49ef7e06SGarrett D'Amore  * 1. Redistributions of source code must retain the above copyright notice,
9*49ef7e06SGarrett D'Amore  *    this list of conditions and the following disclaimer.
10*49ef7e06SGarrett D'Amore  * 2. Redistributions in binary form must reproduce the above copyright notice,
11*49ef7e06SGarrett D'Amore  *    this list of conditions and the following disclaimer in the documentation
12*49ef7e06SGarrett D'Amore  *    and/or other materials provided with the distribution.
13*49ef7e06SGarrett D'Amore  *
14*49ef7e06SGarrett D'Amore  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15*49ef7e06SGarrett D'Amore  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16*49ef7e06SGarrett D'Amore  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17*49ef7e06SGarrett D'Amore  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18*49ef7e06SGarrett D'Amore  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19*49ef7e06SGarrett D'Amore  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20*49ef7e06SGarrett D'Amore  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21*49ef7e06SGarrett D'Amore  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22*49ef7e06SGarrett D'Amore  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23*49ef7e06SGarrett D'Amore  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24*49ef7e06SGarrett D'Amore  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*49ef7e06SGarrett D'Amore  *
26*49ef7e06SGarrett D'Amore  * The views and conclusions contained in the software and documentation are
27*49ef7e06SGarrett D'Amore  * those of the authors and should not be interpreted as representing official
28*49ef7e06SGarrett D'Amore  * policies, either expressed or implied, of the FreeBSD Project.
29*49ef7e06SGarrett D'Amore  */
30*49ef7e06SGarrett D'Amore 
31*49ef7e06SGarrett D'Amore #include "efx.h"
32*49ef7e06SGarrett D'Amore #include "efx_impl.h"
33*49ef7e06SGarrett D'Amore 
34*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_family(__in uint16_t venid,__in uint16_t devid,__out efx_family_t * efp)35*49ef7e06SGarrett D'Amore efx_family(
36*49ef7e06SGarrett D'Amore 	__in		uint16_t venid,
37*49ef7e06SGarrett D'Amore 	__in		uint16_t devid,
38*49ef7e06SGarrett D'Amore 	__out		efx_family_t *efp)
39*49ef7e06SGarrett D'Amore {
40*49ef7e06SGarrett D'Amore 	if (venid == EFX_PCI_VENID_SFC) {
41*49ef7e06SGarrett D'Amore 		switch (devid) {
42*49ef7e06SGarrett D'Amore #if EFSYS_OPT_SIENA
43*49ef7e06SGarrett D'Amore 		case EFX_PCI_DEVID_SIENA_F1_UNINIT:
44*49ef7e06SGarrett D'Amore 			/*
45*49ef7e06SGarrett D'Amore 			 * Hardware default for PF0 of uninitialised Siena.
46*49ef7e06SGarrett D'Amore 			 * manftest must be able to cope with this device id.
47*49ef7e06SGarrett D'Amore 			 */
48*49ef7e06SGarrett D'Amore 			*efp = EFX_FAMILY_SIENA;
49*49ef7e06SGarrett D'Amore 			return (0);
50*49ef7e06SGarrett D'Amore 
51*49ef7e06SGarrett D'Amore 		case EFX_PCI_DEVID_BETHPAGE:
52*49ef7e06SGarrett D'Amore 		case EFX_PCI_DEVID_SIENA:
53*49ef7e06SGarrett D'Amore 			*efp = EFX_FAMILY_SIENA;
54*49ef7e06SGarrett D'Amore 			return (0);
55*49ef7e06SGarrett D'Amore #endif /* EFSYS_OPT_SIENA */
56*49ef7e06SGarrett D'Amore 
57*49ef7e06SGarrett D'Amore #if EFSYS_OPT_HUNTINGTON
58*49ef7e06SGarrett D'Amore 		case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT:
59*49ef7e06SGarrett D'Amore 			/*
60*49ef7e06SGarrett D'Amore 			 * Hardware default for PF0 of uninitialised Huntington.
61*49ef7e06SGarrett D'Amore 			 * manftest must be able to cope with this device id.
62*49ef7e06SGarrett D'Amore 			 */
63*49ef7e06SGarrett D'Amore 			*efp = EFX_FAMILY_HUNTINGTON;
64*49ef7e06SGarrett D'Amore 			return (0);
65*49ef7e06SGarrett D'Amore 
66*49ef7e06SGarrett D'Amore 		case EFX_PCI_DEVID_FARMINGDALE:
67*49ef7e06SGarrett D'Amore 		case EFX_PCI_DEVID_GREENPORT:
68*49ef7e06SGarrett D'Amore 			*efp = EFX_FAMILY_HUNTINGTON;
69*49ef7e06SGarrett D'Amore 			return (0);
70*49ef7e06SGarrett D'Amore 
71*49ef7e06SGarrett D'Amore 		case EFX_PCI_DEVID_FARMINGDALE_VF:
72*49ef7e06SGarrett D'Amore 		case EFX_PCI_DEVID_GREENPORT_VF:
73*49ef7e06SGarrett D'Amore 			*efp = EFX_FAMILY_HUNTINGTON;
74*49ef7e06SGarrett D'Amore 			return (0);
75*49ef7e06SGarrett D'Amore #endif /* EFSYS_OPT_HUNTINGTON */
76*49ef7e06SGarrett D'Amore 
77*49ef7e06SGarrett D'Amore #if EFSYS_OPT_MEDFORD
78*49ef7e06SGarrett D'Amore 		case EFX_PCI_DEVID_MEDFORD_PF_UNINIT:
79*49ef7e06SGarrett D'Amore 			/*
80*49ef7e06SGarrett D'Amore 			 * Hardware default for PF0 of uninitialised Medford.
81*49ef7e06SGarrett D'Amore 			 * manftest must be able to cope with this device id.
82*49ef7e06SGarrett D'Amore 			 */
83*49ef7e06SGarrett D'Amore 			*efp = EFX_FAMILY_MEDFORD;
84*49ef7e06SGarrett D'Amore 			return (0);
85*49ef7e06SGarrett D'Amore 
86*49ef7e06SGarrett D'Amore 		case EFX_PCI_DEVID_MEDFORD:
87*49ef7e06SGarrett D'Amore 			*efp = EFX_FAMILY_MEDFORD;
88*49ef7e06SGarrett D'Amore 			return (0);
89*49ef7e06SGarrett D'Amore 
90*49ef7e06SGarrett D'Amore 		case EFX_PCI_DEVID_MEDFORD_VF:
91*49ef7e06SGarrett D'Amore 			*efp = EFX_FAMILY_MEDFORD;
92*49ef7e06SGarrett D'Amore 			return (0);
93*49ef7e06SGarrett D'Amore #endif /* EFSYS_OPT_MEDFORD */
94*49ef7e06SGarrett D'Amore 
95*49ef7e06SGarrett D'Amore 		case EFX_PCI_DEVID_FALCON:	/* Obsolete, not supported */
96*49ef7e06SGarrett D'Amore 		default:
97*49ef7e06SGarrett D'Amore 			break;
98*49ef7e06SGarrett D'Amore 		}
99*49ef7e06SGarrett D'Amore 	}
100*49ef7e06SGarrett D'Amore 
101*49ef7e06SGarrett D'Amore 	*efp = EFX_FAMILY_INVALID;
102*49ef7e06SGarrett D'Amore 	return (ENOTSUP);
103*49ef7e06SGarrett D'Amore }
104*49ef7e06SGarrett D'Amore 
105*49ef7e06SGarrett D'Amore 
106*49ef7e06SGarrett D'Amore #define	EFX_BIU_MAGIC0	0x01234567
107*49ef7e06SGarrett D'Amore #define	EFX_BIU_MAGIC1	0xfedcba98
108*49ef7e06SGarrett D'Amore 
109*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_nic_biu_test(__in efx_nic_t * enp)110*49ef7e06SGarrett D'Amore efx_nic_biu_test(
111*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp)
112*49ef7e06SGarrett D'Amore {
113*49ef7e06SGarrett D'Amore 	efx_oword_t oword;
114*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
115*49ef7e06SGarrett D'Amore 
116*49ef7e06SGarrett D'Amore 	/*
117*49ef7e06SGarrett D'Amore 	 * Write magic values to scratch registers 0 and 1, then
118*49ef7e06SGarrett D'Amore 	 * verify that the values were written correctly.  Interleave
119*49ef7e06SGarrett D'Amore 	 * the accesses to ensure that the BIU is not just reading
120*49ef7e06SGarrett D'Amore 	 * back the cached value that was last written.
121*49ef7e06SGarrett D'Amore 	 */
122*49ef7e06SGarrett D'Amore 	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
123*49ef7e06SGarrett D'Amore 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
124*49ef7e06SGarrett D'Amore 
125*49ef7e06SGarrett D'Amore 	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
126*49ef7e06SGarrett D'Amore 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
127*49ef7e06SGarrett D'Amore 
128*49ef7e06SGarrett D'Amore 	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
129*49ef7e06SGarrett D'Amore 	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) {
130*49ef7e06SGarrett D'Amore 		rc = EIO;
131*49ef7e06SGarrett D'Amore 		goto fail1;
132*49ef7e06SGarrett D'Amore 	}
133*49ef7e06SGarrett D'Amore 
134*49ef7e06SGarrett D'Amore 	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
135*49ef7e06SGarrett D'Amore 	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) {
136*49ef7e06SGarrett D'Amore 		rc = EIO;
137*49ef7e06SGarrett D'Amore 		goto fail2;
138*49ef7e06SGarrett D'Amore 	}
139*49ef7e06SGarrett D'Amore 
140*49ef7e06SGarrett D'Amore 	/*
141*49ef7e06SGarrett D'Amore 	 * Perform the same test, with the values swapped.  This
142*49ef7e06SGarrett D'Amore 	 * ensures that subsequent tests don't start with the correct
143*49ef7e06SGarrett D'Amore 	 * values already written into the scratch registers.
144*49ef7e06SGarrett D'Amore 	 */
145*49ef7e06SGarrett D'Amore 	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
146*49ef7e06SGarrett D'Amore 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
147*49ef7e06SGarrett D'Amore 
148*49ef7e06SGarrett D'Amore 	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
149*49ef7e06SGarrett D'Amore 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
150*49ef7e06SGarrett D'Amore 
151*49ef7e06SGarrett D'Amore 	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
152*49ef7e06SGarrett D'Amore 	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) {
153*49ef7e06SGarrett D'Amore 		rc = EIO;
154*49ef7e06SGarrett D'Amore 		goto fail3;
155*49ef7e06SGarrett D'Amore 	}
156*49ef7e06SGarrett D'Amore 
157*49ef7e06SGarrett D'Amore 	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
158*49ef7e06SGarrett D'Amore 	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) {
159*49ef7e06SGarrett D'Amore 		rc = EIO;
160*49ef7e06SGarrett D'Amore 		goto fail4;
161*49ef7e06SGarrett D'Amore 	}
162*49ef7e06SGarrett D'Amore 
163*49ef7e06SGarrett D'Amore 	return (0);
164*49ef7e06SGarrett D'Amore 
165*49ef7e06SGarrett D'Amore fail4:
166*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail4);
167*49ef7e06SGarrett D'Amore fail3:
168*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail3);
169*49ef7e06SGarrett D'Amore fail2:
170*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
171*49ef7e06SGarrett D'Amore fail1:
172*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
173*49ef7e06SGarrett D'Amore 
174*49ef7e06SGarrett D'Amore 	return (rc);
175*49ef7e06SGarrett D'Amore }
176*49ef7e06SGarrett D'Amore 
177*49ef7e06SGarrett D'Amore #if EFSYS_OPT_SIENA
178*49ef7e06SGarrett D'Amore 
179*49ef7e06SGarrett D'Amore static const efx_nic_ops_t	__efx_nic_siena_ops = {
180*49ef7e06SGarrett D'Amore 	siena_nic_probe,		/* eno_probe */
181*49ef7e06SGarrett D'Amore 	NULL,				/* eno_board_cfg */
182*49ef7e06SGarrett D'Amore 	NULL,				/* eno_set_drv_limits */
183*49ef7e06SGarrett D'Amore 	siena_nic_reset,		/* eno_reset */
184*49ef7e06SGarrett D'Amore 	siena_nic_init,			/* eno_init */
185*49ef7e06SGarrett D'Amore 	NULL,				/* eno_get_vi_pool */
186*49ef7e06SGarrett D'Amore 	NULL,				/* eno_get_bar_region */
187*49ef7e06SGarrett D'Amore #if EFSYS_OPT_DIAG
188*49ef7e06SGarrett D'Amore 	siena_nic_register_test,	/* eno_register_test */
189*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_DIAG */
190*49ef7e06SGarrett D'Amore 	siena_nic_fini,			/* eno_fini */
191*49ef7e06SGarrett D'Amore 	siena_nic_unprobe,		/* eno_unprobe */
192*49ef7e06SGarrett D'Amore };
193*49ef7e06SGarrett D'Amore 
194*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_SIENA */
195*49ef7e06SGarrett D'Amore 
196*49ef7e06SGarrett D'Amore #if EFSYS_OPT_HUNTINGTON
197*49ef7e06SGarrett D'Amore 
198*49ef7e06SGarrett D'Amore static const efx_nic_ops_t	__efx_nic_hunt_ops = {
199*49ef7e06SGarrett D'Amore 	ef10_nic_probe,			/* eno_probe */
200*49ef7e06SGarrett D'Amore 	hunt_board_cfg,			/* eno_board_cfg */
201*49ef7e06SGarrett D'Amore 	ef10_nic_set_drv_limits,	/* eno_set_drv_limits */
202*49ef7e06SGarrett D'Amore 	ef10_nic_reset,			/* eno_reset */
203*49ef7e06SGarrett D'Amore 	ef10_nic_init,			/* eno_init */
204*49ef7e06SGarrett D'Amore 	ef10_nic_get_vi_pool,		/* eno_get_vi_pool */
205*49ef7e06SGarrett D'Amore 	ef10_nic_get_bar_region,	/* eno_get_bar_region */
206*49ef7e06SGarrett D'Amore #if EFSYS_OPT_DIAG
207*49ef7e06SGarrett D'Amore 	ef10_nic_register_test,		/* eno_register_test */
208*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_DIAG */
209*49ef7e06SGarrett D'Amore 	ef10_nic_fini,			/* eno_fini */
210*49ef7e06SGarrett D'Amore 	ef10_nic_unprobe,		/* eno_unprobe */
211*49ef7e06SGarrett D'Amore };
212*49ef7e06SGarrett D'Amore 
213*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_HUNTINGTON */
214*49ef7e06SGarrett D'Amore 
215*49ef7e06SGarrett D'Amore #if EFSYS_OPT_MEDFORD
216*49ef7e06SGarrett D'Amore 
217*49ef7e06SGarrett D'Amore static const efx_nic_ops_t	__efx_nic_medford_ops = {
218*49ef7e06SGarrett D'Amore 	ef10_nic_probe,			/* eno_probe */
219*49ef7e06SGarrett D'Amore 	medford_board_cfg,		/* eno_board_cfg */
220*49ef7e06SGarrett D'Amore 	ef10_nic_set_drv_limits,	/* eno_set_drv_limits */
221*49ef7e06SGarrett D'Amore 	ef10_nic_reset,			/* eno_reset */
222*49ef7e06SGarrett D'Amore 	ef10_nic_init,			/* eno_init */
223*49ef7e06SGarrett D'Amore 	ef10_nic_get_vi_pool,		/* eno_get_vi_pool */
224*49ef7e06SGarrett D'Amore 	ef10_nic_get_bar_region,	/* eno_get_bar_region */
225*49ef7e06SGarrett D'Amore #if EFSYS_OPT_DIAG
226*49ef7e06SGarrett D'Amore 	ef10_nic_register_test,		/* eno_register_test */
227*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_DIAG */
228*49ef7e06SGarrett D'Amore 	ef10_nic_fini,			/* eno_fini */
229*49ef7e06SGarrett D'Amore 	ef10_nic_unprobe,		/* eno_unprobe */
230*49ef7e06SGarrett D'Amore };
231*49ef7e06SGarrett D'Amore 
232*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_MEDFORD */
233*49ef7e06SGarrett D'Amore 
234*49ef7e06SGarrett D'Amore 
235*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_nic_create(__in efx_family_t family,__in efsys_identifier_t * esip,__in efsys_bar_t * esbp,__in efsys_lock_t * eslp,__deref_out efx_nic_t ** enpp)236*49ef7e06SGarrett D'Amore efx_nic_create(
237*49ef7e06SGarrett D'Amore 	__in		efx_family_t family,
238*49ef7e06SGarrett D'Amore 	__in		efsys_identifier_t *esip,
239*49ef7e06SGarrett D'Amore 	__in		efsys_bar_t *esbp,
240*49ef7e06SGarrett D'Amore 	__in		efsys_lock_t *eslp,
241*49ef7e06SGarrett D'Amore 	__deref_out	efx_nic_t **enpp)
242*49ef7e06SGarrett D'Amore {
243*49ef7e06SGarrett D'Amore 	efx_nic_t *enp;
244*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
245*49ef7e06SGarrett D'Amore 
246*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID);
247*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES);
248*49ef7e06SGarrett D'Amore 
249*49ef7e06SGarrett D'Amore 	/* Allocate a NIC object */
250*49ef7e06SGarrett D'Amore 	EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp);
251*49ef7e06SGarrett D'Amore 
252*49ef7e06SGarrett D'Amore 	if (enp == NULL) {
253*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
254*49ef7e06SGarrett D'Amore 		goto fail1;
255*49ef7e06SGarrett D'Amore 	}
256*49ef7e06SGarrett D'Amore 
257*49ef7e06SGarrett D'Amore 	enp->en_magic = EFX_NIC_MAGIC;
258*49ef7e06SGarrett D'Amore 
259*49ef7e06SGarrett D'Amore 	switch (family) {
260*49ef7e06SGarrett D'Amore #if EFSYS_OPT_SIENA
261*49ef7e06SGarrett D'Amore 	case EFX_FAMILY_SIENA:
262*49ef7e06SGarrett D'Amore 		enp->en_enop = &__efx_nic_siena_ops;
263*49ef7e06SGarrett D'Amore 		enp->en_features =
264*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_IPV6 |
265*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_LFSR_HASH_INSERT |
266*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_LINK_EVENTS |
267*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_PERIODIC_MAC_STATS |
268*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_WOL |
269*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_MCDI |
270*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_LOOKAHEAD_SPLIT |
271*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_MAC_HEADER_FILTERS |
272*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_TX_SRC_FILTERS;
273*49ef7e06SGarrett D'Amore 		break;
274*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_SIENA */
275*49ef7e06SGarrett D'Amore 
276*49ef7e06SGarrett D'Amore #if EFSYS_OPT_HUNTINGTON
277*49ef7e06SGarrett D'Amore 	case EFX_FAMILY_HUNTINGTON:
278*49ef7e06SGarrett D'Amore 		enp->en_enop = &__efx_nic_hunt_ops;
279*49ef7e06SGarrett D'Amore 		/* FIXME: Add WOL support */
280*49ef7e06SGarrett D'Amore 		enp->en_features =
281*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_IPV6 |
282*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_LINK_EVENTS |
283*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_PERIODIC_MAC_STATS |
284*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_MCDI |
285*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_MAC_HEADER_FILTERS |
286*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_MCDI_DMA |
287*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_PIO_BUFFERS |
288*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_FW_ASSISTED_TSO |
289*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_FW_ASSISTED_TSO_V2;
290*49ef7e06SGarrett D'Amore 		break;
291*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_HUNTINGTON */
292*49ef7e06SGarrett D'Amore 
293*49ef7e06SGarrett D'Amore #if EFSYS_OPT_MEDFORD
294*49ef7e06SGarrett D'Amore 	case EFX_FAMILY_MEDFORD:
295*49ef7e06SGarrett D'Amore 		enp->en_enop = &__efx_nic_medford_ops;
296*49ef7e06SGarrett D'Amore 		/*
297*49ef7e06SGarrett D'Amore 		 * FW_ASSISTED_TSO omitted as Medford only supports firmware
298*49ef7e06SGarrett D'Amore 		 * assisted TSO version 2, not the v1 scheme used on Huntington.
299*49ef7e06SGarrett D'Amore 		 */
300*49ef7e06SGarrett D'Amore 		enp->en_features =
301*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_IPV6 |
302*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_LINK_EVENTS |
303*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_PERIODIC_MAC_STATS |
304*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_MCDI |
305*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_MAC_HEADER_FILTERS |
306*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_MCDI_DMA |
307*49ef7e06SGarrett D'Amore 		    EFX_FEATURE_PIO_BUFFERS;
308*49ef7e06SGarrett D'Amore 		break;
309*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_MEDFORD */
310*49ef7e06SGarrett D'Amore 
311*49ef7e06SGarrett D'Amore 	default:
312*49ef7e06SGarrett D'Amore 		rc = ENOTSUP;
313*49ef7e06SGarrett D'Amore 		goto fail2;
314*49ef7e06SGarrett D'Amore 	}
315*49ef7e06SGarrett D'Amore 
316*49ef7e06SGarrett D'Amore 	enp->en_family = family;
317*49ef7e06SGarrett D'Amore 	enp->en_esip = esip;
318*49ef7e06SGarrett D'Amore 	enp->en_esbp = esbp;
319*49ef7e06SGarrett D'Amore 	enp->en_eslp = eslp;
320*49ef7e06SGarrett D'Amore 
321*49ef7e06SGarrett D'Amore 	*enpp = enp;
322*49ef7e06SGarrett D'Amore 
323*49ef7e06SGarrett D'Amore 	return (0);
324*49ef7e06SGarrett D'Amore 
325*49ef7e06SGarrett D'Amore fail2:
326*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
327*49ef7e06SGarrett D'Amore 
328*49ef7e06SGarrett D'Amore 	enp->en_magic = 0;
329*49ef7e06SGarrett D'Amore 
330*49ef7e06SGarrett D'Amore 	/* Free the NIC object */
331*49ef7e06SGarrett D'Amore 	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
332*49ef7e06SGarrett D'Amore 
333*49ef7e06SGarrett D'Amore fail1:
334*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
335*49ef7e06SGarrett D'Amore 
336*49ef7e06SGarrett D'Amore 	return (rc);
337*49ef7e06SGarrett D'Amore }
338*49ef7e06SGarrett D'Amore 
339*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_nic_probe(__in efx_nic_t * enp)340*49ef7e06SGarrett D'Amore efx_nic_probe(
341*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp)
342*49ef7e06SGarrett D'Amore {
343*49ef7e06SGarrett D'Amore 	const efx_nic_ops_t *enop;
344*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
345*49ef7e06SGarrett D'Amore 
346*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
347*49ef7e06SGarrett D'Amore #if EFSYS_OPT_MCDI
348*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
349*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_MCDI */
350*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE));
351*49ef7e06SGarrett D'Amore 
352*49ef7e06SGarrett D'Amore 	enop = enp->en_enop;
353*49ef7e06SGarrett D'Amore 	if ((rc = enop->eno_probe(enp)) != 0)
354*49ef7e06SGarrett D'Amore 		goto fail1;
355*49ef7e06SGarrett D'Amore 
356*49ef7e06SGarrett D'Amore 	if ((rc = efx_phy_probe(enp)) != 0)
357*49ef7e06SGarrett D'Amore 		goto fail2;
358*49ef7e06SGarrett D'Amore 
359*49ef7e06SGarrett D'Amore 	enp->en_mod_flags |= EFX_MOD_PROBE;
360*49ef7e06SGarrett D'Amore 
361*49ef7e06SGarrett D'Amore 	return (0);
362*49ef7e06SGarrett D'Amore 
363*49ef7e06SGarrett D'Amore fail2:
364*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
365*49ef7e06SGarrett D'Amore 
366*49ef7e06SGarrett D'Amore 	enop->eno_unprobe(enp);
367*49ef7e06SGarrett D'Amore 
368*49ef7e06SGarrett D'Amore fail1:
369*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
370*49ef7e06SGarrett D'Amore 
371*49ef7e06SGarrett D'Amore 	return (rc);
372*49ef7e06SGarrett D'Amore }
373*49ef7e06SGarrett D'Amore 
374*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_nic_set_drv_limits(__inout efx_nic_t * enp,__in efx_drv_limits_t * edlp)375*49ef7e06SGarrett D'Amore efx_nic_set_drv_limits(
376*49ef7e06SGarrett D'Amore 	__inout		efx_nic_t *enp,
377*49ef7e06SGarrett D'Amore 	__in		efx_drv_limits_t *edlp)
378*49ef7e06SGarrett D'Amore {
379*49ef7e06SGarrett D'Amore 	const efx_nic_ops_t *enop = enp->en_enop;
380*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
381*49ef7e06SGarrett D'Amore 
382*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
383*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
384*49ef7e06SGarrett D'Amore 
385*49ef7e06SGarrett D'Amore 	if (enop->eno_set_drv_limits != NULL) {
386*49ef7e06SGarrett D'Amore 		if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0)
387*49ef7e06SGarrett D'Amore 			goto fail1;
388*49ef7e06SGarrett D'Amore 	}
389*49ef7e06SGarrett D'Amore 
390*49ef7e06SGarrett D'Amore 	return (0);
391*49ef7e06SGarrett D'Amore 
392*49ef7e06SGarrett D'Amore fail1:
393*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
394*49ef7e06SGarrett D'Amore 
395*49ef7e06SGarrett D'Amore 	return (rc);
396*49ef7e06SGarrett D'Amore }
397*49ef7e06SGarrett D'Amore 
398*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_nic_get_bar_region(__in efx_nic_t * enp,__in efx_nic_region_t region,__out uint32_t * offsetp,__out size_t * sizep)399*49ef7e06SGarrett D'Amore efx_nic_get_bar_region(
400*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp,
401*49ef7e06SGarrett D'Amore 	__in		efx_nic_region_t region,
402*49ef7e06SGarrett D'Amore 	__out		uint32_t *offsetp,
403*49ef7e06SGarrett D'Amore 	__out		size_t *sizep)
404*49ef7e06SGarrett D'Amore {
405*49ef7e06SGarrett D'Amore 	const efx_nic_ops_t *enop = enp->en_enop;
406*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
407*49ef7e06SGarrett D'Amore 
408*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
409*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
410*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
411*49ef7e06SGarrett D'Amore 
412*49ef7e06SGarrett D'Amore 	if (enop->eno_get_bar_region == NULL) {
413*49ef7e06SGarrett D'Amore 		rc = ENOTSUP;
414*49ef7e06SGarrett D'Amore 		goto fail1;
415*49ef7e06SGarrett D'Amore 	}
416*49ef7e06SGarrett D'Amore 	if ((rc = (enop->eno_get_bar_region)(enp,
417*49ef7e06SGarrett D'Amore 		    region, offsetp, sizep)) != 0) {
418*49ef7e06SGarrett D'Amore 		goto fail2;
419*49ef7e06SGarrett D'Amore 	}
420*49ef7e06SGarrett D'Amore 
421*49ef7e06SGarrett D'Amore 	return (0);
422*49ef7e06SGarrett D'Amore 
423*49ef7e06SGarrett D'Amore fail2:
424*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
425*49ef7e06SGarrett D'Amore 
426*49ef7e06SGarrett D'Amore fail1:
427*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
428*49ef7e06SGarrett D'Amore 
429*49ef7e06SGarrett D'Amore 	return (rc);
430*49ef7e06SGarrett D'Amore }
431*49ef7e06SGarrett D'Amore 
432*49ef7e06SGarrett D'Amore 
433*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_nic_get_vi_pool(__in efx_nic_t * enp,__out uint32_t * evq_countp,__out uint32_t * rxq_countp,__out uint32_t * txq_countp)434*49ef7e06SGarrett D'Amore efx_nic_get_vi_pool(
435*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp,
436*49ef7e06SGarrett D'Amore 	__out		uint32_t *evq_countp,
437*49ef7e06SGarrett D'Amore 	__out		uint32_t *rxq_countp,
438*49ef7e06SGarrett D'Amore 	__out		uint32_t *txq_countp)
439*49ef7e06SGarrett D'Amore {
440*49ef7e06SGarrett D'Amore 	const efx_nic_ops_t *enop = enp->en_enop;
441*49ef7e06SGarrett D'Amore 	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
442*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
443*49ef7e06SGarrett D'Amore 
444*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
445*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
446*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
447*49ef7e06SGarrett D'Amore 
448*49ef7e06SGarrett D'Amore 	if (enop->eno_get_vi_pool != NULL) {
449*49ef7e06SGarrett D'Amore 		uint32_t vi_count = 0;
450*49ef7e06SGarrett D'Amore 
451*49ef7e06SGarrett D'Amore 		if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0)
452*49ef7e06SGarrett D'Amore 			goto fail1;
453*49ef7e06SGarrett D'Amore 
454*49ef7e06SGarrett D'Amore 		*evq_countp = vi_count;
455*49ef7e06SGarrett D'Amore 		*rxq_countp = vi_count;
456*49ef7e06SGarrett D'Amore 		*txq_countp = vi_count;
457*49ef7e06SGarrett D'Amore 	} else {
458*49ef7e06SGarrett D'Amore 		/* Use NIC limits as default value */
459*49ef7e06SGarrett D'Amore 		*evq_countp = encp->enc_evq_limit;
460*49ef7e06SGarrett D'Amore 		*rxq_countp = encp->enc_rxq_limit;
461*49ef7e06SGarrett D'Amore 		*txq_countp = encp->enc_txq_limit;
462*49ef7e06SGarrett D'Amore 	}
463*49ef7e06SGarrett D'Amore 
464*49ef7e06SGarrett D'Amore 	return (0);
465*49ef7e06SGarrett D'Amore 
466*49ef7e06SGarrett D'Amore fail1:
467*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
468*49ef7e06SGarrett D'Amore 
469*49ef7e06SGarrett D'Amore 	return (rc);
470*49ef7e06SGarrett D'Amore }
471*49ef7e06SGarrett D'Amore 
472*49ef7e06SGarrett D'Amore 
473*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_nic_init(__in efx_nic_t * enp)474*49ef7e06SGarrett D'Amore efx_nic_init(
475*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp)
476*49ef7e06SGarrett D'Amore {
477*49ef7e06SGarrett D'Amore 	const efx_nic_ops_t *enop = enp->en_enop;
478*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
479*49ef7e06SGarrett D'Amore 
480*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
481*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
482*49ef7e06SGarrett D'Amore 
483*49ef7e06SGarrett D'Amore 	if (enp->en_mod_flags & EFX_MOD_NIC) {
484*49ef7e06SGarrett D'Amore 		rc = EINVAL;
485*49ef7e06SGarrett D'Amore 		goto fail1;
486*49ef7e06SGarrett D'Amore 	}
487*49ef7e06SGarrett D'Amore 
488*49ef7e06SGarrett D'Amore 	if ((rc = enop->eno_init(enp)) != 0)
489*49ef7e06SGarrett D'Amore 		goto fail2;
490*49ef7e06SGarrett D'Amore 
491*49ef7e06SGarrett D'Amore 	enp->en_mod_flags |= EFX_MOD_NIC;
492*49ef7e06SGarrett D'Amore 
493*49ef7e06SGarrett D'Amore 	return (0);
494*49ef7e06SGarrett D'Amore 
495*49ef7e06SGarrett D'Amore fail2:
496*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
497*49ef7e06SGarrett D'Amore fail1:
498*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
499*49ef7e06SGarrett D'Amore 
500*49ef7e06SGarrett D'Amore 	return (rc);
501*49ef7e06SGarrett D'Amore }
502*49ef7e06SGarrett D'Amore 
503*49ef7e06SGarrett D'Amore 			void
efx_nic_fini(__in efx_nic_t * enp)504*49ef7e06SGarrett D'Amore efx_nic_fini(
505*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp)
506*49ef7e06SGarrett D'Amore {
507*49ef7e06SGarrett D'Amore 	const efx_nic_ops_t *enop = enp->en_enop;
508*49ef7e06SGarrett D'Amore 
509*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
510*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
511*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC);
512*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
513*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
514*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
515*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
516*49ef7e06SGarrett D'Amore 
517*49ef7e06SGarrett D'Amore 	enop->eno_fini(enp);
518*49ef7e06SGarrett D'Amore 
519*49ef7e06SGarrett D'Amore 	enp->en_mod_flags &= ~EFX_MOD_NIC;
520*49ef7e06SGarrett D'Amore }
521*49ef7e06SGarrett D'Amore 
522*49ef7e06SGarrett D'Amore 			void
efx_nic_unprobe(__in efx_nic_t * enp)523*49ef7e06SGarrett D'Amore efx_nic_unprobe(
524*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp)
525*49ef7e06SGarrett D'Amore {
526*49ef7e06SGarrett D'Amore 	const efx_nic_ops_t *enop = enp->en_enop;
527*49ef7e06SGarrett D'Amore 
528*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
529*49ef7e06SGarrett D'Amore #if EFSYS_OPT_MCDI
530*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
531*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_MCDI */
532*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
533*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
534*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
535*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
536*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
537*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
538*49ef7e06SGarrett D'Amore 
539*49ef7e06SGarrett D'Amore 	efx_phy_unprobe(enp);
540*49ef7e06SGarrett D'Amore 
541*49ef7e06SGarrett D'Amore 	enop->eno_unprobe(enp);
542*49ef7e06SGarrett D'Amore 
543*49ef7e06SGarrett D'Amore 	enp->en_mod_flags &= ~EFX_MOD_PROBE;
544*49ef7e06SGarrett D'Amore }
545*49ef7e06SGarrett D'Amore 
546*49ef7e06SGarrett D'Amore 			void
efx_nic_destroy(__in efx_nic_t * enp)547*49ef7e06SGarrett D'Amore efx_nic_destroy(
548*49ef7e06SGarrett D'Amore 	__in	efx_nic_t *enp)
549*49ef7e06SGarrett D'Amore {
550*49ef7e06SGarrett D'Amore 	efsys_identifier_t *esip = enp->en_esip;
551*49ef7e06SGarrett D'Amore 
552*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
553*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
554*49ef7e06SGarrett D'Amore 
555*49ef7e06SGarrett D'Amore 	enp->en_family = 0;
556*49ef7e06SGarrett D'Amore 	enp->en_esip = NULL;
557*49ef7e06SGarrett D'Amore 	enp->en_esbp = NULL;
558*49ef7e06SGarrett D'Amore 	enp->en_eslp = NULL;
559*49ef7e06SGarrett D'Amore 
560*49ef7e06SGarrett D'Amore 	enp->en_enop = NULL;
561*49ef7e06SGarrett D'Amore 
562*49ef7e06SGarrett D'Amore 	enp->en_magic = 0;
563*49ef7e06SGarrett D'Amore 
564*49ef7e06SGarrett D'Amore 	/* Free the NIC object */
565*49ef7e06SGarrett D'Amore 	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
566*49ef7e06SGarrett D'Amore }
567*49ef7e06SGarrett D'Amore 
568*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_nic_reset(__in efx_nic_t * enp)569*49ef7e06SGarrett D'Amore efx_nic_reset(
570*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp)
571*49ef7e06SGarrett D'Amore {
572*49ef7e06SGarrett D'Amore 	const efx_nic_ops_t *enop = enp->en_enop;
573*49ef7e06SGarrett D'Amore 	unsigned int mod_flags;
574*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
575*49ef7e06SGarrett D'Amore 
576*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
577*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
578*49ef7e06SGarrett D'Amore 	/*
579*49ef7e06SGarrett D'Amore 	 * All modules except the MCDI, PROBE, NVRAM, VPD, MON, LIC
580*49ef7e06SGarrett D'Amore 	 * (which we do not reset here) must have been shut down or never
581*49ef7e06SGarrett D'Amore 	 * initialized.
582*49ef7e06SGarrett D'Amore 	 *
583*49ef7e06SGarrett D'Amore 	 * A rule of thumb here is: If the controller or MC reboots, is *any*
584*49ef7e06SGarrett D'Amore 	 * state lost. If it's lost and needs reapplying, then the module
585*49ef7e06SGarrett D'Amore 	 * *must* not be initialised during the reset.
586*49ef7e06SGarrett D'Amore 	 */
587*49ef7e06SGarrett D'Amore 	mod_flags = enp->en_mod_flags;
588*49ef7e06SGarrett D'Amore 	mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM |
589*49ef7e06SGarrett D'Amore 		    EFX_MOD_VPD | EFX_MOD_MON | EFX_MOD_LIC);
590*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(mod_flags, ==, 0);
591*49ef7e06SGarrett D'Amore 	if (mod_flags != 0) {
592*49ef7e06SGarrett D'Amore 		rc = EINVAL;
593*49ef7e06SGarrett D'Amore 		goto fail1;
594*49ef7e06SGarrett D'Amore 	}
595*49ef7e06SGarrett D'Amore 
596*49ef7e06SGarrett D'Amore 	if ((rc = enop->eno_reset(enp)) != 0)
597*49ef7e06SGarrett D'Amore 		goto fail2;
598*49ef7e06SGarrett D'Amore 
599*49ef7e06SGarrett D'Amore 	return (0);
600*49ef7e06SGarrett D'Amore 
601*49ef7e06SGarrett D'Amore fail2:
602*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
603*49ef7e06SGarrett D'Amore fail1:
604*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
605*49ef7e06SGarrett D'Amore 
606*49ef7e06SGarrett D'Amore 	return (rc);
607*49ef7e06SGarrett D'Amore }
608*49ef7e06SGarrett D'Amore 
609*49ef7e06SGarrett D'Amore 			const efx_nic_cfg_t *
efx_nic_cfg_get(__in efx_nic_t * enp)610*49ef7e06SGarrett D'Amore efx_nic_cfg_get(
611*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp)
612*49ef7e06SGarrett D'Amore {
613*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
614*49ef7e06SGarrett D'Amore 
615*49ef7e06SGarrett D'Amore 	return (&(enp->en_nic_cfg));
616*49ef7e06SGarrett D'Amore }
617*49ef7e06SGarrett D'Amore 
618*49ef7e06SGarrett D'Amore #if EFSYS_OPT_DIAG
619*49ef7e06SGarrett D'Amore 
620*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_nic_register_test(__in efx_nic_t * enp)621*49ef7e06SGarrett D'Amore efx_nic_register_test(
622*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp)
623*49ef7e06SGarrett D'Amore {
624*49ef7e06SGarrett D'Amore 	const efx_nic_ops_t *enop = enp->en_enop;
625*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
626*49ef7e06SGarrett D'Amore 
627*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
628*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
629*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
630*49ef7e06SGarrett D'Amore 
631*49ef7e06SGarrett D'Amore 	if ((rc = enop->eno_register_test(enp)) != 0)
632*49ef7e06SGarrett D'Amore 		goto fail1;
633*49ef7e06SGarrett D'Amore 
634*49ef7e06SGarrett D'Amore 	return (0);
635*49ef7e06SGarrett D'Amore 
636*49ef7e06SGarrett D'Amore fail1:
637*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
638*49ef7e06SGarrett D'Amore 
639*49ef7e06SGarrett D'Amore 	return (rc);
640*49ef7e06SGarrett D'Amore }
641*49ef7e06SGarrett D'Amore 
642*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_nic_test_registers(__in efx_nic_t * enp,__in efx_register_set_t * rsp,__in size_t count)643*49ef7e06SGarrett D'Amore efx_nic_test_registers(
644*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp,
645*49ef7e06SGarrett D'Amore 	__in		efx_register_set_t *rsp,
646*49ef7e06SGarrett D'Amore 	__in		size_t count)
647*49ef7e06SGarrett D'Amore {
648*49ef7e06SGarrett D'Amore 	unsigned int bit;
649*49ef7e06SGarrett D'Amore 	efx_oword_t original;
650*49ef7e06SGarrett D'Amore 	efx_oword_t reg;
651*49ef7e06SGarrett D'Amore 	efx_oword_t buf;
652*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
653*49ef7e06SGarrett D'Amore 
654*49ef7e06SGarrett D'Amore 	while (count > 0) {
655*49ef7e06SGarrett D'Amore 		/* This function is only suitable for registers */
656*49ef7e06SGarrett D'Amore 		EFSYS_ASSERT(rsp->rows == 1);
657*49ef7e06SGarrett D'Amore 
658*49ef7e06SGarrett D'Amore 		/* bit sweep on and off */
659*49ef7e06SGarrett D'Amore 		EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original,
660*49ef7e06SGarrett D'Amore 			    B_TRUE);
661*49ef7e06SGarrett D'Amore 		for (bit = 0; bit < 128; bit++) {
662*49ef7e06SGarrett D'Amore 			/* Is this bit in the mask? */
663*49ef7e06SGarrett D'Amore 			if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit))
664*49ef7e06SGarrett D'Amore 				continue;
665*49ef7e06SGarrett D'Amore 
666*49ef7e06SGarrett D'Amore 			/* Test this bit can be set in isolation */
667*49ef7e06SGarrett D'Amore 			reg = original;
668*49ef7e06SGarrett D'Amore 			EFX_AND_OWORD(reg, rsp->mask);
669*49ef7e06SGarrett D'Amore 			EFX_SET_OWORD_BIT(reg, bit);
670*49ef7e06SGarrett D'Amore 
671*49ef7e06SGarrett D'Amore 			EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
672*49ef7e06SGarrett D'Amore 				    B_TRUE);
673*49ef7e06SGarrett D'Amore 			EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
674*49ef7e06SGarrett D'Amore 				    B_TRUE);
675*49ef7e06SGarrett D'Amore 
676*49ef7e06SGarrett D'Amore 			EFX_AND_OWORD(buf, rsp->mask);
677*49ef7e06SGarrett D'Amore 			if (memcmp(&reg, &buf, sizeof (reg))) {
678*49ef7e06SGarrett D'Amore 				rc = EIO;
679*49ef7e06SGarrett D'Amore 				goto fail1;
680*49ef7e06SGarrett D'Amore 			}
681*49ef7e06SGarrett D'Amore 
682*49ef7e06SGarrett D'Amore 			/* Test this bit can be cleared in isolation */
683*49ef7e06SGarrett D'Amore 			EFX_OR_OWORD(reg, rsp->mask);
684*49ef7e06SGarrett D'Amore 			EFX_CLEAR_OWORD_BIT(reg, bit);
685*49ef7e06SGarrett D'Amore 
686*49ef7e06SGarrett D'Amore 			EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
687*49ef7e06SGarrett D'Amore 				    B_TRUE);
688*49ef7e06SGarrett D'Amore 			EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
689*49ef7e06SGarrett D'Amore 				    B_TRUE);
690*49ef7e06SGarrett D'Amore 
691*49ef7e06SGarrett D'Amore 			EFX_AND_OWORD(buf, rsp->mask);
692*49ef7e06SGarrett D'Amore 			if (memcmp(&reg, &buf, sizeof (reg))) {
693*49ef7e06SGarrett D'Amore 				rc = EIO;
694*49ef7e06SGarrett D'Amore 				goto fail2;
695*49ef7e06SGarrett D'Amore 			}
696*49ef7e06SGarrett D'Amore 		}
697*49ef7e06SGarrett D'Amore 
698*49ef7e06SGarrett D'Amore 		/* Restore the old value */
699*49ef7e06SGarrett D'Amore 		EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original,
700*49ef7e06SGarrett D'Amore 			    B_TRUE);
701*49ef7e06SGarrett D'Amore 
702*49ef7e06SGarrett D'Amore 		--count;
703*49ef7e06SGarrett D'Amore 		++rsp;
704*49ef7e06SGarrett D'Amore 	}
705*49ef7e06SGarrett D'Amore 
706*49ef7e06SGarrett D'Amore 	return (0);
707*49ef7e06SGarrett D'Amore 
708*49ef7e06SGarrett D'Amore fail2:
709*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
710*49ef7e06SGarrett D'Amore fail1:
711*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
712*49ef7e06SGarrett D'Amore 
713*49ef7e06SGarrett D'Amore 	/* Restore the old value */
714*49ef7e06SGarrett D'Amore 	EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE);
715*49ef7e06SGarrett D'Amore 
716*49ef7e06SGarrett D'Amore 	return (rc);
717*49ef7e06SGarrett D'Amore }
718*49ef7e06SGarrett D'Amore 
719*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_nic_test_tables(__in efx_nic_t * enp,__in efx_register_set_t * rsp,__in efx_pattern_type_t pattern,__in size_t count)720*49ef7e06SGarrett D'Amore efx_nic_test_tables(
721*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp,
722*49ef7e06SGarrett D'Amore 	__in		efx_register_set_t *rsp,
723*49ef7e06SGarrett D'Amore 	__in		efx_pattern_type_t pattern,
724*49ef7e06SGarrett D'Amore 	__in		size_t count)
725*49ef7e06SGarrett D'Amore {
726*49ef7e06SGarrett D'Amore 	efx_sram_pattern_fn_t func;
727*49ef7e06SGarrett D'Amore 	unsigned int index;
728*49ef7e06SGarrett D'Amore 	unsigned int address;
729*49ef7e06SGarrett D'Amore 	efx_oword_t reg;
730*49ef7e06SGarrett D'Amore 	efx_oword_t buf;
731*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
732*49ef7e06SGarrett D'Amore 
733*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES);
734*49ef7e06SGarrett D'Amore 	func = __efx_sram_pattern_fns[pattern];
735*49ef7e06SGarrett D'Amore 
736*49ef7e06SGarrett D'Amore 	while (count > 0) {
737*49ef7e06SGarrett D'Amore 		/* Write */
738*49ef7e06SGarrett D'Amore 		address = rsp->address;
739*49ef7e06SGarrett D'Amore 		for (index = 0; index < rsp->rows; ++index) {
740*49ef7e06SGarrett D'Amore 			func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
741*49ef7e06SGarrett D'Amore 			func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
742*49ef7e06SGarrett D'Amore 			EFX_AND_OWORD(reg, rsp->mask);
743*49ef7e06SGarrett D'Amore 			EFSYS_BAR_WRITEO(enp->en_esbp, address, &reg, B_TRUE);
744*49ef7e06SGarrett D'Amore 
745*49ef7e06SGarrett D'Amore 			address += rsp->step;
746*49ef7e06SGarrett D'Amore 		}
747*49ef7e06SGarrett D'Amore 
748*49ef7e06SGarrett D'Amore 		/* Read */
749*49ef7e06SGarrett D'Amore 		address = rsp->address;
750*49ef7e06SGarrett D'Amore 		for (index = 0; index < rsp->rows; ++index) {
751*49ef7e06SGarrett D'Amore 			func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
752*49ef7e06SGarrett D'Amore 			func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
753*49ef7e06SGarrett D'Amore 			EFX_AND_OWORD(reg, rsp->mask);
754*49ef7e06SGarrett D'Amore 			EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE);
755*49ef7e06SGarrett D'Amore 			if (memcmp(&reg, &buf, sizeof (reg))) {
756*49ef7e06SGarrett D'Amore 				rc = EIO;
757*49ef7e06SGarrett D'Amore 				goto fail1;
758*49ef7e06SGarrett D'Amore 			}
759*49ef7e06SGarrett D'Amore 
760*49ef7e06SGarrett D'Amore 			address += rsp->step;
761*49ef7e06SGarrett D'Amore 		}
762*49ef7e06SGarrett D'Amore 
763*49ef7e06SGarrett D'Amore 		++rsp;
764*49ef7e06SGarrett D'Amore 		--count;
765*49ef7e06SGarrett D'Amore 	}
766*49ef7e06SGarrett D'Amore 
767*49ef7e06SGarrett D'Amore 	return (0);
768*49ef7e06SGarrett D'Amore 
769*49ef7e06SGarrett D'Amore fail1:
770*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
771*49ef7e06SGarrett D'Amore 
772*49ef7e06SGarrett D'Amore 	return (rc);
773*49ef7e06SGarrett D'Amore }
774*49ef7e06SGarrett D'Amore 
775*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_DIAG */
776*49ef7e06SGarrett D'Amore 
777*49ef7e06SGarrett D'Amore #if EFSYS_OPT_LOOPBACK
778*49ef7e06SGarrett D'Amore 
779*49ef7e06SGarrett D'Amore extern			void
efx_loopback_mask(__in efx_loopback_kind_t loopback_kind,__out efx_qword_t * maskp)780*49ef7e06SGarrett D'Amore efx_loopback_mask(
781*49ef7e06SGarrett D'Amore 	__in	efx_loopback_kind_t loopback_kind,
782*49ef7e06SGarrett D'Amore 	__out	efx_qword_t *maskp)
783*49ef7e06SGarrett D'Amore {
784*49ef7e06SGarrett D'Amore 	efx_qword_t mask;
785*49ef7e06SGarrett D'Amore 
786*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS);
787*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(maskp != NULL);
788*49ef7e06SGarrett D'Amore 
789*49ef7e06SGarrett D'Amore 	/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
790*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
791*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
792*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
793*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
794*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
795*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
796*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
797*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
798*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
799*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
800*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
801*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
802*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
803*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
804*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
805*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
806*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
807*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
808*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT);
809*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS);
810*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS);
811*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR ==
812*49ef7e06SGarrett D'Amore 	    EFX_LOOPBACK_XAUI_WS_FAR);
813*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR ==
814*49ef7e06SGarrett D'Amore 	    EFX_LOOPBACK_XAUI_WS_NEAR);
815*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS);
816*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS);
817*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR ==
818*49ef7e06SGarrett D'Amore 	    EFX_LOOPBACK_XFI_WS_FAR);
819*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS);
820*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT);
821*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR);
822*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR);
823*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS ==
824*49ef7e06SGarrett D'Amore 	    EFX_LOOPBACK_PMA_INT_WS);
825*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS ==
826*49ef7e06SGarrett D'Amore 	    EFX_LOOPBACK_SD_FEP2_WS);
827*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS ==
828*49ef7e06SGarrett D'Amore 	    EFX_LOOPBACK_SD_FEP1_5_WS);
829*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS);
830*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS);
831*49ef7e06SGarrett D'Amore 
832*49ef7e06SGarrett D'Amore 	/* Build bitmask of possible loopback types */
833*49ef7e06SGarrett D'Amore 	EFX_ZERO_QWORD(mask);
834*49ef7e06SGarrett D'Amore 
835*49ef7e06SGarrett D'Amore 	if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) ||
836*49ef7e06SGarrett D'Amore 	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
837*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF);
838*49ef7e06SGarrett D'Amore 	}
839*49ef7e06SGarrett D'Amore 
840*49ef7e06SGarrett D'Amore 	if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) ||
841*49ef7e06SGarrett D'Amore 	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
842*49ef7e06SGarrett D'Amore 		/*
843*49ef7e06SGarrett D'Amore 		 * The "MAC" grouping has historically been used by drivers to
844*49ef7e06SGarrett D'Amore 		 * mean loopbacks supported by on-chip hardware. Keep that
845*49ef7e06SGarrett D'Amore 		 * meaning here, and include on-chip PHY layer loopbacks.
846*49ef7e06SGarrett D'Amore 		 */
847*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA);
848*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC);
849*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII);
850*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS);
851*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI);
852*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII);
853*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII);
854*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR);
855*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI);
856*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR);
857*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR);
858*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR);
859*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR);
860*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT);
861*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR);
862*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR);
863*49ef7e06SGarrett D'Amore 	}
864*49ef7e06SGarrett D'Amore 
865*49ef7e06SGarrett D'Amore 	if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) ||
866*49ef7e06SGarrett D'Amore 	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
867*49ef7e06SGarrett D'Amore 		/*
868*49ef7e06SGarrett D'Amore 		 * The "PHY" grouping has historically been used by drivers to
869*49ef7e06SGarrett D'Amore 		 * mean loopbacks supported by off-chip hardware. Keep that
870*49ef7e06SGarrett D'Amore 		 * meaning here.
871*49ef7e06SGarrett D'Amore 		 */
872*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY);
873*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask,	EFX_LOOPBACK_PHY_XS);
874*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS);
875*49ef7e06SGarrett D'Amore 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD);
876*49ef7e06SGarrett D'Amore 	}
877*49ef7e06SGarrett D'Amore 
878*49ef7e06SGarrett D'Amore 	*maskp = mask;
879*49ef7e06SGarrett D'Amore }
880*49ef7e06SGarrett D'Amore 
881*49ef7e06SGarrett D'Amore 	__checkReturn	efx_rc_t
efx_mcdi_get_loopback_modes(__in efx_nic_t * enp)882*49ef7e06SGarrett D'Amore efx_mcdi_get_loopback_modes(
883*49ef7e06SGarrett D'Amore 	__in		efx_nic_t *enp)
884*49ef7e06SGarrett D'Amore {
885*49ef7e06SGarrett D'Amore 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
886*49ef7e06SGarrett D'Amore 	efx_mcdi_req_t req;
887*49ef7e06SGarrett D'Amore 	uint8_t payload[MAX(MC_CMD_GET_LOOPBACK_MODES_IN_LEN,
888*49ef7e06SGarrett D'Amore 			    MC_CMD_GET_LOOPBACK_MODES_OUT_LEN)];
889*49ef7e06SGarrett D'Amore 	efx_qword_t mask;
890*49ef7e06SGarrett D'Amore 	efx_qword_t modes;
891*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
892*49ef7e06SGarrett D'Amore 
893*49ef7e06SGarrett D'Amore 	(void) memset(payload, 0, sizeof (payload));
894*49ef7e06SGarrett D'Amore 	req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES;
895*49ef7e06SGarrett D'Amore 	req.emr_in_buf = payload;
896*49ef7e06SGarrett D'Amore 	req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN;
897*49ef7e06SGarrett D'Amore 	req.emr_out_buf = payload;
898*49ef7e06SGarrett D'Amore 	req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN;
899*49ef7e06SGarrett D'Amore 
900*49ef7e06SGarrett D'Amore 	efx_mcdi_execute(enp, &req);
901*49ef7e06SGarrett D'Amore 
902*49ef7e06SGarrett D'Amore 	if (req.emr_rc != 0) {
903*49ef7e06SGarrett D'Amore 		rc = req.emr_rc;
904*49ef7e06SGarrett D'Amore 		goto fail1;
905*49ef7e06SGarrett D'Amore 	}
906*49ef7e06SGarrett D'Amore 
907*49ef7e06SGarrett D'Amore 	if (req.emr_out_length_used <
908*49ef7e06SGarrett D'Amore 	    MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST +
909*49ef7e06SGarrett D'Amore 	    MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) {
910*49ef7e06SGarrett D'Amore 		rc = EMSGSIZE;
911*49ef7e06SGarrett D'Amore 		goto fail2;
912*49ef7e06SGarrett D'Amore 	}
913*49ef7e06SGarrett D'Amore 
914*49ef7e06SGarrett D'Amore 	/*
915*49ef7e06SGarrett D'Amore 	 * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree
916*49ef7e06SGarrett D'Amore 	 * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link().
917*49ef7e06SGarrett D'Amore 	 */
918*49ef7e06SGarrett D'Amore 	efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask);
919*49ef7e06SGarrett D'Amore 
920*49ef7e06SGarrett D'Amore 	EFX_AND_QWORD(mask,
921*49ef7e06SGarrett D'Amore 	    *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED));
922*49ef7e06SGarrett D'Amore 
923*49ef7e06SGarrett D'Amore 	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M);
924*49ef7e06SGarrett D'Amore 	EFX_AND_QWORD(modes, mask);
925*49ef7e06SGarrett D'Amore 	encp->enc_loopback_types[EFX_LINK_100FDX] = modes;
926*49ef7e06SGarrett D'Amore 
927*49ef7e06SGarrett D'Amore 	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G);
928*49ef7e06SGarrett D'Amore 	EFX_AND_QWORD(modes, mask);
929*49ef7e06SGarrett D'Amore 	encp->enc_loopback_types[EFX_LINK_1000FDX] = modes;
930*49ef7e06SGarrett D'Amore 
931*49ef7e06SGarrett D'Amore 	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G);
932*49ef7e06SGarrett D'Amore 	EFX_AND_QWORD(modes, mask);
933*49ef7e06SGarrett D'Amore 	encp->enc_loopback_types[EFX_LINK_10000FDX] = modes;
934*49ef7e06SGarrett D'Amore 
935*49ef7e06SGarrett D'Amore 	if (req.emr_out_length_used >=
936*49ef7e06SGarrett D'Amore 	    MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST +
937*49ef7e06SGarrett D'Amore 	    MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) {
938*49ef7e06SGarrett D'Amore 		/* Response includes 40G loopback modes */
939*49ef7e06SGarrett D'Amore 		modes =
940*49ef7e06SGarrett D'Amore 		    *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G);
941*49ef7e06SGarrett D'Amore 		EFX_AND_QWORD(modes, mask);
942*49ef7e06SGarrett D'Amore 		encp->enc_loopback_types[EFX_LINK_40000FDX] = modes;
943*49ef7e06SGarrett D'Amore 	}
944*49ef7e06SGarrett D'Amore 
945*49ef7e06SGarrett D'Amore 	EFX_ZERO_QWORD(modes);
946*49ef7e06SGarrett D'Amore 	EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF);
947*49ef7e06SGarrett D'Amore 	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]);
948*49ef7e06SGarrett D'Amore 	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]);
949*49ef7e06SGarrett D'Amore 	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]);
950*49ef7e06SGarrett D'Amore 	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]);
951*49ef7e06SGarrett D'Amore 	encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes;
952*49ef7e06SGarrett D'Amore 
953*49ef7e06SGarrett D'Amore 	return (0);
954*49ef7e06SGarrett D'Amore 
955*49ef7e06SGarrett D'Amore fail2:
956*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
957*49ef7e06SGarrett D'Amore fail1:
958*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
959*49ef7e06SGarrett D'Amore 
960*49ef7e06SGarrett D'Amore 	return (rc);
961*49ef7e06SGarrett D'Amore }
962*49ef7e06SGarrett D'Amore 
963*49ef7e06SGarrett D'Amore #endif /* EFSYS_OPT_LOOPBACK */
964