efx_nic.c revision 299517
1206084Srdivacky/*-
2206084Srdivacky * Copyright (c) 2007-2015 Solarflare Communications Inc.
3206084Srdivacky * All rights reserved.
4206084Srdivacky *
5206084Srdivacky * Redistribution and use in source and binary forms, with or without
6206084Srdivacky * modification, are permitted provided that the following conditions are met:
7206084Srdivacky *
8206084Srdivacky * 1. Redistributions of source code must retain the above copyright notice,
9206084Srdivacky *    this list of conditions and the following disclaimer.
10206084Srdivacky * 2. Redistributions in binary form must reproduce the above copyright notice,
11206084Srdivacky *    this list of conditions and the following disclaimer in the documentation
12206084Srdivacky *    and/or other materials provided with the distribution.
13206084Srdivacky *
14206084Srdivacky * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15206084Srdivacky * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16206084Srdivacky * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17206084Srdivacky * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18206084Srdivacky * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19206084Srdivacky * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20206084Srdivacky * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21206084Srdivacky * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22206084Srdivacky * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23204793Srdivacky * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24204793Srdivacky * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25204793Srdivacky *
26204793Srdivacky * The views and conclusions contained in the software and documentation are
27204793Srdivacky * those of the authors and should not be interpreted as representing official
28204793Srdivacky * policies, either expressed or implied, of the FreeBSD Project.
29204793Srdivacky */
30204793Srdivacky
31204793Srdivacky#include <sys/cdefs.h>
32204793Srdivacky__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/efx_nic.c 299517 2016-05-12 06:19:06Z arybchik $");
33204793Srdivacky
34204793Srdivacky#include "efx.h"
35204793Srdivacky#include "efx_impl.h"
36204793Srdivacky
37204793Srdivacky	__checkReturn	efx_rc_t
38204793Srdivackyefx_family(
39204793Srdivacky	__in		uint16_t venid,
40204793Srdivacky	__in		uint16_t devid,
41204793Srdivacky	__out		efx_family_t *efp)
42204793Srdivacky{
43204793Srdivacky	if (venid == EFX_PCI_VENID_SFC) {
44204793Srdivacky		switch (devid) {
45204793Srdivacky#if EFSYS_OPT_SIENA
46204793Srdivacky		case EFX_PCI_DEVID_SIENA_F1_UNINIT:
47204793Srdivacky			/*
48204962Srdivacky			 * Hardware default for PF0 of uninitialised Siena.
49204793Srdivacky			 * manftest must be able to cope with this device id.
50204793Srdivacky			 */
51204793Srdivacky			*efp = EFX_FAMILY_SIENA;
52204793Srdivacky			return (0);
53204793Srdivacky
54204793Srdivacky		case EFX_PCI_DEVID_BETHPAGE:
55204793Srdivacky		case EFX_PCI_DEVID_SIENA:
56204793Srdivacky			*efp = EFX_FAMILY_SIENA;
57204793Srdivacky			return (0);
58204793Srdivacky#endif /* EFSYS_OPT_SIENA */
59204793Srdivacky
60234353Sdim#if EFSYS_OPT_HUNTINGTON
61234353Sdim		case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT:
62234353Sdim			/*
63204793Srdivacky			 * Hardware default for PF0 of uninitialised Huntington.
64234353Sdim			 * manftest must be able to cope with this device id.
65234353Sdim			 */
66234353Sdim			*efp = EFX_FAMILY_HUNTINGTON;
67234353Sdim			return (0);
68234353Sdim
69234353Sdim		case EFX_PCI_DEVID_FARMINGDALE:
70234353Sdim		case EFX_PCI_DEVID_GREENPORT:
71234353Sdim			*efp = EFX_FAMILY_HUNTINGTON;
72234353Sdim			return (0);
73234353Sdim
74234353Sdim		case EFX_PCI_DEVID_FARMINGDALE_VF:
75234353Sdim		case EFX_PCI_DEVID_GREENPORT_VF:
76234353Sdim			*efp = EFX_FAMILY_HUNTINGTON;
77234353Sdim			return (0);
78204793Srdivacky#endif /* EFSYS_OPT_HUNTINGTON */
79234353Sdim
80234353Sdim#if EFSYS_OPT_MEDFORD
81234353Sdim		case EFX_PCI_DEVID_MEDFORD_PF_UNINIT:
82234353Sdim			/*
83204793Srdivacky			 * Hardware default for PF0 of uninitialised Medford.
84234353Sdim			 * manftest must be able to cope with this device id.
85234353Sdim			 */
86234353Sdim			*efp = EFX_FAMILY_MEDFORD;
87234353Sdim			return (0);
88204793Srdivacky
89206084Srdivacky		case EFX_PCI_DEVID_MEDFORD:
90204793Srdivacky			*efp = EFX_FAMILY_MEDFORD;
91204793Srdivacky			return (0);
92204793Srdivacky
93204793Srdivacky		case EFX_PCI_DEVID_MEDFORD_VF:
94204793Srdivacky			*efp = EFX_FAMILY_MEDFORD;
95204793Srdivacky			return (0);
96206084Srdivacky#endif /* EFSYS_OPT_MEDFORD */
97204793Srdivacky
98204793Srdivacky		case EFX_PCI_DEVID_FALCON:	/* Obsolete, not supported */
99204793Srdivacky		default:
100204793Srdivacky			break;
101204793Srdivacky		}
102204793Srdivacky	}
103206084Srdivacky
104204793Srdivacky	*efp = EFX_FAMILY_INVALID;
105204793Srdivacky	return (ENOTSUP);
106204793Srdivacky}
107204793Srdivacky
108204793Srdivacky
109204793Srdivacky#define	EFX_BIU_MAGIC0	0x01234567
110234353Sdim#define	EFX_BIU_MAGIC1	0xfedcba98
111234353Sdim
112234353Sdim	__checkReturn	efx_rc_t
113234353Sdimefx_nic_biu_test(
114204793Srdivacky	__in		efx_nic_t *enp)
115204962Srdivacky{
116206084Srdivacky	efx_oword_t oword;
117204962Srdivacky	efx_rc_t rc;
118204962Srdivacky
119206084Srdivacky	/*
120204962Srdivacky	 * Write magic values to scratch registers 0 and 1, then
121204962Srdivacky	 * verify that the values were written correctly.  Interleave
122206084Srdivacky	 * the accesses to ensure that the BIU is not just reading
123204962Srdivacky	 * back the cached value that was last written.
124204962Srdivacky	 */
125204962Srdivacky	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
126204962Srdivacky	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
127204962Srdivacky
128204962Srdivacky	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
129234353Sdim	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
130234353Sdim
131234353Sdim	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
132234353Sdim	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) {
133204962Srdivacky		rc = EIO;
134234353Sdim		goto fail1;
135234353Sdim	}
136234353Sdim
137234353Sdim	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
138234353Sdim	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) {
139204962Srdivacky		rc = EIO;
140206084Srdivacky		goto fail2;
141204962Srdivacky	}
142204962Srdivacky
143204962Srdivacky	/*
144204962Srdivacky	 * Perform the same test, with the values swapped.  This
145204962Srdivacky	 * ensures that subsequent tests don't start with the correct
146204962Srdivacky	 * values already written into the scratch registers.
147206084Srdivacky	 */
148204962Srdivacky	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
149204962Srdivacky	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
150204962Srdivacky
151204962Srdivacky	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
152204962Srdivacky	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
153206084Srdivacky
154204962Srdivacky	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
155204962Srdivacky	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) {
156204962Srdivacky		rc = EIO;
157204962Srdivacky		goto fail3;
158204962Srdivacky	}
159206084Srdivacky
160204962Srdivacky	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
161204962Srdivacky	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) {
162204962Srdivacky		rc = EIO;
163204962Srdivacky		goto fail4;
164204962Srdivacky	}
165206084Srdivacky
166204962Srdivacky	return (0);
167204962Srdivacky
168204962Srdivackyfail4:
169204962Srdivacky	EFSYS_PROBE(fail4);
170204962Srdivackyfail3:
171206084Srdivacky	EFSYS_PROBE(fail3);
172204962Srdivackyfail2:
173204962Srdivacky	EFSYS_PROBE(fail2);
174204962Srdivackyfail1:
175204962Srdivacky	EFSYS_PROBE1(fail1, efx_rc_t, rc);
176204962Srdivacky
177206084Srdivacky	return (rc);
178204962Srdivacky}
179204962Srdivacky
180204962Srdivacky#if EFSYS_OPT_SIENA
181204962Srdivacky
182204962Srdivackystatic const efx_nic_ops_t	__efx_nic_siena_ops = {
183206084Srdivacky	siena_nic_probe,		/* eno_probe */
184204962Srdivacky	NULL,				/* eno_board_cfg */
185204962Srdivacky	NULL,				/* eno_set_drv_limits */
186204962Srdivacky	siena_nic_reset,		/* eno_reset */
187204962Srdivacky	siena_nic_init,			/* eno_init */
188204962Srdivacky	NULL,				/* eno_get_vi_pool */
189206084Srdivacky	NULL,				/* eno_get_bar_region */
190204962Srdivacky#if EFSYS_OPT_DIAG
191204962Srdivacky	siena_nic_register_test,	/* eno_register_test */
192204962Srdivacky#endif	/* EFSYS_OPT_DIAG */
193204962Srdivacky	siena_nic_fini,			/* eno_fini */
194204962Srdivacky	siena_nic_unprobe,		/* eno_unprobe */
195204962Srdivacky};
196204962Srdivacky
197204962Srdivacky#endif	/* EFSYS_OPT_SIENA */
198249423Sdim
199210299Sed#if EFSYS_OPT_HUNTINGTON
200249423Sdim
201249423Sdimstatic const efx_nic_ops_t	__efx_nic_hunt_ops = {
202204962Srdivacky	ef10_nic_probe,			/* eno_probe */
203204962Srdivacky	hunt_board_cfg,			/* eno_board_cfg */
204204962Srdivacky	ef10_nic_set_drv_limits,	/* eno_set_drv_limits */
205210299Sed	ef10_nic_reset,			/* eno_reset */
206204962Srdivacky	ef10_nic_init,			/* eno_init */
207204962Srdivacky	ef10_nic_get_vi_pool,		/* eno_get_vi_pool */
208204962Srdivacky	ef10_nic_get_bar_region,	/* eno_get_bar_region */
209204962Srdivacky#if EFSYS_OPT_DIAG
210204962Srdivacky	ef10_nic_register_test,		/* eno_register_test */
211204962Srdivacky#endif	/* EFSYS_OPT_DIAG */
212204962Srdivacky	ef10_nic_fini,			/* eno_fini */
213204962Srdivacky	ef10_nic_unprobe,		/* eno_unprobe */
214204962Srdivacky};
215205219Srdivacky
216205219Srdivacky#endif	/* EFSYS_OPT_HUNTINGTON */
217210299Sed
218234353Sdim#if EFSYS_OPT_MEDFORD
219205219Srdivacky
220210299Sedstatic const efx_nic_ops_t	__efx_nic_medford_ops = {
221234353Sdim	ef10_nic_probe,			/* eno_probe */
222205219Srdivacky	medford_board_cfg,		/* eno_board_cfg */
223205219Srdivacky	ef10_nic_set_drv_limits,	/* eno_set_drv_limits */
224210299Sed	ef10_nic_reset,			/* eno_reset */
225234353Sdim	ef10_nic_init,			/* eno_init */
226205219Srdivacky	ef10_nic_get_vi_pool,		/* eno_get_vi_pool */
227205219Srdivacky	ef10_nic_get_bar_region,	/* eno_get_bar_region */
228204962Srdivacky#if EFSYS_OPT_DIAG
229212904Sdim	ef10_nic_register_test,		/* eno_register_test */
230212904Sdim#endif	/* EFSYS_OPT_DIAG */
231212904Sdim	ef10_nic_fini,			/* eno_fini */
232210299Sed	ef10_nic_unprobe,		/* eno_unprobe */
233234353Sdim};
234210299Sed
235234353Sdim#endif	/* EFSYS_OPT_MEDFORD */
236205219Srdivacky
237210299Sed
238234353Sdim	__checkReturn	efx_rc_t
239205219Srdivackyefx_nic_create(
240205219Srdivacky	__in		efx_family_t family,
241205219Srdivacky	__in		efsys_identifier_t *esip,
242206084Srdivacky	__in		efsys_bar_t *esbp,
243205219Srdivacky	__in		efsys_lock_t *eslp,
244205219Srdivacky	__deref_out	efx_nic_t **enpp)
245205219Srdivacky{
246205219Srdivacky	efx_nic_t *enp;
247205219Srdivacky	efx_rc_t rc;
248206084Srdivacky
249205219Srdivacky	EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID);
250205219Srdivacky	EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES);
251205219Srdivacky
252205219Srdivacky	/* Allocate a NIC object */
253205219Srdivacky	EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp);
254206084Srdivacky
255205219Srdivacky	if (enp == NULL) {
256205219Srdivacky		rc = ENOMEM;
257205219Srdivacky		goto fail1;
258205219Srdivacky	}
259205219Srdivacky
260205219Srdivacky	enp->en_magic = EFX_NIC_MAGIC;
261205219Srdivacky
262234353Sdim	switch (family) {
263205219Srdivacky#if EFSYS_OPT_SIENA
264205219Srdivacky	case EFX_FAMILY_SIENA:
265206084Srdivacky		enp->en_enop = &__efx_nic_siena_ops;
266205219Srdivacky		enp->en_features =
267205219Srdivacky		    EFX_FEATURE_IPV6 |
268234353Sdim		    EFX_FEATURE_LFSR_HASH_INSERT |
269205219Srdivacky		    EFX_FEATURE_LINK_EVENTS |
270205219Srdivacky		    EFX_FEATURE_PERIODIC_MAC_STATS |
271205219Srdivacky		    EFX_FEATURE_WOL |
272206084Srdivacky		    EFX_FEATURE_MCDI |
273205219Srdivacky		    EFX_FEATURE_LOOKAHEAD_SPLIT |
274205219Srdivacky		    EFX_FEATURE_MAC_HEADER_FILTERS |
275205219Srdivacky		    EFX_FEATURE_TX_SRC_FILTERS;
276205219Srdivacky		break;
277205219Srdivacky#endif	/* EFSYS_OPT_SIENA */
278206084Srdivacky
279205219Srdivacky#if EFSYS_OPT_HUNTINGTON
280205219Srdivacky	case EFX_FAMILY_HUNTINGTON:
281205219Srdivacky		enp->en_enop = &__efx_nic_hunt_ops;
282205219Srdivacky		/* FIXME: Add WOL support */
283205219Srdivacky		enp->en_features =
284206084Srdivacky		    EFX_FEATURE_IPV6 |
285205219Srdivacky		    EFX_FEATURE_LINK_EVENTS |
286205219Srdivacky		    EFX_FEATURE_PERIODIC_MAC_STATS |
287205219Srdivacky		    EFX_FEATURE_MCDI |
288205219Srdivacky		    EFX_FEATURE_MAC_HEADER_FILTERS |
289205219Srdivacky		    EFX_FEATURE_MCDI_DMA |
290206084Srdivacky		    EFX_FEATURE_PIO_BUFFERS |
291205219Srdivacky		    EFX_FEATURE_FW_ASSISTED_TSO |
292205219Srdivacky		    EFX_FEATURE_FW_ASSISTED_TSO_V2;
293205219Srdivacky		break;
294205219Srdivacky#endif	/* EFSYS_OPT_HUNTINGTON */
295205219Srdivacky
296206084Srdivacky#if EFSYS_OPT_MEDFORD
297205219Srdivacky	case EFX_FAMILY_MEDFORD:
298205219Srdivacky		enp->en_enop = &__efx_nic_medford_ops;
299205219Srdivacky		/*
300205219Srdivacky		 * FW_ASSISTED_TSO omitted as Medford only supports firmware
301205219Srdivacky		 * assisted TSO version 2, not the v1 scheme used on Huntington.
302206084Srdivacky		 */
303205219Srdivacky		enp->en_features =
304205219Srdivacky		    EFX_FEATURE_IPV6 |
305205219Srdivacky		    EFX_FEATURE_LINK_EVENTS |
306205219Srdivacky		    EFX_FEATURE_PERIODIC_MAC_STATS |
307205219Srdivacky		    EFX_FEATURE_MCDI |
308205219Srdivacky		    EFX_FEATURE_MAC_HEADER_FILTERS |
309206084Srdivacky		    EFX_FEATURE_MCDI_DMA |
310205219Srdivacky		    EFX_FEATURE_PIO_BUFFERS;
311205219Srdivacky		break;
312205219Srdivacky#endif	/* EFSYS_OPT_MEDFORD */
313205219Srdivacky
314205219Srdivacky	default:
315206084Srdivacky		rc = ENOTSUP;
316205219Srdivacky		goto fail2;
317205219Srdivacky	}
318205219Srdivacky
319205219Srdivacky	enp->en_family = family;
320205219Srdivacky	enp->en_esip = esip;
321206084Srdivacky	enp->en_esbp = esbp;
322205219Srdivacky	enp->en_eslp = eslp;
323205219Srdivacky
324205219Srdivacky	*enpp = enp;
325205219Srdivacky
326205219Srdivacky	return (0);
327206084Srdivacky
328205219Srdivackyfail2:
329205219Srdivacky	EFSYS_PROBE(fail2);
330205219Srdivacky
331205219Srdivacky	enp->en_magic = 0;
332205219Srdivacky
333206084Srdivacky	/* Free the NIC object */
334205219Srdivacky	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
335205219Srdivacky
336205219Srdivackyfail1:
337205219Srdivacky	EFSYS_PROBE1(fail1, efx_rc_t, rc);
338205219Srdivacky
339206084Srdivacky	return (rc);
340205219Srdivacky}
341205219Srdivacky
342205219Srdivacky	__checkReturn	efx_rc_t
343205219Srdivackyefx_nic_probe(
344205219Srdivacky	__in		efx_nic_t *enp)
345205219Srdivacky{
346206084Srdivacky	const efx_nic_ops_t *enop;
347205219Srdivacky	efx_rc_t rc;
348205219Srdivacky
349205219Srdivacky	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
350205219Srdivacky#if EFSYS_OPT_MCDI
351205219Srdivacky	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
352205219Srdivacky#endif	/* EFSYS_OPT_MCDI */
353234353Sdim	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE));
354234353Sdim
355234353Sdim	enop = enp->en_enop;
356234353Sdim	if ((rc = enop->eno_probe(enp)) != 0)
357205219Srdivacky		goto fail1;
358234353Sdim
359234353Sdim	if ((rc = efx_phy_probe(enp)) != 0)
360234353Sdim		goto fail2;
361234353Sdim
362234353Sdim	enp->en_mod_flags |= EFX_MOD_PROBE;
363234353Sdim
364205408Srdivacky	return (0);
365205408Srdivacky
366205408Srdivackyfail2:
367205408Srdivacky	EFSYS_PROBE(fail2);
368205408Srdivacky
369205408Srdivacky	enop->eno_unprobe(enp);
370205408Srdivacky
371205408Srdivackyfail1:
372205408Srdivacky	EFSYS_PROBE1(fail1, efx_rc_t, rc);
373205408Srdivacky
374205408Srdivacky	return (rc);
375205408Srdivacky}
376205408Srdivacky
377205408Srdivacky	__checkReturn	efx_rc_t
378205408Srdivackyefx_nic_set_drv_limits(
379205408Srdivacky	__inout		efx_nic_t *enp,
380205408Srdivacky	__in		efx_drv_limits_t *edlp)
381205408Srdivacky{
382205408Srdivacky	const efx_nic_ops_t *enop = enp->en_enop;
383205408Srdivacky	efx_rc_t rc;
384205408Srdivacky
385205408Srdivacky	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
386205408Srdivacky	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
387205408Srdivacky
388205408Srdivacky	if (enop->eno_set_drv_limits != NULL) {
389205408Srdivacky		if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0)
390205408Srdivacky			goto fail1;
391205408Srdivacky	}
392205408Srdivacky
393205408Srdivacky	return (0);
394205408Srdivacky
395205408Srdivackyfail1:
396205408Srdivacky	EFSYS_PROBE1(fail1, efx_rc_t, rc);
397205408Srdivacky
398205408Srdivacky	return (rc);
399205408Srdivacky}
400234353Sdim
401205408Srdivacky	__checkReturn	efx_rc_t
402205408Srdivackyefx_nic_get_bar_region(
403205408Srdivacky	__in		efx_nic_t *enp,
404234353Sdim	__in		efx_nic_region_t region,
405234353Sdim	__out		uint32_t *offsetp,
406234353Sdim	__out		size_t *sizep)
407234353Sdim{
408234353Sdim	const efx_nic_ops_t *enop = enp->en_enop;
409234353Sdim	efx_rc_t rc;
410234353Sdim
411234353Sdim	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
412234353Sdim	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
413234353Sdim	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
414205408Srdivacky
415205408Srdivacky	if (enop->eno_get_bar_region == NULL) {
416205408Srdivacky		rc = ENOTSUP;
417205408Srdivacky		goto fail1;
418205408Srdivacky	}
419205408Srdivacky	if ((rc = (enop->eno_get_bar_region)(enp,
420205408Srdivacky		    region, offsetp, sizep)) != 0) {
421205408Srdivacky		goto fail2;
422205408Srdivacky	}
423205408Srdivacky
424205408Srdivacky	return (0);
425205408Srdivacky
426205408Srdivackyfail2:
427206084Srdivacky	EFSYS_PROBE(fail2);
428205408Srdivacky
429205408Srdivackyfail1:
430234353Sdim	EFSYS_PROBE1(fail1, efx_rc_t, rc);
431205408Srdivacky
432205408Srdivacky	return (rc);
433205408Srdivacky}
434206084Srdivacky
435205408Srdivacky
436205408Srdivacky	__checkReturn	efx_rc_t
437205408Srdivackyefx_nic_get_vi_pool(
438205408Srdivacky	__in		efx_nic_t *enp,
439205408Srdivacky	__out		uint32_t *evq_countp,
440206084Srdivacky	__out		uint32_t *rxq_countp,
441205408Srdivacky	__out		uint32_t *txq_countp)
442205408Srdivacky{
443205408Srdivacky	const efx_nic_ops_t *enop = enp->en_enop;
444205408Srdivacky	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
445205408Srdivacky	efx_rc_t rc;
446206084Srdivacky
447205408Srdivacky	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
448205408Srdivacky	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
449205408Srdivacky	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
450205408Srdivacky
451205408Srdivacky	if (enop->eno_get_vi_pool != NULL) {
452205408Srdivacky		uint32_t vi_count = 0;
453206084Srdivacky
454205408Srdivacky		if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0)
455205408Srdivacky			goto fail1;
456205408Srdivacky
457205408Srdivacky		*evq_countp = vi_count;
458205408Srdivacky		*rxq_countp = vi_count;
459205408Srdivacky		*txq_countp = vi_count;
460234353Sdim	} else {
461234353Sdim		/* Use NIC limits as default value */
462234353Sdim		*evq_countp = encp->enc_evq_limit;
463205408Srdivacky		*rxq_countp = encp->enc_rxq_limit;
464205408Srdivacky		*txq_countp = encp->enc_txq_limit;
465204793Srdivacky	}
466204793Srdivacky
467204793Srdivacky	return (0);
468
469fail1:
470	EFSYS_PROBE1(fail1, efx_rc_t, rc);
471
472	return (rc);
473}
474
475
476	__checkReturn	efx_rc_t
477efx_nic_init(
478	__in		efx_nic_t *enp)
479{
480	const efx_nic_ops_t *enop = enp->en_enop;
481	efx_rc_t rc;
482
483	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
484	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
485
486	if (enp->en_mod_flags & EFX_MOD_NIC) {
487		rc = EINVAL;
488		goto fail1;
489	}
490
491	if ((rc = enop->eno_init(enp)) != 0)
492		goto fail2;
493
494	enp->en_mod_flags |= EFX_MOD_NIC;
495
496	return (0);
497
498fail2:
499	EFSYS_PROBE(fail2);
500fail1:
501	EFSYS_PROBE1(fail1, efx_rc_t, rc);
502
503	return (rc);
504}
505
506			void
507efx_nic_fini(
508	__in		efx_nic_t *enp)
509{
510	const efx_nic_ops_t *enop = enp->en_enop;
511
512	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
513	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
514	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC);
515	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
516	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
517	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
518	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
519
520	enop->eno_fini(enp);
521
522	enp->en_mod_flags &= ~EFX_MOD_NIC;
523}
524
525			void
526efx_nic_unprobe(
527	__in		efx_nic_t *enp)
528{
529	const efx_nic_ops_t *enop = enp->en_enop;
530
531	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
532#if EFSYS_OPT_MCDI
533	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
534#endif	/* EFSYS_OPT_MCDI */
535	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
536	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
537	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
538	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
539	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
540	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
541
542	efx_phy_unprobe(enp);
543
544	enop->eno_unprobe(enp);
545
546	enp->en_mod_flags &= ~EFX_MOD_PROBE;
547}
548
549			void
550efx_nic_destroy(
551	__in	efx_nic_t *enp)
552{
553	efsys_identifier_t *esip = enp->en_esip;
554
555	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
556	EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
557
558	enp->en_family = 0;
559	enp->en_esip = NULL;
560	enp->en_esbp = NULL;
561	enp->en_eslp = NULL;
562
563	enp->en_enop = NULL;
564
565	enp->en_magic = 0;
566
567	/* Free the NIC object */
568	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
569}
570
571	__checkReturn	efx_rc_t
572efx_nic_reset(
573	__in		efx_nic_t *enp)
574{
575	const efx_nic_ops_t *enop = enp->en_enop;
576	unsigned int mod_flags;
577	efx_rc_t rc;
578
579	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
580	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
581	/*
582	 * All modules except the MCDI, PROBE, NVRAM, VPD, MON, LIC
583	 * (which we do not reset here) must have been shut down or never
584	 * initialized.
585	 *
586	 * A rule of thumb here is: If the controller or MC reboots, is *any*
587	 * state lost. If it's lost and needs reapplying, then the module
588	 * *must* not be initialised during the reset.
589	 */
590	mod_flags = enp->en_mod_flags;
591	mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM |
592		    EFX_MOD_VPD | EFX_MOD_MON | EFX_MOD_LIC);
593	EFSYS_ASSERT3U(mod_flags, ==, 0);
594	if (mod_flags != 0) {
595		rc = EINVAL;
596		goto fail1;
597	}
598
599	if ((rc = enop->eno_reset(enp)) != 0)
600		goto fail2;
601
602	enp->en_reset_flags |= EFX_RESET_MAC;
603
604	return (0);
605
606fail2:
607	EFSYS_PROBE(fail2);
608fail1:
609	EFSYS_PROBE1(fail1, efx_rc_t, rc);
610
611	return (rc);
612}
613
614			const efx_nic_cfg_t *
615efx_nic_cfg_get(
616	__in		efx_nic_t *enp)
617{
618	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
619
620	return (&(enp->en_nic_cfg));
621}
622
623#if EFSYS_OPT_DIAG
624
625	__checkReturn	efx_rc_t
626efx_nic_register_test(
627	__in		efx_nic_t *enp)
628{
629	const efx_nic_ops_t *enop = enp->en_enop;
630	efx_rc_t rc;
631
632	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
633	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
634	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
635
636	if ((rc = enop->eno_register_test(enp)) != 0)
637		goto fail1;
638
639	return (0);
640
641fail1:
642	EFSYS_PROBE1(fail1, efx_rc_t, rc);
643
644	return (rc);
645}
646
647	__checkReturn	efx_rc_t
648efx_nic_test_registers(
649	__in		efx_nic_t *enp,
650	__in		efx_register_set_t *rsp,
651	__in		size_t count)
652{
653	unsigned int bit;
654	efx_oword_t original;
655	efx_oword_t reg;
656	efx_oword_t buf;
657	efx_rc_t rc;
658
659	while (count > 0) {
660		/* This function is only suitable for registers */
661		EFSYS_ASSERT(rsp->rows == 1);
662
663		/* bit sweep on and off */
664		EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original,
665			    B_TRUE);
666		for (bit = 0; bit < 128; bit++) {
667			/* Is this bit in the mask? */
668			if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit))
669				continue;
670
671			/* Test this bit can be set in isolation */
672			reg = original;
673			EFX_AND_OWORD(reg, rsp->mask);
674			EFX_SET_OWORD_BIT(reg, bit);
675
676			EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
677				    B_TRUE);
678			EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
679				    B_TRUE);
680
681			EFX_AND_OWORD(buf, rsp->mask);
682			if (memcmp(&reg, &buf, sizeof (reg))) {
683				rc = EIO;
684				goto fail1;
685			}
686
687			/* Test this bit can be cleared in isolation */
688			EFX_OR_OWORD(reg, rsp->mask);
689			EFX_CLEAR_OWORD_BIT(reg, bit);
690
691			EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
692				    B_TRUE);
693			EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
694				    B_TRUE);
695
696			EFX_AND_OWORD(buf, rsp->mask);
697			if (memcmp(&reg, &buf, sizeof (reg))) {
698				rc = EIO;
699				goto fail2;
700			}
701		}
702
703		/* Restore the old value */
704		EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original,
705			    B_TRUE);
706
707		--count;
708		++rsp;
709	}
710
711	return (0);
712
713fail2:
714	EFSYS_PROBE(fail2);
715fail1:
716	EFSYS_PROBE1(fail1, efx_rc_t, rc);
717
718	/* Restore the old value */
719	EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE);
720
721	return (rc);
722}
723
724	__checkReturn	efx_rc_t
725efx_nic_test_tables(
726	__in		efx_nic_t *enp,
727	__in		efx_register_set_t *rsp,
728	__in		efx_pattern_type_t pattern,
729	__in		size_t count)
730{
731	efx_sram_pattern_fn_t func;
732	unsigned int index;
733	unsigned int address;
734	efx_oword_t reg;
735	efx_oword_t buf;
736	efx_rc_t rc;
737
738	EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES);
739	func = __efx_sram_pattern_fns[pattern];
740
741	while (count > 0) {
742		/* Write */
743		address = rsp->address;
744		for (index = 0; index < rsp->rows; ++index) {
745			func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
746			func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
747			EFX_AND_OWORD(reg, rsp->mask);
748			EFSYS_BAR_WRITEO(enp->en_esbp, address, &reg, B_TRUE);
749
750			address += rsp->step;
751		}
752
753		/* Read */
754		address = rsp->address;
755		for (index = 0; index < rsp->rows; ++index) {
756			func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
757			func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
758			EFX_AND_OWORD(reg, rsp->mask);
759			EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE);
760			if (memcmp(&reg, &buf, sizeof (reg))) {
761				rc = EIO;
762				goto fail1;
763			}
764
765			address += rsp->step;
766		}
767
768		++rsp;
769		--count;
770	}
771
772	return (0);
773
774fail1:
775	EFSYS_PROBE1(fail1, efx_rc_t, rc);
776
777	return (rc);
778}
779
780#endif	/* EFSYS_OPT_DIAG */
781
782#if EFSYS_OPT_LOOPBACK
783
784extern			void
785efx_loopback_mask(
786	__in	efx_loopback_kind_t loopback_kind,
787	__out	efx_qword_t *maskp)
788{
789	efx_qword_t mask;
790
791	EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS);
792	EFSYS_ASSERT(maskp != NULL);
793
794	/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
795	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
796	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
797	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
798	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
799	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
800	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
801	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
802	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
803	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
804	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
805	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
806	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
807	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
808	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
809	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
810	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
811	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
812	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
813	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT);
814	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS);
815	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS);
816	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR ==
817	    EFX_LOOPBACK_XAUI_WS_FAR);
818	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR ==
819	    EFX_LOOPBACK_XAUI_WS_NEAR);
820	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS);
821	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS);
822	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR ==
823	    EFX_LOOPBACK_XFI_WS_FAR);
824	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS);
825	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT);
826	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR);
827	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR);
828	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS ==
829	    EFX_LOOPBACK_PMA_INT_WS);
830	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS ==
831	    EFX_LOOPBACK_SD_FEP2_WS);
832	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS ==
833	    EFX_LOOPBACK_SD_FEP1_5_WS);
834	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS);
835	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS);
836
837	/* Build bitmask of possible loopback types */
838	EFX_ZERO_QWORD(mask);
839
840	if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) ||
841	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
842		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF);
843	}
844
845	if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) ||
846	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
847		/*
848		 * The "MAC" grouping has historically been used by drivers to
849		 * mean loopbacks supported by on-chip hardware. Keep that
850		 * meaning here, and include on-chip PHY layer loopbacks.
851		 */
852		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA);
853		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC);
854		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII);
855		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS);
856		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI);
857		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII);
858		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII);
859		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR);
860		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI);
861		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR);
862		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR);
863		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR);
864		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR);
865		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT);
866		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR);
867		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR);
868	}
869
870	if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) ||
871	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
872		/*
873		 * The "PHY" grouping has historically been used by drivers to
874		 * mean loopbacks supported by off-chip hardware. Keep that
875		 * meaning here.
876		 */
877		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY);
878		EFX_SET_QWORD_BIT(mask,	EFX_LOOPBACK_PHY_XS);
879		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS);
880		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD);
881	}
882
883	*maskp = mask;
884}
885
886	__checkReturn	efx_rc_t
887efx_mcdi_get_loopback_modes(
888	__in		efx_nic_t *enp)
889{
890	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
891	efx_mcdi_req_t req;
892	uint8_t payload[MAX(MC_CMD_GET_LOOPBACK_MODES_IN_LEN,
893			    MC_CMD_GET_LOOPBACK_MODES_OUT_LEN)];
894	efx_qword_t mask;
895	efx_qword_t modes;
896	efx_rc_t rc;
897
898	(void) memset(payload, 0, sizeof (payload));
899	req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES;
900	req.emr_in_buf = payload;
901	req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN;
902	req.emr_out_buf = payload;
903	req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN;
904
905	efx_mcdi_execute(enp, &req);
906
907	if (req.emr_rc != 0) {
908		rc = req.emr_rc;
909		goto fail1;
910	}
911
912	if (req.emr_out_length_used <
913	    MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST +
914	    MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) {
915		rc = EMSGSIZE;
916		goto fail2;
917	}
918
919	/*
920	 * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree
921	 * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link().
922	 */
923	efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask);
924
925	EFX_AND_QWORD(mask,
926	    *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED));
927
928	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M);
929	EFX_AND_QWORD(modes, mask);
930	encp->enc_loopback_types[EFX_LINK_100FDX] = modes;
931
932	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G);
933	EFX_AND_QWORD(modes, mask);
934	encp->enc_loopback_types[EFX_LINK_1000FDX] = modes;
935
936	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G);
937	EFX_AND_QWORD(modes, mask);
938	encp->enc_loopback_types[EFX_LINK_10000FDX] = modes;
939
940	if (req.emr_out_length_used >=
941	    MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST +
942	    MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) {
943		/* Response includes 40G loopback modes */
944		modes =
945		    *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G);
946		EFX_AND_QWORD(modes, mask);
947		encp->enc_loopback_types[EFX_LINK_40000FDX] = modes;
948	}
949
950	EFX_ZERO_QWORD(modes);
951	EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF);
952	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]);
953	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]);
954	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]);
955	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]);
956	encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes;
957
958	return (0);
959
960fail2:
961	EFSYS_PROBE(fail2);
962fail1:
963	EFSYS_PROBE1(fail1, efx_rc_t, rc);
964
965	return (rc);
966}
967
968#endif /* EFSYS_OPT_LOOPBACK */
969