efx_mac.c revision 302408
1/*-
2 * Copyright (c) 2007-2016 Solarflare Communications Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 *    this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 *    this list of conditions and the following disclaimer in the documentation
12 *    and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/11/sys/dev/sfxge/common/efx_mac.c 300607 2016-05-24 12:16:57Z arybchik $");
33
34#include "efx.h"
35#include "efx_impl.h"
36
37#if EFSYS_OPT_SIENA
38
39static	__checkReturn	efx_rc_t
40siena_mac_multicast_list_set(
41	__in		efx_nic_t *enp);
42
43#endif /* EFSYS_OPT_SIENA */
44
45#if EFSYS_OPT_SIENA
46static const efx_mac_ops_t	__efx_siena_mac_ops = {
47	siena_mac_poll,				/* emo_poll */
48	siena_mac_up,				/* emo_up */
49	siena_mac_reconfigure,			/* emo_addr_set */
50	siena_mac_reconfigure,			/* emo_pdu_set */
51	siena_mac_pdu_get,			/* emo_pdu_get */
52	siena_mac_reconfigure,			/* emo_reconfigure */
53	siena_mac_multicast_list_set,		/* emo_multicast_list_set */
54	NULL,					/* emo_filter_set_default_rxq */
55	NULL,				/* emo_filter_default_rxq_clear */
56#if EFSYS_OPT_LOOPBACK
57	siena_mac_loopback_set,			/* emo_loopback_set */
58#endif	/* EFSYS_OPT_LOOPBACK */
59#if EFSYS_OPT_MAC_STATS
60	efx_mcdi_mac_stats_upload,		/* emo_stats_upload */
61	efx_mcdi_mac_stats_periodic,		/* emo_stats_periodic */
62	siena_mac_stats_update			/* emo_stats_update */
63#endif	/* EFSYS_OPT_MAC_STATS */
64};
65#endif	/* EFSYS_OPT_SIENA */
66
67#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
68static const efx_mac_ops_t	__efx_ef10_mac_ops = {
69	ef10_mac_poll,				/* emo_poll */
70	ef10_mac_up,				/* emo_up */
71	ef10_mac_addr_set,			/* emo_addr_set */
72	ef10_mac_pdu_set,			/* emo_pdu_set */
73	ef10_mac_pdu_get,			/* emo_pdu_get */
74	ef10_mac_reconfigure,			/* emo_reconfigure */
75	ef10_mac_multicast_list_set,		/* emo_multicast_list_set */
76	ef10_mac_filter_default_rxq_set,	/* emo_filter_default_rxq_set */
77	ef10_mac_filter_default_rxq_clear,
78					/* emo_filter_default_rxq_clear */
79#if EFSYS_OPT_LOOPBACK
80	ef10_mac_loopback_set,			/* emo_loopback_set */
81#endif	/* EFSYS_OPT_LOOPBACK */
82#if EFSYS_OPT_MAC_STATS
83	efx_mcdi_mac_stats_upload,		/* emo_stats_upload */
84	efx_mcdi_mac_stats_periodic,		/* emo_stats_periodic */
85	ef10_mac_stats_update			/* emo_stats_update */
86#endif	/* EFSYS_OPT_MAC_STATS */
87};
88#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
89
90	__checkReturn			efx_rc_t
91efx_mac_pdu_set(
92	__in				efx_nic_t *enp,
93	__in				size_t pdu)
94{
95	efx_port_t *epp = &(enp->en_port);
96	const efx_mac_ops_t *emop = epp->ep_emop;
97	uint32_t old_pdu;
98	efx_rc_t rc;
99
100	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
101	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
102	EFSYS_ASSERT(emop != NULL);
103
104	if (pdu < EFX_MAC_PDU_MIN) {
105		rc = EINVAL;
106		goto fail1;
107	}
108
109	if (pdu > EFX_MAC_PDU_MAX) {
110		rc = EINVAL;
111		goto fail2;
112	}
113
114	old_pdu = epp->ep_mac_pdu;
115	epp->ep_mac_pdu = (uint32_t)pdu;
116	if ((rc = emop->emo_pdu_set(enp)) != 0)
117		goto fail3;
118
119	return (0);
120
121fail3:
122	EFSYS_PROBE(fail3);
123
124	epp->ep_mac_pdu = old_pdu;
125
126fail2:
127	EFSYS_PROBE(fail2);
128fail1:
129	EFSYS_PROBE1(fail1, efx_rc_t, rc);
130
131	return (rc);
132}
133
134	__checkReturn	efx_rc_t
135efx_mac_pdu_get(
136	__in		efx_nic_t *enp,
137	__out		size_t *pdu)
138{
139	efx_port_t *epp = &(enp->en_port);
140	const efx_mac_ops_t *emop = epp->ep_emop;
141	efx_rc_t rc;
142
143	if ((rc = emop->emo_pdu_get(enp, pdu)) != 0)
144		goto fail1;
145
146	return (0);
147
148fail1:
149	EFSYS_PROBE1(fail1, efx_rc_t, rc);
150
151	return (rc);
152}
153
154	__checkReturn			efx_rc_t
155efx_mac_addr_set(
156	__in				efx_nic_t *enp,
157	__in				uint8_t *addr)
158{
159	efx_port_t *epp = &(enp->en_port);
160	const efx_mac_ops_t *emop = epp->ep_emop;
161	uint8_t old_addr[6];
162	uint32_t oui;
163	efx_rc_t rc;
164
165	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
166	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
167
168	if (EFX_MAC_ADDR_IS_MULTICAST(addr)) {
169		rc = EINVAL;
170		goto fail1;
171	}
172
173	oui = addr[0] << 16 | addr[1] << 8 | addr[2];
174	if (oui == 0x000000) {
175		rc = EINVAL;
176		goto fail2;
177	}
178
179	EFX_MAC_ADDR_COPY(old_addr, epp->ep_mac_addr);
180	EFX_MAC_ADDR_COPY(epp->ep_mac_addr, addr);
181	if ((rc = emop->emo_addr_set(enp)) != 0)
182		goto fail3;
183
184	return (0);
185
186fail3:
187	EFSYS_PROBE(fail3);
188
189	EFX_MAC_ADDR_COPY(epp->ep_mac_addr, old_addr);
190
191fail2:
192	EFSYS_PROBE(fail2);
193fail1:
194	EFSYS_PROBE1(fail1, efx_rc_t, rc);
195
196	return (rc);
197}
198
199	__checkReturn			efx_rc_t
200efx_mac_filter_set(
201	__in				efx_nic_t *enp,
202	__in				boolean_t all_unicst,
203	__in				boolean_t mulcst,
204	__in				boolean_t all_mulcst,
205	__in				boolean_t brdcst)
206{
207	efx_port_t *epp = &(enp->en_port);
208	const efx_mac_ops_t *emop = epp->ep_emop;
209	boolean_t old_all_unicst;
210	boolean_t old_mulcst;
211	boolean_t old_all_mulcst;
212	boolean_t old_brdcst;
213	efx_rc_t rc;
214
215	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
216	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
217
218	old_all_unicst = epp->ep_all_unicst;
219	old_mulcst = epp->ep_mulcst;
220	old_all_mulcst = epp->ep_all_mulcst;
221	old_brdcst = epp->ep_brdcst;
222
223	epp->ep_all_unicst = all_unicst;
224	epp->ep_mulcst = mulcst;
225	epp->ep_all_mulcst = all_mulcst;
226	epp->ep_brdcst = brdcst;
227
228	if ((rc = emop->emo_reconfigure(enp)) != 0)
229		goto fail1;
230
231	return (0);
232
233fail1:
234	EFSYS_PROBE1(fail1, efx_rc_t, rc);
235
236	epp->ep_all_unicst = old_all_unicst;
237	epp->ep_mulcst = old_mulcst;
238	epp->ep_all_mulcst = old_all_mulcst;
239	epp->ep_brdcst = old_brdcst;
240
241	return (rc);
242}
243
244	__checkReturn			efx_rc_t
245efx_mac_drain(
246	__in				efx_nic_t *enp,
247	__in				boolean_t enabled)
248{
249	efx_port_t *epp = &(enp->en_port);
250	const efx_mac_ops_t *emop = epp->ep_emop;
251	efx_rc_t rc;
252
253	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
254	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
255	EFSYS_ASSERT(emop != NULL);
256
257	if (epp->ep_mac_drain == enabled)
258		return (0);
259
260	epp->ep_mac_drain = enabled;
261
262	if ((rc = emop->emo_reconfigure(enp)) != 0)
263		goto fail1;
264
265	return (0);
266
267fail1:
268	EFSYS_PROBE1(fail1, efx_rc_t, rc);
269
270	return (rc);
271}
272
273	__checkReturn	efx_rc_t
274efx_mac_up(
275	__in		efx_nic_t *enp,
276	__out		boolean_t *mac_upp)
277{
278	efx_port_t *epp = &(enp->en_port);
279	const efx_mac_ops_t *emop = epp->ep_emop;
280	efx_rc_t rc;
281
282	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
283	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
284
285	if ((rc = emop->emo_up(enp, mac_upp)) != 0)
286		goto fail1;
287
288	return (0);
289
290fail1:
291	EFSYS_PROBE1(fail1, efx_rc_t, rc);
292
293	return (rc);
294}
295
296	__checkReturn			efx_rc_t
297efx_mac_fcntl_set(
298	__in				efx_nic_t *enp,
299	__in				unsigned int fcntl,
300	__in				boolean_t autoneg)
301{
302	efx_port_t *epp = &(enp->en_port);
303	const efx_mac_ops_t *emop = epp->ep_emop;
304	const efx_phy_ops_t *epop = epp->ep_epop;
305	unsigned int old_fcntl;
306	boolean_t old_autoneg;
307	unsigned int old_adv_cap;
308	efx_rc_t rc;
309
310	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
311	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
312
313	if ((fcntl & ~(EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE)) != 0) {
314		rc = EINVAL;
315		goto fail1;
316	}
317
318	/*
319	 * Ignore a request to set flow control auto-negotiation
320	 * if the PHY doesn't support it.
321	 */
322	if (~epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
323		autoneg = B_FALSE;
324
325	old_fcntl = epp->ep_fcntl;
326	old_autoneg = epp->ep_fcntl_autoneg;
327	old_adv_cap = epp->ep_adv_cap_mask;
328
329	epp->ep_fcntl = fcntl;
330	epp->ep_fcntl_autoneg = autoneg;
331
332	/*
333	 * Always encode the flow control settings in the advertised
334	 * capabilities even if we are not trying to auto-negotiate
335	 * them and reconfigure both the PHY and the MAC.
336	 */
337	if (fcntl & EFX_FCNTL_RESPOND)
338		epp->ep_adv_cap_mask |=    (1 << EFX_PHY_CAP_PAUSE |
339					    1 << EFX_PHY_CAP_ASYM);
340	else
341		epp->ep_adv_cap_mask &=   ~(1 << EFX_PHY_CAP_PAUSE |
342					    1 << EFX_PHY_CAP_ASYM);
343
344	if (fcntl & EFX_FCNTL_GENERATE)
345		epp->ep_adv_cap_mask ^= (1 << EFX_PHY_CAP_ASYM);
346
347	if ((rc = epop->epo_reconfigure(enp)) != 0)
348		goto fail2;
349
350	if ((rc = emop->emo_reconfigure(enp)) != 0)
351		goto fail3;
352
353	return (0);
354
355fail3:
356	EFSYS_PROBE(fail3);
357
358fail2:
359	EFSYS_PROBE(fail2);
360
361	epp->ep_fcntl = old_fcntl;
362	epp->ep_fcntl_autoneg = old_autoneg;
363	epp->ep_adv_cap_mask = old_adv_cap;
364
365fail1:
366	EFSYS_PROBE1(fail1, efx_rc_t, rc);
367
368	return (rc);
369}
370
371			void
372efx_mac_fcntl_get(
373	__in		efx_nic_t *enp,
374	__out		unsigned int *fcntl_wantedp,
375	__out		unsigned int *fcntl_linkp)
376{
377	efx_port_t *epp = &(enp->en_port);
378	unsigned int wanted = 0;
379
380	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
381	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
382
383	/*
384	 * Decode the requested flow control settings from the PHY
385	 * advertised capabilities.
386	 */
387	if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_PAUSE))
388		wanted = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
389	if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_ASYM))
390		wanted ^= EFX_FCNTL_GENERATE;
391
392	*fcntl_linkp = epp->ep_fcntl;
393	*fcntl_wantedp = wanted;
394}
395
396	__checkReturn	efx_rc_t
397efx_mac_multicast_list_set(
398	__in				efx_nic_t *enp,
399	__in_ecount(6*count)		uint8_t const *addrs,
400	__in				int count)
401{
402	efx_port_t *epp = &(enp->en_port);
403	const efx_mac_ops_t *emop = epp->ep_emop;
404	uint8_t	*old_mulcst_addr_list = NULL;
405	uint32_t old_mulcst_addr_count;
406	efx_rc_t rc;
407
408	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
409	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
410
411	if (count > EFX_MAC_MULTICAST_LIST_MAX) {
412		rc = EINVAL;
413		goto fail1;
414	}
415
416	old_mulcst_addr_count = epp->ep_mulcst_addr_count;
417	if (old_mulcst_addr_count > 0) {
418		/* Allocate memory to store old list (instead of using stack) */
419		EFSYS_KMEM_ALLOC(enp->en_esip,
420				old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
421				old_mulcst_addr_list);
422		if (old_mulcst_addr_list == NULL) {
423			rc = ENOMEM;
424			goto fail2;
425		}
426
427		/* Save the old list in case we need to rollback */
428		memcpy(old_mulcst_addr_list, epp->ep_mulcst_addr_list,
429			old_mulcst_addr_count * EFX_MAC_ADDR_LEN);
430	}
431
432	/* Store the new list */
433	memcpy(epp->ep_mulcst_addr_list, addrs,
434		count * EFX_MAC_ADDR_LEN);
435	epp->ep_mulcst_addr_count = count;
436
437	if ((rc = emop->emo_multicast_list_set(enp)) != 0)
438		goto fail3;
439
440	if (old_mulcst_addr_count > 0) {
441		EFSYS_KMEM_FREE(enp->en_esip,
442				old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
443				old_mulcst_addr_list);
444	}
445
446	return (0);
447
448fail3:
449	EFSYS_PROBE(fail3);
450
451	/* Restore original list on failure */
452	epp->ep_mulcst_addr_count = old_mulcst_addr_count;
453	if (old_mulcst_addr_count > 0) {
454		memcpy(epp->ep_mulcst_addr_list, old_mulcst_addr_list,
455			old_mulcst_addr_count * EFX_MAC_ADDR_LEN);
456
457		EFSYS_KMEM_FREE(enp->en_esip,
458				old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
459				old_mulcst_addr_list);
460	}
461
462fail2:
463	EFSYS_PROBE(fail2);
464
465fail1:
466	EFSYS_PROBE1(fail1, efx_rc_t, rc);
467
468	return (rc);
469
470}
471
472	__checkReturn	efx_rc_t
473efx_mac_filter_default_rxq_set(
474	__in		efx_nic_t *enp,
475	__in		efx_rxq_t *erp,
476	__in		boolean_t using_rss)
477{
478	efx_port_t *epp = &(enp->en_port);
479	const efx_mac_ops_t *emop = epp->ep_emop;
480	efx_rc_t rc;
481
482	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
483	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
484
485	if (emop->emo_filter_default_rxq_set != NULL) {
486		rc = emop->emo_filter_default_rxq_set(enp, erp, using_rss);
487		if (rc != 0)
488			goto fail1;
489	}
490
491	return (0);
492
493fail1:
494	EFSYS_PROBE1(fail1, efx_rc_t, rc);
495
496	return (rc);
497}
498
499			void
500efx_mac_filter_default_rxq_clear(
501	__in		efx_nic_t *enp)
502{
503	efx_port_t *epp = &(enp->en_port);
504	const efx_mac_ops_t *emop = epp->ep_emop;
505
506	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
507	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
508
509	if (emop->emo_filter_default_rxq_clear != NULL)
510		emop->emo_filter_default_rxq_clear(enp);
511}
512
513
514#if EFSYS_OPT_MAC_STATS
515
516#if EFSYS_OPT_NAMES
517
518/* START MKCONFIG GENERATED EfxMacStatNamesBlock 054d43a31d2d7a45 */
519static const char 	*__efx_mac_stat_name[] = {
520	"rx_octets",
521	"rx_pkts",
522	"rx_unicst_pkts",
523	"rx_multicst_pkts",
524	"rx_brdcst_pkts",
525	"rx_pause_pkts",
526	"rx_le_64_pkts",
527	"rx_65_to_127_pkts",
528	"rx_128_to_255_pkts",
529	"rx_256_to_511_pkts",
530	"rx_512_to_1023_pkts",
531	"rx_1024_to_15xx_pkts",
532	"rx_ge_15xx_pkts",
533	"rx_errors",
534	"rx_fcs_errors",
535	"rx_drop_events",
536	"rx_false_carrier_errors",
537	"rx_symbol_errors",
538	"rx_align_errors",
539	"rx_internal_errors",
540	"rx_jabber_pkts",
541	"rx_lane0_char_err",
542	"rx_lane1_char_err",
543	"rx_lane2_char_err",
544	"rx_lane3_char_err",
545	"rx_lane0_disp_err",
546	"rx_lane1_disp_err",
547	"rx_lane2_disp_err",
548	"rx_lane3_disp_err",
549	"rx_match_fault",
550	"rx_nodesc_drop_cnt",
551	"tx_octets",
552	"tx_pkts",
553	"tx_unicst_pkts",
554	"tx_multicst_pkts",
555	"tx_brdcst_pkts",
556	"tx_pause_pkts",
557	"tx_le_64_pkts",
558	"tx_65_to_127_pkts",
559	"tx_128_to_255_pkts",
560	"tx_256_to_511_pkts",
561	"tx_512_to_1023_pkts",
562	"tx_1024_to_15xx_pkts",
563	"tx_ge_15xx_pkts",
564	"tx_errors",
565	"tx_sgl_col_pkts",
566	"tx_mult_col_pkts",
567	"tx_ex_col_pkts",
568	"tx_late_col_pkts",
569	"tx_def_pkts",
570	"tx_ex_def_pkts",
571	"pm_trunc_bb_overflow",
572	"pm_discard_bb_overflow",
573	"pm_trunc_vfifo_full",
574	"pm_discard_vfifo_full",
575	"pm_trunc_qbb",
576	"pm_discard_qbb",
577	"pm_discard_mapping",
578	"rxdp_q_disabled_pkts",
579	"rxdp_di_dropped_pkts",
580	"rxdp_streaming_pkts",
581	"rxdp_hlb_fetch",
582	"rxdp_hlb_wait",
583	"vadapter_rx_unicast_packets",
584	"vadapter_rx_unicast_bytes",
585	"vadapter_rx_multicast_packets",
586	"vadapter_rx_multicast_bytes",
587	"vadapter_rx_broadcast_packets",
588	"vadapter_rx_broadcast_bytes",
589	"vadapter_rx_bad_packets",
590	"vadapter_rx_bad_bytes",
591	"vadapter_rx_overflow",
592	"vadapter_tx_unicast_packets",
593	"vadapter_tx_unicast_bytes",
594	"vadapter_tx_multicast_packets",
595	"vadapter_tx_multicast_bytes",
596	"vadapter_tx_broadcast_packets",
597	"vadapter_tx_broadcast_bytes",
598	"vadapter_tx_bad_packets",
599	"vadapter_tx_bad_bytes",
600	"vadapter_tx_overflow",
601};
602/* END MKCONFIG GENERATED EfxMacStatNamesBlock */
603
604	__checkReturn			const char *
605efx_mac_stat_name(
606	__in				efx_nic_t *enp,
607	__in				unsigned int id)
608{
609	_NOTE(ARGUNUSED(enp))
610	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
611
612	EFSYS_ASSERT3U(id, <, EFX_MAC_NSTATS);
613	return (__efx_mac_stat_name[id]);
614}
615
616#endif	/* EFSYS_OPT_NAMES */
617
618	__checkReturn			efx_rc_t
619efx_mac_stats_upload(
620	__in				efx_nic_t *enp,
621	__in				efsys_mem_t *esmp)
622{
623	efx_port_t *epp = &(enp->en_port);
624	const efx_mac_ops_t *emop = epp->ep_emop;
625	efx_rc_t rc;
626
627	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
628	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
629	EFSYS_ASSERT(emop != NULL);
630
631	/*
632	 * Don't assert !ep_mac_stats_pending, because the client might
633	 * have failed to finalise statistics when previously stopping
634	 * the port.
635	 */
636	if ((rc = emop->emo_stats_upload(enp, esmp)) != 0)
637		goto fail1;
638
639	epp->ep_mac_stats_pending = B_TRUE;
640
641	return (0);
642
643fail1:
644	EFSYS_PROBE1(fail1, efx_rc_t, rc);
645
646	return (rc);
647}
648
649	__checkReturn			efx_rc_t
650efx_mac_stats_periodic(
651	__in				efx_nic_t *enp,
652	__in				efsys_mem_t *esmp,
653	__in				uint16_t period_ms,
654	__in				boolean_t events)
655{
656	efx_port_t *epp = &(enp->en_port);
657	const efx_mac_ops_t *emop = epp->ep_emop;
658	efx_rc_t rc;
659
660	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
661	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
662
663	EFSYS_ASSERT(emop != NULL);
664
665	if (emop->emo_stats_periodic == NULL) {
666		rc = EINVAL;
667		goto fail1;
668	}
669
670	if ((rc = emop->emo_stats_periodic(enp, esmp, period_ms, events)) != 0)
671		goto fail2;
672
673	return (0);
674
675fail2:
676	EFSYS_PROBE(fail2);
677fail1:
678	EFSYS_PROBE1(fail1, efx_rc_t, rc);
679
680	return (rc);
681}
682
683
684	__checkReturn			efx_rc_t
685efx_mac_stats_update(
686	__in				efx_nic_t *enp,
687	__in				efsys_mem_t *esmp,
688	__inout_ecount(EFX_MAC_NSTATS)	efsys_stat_t *essp,
689	__inout_opt			uint32_t *generationp)
690{
691	efx_port_t *epp = &(enp->en_port);
692	const efx_mac_ops_t *emop = epp->ep_emop;
693	efx_rc_t rc;
694
695	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
696	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
697	EFSYS_ASSERT(emop != NULL);
698
699	rc = emop->emo_stats_update(enp, esmp, essp, generationp);
700	if (rc == 0)
701		epp->ep_mac_stats_pending = B_FALSE;
702
703	return (rc);
704}
705
706#endif	/* EFSYS_OPT_MAC_STATS */
707
708	__checkReturn			efx_rc_t
709efx_mac_select(
710	__in				efx_nic_t *enp)
711{
712	efx_port_t *epp = &(enp->en_port);
713	efx_mac_type_t type = EFX_MAC_INVALID;
714	const efx_mac_ops_t *emop;
715	int rc = EINVAL;
716
717	switch (enp->en_family) {
718#if EFSYS_OPT_SIENA
719	case EFX_FAMILY_SIENA:
720		emop = &__efx_siena_mac_ops;
721		type = EFX_MAC_SIENA;
722		break;
723#endif /* EFSYS_OPT_SIENA */
724
725#if EFSYS_OPT_HUNTINGTON
726	case EFX_FAMILY_HUNTINGTON:
727		emop = &__efx_ef10_mac_ops;
728		type = EFX_MAC_HUNTINGTON;
729		break;
730#endif /* EFSYS_OPT_HUNTINGTON */
731
732#if EFSYS_OPT_MEDFORD
733	case EFX_FAMILY_MEDFORD:
734		emop = &__efx_ef10_mac_ops;
735		type = EFX_MAC_MEDFORD;
736		break;
737#endif /* EFSYS_OPT_MEDFORD */
738
739	default:
740		rc = EINVAL;
741		goto fail1;
742	}
743
744	EFSYS_ASSERT(type != EFX_MAC_INVALID);
745	EFSYS_ASSERT3U(type, <, EFX_MAC_NTYPES);
746	EFSYS_ASSERT(emop != NULL);
747
748	epp->ep_emop = emop;
749	epp->ep_mac_type = type;
750
751	return (0);
752
753fail1:
754	EFSYS_PROBE1(fail1, efx_rc_t, rc);
755
756	return (rc);
757}
758
759
760#if EFSYS_OPT_SIENA
761
762#define	EFX_MAC_HASH_BITS	(1 << 8)
763
764/* Compute the multicast hash as used on Falcon and Siena. */
765static	void
766siena_mac_multicast_hash_compute(
767	__in_ecount(6*count)		uint8_t const *addrs,
768	__in				int count,
769	__out				efx_oword_t *hash_low,
770	__out				efx_oword_t *hash_high)
771{
772	uint32_t crc, index;
773	int i;
774
775	EFSYS_ASSERT(hash_low != NULL);
776	EFSYS_ASSERT(hash_high != NULL);
777
778	EFX_ZERO_OWORD(*hash_low);
779	EFX_ZERO_OWORD(*hash_high);
780
781	for (i = 0; i < count; i++) {
782		/* Calculate hash bucket (IEEE 802.3 CRC32 of the MAC addr) */
783		crc = efx_crc32_calculate(0xffffffff, addrs, EFX_MAC_ADDR_LEN);
784		index = crc % EFX_MAC_HASH_BITS;
785		if (index < 128) {
786			EFX_SET_OWORD_BIT(*hash_low, index);
787		} else {
788			EFX_SET_OWORD_BIT(*hash_high, index - 128);
789		}
790
791		addrs += EFX_MAC_ADDR_LEN;
792	}
793}
794
795static	__checkReturn	efx_rc_t
796siena_mac_multicast_list_set(
797	__in		efx_nic_t *enp)
798{
799	efx_port_t *epp = &(enp->en_port);
800	const efx_mac_ops_t *emop = epp->ep_emop;
801	efx_oword_t old_hash[2];
802	efx_rc_t rc;
803
804	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
805	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
806
807	memcpy(old_hash, epp->ep_multicst_hash, sizeof (old_hash));
808
809	siena_mac_multicast_hash_compute(
810	    epp->ep_mulcst_addr_list,
811	    epp->ep_mulcst_addr_count,
812	    &epp->ep_multicst_hash[0],
813	    &epp->ep_multicst_hash[1]);
814
815	if ((rc = emop->emo_reconfigure(enp)) != 0)
816		goto fail1;
817
818	return (0);
819
820fail1:
821	EFSYS_PROBE1(fail1, efx_rc_t, rc);
822
823	memcpy(epp->ep_multicst_hash, old_hash, sizeof (old_hash));
824
825	return (rc);
826}
827
828#endif /* EFSYS_OPT_SIENA */
829