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