xref: /freebsd/sys/dev/sfxge/common/efx_nic.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1e948693eSPhilip Paeps /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4929c7febSAndrew Rybchenko  * Copyright (c) 2007-2016 Solarflare Communications Inc.
53c838a9fSAndrew Rybchenko  * All rights reserved.
6e948693eSPhilip Paeps  *
7e948693eSPhilip Paeps  * Redistribution and use in source and binary forms, with or without
83c838a9fSAndrew Rybchenko  * modification, are permitted provided that the following conditions are met:
9e948693eSPhilip Paeps  *
103c838a9fSAndrew Rybchenko  * 1. Redistributions of source code must retain the above copyright notice,
113c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer.
123c838a9fSAndrew Rybchenko  * 2. Redistributions in binary form must reproduce the above copyright notice,
133c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer in the documentation
143c838a9fSAndrew Rybchenko  *    and/or other materials provided with the distribution.
153c838a9fSAndrew Rybchenko  *
163c838a9fSAndrew Rybchenko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
173c838a9fSAndrew Rybchenko  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
183c838a9fSAndrew Rybchenko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
193c838a9fSAndrew Rybchenko  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
203c838a9fSAndrew Rybchenko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
213c838a9fSAndrew Rybchenko  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
223c838a9fSAndrew Rybchenko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
233c838a9fSAndrew Rybchenko  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
243c838a9fSAndrew Rybchenko  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
253c838a9fSAndrew Rybchenko  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
263c838a9fSAndrew Rybchenko  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273c838a9fSAndrew Rybchenko  *
283c838a9fSAndrew Rybchenko  * The views and conclusions contained in the software and documentation are
293c838a9fSAndrew Rybchenko  * those of the authors and should not be interpreted as representing official
303c838a9fSAndrew Rybchenko  * policies, either expressed or implied, of the FreeBSD Project.
31e948693eSPhilip Paeps  */
32e948693eSPhilip Paeps 
335dee87d7SPhilip Paeps #include <sys/cdefs.h>
34e948693eSPhilip Paeps #include "efx.h"
35e948693eSPhilip Paeps #include "efx_impl.h"
36e948693eSPhilip Paeps 
37460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_family(__in uint16_t venid,__in uint16_t devid,__out efx_family_t * efp,__out unsigned int * membarp)38e948693eSPhilip Paeps efx_family(
39e948693eSPhilip Paeps 	__in		uint16_t venid,
40e948693eSPhilip Paeps 	__in		uint16_t devid,
4136641d2bSAndrew Rybchenko 	__out		efx_family_t *efp,
4236641d2bSAndrew Rybchenko 	__out		unsigned int *membarp)
43e948693eSPhilip Paeps {
443c838a9fSAndrew Rybchenko 	if (venid == EFX_PCI_VENID_SFC) {
453c838a9fSAndrew Rybchenko 		switch (devid) {
46e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
473c838a9fSAndrew Rybchenko 		case EFX_PCI_DEVID_SIENA_F1_UNINIT:
483c838a9fSAndrew Rybchenko 			/*
493c838a9fSAndrew Rybchenko 			 * Hardware default for PF0 of uninitialised Siena.
503c838a9fSAndrew Rybchenko 			 * manftest must be able to cope with this device id.
513c838a9fSAndrew Rybchenko 			 */
523c838a9fSAndrew Rybchenko 		case EFX_PCI_DEVID_BETHPAGE:
533c838a9fSAndrew Rybchenko 		case EFX_PCI_DEVID_SIENA:
54e948693eSPhilip Paeps 			*efp = EFX_FAMILY_SIENA;
5536641d2bSAndrew Rybchenko 			*membarp = EFX_MEM_BAR_SIENA;
56e948693eSPhilip Paeps 			return (0);
5734f6ea29SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
583c838a9fSAndrew Rybchenko 
593c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
603c838a9fSAndrew Rybchenko 		case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT:
613c838a9fSAndrew Rybchenko 			/*
623c838a9fSAndrew Rybchenko 			 * Hardware default for PF0 of uninitialised Huntington.
633c838a9fSAndrew Rybchenko 			 * manftest must be able to cope with this device id.
643c838a9fSAndrew Rybchenko 			 */
653c838a9fSAndrew Rybchenko 		case EFX_PCI_DEVID_FARMINGDALE:
663c838a9fSAndrew Rybchenko 		case EFX_PCI_DEVID_GREENPORT:
673c838a9fSAndrew Rybchenko 			*efp = EFX_FAMILY_HUNTINGTON;
6836641d2bSAndrew Rybchenko 			*membarp = EFX_MEM_BAR_HUNTINGTON_PF;
693c838a9fSAndrew Rybchenko 			return (0);
703c838a9fSAndrew Rybchenko 
713c838a9fSAndrew Rybchenko 		case EFX_PCI_DEVID_FARMINGDALE_VF:
723c838a9fSAndrew Rybchenko 		case EFX_PCI_DEVID_GREENPORT_VF:
733c838a9fSAndrew Rybchenko 			*efp = EFX_FAMILY_HUNTINGTON;
7436641d2bSAndrew Rybchenko 			*membarp = EFX_MEM_BAR_HUNTINGTON_VF;
753c838a9fSAndrew Rybchenko 			return (0);
7634f6ea29SAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */
7734f6ea29SAndrew Rybchenko 
7834f6ea29SAndrew Rybchenko #if EFSYS_OPT_MEDFORD
7934f6ea29SAndrew Rybchenko 		case EFX_PCI_DEVID_MEDFORD_PF_UNINIT:
8034f6ea29SAndrew Rybchenko 			/*
8134f6ea29SAndrew Rybchenko 			 * Hardware default for PF0 of uninitialised Medford.
8234f6ea29SAndrew Rybchenko 			 * manftest must be able to cope with this device id.
8334f6ea29SAndrew Rybchenko 			 */
8434f6ea29SAndrew Rybchenko 		case EFX_PCI_DEVID_MEDFORD:
8534f6ea29SAndrew Rybchenko 			*efp = EFX_FAMILY_MEDFORD;
8636641d2bSAndrew Rybchenko 			*membarp = EFX_MEM_BAR_MEDFORD_PF;
8734f6ea29SAndrew Rybchenko 			return (0);
8834f6ea29SAndrew Rybchenko 
8934f6ea29SAndrew Rybchenko 		case EFX_PCI_DEVID_MEDFORD_VF:
9034f6ea29SAndrew Rybchenko 			*efp = EFX_FAMILY_MEDFORD;
9136641d2bSAndrew Rybchenko 			*membarp = EFX_MEM_BAR_MEDFORD_VF;
9234f6ea29SAndrew Rybchenko 			return (0);
9334f6ea29SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */
9434f6ea29SAndrew Rybchenko 
95ae64ac93SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
96ae64ac93SAndrew Rybchenko 		case EFX_PCI_DEVID_MEDFORD2_PF_UNINIT:
97ae64ac93SAndrew Rybchenko 			/*
98ae64ac93SAndrew Rybchenko 			 * Hardware default for PF0 of uninitialised Medford2.
99ae64ac93SAndrew Rybchenko 			 * manftest must be able to cope with this device id.
100ae64ac93SAndrew Rybchenko 			 */
101ae64ac93SAndrew Rybchenko 		case EFX_PCI_DEVID_MEDFORD2:
102ae64ac93SAndrew Rybchenko 		case EFX_PCI_DEVID_MEDFORD2_VF:
103ae64ac93SAndrew Rybchenko 			*efp = EFX_FAMILY_MEDFORD2;
10436641d2bSAndrew Rybchenko 			*membarp = EFX_MEM_BAR_MEDFORD2;
105ae64ac93SAndrew Rybchenko 			return (0);
106ae64ac93SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */
107ae64ac93SAndrew Rybchenko 
108e75412c9SAndrew Rybchenko 		case EFX_PCI_DEVID_FALCON:	/* Obsolete, not supported */
1093c838a9fSAndrew Rybchenko 		default:
1103c838a9fSAndrew Rybchenko 			break;
1113c838a9fSAndrew Rybchenko 		}
1123c838a9fSAndrew Rybchenko 	}
1133c838a9fSAndrew Rybchenko 
1143c838a9fSAndrew Rybchenko 	*efp = EFX_FAMILY_INVALID;
115e948693eSPhilip Paeps 	return (ENOTSUP);
116e948693eSPhilip Paeps }
117e948693eSPhilip Paeps 
118e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
119e948693eSPhilip Paeps 
120ec831f7fSAndrew Rybchenko static const efx_nic_ops_t	__efx_nic_siena_ops = {
121e948693eSPhilip Paeps 	siena_nic_probe,		/* eno_probe */
122cfa023ebSAndrew Rybchenko 	NULL,				/* eno_board_cfg */
1233c838a9fSAndrew Rybchenko 	NULL,				/* eno_set_drv_limits */
124e948693eSPhilip Paeps 	siena_nic_reset,		/* eno_reset */
125e948693eSPhilip Paeps 	siena_nic_init,			/* eno_init */
1263c838a9fSAndrew Rybchenko 	NULL,				/* eno_get_vi_pool */
1273c838a9fSAndrew Rybchenko 	NULL,				/* eno_get_bar_region */
128c6d5e85dSAndrew Rybchenko 	NULL,				/* eno_hw_unavailable */
129b2053d80SAndrew Rybchenko 	NULL,				/* eno_set_hw_unavailable */
130e948693eSPhilip Paeps #if EFSYS_OPT_DIAG
131e948693eSPhilip Paeps 	siena_nic_register_test,	/* eno_register_test */
132e948693eSPhilip Paeps #endif	/* EFSYS_OPT_DIAG */
133e948693eSPhilip Paeps 	siena_nic_fini,			/* eno_fini */
134e948693eSPhilip Paeps 	siena_nic_unprobe,		/* eno_unprobe */
135e948693eSPhilip Paeps };
136e948693eSPhilip Paeps 
137e948693eSPhilip Paeps #endif	/* EFSYS_OPT_SIENA */
138e948693eSPhilip Paeps 
1393c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
1403c838a9fSAndrew Rybchenko 
141ec831f7fSAndrew Rybchenko static const efx_nic_ops_t	__efx_nic_hunt_ops = {
142a78d5128SAndrew Rybchenko 	ef10_nic_probe,			/* eno_probe */
143cfa023ebSAndrew Rybchenko 	hunt_board_cfg,			/* eno_board_cfg */
144a78d5128SAndrew Rybchenko 	ef10_nic_set_drv_limits,	/* eno_set_drv_limits */
145a78d5128SAndrew Rybchenko 	ef10_nic_reset,			/* eno_reset */
146a78d5128SAndrew Rybchenko 	ef10_nic_init,			/* eno_init */
147a78d5128SAndrew Rybchenko 	ef10_nic_get_vi_pool,		/* eno_get_vi_pool */
148a78d5128SAndrew Rybchenko 	ef10_nic_get_bar_region,	/* eno_get_bar_region */
149c6d5e85dSAndrew Rybchenko 	ef10_nic_hw_unavailable,	/* eno_hw_unavailable */
150b2053d80SAndrew Rybchenko 	ef10_nic_set_hw_unavailable,	/* eno_set_hw_unavailable */
1513c838a9fSAndrew Rybchenko #if EFSYS_OPT_DIAG
152a78d5128SAndrew Rybchenko 	ef10_nic_register_test,		/* eno_register_test */
1533c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_DIAG */
154a78d5128SAndrew Rybchenko 	ef10_nic_fini,			/* eno_fini */
155a78d5128SAndrew Rybchenko 	ef10_nic_unprobe,		/* eno_unprobe */
1563c838a9fSAndrew Rybchenko };
1573c838a9fSAndrew Rybchenko 
1583c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON */
1593c838a9fSAndrew Rybchenko 
160cfa023ebSAndrew Rybchenko #if EFSYS_OPT_MEDFORD
161cfa023ebSAndrew Rybchenko 
162ec831f7fSAndrew Rybchenko static const efx_nic_ops_t	__efx_nic_medford_ops = {
163cfa023ebSAndrew Rybchenko 	ef10_nic_probe,			/* eno_probe */
164cfa023ebSAndrew Rybchenko 	medford_board_cfg,		/* eno_board_cfg */
165cfa023ebSAndrew Rybchenko 	ef10_nic_set_drv_limits,	/* eno_set_drv_limits */
166cfa023ebSAndrew Rybchenko 	ef10_nic_reset,			/* eno_reset */
167cfa023ebSAndrew Rybchenko 	ef10_nic_init,			/* eno_init */
168cfa023ebSAndrew Rybchenko 	ef10_nic_get_vi_pool,		/* eno_get_vi_pool */
169cfa023ebSAndrew Rybchenko 	ef10_nic_get_bar_region,	/* eno_get_bar_region */
170c6d5e85dSAndrew Rybchenko 	ef10_nic_hw_unavailable,	/* eno_hw_unavailable */
171b2053d80SAndrew Rybchenko 	ef10_nic_set_hw_unavailable,	/* eno_set_hw_unavailable */
172cfa023ebSAndrew Rybchenko #if EFSYS_OPT_DIAG
173cfa023ebSAndrew Rybchenko 	ef10_nic_register_test,		/* eno_register_test */
174cfa023ebSAndrew Rybchenko #endif	/* EFSYS_OPT_DIAG */
175cfa023ebSAndrew Rybchenko 	ef10_nic_fini,			/* eno_fini */
176cfa023ebSAndrew Rybchenko 	ef10_nic_unprobe,		/* eno_unprobe */
177cfa023ebSAndrew Rybchenko };
178cfa023ebSAndrew Rybchenko 
179cfa023ebSAndrew Rybchenko #endif	/* EFSYS_OPT_MEDFORD */
180cfa023ebSAndrew Rybchenko 
181ae64ac93SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
182ae64ac93SAndrew Rybchenko 
183ae64ac93SAndrew Rybchenko static const efx_nic_ops_t	__efx_nic_medford2_ops = {
184ae64ac93SAndrew Rybchenko 	ef10_nic_probe,			/* eno_probe */
185ae64ac93SAndrew Rybchenko 	medford2_board_cfg,		/* eno_board_cfg */
186ae64ac93SAndrew Rybchenko 	ef10_nic_set_drv_limits,	/* eno_set_drv_limits */
187ae64ac93SAndrew Rybchenko 	ef10_nic_reset,			/* eno_reset */
188ae64ac93SAndrew Rybchenko 	ef10_nic_init,			/* eno_init */
189ae64ac93SAndrew Rybchenko 	ef10_nic_get_vi_pool,		/* eno_get_vi_pool */
190ae64ac93SAndrew Rybchenko 	ef10_nic_get_bar_region,	/* eno_get_bar_region */
191c6d5e85dSAndrew Rybchenko 	ef10_nic_hw_unavailable,	/* eno_hw_unavailable */
192b2053d80SAndrew Rybchenko 	ef10_nic_set_hw_unavailable,	/* eno_set_hw_unavailable */
193ae64ac93SAndrew Rybchenko #if EFSYS_OPT_DIAG
194ae64ac93SAndrew Rybchenko 	ef10_nic_register_test,		/* eno_register_test */
195ae64ac93SAndrew Rybchenko #endif	/* EFSYS_OPT_DIAG */
196ae64ac93SAndrew Rybchenko 	ef10_nic_fini,			/* eno_fini */
197ae64ac93SAndrew Rybchenko 	ef10_nic_unprobe,		/* eno_unprobe */
198ae64ac93SAndrew Rybchenko };
199ae64ac93SAndrew Rybchenko 
200ae64ac93SAndrew Rybchenko #endif	/* EFSYS_OPT_MEDFORD2 */
201ae64ac93SAndrew Rybchenko 
202460cb568SAndrew Rybchenko 	__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)203e948693eSPhilip Paeps efx_nic_create(
204e948693eSPhilip Paeps 	__in		efx_family_t family,
205e948693eSPhilip Paeps 	__in		efsys_identifier_t *esip,
206e948693eSPhilip Paeps 	__in		efsys_bar_t *esbp,
207e948693eSPhilip Paeps 	__in		efsys_lock_t *eslp,
208e948693eSPhilip Paeps 	__deref_out	efx_nic_t **enpp)
209e948693eSPhilip Paeps {
210e948693eSPhilip Paeps 	efx_nic_t *enp;
211460cb568SAndrew Rybchenko 	efx_rc_t rc;
212e948693eSPhilip Paeps 
213e948693eSPhilip Paeps 	EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID);
214e948693eSPhilip Paeps 	EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES);
215e948693eSPhilip Paeps 
216e948693eSPhilip Paeps 	/* Allocate a NIC object */
217e948693eSPhilip Paeps 	EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp);
218e948693eSPhilip Paeps 
219e948693eSPhilip Paeps 	if (enp == NULL) {
220e948693eSPhilip Paeps 		rc = ENOMEM;
221e948693eSPhilip Paeps 		goto fail1;
222e948693eSPhilip Paeps 	}
223e948693eSPhilip Paeps 
224e948693eSPhilip Paeps 	enp->en_magic = EFX_NIC_MAGIC;
225e948693eSPhilip Paeps 
226e948693eSPhilip Paeps 	switch (family) {
227e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
228e948693eSPhilip Paeps 	case EFX_FAMILY_SIENA:
229ec831f7fSAndrew Rybchenko 		enp->en_enop = &__efx_nic_siena_ops;
230c071447aSAndrew Rybchenko 		enp->en_features =
231c071447aSAndrew Rybchenko 		    EFX_FEATURE_IPV6 |
232e948693eSPhilip Paeps 		    EFX_FEATURE_LFSR_HASH_INSERT |
233c071447aSAndrew Rybchenko 		    EFX_FEATURE_LINK_EVENTS |
234c071447aSAndrew Rybchenko 		    EFX_FEATURE_PERIODIC_MAC_STATS |
235c071447aSAndrew Rybchenko 		    EFX_FEATURE_MCDI |
2360ff23789SAndrew Rybchenko 		    EFX_FEATURE_LOOKAHEAD_SPLIT |
2373c838a9fSAndrew Rybchenko 		    EFX_FEATURE_MAC_HEADER_FILTERS |
2383c838a9fSAndrew Rybchenko 		    EFX_FEATURE_TX_SRC_FILTERS;
239e948693eSPhilip Paeps 		break;
240e948693eSPhilip Paeps #endif	/* EFSYS_OPT_SIENA */
241e948693eSPhilip Paeps 
2423c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
2433c838a9fSAndrew Rybchenko 	case EFX_FAMILY_HUNTINGTON:
244ec831f7fSAndrew Rybchenko 		enp->en_enop = &__efx_nic_hunt_ops;
2453c838a9fSAndrew Rybchenko 		enp->en_features =
2463c838a9fSAndrew Rybchenko 		    EFX_FEATURE_IPV6 |
2473c838a9fSAndrew Rybchenko 		    EFX_FEATURE_LINK_EVENTS |
2483c838a9fSAndrew Rybchenko 		    EFX_FEATURE_PERIODIC_MAC_STATS |
2493c838a9fSAndrew Rybchenko 		    EFX_FEATURE_MCDI |
2503c838a9fSAndrew Rybchenko 		    EFX_FEATURE_MAC_HEADER_FILTERS |
2513c838a9fSAndrew Rybchenko 		    EFX_FEATURE_MCDI_DMA |
2523c838a9fSAndrew Rybchenko 		    EFX_FEATURE_PIO_BUFFERS |
2534ab49369SAndrew Rybchenko 		    EFX_FEATURE_FW_ASSISTED_TSO |
2548e0c4827SAndrew Rybchenko 		    EFX_FEATURE_FW_ASSISTED_TSO_V2 |
255dc373f78SAndrew Rybchenko 		    EFX_FEATURE_PACKED_STREAM |
256dc373f78SAndrew Rybchenko 		    EFX_FEATURE_TXQ_CKSUM_OP_DESC;
2573c838a9fSAndrew Rybchenko 		break;
2583c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON */
2593c838a9fSAndrew Rybchenko 
260cfa023ebSAndrew Rybchenko #if EFSYS_OPT_MEDFORD
261cfa023ebSAndrew Rybchenko 	case EFX_FAMILY_MEDFORD:
262ec831f7fSAndrew Rybchenko 		enp->en_enop = &__efx_nic_medford_ops;
263cfa023ebSAndrew Rybchenko 		/*
264453130d9SPedro F. Giffuni 		 * FW_ASSISTED_TSO omitted as Medford only supports firmware
265cfa023ebSAndrew Rybchenko 		 * assisted TSO version 2, not the v1 scheme used on Huntington.
266cfa023ebSAndrew Rybchenko 		 */
267cfa023ebSAndrew Rybchenko 		enp->en_features =
268cfa023ebSAndrew Rybchenko 		    EFX_FEATURE_IPV6 |
269cfa023ebSAndrew Rybchenko 		    EFX_FEATURE_LINK_EVENTS |
270cfa023ebSAndrew Rybchenko 		    EFX_FEATURE_PERIODIC_MAC_STATS |
271cfa023ebSAndrew Rybchenko 		    EFX_FEATURE_MCDI |
272cfa023ebSAndrew Rybchenko 		    EFX_FEATURE_MAC_HEADER_FILTERS |
273cfa023ebSAndrew Rybchenko 		    EFX_FEATURE_MCDI_DMA |
274ce674fe1SAndrew Rybchenko 		    EFX_FEATURE_PIO_BUFFERS |
2758e0c4827SAndrew Rybchenko 		    EFX_FEATURE_FW_ASSISTED_TSO_V2 |
276dc373f78SAndrew Rybchenko 		    EFX_FEATURE_PACKED_STREAM |
277dc373f78SAndrew Rybchenko 		    EFX_FEATURE_TXQ_CKSUM_OP_DESC;
278cfa023ebSAndrew Rybchenko 		break;
279cfa023ebSAndrew Rybchenko #endif	/* EFSYS_OPT_MEDFORD */
280cfa023ebSAndrew Rybchenko 
281ae64ac93SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
282ae64ac93SAndrew Rybchenko 	case EFX_FAMILY_MEDFORD2:
283ae64ac93SAndrew Rybchenko 		enp->en_enop = &__efx_nic_medford2_ops;
284ae64ac93SAndrew Rybchenko 		enp->en_features =
285ae64ac93SAndrew Rybchenko 		    EFX_FEATURE_IPV6 |
286ae64ac93SAndrew Rybchenko 		    EFX_FEATURE_LINK_EVENTS |
287ae64ac93SAndrew Rybchenko 		    EFX_FEATURE_PERIODIC_MAC_STATS |
288ae64ac93SAndrew Rybchenko 		    EFX_FEATURE_MCDI |
289ae64ac93SAndrew Rybchenko 		    EFX_FEATURE_MAC_HEADER_FILTERS |
290ae64ac93SAndrew Rybchenko 		    EFX_FEATURE_MCDI_DMA |
291ae64ac93SAndrew Rybchenko 		    EFX_FEATURE_PIO_BUFFERS |
292ae64ac93SAndrew Rybchenko 		    EFX_FEATURE_FW_ASSISTED_TSO_V2 |
293dc373f78SAndrew Rybchenko 		    EFX_FEATURE_PACKED_STREAM |
294dc373f78SAndrew Rybchenko 		    EFX_FEATURE_TXQ_CKSUM_OP_DESC;
295ae64ac93SAndrew Rybchenko 		break;
296ae64ac93SAndrew Rybchenko #endif	/* EFSYS_OPT_MEDFORD2 */
297ae64ac93SAndrew Rybchenko 
298e948693eSPhilip Paeps 	default:
299e948693eSPhilip Paeps 		rc = ENOTSUP;
300e948693eSPhilip Paeps 		goto fail2;
301e948693eSPhilip Paeps 	}
302e948693eSPhilip Paeps 
303e948693eSPhilip Paeps 	enp->en_family = family;
304e948693eSPhilip Paeps 	enp->en_esip = esip;
305e948693eSPhilip Paeps 	enp->en_esbp = esbp;
306e948693eSPhilip Paeps 	enp->en_eslp = eslp;
307e948693eSPhilip Paeps 
308e948693eSPhilip Paeps 	*enpp = enp;
309e948693eSPhilip Paeps 
310e948693eSPhilip Paeps 	return (0);
311e948693eSPhilip Paeps 
312e948693eSPhilip Paeps fail2:
3133c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
314e948693eSPhilip Paeps 
315e948693eSPhilip Paeps 	enp->en_magic = 0;
316e948693eSPhilip Paeps 
317e948693eSPhilip Paeps 	/* Free the NIC object */
318e948693eSPhilip Paeps 	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
319e948693eSPhilip Paeps 
320e948693eSPhilip Paeps fail1:
321460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
322e948693eSPhilip Paeps 
323e948693eSPhilip Paeps 	return (rc);
324e948693eSPhilip Paeps }
325e948693eSPhilip Paeps 
326460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_nic_probe(__in efx_nic_t * enp,__in efx_fw_variant_t efv)327e948693eSPhilip Paeps efx_nic_probe(
32887a67e18SAndrew Rybchenko 	__in		efx_nic_t *enp,
32987a67e18SAndrew Rybchenko 	__in		efx_fw_variant_t efv)
330e948693eSPhilip Paeps {
331ec831f7fSAndrew Rybchenko 	const efx_nic_ops_t *enop;
332460cb568SAndrew Rybchenko 	efx_rc_t rc;
333e948693eSPhilip Paeps 
334e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
335e948693eSPhilip Paeps #if EFSYS_OPT_MCDI
336e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
337e948693eSPhilip Paeps #endif	/* EFSYS_OPT_MCDI */
338e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE));
339e948693eSPhilip Paeps 
34087a67e18SAndrew Rybchenko 	/* Ensure FW variant codes match with MC_CMD_FW codes */
34187a67e18SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_FW_VARIANT_FULL_FEATURED ==
34287a67e18SAndrew Rybchenko 	    MC_CMD_FW_FULL_FEATURED);
34387a67e18SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_FW_VARIANT_LOW_LATENCY ==
34487a67e18SAndrew Rybchenko 	    MC_CMD_FW_LOW_LATENCY);
34587a67e18SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_FW_VARIANT_PACKED_STREAM ==
34687a67e18SAndrew Rybchenko 	    MC_CMD_FW_PACKED_STREAM);
34787a67e18SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_FW_VARIANT_HIGH_TX_RATE ==
34887a67e18SAndrew Rybchenko 	    MC_CMD_FW_HIGH_TX_RATE);
34987a67e18SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_FW_VARIANT_PACKED_STREAM_HASH_MODE_1 ==
35087a67e18SAndrew Rybchenko 	    MC_CMD_FW_PACKED_STREAM_HASH_MODE_1);
35187a67e18SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_FW_VARIANT_RULES_ENGINE ==
35287a67e18SAndrew Rybchenko 	    MC_CMD_FW_RULES_ENGINE);
35387a67e18SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_FW_VARIANT_DPDK ==
35487a67e18SAndrew Rybchenko 	    MC_CMD_FW_DPDK);
35587a67e18SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_FW_VARIANT_DONT_CARE ==
35687a67e18SAndrew Rybchenko 	    (int)MC_CMD_FW_DONT_CARE);
35787a67e18SAndrew Rybchenko 
358e948693eSPhilip Paeps 	enop = enp->en_enop;
35987a67e18SAndrew Rybchenko 	enp->efv = efv;
36087a67e18SAndrew Rybchenko 
361e948693eSPhilip Paeps 	if ((rc = enop->eno_probe(enp)) != 0)
3623c838a9fSAndrew Rybchenko 		goto fail1;
363e948693eSPhilip Paeps 
364e948693eSPhilip Paeps 	if ((rc = efx_phy_probe(enp)) != 0)
3653c838a9fSAndrew Rybchenko 		goto fail2;
366e948693eSPhilip Paeps 
367e948693eSPhilip Paeps 	enp->en_mod_flags |= EFX_MOD_PROBE;
368e948693eSPhilip Paeps 
369e948693eSPhilip Paeps 	return (0);
370e948693eSPhilip Paeps 
3713c838a9fSAndrew Rybchenko fail2:
3723c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
373e948693eSPhilip Paeps 
374e948693eSPhilip Paeps 	enop->eno_unprobe(enp);
375e948693eSPhilip Paeps 
376e948693eSPhilip Paeps fail1:
377460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
378e948693eSPhilip Paeps 
379e948693eSPhilip Paeps 	return (rc);
380e948693eSPhilip Paeps }
381e948693eSPhilip Paeps 
382460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_nic_set_drv_limits(__inout efx_nic_t * enp,__in efx_drv_limits_t * edlp)3833c838a9fSAndrew Rybchenko efx_nic_set_drv_limits(
3843c838a9fSAndrew Rybchenko 	__inout		efx_nic_t *enp,
3853c838a9fSAndrew Rybchenko 	__in		efx_drv_limits_t *edlp)
3863c838a9fSAndrew Rybchenko {
387ec831f7fSAndrew Rybchenko 	const efx_nic_ops_t *enop = enp->en_enop;
388460cb568SAndrew Rybchenko 	efx_rc_t rc;
3893c838a9fSAndrew Rybchenko 
3903c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
3913c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
3923c838a9fSAndrew Rybchenko 
3933c838a9fSAndrew Rybchenko 	if (enop->eno_set_drv_limits != NULL) {
3943c838a9fSAndrew Rybchenko 		if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0)
3953c838a9fSAndrew Rybchenko 			goto fail1;
3963c838a9fSAndrew Rybchenko 	}
3973c838a9fSAndrew Rybchenko 
3983c838a9fSAndrew Rybchenko 	return (0);
3993c838a9fSAndrew Rybchenko 
4003c838a9fSAndrew Rybchenko fail1:
401460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4023c838a9fSAndrew Rybchenko 
4033c838a9fSAndrew Rybchenko 	return (rc);
4043c838a9fSAndrew Rybchenko }
4053c838a9fSAndrew Rybchenko 
406460cb568SAndrew Rybchenko 	__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)4073c838a9fSAndrew Rybchenko efx_nic_get_bar_region(
4083c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp,
4093c838a9fSAndrew Rybchenko 	__in		efx_nic_region_t region,
4103c838a9fSAndrew Rybchenko 	__out		uint32_t *offsetp,
4113c838a9fSAndrew Rybchenko 	__out		size_t *sizep)
4123c838a9fSAndrew Rybchenko {
413ec831f7fSAndrew Rybchenko 	const efx_nic_ops_t *enop = enp->en_enop;
414460cb568SAndrew Rybchenko 	efx_rc_t rc;
4153c838a9fSAndrew Rybchenko 
4163c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
4173c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
4183c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
4193c838a9fSAndrew Rybchenko 
4203c838a9fSAndrew Rybchenko 	if (enop->eno_get_bar_region == NULL) {
4213c838a9fSAndrew Rybchenko 		rc = ENOTSUP;
4223c838a9fSAndrew Rybchenko 		goto fail1;
4233c838a9fSAndrew Rybchenko 	}
4243c838a9fSAndrew Rybchenko 	if ((rc = (enop->eno_get_bar_region)(enp,
4253c838a9fSAndrew Rybchenko 		    region, offsetp, sizep)) != 0) {
4263c838a9fSAndrew Rybchenko 		goto fail2;
4273c838a9fSAndrew Rybchenko 	}
4283c838a9fSAndrew Rybchenko 
4293c838a9fSAndrew Rybchenko 	return (0);
4303c838a9fSAndrew Rybchenko 
4313c838a9fSAndrew Rybchenko fail2:
4323c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
4333c838a9fSAndrew Rybchenko 
4343c838a9fSAndrew Rybchenko fail1:
435460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4363c838a9fSAndrew Rybchenko 
4373c838a9fSAndrew Rybchenko 	return (rc);
4383c838a9fSAndrew Rybchenko }
4393c838a9fSAndrew Rybchenko 
440460cb568SAndrew Rybchenko 	__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)4413c838a9fSAndrew Rybchenko efx_nic_get_vi_pool(
4423c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp,
4433c838a9fSAndrew Rybchenko 	__out		uint32_t *evq_countp,
4443c838a9fSAndrew Rybchenko 	__out		uint32_t *rxq_countp,
4453c838a9fSAndrew Rybchenko 	__out		uint32_t *txq_countp)
4463c838a9fSAndrew Rybchenko {
447ec831f7fSAndrew Rybchenko 	const efx_nic_ops_t *enop = enp->en_enop;
4483c838a9fSAndrew Rybchenko 	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
449460cb568SAndrew Rybchenko 	efx_rc_t rc;
4503c838a9fSAndrew Rybchenko 
4513c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
4523c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
4533c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
4543c838a9fSAndrew Rybchenko 
4553c838a9fSAndrew Rybchenko 	if (enop->eno_get_vi_pool != NULL) {
4563c838a9fSAndrew Rybchenko 		uint32_t vi_count = 0;
4573c838a9fSAndrew Rybchenko 
4583c838a9fSAndrew Rybchenko 		if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0)
4593c838a9fSAndrew Rybchenko 			goto fail1;
4603c838a9fSAndrew Rybchenko 
4613c838a9fSAndrew Rybchenko 		*evq_countp = vi_count;
4623c838a9fSAndrew Rybchenko 		*rxq_countp = vi_count;
4633c838a9fSAndrew Rybchenko 		*txq_countp = vi_count;
4643c838a9fSAndrew Rybchenko 	} else {
4653c838a9fSAndrew Rybchenko 		/* Use NIC limits as default value */
4663c838a9fSAndrew Rybchenko 		*evq_countp = encp->enc_evq_limit;
4673c838a9fSAndrew Rybchenko 		*rxq_countp = encp->enc_rxq_limit;
4683c838a9fSAndrew Rybchenko 		*txq_countp = encp->enc_txq_limit;
4693c838a9fSAndrew Rybchenko 	}
4703c838a9fSAndrew Rybchenko 
4713c838a9fSAndrew Rybchenko 	return (0);
4723c838a9fSAndrew Rybchenko 
4733c838a9fSAndrew Rybchenko fail1:
474460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4753c838a9fSAndrew Rybchenko 
4763c838a9fSAndrew Rybchenko 	return (rc);
4773c838a9fSAndrew Rybchenko }
4783c838a9fSAndrew Rybchenko 
479460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_nic_init(__in efx_nic_t * enp)480e948693eSPhilip Paeps efx_nic_init(
481e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
482e948693eSPhilip Paeps {
483ec831f7fSAndrew Rybchenko 	const efx_nic_ops_t *enop = enp->en_enop;
484460cb568SAndrew Rybchenko 	efx_rc_t rc;
485e948693eSPhilip Paeps 
486e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
487e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
488e948693eSPhilip Paeps 
489e948693eSPhilip Paeps 	if (enp->en_mod_flags & EFX_MOD_NIC) {
490e948693eSPhilip Paeps 		rc = EINVAL;
491e948693eSPhilip Paeps 		goto fail1;
492e948693eSPhilip Paeps 	}
493e948693eSPhilip Paeps 
494e948693eSPhilip Paeps 	if ((rc = enop->eno_init(enp)) != 0)
495e948693eSPhilip Paeps 		goto fail2;
496e948693eSPhilip Paeps 
497e948693eSPhilip Paeps 	enp->en_mod_flags |= EFX_MOD_NIC;
498e948693eSPhilip Paeps 
499e948693eSPhilip Paeps 	return (0);
500e948693eSPhilip Paeps 
501e948693eSPhilip Paeps fail2:
502e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
503e948693eSPhilip Paeps fail1:
504460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
505e948693eSPhilip Paeps 
506e948693eSPhilip Paeps 	return (rc);
507e948693eSPhilip Paeps }
508e948693eSPhilip Paeps 
509e948693eSPhilip Paeps 			void
efx_nic_fini(__in efx_nic_t * enp)510e948693eSPhilip Paeps efx_nic_fini(
511e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
512e948693eSPhilip Paeps {
513ec831f7fSAndrew Rybchenko 	const efx_nic_ops_t *enop = enp->en_enop;
514e948693eSPhilip Paeps 
515e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
516e948693eSPhilip Paeps 	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
517e948693eSPhilip Paeps 	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC);
518e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
519e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
520e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
521e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
522e948693eSPhilip Paeps 
523e948693eSPhilip Paeps 	enop->eno_fini(enp);
524e948693eSPhilip Paeps 
525e948693eSPhilip Paeps 	enp->en_mod_flags &= ~EFX_MOD_NIC;
526e948693eSPhilip Paeps }
527e948693eSPhilip Paeps 
528e948693eSPhilip Paeps 			void
efx_nic_unprobe(__in efx_nic_t * enp)529e948693eSPhilip Paeps efx_nic_unprobe(
530e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
531e948693eSPhilip Paeps {
532ec831f7fSAndrew Rybchenko 	const efx_nic_ops_t *enop = enp->en_enop;
533e948693eSPhilip Paeps 
534e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
535e948693eSPhilip Paeps #if EFSYS_OPT_MCDI
536e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
537e948693eSPhilip Paeps #endif	/* EFSYS_OPT_MCDI */
538e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
539e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
540e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
541e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
542e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
543e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
544e948693eSPhilip Paeps 
545e948693eSPhilip Paeps 	efx_phy_unprobe(enp);
546e948693eSPhilip Paeps 
547e948693eSPhilip Paeps 	enop->eno_unprobe(enp);
548e948693eSPhilip Paeps 
549e948693eSPhilip Paeps 	enp->en_mod_flags &= ~EFX_MOD_PROBE;
550e948693eSPhilip Paeps }
551e948693eSPhilip Paeps 
552e948693eSPhilip Paeps 			void
efx_nic_destroy(__in efx_nic_t * enp)553e948693eSPhilip Paeps efx_nic_destroy(
554e948693eSPhilip Paeps 	__in	efx_nic_t *enp)
555e948693eSPhilip Paeps {
556e948693eSPhilip Paeps 	efsys_identifier_t *esip = enp->en_esip;
557e948693eSPhilip Paeps 
558e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
559e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
560e948693eSPhilip Paeps 
56180d051eeSAndrew Rybchenko 	enp->en_family = EFX_FAMILY_INVALID;
562e948693eSPhilip Paeps 	enp->en_esip = NULL;
563e948693eSPhilip Paeps 	enp->en_esbp = NULL;
564e948693eSPhilip Paeps 	enp->en_eslp = NULL;
565e948693eSPhilip Paeps 
566e948693eSPhilip Paeps 	enp->en_enop = NULL;
567e948693eSPhilip Paeps 
568e948693eSPhilip Paeps 	enp->en_magic = 0;
569e948693eSPhilip Paeps 
570e948693eSPhilip Paeps 	/* Free the NIC object */
571e948693eSPhilip Paeps 	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
572e948693eSPhilip Paeps }
573e948693eSPhilip Paeps 
574460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_nic_reset(__in efx_nic_t * enp)575e948693eSPhilip Paeps efx_nic_reset(
576e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
577e948693eSPhilip Paeps {
578ec831f7fSAndrew Rybchenko 	const efx_nic_ops_t *enop = enp->en_enop;
579e948693eSPhilip Paeps 	unsigned int mod_flags;
580460cb568SAndrew Rybchenko 	efx_rc_t rc;
581e948693eSPhilip Paeps 
582e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
583e948693eSPhilip Paeps 	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
584e948693eSPhilip Paeps 	/*
585fdbe38cfSAndrew Rybchenko 	 * All modules except the MCDI, PROBE, NVRAM, VPD, MON, TUNNEL
5860c848230SAndrew Rybchenko 	 * (which we do not reset here) must have been shut down or never
5870c848230SAndrew Rybchenko 	 * initialized.
588e948693eSPhilip Paeps 	 *
589e948693eSPhilip Paeps 	 * A rule of thumb here is: If the controller or MC reboots, is *any*
590e948693eSPhilip Paeps 	 * state lost. If it's lost and needs reapplying, then the module
591e948693eSPhilip Paeps 	 * *must* not be initialised during the reset.
592e948693eSPhilip Paeps 	 */
593e948693eSPhilip Paeps 	mod_flags = enp->en_mod_flags;
594e948693eSPhilip Paeps 	mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM |
5955df3232cSAndrew Rybchenko 	    EFX_MOD_VPD | EFX_MOD_MON);
596fdbe38cfSAndrew Rybchenko #if EFSYS_OPT_TUNNEL
597fdbe38cfSAndrew Rybchenko 	mod_flags &= ~EFX_MOD_TUNNEL;
598fdbe38cfSAndrew Rybchenko #endif /* EFSYS_OPT_TUNNEL */
599e948693eSPhilip Paeps 	EFSYS_ASSERT3U(mod_flags, ==, 0);
600e948693eSPhilip Paeps 	if (mod_flags != 0) {
601e948693eSPhilip Paeps 		rc = EINVAL;
602e948693eSPhilip Paeps 		goto fail1;
603e948693eSPhilip Paeps 	}
604e948693eSPhilip Paeps 
605e948693eSPhilip Paeps 	if ((rc = enop->eno_reset(enp)) != 0)
606e948693eSPhilip Paeps 		goto fail2;
607e948693eSPhilip Paeps 
608e948693eSPhilip Paeps 	return (0);
609e948693eSPhilip Paeps 
610e948693eSPhilip Paeps fail2:
611e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
612e948693eSPhilip Paeps fail1:
613460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
614e948693eSPhilip Paeps 
615e948693eSPhilip Paeps 	return (rc);
616e948693eSPhilip Paeps }
617e948693eSPhilip Paeps 
618e948693eSPhilip Paeps 			const efx_nic_cfg_t *
efx_nic_cfg_get(__in efx_nic_t * enp)619e948693eSPhilip Paeps efx_nic_cfg_get(
620e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
621e948693eSPhilip Paeps {
622e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
623aea82ebfSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
624e948693eSPhilip Paeps 
625e948693eSPhilip Paeps 	return (&(enp->en_nic_cfg));
626e948693eSPhilip Paeps }
627e948693eSPhilip Paeps 
628d55882dfSAndrew Rybchenko 	__checkReturn		efx_rc_t
efx_nic_get_fw_version(__in efx_nic_t * enp,__out efx_nic_fw_info_t * enfip)629d55882dfSAndrew Rybchenko efx_nic_get_fw_version(
630d55882dfSAndrew Rybchenko 	__in			efx_nic_t *enp,
631d55882dfSAndrew Rybchenko 	__out			efx_nic_fw_info_t *enfip)
632d55882dfSAndrew Rybchenko {
633d55882dfSAndrew Rybchenko 	uint16_t mc_fw_version[4];
634d55882dfSAndrew Rybchenko 	efx_rc_t rc;
635d55882dfSAndrew Rybchenko 
636d55882dfSAndrew Rybchenko 	if (enfip == NULL) {
637d55882dfSAndrew Rybchenko 		rc = EINVAL;
638d55882dfSAndrew Rybchenko 		goto fail1;
639d55882dfSAndrew Rybchenko 	}
640d55882dfSAndrew Rybchenko 
641d55882dfSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
642d55882dfSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
643d55882dfSAndrew Rybchenko 
644d5dbb451SAndrew Rybchenko 	/* Ensure RXDP_FW_ID codes match with MC_CMD_GET_CAPABILITIES codes */
645d5dbb451SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_RXDP_FULL_FEATURED_FW_ID ==
646d5dbb451SAndrew Rybchenko 	    MC_CMD_GET_CAPABILITIES_OUT_RXDP);
647d5dbb451SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_RXDP_LOW_LATENCY_FW_ID ==
648d5dbb451SAndrew Rybchenko 	    MC_CMD_GET_CAPABILITIES_OUT_RXDP_LOW_LATENCY);
649d5dbb451SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_RXDP_PACKED_STREAM_FW_ID ==
650d5dbb451SAndrew Rybchenko 	    MC_CMD_GET_CAPABILITIES_OUT_RXDP_PACKED_STREAM);
651d5dbb451SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_RXDP_RULES_ENGINE_FW_ID ==
652d5dbb451SAndrew Rybchenko 	    MC_CMD_GET_CAPABILITIES_OUT_RXDP_RULES_ENGINE);
653d5dbb451SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_RXDP_DPDK_FW_ID ==
654d5dbb451SAndrew Rybchenko 	    MC_CMD_GET_CAPABILITIES_OUT_RXDP_DPDK);
655d5dbb451SAndrew Rybchenko 
656d55882dfSAndrew Rybchenko 	rc = efx_mcdi_version(enp, mc_fw_version, NULL, NULL);
657d55882dfSAndrew Rybchenko 	if (rc != 0)
658d55882dfSAndrew Rybchenko 		goto fail2;
659d55882dfSAndrew Rybchenko 
660d55882dfSAndrew Rybchenko 	rc = efx_mcdi_get_capabilities(enp, NULL,
661d55882dfSAndrew Rybchenko 	    &enfip->enfi_rx_dpcpu_fw_id,
662d55882dfSAndrew Rybchenko 	    &enfip->enfi_tx_dpcpu_fw_id,
663d55882dfSAndrew Rybchenko 	    NULL, NULL);
664d55882dfSAndrew Rybchenko 	if (rc == 0) {
665d55882dfSAndrew Rybchenko 		enfip->enfi_dpcpu_fw_ids_valid = B_TRUE;
666d55882dfSAndrew Rybchenko 	} else if (rc == ENOTSUP) {
667d55882dfSAndrew Rybchenko 		enfip->enfi_dpcpu_fw_ids_valid = B_FALSE;
668d55882dfSAndrew Rybchenko 		enfip->enfi_rx_dpcpu_fw_id = 0;
669d55882dfSAndrew Rybchenko 		enfip->enfi_tx_dpcpu_fw_id = 0;
670d55882dfSAndrew Rybchenko 	} else {
671d55882dfSAndrew Rybchenko 		goto fail3;
672d55882dfSAndrew Rybchenko 	}
673d55882dfSAndrew Rybchenko 
67495c45bd0SAndrew Rybchenko 	memcpy(enfip->enfi_mc_fw_version, mc_fw_version,
67595c45bd0SAndrew Rybchenko 	    sizeof (mc_fw_version));
676d55882dfSAndrew Rybchenko 
677d55882dfSAndrew Rybchenko 	return (0);
678d55882dfSAndrew Rybchenko 
679d55882dfSAndrew Rybchenko fail3:
680d55882dfSAndrew Rybchenko 	EFSYS_PROBE(fail3);
681d55882dfSAndrew Rybchenko fail2:
682d55882dfSAndrew Rybchenko 	EFSYS_PROBE(fail2);
683d55882dfSAndrew Rybchenko fail1:
684d55882dfSAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
685d55882dfSAndrew Rybchenko 
686d55882dfSAndrew Rybchenko 	return (rc);
687d55882dfSAndrew Rybchenko }
688d55882dfSAndrew Rybchenko 
689c6d5e85dSAndrew Rybchenko 	__checkReturn	boolean_t
efx_nic_hw_unavailable(__in efx_nic_t * enp)690c6d5e85dSAndrew Rybchenko efx_nic_hw_unavailable(
691c6d5e85dSAndrew Rybchenko 	__in		efx_nic_t *enp)
692c6d5e85dSAndrew Rybchenko {
693c6d5e85dSAndrew Rybchenko 	const efx_nic_ops_t *enop = enp->en_enop;
694c6d5e85dSAndrew Rybchenko 
695c6d5e85dSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
696c6d5e85dSAndrew Rybchenko 	/* NOTE: can be used by MCDI before NIC probe */
697c6d5e85dSAndrew Rybchenko 
698c6d5e85dSAndrew Rybchenko 	if (enop->eno_hw_unavailable != NULL) {
699c6d5e85dSAndrew Rybchenko 		if ((enop->eno_hw_unavailable)(enp) != B_FALSE)
700c6d5e85dSAndrew Rybchenko 			goto unavail;
701c6d5e85dSAndrew Rybchenko 	}
702c6d5e85dSAndrew Rybchenko 
703c6d5e85dSAndrew Rybchenko 	return (B_FALSE);
704c6d5e85dSAndrew Rybchenko 
705c6d5e85dSAndrew Rybchenko unavail:
706c6d5e85dSAndrew Rybchenko 	return (B_TRUE);
707c6d5e85dSAndrew Rybchenko }
708c6d5e85dSAndrew Rybchenko 
709b2053d80SAndrew Rybchenko 			void
efx_nic_set_hw_unavailable(__in efx_nic_t * enp)710b2053d80SAndrew Rybchenko efx_nic_set_hw_unavailable(
711b2053d80SAndrew Rybchenko 	__in		efx_nic_t *enp)
712b2053d80SAndrew Rybchenko {
713b2053d80SAndrew Rybchenko 	const efx_nic_ops_t *enop = enp->en_enop;
714b2053d80SAndrew Rybchenko 
715b2053d80SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
716b2053d80SAndrew Rybchenko 
717b2053d80SAndrew Rybchenko 	if (enop->eno_set_hw_unavailable != NULL)
718b2053d80SAndrew Rybchenko 		enop->eno_set_hw_unavailable(enp);
719b2053d80SAndrew Rybchenko }
720b2053d80SAndrew Rybchenko 
721e948693eSPhilip Paeps #if EFSYS_OPT_DIAG
722e948693eSPhilip Paeps 
723460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_nic_register_test(__in efx_nic_t * enp)724e948693eSPhilip Paeps efx_nic_register_test(
725e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
726e948693eSPhilip Paeps {
727ec831f7fSAndrew Rybchenko 	const efx_nic_ops_t *enop = enp->en_enop;
728460cb568SAndrew Rybchenko 	efx_rc_t rc;
729e948693eSPhilip Paeps 
730e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
731e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
732e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
733e948693eSPhilip Paeps 
734e948693eSPhilip Paeps 	if ((rc = enop->eno_register_test(enp)) != 0)
735e948693eSPhilip Paeps 		goto fail1;
736e948693eSPhilip Paeps 
737e948693eSPhilip Paeps 	return (0);
738e948693eSPhilip Paeps 
739e948693eSPhilip Paeps fail1:
740460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
741e948693eSPhilip Paeps 
742e948693eSPhilip Paeps 	return (rc);
743e948693eSPhilip Paeps }
744e948693eSPhilip Paeps 
745e948693eSPhilip Paeps #endif	/* EFSYS_OPT_DIAG */
7463c838a9fSAndrew Rybchenko 
7473c838a9fSAndrew Rybchenko #if EFSYS_OPT_LOOPBACK
7483c838a9fSAndrew Rybchenko 
7493c838a9fSAndrew Rybchenko extern			void
efx_loopback_mask(__in efx_loopback_kind_t loopback_kind,__out efx_qword_t * maskp)7503c838a9fSAndrew Rybchenko efx_loopback_mask(
7513c838a9fSAndrew Rybchenko 	__in	efx_loopback_kind_t loopback_kind,
7523c838a9fSAndrew Rybchenko 	__out	efx_qword_t *maskp)
7533c838a9fSAndrew Rybchenko {
7543c838a9fSAndrew Rybchenko 	efx_qword_t mask;
7553c838a9fSAndrew Rybchenko 
7563c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS);
7573c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(maskp != NULL);
7583c838a9fSAndrew Rybchenko 
7594add9918SAndrew Rybchenko 	/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree */
7604add9918SAndrew Rybchenko #define	LOOPBACK_CHECK(_mcdi, _efx) \
7614add9918SAndrew Rybchenko 	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_##_mcdi == EFX_LOOPBACK_##_efx)
7624add9918SAndrew Rybchenko 
7634add9918SAndrew Rybchenko 	LOOPBACK_CHECK(NONE, OFF);
7644add9918SAndrew Rybchenko 	LOOPBACK_CHECK(DATA, DATA);
7654add9918SAndrew Rybchenko 	LOOPBACK_CHECK(GMAC, GMAC);
7664add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XGMII, XGMII);
7674add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XGXS, XGXS);
7684add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XAUI, XAUI);
7694add9918SAndrew Rybchenko 	LOOPBACK_CHECK(GMII, GMII);
7704add9918SAndrew Rybchenko 	LOOPBACK_CHECK(SGMII, SGMII);
7714add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XGBR, XGBR);
7724add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XFI, XFI);
7734add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XAUI_FAR, XAUI_FAR);
7744add9918SAndrew Rybchenko 	LOOPBACK_CHECK(GMII_FAR, GMII_FAR);
7754add9918SAndrew Rybchenko 	LOOPBACK_CHECK(SGMII_FAR, SGMII_FAR);
7764add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XFI_FAR, XFI_FAR);
7774add9918SAndrew Rybchenko 	LOOPBACK_CHECK(GPHY, GPHY);
7784add9918SAndrew Rybchenko 	LOOPBACK_CHECK(PHYXS, PHY_XS);
7794add9918SAndrew Rybchenko 	LOOPBACK_CHECK(PCS, PCS);
7804add9918SAndrew Rybchenko 	LOOPBACK_CHECK(PMAPMD, PMA_PMD);
7814add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XPORT, XPORT);
7824add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XGMII_WS, XGMII_WS);
7834add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XAUI_WS, XAUI_WS);
7844add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XAUI_WS_FAR, XAUI_WS_FAR);
7854add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XAUI_WS_NEAR, XAUI_WS_NEAR);
7864add9918SAndrew Rybchenko 	LOOPBACK_CHECK(GMII_WS, GMII_WS);
7874add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XFI_WS, XFI_WS);
7884add9918SAndrew Rybchenko 	LOOPBACK_CHECK(XFI_WS_FAR, XFI_WS_FAR);
7894add9918SAndrew Rybchenko 	LOOPBACK_CHECK(PHYXS_WS, PHYXS_WS);
7904add9918SAndrew Rybchenko 	LOOPBACK_CHECK(PMA_INT, PMA_INT);
7914add9918SAndrew Rybchenko 	LOOPBACK_CHECK(SD_NEAR, SD_NEAR);
7924add9918SAndrew Rybchenko 	LOOPBACK_CHECK(SD_FAR, SD_FAR);
7934add9918SAndrew Rybchenko 	LOOPBACK_CHECK(PMA_INT_WS, PMA_INT_WS);
7944add9918SAndrew Rybchenko 	LOOPBACK_CHECK(SD_FEP2_WS, SD_FEP2_WS);
7954add9918SAndrew Rybchenko 	LOOPBACK_CHECK(SD_FEP1_5_WS, SD_FEP1_5_WS);
7964add9918SAndrew Rybchenko 	LOOPBACK_CHECK(SD_FEP_WS, SD_FEP_WS);
7974add9918SAndrew Rybchenko 	LOOPBACK_CHECK(SD_FES_WS, SD_FES_WS);
798725bb178SAndrew Rybchenko 	LOOPBACK_CHECK(AOE_INT_NEAR, AOE_INT_NEAR);
799725bb178SAndrew Rybchenko 	LOOPBACK_CHECK(DATA_WS, DATA_WS);
800725bb178SAndrew Rybchenko 	LOOPBACK_CHECK(FORCE_EXT_LINK, FORCE_EXT_LINK);
8014add9918SAndrew Rybchenko #undef LOOPBACK_CHECK
8023c838a9fSAndrew Rybchenko 
8033c838a9fSAndrew Rybchenko 	/* Build bitmask of possible loopback types */
8043c838a9fSAndrew Rybchenko 	EFX_ZERO_QWORD(mask);
8053c838a9fSAndrew Rybchenko 
8063c838a9fSAndrew Rybchenko 	if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) ||
8073c838a9fSAndrew Rybchenko 	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
8083c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF);
8093c838a9fSAndrew Rybchenko 	}
8103c838a9fSAndrew Rybchenko 
8113c838a9fSAndrew Rybchenko 	if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) ||
8123c838a9fSAndrew Rybchenko 	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
8133c838a9fSAndrew Rybchenko 		/*
8143c838a9fSAndrew Rybchenko 		 * The "MAC" grouping has historically been used by drivers to
8153c838a9fSAndrew Rybchenko 		 * mean loopbacks supported by on-chip hardware. Keep that
8163c838a9fSAndrew Rybchenko 		 * meaning here, and include on-chip PHY layer loopbacks.
8173c838a9fSAndrew Rybchenko 		 */
8183c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA);
8193c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC);
8203c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII);
8213c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS);
8223c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI);
8233c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII);
8243c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII);
8253c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR);
8263c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI);
8273c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR);
8283c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR);
8293c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR);
8303c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR);
8313c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT);
8323c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR);
8333c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR);
8343c838a9fSAndrew Rybchenko 	}
8353c838a9fSAndrew Rybchenko 
8363c838a9fSAndrew Rybchenko 	if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) ||
8373c838a9fSAndrew Rybchenko 	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
8383c838a9fSAndrew Rybchenko 		/*
8393c838a9fSAndrew Rybchenko 		 * The "PHY" grouping has historically been used by drivers to
8403c838a9fSAndrew Rybchenko 		 * mean loopbacks supported by off-chip hardware. Keep that
8413c838a9fSAndrew Rybchenko 		 * meaning here.
8423c838a9fSAndrew Rybchenko 		 */
8433c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY);
8443c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask,	EFX_LOOPBACK_PHY_XS);
8453c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS);
8463c838a9fSAndrew Rybchenko 		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD);
8473c838a9fSAndrew Rybchenko 	}
8483c838a9fSAndrew Rybchenko 
8493c838a9fSAndrew Rybchenko 	*maskp = mask;
8503c838a9fSAndrew Rybchenko }
8513c838a9fSAndrew Rybchenko 
852460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_mcdi_get_loopback_modes(__in efx_nic_t * enp)8533c838a9fSAndrew Rybchenko efx_mcdi_get_loopback_modes(
8543c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp)
8553c838a9fSAndrew Rybchenko {
8563c838a9fSAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
8573c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
858315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LOOPBACK_MODES_IN_LEN,
859315bbbaaSAndrew Rybchenko 		MC_CMD_GET_LOOPBACK_MODES_OUT_V2_LEN);
8603c838a9fSAndrew Rybchenko 	efx_qword_t mask;
8613c838a9fSAndrew Rybchenko 	efx_qword_t modes;
862460cb568SAndrew Rybchenko 	efx_rc_t rc;
8633c838a9fSAndrew Rybchenko 
8643c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES;
8653c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
8663c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN;
8673c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
868725bb178SAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_V2_LEN;
8693c838a9fSAndrew Rybchenko 
8703c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
8713c838a9fSAndrew Rybchenko 
8723c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
8733c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
8743c838a9fSAndrew Rybchenko 		goto fail1;
8753c838a9fSAndrew Rybchenko 	}
8763c838a9fSAndrew Rybchenko 
8773c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used <
8783c838a9fSAndrew Rybchenko 	    MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST +
8793c838a9fSAndrew Rybchenko 	    MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) {
8803c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
8813c838a9fSAndrew Rybchenko 		goto fail2;
8823c838a9fSAndrew Rybchenko 	}
8833c838a9fSAndrew Rybchenko 
8843c838a9fSAndrew Rybchenko 	/*
8853c838a9fSAndrew Rybchenko 	 * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree
8863c838a9fSAndrew Rybchenko 	 * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link().
8873c838a9fSAndrew Rybchenko 	 */
8883c838a9fSAndrew Rybchenko 	efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask);
8893c838a9fSAndrew Rybchenko 
8903c838a9fSAndrew Rybchenko 	EFX_AND_QWORD(mask,
8913c838a9fSAndrew Rybchenko 	    *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED));
8923c838a9fSAndrew Rybchenko 
8933c838a9fSAndrew Rybchenko 	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M);
8943c838a9fSAndrew Rybchenko 	EFX_AND_QWORD(modes, mask);
8953c838a9fSAndrew Rybchenko 	encp->enc_loopback_types[EFX_LINK_100FDX] = modes;
8963c838a9fSAndrew Rybchenko 
8973c838a9fSAndrew Rybchenko 	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G);
8983c838a9fSAndrew Rybchenko 	EFX_AND_QWORD(modes, mask);
8993c838a9fSAndrew Rybchenko 	encp->enc_loopback_types[EFX_LINK_1000FDX] = modes;
9003c838a9fSAndrew Rybchenko 
9013c838a9fSAndrew Rybchenko 	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G);
9023c838a9fSAndrew Rybchenko 	EFX_AND_QWORD(modes, mask);
9033c838a9fSAndrew Rybchenko 	encp->enc_loopback_types[EFX_LINK_10000FDX] = modes;
9043c838a9fSAndrew Rybchenko 
9053c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used >=
9063c838a9fSAndrew Rybchenko 	    MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST +
9073c838a9fSAndrew Rybchenko 	    MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) {
9083c838a9fSAndrew Rybchenko 		/* Response includes 40G loopback modes */
909725bb178SAndrew Rybchenko 		modes = *MCDI_OUT2(req, efx_qword_t,
910725bb178SAndrew Rybchenko 		    GET_LOOPBACK_MODES_OUT_40G);
9113c838a9fSAndrew Rybchenko 		EFX_AND_QWORD(modes, mask);
9123c838a9fSAndrew Rybchenko 		encp->enc_loopback_types[EFX_LINK_40000FDX] = modes;
9133c838a9fSAndrew Rybchenko 	}
9143c838a9fSAndrew Rybchenko 
915725bb178SAndrew Rybchenko 	if (req.emr_out_length_used >=
916725bb178SAndrew Rybchenko 	    MC_CMD_GET_LOOPBACK_MODES_OUT_V2_25G_OFST +
917725bb178SAndrew Rybchenko 	    MC_CMD_GET_LOOPBACK_MODES_OUT_V2_25G_LEN) {
918725bb178SAndrew Rybchenko 		/* Response includes 25G loopback modes */
919725bb178SAndrew Rybchenko 		modes = *MCDI_OUT2(req, efx_qword_t,
920725bb178SAndrew Rybchenko 		    GET_LOOPBACK_MODES_OUT_V2_25G);
921725bb178SAndrew Rybchenko 		EFX_AND_QWORD(modes, mask);
922725bb178SAndrew Rybchenko 		encp->enc_loopback_types[EFX_LINK_25000FDX] = modes;
923725bb178SAndrew Rybchenko 	}
924725bb178SAndrew Rybchenko 
925725bb178SAndrew Rybchenko 	if (req.emr_out_length_used >=
926725bb178SAndrew Rybchenko 	    MC_CMD_GET_LOOPBACK_MODES_OUT_V2_50G_OFST +
927725bb178SAndrew Rybchenko 	    MC_CMD_GET_LOOPBACK_MODES_OUT_V2_50G_LEN) {
928725bb178SAndrew Rybchenko 		/* Response includes 50G loopback modes */
929725bb178SAndrew Rybchenko 		modes = *MCDI_OUT2(req, efx_qword_t,
930725bb178SAndrew Rybchenko 		    GET_LOOPBACK_MODES_OUT_V2_50G);
931725bb178SAndrew Rybchenko 		EFX_AND_QWORD(modes, mask);
932725bb178SAndrew Rybchenko 		encp->enc_loopback_types[EFX_LINK_50000FDX] = modes;
933725bb178SAndrew Rybchenko 	}
934725bb178SAndrew Rybchenko 
935725bb178SAndrew Rybchenko 	if (req.emr_out_length_used >=
936725bb178SAndrew Rybchenko 	    MC_CMD_GET_LOOPBACK_MODES_OUT_V2_100G_OFST +
937725bb178SAndrew Rybchenko 	    MC_CMD_GET_LOOPBACK_MODES_OUT_V2_100G_LEN) {
938725bb178SAndrew Rybchenko 		/* Response includes 100G loopback modes */
939725bb178SAndrew Rybchenko 		modes = *MCDI_OUT2(req, efx_qword_t,
940725bb178SAndrew Rybchenko 		    GET_LOOPBACK_MODES_OUT_V2_100G);
941725bb178SAndrew Rybchenko 		EFX_AND_QWORD(modes, mask);
942725bb178SAndrew Rybchenko 		encp->enc_loopback_types[EFX_LINK_100000FDX] = modes;
943725bb178SAndrew Rybchenko 	}
944725bb178SAndrew Rybchenko 
9453c838a9fSAndrew Rybchenko 	EFX_ZERO_QWORD(modes);
9463c838a9fSAndrew Rybchenko 	EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF);
9473c838a9fSAndrew Rybchenko 	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]);
9483c838a9fSAndrew Rybchenko 	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]);
9493c838a9fSAndrew Rybchenko 	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]);
9503c838a9fSAndrew Rybchenko 	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]);
951725bb178SAndrew Rybchenko 	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_25000FDX]);
952725bb178SAndrew Rybchenko 	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_50000FDX]);
953725bb178SAndrew Rybchenko 	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100000FDX]);
9543c838a9fSAndrew Rybchenko 	encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes;
9553c838a9fSAndrew Rybchenko 
9563c838a9fSAndrew Rybchenko 	return (0);
9573c838a9fSAndrew Rybchenko 
9583c838a9fSAndrew Rybchenko fail2:
9593c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
9603c838a9fSAndrew Rybchenko fail1:
961460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
9623c838a9fSAndrew Rybchenko 
9633c838a9fSAndrew Rybchenko 	return (rc);
9643c838a9fSAndrew Rybchenko }
9653c838a9fSAndrew Rybchenko 
9663c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_LOOPBACK */
967f6d61784SAndrew Rybchenko 
968f6d61784SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_nic_calculate_pcie_link_bandwidth(__in uint32_t pcie_link_width,__in uint32_t pcie_link_gen,__out uint32_t * bandwidth_mbpsp)969f6d61784SAndrew Rybchenko efx_nic_calculate_pcie_link_bandwidth(
970f6d61784SAndrew Rybchenko 	__in		uint32_t pcie_link_width,
971f6d61784SAndrew Rybchenko 	__in		uint32_t pcie_link_gen,
972f6d61784SAndrew Rybchenko 	__out		uint32_t *bandwidth_mbpsp)
973f6d61784SAndrew Rybchenko {
974f6d61784SAndrew Rybchenko 	uint32_t lane_bandwidth;
975f6d61784SAndrew Rybchenko 	uint32_t total_bandwidth;
976f6d61784SAndrew Rybchenko 	efx_rc_t rc;
977f6d61784SAndrew Rybchenko 
978f6d61784SAndrew Rybchenko 	if ((pcie_link_width == 0) || (pcie_link_width > 16) ||
979f6d61784SAndrew Rybchenko 	    !ISP2(pcie_link_width)) {
980f6d61784SAndrew Rybchenko 		rc = EINVAL;
981f6d61784SAndrew Rybchenko 		goto fail1;
982f6d61784SAndrew Rybchenko 	}
983f6d61784SAndrew Rybchenko 
984f6d61784SAndrew Rybchenko 	switch (pcie_link_gen) {
985f6d61784SAndrew Rybchenko 	case EFX_PCIE_LINK_SPEED_GEN1:
986f6d61784SAndrew Rybchenko 		/* 2.5 Gb/s raw bandwidth with 8b/10b encoding */
987f6d61784SAndrew Rybchenko 		lane_bandwidth = 2000;
988f6d61784SAndrew Rybchenko 		break;
989f6d61784SAndrew Rybchenko 	case EFX_PCIE_LINK_SPEED_GEN2:
990f6d61784SAndrew Rybchenko 		/* 5.0 Gb/s raw bandwidth with 8b/10b encoding */
991f6d61784SAndrew Rybchenko 		lane_bandwidth = 4000;
992f6d61784SAndrew Rybchenko 		break;
993f6d61784SAndrew Rybchenko 	case EFX_PCIE_LINK_SPEED_GEN3:
994f6d61784SAndrew Rybchenko 		/* 8.0 Gb/s raw bandwidth with 128b/130b encoding */
995f6d61784SAndrew Rybchenko 		lane_bandwidth = 7877;
996f6d61784SAndrew Rybchenko 		break;
997f6d61784SAndrew Rybchenko 	default:
998f6d61784SAndrew Rybchenko 		rc = EINVAL;
999f6d61784SAndrew Rybchenko 		goto fail2;
1000f6d61784SAndrew Rybchenko 	}
1001f6d61784SAndrew Rybchenko 
1002f6d61784SAndrew Rybchenko 	total_bandwidth = lane_bandwidth * pcie_link_width;
1003f6d61784SAndrew Rybchenko 	*bandwidth_mbpsp = total_bandwidth;
1004f6d61784SAndrew Rybchenko 
1005f6d61784SAndrew Rybchenko 	return (0);
1006f6d61784SAndrew Rybchenko 
1007f6d61784SAndrew Rybchenko fail2:
1008f6d61784SAndrew Rybchenko 	EFSYS_PROBE(fail2);
1009f6d61784SAndrew Rybchenko fail1:
1010f6d61784SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1011f6d61784SAndrew Rybchenko 
1012f6d61784SAndrew Rybchenko 	return (rc);
1013f6d61784SAndrew Rybchenko }
1014f6d61784SAndrew Rybchenko 
101517bcc056SAndrew Rybchenko #if EFSYS_OPT_FW_SUBVARIANT_AWARE
101617bcc056SAndrew Rybchenko 
101717bcc056SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_nic_get_fw_subvariant(__in efx_nic_t * enp,__out efx_nic_fw_subvariant_t * subvariantp)101817bcc056SAndrew Rybchenko efx_nic_get_fw_subvariant(
101917bcc056SAndrew Rybchenko 	__in		efx_nic_t *enp,
102017bcc056SAndrew Rybchenko 	__out		efx_nic_fw_subvariant_t *subvariantp)
102117bcc056SAndrew Rybchenko {
102217bcc056SAndrew Rybchenko 	efx_rc_t rc;
102317bcc056SAndrew Rybchenko 	uint32_t value;
102417bcc056SAndrew Rybchenko 
102517bcc056SAndrew Rybchenko 	rc = efx_mcdi_get_nic_global(enp,
102617bcc056SAndrew Rybchenko 	    MC_CMD_SET_NIC_GLOBAL_IN_FIRMWARE_SUBVARIANT, &value);
102717bcc056SAndrew Rybchenko 	if (rc != 0)
102817bcc056SAndrew Rybchenko 		goto fail1;
102917bcc056SAndrew Rybchenko 
103017bcc056SAndrew Rybchenko 	/* Mapping is not required since values match MCDI */
103117bcc056SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_NIC_FW_SUBVARIANT_DEFAULT ==
103217bcc056SAndrew Rybchenko 	    MC_CMD_SET_NIC_GLOBAL_IN_FW_SUBVARIANT_DEFAULT);
103317bcc056SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_NIC_FW_SUBVARIANT_NO_TX_CSUM ==
103417bcc056SAndrew Rybchenko 	    MC_CMD_SET_NIC_GLOBAL_IN_FW_SUBVARIANT_NO_TX_CSUM);
103517bcc056SAndrew Rybchenko 
103617bcc056SAndrew Rybchenko 	switch (value) {
103717bcc056SAndrew Rybchenko 	case MC_CMD_SET_NIC_GLOBAL_IN_FW_SUBVARIANT_DEFAULT:
103817bcc056SAndrew Rybchenko 	case MC_CMD_SET_NIC_GLOBAL_IN_FW_SUBVARIANT_NO_TX_CSUM:
103917bcc056SAndrew Rybchenko 		*subvariantp = value;
104017bcc056SAndrew Rybchenko 		break;
104117bcc056SAndrew Rybchenko 	default:
104217bcc056SAndrew Rybchenko 		rc = EINVAL;
104317bcc056SAndrew Rybchenko 		goto fail2;
104417bcc056SAndrew Rybchenko 	}
104517bcc056SAndrew Rybchenko 
104617bcc056SAndrew Rybchenko 	return (0);
104717bcc056SAndrew Rybchenko 
104817bcc056SAndrew Rybchenko fail2:
104917bcc056SAndrew Rybchenko 	EFSYS_PROBE(fail2);
105017bcc056SAndrew Rybchenko 
105117bcc056SAndrew Rybchenko fail1:
105217bcc056SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
105317bcc056SAndrew Rybchenko 
105417bcc056SAndrew Rybchenko 	return (rc);
105517bcc056SAndrew Rybchenko }
105617bcc056SAndrew Rybchenko 
105717bcc056SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_nic_set_fw_subvariant(__in efx_nic_t * enp,__in efx_nic_fw_subvariant_t subvariant)105817bcc056SAndrew Rybchenko efx_nic_set_fw_subvariant(
105917bcc056SAndrew Rybchenko 	__in		efx_nic_t *enp,
106017bcc056SAndrew Rybchenko 	__in		efx_nic_fw_subvariant_t subvariant)
106117bcc056SAndrew Rybchenko {
106217bcc056SAndrew Rybchenko 	efx_rc_t rc;
106317bcc056SAndrew Rybchenko 
106417bcc056SAndrew Rybchenko 	switch (subvariant) {
106517bcc056SAndrew Rybchenko 	case EFX_NIC_FW_SUBVARIANT_DEFAULT:
106617bcc056SAndrew Rybchenko 	case EFX_NIC_FW_SUBVARIANT_NO_TX_CSUM:
106717bcc056SAndrew Rybchenko 		/* Mapping is not required since values match MCDI */
106817bcc056SAndrew Rybchenko 		break;
106917bcc056SAndrew Rybchenko 	default:
107017bcc056SAndrew Rybchenko 		rc = EINVAL;
107117bcc056SAndrew Rybchenko 		goto fail1;
107217bcc056SAndrew Rybchenko 	}
107317bcc056SAndrew Rybchenko 
107417bcc056SAndrew Rybchenko 	rc = efx_mcdi_set_nic_global(enp,
107517bcc056SAndrew Rybchenko 	    MC_CMD_SET_NIC_GLOBAL_IN_FIRMWARE_SUBVARIANT, subvariant);
107617bcc056SAndrew Rybchenko 	if (rc != 0)
107717bcc056SAndrew Rybchenko 		goto fail2;
107817bcc056SAndrew Rybchenko 
107917bcc056SAndrew Rybchenko 	return (0);
108017bcc056SAndrew Rybchenko 
108117bcc056SAndrew Rybchenko fail2:
108217bcc056SAndrew Rybchenko 	EFSYS_PROBE(fail2);
108317bcc056SAndrew Rybchenko 
108417bcc056SAndrew Rybchenko fail1:
108517bcc056SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
108617bcc056SAndrew Rybchenko 
108717bcc056SAndrew Rybchenko 	return (rc);
108817bcc056SAndrew Rybchenko }
108917bcc056SAndrew Rybchenko 
109017bcc056SAndrew Rybchenko #endif	/* EFSYS_OPT_FW_SUBVARIANT_AWARE */
1091f6d61784SAndrew Rybchenko 
1092f6d61784SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_nic_check_pcie_link_speed(__in efx_nic_t * enp,__in uint32_t pcie_link_width,__in uint32_t pcie_link_gen,__out efx_pcie_link_performance_t * resultp)1093f6d61784SAndrew Rybchenko efx_nic_check_pcie_link_speed(
1094f6d61784SAndrew Rybchenko 	__in		efx_nic_t *enp,
1095f6d61784SAndrew Rybchenko 	__in		uint32_t pcie_link_width,
1096f6d61784SAndrew Rybchenko 	__in		uint32_t pcie_link_gen,
1097f6d61784SAndrew Rybchenko 	__out		efx_pcie_link_performance_t *resultp)
1098f6d61784SAndrew Rybchenko {
1099f6d61784SAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1100f6d61784SAndrew Rybchenko 	uint32_t bandwidth;
1101f6d61784SAndrew Rybchenko 	efx_pcie_link_performance_t result;
1102f6d61784SAndrew Rybchenko 	efx_rc_t rc;
1103f6d61784SAndrew Rybchenko 
1104f6d61784SAndrew Rybchenko 	if ((encp->enc_required_pcie_bandwidth_mbps == 0) ||
1105f6d61784SAndrew Rybchenko 	    (pcie_link_width == 0) || (pcie_link_width == 32) ||
1106f6d61784SAndrew Rybchenko 	    (pcie_link_gen == 0)) {
1107f6d61784SAndrew Rybchenko 		/*
1108f6d61784SAndrew Rybchenko 		 * No usable info on what is required and/or in use. In virtual
1109f6d61784SAndrew Rybchenko 		 * machines, sometimes the PCIe link width is reported as 0 or
1110f6d61784SAndrew Rybchenko 		 * 32, or the speed as 0.
1111f6d61784SAndrew Rybchenko 		 */
1112f6d61784SAndrew Rybchenko 		result = EFX_PCIE_LINK_PERFORMANCE_UNKNOWN_BANDWIDTH;
1113f6d61784SAndrew Rybchenko 		goto out;
1114f6d61784SAndrew Rybchenko 	}
1115f6d61784SAndrew Rybchenko 
1116f6d61784SAndrew Rybchenko 	/* Calculate the available bandwidth in megabits per second */
1117f6d61784SAndrew Rybchenko 	rc = efx_nic_calculate_pcie_link_bandwidth(pcie_link_width,
1118f6d61784SAndrew Rybchenko 					    pcie_link_gen, &bandwidth);
1119f6d61784SAndrew Rybchenko 	if (rc != 0)
1120f6d61784SAndrew Rybchenko 		goto fail1;
1121f6d61784SAndrew Rybchenko 
1122f6d61784SAndrew Rybchenko 	if (bandwidth < encp->enc_required_pcie_bandwidth_mbps) {
1123f6d61784SAndrew Rybchenko 		result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_BANDWIDTH;
1124f6d61784SAndrew Rybchenko 	} else if (pcie_link_gen < encp->enc_max_pcie_link_gen) {
1125f6d61784SAndrew Rybchenko 		/* The link provides enough bandwidth but not optimal latency */
1126f6d61784SAndrew Rybchenko 		result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_LATENCY;
1127f6d61784SAndrew Rybchenko 	} else {
1128f6d61784SAndrew Rybchenko 		result = EFX_PCIE_LINK_PERFORMANCE_OPTIMAL;
1129f6d61784SAndrew Rybchenko 	}
1130f6d61784SAndrew Rybchenko 
1131f6d61784SAndrew Rybchenko out:
1132f6d61784SAndrew Rybchenko 	*resultp = result;
1133f6d61784SAndrew Rybchenko 
1134f6d61784SAndrew Rybchenko 	return (0);
1135f6d61784SAndrew Rybchenko 
1136f6d61784SAndrew Rybchenko fail1:
1137f6d61784SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1138f6d61784SAndrew Rybchenko 
1139f6d61784SAndrew Rybchenko 	return (rc);
1140f6d61784SAndrew Rybchenko }
1141