xref: /freebsd/sys/dev/sfxge/common/efx_mac.c (revision 929c7feb)
1e948693eSPhilip Paeps /*-
2929c7febSAndrew Rybchenko  * Copyright (c) 2007-2016 Solarflare Communications Inc.
33c838a9fSAndrew Rybchenko  * All rights reserved.
4e948693eSPhilip Paeps  *
5e948693eSPhilip Paeps  * Redistribution and use in source and binary forms, with or without
63c838a9fSAndrew Rybchenko  * modification, are permitted provided that the following conditions are met:
7e948693eSPhilip Paeps  *
83c838a9fSAndrew Rybchenko  * 1. Redistributions of source code must retain the above copyright notice,
93c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer.
103c838a9fSAndrew Rybchenko  * 2. Redistributions in binary form must reproduce the above copyright notice,
113c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer in the documentation
123c838a9fSAndrew Rybchenko  *    and/or other materials provided with the distribution.
133c838a9fSAndrew Rybchenko  *
143c838a9fSAndrew Rybchenko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
153c838a9fSAndrew Rybchenko  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
163c838a9fSAndrew Rybchenko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
173c838a9fSAndrew Rybchenko  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
183c838a9fSAndrew Rybchenko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
193c838a9fSAndrew Rybchenko  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
203c838a9fSAndrew Rybchenko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
213c838a9fSAndrew Rybchenko  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
223c838a9fSAndrew Rybchenko  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
233c838a9fSAndrew Rybchenko  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
243c838a9fSAndrew Rybchenko  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
253c838a9fSAndrew Rybchenko  *
263c838a9fSAndrew Rybchenko  * The views and conclusions contained in the software and documentation are
273c838a9fSAndrew Rybchenko  * those of the authors and should not be interpreted as representing official
283c838a9fSAndrew Rybchenko  * policies, either expressed or implied, of the FreeBSD Project.
29e948693eSPhilip Paeps  */
30e948693eSPhilip Paeps 
315dee87d7SPhilip Paeps #include <sys/cdefs.h>
325dee87d7SPhilip Paeps __FBSDID("$FreeBSD$");
335dee87d7SPhilip Paeps 
34e948693eSPhilip Paeps #include "efx.h"
35e948693eSPhilip Paeps #include "efx_impl.h"
36e948693eSPhilip Paeps 
37e75412c9SAndrew Rybchenko #if EFSYS_OPT_SIENA
383c838a9fSAndrew Rybchenko 
39460cb568SAndrew Rybchenko static	__checkReturn	efx_rc_t
405cab4fc7SAndrew Rybchenko siena_mac_multicast_list_set(
413c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp);
423c838a9fSAndrew Rybchenko 
43e75412c9SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
443c838a9fSAndrew Rybchenko 
45e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
46ec831f7fSAndrew Rybchenko static const efx_mac_ops_t	__efx_siena_mac_ops = {
47e948693eSPhilip Paeps 	siena_mac_poll,				/* emo_poll */
48e948693eSPhilip Paeps 	siena_mac_up,				/* emo_up */
493c838a9fSAndrew Rybchenko 	siena_mac_reconfigure,			/* emo_addr_set */
5008c5af79SAndrew Rybchenko 	siena_mac_reconfigure,			/* emo_pdu_set */
51d8484af2SAndrew Rybchenko 	siena_mac_pdu_get,			/* emo_pdu_get */
52e948693eSPhilip Paeps 	siena_mac_reconfigure,			/* emo_reconfigure */
535cab4fc7SAndrew Rybchenko 	siena_mac_multicast_list_set,		/* emo_multicast_list_set */
543c838a9fSAndrew Rybchenko 	NULL,					/* emo_filter_set_default_rxq */
553c838a9fSAndrew Rybchenko 	NULL,				/* emo_filter_default_rxq_clear */
56e948693eSPhilip Paeps #if EFSYS_OPT_LOOPBACK
57e948693eSPhilip Paeps 	siena_mac_loopback_set,			/* emo_loopback_set */
58e948693eSPhilip Paeps #endif	/* EFSYS_OPT_LOOPBACK */
59e948693eSPhilip Paeps #if EFSYS_OPT_MAC_STATS
603c838a9fSAndrew Rybchenko 	efx_mcdi_mac_stats_upload,		/* emo_stats_upload */
613c838a9fSAndrew Rybchenko 	efx_mcdi_mac_stats_periodic,		/* emo_stats_periodic */
62e948693eSPhilip Paeps 	siena_mac_stats_update			/* emo_stats_update */
63e948693eSPhilip Paeps #endif	/* EFSYS_OPT_MAC_STATS */
64e948693eSPhilip Paeps };
65e948693eSPhilip Paeps #endif	/* EFSYS_OPT_SIENA */
66e948693eSPhilip Paeps 
67c15d6d21SAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
68ec831f7fSAndrew Rybchenko static const efx_mac_ops_t	__efx_ef10_mac_ops = {
69c15d6d21SAndrew Rybchenko 	ef10_mac_poll,				/* emo_poll */
70c15d6d21SAndrew Rybchenko 	ef10_mac_up,				/* emo_up */
71c15d6d21SAndrew Rybchenko 	ef10_mac_addr_set,			/* emo_addr_set */
7208c5af79SAndrew Rybchenko 	ef10_mac_pdu_set,			/* emo_pdu_set */
73d8484af2SAndrew Rybchenko 	ef10_mac_pdu_get,			/* emo_pdu_get */
74c15d6d21SAndrew Rybchenko 	ef10_mac_reconfigure,			/* emo_reconfigure */
75c15d6d21SAndrew Rybchenko 	ef10_mac_multicast_list_set,		/* emo_multicast_list_set */
76c15d6d21SAndrew Rybchenko 	ef10_mac_filter_default_rxq_set,	/* emo_filter_default_rxq_set */
77c15d6d21SAndrew Rybchenko 	ef10_mac_filter_default_rxq_clear,
783c838a9fSAndrew Rybchenko 					/* emo_filter_default_rxq_clear */
793c838a9fSAndrew Rybchenko #if EFSYS_OPT_LOOPBACK
80c15d6d21SAndrew Rybchenko 	ef10_mac_loopback_set,			/* emo_loopback_set */
813c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_LOOPBACK */
823c838a9fSAndrew Rybchenko #if EFSYS_OPT_MAC_STATS
833c838a9fSAndrew Rybchenko 	efx_mcdi_mac_stats_upload,		/* emo_stats_upload */
843c838a9fSAndrew Rybchenko 	efx_mcdi_mac_stats_periodic,		/* emo_stats_periodic */
85c15d6d21SAndrew Rybchenko 	ef10_mac_stats_update			/* emo_stats_update */
863c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_MAC_STATS */
873c838a9fSAndrew Rybchenko };
88c15d6d21SAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
893c838a9fSAndrew Rybchenko 
90460cb568SAndrew Rybchenko 	__checkReturn			efx_rc_t
91e948693eSPhilip Paeps efx_mac_pdu_set(
92e948693eSPhilip Paeps 	__in				efx_nic_t *enp,
93e948693eSPhilip Paeps 	__in				size_t pdu)
94e948693eSPhilip Paeps {
95e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
96ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
97e948693eSPhilip Paeps 	uint32_t old_pdu;
98460cb568SAndrew Rybchenko 	efx_rc_t rc;
99e948693eSPhilip Paeps 
100e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
101e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
102e948693eSPhilip Paeps 	EFSYS_ASSERT(emop != NULL);
103e948693eSPhilip Paeps 
104e948693eSPhilip Paeps 	if (pdu < EFX_MAC_PDU_MIN) {
105e948693eSPhilip Paeps 		rc = EINVAL;
106e948693eSPhilip Paeps 		goto fail1;
107e948693eSPhilip Paeps 	}
108e948693eSPhilip Paeps 
109e948693eSPhilip Paeps 	if (pdu > EFX_MAC_PDU_MAX) {
110e948693eSPhilip Paeps 		rc = EINVAL;
111e948693eSPhilip Paeps 		goto fail2;
112e948693eSPhilip Paeps 	}
113e948693eSPhilip Paeps 
114e948693eSPhilip Paeps 	old_pdu = epp->ep_mac_pdu;
115e948693eSPhilip Paeps 	epp->ep_mac_pdu = (uint32_t)pdu;
11608c5af79SAndrew Rybchenko 	if ((rc = emop->emo_pdu_set(enp)) != 0)
117e948693eSPhilip Paeps 		goto fail3;
118e948693eSPhilip Paeps 
119e948693eSPhilip Paeps 	return (0);
120e948693eSPhilip Paeps 
121e948693eSPhilip Paeps fail3:
122e948693eSPhilip Paeps 	EFSYS_PROBE(fail3);
123e948693eSPhilip Paeps 
124e948693eSPhilip Paeps 	epp->ep_mac_pdu = old_pdu;
125e948693eSPhilip Paeps 
126e948693eSPhilip Paeps fail2:
127e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
128e948693eSPhilip Paeps fail1:
129460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
130e948693eSPhilip Paeps 
131e948693eSPhilip Paeps 	return (rc);
132e948693eSPhilip Paeps }
133e948693eSPhilip Paeps 
134460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
135d8484af2SAndrew Rybchenko efx_mac_pdu_get(
136d8484af2SAndrew Rybchenko 	__in		efx_nic_t *enp,
137d8484af2SAndrew Rybchenko 	__out		size_t *pdu)
138d8484af2SAndrew Rybchenko {
139d8484af2SAndrew Rybchenko 	efx_port_t *epp = &(enp->en_port);
140d8484af2SAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
141d8484af2SAndrew Rybchenko 	efx_rc_t rc;
142d8484af2SAndrew Rybchenko 
143d8484af2SAndrew Rybchenko 	if ((rc = emop->emo_pdu_get(enp, pdu)) != 0)
144d8484af2SAndrew Rybchenko 		goto fail1;
145d8484af2SAndrew Rybchenko 
146d8484af2SAndrew Rybchenko 	return (0);
147d8484af2SAndrew Rybchenko 
148d8484af2SAndrew Rybchenko fail1:
149d8484af2SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
150d8484af2SAndrew Rybchenko 
151d8484af2SAndrew Rybchenko 	return (rc);
152d8484af2SAndrew Rybchenko }
153d8484af2SAndrew Rybchenko 
154d8484af2SAndrew Rybchenko 	__checkReturn			efx_rc_t
155e948693eSPhilip Paeps efx_mac_addr_set(
156e948693eSPhilip Paeps 	__in				efx_nic_t *enp,
157e948693eSPhilip Paeps 	__in				uint8_t *addr)
158e948693eSPhilip Paeps {
159e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
160ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
161e948693eSPhilip Paeps 	uint8_t old_addr[6];
162e948693eSPhilip Paeps 	uint32_t oui;
163460cb568SAndrew Rybchenko 	efx_rc_t rc;
164e948693eSPhilip Paeps 
165e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
166e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
167e948693eSPhilip Paeps 
1683c838a9fSAndrew Rybchenko 	if (EFX_MAC_ADDR_IS_MULTICAST(addr)) {
169e948693eSPhilip Paeps 		rc = EINVAL;
170e948693eSPhilip Paeps 		goto fail1;
171e948693eSPhilip Paeps 	}
172e948693eSPhilip Paeps 
173e948693eSPhilip Paeps 	oui = addr[0] << 16 | addr[1] << 8 | addr[2];
174e948693eSPhilip Paeps 	if (oui == 0x000000) {
175e948693eSPhilip Paeps 		rc = EINVAL;
176e948693eSPhilip Paeps 		goto fail2;
177e948693eSPhilip Paeps 	}
178e948693eSPhilip Paeps 
179e948693eSPhilip Paeps 	EFX_MAC_ADDR_COPY(old_addr, epp->ep_mac_addr);
180e948693eSPhilip Paeps 	EFX_MAC_ADDR_COPY(epp->ep_mac_addr, addr);
1813c838a9fSAndrew Rybchenko 	if ((rc = emop->emo_addr_set(enp)) != 0)
182e948693eSPhilip Paeps 		goto fail3;
183e948693eSPhilip Paeps 
184e948693eSPhilip Paeps 	return (0);
185e948693eSPhilip Paeps 
186e948693eSPhilip Paeps fail3:
187e948693eSPhilip Paeps 	EFSYS_PROBE(fail3);
188e948693eSPhilip Paeps 
189e948693eSPhilip Paeps 	EFX_MAC_ADDR_COPY(epp->ep_mac_addr, old_addr);
190e948693eSPhilip Paeps 
191e948693eSPhilip Paeps fail2:
192e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
193e948693eSPhilip Paeps fail1:
194460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
195e948693eSPhilip Paeps 
196e948693eSPhilip Paeps 	return (rc);
197e948693eSPhilip Paeps }
198e948693eSPhilip Paeps 
199460cb568SAndrew Rybchenko 	__checkReturn			efx_rc_t
200e948693eSPhilip Paeps efx_mac_filter_set(
201e948693eSPhilip Paeps 	__in				efx_nic_t *enp,
2023c838a9fSAndrew Rybchenko 	__in				boolean_t all_unicst,
2033c838a9fSAndrew Rybchenko 	__in				boolean_t mulcst,
2043c838a9fSAndrew Rybchenko 	__in				boolean_t all_mulcst,
205e948693eSPhilip Paeps 	__in				boolean_t brdcst)
206e948693eSPhilip Paeps {
207e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
208ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
2093c838a9fSAndrew Rybchenko 	boolean_t old_all_unicst;
2103c838a9fSAndrew Rybchenko 	boolean_t old_mulcst;
2113c838a9fSAndrew Rybchenko 	boolean_t old_all_mulcst;
212e948693eSPhilip Paeps 	boolean_t old_brdcst;
213460cb568SAndrew Rybchenko 	efx_rc_t rc;
214e948693eSPhilip Paeps 
215e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
216e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
217e948693eSPhilip Paeps 
2183c838a9fSAndrew Rybchenko 	old_all_unicst = epp->ep_all_unicst;
2193c838a9fSAndrew Rybchenko 	old_mulcst = epp->ep_mulcst;
2203c838a9fSAndrew Rybchenko 	old_all_mulcst = epp->ep_all_mulcst;
2213c838a9fSAndrew Rybchenko 	old_brdcst = epp->ep_brdcst;
222e948693eSPhilip Paeps 
2233c838a9fSAndrew Rybchenko 	epp->ep_all_unicst = all_unicst;
2243c838a9fSAndrew Rybchenko 	epp->ep_mulcst = mulcst;
2253c838a9fSAndrew Rybchenko 	epp->ep_all_mulcst = all_mulcst;
226e948693eSPhilip Paeps 	epp->ep_brdcst = brdcst;
227e948693eSPhilip Paeps 
228e948693eSPhilip Paeps 	if ((rc = emop->emo_reconfigure(enp)) != 0)
229e948693eSPhilip Paeps 		goto fail1;
230e948693eSPhilip Paeps 
231e948693eSPhilip Paeps 	return (0);
232e948693eSPhilip Paeps 
233e948693eSPhilip Paeps fail1:
234460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
235e948693eSPhilip Paeps 
2363c838a9fSAndrew Rybchenko 	epp->ep_all_unicst = old_all_unicst;
2373c838a9fSAndrew Rybchenko 	epp->ep_mulcst = old_mulcst;
2383c838a9fSAndrew Rybchenko 	epp->ep_all_mulcst = old_all_mulcst;
239e948693eSPhilip Paeps 	epp->ep_brdcst = old_brdcst;
240e948693eSPhilip Paeps 
241e948693eSPhilip Paeps 	return (rc);
242e948693eSPhilip Paeps }
243e948693eSPhilip Paeps 
244460cb568SAndrew Rybchenko 	__checkReturn			efx_rc_t
245e948693eSPhilip Paeps efx_mac_drain(
246e948693eSPhilip Paeps 	__in				efx_nic_t *enp,
247e948693eSPhilip Paeps 	__in				boolean_t enabled)
248e948693eSPhilip Paeps {
249e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
250ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
251460cb568SAndrew Rybchenko 	efx_rc_t rc;
252e948693eSPhilip Paeps 
253e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
254e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
255e948693eSPhilip Paeps 	EFSYS_ASSERT(emop != NULL);
256e948693eSPhilip Paeps 
257e948693eSPhilip Paeps 	if (epp->ep_mac_drain == enabled)
258e948693eSPhilip Paeps 		return (0);
259e948693eSPhilip Paeps 
260e948693eSPhilip Paeps 	epp->ep_mac_drain = enabled;
261e948693eSPhilip Paeps 
262e948693eSPhilip Paeps 	if ((rc = emop->emo_reconfigure(enp)) != 0)
2630c909247SAndrew Rybchenko 		goto fail1;
264e948693eSPhilip Paeps 
265e948693eSPhilip Paeps 	return (0);
266e948693eSPhilip Paeps 
267e948693eSPhilip Paeps fail1:
268460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
269e948693eSPhilip Paeps 
270e948693eSPhilip Paeps 	return (rc);
271e948693eSPhilip Paeps }
272e948693eSPhilip Paeps 
273460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
274e948693eSPhilip Paeps efx_mac_up(
275e948693eSPhilip Paeps 	__in		efx_nic_t *enp,
276e948693eSPhilip Paeps 	__out		boolean_t *mac_upp)
277e948693eSPhilip Paeps {
278e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
279ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
280460cb568SAndrew Rybchenko 	efx_rc_t rc;
281e948693eSPhilip Paeps 
282e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
283e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
284e948693eSPhilip Paeps 
285e948693eSPhilip Paeps 	if ((rc = emop->emo_up(enp, mac_upp)) != 0)
286e948693eSPhilip Paeps 		goto fail1;
287e948693eSPhilip Paeps 
288e948693eSPhilip Paeps 	return (0);
289e948693eSPhilip Paeps 
290e948693eSPhilip Paeps fail1:
291460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
292e948693eSPhilip Paeps 
293e948693eSPhilip Paeps 	return (rc);
294e948693eSPhilip Paeps }
295e948693eSPhilip Paeps 
296460cb568SAndrew Rybchenko 	__checkReturn			efx_rc_t
297e948693eSPhilip Paeps efx_mac_fcntl_set(
298e948693eSPhilip Paeps 	__in				efx_nic_t *enp,
299e948693eSPhilip Paeps 	__in				unsigned int fcntl,
300e948693eSPhilip Paeps 	__in				boolean_t autoneg)
301e948693eSPhilip Paeps {
302e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
303ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
304ec831f7fSAndrew Rybchenko 	const efx_phy_ops_t *epop = epp->ep_epop;
305e948693eSPhilip Paeps 	unsigned int old_fcntl;
306e948693eSPhilip Paeps 	boolean_t old_autoneg;
307e948693eSPhilip Paeps 	unsigned int old_adv_cap;
308460cb568SAndrew Rybchenko 	efx_rc_t rc;
309e948693eSPhilip Paeps 
310e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
311e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
312e948693eSPhilip Paeps 
313e948693eSPhilip Paeps 	if ((fcntl & ~(EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE)) != 0) {
314e948693eSPhilip Paeps 		rc = EINVAL;
315e948693eSPhilip Paeps 		goto fail1;
316e948693eSPhilip Paeps 	}
317e948693eSPhilip Paeps 
318e948693eSPhilip Paeps 	/*
3193c838a9fSAndrew Rybchenko 	 * Ignore a request to set flow control auto-negotiation
320e948693eSPhilip Paeps 	 * if the PHY doesn't support it.
321e948693eSPhilip Paeps 	 */
322e948693eSPhilip Paeps 	if (~epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
323e948693eSPhilip Paeps 		autoneg = B_FALSE;
324e948693eSPhilip Paeps 
325e948693eSPhilip Paeps 	old_fcntl = epp->ep_fcntl;
3263c838a9fSAndrew Rybchenko 	old_autoneg = epp->ep_fcntl_autoneg;
327e948693eSPhilip Paeps 	old_adv_cap = epp->ep_adv_cap_mask;
328e948693eSPhilip Paeps 
329e948693eSPhilip Paeps 	epp->ep_fcntl = fcntl;
330e948693eSPhilip Paeps 	epp->ep_fcntl_autoneg = autoneg;
331e948693eSPhilip Paeps 
332e948693eSPhilip Paeps 	/*
3333c838a9fSAndrew Rybchenko 	 * Always encode the flow control settings in the advertised
3343c838a9fSAndrew Rybchenko 	 * capabilities even if we are not trying to auto-negotiate
3353c838a9fSAndrew Rybchenko 	 * them and reconfigure both the PHY and the MAC.
336e948693eSPhilip Paeps 	 */
337e948693eSPhilip Paeps 	if (fcntl & EFX_FCNTL_RESPOND)
338e948693eSPhilip Paeps 		epp->ep_adv_cap_mask |=    (1 << EFX_PHY_CAP_PAUSE |
339e948693eSPhilip Paeps 					    1 << EFX_PHY_CAP_ASYM);
340e948693eSPhilip Paeps 	else
341e948693eSPhilip Paeps 		epp->ep_adv_cap_mask &=   ~(1 << EFX_PHY_CAP_PAUSE |
342e948693eSPhilip Paeps 					    1 << EFX_PHY_CAP_ASYM);
343e948693eSPhilip Paeps 
344e948693eSPhilip Paeps 	if (fcntl & EFX_FCNTL_GENERATE)
345e948693eSPhilip Paeps 		epp->ep_adv_cap_mask ^= (1 << EFX_PHY_CAP_ASYM);
346e948693eSPhilip Paeps 
347e948693eSPhilip Paeps 	if ((rc = epop->epo_reconfigure(enp)) != 0)
348e948693eSPhilip Paeps 		goto fail2;
349e948693eSPhilip Paeps 
350e948693eSPhilip Paeps 	if ((rc = emop->emo_reconfigure(enp)) != 0)
3513c838a9fSAndrew Rybchenko 		goto fail3;
352e948693eSPhilip Paeps 
353e948693eSPhilip Paeps 	return (0);
354e948693eSPhilip Paeps 
3553c838a9fSAndrew Rybchenko fail3:
3563c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
3573c838a9fSAndrew Rybchenko 
358e948693eSPhilip Paeps fail2:
359e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
360e948693eSPhilip Paeps 
361e948693eSPhilip Paeps 	epp->ep_fcntl = old_fcntl;
362e948693eSPhilip Paeps 	epp->ep_fcntl_autoneg = old_autoneg;
363e948693eSPhilip Paeps 	epp->ep_adv_cap_mask = old_adv_cap;
364e948693eSPhilip Paeps 
365e948693eSPhilip Paeps fail1:
366460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
367e948693eSPhilip Paeps 
368e948693eSPhilip Paeps 	return (rc);
369e948693eSPhilip Paeps }
370e948693eSPhilip Paeps 
371e948693eSPhilip Paeps 			void
372e948693eSPhilip Paeps efx_mac_fcntl_get(
373e948693eSPhilip Paeps 	__in		efx_nic_t *enp,
374e948693eSPhilip Paeps 	__out		unsigned int *fcntl_wantedp,
375e948693eSPhilip Paeps 	__out		unsigned int *fcntl_linkp)
376e948693eSPhilip Paeps {
377e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
3783c838a9fSAndrew Rybchenko 	unsigned int wanted = 0;
379e948693eSPhilip Paeps 
380e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
381e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
382e948693eSPhilip Paeps 
383e948693eSPhilip Paeps 	/*
3843c838a9fSAndrew Rybchenko 	 * Decode the requested flow control settings from the PHY
3853c838a9fSAndrew Rybchenko 	 * advertised capabilities.
386e948693eSPhilip Paeps 	 */
387e948693eSPhilip Paeps 	if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_PAUSE))
388e948693eSPhilip Paeps 		wanted = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
389e948693eSPhilip Paeps 	if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_ASYM))
390e948693eSPhilip Paeps 		wanted ^= EFX_FCNTL_GENERATE;
391e948693eSPhilip Paeps 
392e948693eSPhilip Paeps 	*fcntl_linkp = epp->ep_fcntl;
393e948693eSPhilip Paeps 	*fcntl_wantedp = wanted;
394e948693eSPhilip Paeps }
395e948693eSPhilip Paeps 
396460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
3973c838a9fSAndrew Rybchenko efx_mac_multicast_list_set(
3983c838a9fSAndrew Rybchenko 	__in				efx_nic_t *enp,
3993c838a9fSAndrew Rybchenko 	__in_ecount(6*count)		uint8_t const *addrs,
4003c838a9fSAndrew Rybchenko 	__in				int count)
4013c838a9fSAndrew Rybchenko {
4023c838a9fSAndrew Rybchenko 	efx_port_t *epp = &(enp->en_port);
403ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
4043c838a9fSAndrew Rybchenko 	uint8_t	*old_mulcst_addr_list = NULL;
4053c838a9fSAndrew Rybchenko 	uint32_t old_mulcst_addr_count;
406460cb568SAndrew Rybchenko 	efx_rc_t rc;
4073c838a9fSAndrew Rybchenko 
4083c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
4093c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
4103c838a9fSAndrew Rybchenko 
4113c838a9fSAndrew Rybchenko 	if (count > EFX_MAC_MULTICAST_LIST_MAX) {
4123c838a9fSAndrew Rybchenko 		rc = EINVAL;
4133c838a9fSAndrew Rybchenko 		goto fail1;
4143c838a9fSAndrew Rybchenko 	}
4153c838a9fSAndrew Rybchenko 
4163c838a9fSAndrew Rybchenko 	old_mulcst_addr_count = epp->ep_mulcst_addr_count;
4173c838a9fSAndrew Rybchenko 	if (old_mulcst_addr_count > 0) {
4183c838a9fSAndrew Rybchenko 		/* Allocate memory to store old list (instead of using stack) */
4193c838a9fSAndrew Rybchenko 		EFSYS_KMEM_ALLOC(enp->en_esip,
4203c838a9fSAndrew Rybchenko 				old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
4213c838a9fSAndrew Rybchenko 				old_mulcst_addr_list);
4223c838a9fSAndrew Rybchenko 		if (old_mulcst_addr_list == NULL) {
4233c838a9fSAndrew Rybchenko 			rc = ENOMEM;
4243c838a9fSAndrew Rybchenko 			goto fail2;
4253c838a9fSAndrew Rybchenko 		}
4263c838a9fSAndrew Rybchenko 
4273c838a9fSAndrew Rybchenko 		/* Save the old list in case we need to rollback */
4283c838a9fSAndrew Rybchenko 		memcpy(old_mulcst_addr_list, epp->ep_mulcst_addr_list,
4293c838a9fSAndrew Rybchenko 			old_mulcst_addr_count * EFX_MAC_ADDR_LEN);
4303c838a9fSAndrew Rybchenko 	}
4313c838a9fSAndrew Rybchenko 
4323c838a9fSAndrew Rybchenko 	/* Store the new list */
4333c838a9fSAndrew Rybchenko 	memcpy(epp->ep_mulcst_addr_list, addrs,
4343c838a9fSAndrew Rybchenko 		count * EFX_MAC_ADDR_LEN);
4353c838a9fSAndrew Rybchenko 	epp->ep_mulcst_addr_count = count;
4363c838a9fSAndrew Rybchenko 
4373c838a9fSAndrew Rybchenko 	if ((rc = emop->emo_multicast_list_set(enp)) != 0)
4383c838a9fSAndrew Rybchenko 		goto fail3;
4393c838a9fSAndrew Rybchenko 
4403c838a9fSAndrew Rybchenko 	if (old_mulcst_addr_count > 0) {
4413c838a9fSAndrew Rybchenko 		EFSYS_KMEM_FREE(enp->en_esip,
4423c838a9fSAndrew Rybchenko 				old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
4433c838a9fSAndrew Rybchenko 				old_mulcst_addr_list);
4443c838a9fSAndrew Rybchenko 	}
4453c838a9fSAndrew Rybchenko 
4463c838a9fSAndrew Rybchenko 	return (0);
4473c838a9fSAndrew Rybchenko 
4483c838a9fSAndrew Rybchenko fail3:
4493c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
4503c838a9fSAndrew Rybchenko 
4513c838a9fSAndrew Rybchenko 	/* Restore original list on failure */
4523c838a9fSAndrew Rybchenko 	epp->ep_mulcst_addr_count = old_mulcst_addr_count;
4533c838a9fSAndrew Rybchenko 	if (old_mulcst_addr_count > 0) {
4543c838a9fSAndrew Rybchenko 		memcpy(epp->ep_mulcst_addr_list, old_mulcst_addr_list,
4553c838a9fSAndrew Rybchenko 			old_mulcst_addr_count * EFX_MAC_ADDR_LEN);
4563c838a9fSAndrew Rybchenko 
4573c838a9fSAndrew Rybchenko 		EFSYS_KMEM_FREE(enp->en_esip,
4583c838a9fSAndrew Rybchenko 				old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
4593c838a9fSAndrew Rybchenko 				old_mulcst_addr_list);
4603c838a9fSAndrew Rybchenko 	}
4613c838a9fSAndrew Rybchenko 
4623c838a9fSAndrew Rybchenko fail2:
4633c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
4643c838a9fSAndrew Rybchenko 
4653c838a9fSAndrew Rybchenko fail1:
466460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4673c838a9fSAndrew Rybchenko 
4683c838a9fSAndrew Rybchenko 	return (rc);
4693c838a9fSAndrew Rybchenko 
4703c838a9fSAndrew Rybchenko }
4713c838a9fSAndrew Rybchenko 
472460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
4733c838a9fSAndrew Rybchenko efx_mac_filter_default_rxq_set(
4743c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp,
4753c838a9fSAndrew Rybchenko 	__in		efx_rxq_t *erp,
4763c838a9fSAndrew Rybchenko 	__in		boolean_t using_rss)
4773c838a9fSAndrew Rybchenko {
4783c838a9fSAndrew Rybchenko 	efx_port_t *epp = &(enp->en_port);
479ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
480460cb568SAndrew Rybchenko 	efx_rc_t rc;
4813c838a9fSAndrew Rybchenko 
4823c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
4833c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
4843c838a9fSAndrew Rybchenko 
4853c838a9fSAndrew Rybchenko 	if (emop->emo_filter_default_rxq_set != NULL) {
4863c838a9fSAndrew Rybchenko 		rc = emop->emo_filter_default_rxq_set(enp, erp, using_rss);
4873c838a9fSAndrew Rybchenko 		if (rc != 0)
4883c838a9fSAndrew Rybchenko 			goto fail1;
4893c838a9fSAndrew Rybchenko 	}
4903c838a9fSAndrew Rybchenko 
4913c838a9fSAndrew Rybchenko 	return (0);
4923c838a9fSAndrew Rybchenko 
4933c838a9fSAndrew Rybchenko fail1:
494460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4953c838a9fSAndrew Rybchenko 
4963c838a9fSAndrew Rybchenko 	return (rc);
4973c838a9fSAndrew Rybchenko }
4983c838a9fSAndrew Rybchenko 
4993c838a9fSAndrew Rybchenko 			void
5003c838a9fSAndrew Rybchenko efx_mac_filter_default_rxq_clear(
5013c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp)
5023c838a9fSAndrew Rybchenko {
5033c838a9fSAndrew Rybchenko 	efx_port_t *epp = &(enp->en_port);
504ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
5053c838a9fSAndrew Rybchenko 
5063c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
5073c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
5083c838a9fSAndrew Rybchenko 
5093c838a9fSAndrew Rybchenko 	if (emop->emo_filter_default_rxq_clear != NULL)
5103c838a9fSAndrew Rybchenko 		emop->emo_filter_default_rxq_clear(enp);
5113c838a9fSAndrew Rybchenko }
5123c838a9fSAndrew Rybchenko 
5133c838a9fSAndrew Rybchenko 
514e948693eSPhilip Paeps #if EFSYS_OPT_MAC_STATS
515e948693eSPhilip Paeps 
516e948693eSPhilip Paeps #if EFSYS_OPT_NAMES
517e948693eSPhilip Paeps 
5183c838a9fSAndrew Rybchenko /* START MKCONFIG GENERATED EfxMacStatNamesBlock 054d43a31d2d7a45 */
5193c838a9fSAndrew Rybchenko static const char 	*__efx_mac_stat_name[] = {
520e948693eSPhilip Paeps 	"rx_octets",
521e948693eSPhilip Paeps 	"rx_pkts",
522e948693eSPhilip Paeps 	"rx_unicst_pkts",
523e948693eSPhilip Paeps 	"rx_multicst_pkts",
524e948693eSPhilip Paeps 	"rx_brdcst_pkts",
525e948693eSPhilip Paeps 	"rx_pause_pkts",
526e948693eSPhilip Paeps 	"rx_le_64_pkts",
527e948693eSPhilip Paeps 	"rx_65_to_127_pkts",
528e948693eSPhilip Paeps 	"rx_128_to_255_pkts",
529e948693eSPhilip Paeps 	"rx_256_to_511_pkts",
530e948693eSPhilip Paeps 	"rx_512_to_1023_pkts",
531e948693eSPhilip Paeps 	"rx_1024_to_15xx_pkts",
532e948693eSPhilip Paeps 	"rx_ge_15xx_pkts",
533e948693eSPhilip Paeps 	"rx_errors",
534e948693eSPhilip Paeps 	"rx_fcs_errors",
535e948693eSPhilip Paeps 	"rx_drop_events",
536e948693eSPhilip Paeps 	"rx_false_carrier_errors",
537e948693eSPhilip Paeps 	"rx_symbol_errors",
538e948693eSPhilip Paeps 	"rx_align_errors",
539e948693eSPhilip Paeps 	"rx_internal_errors",
540e948693eSPhilip Paeps 	"rx_jabber_pkts",
541e948693eSPhilip Paeps 	"rx_lane0_char_err",
542e948693eSPhilip Paeps 	"rx_lane1_char_err",
543e948693eSPhilip Paeps 	"rx_lane2_char_err",
544e948693eSPhilip Paeps 	"rx_lane3_char_err",
545e948693eSPhilip Paeps 	"rx_lane0_disp_err",
546e948693eSPhilip Paeps 	"rx_lane1_disp_err",
547e948693eSPhilip Paeps 	"rx_lane2_disp_err",
548e948693eSPhilip Paeps 	"rx_lane3_disp_err",
549e948693eSPhilip Paeps 	"rx_match_fault",
550e948693eSPhilip Paeps 	"rx_nodesc_drop_cnt",
551e948693eSPhilip Paeps 	"tx_octets",
552e948693eSPhilip Paeps 	"tx_pkts",
553e948693eSPhilip Paeps 	"tx_unicst_pkts",
554e948693eSPhilip Paeps 	"tx_multicst_pkts",
555e948693eSPhilip Paeps 	"tx_brdcst_pkts",
556e948693eSPhilip Paeps 	"tx_pause_pkts",
557e948693eSPhilip Paeps 	"tx_le_64_pkts",
558e948693eSPhilip Paeps 	"tx_65_to_127_pkts",
559e948693eSPhilip Paeps 	"tx_128_to_255_pkts",
560e948693eSPhilip Paeps 	"tx_256_to_511_pkts",
561e948693eSPhilip Paeps 	"tx_512_to_1023_pkts",
562e948693eSPhilip Paeps 	"tx_1024_to_15xx_pkts",
563e948693eSPhilip Paeps 	"tx_ge_15xx_pkts",
564e948693eSPhilip Paeps 	"tx_errors",
565e948693eSPhilip Paeps 	"tx_sgl_col_pkts",
566e948693eSPhilip Paeps 	"tx_mult_col_pkts",
567e948693eSPhilip Paeps 	"tx_ex_col_pkts",
568e948693eSPhilip Paeps 	"tx_late_col_pkts",
569e948693eSPhilip Paeps 	"tx_def_pkts",
570e948693eSPhilip Paeps 	"tx_ex_def_pkts",
5713c838a9fSAndrew Rybchenko 	"pm_trunc_bb_overflow",
5723c838a9fSAndrew Rybchenko 	"pm_discard_bb_overflow",
5733c838a9fSAndrew Rybchenko 	"pm_trunc_vfifo_full",
5743c838a9fSAndrew Rybchenko 	"pm_discard_vfifo_full",
5753c838a9fSAndrew Rybchenko 	"pm_trunc_qbb",
5763c838a9fSAndrew Rybchenko 	"pm_discard_qbb",
5773c838a9fSAndrew Rybchenko 	"pm_discard_mapping",
5783c838a9fSAndrew Rybchenko 	"rxdp_q_disabled_pkts",
5793c838a9fSAndrew Rybchenko 	"rxdp_di_dropped_pkts",
5803c838a9fSAndrew Rybchenko 	"rxdp_streaming_pkts",
5813c838a9fSAndrew Rybchenko 	"rxdp_hlb_fetch",
5823c838a9fSAndrew Rybchenko 	"rxdp_hlb_wait",
5833c838a9fSAndrew Rybchenko 	"vadapter_rx_unicast_packets",
5843c838a9fSAndrew Rybchenko 	"vadapter_rx_unicast_bytes",
5853c838a9fSAndrew Rybchenko 	"vadapter_rx_multicast_packets",
5863c838a9fSAndrew Rybchenko 	"vadapter_rx_multicast_bytes",
5873c838a9fSAndrew Rybchenko 	"vadapter_rx_broadcast_packets",
5883c838a9fSAndrew Rybchenko 	"vadapter_rx_broadcast_bytes",
5893c838a9fSAndrew Rybchenko 	"vadapter_rx_bad_packets",
5903c838a9fSAndrew Rybchenko 	"vadapter_rx_bad_bytes",
5913c838a9fSAndrew Rybchenko 	"vadapter_rx_overflow",
5923c838a9fSAndrew Rybchenko 	"vadapter_tx_unicast_packets",
5933c838a9fSAndrew Rybchenko 	"vadapter_tx_unicast_bytes",
5943c838a9fSAndrew Rybchenko 	"vadapter_tx_multicast_packets",
5953c838a9fSAndrew Rybchenko 	"vadapter_tx_multicast_bytes",
5963c838a9fSAndrew Rybchenko 	"vadapter_tx_broadcast_packets",
5973c838a9fSAndrew Rybchenko 	"vadapter_tx_broadcast_bytes",
5983c838a9fSAndrew Rybchenko 	"vadapter_tx_bad_packets",
5993c838a9fSAndrew Rybchenko 	"vadapter_tx_bad_bytes",
6003c838a9fSAndrew Rybchenko 	"vadapter_tx_overflow",
601e948693eSPhilip Paeps };
602e948693eSPhilip Paeps /* END MKCONFIG GENERATED EfxMacStatNamesBlock */
603e948693eSPhilip Paeps 
6043c838a9fSAndrew Rybchenko 	__checkReturn			const char *
605e948693eSPhilip Paeps efx_mac_stat_name(
606e948693eSPhilip Paeps 	__in				efx_nic_t *enp,
607e948693eSPhilip Paeps 	__in				unsigned int id)
608e948693eSPhilip Paeps {
609e948693eSPhilip Paeps 	_NOTE(ARGUNUSED(enp))
610e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
611e948693eSPhilip Paeps 
612e948693eSPhilip Paeps 	EFSYS_ASSERT3U(id, <, EFX_MAC_NSTATS);
613e948693eSPhilip Paeps 	return (__efx_mac_stat_name[id]);
614e948693eSPhilip Paeps }
615e948693eSPhilip Paeps 
6163c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_NAMES */
617e948693eSPhilip Paeps 
618460cb568SAndrew Rybchenko 	__checkReturn			efx_rc_t
619e948693eSPhilip Paeps efx_mac_stats_upload(
620e948693eSPhilip Paeps 	__in				efx_nic_t *enp,
621e948693eSPhilip Paeps 	__in				efsys_mem_t *esmp)
622e948693eSPhilip Paeps {
623e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
624ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
625460cb568SAndrew Rybchenko 	efx_rc_t rc;
626e948693eSPhilip Paeps 
627e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
628e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
629e948693eSPhilip Paeps 	EFSYS_ASSERT(emop != NULL);
630e948693eSPhilip Paeps 
631e948693eSPhilip Paeps 	/*
632e948693eSPhilip Paeps 	 * Don't assert !ep_mac_stats_pending, because the client might
633e948693eSPhilip Paeps 	 * have failed to finalise statistics when previously stopping
634e948693eSPhilip Paeps 	 * the port.
635e948693eSPhilip Paeps 	 */
636e948693eSPhilip Paeps 	if ((rc = emop->emo_stats_upload(enp, esmp)) != 0)
637e948693eSPhilip Paeps 		goto fail1;
638e948693eSPhilip Paeps 
639e948693eSPhilip Paeps 	epp->ep_mac_stats_pending = B_TRUE;
640e948693eSPhilip Paeps 
641e948693eSPhilip Paeps 	return (0);
642e948693eSPhilip Paeps 
643e948693eSPhilip Paeps fail1:
644460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
645e948693eSPhilip Paeps 
646e948693eSPhilip Paeps 	return (rc);
647e948693eSPhilip Paeps }
648e948693eSPhilip Paeps 
649460cb568SAndrew Rybchenko 	__checkReturn			efx_rc_t
650e948693eSPhilip Paeps efx_mac_stats_periodic(
651e948693eSPhilip Paeps 	__in				efx_nic_t *enp,
652e948693eSPhilip Paeps 	__in				efsys_mem_t *esmp,
653e948693eSPhilip Paeps 	__in				uint16_t period_ms,
654e948693eSPhilip Paeps 	__in				boolean_t events)
655e948693eSPhilip Paeps {
656e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
657ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
658460cb568SAndrew Rybchenko 	efx_rc_t rc;
659e948693eSPhilip Paeps 
660e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
661e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
662e948693eSPhilip Paeps 
663e948693eSPhilip Paeps 	EFSYS_ASSERT(emop != NULL);
664e948693eSPhilip Paeps 
665e948693eSPhilip Paeps 	if (emop->emo_stats_periodic == NULL) {
666e948693eSPhilip Paeps 		rc = EINVAL;
667e948693eSPhilip Paeps 		goto fail1;
668e948693eSPhilip Paeps 	}
669e948693eSPhilip Paeps 
670e948693eSPhilip Paeps 	if ((rc = emop->emo_stats_periodic(enp, esmp, period_ms, events)) != 0)
671e948693eSPhilip Paeps 		goto fail2;
672e948693eSPhilip Paeps 
673e948693eSPhilip Paeps 	return (0);
674e948693eSPhilip Paeps 
675e948693eSPhilip Paeps fail2:
676e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
677e948693eSPhilip Paeps fail1:
678460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
679e948693eSPhilip Paeps 
680e948693eSPhilip Paeps 	return (rc);
681e948693eSPhilip Paeps }
682e948693eSPhilip Paeps 
683e948693eSPhilip Paeps 
684460cb568SAndrew Rybchenko 	__checkReturn			efx_rc_t
685e948693eSPhilip Paeps efx_mac_stats_update(
686e948693eSPhilip Paeps 	__in				efx_nic_t *enp,
687e948693eSPhilip Paeps 	__in				efsys_mem_t *esmp,
688e948693eSPhilip Paeps 	__inout_ecount(EFX_MAC_NSTATS)	efsys_stat_t *essp,
68914c3e490SAndrew Rybchenko 	__inout_opt			uint32_t *generationp)
690e948693eSPhilip Paeps {
691e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
692ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
693460cb568SAndrew Rybchenko 	efx_rc_t rc;
694e948693eSPhilip Paeps 
695e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
696e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
697e948693eSPhilip Paeps 	EFSYS_ASSERT(emop != NULL);
698e948693eSPhilip Paeps 
699e948693eSPhilip Paeps 	rc = emop->emo_stats_update(enp, esmp, essp, generationp);
700e948693eSPhilip Paeps 	if (rc == 0)
701e948693eSPhilip Paeps 		epp->ep_mac_stats_pending = B_FALSE;
702e948693eSPhilip Paeps 
703e948693eSPhilip Paeps 	return (rc);
704e948693eSPhilip Paeps }
705e948693eSPhilip Paeps 
706e948693eSPhilip Paeps #endif	/* EFSYS_OPT_MAC_STATS */
707e948693eSPhilip Paeps 
708460cb568SAndrew Rybchenko 	__checkReturn			efx_rc_t
709e948693eSPhilip Paeps efx_mac_select(
710e948693eSPhilip Paeps 	__in				efx_nic_t *enp)
711e948693eSPhilip Paeps {
712e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
713e948693eSPhilip Paeps 	efx_mac_type_t type = EFX_MAC_INVALID;
714ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop;
715e948693eSPhilip Paeps 	int rc = EINVAL;
716e948693eSPhilip Paeps 
71795812f27SAndrew Rybchenko 	switch (enp->en_family) {
718c15d6d21SAndrew Rybchenko #if EFSYS_OPT_SIENA
71995812f27SAndrew Rybchenko 	case EFX_FAMILY_SIENA:
72095812f27SAndrew Rybchenko 		emop = &__efx_siena_mac_ops;
721c15d6d21SAndrew Rybchenko 		type = EFX_MAC_SIENA;
72295812f27SAndrew Rybchenko 		break;
72395812f27SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
724c15d6d21SAndrew Rybchenko 
7253c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
72695812f27SAndrew Rybchenko 	case EFX_FAMILY_HUNTINGTON:
72795812f27SAndrew Rybchenko 		emop = &__efx_ef10_mac_ops;
7283c838a9fSAndrew Rybchenko 		type = EFX_MAC_HUNTINGTON;
72995812f27SAndrew Rybchenko 		break;
73095812f27SAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */
7313c838a9fSAndrew Rybchenko 
732c15d6d21SAndrew Rybchenko #if EFSYS_OPT_MEDFORD
73395812f27SAndrew Rybchenko 	case EFX_FAMILY_MEDFORD:
73495812f27SAndrew Rybchenko 		emop = &__efx_ef10_mac_ops;
735c15d6d21SAndrew Rybchenko 		type = EFX_MAC_MEDFORD;
73695812f27SAndrew Rybchenko 		break;
73795812f27SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */
738e948693eSPhilip Paeps 
73995812f27SAndrew Rybchenko 	default:
74095812f27SAndrew Rybchenko 		rc = EINVAL;
74195812f27SAndrew Rybchenko 		goto fail1;
74295812f27SAndrew Rybchenko 	}
74395812f27SAndrew Rybchenko 
744e948693eSPhilip Paeps 	EFSYS_ASSERT(type != EFX_MAC_INVALID);
745e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_MAC_NTYPES);
746e948693eSPhilip Paeps 	EFSYS_ASSERT(emop != NULL);
747e948693eSPhilip Paeps 
74895812f27SAndrew Rybchenko 	epp->ep_emop = emop;
749e948693eSPhilip Paeps 	epp->ep_mac_type = type;
750e948693eSPhilip Paeps 
751e948693eSPhilip Paeps 	return (0);
752e948693eSPhilip Paeps 
753e948693eSPhilip Paeps fail1:
754460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
755e948693eSPhilip Paeps 
756e948693eSPhilip Paeps 	return (rc);
757e948693eSPhilip Paeps }
7583c838a9fSAndrew Rybchenko 
7593c838a9fSAndrew Rybchenko 
760e75412c9SAndrew Rybchenko #if EFSYS_OPT_SIENA
7613c838a9fSAndrew Rybchenko 
76274bb0ed8SAndrew Rybchenko #define	EFX_MAC_HASH_BITS	(1 << 8)
76374bb0ed8SAndrew Rybchenko 
7643c838a9fSAndrew Rybchenko /* Compute the multicast hash as used on Falcon and Siena. */
7653c838a9fSAndrew Rybchenko static	void
7665cab4fc7SAndrew Rybchenko siena_mac_multicast_hash_compute(
7673c838a9fSAndrew Rybchenko 	__in_ecount(6*count)		uint8_t const *addrs,
7683c838a9fSAndrew Rybchenko 	__in				int count,
7693c838a9fSAndrew Rybchenko 	__out				efx_oword_t *hash_low,
7703c838a9fSAndrew Rybchenko 	__out				efx_oword_t *hash_high)
7713c838a9fSAndrew Rybchenko {
7723c838a9fSAndrew Rybchenko 	uint32_t crc, index;
7733c838a9fSAndrew Rybchenko 	int i;
7743c838a9fSAndrew Rybchenko 
7753c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(hash_low != NULL);
7763c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(hash_high != NULL);
7773c838a9fSAndrew Rybchenko 
7783c838a9fSAndrew Rybchenko 	EFX_ZERO_OWORD(*hash_low);
7793c838a9fSAndrew Rybchenko 	EFX_ZERO_OWORD(*hash_high);
7803c838a9fSAndrew Rybchenko 
7813c838a9fSAndrew Rybchenko 	for (i = 0; i < count; i++) {
7823c838a9fSAndrew Rybchenko 		/* Calculate hash bucket (IEEE 802.3 CRC32 of the MAC addr) */
7833c838a9fSAndrew Rybchenko 		crc = efx_crc32_calculate(0xffffffff, addrs, EFX_MAC_ADDR_LEN);
7843c838a9fSAndrew Rybchenko 		index = crc % EFX_MAC_HASH_BITS;
7853c838a9fSAndrew Rybchenko 		if (index < 128) {
7863c838a9fSAndrew Rybchenko 			EFX_SET_OWORD_BIT(*hash_low, index);
7873c838a9fSAndrew Rybchenko 		} else {
7883c838a9fSAndrew Rybchenko 			EFX_SET_OWORD_BIT(*hash_high, index - 128);
7893c838a9fSAndrew Rybchenko 		}
7903c838a9fSAndrew Rybchenko 
7913c838a9fSAndrew Rybchenko 		addrs += EFX_MAC_ADDR_LEN;
7923c838a9fSAndrew Rybchenko 	}
7933c838a9fSAndrew Rybchenko }
7943c838a9fSAndrew Rybchenko 
795460cb568SAndrew Rybchenko static	__checkReturn	efx_rc_t
7965cab4fc7SAndrew Rybchenko siena_mac_multicast_list_set(
7973c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp)
7983c838a9fSAndrew Rybchenko {
7993c838a9fSAndrew Rybchenko 	efx_port_t *epp = &(enp->en_port);
800ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
8013c838a9fSAndrew Rybchenko 	efx_oword_t old_hash[2];
802460cb568SAndrew Rybchenko 	efx_rc_t rc;
8033c838a9fSAndrew Rybchenko 
8043c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
8053c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
8063c838a9fSAndrew Rybchenko 
8073c838a9fSAndrew Rybchenko 	memcpy(old_hash, epp->ep_multicst_hash, sizeof (old_hash));
8083c838a9fSAndrew Rybchenko 
8095cab4fc7SAndrew Rybchenko 	siena_mac_multicast_hash_compute(
8105cab4fc7SAndrew Rybchenko 	    epp->ep_mulcst_addr_list,
8113c838a9fSAndrew Rybchenko 	    epp->ep_mulcst_addr_count,
8123c838a9fSAndrew Rybchenko 	    &epp->ep_multicst_hash[0],
8133c838a9fSAndrew Rybchenko 	    &epp->ep_multicst_hash[1]);
8143c838a9fSAndrew Rybchenko 
8153c838a9fSAndrew Rybchenko 	if ((rc = emop->emo_reconfigure(enp)) != 0)
8163c838a9fSAndrew Rybchenko 		goto fail1;
8173c838a9fSAndrew Rybchenko 
8183c838a9fSAndrew Rybchenko 	return (0);
8193c838a9fSAndrew Rybchenko 
8203c838a9fSAndrew Rybchenko fail1:
821460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
8223c838a9fSAndrew Rybchenko 
8233c838a9fSAndrew Rybchenko 	memcpy(epp->ep_multicst_hash, old_hash, sizeof (old_hash));
8243c838a9fSAndrew Rybchenko 
8253c838a9fSAndrew Rybchenko 	return (rc);
8263c838a9fSAndrew Rybchenko }
8273c838a9fSAndrew Rybchenko 
828e75412c9SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
829