efx_nic.c revision 342446
1227569Sphilip/*-
2300607Sarybchik * Copyright (c) 2007-2016 Solarflare Communications Inc.
3283514Sarybchik * All rights reserved.
4227569Sphilip *
5227569Sphilip * Redistribution and use in source and binary forms, with or without
6283514Sarybchik * modification, are permitted provided that the following conditions are met:
7227569Sphilip *
8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9283514Sarybchik *    this list of conditions and the following disclaimer.
10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11283514Sarybchik *    this list of conditions and the following disclaimer in the documentation
12283514Sarybchik *    and/or other materials provided with the distribution.
13283514Sarybchik *
14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25283514Sarybchik *
26283514Sarybchik * The views and conclusions contained in the software and documentation are
27283514Sarybchik * those of the authors and should not be interpreted as representing official
28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29227569Sphilip */
30227569Sphilip
31228078Sphilip#include <sys/cdefs.h>
32228078Sphilip__FBSDID("$FreeBSD: stable/11/sys/dev/sfxge/common/efx_nic.c 342446 2018-12-25 07:30:17Z arybchik $");
33228078Sphilip
34227569Sphilip#include "efx.h"
35227569Sphilip#include "efx_impl.h"
36227569Sphilip
37291436Sarybchik	__checkReturn	efx_rc_t
38227569Sphilipefx_family(
39227569Sphilip	__in		uint16_t venid,
40227569Sphilip	__in		uint16_t devid,
41227569Sphilip	__out		efx_family_t *efp)
42227569Sphilip{
43283514Sarybchik	if (venid == EFX_PCI_VENID_SFC) {
44283514Sarybchik		switch (devid) {
45227569Sphilip#if EFSYS_OPT_SIENA
46283514Sarybchik		case EFX_PCI_DEVID_SIENA_F1_UNINIT:
47283514Sarybchik			/*
48283514Sarybchik			 * Hardware default for PF0 of uninitialised Siena.
49283514Sarybchik			 * manftest must be able to cope with this device id.
50283514Sarybchik			 */
51283514Sarybchik			*efp = EFX_FAMILY_SIENA;
52283514Sarybchik			return (0);
53283514Sarybchik
54283514Sarybchik		case EFX_PCI_DEVID_BETHPAGE:
55283514Sarybchik		case EFX_PCI_DEVID_SIENA:
56283514Sarybchik			*efp = EFX_FAMILY_SIENA;
57283514Sarybchik			return (0);
58293731Sarybchik#endif /* EFSYS_OPT_SIENA */
59283514Sarybchik
60283514Sarybchik#if EFSYS_OPT_HUNTINGTON
61283514Sarybchik		case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT:
62283514Sarybchik			/*
63283514Sarybchik			 * Hardware default for PF0 of uninitialised Huntington.
64283514Sarybchik			 * manftest must be able to cope with this device id.
65283514Sarybchik			 */
66283514Sarybchik			*efp = EFX_FAMILY_HUNTINGTON;
67283514Sarybchik			return (0);
68283514Sarybchik
69283514Sarybchik		case EFX_PCI_DEVID_FARMINGDALE:
70283514Sarybchik		case EFX_PCI_DEVID_GREENPORT:
71283514Sarybchik			*efp = EFX_FAMILY_HUNTINGTON;
72283514Sarybchik			return (0);
73283514Sarybchik
74283514Sarybchik		case EFX_PCI_DEVID_FARMINGDALE_VF:
75283514Sarybchik		case EFX_PCI_DEVID_GREENPORT_VF:
76283514Sarybchik			*efp = EFX_FAMILY_HUNTINGTON;
77283514Sarybchik			return (0);
78293731Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */
79293731Sarybchik
80293731Sarybchik#if EFSYS_OPT_MEDFORD
81293731Sarybchik		case EFX_PCI_DEVID_MEDFORD_PF_UNINIT:
82293731Sarybchik			/*
83293731Sarybchik			 * Hardware default for PF0 of uninitialised Medford.
84293731Sarybchik			 * manftest must be able to cope with this device id.
85293731Sarybchik			 */
86293731Sarybchik			*efp = EFX_FAMILY_MEDFORD;
87293731Sarybchik			return (0);
88293731Sarybchik
89293731Sarybchik		case EFX_PCI_DEVID_MEDFORD:
90293731Sarybchik			*efp = EFX_FAMILY_MEDFORD;
91293731Sarybchik			return (0);
92293731Sarybchik
93293731Sarybchik		case EFX_PCI_DEVID_MEDFORD_VF:
94293731Sarybchik			*efp = EFX_FAMILY_MEDFORD;
95293731Sarybchik			return (0);
96293731Sarybchik#endif /* EFSYS_OPT_MEDFORD */
97293731Sarybchik
98299320Sarybchik		case EFX_PCI_DEVID_FALCON:	/* Obsolete, not supported */
99283514Sarybchik		default:
100283514Sarybchik			break;
101283514Sarybchik		}
102227569Sphilip	}
103283514Sarybchik
104283514Sarybchik	*efp = EFX_FAMILY_INVALID;
105227569Sphilip	return (ENOTSUP);
106227569Sphilip}
107227569Sphilip
108227569Sphilip#if EFSYS_OPT_SIENA
109227569Sphilip
110299517Sarybchikstatic const efx_nic_ops_t	__efx_nic_siena_ops = {
111227569Sphilip	siena_nic_probe,		/* eno_probe */
112293887Sarybchik	NULL,				/* eno_board_cfg */
113283514Sarybchik	NULL,				/* eno_set_drv_limits */
114227569Sphilip	siena_nic_reset,		/* eno_reset */
115227569Sphilip	siena_nic_init,			/* eno_init */
116283514Sarybchik	NULL,				/* eno_get_vi_pool */
117283514Sarybchik	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
127283514Sarybchik#if EFSYS_OPT_HUNTINGTON
128283514Sarybchik
129299517Sarybchikstatic const efx_nic_ops_t	__efx_nic_hunt_ops = {
130293805Sarybchik	ef10_nic_probe,			/* eno_probe */
131293887Sarybchik	hunt_board_cfg,			/* eno_board_cfg */
132293805Sarybchik	ef10_nic_set_drv_limits,	/* eno_set_drv_limits */
133293805Sarybchik	ef10_nic_reset,			/* eno_reset */
134293805Sarybchik	ef10_nic_init,			/* eno_init */
135293805Sarybchik	ef10_nic_get_vi_pool,		/* eno_get_vi_pool */
136293805Sarybchik	ef10_nic_get_bar_region,	/* eno_get_bar_region */
137283514Sarybchik#if EFSYS_OPT_DIAG
138293805Sarybchik	ef10_nic_register_test,		/* eno_register_test */
139283514Sarybchik#endif	/* EFSYS_OPT_DIAG */
140293805Sarybchik	ef10_nic_fini,			/* eno_fini */
141293805Sarybchik	ef10_nic_unprobe,		/* eno_unprobe */
142283514Sarybchik};
143283514Sarybchik
144283514Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
145283514Sarybchik
146293887Sarybchik#if EFSYS_OPT_MEDFORD
147293887Sarybchik
148299517Sarybchikstatic const efx_nic_ops_t	__efx_nic_medford_ops = {
149293887Sarybchik	ef10_nic_probe,			/* eno_probe */
150293887Sarybchik	medford_board_cfg,		/* eno_board_cfg */
151293887Sarybchik	ef10_nic_set_drv_limits,	/* eno_set_drv_limits */
152293887Sarybchik	ef10_nic_reset,			/* eno_reset */
153293887Sarybchik	ef10_nic_init,			/* eno_init */
154293887Sarybchik	ef10_nic_get_vi_pool,		/* eno_get_vi_pool */
155293887Sarybchik	ef10_nic_get_bar_region,	/* eno_get_bar_region */
156293887Sarybchik#if EFSYS_OPT_DIAG
157293887Sarybchik	ef10_nic_register_test,		/* eno_register_test */
158293887Sarybchik#endif	/* EFSYS_OPT_DIAG */
159293887Sarybchik	ef10_nic_fini,			/* eno_fini */
160293887Sarybchik	ef10_nic_unprobe,		/* eno_unprobe */
161293887Sarybchik};
162293887Sarybchik
163293887Sarybchik#endif	/* EFSYS_OPT_MEDFORD */
164293887Sarybchik
165293887Sarybchik
166291436Sarybchik	__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;
175291436Sarybchik	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:
193299517Sarybchik		enp->en_enop = &__efx_nic_siena_ops;
194279141Sarybchik		enp->en_features =
195279141Sarybchik		    EFX_FEATURE_IPV6 |
196227569Sphilip		    EFX_FEATURE_LFSR_HASH_INSERT |
197279141Sarybchik		    EFX_FEATURE_LINK_EVENTS |
198279141Sarybchik		    EFX_FEATURE_PERIODIC_MAC_STATS |
199279141Sarybchik		    EFX_FEATURE_MCDI |
200278839Sarybchik		    EFX_FEATURE_LOOKAHEAD_SPLIT |
201283514Sarybchik		    EFX_FEATURE_MAC_HEADER_FILTERS |
202283514Sarybchik		    EFX_FEATURE_TX_SRC_FILTERS;
203227569Sphilip		break;
204227569Sphilip#endif	/* EFSYS_OPT_SIENA */
205227569Sphilip
206283514Sarybchik#if EFSYS_OPT_HUNTINGTON
207283514Sarybchik	case EFX_FAMILY_HUNTINGTON:
208299517Sarybchik		enp->en_enop = &__efx_nic_hunt_ops;
209283514Sarybchik		enp->en_features =
210283514Sarybchik		    EFX_FEATURE_IPV6 |
211283514Sarybchik		    EFX_FEATURE_LINK_EVENTS |
212283514Sarybchik		    EFX_FEATURE_PERIODIC_MAC_STATS |
213283514Sarybchik		    EFX_FEATURE_MCDI |
214283514Sarybchik		    EFX_FEATURE_MAC_HEADER_FILTERS |
215283514Sarybchik		    EFX_FEATURE_MCDI_DMA |
216283514Sarybchik		    EFX_FEATURE_PIO_BUFFERS |
217293891Sarybchik		    EFX_FEATURE_FW_ASSISTED_TSO |
218293891Sarybchik		    EFX_FEATURE_FW_ASSISTED_TSO_V2;
219283514Sarybchik		break;
220283514Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
221283514Sarybchik
222293887Sarybchik#if EFSYS_OPT_MEDFORD
223293887Sarybchik	case EFX_FAMILY_MEDFORD:
224299517Sarybchik		enp->en_enop = &__efx_nic_medford_ops;
225293887Sarybchik		/*
226298955Spfg		 * FW_ASSISTED_TSO omitted as Medford only supports firmware
227293887Sarybchik		 * assisted TSO version 2, not the v1 scheme used on Huntington.
228293887Sarybchik		 */
229293887Sarybchik		enp->en_features =
230293887Sarybchik		    EFX_FEATURE_IPV6 |
231293887Sarybchik		    EFX_FEATURE_LINK_EVENTS |
232293887Sarybchik		    EFX_FEATURE_PERIODIC_MAC_STATS |
233293887Sarybchik		    EFX_FEATURE_MCDI |
234293887Sarybchik		    EFX_FEATURE_MAC_HEADER_FILTERS |
235293887Sarybchik		    EFX_FEATURE_MCDI_DMA |
236299917Sarybchik		    EFX_FEATURE_PIO_BUFFERS |
237299917Sarybchik		    EFX_FEATURE_FW_ASSISTED_TSO_V2;
238293887Sarybchik		break;
239293887Sarybchik#endif	/* EFSYS_OPT_MEDFORD */
240293887Sarybchik
241227569Sphilip	default:
242227569Sphilip		rc = ENOTSUP;
243227569Sphilip		goto fail2;
244227569Sphilip	}
245227569Sphilip
246227569Sphilip	enp->en_family = family;
247227569Sphilip	enp->en_esip = esip;
248227569Sphilip	enp->en_esbp = esbp;
249227569Sphilip	enp->en_eslp = eslp;
250227569Sphilip
251227569Sphilip	*enpp = enp;
252227569Sphilip
253227569Sphilip	return (0);
254227569Sphilip
255227569Sphilipfail2:
256283514Sarybchik	EFSYS_PROBE(fail2);
257227569Sphilip
258227569Sphilip	enp->en_magic = 0;
259227569Sphilip
260227569Sphilip	/* Free the NIC object */
261227569Sphilip	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
262227569Sphilip
263227569Sphilipfail1:
264291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
265227569Sphilip
266227569Sphilip	return (rc);
267227569Sphilip}
268227569Sphilip
269291436Sarybchik	__checkReturn	efx_rc_t
270227569Sphilipefx_nic_probe(
271227569Sphilip	__in		efx_nic_t *enp)
272227569Sphilip{
273299517Sarybchik	const efx_nic_ops_t *enop;
274291436Sarybchik	efx_rc_t rc;
275227569Sphilip
276227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
277227569Sphilip#if EFSYS_OPT_MCDI
278227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
279227569Sphilip#endif	/* EFSYS_OPT_MCDI */
280227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE));
281227569Sphilip
282227569Sphilip	enop = enp->en_enop;
283227569Sphilip	if ((rc = enop->eno_probe(enp)) != 0)
284283514Sarybchik		goto fail1;
285227569Sphilip
286227569Sphilip	if ((rc = efx_phy_probe(enp)) != 0)
287283514Sarybchik		goto fail2;
288227569Sphilip
289227569Sphilip	enp->en_mod_flags |= EFX_MOD_PROBE;
290227569Sphilip
291227569Sphilip	return (0);
292227569Sphilip
293283514Sarybchikfail2:
294283514Sarybchik	EFSYS_PROBE(fail2);
295227569Sphilip
296227569Sphilip	enop->eno_unprobe(enp);
297227569Sphilip
298227569Sphilipfail1:
299291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
300227569Sphilip
301227569Sphilip	return (rc);
302227569Sphilip}
303227569Sphilip
304291436Sarybchik	__checkReturn	efx_rc_t
305283514Sarybchikefx_nic_set_drv_limits(
306283514Sarybchik	__inout		efx_nic_t *enp,
307283514Sarybchik	__in		efx_drv_limits_t *edlp)
308283514Sarybchik{
309299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
310291436Sarybchik	efx_rc_t rc;
311283514Sarybchik
312283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
313283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
314283514Sarybchik
315283514Sarybchik	if (enop->eno_set_drv_limits != NULL) {
316283514Sarybchik		if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0)
317283514Sarybchik			goto fail1;
318283514Sarybchik	}
319283514Sarybchik
320283514Sarybchik	return (0);
321283514Sarybchik
322283514Sarybchikfail1:
323291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
324283514Sarybchik
325283514Sarybchik	return (rc);
326283514Sarybchik}
327283514Sarybchik
328291436Sarybchik	__checkReturn	efx_rc_t
329283514Sarybchikefx_nic_get_bar_region(
330283514Sarybchik	__in		efx_nic_t *enp,
331283514Sarybchik	__in		efx_nic_region_t region,
332283514Sarybchik	__out		uint32_t *offsetp,
333283514Sarybchik	__out		size_t *sizep)
334283514Sarybchik{
335299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
336291436Sarybchik	efx_rc_t rc;
337283514Sarybchik
338283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
339283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
340283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
341283514Sarybchik
342283514Sarybchik	if (enop->eno_get_bar_region == NULL) {
343283514Sarybchik		rc = ENOTSUP;
344283514Sarybchik		goto fail1;
345283514Sarybchik	}
346283514Sarybchik	if ((rc = (enop->eno_get_bar_region)(enp,
347283514Sarybchik		    region, offsetp, sizep)) != 0) {
348283514Sarybchik		goto fail2;
349283514Sarybchik	}
350283514Sarybchik
351283514Sarybchik	return (0);
352283514Sarybchik
353283514Sarybchikfail2:
354283514Sarybchik	EFSYS_PROBE(fail2);
355283514Sarybchik
356283514Sarybchikfail1:
357291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
358283514Sarybchik
359283514Sarybchik	return (rc);
360283514Sarybchik}
361283514Sarybchik
362283514Sarybchik
363291436Sarybchik	__checkReturn	efx_rc_t
364283514Sarybchikefx_nic_get_vi_pool(
365283514Sarybchik	__in		efx_nic_t *enp,
366283514Sarybchik	__out		uint32_t *evq_countp,
367283514Sarybchik	__out		uint32_t *rxq_countp,
368283514Sarybchik	__out		uint32_t *txq_countp)
369283514Sarybchik{
370299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
371283514Sarybchik	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
372291436Sarybchik	efx_rc_t rc;
373283514Sarybchik
374283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
375283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
376283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
377283514Sarybchik
378283514Sarybchik	if (enop->eno_get_vi_pool != NULL) {
379283514Sarybchik		uint32_t vi_count = 0;
380283514Sarybchik
381283514Sarybchik		if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0)
382283514Sarybchik			goto fail1;
383283514Sarybchik
384283514Sarybchik		*evq_countp = vi_count;
385283514Sarybchik		*rxq_countp = vi_count;
386283514Sarybchik		*txq_countp = vi_count;
387283514Sarybchik	} else {
388283514Sarybchik		/* Use NIC limits as default value */
389283514Sarybchik		*evq_countp = encp->enc_evq_limit;
390283514Sarybchik		*rxq_countp = encp->enc_rxq_limit;
391283514Sarybchik		*txq_countp = encp->enc_txq_limit;
392283514Sarybchik	}
393283514Sarybchik
394283514Sarybchik	return (0);
395283514Sarybchik
396283514Sarybchikfail1:
397291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
398283514Sarybchik
399283514Sarybchik	return (rc);
400283514Sarybchik}
401283514Sarybchik
402283514Sarybchik
403291436Sarybchik	__checkReturn	efx_rc_t
404227569Sphilipefx_nic_init(
405227569Sphilip	__in		efx_nic_t *enp)
406227569Sphilip{
407299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
408291436Sarybchik	efx_rc_t rc;
409227569Sphilip
410227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
411227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
412227569Sphilip
413227569Sphilip	if (enp->en_mod_flags & EFX_MOD_NIC) {
414227569Sphilip		rc = EINVAL;
415227569Sphilip		goto fail1;
416227569Sphilip	}
417227569Sphilip
418227569Sphilip	if ((rc = enop->eno_init(enp)) != 0)
419227569Sphilip		goto fail2;
420227569Sphilip
421227569Sphilip	enp->en_mod_flags |= EFX_MOD_NIC;
422227569Sphilip
423227569Sphilip	return (0);
424227569Sphilip
425227569Sphilipfail2:
426227569Sphilip	EFSYS_PROBE(fail2);
427227569Sphilipfail1:
428291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
429227569Sphilip
430227569Sphilip	return (rc);
431227569Sphilip}
432227569Sphilip
433227569Sphilip			void
434227569Sphilipefx_nic_fini(
435227569Sphilip	__in		efx_nic_t *enp)
436227569Sphilip{
437299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
438227569Sphilip
439227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
440227569Sphilip	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
441227569Sphilip	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC);
442227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
443227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
444227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
445227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
446227569Sphilip
447227569Sphilip	enop->eno_fini(enp);
448227569Sphilip
449227569Sphilip	enp->en_mod_flags &= ~EFX_MOD_NIC;
450227569Sphilip}
451227569Sphilip
452227569Sphilip			void
453227569Sphilipefx_nic_unprobe(
454227569Sphilip	__in		efx_nic_t *enp)
455227569Sphilip{
456299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
457227569Sphilip
458227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
459227569Sphilip#if EFSYS_OPT_MCDI
460227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
461227569Sphilip#endif	/* EFSYS_OPT_MCDI */
462227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
463227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
464227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR));
465227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
466227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
467227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
468227569Sphilip
469227569Sphilip	efx_phy_unprobe(enp);
470227569Sphilip
471227569Sphilip	enop->eno_unprobe(enp);
472227569Sphilip
473227569Sphilip	enp->en_mod_flags &= ~EFX_MOD_PROBE;
474227569Sphilip}
475227569Sphilip
476227569Sphilip			void
477227569Sphilipefx_nic_destroy(
478227569Sphilip	__in	efx_nic_t *enp)
479227569Sphilip{
480227569Sphilip	efsys_identifier_t *esip = enp->en_esip;
481227569Sphilip
482227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
483227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
484227569Sphilip
485310937Sarybchik	enp->en_family = EFX_FAMILY_INVALID;
486227569Sphilip	enp->en_esip = NULL;
487227569Sphilip	enp->en_esbp = NULL;
488227569Sphilip	enp->en_eslp = NULL;
489227569Sphilip
490227569Sphilip	enp->en_enop = NULL;
491227569Sphilip
492227569Sphilip	enp->en_magic = 0;
493227569Sphilip
494227569Sphilip	/* Free the NIC object */
495227569Sphilip	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);
496227569Sphilip}
497227569Sphilip
498291436Sarybchik	__checkReturn	efx_rc_t
499227569Sphilipefx_nic_reset(
500227569Sphilip	__in		efx_nic_t *enp)
501227569Sphilip{
502299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
503227569Sphilip	unsigned int mod_flags;
504291436Sarybchik	efx_rc_t rc;
505227569Sphilip
506227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
507227569Sphilip	EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
508227569Sphilip	/*
509300007Sarybchik	 * All modules except the MCDI, PROBE, NVRAM, VPD, MON
510293901Sarybchik	 * (which we do not reset here) must have been shut down or never
511293901Sarybchik	 * initialized.
512227569Sphilip	 *
513227569Sphilip	 * A rule of thumb here is: If the controller or MC reboots, is *any*
514227569Sphilip	 * state lost. If it's lost and needs reapplying, then the module
515227569Sphilip	 * *must* not be initialised during the reset.
516227569Sphilip	 */
517227569Sphilip	mod_flags = enp->en_mod_flags;
518227569Sphilip	mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM |
519300007Sarybchik		    EFX_MOD_VPD | EFX_MOD_MON);
520227569Sphilip	EFSYS_ASSERT3U(mod_flags, ==, 0);
521227569Sphilip	if (mod_flags != 0) {
522227569Sphilip		rc = EINVAL;
523227569Sphilip		goto fail1;
524227569Sphilip	}
525227569Sphilip
526227569Sphilip	if ((rc = enop->eno_reset(enp)) != 0)
527227569Sphilip		goto fail2;
528227569Sphilip
529227569Sphilip	return (0);
530227569Sphilip
531227569Sphilipfail2:
532227569Sphilip	EFSYS_PROBE(fail2);
533227569Sphilipfail1:
534291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
535227569Sphilip
536227569Sphilip	return (rc);
537227569Sphilip}
538227569Sphilip
539227569Sphilip			const efx_nic_cfg_t *
540227569Sphilipefx_nic_cfg_get(
541227569Sphilip	__in		efx_nic_t *enp)
542227569Sphilip{
543227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
544342446Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
545227569Sphilip
546227569Sphilip	return (&(enp->en_nic_cfg));
547227569Sphilip}
548227569Sphilip
549227569Sphilip#if EFSYS_OPT_DIAG
550227569Sphilip
551291436Sarybchik	__checkReturn	efx_rc_t
552227569Sphilipefx_nic_register_test(
553227569Sphilip	__in		efx_nic_t *enp)
554227569Sphilip{
555299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
556291436Sarybchik	efx_rc_t rc;
557227569Sphilip
558227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
559227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
560227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
561227569Sphilip
562227569Sphilip	if ((rc = enop->eno_register_test(enp)) != 0)
563227569Sphilip		goto fail1;
564227569Sphilip
565227569Sphilip	return (0);
566227569Sphilip
567227569Sphilipfail1:
568291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
569227569Sphilip
570227569Sphilip	return (rc);
571227569Sphilip}
572227569Sphilip
573227569Sphilip#endif	/* EFSYS_OPT_DIAG */
574283514Sarybchik
575283514Sarybchik#if EFSYS_OPT_LOOPBACK
576283514Sarybchik
577283514Sarybchikextern			void
578283514Sarybchikefx_loopback_mask(
579283514Sarybchik	__in	efx_loopback_kind_t loopback_kind,
580283514Sarybchik	__out	efx_qword_t *maskp)
581283514Sarybchik{
582283514Sarybchik	efx_qword_t mask;
583283514Sarybchik
584283514Sarybchik	EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS);
585283514Sarybchik	EFSYS_ASSERT(maskp != NULL);
586283514Sarybchik
587283514Sarybchik	/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
588283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
589283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
590283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
591283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
592283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
593283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
594283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
595283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
596283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
597283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
598283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
599283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
600283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
601283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
602283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
603283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
604283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
605283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
606283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT);
607283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS);
608283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS);
609283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR ==
610283514Sarybchik	    EFX_LOOPBACK_XAUI_WS_FAR);
611283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR ==
612283514Sarybchik	    EFX_LOOPBACK_XAUI_WS_NEAR);
613283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS);
614283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS);
615283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR ==
616283514Sarybchik	    EFX_LOOPBACK_XFI_WS_FAR);
617283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS);
618283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT);
619283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR);
620283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR);
621283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS ==
622283514Sarybchik	    EFX_LOOPBACK_PMA_INT_WS);
623283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS ==
624283514Sarybchik	    EFX_LOOPBACK_SD_FEP2_WS);
625283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS ==
626283514Sarybchik	    EFX_LOOPBACK_SD_FEP1_5_WS);
627283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS);
628283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS);
629283514Sarybchik
630283514Sarybchik	/* Build bitmask of possible loopback types */
631283514Sarybchik	EFX_ZERO_QWORD(mask);
632283514Sarybchik
633283514Sarybchik	if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) ||
634283514Sarybchik	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
635283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF);
636283514Sarybchik	}
637283514Sarybchik
638283514Sarybchik	if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) ||
639283514Sarybchik	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
640283514Sarybchik		/*
641283514Sarybchik		 * The "MAC" grouping has historically been used by drivers to
642283514Sarybchik		 * mean loopbacks supported by on-chip hardware. Keep that
643283514Sarybchik		 * meaning here, and include on-chip PHY layer loopbacks.
644283514Sarybchik		 */
645283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA);
646283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC);
647283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII);
648283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS);
649283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI);
650283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII);
651283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII);
652283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR);
653283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI);
654283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR);
655283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR);
656283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR);
657283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR);
658283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT);
659283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR);
660283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR);
661283514Sarybchik	}
662283514Sarybchik
663283514Sarybchik	if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) ||
664283514Sarybchik	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
665283514Sarybchik		/*
666283514Sarybchik		 * The "PHY" grouping has historically been used by drivers to
667283514Sarybchik		 * mean loopbacks supported by off-chip hardware. Keep that
668283514Sarybchik		 * meaning here.
669283514Sarybchik		 */
670283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY);
671283514Sarybchik		EFX_SET_QWORD_BIT(mask,	EFX_LOOPBACK_PHY_XS);
672283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS);
673283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD);
674283514Sarybchik	}
675283514Sarybchik
676283514Sarybchik	*maskp = mask;
677283514Sarybchik}
678283514Sarybchik
679291436Sarybchik	__checkReturn	efx_rc_t
680283514Sarybchikefx_mcdi_get_loopback_modes(
681283514Sarybchik	__in		efx_nic_t *enp)
682283514Sarybchik{
683283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
684283514Sarybchik	efx_mcdi_req_t req;
685342445Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LOOPBACK_MODES_IN_LEN,
686342445Sarybchik		MC_CMD_GET_LOOPBACK_MODES_OUT_LEN);
687283514Sarybchik	efx_qword_t mask;
688283514Sarybchik	efx_qword_t modes;
689291436Sarybchik	efx_rc_t rc;
690283514Sarybchik
691283514Sarybchik	req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES;
692283514Sarybchik	req.emr_in_buf = payload;
693283514Sarybchik	req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN;
694283514Sarybchik	req.emr_out_buf = payload;
695283514Sarybchik	req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN;
696283514Sarybchik
697283514Sarybchik	efx_mcdi_execute(enp, &req);
698283514Sarybchik
699283514Sarybchik	if (req.emr_rc != 0) {
700283514Sarybchik		rc = req.emr_rc;
701283514Sarybchik		goto fail1;
702283514Sarybchik	}
703283514Sarybchik
704283514Sarybchik	if (req.emr_out_length_used <
705283514Sarybchik	    MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST +
706283514Sarybchik	    MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) {
707283514Sarybchik		rc = EMSGSIZE;
708283514Sarybchik		goto fail2;
709283514Sarybchik	}
710283514Sarybchik
711283514Sarybchik	/*
712283514Sarybchik	 * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree
713283514Sarybchik	 * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link().
714283514Sarybchik	 */
715283514Sarybchik	efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask);
716283514Sarybchik
717283514Sarybchik	EFX_AND_QWORD(mask,
718283514Sarybchik	    *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED));
719283514Sarybchik
720283514Sarybchik	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M);
721283514Sarybchik	EFX_AND_QWORD(modes, mask);
722283514Sarybchik	encp->enc_loopback_types[EFX_LINK_100FDX] = modes;
723283514Sarybchik
724283514Sarybchik	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G);
725283514Sarybchik	EFX_AND_QWORD(modes, mask);
726283514Sarybchik	encp->enc_loopback_types[EFX_LINK_1000FDX] = modes;
727283514Sarybchik
728283514Sarybchik	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G);
729283514Sarybchik	EFX_AND_QWORD(modes, mask);
730283514Sarybchik	encp->enc_loopback_types[EFX_LINK_10000FDX] = modes;
731283514Sarybchik
732283514Sarybchik	if (req.emr_out_length_used >=
733283514Sarybchik	    MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST +
734283514Sarybchik	    MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) {
735283514Sarybchik		/* Response includes 40G loopback modes */
736283514Sarybchik		modes =
737283514Sarybchik		    *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G);
738283514Sarybchik		EFX_AND_QWORD(modes, mask);
739283514Sarybchik		encp->enc_loopback_types[EFX_LINK_40000FDX] = modes;
740283514Sarybchik	}
741283514Sarybchik
742283514Sarybchik	EFX_ZERO_QWORD(modes);
743283514Sarybchik	EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF);
744283514Sarybchik	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]);
745283514Sarybchik	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]);
746283514Sarybchik	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]);
747283514Sarybchik	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]);
748283514Sarybchik	encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes;
749283514Sarybchik
750283514Sarybchik	return (0);
751283514Sarybchik
752283514Sarybchikfail2:
753283514Sarybchik	EFSYS_PROBE(fail2);
754283514Sarybchikfail1:
755291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
756283514Sarybchik
757283514Sarybchik	return (rc);
758283514Sarybchik}
759283514Sarybchik
760283514Sarybchik#endif /* EFSYS_OPT_LOOPBACK */
761299904Sarybchik
762299904Sarybchik	__checkReturn	efx_rc_t
763299904Sarybchikefx_nic_calculate_pcie_link_bandwidth(
764299904Sarybchik	__in		uint32_t pcie_link_width,
765299904Sarybchik	__in		uint32_t pcie_link_gen,
766299904Sarybchik	__out		uint32_t *bandwidth_mbpsp)
767299904Sarybchik{
768299904Sarybchik	uint32_t lane_bandwidth;
769299904Sarybchik	uint32_t total_bandwidth;
770299904Sarybchik	efx_rc_t rc;
771299904Sarybchik
772299904Sarybchik	if ((pcie_link_width == 0) || (pcie_link_width > 16) ||
773299904Sarybchik	    !ISP2(pcie_link_width)) {
774299904Sarybchik		rc = EINVAL;
775299904Sarybchik		goto fail1;
776299904Sarybchik	}
777299904Sarybchik
778299904Sarybchik	switch (pcie_link_gen) {
779299904Sarybchik	case EFX_PCIE_LINK_SPEED_GEN1:
780299904Sarybchik		/* 2.5 Gb/s raw bandwidth with 8b/10b encoding */
781299904Sarybchik		lane_bandwidth = 2000;
782299904Sarybchik		break;
783299904Sarybchik	case EFX_PCIE_LINK_SPEED_GEN2:
784299904Sarybchik		/* 5.0 Gb/s raw bandwidth with 8b/10b encoding */
785299904Sarybchik		lane_bandwidth = 4000;
786299904Sarybchik		break;
787299904Sarybchik	case EFX_PCIE_LINK_SPEED_GEN3:
788299904Sarybchik		/* 8.0 Gb/s raw bandwidth with 128b/130b encoding */
789299904Sarybchik		lane_bandwidth = 7877;
790299904Sarybchik		break;
791299904Sarybchik	default:
792299904Sarybchik		rc = EINVAL;
793299904Sarybchik		goto fail2;
794299904Sarybchik	}
795299904Sarybchik
796299904Sarybchik	total_bandwidth = lane_bandwidth * pcie_link_width;
797299904Sarybchik	*bandwidth_mbpsp = total_bandwidth;
798299904Sarybchik
799299904Sarybchik	return (0);
800299904Sarybchik
801299904Sarybchikfail2:
802299904Sarybchik	EFSYS_PROBE(fail2);
803299904Sarybchikfail1:
804299904Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
805299904Sarybchik
806299904Sarybchik	return (rc);
807299904Sarybchik}
808299904Sarybchik
809299904Sarybchik
810299904Sarybchik	__checkReturn	efx_rc_t
811299904Sarybchikefx_nic_check_pcie_link_speed(
812299904Sarybchik	__in		efx_nic_t *enp,
813299904Sarybchik	__in		uint32_t pcie_link_width,
814299904Sarybchik	__in		uint32_t pcie_link_gen,
815299904Sarybchik	__out		efx_pcie_link_performance_t *resultp)
816299904Sarybchik{
817299904Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
818299904Sarybchik	uint32_t bandwidth;
819299904Sarybchik	efx_pcie_link_performance_t result;
820299904Sarybchik	efx_rc_t rc;
821299904Sarybchik
822299904Sarybchik	if ((encp->enc_required_pcie_bandwidth_mbps == 0) ||
823299904Sarybchik	    (pcie_link_width == 0) || (pcie_link_width == 32) ||
824299904Sarybchik	    (pcie_link_gen == 0)) {
825299904Sarybchik		/*
826299904Sarybchik		 * No usable info on what is required and/or in use. In virtual
827299904Sarybchik		 * machines, sometimes the PCIe link width is reported as 0 or
828299904Sarybchik		 * 32, or the speed as 0.
829299904Sarybchik		 */
830299904Sarybchik		result = EFX_PCIE_LINK_PERFORMANCE_UNKNOWN_BANDWIDTH;
831299904Sarybchik		goto out;
832299904Sarybchik	}
833299904Sarybchik
834299904Sarybchik	/* Calculate the available bandwidth in megabits per second */
835299904Sarybchik	rc = efx_nic_calculate_pcie_link_bandwidth(pcie_link_width,
836299904Sarybchik					    pcie_link_gen, &bandwidth);
837299904Sarybchik	if (rc != 0)
838299904Sarybchik		goto fail1;
839299904Sarybchik
840299904Sarybchik	if (bandwidth < encp->enc_required_pcie_bandwidth_mbps) {
841299904Sarybchik		result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_BANDWIDTH;
842299904Sarybchik	} else if (pcie_link_gen < encp->enc_max_pcie_link_gen) {
843299904Sarybchik		/* The link provides enough bandwidth but not optimal latency */
844299904Sarybchik		result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_LATENCY;
845299904Sarybchik	} else {
846299904Sarybchik		result = EFX_PCIE_LINK_PERFORMANCE_OPTIMAL;
847299904Sarybchik	}
848299904Sarybchik
849299904Sarybchikout:
850299904Sarybchik	*resultp = result;
851299904Sarybchik
852299904Sarybchik	return (0);
853299904Sarybchik
854299904Sarybchikfail1:
855299904Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
856299904Sarybchik
857299904Sarybchik	return (rc);
858299904Sarybchik}
859