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 342453 2018-12-25 07:37:42Z 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 |
218342453Sarybchik		    EFX_FEATURE_FW_ASSISTED_TSO_V2 |
219342453Sarybchik		    EFX_FEATURE_TXQ_CKSUM_OP_DESC;
220283514Sarybchik		break;
221283514Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
222283514Sarybchik
223293887Sarybchik#if EFSYS_OPT_MEDFORD
224293887Sarybchik	case EFX_FAMILY_MEDFORD:
225299517Sarybchik		enp->en_enop = &__efx_nic_medford_ops;
226293887Sarybchik		/*
227298955Spfg		 * FW_ASSISTED_TSO omitted as Medford only supports firmware
228293887Sarybchik		 * assisted TSO version 2, not the v1 scheme used on Huntington.
229293887Sarybchik		 */
230293887Sarybchik		enp->en_features =
231293887Sarybchik		    EFX_FEATURE_IPV6 |
232293887Sarybchik		    EFX_FEATURE_LINK_EVENTS |
233293887Sarybchik		    EFX_FEATURE_PERIODIC_MAC_STATS |
234293887Sarybchik		    EFX_FEATURE_MCDI |
235293887Sarybchik		    EFX_FEATURE_MAC_HEADER_FILTERS |
236293887Sarybchik		    EFX_FEATURE_MCDI_DMA |
237299917Sarybchik		    EFX_FEATURE_PIO_BUFFERS |
238342453Sarybchik		    EFX_FEATURE_FW_ASSISTED_TSO_V2 |
239342453Sarybchik		    EFX_FEATURE_TXQ_CKSUM_OP_DESC;
240293887Sarybchik		break;
241293887Sarybchik#endif	/* EFSYS_OPT_MEDFORD */
242293887Sarybchik
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:
258283514Sarybchik	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:
266291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
267227569Sphilip
268227569Sphilip	return (rc);
269227569Sphilip}
270227569Sphilip
271291436Sarybchik	__checkReturn	efx_rc_t
272227569Sphilipefx_nic_probe(
273227569Sphilip	__in		efx_nic_t *enp)
274227569Sphilip{
275299517Sarybchik	const efx_nic_ops_t *enop;
276291436Sarybchik	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)
286283514Sarybchik		goto fail1;
287227569Sphilip
288227569Sphilip	if ((rc = efx_phy_probe(enp)) != 0)
289283514Sarybchik		goto fail2;
290227569Sphilip
291227569Sphilip	enp->en_mod_flags |= EFX_MOD_PROBE;
292227569Sphilip
293227569Sphilip	return (0);
294227569Sphilip
295283514Sarybchikfail2:
296283514Sarybchik	EFSYS_PROBE(fail2);
297227569Sphilip
298227569Sphilip	enop->eno_unprobe(enp);
299227569Sphilip
300227569Sphilipfail1:
301291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
302227569Sphilip
303227569Sphilip	return (rc);
304227569Sphilip}
305227569Sphilip
306291436Sarybchik	__checkReturn	efx_rc_t
307283514Sarybchikefx_nic_set_drv_limits(
308283514Sarybchik	__inout		efx_nic_t *enp,
309283514Sarybchik	__in		efx_drv_limits_t *edlp)
310283514Sarybchik{
311299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
312291436Sarybchik	efx_rc_t rc;
313283514Sarybchik
314283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
315283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
316283514Sarybchik
317283514Sarybchik	if (enop->eno_set_drv_limits != NULL) {
318283514Sarybchik		if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0)
319283514Sarybchik			goto fail1;
320283514Sarybchik	}
321283514Sarybchik
322283514Sarybchik	return (0);
323283514Sarybchik
324283514Sarybchikfail1:
325291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
326283514Sarybchik
327283514Sarybchik	return (rc);
328283514Sarybchik}
329283514Sarybchik
330291436Sarybchik	__checkReturn	efx_rc_t
331283514Sarybchikefx_nic_get_bar_region(
332283514Sarybchik	__in		efx_nic_t *enp,
333283514Sarybchik	__in		efx_nic_region_t region,
334283514Sarybchik	__out		uint32_t *offsetp,
335283514Sarybchik	__out		size_t *sizep)
336283514Sarybchik{
337299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
338291436Sarybchik	efx_rc_t rc;
339283514Sarybchik
340283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
341283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
342283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
343283514Sarybchik
344283514Sarybchik	if (enop->eno_get_bar_region == NULL) {
345283514Sarybchik		rc = ENOTSUP;
346283514Sarybchik		goto fail1;
347283514Sarybchik	}
348283514Sarybchik	if ((rc = (enop->eno_get_bar_region)(enp,
349283514Sarybchik		    region, offsetp, sizep)) != 0) {
350283514Sarybchik		goto fail2;
351283514Sarybchik	}
352283514Sarybchik
353283514Sarybchik	return (0);
354283514Sarybchik
355283514Sarybchikfail2:
356283514Sarybchik	EFSYS_PROBE(fail2);
357283514Sarybchik
358283514Sarybchikfail1:
359291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
360283514Sarybchik
361283514Sarybchik	return (rc);
362283514Sarybchik}
363283514Sarybchik
364283514Sarybchik
365291436Sarybchik	__checkReturn	efx_rc_t
366283514Sarybchikefx_nic_get_vi_pool(
367283514Sarybchik	__in		efx_nic_t *enp,
368283514Sarybchik	__out		uint32_t *evq_countp,
369283514Sarybchik	__out		uint32_t *rxq_countp,
370283514Sarybchik	__out		uint32_t *txq_countp)
371283514Sarybchik{
372299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
373283514Sarybchik	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
374291436Sarybchik	efx_rc_t rc;
375283514Sarybchik
376283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
377283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
378283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
379283514Sarybchik
380283514Sarybchik	if (enop->eno_get_vi_pool != NULL) {
381283514Sarybchik		uint32_t vi_count = 0;
382283514Sarybchik
383283514Sarybchik		if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0)
384283514Sarybchik			goto fail1;
385283514Sarybchik
386283514Sarybchik		*evq_countp = vi_count;
387283514Sarybchik		*rxq_countp = vi_count;
388283514Sarybchik		*txq_countp = vi_count;
389283514Sarybchik	} else {
390283514Sarybchik		/* Use NIC limits as default value */
391283514Sarybchik		*evq_countp = encp->enc_evq_limit;
392283514Sarybchik		*rxq_countp = encp->enc_rxq_limit;
393283514Sarybchik		*txq_countp = encp->enc_txq_limit;
394283514Sarybchik	}
395283514Sarybchik
396283514Sarybchik	return (0);
397283514Sarybchik
398283514Sarybchikfail1:
399291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
400283514Sarybchik
401283514Sarybchik	return (rc);
402283514Sarybchik}
403283514Sarybchik
404283514Sarybchik
405291436Sarybchik	__checkReturn	efx_rc_t
406227569Sphilipefx_nic_init(
407227569Sphilip	__in		efx_nic_t *enp)
408227569Sphilip{
409299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
410291436Sarybchik	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:
430291436Sarybchik	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{
439299517Sarybchik	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{
458299517Sarybchik	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
487310937Sarybchik	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
500291436Sarybchik	__checkReturn	efx_rc_t
501227569Sphilipefx_nic_reset(
502227569Sphilip	__in		efx_nic_t *enp)
503227569Sphilip{
504299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
505227569Sphilip	unsigned int mod_flags;
506291436Sarybchik	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	/*
511300007Sarybchik	 * All modules except the MCDI, PROBE, NVRAM, VPD, MON
512293901Sarybchik	 * (which we do not reset here) must have been shut down or never
513293901Sarybchik	 * 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 |
521300007Sarybchik		    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:
536291436Sarybchik	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);
546342446Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
547227569Sphilip
548227569Sphilip	return (&(enp->en_nic_cfg));
549227569Sphilip}
550227569Sphilip
551227569Sphilip#if EFSYS_OPT_DIAG
552227569Sphilip
553291436Sarybchik	__checkReturn	efx_rc_t
554227569Sphilipefx_nic_register_test(
555227569Sphilip	__in		efx_nic_t *enp)
556227569Sphilip{
557299517Sarybchik	const efx_nic_ops_t *enop = enp->en_enop;
558291436Sarybchik	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:
570291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
571227569Sphilip
572227569Sphilip	return (rc);
573227569Sphilip}
574227569Sphilip
575227569Sphilip#endif	/* EFSYS_OPT_DIAG */
576283514Sarybchik
577283514Sarybchik#if EFSYS_OPT_LOOPBACK
578283514Sarybchik
579283514Sarybchikextern			void
580283514Sarybchikefx_loopback_mask(
581283514Sarybchik	__in	efx_loopback_kind_t loopback_kind,
582283514Sarybchik	__out	efx_qword_t *maskp)
583283514Sarybchik{
584283514Sarybchik	efx_qword_t mask;
585283514Sarybchik
586283514Sarybchik	EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS);
587283514Sarybchik	EFSYS_ASSERT(maskp != NULL);
588283514Sarybchik
589283514Sarybchik	/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
590283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
591283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
592283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
593283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
594283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
595283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
596283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
597283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
598283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
599283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
600283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
601283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
602283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
603283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
604283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
605283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
606283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
607283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
608283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT);
609283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS);
610283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS);
611283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR ==
612283514Sarybchik	    EFX_LOOPBACK_XAUI_WS_FAR);
613283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR ==
614283514Sarybchik	    EFX_LOOPBACK_XAUI_WS_NEAR);
615283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS);
616283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS);
617283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR ==
618283514Sarybchik	    EFX_LOOPBACK_XFI_WS_FAR);
619283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS);
620283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT);
621283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR);
622283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR);
623283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS ==
624283514Sarybchik	    EFX_LOOPBACK_PMA_INT_WS);
625283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS ==
626283514Sarybchik	    EFX_LOOPBACK_SD_FEP2_WS);
627283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS ==
628283514Sarybchik	    EFX_LOOPBACK_SD_FEP1_5_WS);
629283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS);
630283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS);
631283514Sarybchik
632283514Sarybchik	/* Build bitmask of possible loopback types */
633283514Sarybchik	EFX_ZERO_QWORD(mask);
634283514Sarybchik
635283514Sarybchik	if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) ||
636283514Sarybchik	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
637283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF);
638283514Sarybchik	}
639283514Sarybchik
640283514Sarybchik	if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) ||
641283514Sarybchik	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
642283514Sarybchik		/*
643283514Sarybchik		 * The "MAC" grouping has historically been used by drivers to
644283514Sarybchik		 * mean loopbacks supported by on-chip hardware. Keep that
645283514Sarybchik		 * meaning here, and include on-chip PHY layer loopbacks.
646283514Sarybchik		 */
647283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA);
648283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC);
649283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII);
650283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS);
651283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI);
652283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII);
653283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII);
654283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR);
655283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI);
656283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR);
657283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR);
658283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR);
659283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR);
660283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT);
661283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR);
662283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR);
663283514Sarybchik	}
664283514Sarybchik
665283514Sarybchik	if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) ||
666283514Sarybchik	    (loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
667283514Sarybchik		/*
668283514Sarybchik		 * The "PHY" grouping has historically been used by drivers to
669283514Sarybchik		 * mean loopbacks supported by off-chip hardware. Keep that
670283514Sarybchik		 * meaning here.
671283514Sarybchik		 */
672283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY);
673283514Sarybchik		EFX_SET_QWORD_BIT(mask,	EFX_LOOPBACK_PHY_XS);
674283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS);
675283514Sarybchik		EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD);
676283514Sarybchik	}
677283514Sarybchik
678283514Sarybchik	*maskp = mask;
679283514Sarybchik}
680283514Sarybchik
681291436Sarybchik	__checkReturn	efx_rc_t
682283514Sarybchikefx_mcdi_get_loopback_modes(
683283514Sarybchik	__in		efx_nic_t *enp)
684283514Sarybchik{
685283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
686283514Sarybchik	efx_mcdi_req_t req;
687342445Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LOOPBACK_MODES_IN_LEN,
688342445Sarybchik		MC_CMD_GET_LOOPBACK_MODES_OUT_LEN);
689283514Sarybchik	efx_qword_t mask;
690283514Sarybchik	efx_qword_t modes;
691291436Sarybchik	efx_rc_t rc;
692283514Sarybchik
693283514Sarybchik	req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES;
694283514Sarybchik	req.emr_in_buf = payload;
695283514Sarybchik	req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN;
696283514Sarybchik	req.emr_out_buf = payload;
697283514Sarybchik	req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN;
698283514Sarybchik
699283514Sarybchik	efx_mcdi_execute(enp, &req);
700283514Sarybchik
701283514Sarybchik	if (req.emr_rc != 0) {
702283514Sarybchik		rc = req.emr_rc;
703283514Sarybchik		goto fail1;
704283514Sarybchik	}
705283514Sarybchik
706283514Sarybchik	if (req.emr_out_length_used <
707283514Sarybchik	    MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST +
708283514Sarybchik	    MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) {
709283514Sarybchik		rc = EMSGSIZE;
710283514Sarybchik		goto fail2;
711283514Sarybchik	}
712283514Sarybchik
713283514Sarybchik	/*
714283514Sarybchik	 * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree
715283514Sarybchik	 * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link().
716283514Sarybchik	 */
717283514Sarybchik	efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask);
718283514Sarybchik
719283514Sarybchik	EFX_AND_QWORD(mask,
720283514Sarybchik	    *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED));
721283514Sarybchik
722283514Sarybchik	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M);
723283514Sarybchik	EFX_AND_QWORD(modes, mask);
724283514Sarybchik	encp->enc_loopback_types[EFX_LINK_100FDX] = modes;
725283514Sarybchik
726283514Sarybchik	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G);
727283514Sarybchik	EFX_AND_QWORD(modes, mask);
728283514Sarybchik	encp->enc_loopback_types[EFX_LINK_1000FDX] = modes;
729283514Sarybchik
730283514Sarybchik	modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G);
731283514Sarybchik	EFX_AND_QWORD(modes, mask);
732283514Sarybchik	encp->enc_loopback_types[EFX_LINK_10000FDX] = modes;
733283514Sarybchik
734283514Sarybchik	if (req.emr_out_length_used >=
735283514Sarybchik	    MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST +
736283514Sarybchik	    MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) {
737283514Sarybchik		/* Response includes 40G loopback modes */
738283514Sarybchik		modes =
739283514Sarybchik		    *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G);
740283514Sarybchik		EFX_AND_QWORD(modes, mask);
741283514Sarybchik		encp->enc_loopback_types[EFX_LINK_40000FDX] = modes;
742283514Sarybchik	}
743283514Sarybchik
744283514Sarybchik	EFX_ZERO_QWORD(modes);
745283514Sarybchik	EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF);
746283514Sarybchik	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]);
747283514Sarybchik	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]);
748283514Sarybchik	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]);
749283514Sarybchik	EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]);
750283514Sarybchik	encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes;
751283514Sarybchik
752283514Sarybchik	return (0);
753283514Sarybchik
754283514Sarybchikfail2:
755283514Sarybchik	EFSYS_PROBE(fail2);
756283514Sarybchikfail1:
757291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
758283514Sarybchik
759283514Sarybchik	return (rc);
760283514Sarybchik}
761283514Sarybchik
762283514Sarybchik#endif /* EFSYS_OPT_LOOPBACK */
763299904Sarybchik
764299904Sarybchik	__checkReturn	efx_rc_t
765299904Sarybchikefx_nic_calculate_pcie_link_bandwidth(
766299904Sarybchik	__in		uint32_t pcie_link_width,
767299904Sarybchik	__in		uint32_t pcie_link_gen,
768299904Sarybchik	__out		uint32_t *bandwidth_mbpsp)
769299904Sarybchik{
770299904Sarybchik	uint32_t lane_bandwidth;
771299904Sarybchik	uint32_t total_bandwidth;
772299904Sarybchik	efx_rc_t rc;
773299904Sarybchik
774299904Sarybchik	if ((pcie_link_width == 0) || (pcie_link_width > 16) ||
775299904Sarybchik	    !ISP2(pcie_link_width)) {
776299904Sarybchik		rc = EINVAL;
777299904Sarybchik		goto fail1;
778299904Sarybchik	}
779299904Sarybchik
780299904Sarybchik	switch (pcie_link_gen) {
781299904Sarybchik	case EFX_PCIE_LINK_SPEED_GEN1:
782299904Sarybchik		/* 2.5 Gb/s raw bandwidth with 8b/10b encoding */
783299904Sarybchik		lane_bandwidth = 2000;
784299904Sarybchik		break;
785299904Sarybchik	case EFX_PCIE_LINK_SPEED_GEN2:
786299904Sarybchik		/* 5.0 Gb/s raw bandwidth with 8b/10b encoding */
787299904Sarybchik		lane_bandwidth = 4000;
788299904Sarybchik		break;
789299904Sarybchik	case EFX_PCIE_LINK_SPEED_GEN3:
790299904Sarybchik		/* 8.0 Gb/s raw bandwidth with 128b/130b encoding */
791299904Sarybchik		lane_bandwidth = 7877;
792299904Sarybchik		break;
793299904Sarybchik	default:
794299904Sarybchik		rc = EINVAL;
795299904Sarybchik		goto fail2;
796299904Sarybchik	}
797299904Sarybchik
798299904Sarybchik	total_bandwidth = lane_bandwidth * pcie_link_width;
799299904Sarybchik	*bandwidth_mbpsp = total_bandwidth;
800299904Sarybchik
801299904Sarybchik	return (0);
802299904Sarybchik
803299904Sarybchikfail2:
804299904Sarybchik	EFSYS_PROBE(fail2);
805299904Sarybchikfail1:
806299904Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
807299904Sarybchik
808299904Sarybchik	return (rc);
809299904Sarybchik}
810299904Sarybchik
811299904Sarybchik
812299904Sarybchik	__checkReturn	efx_rc_t
813299904Sarybchikefx_nic_check_pcie_link_speed(
814299904Sarybchik	__in		efx_nic_t *enp,
815299904Sarybchik	__in		uint32_t pcie_link_width,
816299904Sarybchik	__in		uint32_t pcie_link_gen,
817299904Sarybchik	__out		efx_pcie_link_performance_t *resultp)
818299904Sarybchik{
819299904Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
820299904Sarybchik	uint32_t bandwidth;
821299904Sarybchik	efx_pcie_link_performance_t result;
822299904Sarybchik	efx_rc_t rc;
823299904Sarybchik
824299904Sarybchik	if ((encp->enc_required_pcie_bandwidth_mbps == 0) ||
825299904Sarybchik	    (pcie_link_width == 0) || (pcie_link_width == 32) ||
826299904Sarybchik	    (pcie_link_gen == 0)) {
827299904Sarybchik		/*
828299904Sarybchik		 * No usable info on what is required and/or in use. In virtual
829299904Sarybchik		 * machines, sometimes the PCIe link width is reported as 0 or
830299904Sarybchik		 * 32, or the speed as 0.
831299904Sarybchik		 */
832299904Sarybchik		result = EFX_PCIE_LINK_PERFORMANCE_UNKNOWN_BANDWIDTH;
833299904Sarybchik		goto out;
834299904Sarybchik	}
835299904Sarybchik
836299904Sarybchik	/* Calculate the available bandwidth in megabits per second */
837299904Sarybchik	rc = efx_nic_calculate_pcie_link_bandwidth(pcie_link_width,
838299904Sarybchik					    pcie_link_gen, &bandwidth);
839299904Sarybchik	if (rc != 0)
840299904Sarybchik		goto fail1;
841299904Sarybchik
842299904Sarybchik	if (bandwidth < encp->enc_required_pcie_bandwidth_mbps) {
843299904Sarybchik		result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_BANDWIDTH;
844299904Sarybchik	} else if (pcie_link_gen < encp->enc_max_pcie_link_gen) {
845299904Sarybchik		/* The link provides enough bandwidth but not optimal latency */
846299904Sarybchik		result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_LATENCY;
847299904Sarybchik	} else {
848299904Sarybchik		result = EFX_PCIE_LINK_PERFORMANCE_OPTIMAL;
849299904Sarybchik	}
850299904Sarybchik
851299904Sarybchikout:
852299904Sarybchik	*resultp = result;
853299904Sarybchik
854299904Sarybchik	return (0);
855299904Sarybchik
856299904Sarybchikfail1:
857299904Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
858299904Sarybchik
859299904Sarybchik	return (rc);
860299904Sarybchik}
861