xref: /illumos-gate/usr/src/uts/common/io/sfxge/sfxge_mac.c (revision 4c28a617e3922d92a58e813a5b955eb526b9c386)
1 /*
2  * Copyright (c) 2008-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 /*
32  * All efx_mac_*() must be after efx_port_init()
33  * LOCKING STRATEGY: Aquire sm_lock and test sm_state==SFXGE_MAC_STARTED
34  * to serialise against sfxge_restart()
35  */
36 
37 #include <sys/types.h>
38 #include <sys/sysmacros.h>
39 #include <sys/ddi.h>
40 #include <sys/sunddi.h>
41 
42 #include "sfxge.h"
43 #include "efx.h"
44 
45 #define	SFXGE_MAC_POLL_PERIOD_MS 1000
46 
47 static void sfxge_mac_link_update_locked(sfxge_t *sp, efx_link_mode_t mode);
48 
49 
50 /* MAC DMA attributes */
51 static ddi_device_acc_attr_t sfxge_mac_devacc = {
52 
53 	DDI_DEVICE_ATTR_V0,	/* devacc_attr_version */
54 	DDI_NEVERSWAP_ACC,	/* devacc_attr_endian_flags */
55 	DDI_STRICTORDER_ACC	/* devacc_attr_dataorder */
56 };
57 
58 static ddi_dma_attr_t sfxge_mac_dma_attr = {
59 	DMA_ATTR_V0,		/* dma_attr_version	*/
60 	0,			/* dma_attr_addr_lo	*/
61 	0xffffffffffffffffull,	/* dma_attr_addr_hi	*/
62 	0xffffffffffffffffull,	/* dma_attr_count_max	*/
63 	0x1000,			/* dma_attr_align	*/
64 	0xffffffff,		/* dma_attr_burstsizes	*/
65 	1,			/* dma_attr_minxfer	*/
66 	0xffffffffffffffffull,	/* dma_attr_maxxfer	*/
67 	0xffffffffffffffffull,	/* dma_attr_seg		*/
68 	1,			/* dma_attr_sgllen	*/
69 	1,			/* dma_attr_granular	*/
70 	0			/* dma_attr_flags	*/
71 };
72 
73 
74 static void
75 _sfxge_mac_stat_update(sfxge_mac_t *smp, int tries, int delay_usec)
76 {
77 	sfxge_t *sp = smp->sm_sp;
78 	efsys_mem_t *esmp = &(smp->sm_mem);
79 	int i;
80 
81 	ASSERT(mutex_owned(&(smp->sm_lock)));
82 	ASSERT3U(smp->sm_state, !=, SFXGE_MAC_UNINITIALIZED);
83 
84 	/* if no stats pending then they are already freshly updated */
85 	if (smp->sm_mac_stats_timer_reqd && !smp->sm_mac_stats_pend)
86 		return;
87 
88 	for (i = 0; i < tries; i++) {
89 		/* Try to update the cached counters */
90 		if (efx_mac_stats_update(sp->s_enp, esmp, smp->sm_stat,
91 		    NULL) != EAGAIN)
92 			goto done;
93 
94 		drv_usecwait(delay_usec);
95 	}
96 
97 	DTRACE_PROBE(mac_stat_timeout);
98 	dev_err(sp->s_dip, CE_NOTE, SFXGE_CMN_ERR "MAC stats timeout");
99 	return;
100 
101 done:
102 	smp->sm_mac_stats_pend = B_FALSE;
103 	smp->sm_lbolt = ddi_get_lbolt();
104 }
105 
106 static void
107 sfxge_mac_stat_update_quick(sfxge_mac_t *smp)
108 {
109 	/*
110 	 * Update the statistics from the most recent DMA. This might race
111 	 * with an inflight dma, so retry once. Otherwise get mac stat
112 	 * values from the last mac_poll() or MC periodic stats.
113 	 */
114 	_sfxge_mac_stat_update(smp, 2, 50);
115 }
116 
117 static void
118 sfxge_mac_stat_update_wait(sfxge_mac_t *smp)
119 {
120 	/* Wait a max of 20 * 500us = 10ms */
121 	_sfxge_mac_stat_update(smp, 20, 500);
122 }
123 
124 static int
125 sfxge_mac_kstat_update(kstat_t *ksp, int rw)
126 {
127 	sfxge_mac_t *smp = ksp->ks_private;
128 	kstat_named_t *knp;
129 	int rc;
130 	unsigned int val;
131 	sfxge_rx_coalesce_mode_t rxmode;
132 
133 	if (rw != KSTAT_READ) {
134 		rc = EACCES;
135 		goto fail1;
136 	}
137 
138 	ASSERT(mutex_owned(&(smp->sm_lock)));
139 
140 	if (smp->sm_state != SFXGE_MAC_STARTED)
141 		goto done;
142 
143 	sfxge_mac_stat_update_quick(smp);
144 
145 	knp = smp->sm_stat;
146 	knp += EFX_MAC_NSTATS;
147 
148 	knp->value.ui64 = (smp->sm_link_up) ? 1 : 0;
149 	knp++;
150 
151 	knp->value.ui64 = smp->sm_link_speed;
152 	knp++;
153 
154 	knp->value.ui64 = smp->sm_link_duplex;
155 	knp++;
156 
157 	knp->value.ui64 = (smp->sm_fcntl & EFX_FCNTL_GENERATE) ? 1 : 0;
158 	knp++;
159 
160 	knp->value.ui64 = (smp->sm_fcntl & EFX_FCNTL_RESPOND) ? 1 : 0;
161 	knp++;
162 
163 	sfxge_ev_moderation_get(smp->sm_sp, &val);
164 	knp->value.ui64 = val;
165 	knp++;
166 
167 	sfxge_rx_coalesce_mode_get(smp->sm_sp, &rxmode);
168 	knp->value.ui64 = (uint64_t)rxmode;
169 	knp++;
170 
171 	if (sfxge_rx_scale_count_get(smp->sm_sp, &val) != 0)
172 		val = 0;
173 	knp->value.ui64 = val;
174 	knp++;
175 
176 done:
177 	return (0);
178 
179 fail1:
180 	DTRACE_PROBE1(fail1, int, rc);
181 
182 	return (rc);
183 }
184 
185 static int
186 sfxge_mac_kstat_init(sfxge_t *sp)
187 {
188 	sfxge_mac_t *smp = &(sp->s_mac);
189 	dev_info_t *dip = sp->s_dip;
190 	char name[MAXNAMELEN];
191 	kstat_t *ksp;
192 	kstat_named_t *knp;
193 	unsigned int id;
194 	int rc;
195 
196 	/* Create the set */
197 	(void) snprintf(name, MAXNAMELEN - 1, "%s_mac", ddi_driver_name(dip));
198 
199 	if ((ksp = kstat_create((char *)ddi_driver_name(dip),
200 	    ddi_get_instance(dip), name, "mac", KSTAT_TYPE_NAMED,
201 	    EFX_MAC_NSTATS + 8, 0)) == NULL) {
202 		rc = ENOMEM;
203 		goto fail1;
204 	}
205 
206 	smp->sm_ksp = ksp;
207 
208 	ksp->ks_update = sfxge_mac_kstat_update;
209 	ksp->ks_private = smp;
210 	ksp->ks_lock = &(smp->sm_lock);
211 
212 	/* Initialise the named stats */
213 	smp->sm_stat = knp = ksp->ks_data;
214 	for (id = 0; id < EFX_MAC_NSTATS; id++) {
215 		kstat_named_init(knp, (char *)efx_mac_stat_name(sp->s_enp, id),
216 		    KSTAT_DATA_UINT64);
217 		knp++;
218 	}
219 
220 	kstat_named_init(knp++, "link_up", KSTAT_DATA_UINT64);
221 	kstat_named_init(knp++, "link_speed", KSTAT_DATA_UINT64);
222 	kstat_named_init(knp++, "link_duplex", KSTAT_DATA_UINT64);
223 	kstat_named_init(knp++, "fcntl_generate", KSTAT_DATA_UINT64);
224 	kstat_named_init(knp++, "fcntl_respond", KSTAT_DATA_UINT64);
225 	kstat_named_init(knp++, "intr_moderation", KSTAT_DATA_UINT64);
226 	kstat_named_init(knp++, "rx_coalesce_mode", KSTAT_DATA_UINT64);
227 	kstat_named_init(knp++, "rx_scale_count", KSTAT_DATA_UINT64);
228 
229 	kstat_install(ksp);
230 
231 	return (0);
232 
233 fail1:
234 	DTRACE_PROBE1(fail1, int, rc);
235 
236 	return (rc);
237 }
238 
239 static void
240 sfxge_mac_kstat_fini(sfxge_t *sp)
241 {
242 	sfxge_mac_t *smp = &(sp->s_mac);
243 
244 	/* Destroy the set */
245 	kstat_delete(smp->sm_ksp);
246 	smp->sm_ksp = NULL;
247 	smp->sm_stat = NULL;
248 }
249 
250 void
251 sfxge_mac_stat_get(sfxge_t *sp, unsigned int id, uint64_t *valp)
252 {
253 	sfxge_mac_t *smp = &(sp->s_mac);
254 
255 	/* Make sure the cached counter values are recent */
256 	mutex_enter(&(smp->sm_lock));
257 
258 	if (smp->sm_state != SFXGE_MAC_STARTED)
259 		goto done;
260 
261 	sfxge_mac_stat_update_quick(smp);
262 
263 	*valp = smp->sm_stat[id].value.ui64;
264 
265 done:
266 	mutex_exit(&(smp->sm_lock));
267 }
268 
269 static void
270 sfxge_mac_poll(void *arg)
271 {
272 	sfxge_t *sp = arg;
273 	efx_nic_t *enp = sp->s_enp;
274 	sfxge_mac_t *smp = &(sp->s_mac);
275 	efsys_mem_t *esmp = &(smp->sm_mem);
276 	efx_link_mode_t mode;
277 	clock_t timeout;
278 
279 	mutex_enter(&(smp->sm_lock));
280 	while (smp->sm_state == SFXGE_MAC_STARTED) {
281 
282 		/* clears smp->sm_mac_stats_pend if appropriate */
283 		if (smp->sm_mac_stats_pend)
284 			sfxge_mac_stat_update_wait(smp);
285 
286 		/* This may sleep waiting for MCDI completion */
287 		mode = EFX_LINK_UNKNOWN;
288 		if (efx_port_poll(enp, &mode) == 0)
289 			sfxge_mac_link_update_locked(sp, mode);
290 
291 		if ((smp->sm_link_poll_reqd == B_FALSE) &&
292 		    (smp->sm_mac_stats_timer_reqd == B_FALSE))
293 			goto done;
294 
295 		/* Zero the memory */
296 		bzero(esmp->esm_base, EFX_MAC_STATS_SIZE);
297 
298 		/* Trigger upload the MAC statistics counters */
299 		if (smp->sm_link_up &&
300 		    efx_mac_stats_upload(sp->s_enp, esmp) == 0)
301 			smp->sm_mac_stats_pend = B_TRUE;
302 
303 		/* Wait for timeout or end of polling */
304 		timeout = ddi_get_lbolt() + drv_usectohz(1000 *
305 		    SFXGE_MAC_POLL_PERIOD_MS);
306 		while (smp->sm_state == SFXGE_MAC_STARTED) {
307 			if (cv_timedwait(&(smp->sm_link_poll_kv),
308 			    &(smp->sm_lock), timeout) < 0) {
309 				/* Timeout - poll if polling still enabled */
310 				break;
311 			}
312 		}
313 	}
314 done:
315 	mutex_exit(&(smp->sm_lock));
316 
317 }
318 
319 static void
320 sfxge_mac_poll_start(sfxge_t *sp)
321 {
322 	sfxge_mac_t *smp = &(sp->s_mac);
323 
324 	ASSERT(mutex_owned(&(smp->sm_lock)));
325 	ASSERT3U(smp->sm_state, ==, SFXGE_MAC_STARTED);
326 
327 	/* Schedule a poll */
328 	(void) ddi_taskq_dispatch(smp->sm_tqp, sfxge_mac_poll, sp, DDI_SLEEP);
329 }
330 
331 static void
332 sfxge_mac_poll_stop(sfxge_t *sp)
333 {
334 	sfxge_mac_t *smp = &(sp->s_mac);
335 
336 	ASSERT(mutex_owned(&(smp->sm_lock)));
337 	ASSERT3U(smp->sm_state, ==, SFXGE_MAC_INITIALIZED);
338 
339 	cv_broadcast(&(smp->sm_link_poll_kv));
340 
341 	/* Wait for link polling to cease */
342 	mutex_exit(&(smp->sm_lock));
343 	ddi_taskq_wait(smp->sm_tqp);
344 	mutex_enter(&(smp->sm_lock));
345 
346 	/* Collect the final statistics. */
347 	sfxge_mac_stat_update_wait(smp);
348 }
349 
350 int
351 sfxge_mac_init(sfxge_t *sp)
352 {
353 	sfxge_mac_t *smp = &(sp->s_mac);
354 	efsys_mem_t *esmp = &(smp->sm_mem);
355 	dev_info_t *dip = sp->s_dip;
356 	sfxge_dma_buffer_attr_t dma_attr;
357 	const efx_nic_cfg_t *encp;
358 	unsigned char *bytes;
359 	unsigned int n;
360 	int err, rc;
361 
362 	SFXGE_OBJ_CHECK(smp, sfxge_mac_t);
363 
364 	ASSERT3U(smp->sm_state, ==, SFXGE_MAC_UNINITIALIZED);
365 
366 	smp->sm_sp = sp;
367 	encp = efx_nic_cfg_get(sp->s_enp);
368 	smp->sm_link_poll_reqd = (~encp->enc_features &
369 	    EFX_FEATURE_LINK_EVENTS);
370 	smp->sm_mac_stats_timer_reqd = (~encp->enc_features &
371 	    EFX_FEATURE_PERIODIC_MAC_STATS);
372 
373 	mutex_init(&(smp->sm_lock), NULL, MUTEX_DRIVER,
374 	    DDI_INTR_PRI(sp->s_intr.si_intr_pri));
375 	cv_init(&(smp->sm_link_poll_kv), NULL, CV_DRIVER, NULL);
376 
377 	/* Create link poll taskq */
378 	smp->sm_tqp = ddi_taskq_create(dip, "mac_tq", 1, TASKQ_DEFAULTPRI, 0);
379 	if (smp->sm_tqp == NULL) {
380 		rc = ENOMEM;
381 		goto fail1;
382 	}
383 
384 	if ((rc = sfxge_phy_init(sp)) != 0)
385 		goto fail2;
386 
387 	dma_attr.sdba_dip	 = dip;
388 	dma_attr.sdba_dattrp	 = &sfxge_mac_dma_attr;
389 	dma_attr.sdba_callback	 = DDI_DMA_SLEEP;
390 	dma_attr.sdba_length	 = EFX_MAC_STATS_SIZE;
391 	dma_attr.sdba_memflags	 = DDI_DMA_CONSISTENT;
392 	dma_attr.sdba_devaccp	 = &sfxge_mac_devacc;
393 	dma_attr.sdba_bindflags	 = DDI_DMA_READ | DDI_DMA_CONSISTENT;
394 	dma_attr.sdba_maxcookies = 1;
395 	dma_attr.sdba_zeroinit	 = B_TRUE;
396 
397 	if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
398 		goto fail3;
399 
400 	/* Set the initial flow control values */
401 	smp->sm_fcntl = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
402 
403 	/*
404 	 * Determine the 'burnt-in' MAC address:
405 	 *
406 	 * A: if the "mac-address" property is set on our device node use that.
407 	 * B: otherwise, use the value from NVRAM.
408 	 */
409 
410 	/* A: property  */
411 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
412 	    "mac-address", &bytes, &n);
413 	switch (err) {
414 	case DDI_PROP_SUCCESS:
415 		if (n == ETHERADDRL) {
416 			bcopy(bytes, smp->sm_bia, ETHERADDRL);
417 			goto done;
418 		}
419 
420 		ddi_prop_free(bytes);
421 		break;
422 
423 	default:
424 		break;
425 	}
426 
427 	/* B: NVRAM */
428 	bcopy(encp->enc_mac_addr, smp->sm_bia, ETHERADDRL);
429 
430 done:
431 	/* Initialize the statistics */
432 	if ((rc = sfxge_mac_kstat_init(sp)) != 0)
433 		goto fail4;
434 
435 	if ((rc = sfxge_phy_kstat_init(sp)) != 0)
436 		goto fail5;
437 
438 	smp->sm_state = SFXGE_MAC_INITIALIZED;
439 
440 	return (0);
441 
442 fail5:
443 	DTRACE_PROBE(fail5);
444 
445 	sfxge_mac_kstat_fini(sp);
446 fail4:
447 	DTRACE_PROBE(fail4);
448 
449 	/* Tear down DMA setup */
450 	sfxge_dma_buffer_destroy(esmp);
451 fail3:
452 	DTRACE_PROBE(fail3);
453 
454 	sfxge_phy_fini(sp);
455 fail2:
456 	DTRACE_PROBE(fail2);
457 
458 	/* Destroy the link poll taskq */
459 	ddi_taskq_destroy(smp->sm_tqp);
460 	smp->sm_tqp = NULL;
461 
462 fail1:
463 	DTRACE_PROBE1(fail1, int, rc);
464 
465 	cv_destroy(&(smp->sm_link_poll_kv));
466 
467 	mutex_destroy(&(smp->sm_lock));
468 
469 	smp->sm_sp = NULL;
470 
471 	return (rc);
472 }
473 
474 static int
475 sfxge_mac_filter_apply(sfxge_t *sp)
476 {
477 	efx_nic_t *enp = sp->s_enp;
478 	sfxge_mac_t *smp = &(sp->s_mac);
479 	int rc;
480 
481 	ASSERT(mutex_owned(&(smp->sm_lock)));
482 
483 	if (smp->sm_state == SFXGE_MAC_STARTED) {
484 		boolean_t all_unicst;
485 		boolean_t mulcst;
486 		boolean_t all_mulcst;
487 		boolean_t brdcst;
488 
489 		all_unicst = (smp->sm_promisc == SFXGE_PROMISC_ALL_PHYS);
490 		mulcst = (smp->sm_mcast_count > 0);
491 		all_mulcst = (smp->sm_promisc >= SFXGE_PROMISC_ALL_MULTI);
492 		brdcst = B_TRUE;
493 
494 		if ((rc = efx_mac_filter_set(enp, all_unicst, mulcst,
495 		    all_mulcst, brdcst)) != 0) {
496 			goto fail1;
497 		}
498 		if ((rc = efx_mac_multicast_list_set(enp,
499 		    smp->sm_mcast_addr, smp->sm_mcast_count)) != 0)
500 			goto fail2;
501 	}
502 
503 	return (0);
504 
505 fail2:
506 	DTRACE_PROBE(fail2);
507 fail1:
508 	DTRACE_PROBE1(fail1, int, rc);
509 
510 	return (rc);
511 }
512 
513 int
514 sfxge_mac_start(sfxge_t *sp, boolean_t restart)
515 {
516 	sfxge_mac_t *smp = &(sp->s_mac);
517 	efsys_mem_t *esmp = &(smp->sm_mem);
518 	efx_nic_t *enp = sp->s_enp;
519 	size_t pdu;
520 	int rc;
521 
522 	mutex_enter(&(smp->sm_lock));
523 
524 	ASSERT3U(smp->sm_state, ==, SFXGE_MAC_INITIALIZED);
525 
526 	if ((rc = efx_port_init(enp)) != 0)
527 		goto fail1;
528 
529 	/*
530 	 * Set up the advertised capabilities that may have been asked for
531 	 * before the call to efx_port_init().
532 	 */
533 	if ((rc = sfxge_phy_cap_apply(sp, !restart)) != 0)
534 		goto fail2;
535 
536 	/* Set the SDU */
537 	pdu = EFX_MAC_PDU(sp->s_mtu);
538 	if ((rc = efx_mac_pdu_set(enp, pdu)) != 0)
539 		goto fail3;
540 
541 	if ((rc = efx_mac_fcntl_set(enp, smp->sm_fcntl, B_TRUE)) != 0)
542 		goto fail4;
543 
544 	/* Set the unicast address */
545 	if ((rc = efx_mac_addr_set(enp, (smp->sm_laa_valid) ?
546 	    smp->sm_laa : smp->sm_bia)) != 0)
547 		goto fail5;
548 
549 	if ((rc = sfxge_mac_filter_apply(sp)) != 0)
550 		goto fail6;
551 
552 	if (!smp->sm_mac_stats_timer_reqd) {
553 		if ((rc = efx_mac_stats_periodic(enp, esmp,
554 		    SFXGE_MAC_POLL_PERIOD_MS, B_FALSE)) != 0)
555 			goto fail7;
556 	}
557 
558 	if ((rc = efx_mac_drain(enp, B_FALSE)) != 0)
559 		goto fail8;
560 
561 	smp->sm_state = SFXGE_MAC_STARTED;
562 
563 	/*
564 	 * Start link state polling. For hardware that reports link change
565 	 * events we still poll once to update the initial link state.
566 	 */
567 	sfxge_mac_poll_start(sp);
568 
569 	mutex_exit(&(smp->sm_lock));
570 	return (0);
571 
572 fail8:
573 	DTRACE_PROBE(fail8);
574 	(void) efx_mac_stats_periodic(enp, esmp, 0, B_FALSE);
575 fail7:
576 	DTRACE_PROBE(fail7);
577 fail6:
578 	DTRACE_PROBE(fail6);
579 fail5:
580 	DTRACE_PROBE(fail5);
581 fail4:
582 	DTRACE_PROBE(fail4);
583 fail3:
584 	DTRACE_PROBE(fail3);
585 fail2:
586 	DTRACE_PROBE(fail2);
587 	efx_port_fini(enp);
588 fail1:
589 	DTRACE_PROBE1(fail1, int, rc);
590 
591 	mutex_exit(&(smp->sm_lock));
592 
593 	return (rc);
594 }
595 
596 
597 static void
598 sfxge_mac_link_update_locked(sfxge_t *sp, efx_link_mode_t mode)
599 {
600 	sfxge_mac_t *smp = &(sp->s_mac);
601 	const char *change, *duplex;
602 	char info[sizeof (": now 10000Mbps FULL duplex")];
603 
604 	ASSERT(mutex_owned(&(smp->sm_lock)));
605 	if (smp->sm_state != SFXGE_MAC_STARTED)
606 		return;
607 
608 	if (smp->sm_link_mode == mode)
609 		return;
610 
611 	smp->sm_link_mode = mode;
612 	smp->sm_link_up = B_TRUE;
613 
614 	switch (smp->sm_link_mode) {
615 	case EFX_LINK_UNKNOWN:
616 	case EFX_LINK_DOWN:
617 		smp->sm_link_speed = 0;
618 		smp->sm_link_duplex = SFXGE_LINK_DUPLEX_UNKNOWN;
619 		smp->sm_link_up = B_FALSE;
620 		break;
621 
622 	case EFX_LINK_10HDX:
623 	case EFX_LINK_10FDX:
624 		smp->sm_link_speed = 10;
625 		smp->sm_link_duplex = (smp->sm_link_mode == EFX_LINK_10HDX) ?
626 		    SFXGE_LINK_DUPLEX_HALF : SFXGE_LINK_DUPLEX_FULL;
627 		break;
628 
629 	case EFX_LINK_100HDX:
630 	case EFX_LINK_100FDX:
631 		smp->sm_link_speed = 100;
632 		smp->sm_link_duplex = (smp->sm_link_mode == EFX_LINK_100HDX) ?
633 		    SFXGE_LINK_DUPLEX_HALF : SFXGE_LINK_DUPLEX_FULL;
634 		break;
635 
636 	case EFX_LINK_1000HDX:
637 	case EFX_LINK_1000FDX:
638 		smp->sm_link_speed = 1000;
639 		smp->sm_link_duplex = (smp->sm_link_mode == EFX_LINK_1000HDX) ?
640 		    SFXGE_LINK_DUPLEX_HALF : SFXGE_LINK_DUPLEX_FULL;
641 		break;
642 
643 	case EFX_LINK_10000FDX:
644 		smp->sm_link_speed = 10000;
645 		smp->sm_link_duplex = SFXGE_LINK_DUPLEX_FULL;
646 		break;
647 
648 	case EFX_LINK_40000FDX:
649 		smp->sm_link_speed = 40000;
650 		smp->sm_link_duplex = SFXGE_LINK_DUPLEX_FULL;
651 		break;
652 
653 	default:
654 		ASSERT(B_FALSE);
655 		break;
656 	}
657 
658 	duplex = (smp->sm_link_duplex == SFXGE_LINK_DUPLEX_FULL) ?
659 	    "full" : "half";
660 	change = (smp->sm_link_up) ? "UP" : "DOWN";
661 	(void) snprintf(info, sizeof (info), ": now %dMbps %s duplex",
662 	    smp->sm_link_speed, duplex);
663 
664 	dev_err(sp->s_dip, CE_NOTE, SFXGE_CMN_ERR "Link %s%s",
665 	    change, smp->sm_link_up ? info : "");
666 
667 	/* Push link state update to the OS */
668 	sfxge_gld_link_update(sp);
669 }
670 
671 void
672 sfxge_mac_link_update(sfxge_t *sp, efx_link_mode_t mode)
673 {
674 	sfxge_mac_t *smp = &(sp->s_mac);
675 
676 	mutex_enter(&(smp->sm_lock));
677 	sfxge_mac_link_update_locked(sp, mode);
678 	mutex_exit(&(smp->sm_lock));
679 }
680 
681 void
682 sfxge_mac_link_check(sfxge_t *sp, boolean_t *upp)
683 {
684 	sfxge_mac_t *smp = &(sp->s_mac);
685 
686 	mutex_enter(&(smp->sm_lock));
687 	*upp = smp->sm_link_up;
688 	mutex_exit(&(smp->sm_lock));
689 }
690 
691 void
692 sfxge_mac_link_speed_get(sfxge_t *sp, unsigned int *speedp)
693 {
694 	sfxge_mac_t *smp = &(sp->s_mac);
695 
696 	mutex_enter(&(smp->sm_lock));
697 	*speedp = smp->sm_link_speed;
698 	mutex_exit(&(smp->sm_lock));
699 }
700 
701 void
702 sfxge_mac_link_duplex_get(sfxge_t *sp, sfxge_link_duplex_t *duplexp)
703 {
704 	sfxge_mac_t *smp = &(sp->s_mac);
705 
706 	mutex_enter(&(smp->sm_lock));
707 	*duplexp = smp->sm_link_duplex;
708 	mutex_exit(&(smp->sm_lock));
709 }
710 
711 void
712 sfxge_mac_fcntl_get(sfxge_t *sp, unsigned int *fcntlp)
713 {
714 	sfxge_mac_t *smp = &(sp->s_mac);
715 
716 	mutex_enter(&(smp->sm_lock));
717 	*fcntlp = smp->sm_fcntl;
718 	mutex_exit(&(smp->sm_lock));
719 }
720 
721 int
722 sfxge_mac_fcntl_set(sfxge_t *sp, unsigned int fcntl)
723 {
724 	sfxge_mac_t *smp = &(sp->s_mac);
725 	int rc;
726 
727 	mutex_enter(&(smp->sm_lock));
728 
729 	if (smp->sm_fcntl == fcntl)
730 		goto done;
731 
732 	smp->sm_fcntl = fcntl;
733 
734 	if (smp->sm_state != SFXGE_MAC_STARTED)
735 		goto done;
736 
737 	if ((rc = efx_mac_fcntl_set(sp->s_enp, smp->sm_fcntl, B_TRUE)) != 0)
738 		goto fail1;
739 
740 done:
741 	mutex_exit(&(smp->sm_lock));
742 
743 	return (0);
744 
745 fail1:
746 	DTRACE_PROBE1(fail1, int, rc);
747 
748 	mutex_exit(&(smp->sm_lock));
749 
750 	return (rc);
751 }
752 
753 int
754 sfxge_mac_unicst_get(sfxge_t *sp, sfxge_unicst_type_t type, uint8_t *addr)
755 {
756 	sfxge_mac_t *smp = &(sp->s_mac);
757 	int rc;
758 
759 	if (type >= SFXGE_UNICST_NTYPES) {
760 		rc = EINVAL;
761 		goto fail1;
762 	}
763 
764 	mutex_enter(&(smp->sm_lock));
765 
766 	if (smp->sm_state != SFXGE_MAC_INITIALIZED &&
767 	    smp->sm_state != SFXGE_MAC_STARTED) {
768 		rc = EFAULT;
769 		goto fail2;
770 	}
771 
772 	switch (type) {
773 	case SFXGE_UNICST_BIA:
774 		bcopy(smp->sm_bia, addr, ETHERADDRL);
775 		break;
776 
777 	case SFXGE_UNICST_LAA:
778 		if (!(smp->sm_laa_valid)) {
779 			rc = ENOENT;
780 			goto fail3;
781 		}
782 
783 		bcopy(smp->sm_laa, addr, ETHERADDRL);
784 		break;
785 
786 	default:
787 		ASSERT(B_FALSE);
788 		break;
789 	}
790 
791 	mutex_exit(&(smp->sm_lock));
792 
793 	return (0);
794 
795 
796 fail3:
797 	DTRACE_PROBE(fail3);
798 fail2:
799 	DTRACE_PROBE(fail2);
800 
801 	mutex_exit(&(smp->sm_lock));
802 
803 fail1:
804 	DTRACE_PROBE1(fail1, int, rc);
805 
806 	return (rc);
807 }
808 
809 int
810 sfxge_mac_unicst_set(sfxge_t *sp, uint8_t *addr)
811 {
812 	sfxge_mac_t *smp = &(sp->s_mac);
813 	efx_nic_t *enp = sp->s_enp;
814 	boolean_t old_mac_valid;
815 	uint8_t old_mac[ETHERADDRL];
816 	int rc;
817 
818 	mutex_enter(&(smp->sm_lock));
819 
820 	old_mac_valid = smp->sm_laa_valid;
821 	if (old_mac_valid)
822 		bcopy(smp->sm_laa, old_mac, ETHERADDRL);
823 
824 	bcopy(addr, smp->sm_laa, ETHERADDRL);
825 	smp->sm_laa_valid = B_TRUE;
826 
827 	if (smp->sm_state != SFXGE_MAC_STARTED)
828 		goto done;
829 
830 	if (efx_nic_cfg_get(enp)->enc_allow_set_mac_with_installed_filters) {
831 		if ((rc = efx_mac_addr_set(enp, smp->sm_laa)) != 0) {
832 			dev_err(sp->s_dip, CE_NOTE, SFXGE_CMN_ERR
833 			    "unable to set unicast MAC filter");
834 			goto fail1;
835 		}
836 	} else {
837 		/* Older EF10 firmware requires a device start */
838 		mutex_exit(&smp->sm_lock);
839 		sfxge_stop(sp);
840 		if ((rc = sfxge_start(sp, B_TRUE)) != 0) {
841 			dev_err(sp->s_dip, CE_NOTE, SFXGE_CMN_ERR
842 			    "unable to restart with a new MAC");
843 			mutex_enter(&(smp->sm_lock));
844 			goto fail1;
845 		}
846 		mutex_enter(&smp->sm_lock);
847 	}
848 
849 	if ((rc = efx_mac_addr_set(enp, smp->sm_laa)) != 0)
850 		goto fail1;
851 
852 done:
853 	mutex_exit(&(smp->sm_lock));
854 
855 	return (0);
856 
857 fail1:
858 	if (old_mac_valid)
859 		bcopy(old_mac, smp->sm_laa, ETHERADDRL);
860 	else
861 		smp->sm_laa_valid = B_FALSE;
862 
863 	DTRACE_PROBE1(fail1, int, rc);
864 
865 	mutex_exit(&(smp->sm_lock));
866 
867 	return (rc);
868 }
869 
870 int
871 sfxge_mac_promisc_set(sfxge_t *sp, sfxge_promisc_type_t promisc)
872 {
873 	sfxge_mac_t *smp = &(sp->s_mac);
874 	int rc;
875 
876 	mutex_enter(&(smp->sm_lock));
877 
878 	if (smp->sm_promisc == promisc)
879 		goto done;
880 
881 	smp->sm_promisc = promisc;
882 
883 	if ((rc = sfxge_mac_filter_apply(sp)) != 0)
884 		goto fail1;
885 
886 done:
887 	mutex_exit(&(smp->sm_lock));
888 	return (0);
889 
890 fail1:
891 	DTRACE_PROBE1(fail1, int, rc);
892 	mutex_exit(&(smp->sm_lock));
893 
894 	return (rc);
895 }
896 
897 int
898 sfxge_mac_multicst_add(sfxge_t *sp, const uint8_t *addr)
899 {
900 	sfxge_mac_t *smp = &(sp->s_mac);
901 	int i;
902 	int rc;
903 
904 	mutex_enter(&(smp->sm_lock));
905 
906 	if ((addr[0] & 0x1) == 0) {
907 		rc = EINVAL;
908 		goto fail1;
909 	}
910 
911 	/* Check if the address is already in the list */
912 	i = 0;
913 	while (i < smp->sm_mcast_count) {
914 		if (bcmp(smp->sm_mcast_addr + (i * ETHERADDRL),
915 		    addr, ETHERADDRL) == 0)
916 			goto done;
917 		else
918 			i++;
919 	}
920 
921 	if (smp->sm_mcast_count >= EFX_MAC_MULTICAST_LIST_MAX) {
922 		rc = ENOENT;
923 		goto fail1;
924 	}
925 
926 	/* Add to the list */
927 	bcopy(addr, smp->sm_mcast_addr + (smp->sm_mcast_count++ * ETHERADDRL),
928 	    ETHERADDRL);
929 
930 	if ((rc = sfxge_mac_filter_apply(sp)) != 0)
931 		goto fail2;
932 
933 done:
934 	mutex_exit(&(smp->sm_lock));
935 	return (0);
936 
937 fail2:
938 	DTRACE_PROBE(fail2);
939 	smp->sm_mcast_count--;
940 fail1:
941 	DTRACE_PROBE1(fail1, int, rc);
942 	mutex_exit(&(smp->sm_lock));
943 
944 	return (rc);
945 }
946 
947 int
948 sfxge_mac_multicst_remove(sfxge_t *sp, const uint8_t *addr)
949 {
950 	sfxge_mac_t *smp = &(sp->s_mac);
951 	int i;
952 	int rc;
953 
954 	mutex_enter(&(smp->sm_lock));
955 
956 	i = 0;
957 	while (i < smp->sm_mcast_count) {
958 		if (bcmp(smp->sm_mcast_addr + (i * ETHERADDRL),
959 		    addr, ETHERADDRL) == 0) {
960 			(void) memmove(smp->sm_mcast_addr + (i * ETHERADDRL),
961 			    smp->sm_mcast_addr + ((i + 1) * ETHERADDRL),
962 			    (smp->sm_mcast_count - (i + 1)) * ETHERADDRL);
963 			smp->sm_mcast_count--;
964 		} else
965 			i++;
966 	}
967 
968 	if ((rc = sfxge_mac_filter_apply(sp)) != 0)
969 		goto fail1;
970 
971 	mutex_exit(&(smp->sm_lock));
972 	return (0);
973 
974 fail1:
975 	DTRACE_PROBE1(fail1, int, rc);
976 	mutex_exit(&(smp->sm_lock));
977 
978 	return (rc);
979 }
980 
981 void
982 sfxge_mac_stop(sfxge_t *sp)
983 {
984 	sfxge_mac_t *smp = &(sp->s_mac);
985 	efx_nic_t *enp = sp->s_enp;
986 	efsys_mem_t *esmp = &(smp->sm_mem);
987 
988 	mutex_enter(&(smp->sm_lock));
989 
990 	ASSERT3U(smp->sm_state, ==, SFXGE_MAC_STARTED);
991 	ASSERT3P(smp->sm_sp, ==, sp);
992 	smp->sm_state = SFXGE_MAC_INITIALIZED;
993 
994 	/* If stopping in response to an MC reboot this may fail */
995 	if (!smp->sm_mac_stats_timer_reqd)
996 		(void) efx_mac_stats_periodic(enp, esmp, 0, B_FALSE);
997 
998 	sfxge_mac_poll_stop(sp);
999 
1000 	smp->sm_lbolt = 0;
1001 
1002 	smp->sm_link_up = B_FALSE;
1003 	smp->sm_link_speed = 0;
1004 	smp->sm_link_duplex = SFXGE_LINK_DUPLEX_UNKNOWN;
1005 
1006 	/* This may call MCDI */
1007 	(void) efx_mac_drain(enp, B_TRUE);
1008 
1009 	smp->sm_link_mode = EFX_LINK_UNKNOWN;
1010 
1011 	efx_port_fini(enp);
1012 
1013 	mutex_exit(&(smp->sm_lock));
1014 }
1015 
1016 void
1017 sfxge_mac_fini(sfxge_t *sp)
1018 {
1019 	sfxge_mac_t *smp = &(sp->s_mac);
1020 	efsys_mem_t *esmp = &(smp->sm_mem);
1021 
1022 	ASSERT3U(smp->sm_state, ==, SFXGE_MAC_INITIALIZED);
1023 	ASSERT3P(smp->sm_sp, ==, sp);
1024 
1025 	/* Tear down the statistics */
1026 	sfxge_phy_kstat_fini(sp);
1027 	sfxge_mac_kstat_fini(sp);
1028 
1029 	smp->sm_state = SFXGE_MAC_UNINITIALIZED;
1030 	smp->sm_link_mode = EFX_LINK_UNKNOWN;
1031 	smp->sm_promisc = SFXGE_PROMISC_OFF;
1032 
1033 	bzero(smp->sm_mcast_addr, sizeof (smp->sm_mcast_addr));
1034 	smp->sm_mcast_count = 0;
1035 
1036 	bzero(smp->sm_laa, ETHERADDRL);
1037 	smp->sm_laa_valid = B_FALSE;
1038 
1039 	bzero(smp->sm_bia, ETHERADDRL);
1040 
1041 	smp->sm_fcntl = 0;
1042 
1043 	/* Finish with PHY DMA memory */
1044 	sfxge_phy_fini(sp);
1045 
1046 	/* Teardown the DMA */
1047 	sfxge_dma_buffer_destroy(esmp);
1048 
1049 	/* Destroy the link poll taskq */
1050 	ddi_taskq_destroy(smp->sm_tqp);
1051 	smp->sm_tqp = NULL;
1052 
1053 	mutex_destroy(&(smp->sm_lock));
1054 
1055 	smp->sm_sp = NULL;
1056 }
1057