efx_mac.c revision 331722
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 331722 2018-03-29 02:50:57Z eadler $");
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	siena_mac_stats_get_mask,		/* emo_stats_get_mask */
61	efx_mcdi_mac_stats_upload,		/* emo_stats_upload */
62	efx_mcdi_mac_stats_periodic,		/* emo_stats_periodic */
63	siena_mac_stats_update			/* emo_stats_update */
64#endif	/* EFSYS_OPT_MAC_STATS */
65};
66#endif	/* EFSYS_OPT_SIENA */
67
68#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
69static const efx_mac_ops_t	__efx_ef10_mac_ops = {
70	ef10_mac_poll,				/* emo_poll */
71	ef10_mac_up,				/* emo_up */
72	ef10_mac_addr_set,			/* emo_addr_set */
73	ef10_mac_pdu_set,			/* emo_pdu_set */
74	ef10_mac_pdu_get,			/* emo_pdu_get */
75	ef10_mac_reconfigure,			/* emo_reconfigure */
76	ef10_mac_multicast_list_set,		/* emo_multicast_list_set */
77	ef10_mac_filter_default_rxq_set,	/* emo_filter_default_rxq_set */
78	ef10_mac_filter_default_rxq_clear,
79					/* emo_filter_default_rxq_clear */
80#if EFSYS_OPT_LOOPBACK
81	ef10_mac_loopback_set,			/* emo_loopback_set */
82#endif	/* EFSYS_OPT_LOOPBACK */
83#if EFSYS_OPT_MAC_STATS
84	ef10_mac_stats_get_mask,		/* emo_stats_get_mask */
85	efx_mcdi_mac_stats_upload,		/* emo_stats_upload */
86	efx_mcdi_mac_stats_periodic,		/* emo_stats_periodic */
87	ef10_mac_stats_update			/* emo_stats_update */
88#endif	/* EFSYS_OPT_MAC_STATS */
89};
90#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
91
92	__checkReturn			efx_rc_t
93efx_mac_pdu_set(
94	__in				efx_nic_t *enp,
95	__in				size_t pdu)
96{
97	efx_port_t *epp = &(enp->en_port);
98	const efx_mac_ops_t *emop = epp->ep_emop;
99	uint32_t old_pdu;
100	efx_rc_t rc;
101
102	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
103	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
104	EFSYS_ASSERT(emop != NULL);
105
106	if (pdu < EFX_MAC_PDU_MIN) {
107		rc = EINVAL;
108		goto fail1;
109	}
110
111	if (pdu > EFX_MAC_PDU_MAX) {
112		rc = EINVAL;
113		goto fail2;
114	}
115
116	old_pdu = epp->ep_mac_pdu;
117	epp->ep_mac_pdu = (uint32_t)pdu;
118	if ((rc = emop->emo_pdu_set(enp)) != 0)
119		goto fail3;
120
121	return (0);
122
123fail3:
124	EFSYS_PROBE(fail3);
125
126	epp->ep_mac_pdu = old_pdu;
127
128fail2:
129	EFSYS_PROBE(fail2);
130fail1:
131	EFSYS_PROBE1(fail1, efx_rc_t, rc);
132
133	return (rc);
134}
135
136	__checkReturn	efx_rc_t
137efx_mac_pdu_get(
138	__in		efx_nic_t *enp,
139	__out		size_t *pdu)
140{
141	efx_port_t *epp = &(enp->en_port);
142	const efx_mac_ops_t *emop = epp->ep_emop;
143	efx_rc_t rc;
144
145	if ((rc = emop->emo_pdu_get(enp, pdu)) != 0)
146		goto fail1;
147
148	return (0);
149
150fail1:
151	EFSYS_PROBE1(fail1, efx_rc_t, rc);
152
153	return (rc);
154}
155
156	__checkReturn			efx_rc_t
157efx_mac_addr_set(
158	__in				efx_nic_t *enp,
159	__in				uint8_t *addr)
160{
161	efx_port_t *epp = &(enp->en_port);
162	const efx_mac_ops_t *emop = epp->ep_emop;
163	uint8_t old_addr[6];
164	uint32_t oui;
165	efx_rc_t rc;
166
167	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
168	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
169
170	if (EFX_MAC_ADDR_IS_MULTICAST(addr)) {
171		rc = EINVAL;
172		goto fail1;
173	}
174
175	oui = addr[0] << 16 | addr[1] << 8 | addr[2];
176	if (oui == 0x000000) {
177		rc = EINVAL;
178		goto fail2;
179	}
180
181	EFX_MAC_ADDR_COPY(old_addr, epp->ep_mac_addr);
182	EFX_MAC_ADDR_COPY(epp->ep_mac_addr, addr);
183	if ((rc = emop->emo_addr_set(enp)) != 0)
184		goto fail3;
185
186	return (0);
187
188fail3:
189	EFSYS_PROBE(fail3);
190
191	EFX_MAC_ADDR_COPY(epp->ep_mac_addr, old_addr);
192
193fail2:
194	EFSYS_PROBE(fail2);
195fail1:
196	EFSYS_PROBE1(fail1, efx_rc_t, rc);
197
198	return (rc);
199}
200
201	__checkReturn			efx_rc_t
202efx_mac_filter_set(
203	__in				efx_nic_t *enp,
204	__in				boolean_t all_unicst,
205	__in				boolean_t mulcst,
206	__in				boolean_t all_mulcst,
207	__in				boolean_t brdcst)
208{
209	efx_port_t *epp = &(enp->en_port);
210	const efx_mac_ops_t *emop = epp->ep_emop;
211	boolean_t old_all_unicst;
212	boolean_t old_mulcst;
213	boolean_t old_all_mulcst;
214	boolean_t old_brdcst;
215	efx_rc_t rc;
216
217	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
218	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
219
220	old_all_unicst = epp->ep_all_unicst;
221	old_mulcst = epp->ep_mulcst;
222	old_all_mulcst = epp->ep_all_mulcst;
223	old_brdcst = epp->ep_brdcst;
224
225	epp->ep_all_unicst = all_unicst;
226	epp->ep_mulcst = mulcst;
227	epp->ep_all_mulcst = all_mulcst;
228	epp->ep_brdcst = brdcst;
229
230	if ((rc = emop->emo_reconfigure(enp)) != 0)
231		goto fail1;
232
233	return (0);
234
235fail1:
236	EFSYS_PROBE1(fail1, efx_rc_t, rc);
237
238	epp->ep_all_unicst = old_all_unicst;
239	epp->ep_mulcst = old_mulcst;
240	epp->ep_all_mulcst = old_all_mulcst;
241	epp->ep_brdcst = old_brdcst;
242
243	return (rc);
244}
245
246	__checkReturn			efx_rc_t
247efx_mac_drain(
248	__in				efx_nic_t *enp,
249	__in				boolean_t enabled)
250{
251	efx_port_t *epp = &(enp->en_port);
252	const efx_mac_ops_t *emop = epp->ep_emop;
253	efx_rc_t rc;
254
255	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
256	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
257	EFSYS_ASSERT(emop != NULL);
258
259	if (epp->ep_mac_drain == enabled)
260		return (0);
261
262	epp->ep_mac_drain = enabled;
263
264	if ((rc = emop->emo_reconfigure(enp)) != 0)
265		goto fail1;
266
267	return (0);
268
269fail1:
270	EFSYS_PROBE1(fail1, efx_rc_t, rc);
271
272	return (rc);
273}
274
275	__checkReturn	efx_rc_t
276efx_mac_up(
277	__in		efx_nic_t *enp,
278	__out		boolean_t *mac_upp)
279{
280	efx_port_t *epp = &(enp->en_port);
281	const efx_mac_ops_t *emop = epp->ep_emop;
282	efx_rc_t rc;
283
284	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
285	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
286
287	if ((rc = emop->emo_up(enp, mac_upp)) != 0)
288		goto fail1;
289
290	return (0);
291
292fail1:
293	EFSYS_PROBE1(fail1, efx_rc_t, rc);
294
295	return (rc);
296}
297
298	__checkReturn			efx_rc_t
299efx_mac_fcntl_set(
300	__in				efx_nic_t *enp,
301	__in				unsigned int fcntl,
302	__in				boolean_t autoneg)
303{
304	efx_port_t *epp = &(enp->en_port);
305	const efx_mac_ops_t *emop = epp->ep_emop;
306	const efx_phy_ops_t *epop = epp->ep_epop;
307	unsigned int old_fcntl;
308	boolean_t old_autoneg;
309	unsigned int old_adv_cap;
310	efx_rc_t rc;
311
312	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
313	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
314
315	if ((fcntl & ~(EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE)) != 0) {
316		rc = EINVAL;
317		goto fail1;
318	}
319
320	/*
321	 * Ignore a request to set flow control auto-negotiation
322	 * if the PHY doesn't support it.
323	 */
324	if (~epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
325		autoneg = B_FALSE;
326
327	old_fcntl = epp->ep_fcntl;
328	old_autoneg = epp->ep_fcntl_autoneg;
329	old_adv_cap = epp->ep_adv_cap_mask;
330
331	epp->ep_fcntl = fcntl;
332	epp->ep_fcntl_autoneg = autoneg;
333
334	/*
335	 * Always encode the flow control settings in the advertised
336	 * capabilities even if we are not trying to auto-negotiate
337	 * them and reconfigure both the PHY and the MAC.
338	 */
339	if (fcntl & EFX_FCNTL_RESPOND)
340		epp->ep_adv_cap_mask |=    (1 << EFX_PHY_CAP_PAUSE |
341					    1 << EFX_PHY_CAP_ASYM);
342	else
343		epp->ep_adv_cap_mask &=   ~(1 << EFX_PHY_CAP_PAUSE |
344					    1 << EFX_PHY_CAP_ASYM);
345
346	if (fcntl & EFX_FCNTL_GENERATE)
347		epp->ep_adv_cap_mask ^= (1 << EFX_PHY_CAP_ASYM);
348
349	if ((rc = epop->epo_reconfigure(enp)) != 0)
350		goto fail2;
351
352	if ((rc = emop->emo_reconfigure(enp)) != 0)
353		goto fail3;
354
355	return (0);
356
357fail3:
358	EFSYS_PROBE(fail3);
359
360fail2:
361	EFSYS_PROBE(fail2);
362
363	epp->ep_fcntl = old_fcntl;
364	epp->ep_fcntl_autoneg = old_autoneg;
365	epp->ep_adv_cap_mask = old_adv_cap;
366
367fail1:
368	EFSYS_PROBE1(fail1, efx_rc_t, rc);
369
370	return (rc);
371}
372
373			void
374efx_mac_fcntl_get(
375	__in		efx_nic_t *enp,
376	__out		unsigned int *fcntl_wantedp,
377	__out		unsigned int *fcntl_linkp)
378{
379	efx_port_t *epp = &(enp->en_port);
380	unsigned int wanted = 0;
381
382	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
383	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
384
385	/*
386	 * Decode the requested flow control settings from the PHY
387	 * advertised capabilities.
388	 */
389	if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_PAUSE))
390		wanted = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
391	if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_ASYM))
392		wanted ^= EFX_FCNTL_GENERATE;
393
394	*fcntl_linkp = epp->ep_fcntl;
395	*fcntl_wantedp = wanted;
396}
397
398	__checkReturn	efx_rc_t
399efx_mac_multicast_list_set(
400	__in				efx_nic_t *enp,
401	__in_ecount(6*count)		uint8_t const *addrs,
402	__in				int count)
403{
404	efx_port_t *epp = &(enp->en_port);
405	const efx_mac_ops_t *emop = epp->ep_emop;
406	uint8_t	*old_mulcst_addr_list = NULL;
407	uint32_t old_mulcst_addr_count;
408	efx_rc_t rc;
409
410	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
411	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
412
413	if (count > EFX_MAC_MULTICAST_LIST_MAX) {
414		rc = EINVAL;
415		goto fail1;
416	}
417
418	old_mulcst_addr_count = epp->ep_mulcst_addr_count;
419	if (old_mulcst_addr_count > 0) {
420		/* Allocate memory to store old list (instead of using stack) */
421		EFSYS_KMEM_ALLOC(enp->en_esip,
422				old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
423				old_mulcst_addr_list);
424		if (old_mulcst_addr_list == NULL) {
425			rc = ENOMEM;
426			goto fail2;
427		}
428
429		/* Save the old list in case we need to rollback */
430		memcpy(old_mulcst_addr_list, epp->ep_mulcst_addr_list,
431			old_mulcst_addr_count * EFX_MAC_ADDR_LEN);
432	}
433
434	/* Store the new list */
435	memcpy(epp->ep_mulcst_addr_list, addrs,
436		count * EFX_MAC_ADDR_LEN);
437	epp->ep_mulcst_addr_count = count;
438
439	if ((rc = emop->emo_multicast_list_set(enp)) != 0)
440		goto fail3;
441
442	if (old_mulcst_addr_count > 0) {
443		EFSYS_KMEM_FREE(enp->en_esip,
444				old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
445				old_mulcst_addr_list);
446	}
447
448	return (0);
449
450fail3:
451	EFSYS_PROBE(fail3);
452
453	/* Restore original list on failure */
454	epp->ep_mulcst_addr_count = old_mulcst_addr_count;
455	if (old_mulcst_addr_count > 0) {
456		memcpy(epp->ep_mulcst_addr_list, old_mulcst_addr_list,
457			old_mulcst_addr_count * EFX_MAC_ADDR_LEN);
458
459		EFSYS_KMEM_FREE(enp->en_esip,
460				old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
461				old_mulcst_addr_list);
462	}
463
464fail2:
465	EFSYS_PROBE(fail2);
466
467fail1:
468	EFSYS_PROBE1(fail1, efx_rc_t, rc);
469
470	return (rc);
471
472}
473
474	__checkReturn	efx_rc_t
475efx_mac_filter_default_rxq_set(
476	__in		efx_nic_t *enp,
477	__in		efx_rxq_t *erp,
478	__in		boolean_t using_rss)
479{
480	efx_port_t *epp = &(enp->en_port);
481	const efx_mac_ops_t *emop = epp->ep_emop;
482	efx_rc_t rc;
483
484	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
485	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
486
487	if (emop->emo_filter_default_rxq_set != NULL) {
488		rc = emop->emo_filter_default_rxq_set(enp, erp, using_rss);
489		if (rc != 0)
490			goto fail1;
491	}
492
493	return (0);
494
495fail1:
496	EFSYS_PROBE1(fail1, efx_rc_t, rc);
497
498	return (rc);
499}
500
501			void
502efx_mac_filter_default_rxq_clear(
503	__in		efx_nic_t *enp)
504{
505	efx_port_t *epp = &(enp->en_port);
506	const efx_mac_ops_t *emop = epp->ep_emop;
507
508	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
509	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
510
511	if (emop->emo_filter_default_rxq_clear != NULL)
512		emop->emo_filter_default_rxq_clear(enp);
513}
514
515
516#if EFSYS_OPT_MAC_STATS
517
518#if EFSYS_OPT_NAMES
519
520/* START MKCONFIG GENERATED EfxMacStatNamesBlock c11b91b42f922516 */
521static const char * const __efx_mac_stat_name[] = {
522	"rx_octets",
523	"rx_pkts",
524	"rx_unicst_pkts",
525	"rx_multicst_pkts",
526	"rx_brdcst_pkts",
527	"rx_pause_pkts",
528	"rx_le_64_pkts",
529	"rx_65_to_127_pkts",
530	"rx_128_to_255_pkts",
531	"rx_256_to_511_pkts",
532	"rx_512_to_1023_pkts",
533	"rx_1024_to_15xx_pkts",
534	"rx_ge_15xx_pkts",
535	"rx_errors",
536	"rx_fcs_errors",
537	"rx_drop_events",
538	"rx_false_carrier_errors",
539	"rx_symbol_errors",
540	"rx_align_errors",
541	"rx_internal_errors",
542	"rx_jabber_pkts",
543	"rx_lane0_char_err",
544	"rx_lane1_char_err",
545	"rx_lane2_char_err",
546	"rx_lane3_char_err",
547	"rx_lane0_disp_err",
548	"rx_lane1_disp_err",
549	"rx_lane2_disp_err",
550	"rx_lane3_disp_err",
551	"rx_match_fault",
552	"rx_nodesc_drop_cnt",
553	"tx_octets",
554	"tx_pkts",
555	"tx_unicst_pkts",
556	"tx_multicst_pkts",
557	"tx_brdcst_pkts",
558	"tx_pause_pkts",
559	"tx_le_64_pkts",
560	"tx_65_to_127_pkts",
561	"tx_128_to_255_pkts",
562	"tx_256_to_511_pkts",
563	"tx_512_to_1023_pkts",
564	"tx_1024_to_15xx_pkts",
565	"tx_ge_15xx_pkts",
566	"tx_errors",
567	"tx_sgl_col_pkts",
568	"tx_mult_col_pkts",
569	"tx_ex_col_pkts",
570	"tx_late_col_pkts",
571	"tx_def_pkts",
572	"tx_ex_def_pkts",
573	"pm_trunc_bb_overflow",
574	"pm_discard_bb_overflow",
575	"pm_trunc_vfifo_full",
576	"pm_discard_vfifo_full",
577	"pm_trunc_qbb",
578	"pm_discard_qbb",
579	"pm_discard_mapping",
580	"rxdp_q_disabled_pkts",
581	"rxdp_di_dropped_pkts",
582	"rxdp_streaming_pkts",
583	"rxdp_hlb_fetch",
584	"rxdp_hlb_wait",
585	"vadapter_rx_unicast_packets",
586	"vadapter_rx_unicast_bytes",
587	"vadapter_rx_multicast_packets",
588	"vadapter_rx_multicast_bytes",
589	"vadapter_rx_broadcast_packets",
590	"vadapter_rx_broadcast_bytes",
591	"vadapter_rx_bad_packets",
592	"vadapter_rx_bad_bytes",
593	"vadapter_rx_overflow",
594	"vadapter_tx_unicast_packets",
595	"vadapter_tx_unicast_bytes",
596	"vadapter_tx_multicast_packets",
597	"vadapter_tx_multicast_bytes",
598	"vadapter_tx_broadcast_packets",
599	"vadapter_tx_broadcast_bytes",
600	"vadapter_tx_bad_packets",
601	"vadapter_tx_bad_bytes",
602	"vadapter_tx_overflow",
603};
604/* END MKCONFIG GENERATED EfxMacStatNamesBlock */
605
606	__checkReturn			const char *
607efx_mac_stat_name(
608	__in				efx_nic_t *enp,
609	__in				unsigned int id)
610{
611	_NOTE(ARGUNUSED(enp))
612	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
613
614	EFSYS_ASSERT3U(id, <, EFX_MAC_NSTATS);
615	return (__efx_mac_stat_name[id]);
616}
617
618#endif	/* EFSYS_OPT_NAMES */
619
620static					efx_rc_t
621efx_mac_stats_mask_add_range(
622	__inout_bcount(mask_size)	uint32_t *maskp,
623	__in				size_t mask_size,
624	__in				const struct efx_mac_stats_range *rngp)
625{
626	unsigned int mask_npages = mask_size / sizeof (*maskp);
627	unsigned int el;
628	unsigned int el_min;
629	unsigned int el_max;
630	unsigned int low;
631	unsigned int high;
632	unsigned int width;
633	efx_rc_t rc;
634
635	if ((mask_npages * EFX_MAC_STATS_MASK_BITS_PER_PAGE) <=
636	    (unsigned int)rngp->last) {
637		rc = EINVAL;
638		goto fail1;
639	}
640
641	EFSYS_ASSERT3U(rngp->first, <=, rngp->last);
642	EFSYS_ASSERT3U(rngp->last, <, EFX_MAC_NSTATS);
643
644	for (el = 0; el < mask_npages; ++el) {
645		el_min = el * EFX_MAC_STATS_MASK_BITS_PER_PAGE;
646		el_max =
647		    el_min + (EFX_MAC_STATS_MASK_BITS_PER_PAGE - 1);
648		if ((unsigned int)rngp->first > el_max ||
649		    (unsigned int)rngp->last < el_min)
650			continue;
651		low = MAX((unsigned int)rngp->first, el_min);
652		high = MIN((unsigned int)rngp->last, el_max);
653		width = high - low + 1;
654		maskp[el] |=
655		    (width == EFX_MAC_STATS_MASK_BITS_PER_PAGE) ?
656		    (~0ULL) : (((1ULL << width) - 1) << (low - el_min));
657	}
658
659	return (0);
660
661fail1:
662	EFSYS_PROBE1(fail1, efx_rc_t, rc);
663
664	return (rc);
665}
666
667					efx_rc_t
668efx_mac_stats_mask_add_ranges(
669	__inout_bcount(mask_size)	uint32_t *maskp,
670	__in				size_t mask_size,
671	__in_ecount(rng_count)		const struct efx_mac_stats_range *rngp,
672	__in				unsigned int rng_count)
673{
674	unsigned int i;
675	efx_rc_t rc;
676
677	for (i = 0; i < rng_count; ++i) {
678		if ((rc = efx_mac_stats_mask_add_range(maskp, mask_size,
679		    &rngp[i])) != 0)
680			goto fail1;
681	}
682
683	return (0);
684
685fail1:
686	EFSYS_PROBE1(fail1, efx_rc_t, rc);
687
688	return (rc);
689}
690
691	__checkReturn			efx_rc_t
692efx_mac_stats_get_mask(
693	__in				efx_nic_t *enp,
694	__out_bcount(mask_size)		uint32_t *maskp,
695	__in				size_t mask_size)
696{
697	efx_port_t *epp = &(enp->en_port);
698	const efx_mac_ops_t *emop = epp->ep_emop;
699	efx_rc_t rc;
700
701	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
702	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
703	EFSYS_ASSERT(maskp != NULL);
704	EFSYS_ASSERT(mask_size % sizeof (maskp[0]) == 0);
705
706	(void) memset(maskp, 0, mask_size);
707
708	if ((rc = emop->emo_stats_get_mask(enp, maskp, mask_size)) != 0)
709		goto fail1;
710
711	return (0);
712
713fail1:
714	EFSYS_PROBE1(fail1, efx_rc_t, rc);
715
716	return (rc);
717}
718
719	__checkReturn			efx_rc_t
720efx_mac_stats_upload(
721	__in				efx_nic_t *enp,
722	__in				efsys_mem_t *esmp)
723{
724	efx_port_t *epp = &(enp->en_port);
725	const efx_mac_ops_t *emop = epp->ep_emop;
726	efx_rc_t rc;
727
728	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
729	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
730	EFSYS_ASSERT(emop != NULL);
731
732	/*
733	 * Don't assert !ep_mac_stats_pending, because the client might
734	 * have failed to finalise statistics when previously stopping
735	 * the port.
736	 */
737	if ((rc = emop->emo_stats_upload(enp, esmp)) != 0)
738		goto fail1;
739
740	epp->ep_mac_stats_pending = B_TRUE;
741
742	return (0);
743
744fail1:
745	EFSYS_PROBE1(fail1, efx_rc_t, rc);
746
747	return (rc);
748}
749
750	__checkReturn			efx_rc_t
751efx_mac_stats_periodic(
752	__in				efx_nic_t *enp,
753	__in				efsys_mem_t *esmp,
754	__in				uint16_t period_ms,
755	__in				boolean_t events)
756{
757	efx_port_t *epp = &(enp->en_port);
758	const efx_mac_ops_t *emop = epp->ep_emop;
759	efx_rc_t rc;
760
761	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
762	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
763
764	EFSYS_ASSERT(emop != NULL);
765
766	if (emop->emo_stats_periodic == NULL) {
767		rc = EINVAL;
768		goto fail1;
769	}
770
771	if ((rc = emop->emo_stats_periodic(enp, esmp, period_ms, events)) != 0)
772		goto fail2;
773
774	return (0);
775
776fail2:
777	EFSYS_PROBE(fail2);
778fail1:
779	EFSYS_PROBE1(fail1, efx_rc_t, rc);
780
781	return (rc);
782}
783
784
785	__checkReturn			efx_rc_t
786efx_mac_stats_update(
787	__in				efx_nic_t *enp,
788	__in				efsys_mem_t *esmp,
789	__inout_ecount(EFX_MAC_NSTATS)	efsys_stat_t *essp,
790	__inout_opt			uint32_t *generationp)
791{
792	efx_port_t *epp = &(enp->en_port);
793	const efx_mac_ops_t *emop = epp->ep_emop;
794	efx_rc_t rc;
795
796	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
797	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
798	EFSYS_ASSERT(emop != NULL);
799
800	rc = emop->emo_stats_update(enp, esmp, essp, generationp);
801	if (rc == 0)
802		epp->ep_mac_stats_pending = B_FALSE;
803
804	return (rc);
805}
806
807#endif	/* EFSYS_OPT_MAC_STATS */
808
809	__checkReturn			efx_rc_t
810efx_mac_select(
811	__in				efx_nic_t *enp)
812{
813	efx_port_t *epp = &(enp->en_port);
814	efx_mac_type_t type = EFX_MAC_INVALID;
815	const efx_mac_ops_t *emop;
816	int rc = EINVAL;
817
818	switch (enp->en_family) {
819#if EFSYS_OPT_SIENA
820	case EFX_FAMILY_SIENA:
821		emop = &__efx_siena_mac_ops;
822		type = EFX_MAC_SIENA;
823		break;
824#endif /* EFSYS_OPT_SIENA */
825
826#if EFSYS_OPT_HUNTINGTON
827	case EFX_FAMILY_HUNTINGTON:
828		emop = &__efx_ef10_mac_ops;
829		type = EFX_MAC_HUNTINGTON;
830		break;
831#endif /* EFSYS_OPT_HUNTINGTON */
832
833#if EFSYS_OPT_MEDFORD
834	case EFX_FAMILY_MEDFORD:
835		emop = &__efx_ef10_mac_ops;
836		type = EFX_MAC_MEDFORD;
837		break;
838#endif /* EFSYS_OPT_MEDFORD */
839
840	default:
841		rc = EINVAL;
842		goto fail1;
843	}
844
845	EFSYS_ASSERT(type != EFX_MAC_INVALID);
846	EFSYS_ASSERT3U(type, <, EFX_MAC_NTYPES);
847	EFSYS_ASSERT(emop != NULL);
848
849	epp->ep_emop = emop;
850	epp->ep_mac_type = type;
851
852	return (0);
853
854fail1:
855	EFSYS_PROBE1(fail1, efx_rc_t, rc);
856
857	return (rc);
858}
859
860
861#if EFSYS_OPT_SIENA
862
863#define	EFX_MAC_HASH_BITS	(1 << 8)
864
865/* Compute the multicast hash as used on Falcon and Siena. */
866static	void
867siena_mac_multicast_hash_compute(
868	__in_ecount(6*count)		uint8_t const *addrs,
869	__in				int count,
870	__out				efx_oword_t *hash_low,
871	__out				efx_oword_t *hash_high)
872{
873	uint32_t crc, index;
874	int i;
875
876	EFSYS_ASSERT(hash_low != NULL);
877	EFSYS_ASSERT(hash_high != NULL);
878
879	EFX_ZERO_OWORD(*hash_low);
880	EFX_ZERO_OWORD(*hash_high);
881
882	for (i = 0; i < count; i++) {
883		/* Calculate hash bucket (IEEE 802.3 CRC32 of the MAC addr) */
884		crc = efx_crc32_calculate(0xffffffff, addrs, EFX_MAC_ADDR_LEN);
885		index = crc % EFX_MAC_HASH_BITS;
886		if (index < 128) {
887			EFX_SET_OWORD_BIT(*hash_low, index);
888		} else {
889			EFX_SET_OWORD_BIT(*hash_high, index - 128);
890		}
891
892		addrs += EFX_MAC_ADDR_LEN;
893	}
894}
895
896static	__checkReturn	efx_rc_t
897siena_mac_multicast_list_set(
898	__in		efx_nic_t *enp)
899{
900	efx_port_t *epp = &(enp->en_port);
901	const efx_mac_ops_t *emop = epp->ep_emop;
902	efx_oword_t old_hash[2];
903	efx_rc_t rc;
904
905	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
906	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
907
908	memcpy(old_hash, epp->ep_multicst_hash, sizeof (old_hash));
909
910	siena_mac_multicast_hash_compute(
911	    epp->ep_mulcst_addr_list,
912	    epp->ep_mulcst_addr_count,
913	    &epp->ep_multicst_hash[0],
914	    &epp->ep_multicst_hash[1]);
915
916	if ((rc = emop->emo_reconfigure(enp)) != 0)
917		goto fail1;
918
919	return (0);
920
921fail1:
922	EFSYS_PROBE1(fail1, efx_rc_t, rc);
923
924	memcpy(epp->ep_multicst_hash, old_hash, sizeof (old_hash));
925
926	return (rc);
927}
928
929#endif /* EFSYS_OPT_SIENA */
930