1227569Sphilip/*-
2227569Sphilip * Copyright 2007-2009 Solarflare Communications Inc.  All rights reserved.
3227569Sphilip *
4227569Sphilip * Redistribution and use in source and binary forms, with or without
5227569Sphilip * modification, are permitted provided that the following conditions
6227569Sphilip * are met:
7227569Sphilip * 1. Redistributions of source code must retain the above copyright
8227569Sphilip *    notice, this list of conditions and the following disclaimer.
9227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright
10227569Sphilip *    notice, this list of conditions and the following disclaimer in the
11227569Sphilip *    documentation and/or other materials provided with the distribution.
12227569Sphilip *
13227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16227569Sphilip * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23227569Sphilip * SUCH DAMAGE.
24227569Sphilip */
25227569Sphilip
26228100Sphilip#include <sys/cdefs.h>
27228100Sphilip__FBSDID("$FreeBSD$");
28228100Sphilip
29227569Sphilip#include "efsys.h"
30227569Sphilip#include "efx.h"
31227569Sphilip#include "efx_types.h"
32227569Sphilip#include "efx_impl.h"
33227569Sphilip
34227569Sphilip#if EFSYS_OPT_MAC_FALCON_GMAC
35227569Sphilip#include "falcon_gmac.h"
36227569Sphilip#endif
37227569Sphilip
38227569Sphilip#if EFSYS_OPT_MAC_FALCON_XMAC
39227569Sphilip#include "falcon_xmac.h"
40227569Sphilip#endif
41227569Sphilip
42227569Sphilip#if EFSYS_OPT_MAC_FALCON_GMAC
43227569Sphilipstatic efx_mac_ops_t	__cs __efx_falcon_gmac_ops = {
44227569Sphilip	falcon_gmac_reset,		/* emo_reset */
45227569Sphilip	falcon_mac_poll,		/* emo_poll */
46227569Sphilip	falcon_mac_up,			/* emo_up */
47227569Sphilip	falcon_gmac_reconfigure,	/* emo_reconfigure */
48227569Sphilip#if EFSYS_OPT_LOOPBACK
49227569Sphilip	falcon_mac_loopback_set,	/* emo_loopback_set */
50227569Sphilip#endif	/* EFSYS_OPT_LOOPBACK */
51227569Sphilip#if EFSYS_OPT_MAC_STATS
52227569Sphilip	falcon_mac_stats_upload,	/* emo_stats_upload */
53227569Sphilip	NULL,				/* emo_stats_periodic */
54227569Sphilip	falcon_gmac_stats_update	/* emo_stats_update */
55227569Sphilip#endif	/* EFSYS_OPT_MAC_STATS */
56227569Sphilip};
57227569Sphilip#endif	/* EFSYS_OPT_MAC_FALCON_GMAC */
58227569Sphilip
59227569Sphilip#if EFSYS_OPT_MAC_FALCON_XMAC
60227569Sphilipstatic efx_mac_ops_t	__cs __efx_falcon_xmac_ops = {
61227569Sphilip	falcon_xmac_reset,		/* emo_reset */
62227569Sphilip	falcon_mac_poll,		/* emo_poll */
63227569Sphilip	falcon_mac_up,			/* emo_up */
64227569Sphilip	falcon_xmac_reconfigure,	/* emo_reconfigure */
65227569Sphilip#if EFSYS_OPT_LOOPBACK
66227569Sphilip	falcon_mac_loopback_set,	/* emo_loopback_set */
67227569Sphilip#endif	/* EFSYS_OPT_LOOPBACK */
68227569Sphilip#if EFSYS_OPT_MAC_STATS
69227569Sphilip	falcon_mac_stats_upload,	/* emo_stats_upload */
70227569Sphilip	NULL,				/* emo_stats_periodic */
71227569Sphilip	falcon_xmac_stats_update	/* emo_stats_update */
72227569Sphilip#endif	/* EFSYS_OPT_MAC_STATS */
73227569Sphilip};
74227569Sphilip#endif	/* EFSYS_OPT_MAC_FALCON_XMAC */
75227569Sphilip
76227569Sphilip#if EFSYS_OPT_SIENA
77227569Sphilipstatic efx_mac_ops_t	__cs __efx_siena_mac_ops = {
78227569Sphilip	NULL,				/* emo_reset */
79227569Sphilip	siena_mac_poll,			/* emo_poll */
80227569Sphilip	siena_mac_up,			/* emo_up */
81227569Sphilip	siena_mac_reconfigure,		/* emo_reconfigure */
82227569Sphilip#if EFSYS_OPT_LOOPBACK
83227569Sphilip	siena_mac_loopback_set,		/* emo_loopback_set */
84227569Sphilip#endif	/* EFSYS_OPT_LOOPBACK */
85227569Sphilip#if EFSYS_OPT_MAC_STATS
86227569Sphilip	siena_mac_stats_upload,		/* emo_stats_upload */
87227569Sphilip	siena_mac_stats_periodic,	/* emo_stats_periodic */
88227569Sphilip	siena_mac_stats_update		/* emo_stats_update */
89227569Sphilip#endif	/* EFSYS_OPT_MAC_STATS */
90227569Sphilip};
91227569Sphilip#endif	/* EFSYS_OPT_SIENA */
92227569Sphilip
93227569Sphilipstatic efx_mac_ops_t	__cs * __cs __efx_mac_ops[] = {
94227569Sphilip	NULL,
95227569Sphilip#if EFSYS_OPT_MAC_FALCON_GMAC
96227569Sphilip	&__efx_falcon_gmac_ops,
97227569Sphilip#else
98227569Sphilip	NULL,
99227569Sphilip#endif	/* EFSYS_OPT_MAC_FALCON_GMAC */
100227569Sphilip#if EFSYS_OPT_MAC_FALCON_XMAC
101227569Sphilip	&__efx_falcon_xmac_ops,
102227569Sphilip#else
103227569Sphilip	NULL,
104227569Sphilip#endif	/* EFSYS_OPT_MAC_FALCON_XMAC */
105227569Sphilip#if EFSYS_OPT_SIENA
106227569Sphilip	&__efx_siena_mac_ops,
107227569Sphilip#else
108227569Sphilip	NULL,
109227569Sphilip#endif	/* EFSYS_OPT_SIENA */
110227569Sphilip};
111227569Sphilip
112227569Sphilip	__checkReturn			int
113227569Sphilipefx_mac_pdu_set(
114227569Sphilip	__in				efx_nic_t *enp,
115227569Sphilip	__in				size_t pdu)
116227569Sphilip{
117227569Sphilip	efx_port_t *epp = &(enp->en_port);
118227569Sphilip	efx_mac_ops_t *emop = epp->ep_emop;
119227569Sphilip	uint32_t old_pdu;
120227569Sphilip	int rc;
121227569Sphilip
122227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
123227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
124227569Sphilip	EFSYS_ASSERT(emop != NULL);
125227569Sphilip
126227569Sphilip	if (pdu < EFX_MAC_PDU_MIN) {
127227569Sphilip		rc = EINVAL;
128227569Sphilip		goto fail1;
129227569Sphilip	}
130227569Sphilip
131227569Sphilip	if (pdu > EFX_MAC_PDU_MAX) {
132227569Sphilip		rc = EINVAL;
133227569Sphilip		goto fail2;
134227569Sphilip	}
135227569Sphilip
136227569Sphilip	old_pdu = epp->ep_mac_pdu;
137227569Sphilip	epp->ep_mac_pdu = (uint32_t)pdu;
138227569Sphilip	if ((rc = emop->emo_reconfigure(enp)) != 0)
139227569Sphilip		goto fail3;
140227569Sphilip
141227569Sphilip	return (0);
142227569Sphilip
143227569Sphilipfail3:
144227569Sphilip	EFSYS_PROBE(fail3);
145227569Sphilip
146227569Sphilip	epp->ep_mac_pdu = old_pdu;
147227569Sphilip
148227569Sphilipfail2:
149227569Sphilip	EFSYS_PROBE(fail2);
150227569Sphilipfail1:
151227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
152227569Sphilip
153227569Sphilip	return (rc);
154227569Sphilip}
155227569Sphilip
156227569Sphilip	__checkReturn			int
157227569Sphilipefx_mac_addr_set(
158227569Sphilip	__in				efx_nic_t *enp,
159227569Sphilip	__in				uint8_t *addr)
160227569Sphilip{
161227569Sphilip	efx_port_t *epp = &(enp->en_port);
162227569Sphilip	efx_mac_ops_t *emop = epp->ep_emop;
163227569Sphilip	uint8_t old_addr[6];
164227569Sphilip	uint32_t oui;
165227569Sphilip	int rc;
166227569Sphilip
167227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
168227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
169227569Sphilip
170227569Sphilip	if (addr[0] & 0x01) {
171227569Sphilip		rc = EINVAL;
172227569Sphilip		goto fail1;
173227569Sphilip	}
174227569Sphilip
175227569Sphilip	oui = addr[0] << 16 | addr[1] << 8 | addr[2];
176227569Sphilip	if (oui == 0x000000) {
177227569Sphilip		rc = EINVAL;
178227569Sphilip		goto fail2;
179227569Sphilip	}
180227569Sphilip
181227569Sphilip	EFX_MAC_ADDR_COPY(old_addr, epp->ep_mac_addr);
182227569Sphilip	EFX_MAC_ADDR_COPY(epp->ep_mac_addr, addr);
183227569Sphilip	if ((rc = emop->emo_reconfigure(enp)) != 0)
184227569Sphilip		goto fail3;
185227569Sphilip
186227569Sphilip	return (0);
187227569Sphilip
188227569Sphilipfail3:
189227569Sphilip	EFSYS_PROBE(fail3);
190227569Sphilip
191227569Sphilip	EFX_MAC_ADDR_COPY(epp->ep_mac_addr, old_addr);
192227569Sphilip
193227569Sphilipfail2:
194227569Sphilip	EFSYS_PROBE(fail2);
195227569Sphilipfail1:
196227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
197227569Sphilip
198227569Sphilip	return (rc);
199227569Sphilip}
200227569Sphilip
201227569Sphilip	__checkReturn			int
202227569Sphilipefx_mac_filter_set(
203227569Sphilip	__in				efx_nic_t *enp,
204227569Sphilip	__in				boolean_t unicst,
205227569Sphilip	__in				boolean_t brdcst)
206227569Sphilip{
207227569Sphilip	efx_port_t *epp = &(enp->en_port);
208227569Sphilip	efx_mac_ops_t *emop = epp->ep_emop;
209227569Sphilip	boolean_t old_unicst;
210227569Sphilip	boolean_t old_brdcst;
211227569Sphilip	int rc;
212227569Sphilip
213227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
214227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
215227569Sphilip
216227569Sphilip	old_unicst = unicst;
217227569Sphilip	old_brdcst = brdcst;
218227569Sphilip
219227569Sphilip	epp->ep_unicst = unicst;
220227569Sphilip	epp->ep_brdcst = brdcst;
221227569Sphilip
222227569Sphilip	if ((rc = emop->emo_reconfigure(enp)) != 0)
223227569Sphilip		goto fail1;
224227569Sphilip
225227569Sphilip	return (0);
226227569Sphilip
227227569Sphilipfail1:
228227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
229227569Sphilip
230227569Sphilip	epp->ep_unicst = old_unicst;
231227569Sphilip	epp->ep_brdcst = old_brdcst;
232227569Sphilip
233227569Sphilip	return (rc);
234227569Sphilip}
235227569Sphilip
236227569Sphilip	__checkReturn			int
237227569Sphilipefx_mac_drain(
238227569Sphilip	__in				efx_nic_t *enp,
239227569Sphilip	__in				boolean_t enabled)
240227569Sphilip{
241227569Sphilip	efx_port_t *epp = &(enp->en_port);
242227569Sphilip	efx_mac_ops_t *emop = epp->ep_emop;
243227569Sphilip	int rc;
244227569Sphilip
245227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
246227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
247227569Sphilip	EFSYS_ASSERT(emop != NULL);
248227569Sphilip
249227569Sphilip	if (epp->ep_mac_drain == enabled)
250227569Sphilip		return (0);
251227569Sphilip
252227569Sphilip	epp->ep_mac_drain = enabled;
253227569Sphilip
254227569Sphilip	if (enabled && emop->emo_reset != NULL) {
255227569Sphilip		if ((rc = emop->emo_reset(enp)) != 0)
256227569Sphilip			goto fail1;
257227569Sphilip
258227569Sphilip		EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_MAC);
259227569Sphilip		enp->en_reset_flags &= ~EFX_RESET_PHY;
260227569Sphilip	}
261227569Sphilip
262227569Sphilip	if ((rc = emop->emo_reconfigure(enp)) != 0)
263227569Sphilip		goto fail2;
264227569Sphilip
265227569Sphilip	return (0);
266227569Sphilip
267227569Sphilipfail2:
268227569Sphilip	EFSYS_PROBE(fail2);
269227569Sphilipfail1:
270227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
271227569Sphilip
272227569Sphilip	return (rc);
273227569Sphilip}
274227569Sphilip
275227569Sphilip	__checkReturn	int
276227569Sphilipefx_mac_up(
277227569Sphilip	__in		efx_nic_t *enp,
278227569Sphilip	__out		boolean_t *mac_upp)
279227569Sphilip{
280227569Sphilip	efx_port_t *epp = &(enp->en_port);
281227569Sphilip	efx_mac_ops_t *emop = epp->ep_emop;
282227569Sphilip	int rc;
283227569Sphilip
284227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
285227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
286227569Sphilip
287227569Sphilip	if ((rc = emop->emo_up(enp, mac_upp)) != 0)
288227569Sphilip		goto fail1;
289227569Sphilip
290227569Sphilip	return (0);
291227569Sphilip
292227569Sphilipfail1:
293227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
294227569Sphilip
295227569Sphilip	return (rc);
296227569Sphilip}
297227569Sphilip
298227569Sphilip	__checkReturn			int
299227569Sphilipefx_mac_fcntl_set(
300227569Sphilip	__in				efx_nic_t *enp,
301227569Sphilip	__in				unsigned int fcntl,
302227569Sphilip	__in				boolean_t autoneg)
303227569Sphilip{
304227569Sphilip	efx_port_t *epp = &(enp->en_port);
305227569Sphilip	efx_mac_ops_t *emop = epp->ep_emop;
306227569Sphilip	efx_phy_ops_t *epop = epp->ep_epop;
307227569Sphilip	unsigned int old_fcntl;
308227569Sphilip	boolean_t old_autoneg;
309227569Sphilip	unsigned int old_adv_cap;
310227569Sphilip	int rc;
311227569Sphilip
312227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
313227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
314227569Sphilip
315227569Sphilip	if ((fcntl & ~(EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE)) != 0) {
316227569Sphilip		rc = EINVAL;
317227569Sphilip		goto fail1;
318227569Sphilip	}
319227569Sphilip
320227569Sphilip	/*
321227569Sphilip	 * Ignore a request to set flow control autonegotiation
322227569Sphilip	 * if the PHY doesn't support it.
323227569Sphilip	 */
324227569Sphilip	if (~epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
325227569Sphilip		autoneg = B_FALSE;
326227569Sphilip
327227569Sphilip	old_fcntl = epp->ep_fcntl;
328227569Sphilip	old_autoneg = autoneg;
329227569Sphilip	old_adv_cap = epp->ep_adv_cap_mask;
330227569Sphilip
331227569Sphilip	epp->ep_fcntl = fcntl;
332227569Sphilip	epp->ep_fcntl_autoneg = autoneg;
333227569Sphilip
334227569Sphilip	/*
335227569Sphilip	 * If the PHY supports autonegotiation, then encode the flow control
336227569Sphilip	 * settings in the advertised capabilities, and restart AN. Otherwise,
337227569Sphilip	 * just push the new settings directly to the MAC.
338227569Sphilip	 */
339227569Sphilip	if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN)) {
340227569Sphilip		if (fcntl & EFX_FCNTL_RESPOND)
341227569Sphilip			epp->ep_adv_cap_mask |=    (1 << EFX_PHY_CAP_PAUSE |
342227569Sphilip						    1 << EFX_PHY_CAP_ASYM);
343227569Sphilip		else
344227569Sphilip			epp->ep_adv_cap_mask &=   ~(1 << EFX_PHY_CAP_PAUSE |
345227569Sphilip						    1 << EFX_PHY_CAP_ASYM);
346227569Sphilip
347227569Sphilip		if (fcntl & EFX_FCNTL_GENERATE)
348227569Sphilip			epp->ep_adv_cap_mask ^= (1 << EFX_PHY_CAP_ASYM);
349227569Sphilip
350227569Sphilip		if ((rc = epop->epo_reconfigure(enp)) != 0)
351227569Sphilip			goto fail2;
352227569Sphilip
353227569Sphilip	} else {
354227569Sphilip		if ((rc = emop->emo_reconfigure(enp)) != 0)
355227569Sphilip			goto fail2;
356227569Sphilip	}
357227569Sphilip
358227569Sphilip	return (0);
359227569Sphilip
360227569Sphilipfail2:
361227569Sphilip	EFSYS_PROBE(fail2);
362227569Sphilip
363227569Sphilip	epp->ep_fcntl = old_fcntl;
364227569Sphilip	epp->ep_fcntl_autoneg = old_autoneg;
365227569Sphilip	epp->ep_adv_cap_mask = old_adv_cap;
366227569Sphilip
367227569Sphilipfail1:
368227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
369227569Sphilip
370227569Sphilip	return (rc);
371227569Sphilip}
372227569Sphilip
373227569Sphilip			void
374227569Sphilipefx_mac_fcntl_get(
375227569Sphilip	__in		efx_nic_t *enp,
376227569Sphilip	__out		unsigned int *fcntl_wantedp,
377227569Sphilip	__out		unsigned int *fcntl_linkp)
378227569Sphilip{
379227569Sphilip	efx_port_t *epp = &(enp->en_port);
380227569Sphilip	unsigned int wanted;
381227569Sphilip
382227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
383227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
384227569Sphilip
385227569Sphilip	/*
386227569Sphilip	 * If the PHY supports auto negotiation, then the requested flow
387227569Sphilip	 * control settings are encoded in the advertised capabilities.
388227569Sphilip	 */
389227569Sphilip	if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN)) {
390227569Sphilip		wanted = 0;
391227569Sphilip
392227569Sphilip		if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_PAUSE))
393227569Sphilip			wanted = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
394227569Sphilip		if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_ASYM))
395227569Sphilip			wanted ^= EFX_FCNTL_GENERATE;
396227569Sphilip	} else
397227569Sphilip		wanted = epp->ep_fcntl;
398227569Sphilip
399227569Sphilip	*fcntl_linkp = epp->ep_fcntl;
400227569Sphilip	*fcntl_wantedp = wanted;
401227569Sphilip}
402227569Sphilip
403227569Sphilip	__checkReturn			int
404227569Sphilipefx_mac_hash_set(
405227569Sphilip	__in				efx_nic_t *enp,
406227569Sphilip	__in_ecount(EFX_MAC_HASH_BITS)	unsigned int const *bucket)
407227569Sphilip{
408227569Sphilip	efx_port_t *epp = &(enp->en_port);
409227569Sphilip	efx_mac_ops_t *emop = epp->ep_emop;
410227569Sphilip	efx_oword_t old_hash[2];
411227569Sphilip	unsigned int index;
412227569Sphilip	int rc;
413227569Sphilip
414227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
415227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
416227569Sphilip
417227569Sphilip	memcpy(old_hash, epp->ep_multicst_hash, sizeof (old_hash));
418227569Sphilip
419227569Sphilip	/* Set the lower 128 bits of the hash */
420227569Sphilip	EFX_ZERO_OWORD(epp->ep_multicst_hash[0]);
421227569Sphilip	for (index = 0; index < 128; index++) {
422227569Sphilip		if (bucket[index] != 0)
423227569Sphilip			EFX_SET_OWORD_BIT(epp->ep_multicst_hash[0], index);
424227569Sphilip	}
425227569Sphilip
426227569Sphilip	/* Set the upper 128 bits of the hash */
427227569Sphilip	EFX_ZERO_OWORD(epp->ep_multicst_hash[1]);
428227569Sphilip	for (index = 0; index < 128; index++) {
429227569Sphilip		if (bucket[index + 128] != 0)
430227569Sphilip			EFX_SET_OWORD_BIT(epp->ep_multicst_hash[1], index);
431227569Sphilip	}
432227569Sphilip
433227569Sphilip	if ((rc = emop->emo_reconfigure(enp)) != 0)
434227569Sphilip		goto fail1;
435227569Sphilip
436227569Sphilip	return (0);
437227569Sphilip
438227569Sphilipfail1:
439227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
440227569Sphilip
441227569Sphilip	memcpy(epp->ep_multicst_hash, old_hash, sizeof (old_hash));
442227569Sphilip
443227569Sphilip	return (rc);
444227569Sphilip}
445227569Sphilip
446227569Sphilip#if EFSYS_OPT_MAC_STATS
447227569Sphilip
448227569Sphilip#if EFSYS_OPT_NAMES
449227569Sphilip
450227569Sphilip/* START MKCONFIG GENERATED EfxMacStatNamesBlock adf707adba80813e */
451227569Sphilipstatic const char 	__cs * __cs __efx_mac_stat_name[] = {
452227569Sphilip	"rx_octets",
453227569Sphilip	"rx_pkts",
454227569Sphilip	"rx_unicst_pkts",
455227569Sphilip	"rx_multicst_pkts",
456227569Sphilip	"rx_brdcst_pkts",
457227569Sphilip	"rx_pause_pkts",
458227569Sphilip	"rx_le_64_pkts",
459227569Sphilip	"rx_65_to_127_pkts",
460227569Sphilip	"rx_128_to_255_pkts",
461227569Sphilip	"rx_256_to_511_pkts",
462227569Sphilip	"rx_512_to_1023_pkts",
463227569Sphilip	"rx_1024_to_15xx_pkts",
464227569Sphilip	"rx_ge_15xx_pkts",
465227569Sphilip	"rx_errors",
466227569Sphilip	"rx_fcs_errors",
467227569Sphilip	"rx_drop_events",
468227569Sphilip	"rx_false_carrier_errors",
469227569Sphilip	"rx_symbol_errors",
470227569Sphilip	"rx_align_errors",
471227569Sphilip	"rx_internal_errors",
472227569Sphilip	"rx_jabber_pkts",
473227569Sphilip	"rx_lane0_char_err",
474227569Sphilip	"rx_lane1_char_err",
475227569Sphilip	"rx_lane2_char_err",
476227569Sphilip	"rx_lane3_char_err",
477227569Sphilip	"rx_lane0_disp_err",
478227569Sphilip	"rx_lane1_disp_err",
479227569Sphilip	"rx_lane2_disp_err",
480227569Sphilip	"rx_lane3_disp_err",
481227569Sphilip	"rx_match_fault",
482227569Sphilip	"rx_nodesc_drop_cnt",
483227569Sphilip	"tx_octets",
484227569Sphilip	"tx_pkts",
485227569Sphilip	"tx_unicst_pkts",
486227569Sphilip	"tx_multicst_pkts",
487227569Sphilip	"tx_brdcst_pkts",
488227569Sphilip	"tx_pause_pkts",
489227569Sphilip	"tx_le_64_pkts",
490227569Sphilip	"tx_65_to_127_pkts",
491227569Sphilip	"tx_128_to_255_pkts",
492227569Sphilip	"tx_256_to_511_pkts",
493227569Sphilip	"tx_512_to_1023_pkts",
494227569Sphilip	"tx_1024_to_15xx_pkts",
495227569Sphilip	"tx_ge_15xx_pkts",
496227569Sphilip	"tx_errors",
497227569Sphilip	"tx_sgl_col_pkts",
498227569Sphilip	"tx_mult_col_pkts",
499227569Sphilip	"tx_ex_col_pkts",
500227569Sphilip	"tx_late_col_pkts",
501227569Sphilip	"tx_def_pkts",
502227569Sphilip	"tx_ex_def_pkts",
503227569Sphilip};
504227569Sphilip/* END MKCONFIG GENERATED EfxMacStatNamesBlock */
505227569Sphilip
506227569Sphilip	__checkReturn			const char __cs *
507227569Sphilipefx_mac_stat_name(
508227569Sphilip	__in				efx_nic_t *enp,
509227569Sphilip	__in				unsigned int id)
510227569Sphilip{
511227569Sphilip	_NOTE(ARGUNUSED(enp))
512227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
513227569Sphilip
514227569Sphilip	EFSYS_ASSERT3U(id, <, EFX_MAC_NSTATS);
515227569Sphilip	return (__efx_mac_stat_name[id]);
516227569Sphilip}
517227569Sphilip
518227569Sphilip#endif	/* EFSYS_OPT_STAT_NAME */
519227569Sphilip
520227569Sphilip	__checkReturn			int
521227569Sphilipefx_mac_stats_upload(
522227569Sphilip	__in				efx_nic_t *enp,
523227569Sphilip	__in				efsys_mem_t *esmp)
524227569Sphilip{
525227569Sphilip	efx_port_t *epp = &(enp->en_port);
526227569Sphilip	efx_mac_ops_t *emop = epp->ep_emop;
527227569Sphilip	int rc;
528227569Sphilip
529227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
530227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
531227569Sphilip	EFSYS_ASSERT(emop != NULL);
532227569Sphilip
533227569Sphilip	/*
534227569Sphilip	 * Don't assert !ep_mac_stats_pending, because the client might
535227569Sphilip	 * have failed to finalise statistics when previously stopping
536227569Sphilip	 * the port.
537227569Sphilip	 */
538227569Sphilip	if ((rc = emop->emo_stats_upload(enp, esmp)) != 0)
539227569Sphilip		goto fail1;
540227569Sphilip
541227569Sphilip	epp->ep_mac_stats_pending = B_TRUE;
542227569Sphilip
543227569Sphilip	return (0);
544227569Sphilip
545227569Sphilipfail1:
546227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
547227569Sphilip
548227569Sphilip	return (rc);
549227569Sphilip}
550227569Sphilip
551227569Sphilip	__checkReturn			int
552227569Sphilipefx_mac_stats_periodic(
553227569Sphilip	__in				efx_nic_t *enp,
554227569Sphilip	__in				efsys_mem_t *esmp,
555227569Sphilip	__in				uint16_t period_ms,
556227569Sphilip	__in				boolean_t events)
557227569Sphilip{
558227569Sphilip	efx_port_t *epp = &(enp->en_port);
559227569Sphilip	efx_mac_ops_t *emop = epp->ep_emop;
560227569Sphilip	int rc;
561227569Sphilip
562227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
563227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
564227569Sphilip
565227569Sphilip	EFSYS_ASSERT(emop != NULL);
566227569Sphilip
567227569Sphilip	if (emop->emo_stats_periodic == NULL) {
568227569Sphilip		rc = EINVAL;
569227569Sphilip		goto fail1;
570227569Sphilip	}
571227569Sphilip
572227569Sphilip	if ((rc = emop->emo_stats_periodic(enp, esmp, period_ms, events)) != 0)
573227569Sphilip		goto fail2;
574227569Sphilip
575227569Sphilip	return (0);
576227569Sphilip
577227569Sphilipfail2:
578227569Sphilip	EFSYS_PROBE(fail2);
579227569Sphilipfail1:
580227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
581227569Sphilip
582227569Sphilip	return (rc);
583227569Sphilip}
584227569Sphilip
585227569Sphilip
586227569Sphilip	__checkReturn			int
587227569Sphilipefx_mac_stats_update(
588227569Sphilip	__in				efx_nic_t *enp,
589227569Sphilip	__in				efsys_mem_t *esmp,
590227569Sphilip	__inout_ecount(EFX_MAC_NSTATS)	efsys_stat_t *essp,
591227569Sphilip	__in				uint32_t *generationp)
592227569Sphilip{
593227569Sphilip	efx_port_t *epp = &(enp->en_port);
594227569Sphilip	efx_mac_ops_t *emop = epp->ep_emop;
595227569Sphilip	int rc;
596227569Sphilip
597227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
598227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
599227569Sphilip	EFSYS_ASSERT(emop != NULL);
600227569Sphilip
601227569Sphilip	rc = emop->emo_stats_update(enp, esmp, essp, generationp);
602227569Sphilip	if (rc == 0)
603227569Sphilip		epp->ep_mac_stats_pending = B_FALSE;
604227569Sphilip
605227569Sphilip	return (rc);
606227569Sphilip}
607227569Sphilip
608227569Sphilip#endif	/* EFSYS_OPT_MAC_STATS */
609227569Sphilip
610227569Sphilip	__checkReturn			int
611227569Sphilipefx_mac_select(
612227569Sphilip	__in				efx_nic_t *enp)
613227569Sphilip{
614227569Sphilip	efx_port_t *epp = &(enp->en_port);
615227569Sphilip	efx_mac_type_t type = EFX_MAC_INVALID;
616227569Sphilip	efx_mac_ops_t *emop;
617227569Sphilip	int rc = EINVAL;
618227569Sphilip
619227569Sphilip#if EFSYS_OPT_SIENA
620227569Sphilip	if (enp->en_family == EFX_FAMILY_SIENA) {
621227569Sphilip		type = EFX_MAC_SIENA;
622227569Sphilip		goto chosen;
623227569Sphilip	}
624227569Sphilip#endif
625227569Sphilip
626227569Sphilip#if EFSYS_OPT_FALCON
627227569Sphilip	switch (epp->ep_link_mode) {
628227569Sphilip#if EFSYS_OPT_MAC_FALCON_GMAC
629227569Sphilip	case EFX_LINK_100HDX:
630227569Sphilip	case EFX_LINK_100FDX:
631227569Sphilip	case EFX_LINK_1000HDX:
632227569Sphilip	case EFX_LINK_1000FDX:
633227569Sphilip		type = EFX_MAC_FALCON_GMAC;
634227569Sphilip		goto chosen;
635227569Sphilip#endif	/* EFSYS_OPT_FALCON_GMAC */
636227569Sphilip
637227569Sphilip#if EFSYS_OPT_MAC_FALCON_XMAC
638227569Sphilip	case EFX_LINK_10000FDX:
639227569Sphilip		type = EFX_MAC_FALCON_XMAC;
640227569Sphilip		goto chosen;
641227569Sphilip#endif	/* EFSYS_OPT_FALCON_XMAC */
642227569Sphilip
643227569Sphilip	default:
644227569Sphilip#if EFSYS_OPT_MAC_FALCON_GMAC && EFSYS_OPT_MAC_FALCON_XMAC
645227569Sphilip		/* Only initialise a MAC supported by the PHY */
646227569Sphilip		if (epp->ep_phy_cap_mask &
647227569Sphilip		    ((1 << EFX_PHY_CAP_1000FDX) |
648227569Sphilip		    (1 << EFX_PHY_CAP_1000HDX) |
649227569Sphilip		    (1 << EFX_PHY_CAP_100FDX) |
650227569Sphilip		    (1 << EFX_PHY_CAP_100HDX) |
651227569Sphilip		    (1 << EFX_PHY_CAP_10FDX) |
652227569Sphilip		    (1 << EFX_PHY_CAP_10FDX)))
653227569Sphilip			type = EFX_MAC_FALCON_GMAC;
654227569Sphilip		else
655227569Sphilip			type = EFX_MAC_FALCON_XMAC;
656227569Sphilip#elif EFSYS_OPT_MAC_FALCON_GMAC
657227569Sphilip		type = EFX_MAC_FALCON_GMAC;
658227569Sphilip#else
659227569Sphilip		type = EFX_MAC_FALCON_XMAC;
660227569Sphilip#endif
661227569Sphilip		goto chosen;
662227569Sphilip	}
663227569Sphilip#endif	/* EFSYS_OPT_FALCON */
664227569Sphilip
665227569Sphilipchosen:
666227569Sphilip	EFSYS_ASSERT(type != EFX_MAC_INVALID);
667227569Sphilip	EFSYS_ASSERT3U(type, <, EFX_MAC_NTYPES);
668227569Sphilip	emop = epp->ep_emop = (efx_mac_ops_t *)__efx_mac_ops[type];
669227569Sphilip	EFSYS_ASSERT(emop != NULL);
670227569Sphilip
671227569Sphilip	epp->ep_mac_type = type;
672227569Sphilip
673227569Sphilip	if (emop->emo_reset != NULL) {
674227569Sphilip		if ((rc = emop->emo_reset(enp)) != 0)
675227569Sphilip			goto fail1;
676227569Sphilip
677227569Sphilip		EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_MAC);
678227569Sphilip		enp->en_reset_flags &= ~EFX_RESET_MAC;
679227569Sphilip	}
680227569Sphilip
681227569Sphilip	return (0);
682227569Sphilip
683227569Sphilipfail1:
684227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
685227569Sphilip
686227569Sphilip	return (rc);
687227569Sphilip}
688