1227569Sphilip/*-
2301388Sarybchik * Copyright (c) 2007-2016 Solarflare Communications Inc.
3284555Sarybchik * All rights reserved.
4227569Sphilip *
5227569Sphilip * Redistribution and use in source and binary forms, with or without
6284555Sarybchik * modification, are permitted provided that the following conditions are met:
7227569Sphilip *
8284555Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9284555Sarybchik *    this list of conditions and the following disclaimer.
10284555Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11284555Sarybchik *    this list of conditions and the following disclaimer in the documentation
12284555Sarybchik *    and/or other materials provided with the distribution.
13284555Sarybchik *
14284555Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15284555Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16284555Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17284555Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18284555Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19284555Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20284555Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21284555Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22284555Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23284555Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24284555Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25284555Sarybchik *
26284555Sarybchik * The views and conclusions contained in the software and documentation are
27284555Sarybchik * those of the authors and should not be interpreted as representing official
28284555Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29227569Sphilip */
30227569Sphilip
31228078Sphilip#include <sys/cdefs.h>
32228078Sphilip__FBSDID("$FreeBSD: stable/10/sys/dev/sfxge/common/efx_nic.c 342524 2018-12-26 10:37:06Z arybchik $");
33228078Sphilip
34227569Sphilip#include "efx.h"
35227569Sphilip#include "efx_impl.h"
36227569Sphilip
37293927Sarybchik	__checkReturn	efx_rc_t
38227569Sphilipefx_family(
39227569Sphilip	__in		uint16_t venid,
40227569Sphilip	__in		uint16_t devid,
41227569Sphilip	__out		efx_family_t *efp)
42227569Sphilip{
43284555Sarybchik	if (venid == EFX_PCI_VENID_SFC) {
44284555Sarybchik		switch (devid) {
45227569Sphilip#if EFSYS_OPT_SIENA
46284555Sarybchik		case EFX_PCI_DEVID_SIENA_F1_UNINIT:
47284555Sarybchik			/*
48284555Sarybchik			 * Hardware default for PF0 of uninitialised Siena.
49284555Sarybchik			 * manftest must be able to cope with this device id.
50284555Sarybchik			 */
51284555Sarybchik			*efp = EFX_FAMILY_SIENA;
52284555Sarybchik			return (0);
53284555Sarybchik
54284555Sarybchik		case EFX_PCI_DEVID_BETHPAGE:
55284555Sarybchik		case EFX_PCI_DEVID_SIENA:
56284555Sarybchik			*efp = EFX_FAMILY_SIENA;
57284555Sarybchik			return (0);
58293975Sarybchik#endif /* EFSYS_OPT_SIENA */
59284555Sarybchik
60284555Sarybchik#if EFSYS_OPT_HUNTINGTON
61284555Sarybchik		case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT:
62284555Sarybchik			/*
63284555Sarybchik			 * Hardware default for PF0 of uninitialised Huntington.
64284555Sarybchik			 * manftest must be able to cope with this device id.
65284555Sarybchik			 */
66284555Sarybchik			*efp = EFX_FAMILY_HUNTINGTON;
67284555Sarybchik			return (0);
68284555Sarybchik
69284555Sarybchik		case EFX_PCI_DEVID_FARMINGDALE:
70284555Sarybchik		case EFX_PCI_DEVID_GREENPORT:
71284555Sarybchik			*efp = EFX_FAMILY_HUNTINGTON;
72284555Sarybchik			return (0);
73284555Sarybchik
74284555Sarybchik		case EFX_PCI_DEVID_FARMINGDALE_VF:
75284555Sarybchik		case EFX_PCI_DEVID_GREENPORT_VF:
76284555Sarybchik			*efp = EFX_FAMILY_HUNTINGTON;
77284555Sarybchik			return (0);
78293975Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */
79293975Sarybchik
80293975Sarybchik#if EFSYS_OPT_MEDFORD
81293975Sarybchik		case EFX_PCI_DEVID_MEDFORD_PF_UNINIT:
82293975Sarybchik			/*
83293975Sarybchik			 * Hardware default for PF0 of uninitialised Medford.
84293975Sarybchik			 * manftest must be able to cope with this device id.
85293975Sarybchik			 */
86293975Sarybchik			*efp = EFX_FAMILY_MEDFORD;
87293975Sarybchik			return (0);
88293975Sarybchik
89293975Sarybchik		case EFX_PCI_DEVID_MEDFORD:
90293975Sarybchik			*efp = EFX_FAMILY_MEDFORD;
91293975Sarybchik			return (0);
92293975Sarybchik
93293975Sarybchik		case EFX_PCI_DEVID_MEDFORD_VF:
94293975Sarybchik			*efp = EFX_FAMILY_MEDFORD;
95293975Sarybchik			return (0);
96293975Sarybchik#endif /* EFSYS_OPT_MEDFORD */
97293975Sarybchik
98301324Sarybchik		case EFX_PCI_DEVID_FALCON:	/* Obsolete, not supported */
99284555Sarybchik		default:
100284555Sarybchik			break;
101284555Sarybchik		}
102227569Sphilip	}
103284555Sarybchik
104284555Sarybchik	*efp = EFX_FAMILY_INVALID;
105227569Sphilip	return (ENOTSUP);
106227569Sphilip}
107227569Sphilip
108227569Sphilip#if EFSYS_OPT_SIENA
109227569Sphilip
110301340Sarybchikstatic const efx_nic_ops_t	__efx_nic_siena_ops = {
111227569Sphilip	siena_nic_probe,		/* eno_probe */
112294377Sarybchik	NULL,				/* eno_board_cfg */
113284555Sarybchik	NULL,				/* eno_set_drv_limits */
114227569Sphilip	siena_nic_reset,		/* eno_reset */
115227569Sphilip	siena_nic_init,			/* eno_init */
116284555Sarybchik	NULL,				/* eno_get_vi_pool */
117284555Sarybchik	NULL,				/* eno_get_bar_region */
118227569Sphilip#if EFSYS_OPT_DIAG
119227569Sphilip	siena_nic_register_test,	/* eno_register_test */
120227569Sphilip#endif	/* EFSYS_OPT_DIAG */
121227569Sphilip	siena_nic_fini,			/* eno_fini */
122227569Sphilip	siena_nic_unprobe,		/* eno_unprobe */
123227569Sphilip};
124227569Sphilip
125227569Sphilip#endif	/* EFSYS_OPT_SIENA */
126227569Sphilip
127284555Sarybchik#if EFSYS_OPT_HUNTINGTON
128284555Sarybchik
129301340Sarybchikstatic const efx_nic_ops_t	__efx_nic_hunt_ops = {
130294006Sarybchik	ef10_nic_probe,			/* eno_probe */
131294377Sarybchik	hunt_board_cfg,			/* eno_board_cfg */
132294006Sarybchik	ef10_nic_set_drv_limits,	/* eno_set_drv_limits */
133294006Sarybchik	ef10_nic_reset,			/* eno_reset */
134294006Sarybchik	ef10_nic_init,			/* eno_init */
135294006Sarybchik	ef10_nic_get_vi_pool,		/* eno_get_vi_pool */
136294006Sarybchik	ef10_nic_get_bar_region,	/* eno_get_bar_region */
137284555Sarybchik#if EFSYS_OPT_DIAG
138294006Sarybchik	ef10_nic_register_test,		/* eno_register_test */
139284555Sarybchik#endif	/* EFSYS_OPT_DIAG */
140294006Sarybchik	ef10_nic_fini,			/* eno_fini */
141294006Sarybchik	ef10_nic_unprobe,		/* eno_unprobe */
142284555Sarybchik};
143284555Sarybchik
144284555Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
145284555Sarybchik
146294377Sarybchik#if EFSYS_OPT_MEDFORD
147294377Sarybchik
148301340Sarybchikstatic const efx_nic_ops_t	__efx_nic_medford_ops = {
149294377Sarybchik	ef10_nic_probe,			/* eno_probe */
150294377Sarybchik	medford_board_cfg,		/* eno_board_cfg */
151294377Sarybchik	ef10_nic_set_drv_limits,	/* eno_set_drv_limits */
152294377Sarybchik	ef10_nic_reset,			/* eno_reset */
153294377Sarybchik	ef10_nic_init,			/* eno_init */
154294377Sarybchik	ef10_nic_get_vi_pool,		/* eno_get_vi_pool */
155294377Sarybchik	ef10_nic_get_bar_region,	/* eno_get_bar_region */
156294377Sarybchik#if EFSYS_OPT_DIAG
157294377Sarybchik	ef10_nic_register_test,		/* eno_register_test */
158294377Sarybchik#endif	/* EFSYS_OPT_DIAG */
159294377Sarybchik	ef10_nic_fini,			/* eno_fini */
160294377Sarybchik	ef10_nic_unprobe,		/* eno_unprobe */
161294377Sarybchik};
162294377Sarybchik
163294377Sarybchik#endif	/* EFSYS_OPT_MEDFORD */
164294377Sarybchik
165294377Sarybchik
166293927Sarybchik	__checkReturn	efx_rc_t
167227569Sphilipefx_nic_create(
168227569Sphilip	__in		efx_family_t family,
169227569Sphilip	__in		efsys_identifier_t *esip,
170227569Sphilip	__in		efsys_bar_t *esbp,
171227569Sphilip	__in		efsys_lock_t *eslp,
172227569Sphilip	__deref_out	efx_nic_t **enpp)
173227569Sphilip{
174227569Sphilip	efx_nic_t *enp;
175293927Sarybchik	efx_rc_t rc;
176227569Sphilip
177227569Sphilip	EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID);
178227569Sphilip	EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES);
179227569Sphilip
180227569Sphilip	/* Allocate a NIC object */
181227569Sphilip	EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp);
182227569Sphilip
183227569Sphilip	if (enp == NULL) {
184227569Sphilip		rc = ENOMEM;
185227569Sphilip		goto fail1;
186227569Sphilip	}
187227569Sphilip
188227569Sphilip	enp->en_magic = EFX_NIC_MAGIC;
189227569Sphilip
190227569Sphilip	switch (family) {
191227569Sphilip#if EFSYS_OPT_SIENA
192227569Sphilip	case EFX_FAMILY_SIENA:
193301340Sarybchik		enp->en_enop = &__efx_nic_siena_ops;
194280563Sarybchik		enp->en_features =
195280563Sarybchik		    EFX_FEATURE_IPV6 |
196227569Sphilip		    EFX_FEATURE_LFSR_HASH_INSERT |
197280563Sarybchik		    EFX_FEATURE_LINK_EVENTS |
198280563Sarybchik		    EFX_FEATURE_PERIODIC_MAC_STATS |
199280563Sarybchik		    EFX_FEATURE_MCDI |
200280535Sarybchik		    EFX_FEATURE_LOOKAHEAD_SPLIT |
201284555Sarybchik		    EFX_FEATURE_MAC_HEADER_FILTERS |
202284555Sarybchik		    EFX_FEATURE_TX_SRC_FILTERS;
203227569Sphilip		break;
204227569Sphilip#endif	/* EFSYS_OPT_SIENA */
205227569Sphilip
206284555Sarybchik#if EFSYS_OPT_HUNTINGTON
207284555Sarybchik	case EFX_FAMILY_HUNTINGTON:
208301340Sarybchik		enp->en_enop = &__efx_nic_hunt_ops;
209284555Sarybchik		enp->en_features =
210284555Sarybchik		    EFX_FEATURE_IPV6 |
211284555Sarybchik		    EFX_FEATURE_LINK_EVENTS |
212284555Sarybchik		    EFX_FEATURE_PERIODIC_MAC_STATS |
213284555Sarybchik		    EFX_FEATURE_MCDI |
214284555Sarybchik		    EFX_FEATURE_MAC_HEADER_FILTERS |
215284555Sarybchik		    EFX_FEATURE_MCDI_DMA |
216284555Sarybchik		    EFX_FEATURE_PIO_BUFFERS |
217294381Sarybchik		    EFX_FEATURE_FW_ASSISTED_TSO |
218342524Sarybchik		    EFX_FEATURE_FW_ASSISTED_TSO_V2 |
219342524Sarybchik		    EFX_FEATURE_TXQ_CKSUM_OP_DESC;
220284555Sarybchik		break;
221284555Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
222284555Sarybchik
223294377Sarybchik#if EFSYS_OPT_MEDFORD
224294377Sarybchik	case EFX_FAMILY_MEDFORD:
225301340Sarybchik		enp->en_enop = &__efx_nic_medford_ops;
226294377Sarybchik		/*
227294377Sarybchik		 * FW_ASSISTED_TSO ommitted as Medford only supports firmware
228294377Sarybchik		 * assisted TSO version 2, not the v1 scheme used on Huntington.
229294377Sarybchik		 */
230294377Sarybchik		enp->en_features =
231294377Sarybchik		    EFX_FEATURE_IPV6 |
232294377Sarybchik		    EFX_FEATURE_LINK_EVENTS |
233294377Sarybchik		    EFX_FEATURE_PERIODIC_MAC_STATS |
234294377Sarybchik		    EFX_FEATURE_MCDI |
235294377Sarybchik		    EFX_FEATURE_MAC_HEADER_FILTERS |
236294377Sarybchik		    EFX_FEATURE_MCDI_DMA |
237301372Sarybchik		    EFX_FEATURE_PIO_BUFFERS |
238342524Sarybchik		    EFX_FEATURE_FW_ASSISTED_TSO_V2 |
239342524Sarybchik		    EFX_FEATURE_TXQ_CKSUM_OP_DESC;
240294377Sarybchik		break;
241294377Sarybchik#endif	/* EFSYS_OPT_MEDFORD */
242294377Sarybchik
243227569Sphilip	default:
244227569Sphilip		rc = ENOTSUP;
245227569Sphilip		goto fail2;
246227569Sphilip	}
247227569Sphilip
248227569Sphilip	enp->en_family = family;
249227569Sphilip	enp->en_esip = esip;
250227569Sphilip	enp->en_esbp = esbp;
251227569Sphilip	enp->en_eslp = eslp;
252227569Sphilip
253227569Sphilip	*enpp = enp;
254227569Sphilip
255227569Sphilip	return (0);
256227569Sphilip
257227569Sphilipfail2:
258284555Sarybchik	EFSYS_PROBE(fail2);
259227569Sphilip
260227569Sphilip	enp->en_magic = 0;
261227569Sphilip
262227569Sphilip	/* Free the NIC object */
263227569Sphilip	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
264227569Sphilip
265227569Sphilipfail1:
266293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
267227569Sphilip
268227569Sphilip	return (rc);
269227569Sphilip}
270227569Sphilip
271293927Sarybchik	__checkReturn	efx_rc_t
272227569Sphilipefx_nic_probe(
273227569Sphilip	__in		efx_nic_t *enp)
274227569Sphilip{
275301340Sarybchik	const efx_nic_ops_t *enop;
276293927Sarybchik	efx_rc_t rc;
277227569Sphilip
278227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
279227569Sphilip#if EFSYS_OPT_MCDI
280227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
281227569Sphilip#endif	/* EFSYS_OPT_MCDI */
282227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE));
283227569Sphilip
284227569Sphilip	enop = enp->en_enop;
285227569Sphilip	if ((rc = enop->eno_probe(enp)) != 0)
286284555Sarybchik		goto fail1;
287227569Sphilip
288227569Sphilip	if ((rc = efx_phy_probe(enp)) != 0)
289284555Sarybchik		goto fail2;
290227569Sphilip
291227569Sphilip	enp->en_mod_flags |= EFX_MOD_PROBE;
292227569Sphilip
293227569Sphilip	return (0);
294227569Sphilip
295284555Sarybchikfail2:
296284555Sarybchik	EFSYS_PROBE(fail2);
297227569Sphilip
298227569Sphilip	enop->eno_unprobe(enp);
299227569Sphilip
300227569Sphilipfail1:
301293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
302227569Sphilip
303227569Sphilip	return (rc);
304227569Sphilip}
305227569Sphilip
306293927Sarybchik	__checkReturn	efx_rc_t
307284555Sarybchikefx_nic_set_drv_limits(
308284555Sarybchik	__inout		efx_nic_t *enp,
309284555Sarybchik	__in		efx_drv_limits_t *edlp)
310284555Sarybchik{
311301340Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
312293927Sarybchik	efx_rc_t rc;
313284555Sarybchik
314284555Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
315284555Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
316284555Sarybchik
317284555Sarybchik	if (enop->eno_set_drv_limits != NULL) {
318284555Sarybchik		if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0)
319284555Sarybchik			goto fail1;
320284555Sarybchik	}
321284555Sarybchik
322284555Sarybchik	return (0);
323284555Sarybchik
324284555Sarybchikfail1:
325293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
326284555Sarybchik
327284555Sarybchik	return (rc);
328284555Sarybchik}
329284555Sarybchik
330293927Sarybchik	__checkReturn	efx_rc_t
331284555Sarybchikefx_nic_get_bar_region(
332284555Sarybchik	__in		efx_nic_t *enp,
333284555Sarybchik	__in		efx_nic_region_t region,
334284555Sarybchik	__out		uint32_t *offsetp,
335284555Sarybchik	__out		size_t *sizep)
336284555Sarybchik{
337301340Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
338293927Sarybchik	efx_rc_t rc;
339284555Sarybchik
340284555Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
341284555Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
342284555Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
343284555Sarybchik
344284555Sarybchik	if (enop->eno_get_bar_region == NULL) {
345284555Sarybchik		rc = ENOTSUP;
346284555Sarybchik		goto fail1;
347284555Sarybchik	}
348284555Sarybchik	if ((rc = (enop->eno_get_bar_region)(enp,
349284555Sarybchik		    region, offsetp, sizep)) != 0) {
350284555Sarybchik		goto fail2;
351284555Sarybchik	}
352284555Sarybchik
353284555Sarybchik	return (0);
354284555Sarybchik
355284555Sarybchikfail2:
356284555Sarybchik	EFSYS_PROBE(fail2);
357284555Sarybchik
358284555Sarybchikfail1:
359293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
360284555Sarybchik
361284555Sarybchik	return (rc);
362284555Sarybchik}
363284555Sarybchik
364284555Sarybchik
365293927Sarybchik	__checkReturn	efx_rc_t
366284555Sarybchikefx_nic_get_vi_pool(
367284555Sarybchik	__in		efx_nic_t *enp,
368284555Sarybchik	__out		uint32_t *evq_countp,
369284555Sarybchik	__out		uint32_t *rxq_countp,
370284555Sarybchik	__out		uint32_t *txq_countp)
371284555Sarybchik{
372301340Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
373284555Sarybchik	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
374293927Sarybchik	efx_rc_t rc;
375284555Sarybchik
376284555Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
377284555Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
378284555Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
379284555Sarybchik
380284555Sarybchik	if (enop->eno_get_vi_pool != NULL) {
381284555Sarybchik		uint32_t vi_count = 0;
382284555Sarybchik
383284555Sarybchik		if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0)
384284555Sarybchik			goto fail1;
385284555Sarybchik
386284555Sarybchik		*evq_countp = vi_count;
387284555Sarybchik		*rxq_countp = vi_count;
388284555Sarybchik		*txq_countp = vi_count;
389284555Sarybchik	} else {
390284555Sarybchik		/* Use NIC limits as default value */
391284555Sarybchik		*evq_countp = encp->enc_evq_limit;
392284555Sarybchik		*rxq_countp = encp->enc_rxq_limit;
393284555Sarybchik		*txq_countp = encp->enc_txq_limit;
394284555Sarybchik	}
395284555Sarybchik
396284555Sarybchik	return (0);
397284555Sarybchik
398284555Sarybchikfail1:
399293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
400284555Sarybchik
401284555Sarybchik	return (rc);
402284555Sarybchik}
403284555Sarybchik
404284555Sarybchik
405293927Sarybchik	__checkReturn	efx_rc_t
406227569Sphilipefx_nic_init(
407227569Sphilip	__in		efx_nic_t *enp)
408227569Sphilip{
409301340Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
410293927Sarybchik	efx_rc_t rc;
411227569Sphilip
412227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
413227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
414227569Sphilip
415227569Sphilip	if (enp->en_mod_flags & EFX_MOD_NIC) {
416227569Sphilip		rc = EINVAL;
417227569Sphilip		goto fail1;
418227569Sphilip	}
419227569Sphilip
420227569Sphilip	if ((rc = enop->eno_init(enp)) != 0)
421227569Sphilip		goto fail2;
422227569Sphilip
423227569Sphilip	enp->en_mod_flags |= EFX_MOD_NIC;
424227569Sphilip
425227569Sphilip	return (0);
426227569Sphilip
427227569Sphilipfail2:
428227569Sphilip	EFSYS_PROBE(fail2);
429227569Sphilipfail1:
430293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
431227569Sphilip
432227569Sphilip	return (rc);
433227569Sphilip}
434227569Sphilip
435227569Sphilip			void
436227569Sphilipefx_nic_fini(
437227569Sphilip	__in		efx_nic_t *enp)
438227569Sphilip{
439301340Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
440227569Sphilip
441227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
442227569Sphilip	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
443227569Sphilip	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC);
444227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
445227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
446227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
447227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
448227569Sphilip
449227569Sphilip	enop->eno_fini(enp);
450227569Sphilip
451227569Sphilip	enp->en_mod_flags &= ~EFX_MOD_NIC;
452227569Sphilip}
453227569Sphilip
454227569Sphilip			void
455227569Sphilipefx_nic_unprobe(
456227569Sphilip	__in		efx_nic_t *enp)
457227569Sphilip{
458301340Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
459227569Sphilip
460227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
461227569Sphilip#if EFSYS_OPT_MCDI
462227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
463227569Sphilip#endif	/* EFSYS_OPT_MCDI */
464227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
465227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
466227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
467227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
468227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
469227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
470227569Sphilip
471227569Sphilip	efx_phy_unprobe(enp);
472227569Sphilip
473227569Sphilip	enop->eno_unprobe(enp);
474227569Sphilip
475227569Sphilip	enp->en_mod_flags &= ~EFX_MOD_PROBE;
476227569Sphilip}
477227569Sphilip
478227569Sphilip			void
479227569Sphilipefx_nic_destroy(
480227569Sphilip	__in	efx_nic_t *enp)
481227569Sphilip{
482227569Sphilip	efsys_identifier_t *esip = enp->en_esip;
483227569Sphilip
484227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
485227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
486227569Sphilip
487311068Sarybchik	enp->en_family = EFX_FAMILY_INVALID;
488227569Sphilip	enp->en_esip = NULL;
489227569Sphilip	enp->en_esbp = NULL;
490227569Sphilip	enp->en_eslp = NULL;
491227569Sphilip
492227569Sphilip	enp->en_enop = NULL;
493227569Sphilip
494227569Sphilip	enp->en_magic = 0;
495227569Sphilip
496227569Sphilip	/* Free the NIC object */
497227569Sphilip	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
498227569Sphilip}
499227569Sphilip
500293927Sarybchik	__checkReturn	efx_rc_t
501227569Sphilipefx_nic_reset(
502227569Sphilip	__in		efx_nic_t *enp)
503227569Sphilip{
504301340Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
505227569Sphilip	unsigned int mod_flags;
506293927Sarybchik	efx_rc_t rc;
507227569Sphilip
508227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
509227569Sphilip	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
510227569Sphilip	/*
511301379Sarybchik	 * All modules except the MCDI, PROBE, NVRAM, VPD, MON
512294386Sarybchik	 * (which we do not reset here) must have been shut down or never
513294386Sarybchik	 * initialized.
514227569Sphilip	 *
515227569Sphilip	 * A rule of thumb here is: If the controller or MC reboots, is *any*
516227569Sphilip	 * state lost. If it's lost and needs reapplying, then the module
517227569Sphilip	 * *must* not be initialised during the reset.
518227569Sphilip	 */
519227569Sphilip	mod_flags = enp->en_mod_flags;
520227569Sphilip	mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM |
521301379Sarybchik		    EFX_MOD_VPD | EFX_MOD_MON);
522227569Sphilip	EFSYS_ASSERT3U(mod_flags, ==, 0);
523227569Sphilip	if (mod_flags != 0) {
524227569Sphilip		rc = EINVAL;
525227569Sphilip		goto fail1;
526227569Sphilip	}
527227569Sphilip
528227569Sphilip	if ((rc = enop->eno_reset(enp)) != 0)
529227569Sphilip		goto fail2;
530227569Sphilip
531227569Sphilip	return (0);
532227569Sphilip
533227569Sphilipfail2:
534227569Sphilip	EFSYS_PROBE(fail2);
535227569Sphilipfail1:
536293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
537227569Sphilip
538227569Sphilip	return (rc);
539227569Sphilip}
540227569Sphilip
541227569Sphilip			const efx_nic_cfg_t *
542227569Sphilipefx_nic_cfg_get(
543227569Sphilip	__in		efx_nic_t *enp)
544227569Sphilip{
545227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
546342517Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
547227569Sphilip
548227569Sphilip	return (&(enp->en_nic_cfg));
549227569Sphilip}
550227569Sphilip
551227569Sphilip#if EFSYS_OPT_DIAG
552227569Sphilip
553293927Sarybchik	__checkReturn	efx_rc_t
554227569Sphilipefx_nic_register_test(
555227569Sphilip	__in		efx_nic_t *enp)
556227569Sphilip{
557301340Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
558293927Sarybchik	efx_rc_t rc;
559227569Sphilip
560227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
561227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
562227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
563227569Sphilip
564227569Sphilip	if ((rc = enop->eno_register_test(enp)) != 0)
565227569Sphilip		goto fail1;
566227569Sphilip
567227569Sphilip	return (0);
568227569Sphilip
569227569Sphilipfail1:
570293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
571227569Sphilip
572227569Sphilip	return (rc);
573227569Sphilip}
574227569Sphilip
575227569Sphilip#endif	/* EFSYS_OPT_DIAG */
576284555Sarybchik
577284555Sarybchik#if EFSYS_OPT_LOOPBACK
578284555Sarybchik
579284555Sarybchikextern			void
580284555Sarybchikefx_loopback_mask(
581284555Sarybchik	__in	efx_loopback_kind_t loopback_kind,
582284555Sarybchik	__out	efx_qword_t *maskp)
583284555Sarybchik{
584284555Sarybchik	efx_qword_t mask;
585284555Sarybchik
586284555Sarybchik	EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS);
587284555Sarybchik	EFSYS_ASSERT(maskp != NULL);
588284555Sarybchik
589284555Sarybchik	/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
590284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
591284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
592284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
593284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
594284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
595284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
596284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
597284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
598284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
599284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
600284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
601284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
602284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
603284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
604284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
605284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
606284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
607284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
608284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT);
609284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS);
610284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS);
611284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR ==
612284555Sarybchik	    EFX_LOOPBACK_XAUI_WS_FAR);
613284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR ==
614284555Sarybchik	    EFX_LOOPBACK_XAUI_WS_NEAR);
615284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS);
616284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS);
617284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR ==
618284555Sarybchik	    EFX_LOOPBACK_XFI_WS_FAR);
619284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS);
620284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT);
621284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR);
622284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR);
623284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS ==
624284555Sarybchik	    EFX_LOOPBACK_PMA_INT_WS);
625284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS ==
626284555Sarybchik	    EFX_LOOPBACK_SD_FEP2_WS);
627284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS ==
628284555Sarybchik	    EFX_LOOPBACK_SD_FEP1_5_WS);
629284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS);
630284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS);
631284555Sarybchik
632284555Sarybchik	/* Build bitmask of possible loopback types */
633284555Sarybchik	EFX_ZERO_QWORD(mask);
634284555Sarybchik
635284555Sarybchik	if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) ||
636284555Sarybchik	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
637284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF);
638284555Sarybchik	}
639284555Sarybchik
640284555Sarybchik	if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) ||
641284555Sarybchik	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
642284555Sarybchik		/*
643284555Sarybchik		 * The "MAC" grouping has historically been used by drivers to
644284555Sarybchik		 * mean loopbacks supported by on-chip hardware. Keep that
645284555Sarybchik		 * meaning here, and include on-chip PHY layer loopbacks.
646284555Sarybchik		 */
647284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA);
648284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC);
649284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII);
650284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS);
651284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI);
652284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII);
653284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII);
654284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR);
655284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI);
656284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR);
657284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR);
658284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR);
659284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR);
660284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT);
661284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR);
662284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR);
663284555Sarybchik	}
664284555Sarybchik
665284555Sarybchik	if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) ||
666284555Sarybchik	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
667284555Sarybchik		/*
668284555Sarybchik		 * The "PHY" grouping has historically been used by drivers to
669284555Sarybchik		 * mean loopbacks supported by off-chip hardware. Keep that
670284555Sarybchik		 * meaning here.
671284555Sarybchik		 */
672284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY);
673284555Sarybchik		EFX_SET_QWORD_BIT(mask,	EFX_LOOPBACK_PHY_XS);
674284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS);
675284555Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD);
676284555Sarybchik	}
677284555Sarybchik
678284555Sarybchik	*maskp = mask;
679284555Sarybchik}
680284555Sarybchik
681293927Sarybchik	__checkReturn	efx_rc_t
682284555Sarybchikefx_mcdi_get_loopback_modes(
683284555Sarybchik	__in		efx_nic_t *enp)
684284555Sarybchik{
685284555Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
686284555Sarybchik	efx_mcdi_req_t req;
687342516Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LOOPBACK_MODES_IN_LEN,
688342516Sarybchik		MC_CMD_GET_LOOPBACK_MODES_OUT_LEN);
689284555Sarybchik	efx_qword_t mask;
690284555Sarybchik	efx_qword_t modes;
691293927Sarybchik	efx_rc_t rc;
692284555Sarybchik
693284555Sarybchik	req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES;
694284555Sarybchik	req.emr_in_buf = payload;
695284555Sarybchik	req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN;
696284555Sarybchik	req.emr_out_buf = payload;
697284555Sarybchik	req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN;
698284555Sarybchik
699284555Sarybchik	efx_mcdi_execute(enp, &req);
700284555Sarybchik
701284555Sarybchik	if (req.emr_rc != 0) {
702284555Sarybchik		rc = req.emr_rc;
703284555Sarybchik		goto fail1;
704284555Sarybchik	}
705284555Sarybchik
706284555Sarybchik	if (req.emr_out_length_used <
707284555Sarybchik	    MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST +
708284555Sarybchik	    MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) {
709284555Sarybchik		rc = EMSGSIZE;
710284555Sarybchik		goto fail2;
711284555Sarybchik	}
712284555Sarybchik
713284555Sarybchik	/*
714284555Sarybchik	 * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree
715284555Sarybchik	 * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link().
716284555Sarybchik	 */
717284555Sarybchik	efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask);
718284555Sarybchik
719284555Sarybchik	EFX_AND_QWORD(mask,
720284555Sarybchik	    *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED));
721284555Sarybchik
722284555Sarybchik	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M);
723284555Sarybchik	EFX_AND_QWORD(modes, mask);
724284555Sarybchik	encp->enc_loopback_types[EFX_LINK_100FDX] = modes;
725284555Sarybchik
726284555Sarybchik	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G);
727284555Sarybchik	EFX_AND_QWORD(modes, mask);
728284555Sarybchik	encp->enc_loopback_types[EFX_LINK_1000FDX] = modes;
729284555Sarybchik
730284555Sarybchik	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G);
731284555Sarybchik	EFX_AND_QWORD(modes, mask);
732284555Sarybchik	encp->enc_loopback_types[EFX_LINK_10000FDX] = modes;
733284555Sarybchik
734284555Sarybchik	if (req.emr_out_length_used >=
735284555Sarybchik	    MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST +
736284555Sarybchik	    MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) {
737284555Sarybchik		/* Response includes 40G loopback modes */
738284555Sarybchik		modes =
739284555Sarybchik		    *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G);
740284555Sarybchik		EFX_AND_QWORD(modes, mask);
741284555Sarybchik		encp->enc_loopback_types[EFX_LINK_40000FDX] = modes;
742284555Sarybchik	}
743284555Sarybchik
744284555Sarybchik	EFX_ZERO_QWORD(modes);
745284555Sarybchik	EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF);
746284555Sarybchik	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]);
747284555Sarybchik	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]);
748284555Sarybchik	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]);
749284555Sarybchik	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]);
750284555Sarybchik	encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes;
751284555Sarybchik
752284555Sarybchik	return (0);
753284555Sarybchik
754284555Sarybchikfail2:
755284555Sarybchik	EFSYS_PROBE(fail2);
756284555Sarybchikfail1:
757293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
758284555Sarybchik
759284555Sarybchik	return (rc);
760284555Sarybchik}
761284555Sarybchik
762284555Sarybchik#endif /* EFSYS_OPT_LOOPBACK */
763301365Sarybchik
764301365Sarybchik	__checkReturn	efx_rc_t
765301365Sarybchikefx_nic_calculate_pcie_link_bandwidth(
766301365Sarybchik	__in		uint32_t pcie_link_width,
767301365Sarybchik	__in		uint32_t pcie_link_gen,
768301365Sarybchik	__out		uint32_t *bandwidth_mbpsp)
769301365Sarybchik{
770301365Sarybchik	uint32_t lane_bandwidth;
771301365Sarybchik	uint32_t total_bandwidth;
772301365Sarybchik	efx_rc_t rc;
773301365Sarybchik
774301365Sarybchik	if ((pcie_link_width == 0) || (pcie_link_width > 16) ||
775301365Sarybchik	    !ISP2(pcie_link_width)) {
776301365Sarybchik		rc = EINVAL;
777301365Sarybchik		goto fail1;
778301365Sarybchik	}
779301365Sarybchik
780301365Sarybchik	switch (pcie_link_gen) {
781301365Sarybchik	case EFX_PCIE_LINK_SPEED_GEN1:
782301365Sarybchik		/* 2.5 Gb/s raw bandwidth with 8b/10b encoding */
783301365Sarybchik		lane_bandwidth = 2000;
784301365Sarybchik		break;
785301365Sarybchik	case EFX_PCIE_LINK_SPEED_GEN2:
786301365Sarybchik		/* 5.0 Gb/s raw bandwidth with 8b/10b encoding */
787301365Sarybchik		lane_bandwidth = 4000;
788301365Sarybchik		break;
789301365Sarybchik	case EFX_PCIE_LINK_SPEED_GEN3:
790301365Sarybchik		/* 8.0 Gb/s raw bandwidth with 128b/130b encoding */
791301365Sarybchik		lane_bandwidth = 7877;
792301365Sarybchik		break;
793301365Sarybchik	default:
794301365Sarybchik		rc = EINVAL;
795301365Sarybchik		goto fail2;
796301365Sarybchik	}
797301365Sarybchik
798301365Sarybchik	total_bandwidth = lane_bandwidth * pcie_link_width;
799301365Sarybchik	*bandwidth_mbpsp = total_bandwidth;
800301365Sarybchik
801301365Sarybchik	return (0);
802301365Sarybchik
803301365Sarybchikfail2:
804301365Sarybchik	EFSYS_PROBE(fail2);
805301365Sarybchikfail1:
806301365Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
807301365Sarybchik
808301365Sarybchik	return (rc);
809301365Sarybchik}
810301365Sarybchik
811301365Sarybchik
812301365Sarybchik	__checkReturn	efx_rc_t
813301365Sarybchikefx_nic_check_pcie_link_speed(
814301365Sarybchik	__in		efx_nic_t *enp,
815301365Sarybchik	__in		uint32_t pcie_link_width,
816301365Sarybchik	__in		uint32_t pcie_link_gen,
817301365Sarybchik	__out		efx_pcie_link_performance_t *resultp)
818301365Sarybchik{
819301365Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
820301365Sarybchik	uint32_t bandwidth;
821301365Sarybchik	efx_pcie_link_performance_t result;
822301365Sarybchik	efx_rc_t rc;
823301365Sarybchik
824301365Sarybchik	if ((encp->enc_required_pcie_bandwidth_mbps == 0) ||
825301365Sarybchik	    (pcie_link_width == 0) || (pcie_link_width == 32) ||
826301365Sarybchik	    (pcie_link_gen == 0)) {
827301365Sarybchik		/*
828301365Sarybchik		 * No usable info on what is required and/or in use. In virtual
829301365Sarybchik		 * machines, sometimes the PCIe link width is reported as 0 or
830301365Sarybchik		 * 32, or the speed as 0.
831301365Sarybchik		 */
832301365Sarybchik		result = EFX_PCIE_LINK_PERFORMANCE_UNKNOWN_BANDWIDTH;
833301365Sarybchik		goto out;
834301365Sarybchik	}
835301365Sarybchik
836301365Sarybchik	/* Calculate the available bandwidth in megabits per second */
837301365Sarybchik	rc = efx_nic_calculate_pcie_link_bandwidth(pcie_link_width,
838301365Sarybchik					    pcie_link_gen, &bandwidth);
839301365Sarybchik	if (rc != 0)
840301365Sarybchik		goto fail1;
841301365Sarybchik
842301365Sarybchik	if (bandwidth < encp->enc_required_pcie_bandwidth_mbps) {
843301365Sarybchik		result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_BANDWIDTH;
844301365Sarybchik	} else if (pcie_link_gen < encp->enc_max_pcie_link_gen) {
845301365Sarybchik		/* The link provides enough bandwidth but not optimal latency */
846301365Sarybchik		result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_LATENCY;
847301365Sarybchik	} else {
848301365Sarybchik		result = EFX_PCIE_LINK_PERFORMANCE_OPTIMAL;
849301365Sarybchik	}
850301365Sarybchik
851301365Sarybchikout:
852301365Sarybchik	*resultp = result;
853301365Sarybchik
854301365Sarybchik	return (0);
855301365Sarybchik
856301365Sarybchikfail1:
857301365Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
858301365Sarybchik
859301365Sarybchik	return (rc);
860301365Sarybchik}
861