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