xref: /illumos-gate/usr/src/uts/common/io/sfxge/sfxge_ev.c (revision 49ef7e06)
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 #include <sys/types.h>
32*49ef7e06SGarrett D'Amore #include <sys/sysmacros.h>
33*49ef7e06SGarrett D'Amore #include <sys/ddi.h>
34*49ef7e06SGarrett D'Amore #include <sys/sunddi.h>
35*49ef7e06SGarrett D'Amore #include <sys/stream.h>
36*49ef7e06SGarrett D'Amore #include <sys/strsun.h>
37*49ef7e06SGarrett D'Amore #include <sys/strsubr.h>
38*49ef7e06SGarrett D'Amore #include <sys/cpu.h>
39*49ef7e06SGarrett D'Amore #include <sys/pghw.h>
40*49ef7e06SGarrett D'Amore 
41*49ef7e06SGarrett D'Amore #include "sfxge.h"
42*49ef7e06SGarrett D'Amore 
43*49ef7e06SGarrett D'Amore #include "efx.h"
44*49ef7e06SGarrett D'Amore 
45*49ef7e06SGarrett D'Amore 
46*49ef7e06SGarrett D'Amore /* Timeout to wait for DRIVER_EV_START event at EVQ startup */
47*49ef7e06SGarrett D'Amore #define	SFXGE_EV_QSTART_TIMEOUT_USEC	(2000000)
48*49ef7e06SGarrett D'Amore 
49*49ef7e06SGarrett D'Amore 
50*49ef7e06SGarrett D'Amore /* Event queue DMA attributes */
51*49ef7e06SGarrett D'Amore static ddi_device_acc_attr_t sfxge_evq_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_evq_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 	EFX_BUF_SIZE,		/* 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 static int
_sfxge_ev_qctor(sfxge_t * sp,sfxge_evq_t * sep,int kmflags,uint16_t evq_size)74*49ef7e06SGarrett D'Amore _sfxge_ev_qctor(sfxge_t *sp, sfxge_evq_t *sep, int kmflags, uint16_t evq_size)
75*49ef7e06SGarrett D'Amore {
76*49ef7e06SGarrett D'Amore 	efsys_mem_t *esmp = &(sep->se_mem);
77*49ef7e06SGarrett D'Amore 	sfxge_dma_buffer_attr_t dma_attr;
78*49ef7e06SGarrett D'Amore 	int rc;
79*49ef7e06SGarrett D'Amore 
80*49ef7e06SGarrett D'Amore 	/* Compile-time structure layout checks */
81*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(sizeof (sep->__se_u1.__se_s1) <=
82*49ef7e06SGarrett D'Amore 	    sizeof (sep->__se_u1.__se_pad));
83*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(sizeof (sep->__se_u2.__se_s2) <=
84*49ef7e06SGarrett D'Amore 	    sizeof (sep->__se_u2.__se_pad));
85*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(sizeof (sep->__se_u3.__se_s3) <=
86*49ef7e06SGarrett D'Amore 	    sizeof (sep->__se_u3.__se_pad));
87*49ef7e06SGarrett D'Amore 
88*49ef7e06SGarrett D'Amore 	bzero(sep, sizeof (sfxge_evq_t));
89*49ef7e06SGarrett D'Amore 
90*49ef7e06SGarrett D'Amore 	sep->se_sp = sp;
91*49ef7e06SGarrett D'Amore 
92*49ef7e06SGarrett D'Amore 	dma_attr.sdba_dip	 = sp->s_dip;
93*49ef7e06SGarrett D'Amore 	dma_attr.sdba_dattrp	 = &sfxge_evq_dma_attr;
94*49ef7e06SGarrett D'Amore 	dma_attr.sdba_callback	 = (kmflags == KM_SLEEP) ?
95*49ef7e06SGarrett D'Amore 	    DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
96*49ef7e06SGarrett D'Amore 	dma_attr.sdba_length	 = EFX_EVQ_SIZE(evq_size);
97*49ef7e06SGarrett D'Amore 	dma_attr.sdba_memflags	 = DDI_DMA_CONSISTENT;
98*49ef7e06SGarrett D'Amore 	dma_attr.sdba_devaccp	 = &sfxge_evq_devacc;
99*49ef7e06SGarrett D'Amore 	dma_attr.sdba_bindflags	 = DDI_DMA_READ | DDI_DMA_CONSISTENT;
100*49ef7e06SGarrett D'Amore 	dma_attr.sdba_maxcookies = 1;
101*49ef7e06SGarrett D'Amore 	dma_attr.sdba_zeroinit	 = B_FALSE;
102*49ef7e06SGarrett D'Amore 
103*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
104*49ef7e06SGarrett D'Amore 		goto fail1;
105*49ef7e06SGarrett D'Amore 
106*49ef7e06SGarrett D'Amore 	/* Allocate some buffer table entries */
107*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_sram_buf_tbl_alloc(sp, EFX_EVQ_NBUFS(evq_size),
108*49ef7e06SGarrett D'Amore 	    &(sep->se_id))) != 0)
109*49ef7e06SGarrett D'Amore 		goto fail2;
110*49ef7e06SGarrett D'Amore 
111*49ef7e06SGarrett D'Amore 	sep->se_stpp = &(sep->se_stp);
112*49ef7e06SGarrett D'Amore 
113*49ef7e06SGarrett D'Amore 	return (0);
114*49ef7e06SGarrett D'Amore 
115*49ef7e06SGarrett D'Amore fail2:
116*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
117*49ef7e06SGarrett D'Amore 
118*49ef7e06SGarrett D'Amore 	/* Tear down DMA setup */
119*49ef7e06SGarrett D'Amore 	esmp->esm_addr = 0;
120*49ef7e06SGarrett D'Amore 	sfxge_dma_buffer_destroy(esmp);
121*49ef7e06SGarrett D'Amore 
122*49ef7e06SGarrett D'Amore fail1:
123*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
124*49ef7e06SGarrett D'Amore 
125*49ef7e06SGarrett D'Amore 	sep->se_sp = NULL;
126*49ef7e06SGarrett D'Amore 
127*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(sep, sfxge_evq_t);
128*49ef7e06SGarrett D'Amore 
129*49ef7e06SGarrett D'Amore 	return (-1);
130*49ef7e06SGarrett D'Amore }
131*49ef7e06SGarrett D'Amore 
132*49ef7e06SGarrett D'Amore static int
sfxge_ev_q0ctor(void * buf,void * arg,int kmflags)133*49ef7e06SGarrett D'Amore sfxge_ev_q0ctor(void *buf, void *arg, int kmflags)
134*49ef7e06SGarrett D'Amore {
135*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = buf;
136*49ef7e06SGarrett D'Amore 	sfxge_t *sp = arg;
137*49ef7e06SGarrett D'Amore 	return (_sfxge_ev_qctor(sp, sep, kmflags, sp->s_evq0_size));
138*49ef7e06SGarrett D'Amore }
139*49ef7e06SGarrett D'Amore 
140*49ef7e06SGarrett D'Amore static int
sfxge_ev_qXctor(void * buf,void * arg,int kmflags)141*49ef7e06SGarrett D'Amore sfxge_ev_qXctor(void *buf, void *arg, int kmflags)
142*49ef7e06SGarrett D'Amore {
143*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = buf;
144*49ef7e06SGarrett D'Amore 	sfxge_t *sp = arg;
145*49ef7e06SGarrett D'Amore 	return (_sfxge_ev_qctor(sp, sep, kmflags, sp->s_evqX_size));
146*49ef7e06SGarrett D'Amore }
147*49ef7e06SGarrett D'Amore static void
_sfxge_ev_qdtor(sfxge_t * sp,sfxge_evq_t * sep,uint16_t evq_size)148*49ef7e06SGarrett D'Amore _sfxge_ev_qdtor(sfxge_t *sp, sfxge_evq_t *sep, uint16_t evq_size)
149*49ef7e06SGarrett D'Amore {
150*49ef7e06SGarrett D'Amore 	efsys_mem_t *esmp = &(sep->se_mem);
151*49ef7e06SGarrett D'Amore 	ASSERT3P(sep->se_sp, ==, sp);
152*49ef7e06SGarrett D'Amore 	ASSERT3P(sep->se_stpp, ==, &(sep->se_stp));
153*49ef7e06SGarrett D'Amore 	sep->se_stpp = NULL;
154*49ef7e06SGarrett D'Amore 
155*49ef7e06SGarrett D'Amore 	/* Free the buffer table entries */
156*49ef7e06SGarrett D'Amore 	sfxge_sram_buf_tbl_free(sp, sep->se_id, EFX_EVQ_NBUFS(evq_size));
157*49ef7e06SGarrett D'Amore 	sep->se_id = 0;
158*49ef7e06SGarrett D'Amore 
159*49ef7e06SGarrett D'Amore 	/* Tear down DMA setup */
160*49ef7e06SGarrett D'Amore 	sfxge_dma_buffer_destroy(esmp);
161*49ef7e06SGarrett D'Amore 
162*49ef7e06SGarrett D'Amore 	sep->se_sp = NULL;
163*49ef7e06SGarrett D'Amore 
164*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(sep, sfxge_evq_t);
165*49ef7e06SGarrett D'Amore }
166*49ef7e06SGarrett D'Amore 
167*49ef7e06SGarrett D'Amore static void
sfxge_ev_q0dtor(void * buf,void * arg)168*49ef7e06SGarrett D'Amore sfxge_ev_q0dtor(void *buf, void *arg)
169*49ef7e06SGarrett D'Amore {
170*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = buf;
171*49ef7e06SGarrett D'Amore 	sfxge_t *sp = arg;
172*49ef7e06SGarrett D'Amore 	_sfxge_ev_qdtor(sp, sep, sp->s_evq0_size);
173*49ef7e06SGarrett D'Amore }
174*49ef7e06SGarrett D'Amore 
175*49ef7e06SGarrett D'Amore static void
sfxge_ev_qXdtor(void * buf,void * arg)176*49ef7e06SGarrett D'Amore sfxge_ev_qXdtor(void *buf, void *arg)
177*49ef7e06SGarrett D'Amore {
178*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = buf;
179*49ef7e06SGarrett D'Amore 	sfxge_t *sp = arg;
180*49ef7e06SGarrett D'Amore 	_sfxge_ev_qdtor(sp, sep, sp->s_evqX_size);
181*49ef7e06SGarrett D'Amore }
182*49ef7e06SGarrett D'Amore 
183*49ef7e06SGarrett D'Amore static boolean_t
sfxge_ev_initialized(void * arg)184*49ef7e06SGarrett D'Amore sfxge_ev_initialized(void *arg)
185*49ef7e06SGarrett D'Amore {
186*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = arg;
187*49ef7e06SGarrett D'Amore 
188*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
189*49ef7e06SGarrett D'Amore 
190*49ef7e06SGarrett D'Amore 	/* Init done events may be duplicated on 7xxx (see SFCbug31631) */
191*49ef7e06SGarrett D'Amore 	if (sep->se_state == SFXGE_EVQ_STARTED)
192*49ef7e06SGarrett D'Amore 		goto done;
193*49ef7e06SGarrett D'Amore 
194*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_state, ==, SFXGE_EVQ_STARTING);
195*49ef7e06SGarrett D'Amore 	sep->se_state = SFXGE_EVQ_STARTED;
196*49ef7e06SGarrett D'Amore 
197*49ef7e06SGarrett D'Amore 	cv_broadcast(&(sep->se_init_kv));
198*49ef7e06SGarrett D'Amore 
199*49ef7e06SGarrett D'Amore done:
200*49ef7e06SGarrett D'Amore 	return (B_FALSE);
201*49ef7e06SGarrett D'Amore }
202*49ef7e06SGarrett D'Amore 
203*49ef7e06SGarrett D'Amore static void
sfxge_ev_qcomplete(sfxge_evq_t * sep,boolean_t eop)204*49ef7e06SGarrett D'Amore sfxge_ev_qcomplete(sfxge_evq_t *sep, boolean_t eop)
205*49ef7e06SGarrett D'Amore {
206*49ef7e06SGarrett D'Amore 	sfxge_t *sp = sep->se_sp;
207*49ef7e06SGarrett D'Amore 	unsigned int index = sep->se_index;
208*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp = sp->s_srp[index];
209*49ef7e06SGarrett D'Amore 	sfxge_txq_t *stp;
210*49ef7e06SGarrett D'Amore 
211*49ef7e06SGarrett D'Amore 	if ((stp = sep->se_stp) != NULL) {
212*49ef7e06SGarrett D'Amore 		sep->se_stp = NULL;
213*49ef7e06SGarrett D'Amore 		sep->se_stpp = &(sep->se_stp);
214*49ef7e06SGarrett D'Amore 
215*49ef7e06SGarrett D'Amore 		do {
216*49ef7e06SGarrett D'Amore 			sfxge_txq_t *next;
217*49ef7e06SGarrett D'Amore 
218*49ef7e06SGarrett D'Amore 			next = stp->st_next;
219*49ef7e06SGarrett D'Amore 			stp->st_next = NULL;
220*49ef7e06SGarrett D'Amore 
221*49ef7e06SGarrett D'Amore 			ASSERT3U(stp->st_evq, ==, index);
222*49ef7e06SGarrett D'Amore 
223*49ef7e06SGarrett D'Amore 			if (stp->st_pending != stp->st_completed)
224*49ef7e06SGarrett D'Amore 				sfxge_tx_qcomplete(stp);
225*49ef7e06SGarrett D'Amore 
226*49ef7e06SGarrett D'Amore 			stp = next;
227*49ef7e06SGarrett D'Amore 		} while (stp != NULL);
228*49ef7e06SGarrett D'Amore 	}
229*49ef7e06SGarrett D'Amore 
230*49ef7e06SGarrett D'Amore 	if (srp != NULL) {
231*49ef7e06SGarrett D'Amore 		if (srp->sr_pending != srp->sr_completed)
232*49ef7e06SGarrett D'Amore 			sfxge_rx_qcomplete(srp, eop);
233*49ef7e06SGarrett D'Amore 	}
234*49ef7e06SGarrett D'Amore }
235*49ef7e06SGarrett D'Amore 
236*49ef7e06SGarrett D'Amore static boolean_t
sfxge_ev_rx(void * arg,uint32_t label,uint32_t id,uint32_t size,uint16_t flags)237*49ef7e06SGarrett D'Amore sfxge_ev_rx(void *arg, uint32_t label, uint32_t id, uint32_t size,
238*49ef7e06SGarrett D'Amore     uint16_t flags)
239*49ef7e06SGarrett D'Amore {
240*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = arg;
241*49ef7e06SGarrett D'Amore 	sfxge_t *sp = sep->se_sp;
242*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp;
243*49ef7e06SGarrett D'Amore 	sfxge_rx_packet_t *srpp;
244*49ef7e06SGarrett D'Amore 	unsigned int prefetch;
245*49ef7e06SGarrett D'Amore 	unsigned int stop;
246*49ef7e06SGarrett D'Amore 	unsigned int delta;
247*49ef7e06SGarrett D'Amore 
248*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
249*49ef7e06SGarrett D'Amore 
250*49ef7e06SGarrett D'Amore 	if (sep->se_exception)
251*49ef7e06SGarrett D'Amore 		goto done;
252*49ef7e06SGarrett D'Amore 
253*49ef7e06SGarrett D'Amore 	srp = sp->s_srp[label];
254*49ef7e06SGarrett D'Amore 	if (srp == NULL)
255*49ef7e06SGarrett D'Amore 		goto done;
256*49ef7e06SGarrett D'Amore 
257*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_index, ==, srp->sr_index);
258*49ef7e06SGarrett D'Amore 	ASSERT3U(id, <, sp->s_rxq_size);
259*49ef7e06SGarrett D'Amore 
260*49ef7e06SGarrett D'Amore 	/*
261*49ef7e06SGarrett D'Amore 	 * Note that in sfxge_stop() EVQ stopped after RXQ, and will be reset
262*49ef7e06SGarrett D'Amore 	 * So the return missing srp->sr_pending increase is safe
263*49ef7e06SGarrett D'Amore 	 */
264*49ef7e06SGarrett D'Amore 	if (srp->sr_state != SFXGE_RXQ_STARTED)
265*49ef7e06SGarrett D'Amore 		goto done;
266*49ef7e06SGarrett D'Amore 
267*49ef7e06SGarrett D'Amore 	stop = (id + 1) & (sp->s_rxq_size - 1);
268*49ef7e06SGarrett D'Amore 	id = srp->sr_pending & (sp->s_rxq_size - 1);
269*49ef7e06SGarrett D'Amore 
270*49ef7e06SGarrett D'Amore 	delta = (stop >= id) ? (stop - id) : (sp->s_rxq_size - id + stop);
271*49ef7e06SGarrett D'Amore 	srp->sr_pending += delta;
272*49ef7e06SGarrett D'Amore 
273*49ef7e06SGarrett D'Amore 	if (delta != 1) {
274*49ef7e06SGarrett D'Amore 		if ((!efx_nic_cfg_get(sp->s_enp)->enc_rx_batching_enabled) ||
275*49ef7e06SGarrett D'Amore 		    (delta == 0) ||
276*49ef7e06SGarrett D'Amore 		    (delta > efx_nic_cfg_get(sp->s_enp)->enc_rx_batch_max)) {
277*49ef7e06SGarrett D'Amore 			/*
278*49ef7e06SGarrett D'Amore 			 * FIXME: This does not take into account scatter
279*49ef7e06SGarrett D'Amore 			 * aborts.  See Bug40811
280*49ef7e06SGarrett D'Amore 			 */
281*49ef7e06SGarrett D'Amore 			sep->se_exception = B_TRUE;
282*49ef7e06SGarrett D'Amore 
283*49ef7e06SGarrett D'Amore 			DTRACE_PROBE(restart_ev_rx_id);
284*49ef7e06SGarrett D'Amore 			/* sfxge_evq_t->se_lock held */
285*49ef7e06SGarrett D'Amore 			(void) sfxge_restart_dispatch(sp, DDI_SLEEP,
286*49ef7e06SGarrett D'Amore 			    SFXGE_HW_ERR, "Out of order RX event", delta);
287*49ef7e06SGarrett D'Amore 
288*49ef7e06SGarrett D'Amore 			goto done;
289*49ef7e06SGarrett D'Amore 		}
290*49ef7e06SGarrett D'Amore 	}
291*49ef7e06SGarrett D'Amore 
292*49ef7e06SGarrett D'Amore 	prefetch = (id + 4) & (sp->s_rxq_size - 1);
293*49ef7e06SGarrett D'Amore 	if ((srpp = srp->sr_srpp[prefetch]) != NULL)
294*49ef7e06SGarrett D'Amore 		prefetch_read_many(srpp);
295*49ef7e06SGarrett D'Amore 
296*49ef7e06SGarrett D'Amore 	srpp = srp->sr_srpp[id];
297*49ef7e06SGarrett D'Amore 	ASSERT(srpp != NULL);
298*49ef7e06SGarrett D'Amore 	prefetch_read_many(srpp->srp_mp);
299*49ef7e06SGarrett D'Amore 
300*49ef7e06SGarrett D'Amore 	for (; id != stop; id = (id + 1) & (sp->s_rxq_size - 1)) {
301*49ef7e06SGarrett D'Amore 		srpp = srp->sr_srpp[id];
302*49ef7e06SGarrett D'Amore 		ASSERT(srpp != NULL);
303*49ef7e06SGarrett D'Amore 
304*49ef7e06SGarrett D'Amore 		ASSERT3U(srpp->srp_flags, ==, EFX_DISCARD);
305*49ef7e06SGarrett D'Amore 		srpp->srp_flags = flags;
306*49ef7e06SGarrett D'Amore 
307*49ef7e06SGarrett D'Amore 		ASSERT3U(size, <, (1 << 16));
308*49ef7e06SGarrett D'Amore 		srpp->srp_size = (uint16_t)size;
309*49ef7e06SGarrett D'Amore 	}
310*49ef7e06SGarrett D'Amore 
311*49ef7e06SGarrett D'Amore 	sep->se_rx++;
312*49ef7e06SGarrett D'Amore 
313*49ef7e06SGarrett D'Amore 	DTRACE_PROBE2(qlevel, unsigned int, srp->sr_index,
314*49ef7e06SGarrett D'Amore 	    unsigned int, srp->sr_added - srp->sr_pending);
315*49ef7e06SGarrett D'Amore 
316*49ef7e06SGarrett D'Amore 	if (srp->sr_pending - srp->sr_completed >= SFXGE_RX_BATCH)
317*49ef7e06SGarrett D'Amore 		sfxge_ev_qcomplete(sep, B_FALSE);
318*49ef7e06SGarrett D'Amore 
319*49ef7e06SGarrett D'Amore done:
320*49ef7e06SGarrett D'Amore 	/* returning B_TRUE makes efx_ev_qpoll() stop processing events */
321*49ef7e06SGarrett D'Amore 	return (sep->se_rx >= sep->se_ev_batch);
322*49ef7e06SGarrett D'Amore }
323*49ef7e06SGarrett D'Amore 
324*49ef7e06SGarrett D'Amore static boolean_t
sfxge_ev_exception(void * arg,uint32_t code,uint32_t data)325*49ef7e06SGarrett D'Amore sfxge_ev_exception(void *arg, uint32_t code, uint32_t data)
326*49ef7e06SGarrett D'Amore {
327*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = arg;
328*49ef7e06SGarrett D'Amore 	sfxge_t *sp = sep->se_sp;
329*49ef7e06SGarrett D'Amore 
330*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(code))
331*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(data))
332*49ef7e06SGarrett D'Amore 
333*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
334*49ef7e06SGarrett D'Amore 	sep->se_exception = B_TRUE;
335*49ef7e06SGarrett D'Amore 
336*49ef7e06SGarrett D'Amore 	if (code != EFX_EXCEPTION_UNKNOWN_SENSOREVT) {
337*49ef7e06SGarrett D'Amore 
338*49ef7e06SGarrett D'Amore 		DTRACE_PROBE(restart_ev_exception);
339*49ef7e06SGarrett D'Amore 
340*49ef7e06SGarrett D'Amore 		/* sfxge_evq_t->se_lock held */
341*49ef7e06SGarrett D'Amore 		(void) sfxge_restart_dispatch(sp, DDI_SLEEP, SFXGE_HW_ERR,
342*49ef7e06SGarrett D'Amore 		    "Unknown EV", code);
343*49ef7e06SGarrett D'Amore 	}
344*49ef7e06SGarrett D'Amore 
345*49ef7e06SGarrett D'Amore 	return (B_FALSE);
346*49ef7e06SGarrett D'Amore }
347*49ef7e06SGarrett D'Amore 
348*49ef7e06SGarrett D'Amore static boolean_t
sfxge_ev_rxq_flush_done(void * arg,uint32_t rxq_index)349*49ef7e06SGarrett D'Amore sfxge_ev_rxq_flush_done(void *arg, uint32_t rxq_index)
350*49ef7e06SGarrett D'Amore {
351*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep_targetq, *sep = arg;
352*49ef7e06SGarrett D'Amore 	sfxge_t *sp = sep->se_sp;
353*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp;
354*49ef7e06SGarrett D'Amore 	unsigned int index;
355*49ef7e06SGarrett D'Amore 	unsigned int label;
356*49ef7e06SGarrett D'Amore 	uint16_t magic;
357*49ef7e06SGarrett D'Amore 
358*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
359*49ef7e06SGarrett D'Amore 
360*49ef7e06SGarrett D'Amore 	/* Ensure RXQ exists, as events may arrive after RXQ was destroyed */
361*49ef7e06SGarrett D'Amore 	srp = sp->s_srp[rxq_index];
362*49ef7e06SGarrett D'Amore 	if (srp == NULL)
363*49ef7e06SGarrett D'Amore 		goto done;
364*49ef7e06SGarrett D'Amore 
365*49ef7e06SGarrett D'Amore 	/* Process right now if it is the correct event queue */
366*49ef7e06SGarrett D'Amore 	index = srp->sr_index;
367*49ef7e06SGarrett D'Amore 	if (index == sep->se_index) {
368*49ef7e06SGarrett D'Amore 		sfxge_rx_qflush_done(srp);
369*49ef7e06SGarrett D'Amore 		goto done;
370*49ef7e06SGarrett D'Amore 	}
371*49ef7e06SGarrett D'Amore 
372*49ef7e06SGarrett D'Amore 	/* Resend a software event on the correct queue */
373*49ef7e06SGarrett D'Amore 	sep_targetq = sp->s_sep[index];
374*49ef7e06SGarrett D'Amore 
375*49ef7e06SGarrett D'Amore 	if (sep_targetq->se_state != SFXGE_EVQ_STARTED)
376*49ef7e06SGarrett D'Amore 		goto done; /* TBD: state test not under the lock */
377*49ef7e06SGarrett D'Amore 
378*49ef7e06SGarrett D'Amore 	label = rxq_index;
379*49ef7e06SGarrett D'Amore 	ASSERT((label & SFXGE_MAGIC_DMAQ_LABEL_MASK) == label);
380*49ef7e06SGarrett D'Amore 	magic = SFXGE_MAGIC_RX_QFLUSH_DONE | label;
381*49ef7e06SGarrett D'Amore 
382*49ef7e06SGarrett D'Amore 	efx_ev_qpost(sep_targetq->se_eep, magic);
383*49ef7e06SGarrett D'Amore 
384*49ef7e06SGarrett D'Amore done:
385*49ef7e06SGarrett D'Amore 	return (B_FALSE);
386*49ef7e06SGarrett D'Amore }
387*49ef7e06SGarrett D'Amore 
388*49ef7e06SGarrett D'Amore static boolean_t
sfxge_ev_rxq_flush_failed(void * arg,uint32_t rxq_index)389*49ef7e06SGarrett D'Amore sfxge_ev_rxq_flush_failed(void *arg, uint32_t rxq_index)
390*49ef7e06SGarrett D'Amore {
391*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep_targetq, *sep = arg;
392*49ef7e06SGarrett D'Amore 	sfxge_t *sp = sep->se_sp;
393*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp;
394*49ef7e06SGarrett D'Amore 	unsigned int index;
395*49ef7e06SGarrett D'Amore 	unsigned int label;
396*49ef7e06SGarrett D'Amore 	uint16_t magic;
397*49ef7e06SGarrett D'Amore 
398*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
399*49ef7e06SGarrett D'Amore 
400*49ef7e06SGarrett D'Amore 	/* Ensure RXQ exists, as events may arrive after RXQ was destroyed */
401*49ef7e06SGarrett D'Amore 	srp = sp->s_srp[rxq_index];
402*49ef7e06SGarrett D'Amore 	if (srp == NULL)
403*49ef7e06SGarrett D'Amore 		goto done;
404*49ef7e06SGarrett D'Amore 
405*49ef7e06SGarrett D'Amore 	/* Process right now if it is the correct event queue */
406*49ef7e06SGarrett D'Amore 	index = srp->sr_index;
407*49ef7e06SGarrett D'Amore 	if (index == sep->se_index) {
408*49ef7e06SGarrett D'Amore 		sfxge_rx_qflush_failed(srp);
409*49ef7e06SGarrett D'Amore 		goto done;
410*49ef7e06SGarrett D'Amore 	}
411*49ef7e06SGarrett D'Amore 
412*49ef7e06SGarrett D'Amore 	/* Resend a software event on the correct queue */
413*49ef7e06SGarrett D'Amore 	sep_targetq = sp->s_sep[index];
414*49ef7e06SGarrett D'Amore 
415*49ef7e06SGarrett D'Amore 	label = rxq_index;
416*49ef7e06SGarrett D'Amore 	ASSERT((label & SFXGE_MAGIC_DMAQ_LABEL_MASK) == label);
417*49ef7e06SGarrett D'Amore 	magic = SFXGE_MAGIC_RX_QFLUSH_FAILED | label;
418*49ef7e06SGarrett D'Amore 
419*49ef7e06SGarrett D'Amore 	if (sep_targetq->se_state != SFXGE_EVQ_STARTED)
420*49ef7e06SGarrett D'Amore 		goto done; /* TBD: state test not under the lock */
421*49ef7e06SGarrett D'Amore 
422*49ef7e06SGarrett D'Amore 	efx_ev_qpost(sep_targetq->se_eep, magic);
423*49ef7e06SGarrett D'Amore 
424*49ef7e06SGarrett D'Amore done:
425*49ef7e06SGarrett D'Amore 	return (B_FALSE);
426*49ef7e06SGarrett D'Amore }
427*49ef7e06SGarrett D'Amore 
428*49ef7e06SGarrett D'Amore static boolean_t
sfxge_ev_tx(void * arg,uint32_t label,uint32_t id)429*49ef7e06SGarrett D'Amore sfxge_ev_tx(void *arg, uint32_t label, uint32_t id)
430*49ef7e06SGarrett D'Amore {
431*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = arg;
432*49ef7e06SGarrett D'Amore 	sfxge_txq_t *stp;
433*49ef7e06SGarrett D'Amore 	unsigned int stop;
434*49ef7e06SGarrett D'Amore 	unsigned int delta;
435*49ef7e06SGarrett D'Amore 
436*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
437*49ef7e06SGarrett D'Amore 
438*49ef7e06SGarrett D'Amore 	stp = sep->se_label_stp[label];
439*49ef7e06SGarrett D'Amore 	if (stp == NULL)
440*49ef7e06SGarrett D'Amore 		goto done;
441*49ef7e06SGarrett D'Amore 
442*49ef7e06SGarrett D'Amore 	if (stp->st_state != SFXGE_TXQ_STARTED)
443*49ef7e06SGarrett D'Amore 		goto done;
444*49ef7e06SGarrett D'Amore 
445*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_index, ==, stp->st_evq);
446*49ef7e06SGarrett D'Amore 
447*49ef7e06SGarrett D'Amore 	stop = (id + 1) & (SFXGE_TX_NDESCS - 1);
448*49ef7e06SGarrett D'Amore 	id = stp->st_pending & (SFXGE_TX_NDESCS - 1);
449*49ef7e06SGarrett D'Amore 
450*49ef7e06SGarrett D'Amore 	delta = (stop >= id) ? (stop - id) : (SFXGE_TX_NDESCS - id + stop);
451*49ef7e06SGarrett D'Amore 	stp->st_pending += delta;
452*49ef7e06SGarrett D'Amore 
453*49ef7e06SGarrett D'Amore 	sep->se_tx++;
454*49ef7e06SGarrett D'Amore 
455*49ef7e06SGarrett D'Amore 	if (stp->st_next == NULL &&
456*49ef7e06SGarrett D'Amore 	    sep->se_stpp != &(stp->st_next)) {
457*49ef7e06SGarrett D'Amore 		*(sep->se_stpp) = stp;
458*49ef7e06SGarrett D'Amore 		sep->se_stpp = &(stp->st_next);
459*49ef7e06SGarrett D'Amore 	}
460*49ef7e06SGarrett D'Amore 
461*49ef7e06SGarrett D'Amore 	DTRACE_PROBE2(qlevel, unsigned int, stp->st_index,
462*49ef7e06SGarrett D'Amore 	    unsigned int, stp->st_added - stp->st_pending);
463*49ef7e06SGarrett D'Amore 
464*49ef7e06SGarrett D'Amore 	if (stp->st_pending - stp->st_completed >= SFXGE_TX_BATCH)
465*49ef7e06SGarrett D'Amore 		sfxge_tx_qcomplete(stp);
466*49ef7e06SGarrett D'Amore 
467*49ef7e06SGarrett D'Amore done:
468*49ef7e06SGarrett D'Amore 	/* returning B_TRUE makes efx_ev_qpoll() stop processing events */
469*49ef7e06SGarrett D'Amore 	return (sep->se_tx >= sep->se_ev_batch);
470*49ef7e06SGarrett D'Amore }
471*49ef7e06SGarrett D'Amore 
472*49ef7e06SGarrett D'Amore static boolean_t
sfxge_ev_txq_flush_done(void * arg,uint32_t txq_index)473*49ef7e06SGarrett D'Amore sfxge_ev_txq_flush_done(void *arg, uint32_t txq_index)
474*49ef7e06SGarrett D'Amore {
475*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = arg;
476*49ef7e06SGarrett D'Amore 	sfxge_t *sp = sep->se_sp;
477*49ef7e06SGarrett D'Amore 	sfxge_txq_t *stp;
478*49ef7e06SGarrett D'Amore 	unsigned int evq;
479*49ef7e06SGarrett D'Amore 	unsigned int label;
480*49ef7e06SGarrett D'Amore 	uint16_t magic;
481*49ef7e06SGarrett D'Amore 
482*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
483*49ef7e06SGarrett D'Amore 
484*49ef7e06SGarrett D'Amore 	/* Ensure TXQ exists, as events may arrive after TXQ was destroyed */
485*49ef7e06SGarrett D'Amore 	stp = sp->s_stp[txq_index];
486*49ef7e06SGarrett D'Amore 	if (stp == NULL)
487*49ef7e06SGarrett D'Amore 		goto done;
488*49ef7e06SGarrett D'Amore 
489*49ef7e06SGarrett D'Amore 	/* Process right now if it is the correct event queue */
490*49ef7e06SGarrett D'Amore 	evq = stp->st_evq;
491*49ef7e06SGarrett D'Amore 	if (evq == sep->se_index) {
492*49ef7e06SGarrett D'Amore 		sfxge_tx_qflush_done(stp);
493*49ef7e06SGarrett D'Amore 		goto done;
494*49ef7e06SGarrett D'Amore 	}
495*49ef7e06SGarrett D'Amore 
496*49ef7e06SGarrett D'Amore 	/* Resend a software event on the correct queue */
497*49ef7e06SGarrett D'Amore 	sep = sp->s_sep[evq];
498*49ef7e06SGarrett D'Amore 
499*49ef7e06SGarrett D'Amore 	label = stp->st_label;
500*49ef7e06SGarrett D'Amore 
501*49ef7e06SGarrett D'Amore 	ASSERT((label & SFXGE_MAGIC_DMAQ_LABEL_MASK) == label);
502*49ef7e06SGarrett D'Amore 	magic = SFXGE_MAGIC_TX_QFLUSH_DONE | label;
503*49ef7e06SGarrett D'Amore 
504*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_state, ==, SFXGE_EVQ_STARTED);
505*49ef7e06SGarrett D'Amore 	efx_ev_qpost(sep->se_eep, magic);
506*49ef7e06SGarrett D'Amore 
507*49ef7e06SGarrett D'Amore done:
508*49ef7e06SGarrett D'Amore 	return (B_FALSE);
509*49ef7e06SGarrett D'Amore }
510*49ef7e06SGarrett D'Amore 
511*49ef7e06SGarrett D'Amore static boolean_t
sfxge_ev_software(void * arg,uint16_t magic)512*49ef7e06SGarrett D'Amore sfxge_ev_software(void *arg, uint16_t magic)
513*49ef7e06SGarrett D'Amore {
514*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = arg;
515*49ef7e06SGarrett D'Amore 	sfxge_t *sp = sep->se_sp;
516*49ef7e06SGarrett D'Amore 	dev_info_t *dip = sp->s_dip;
517*49ef7e06SGarrett D'Amore 	unsigned int label;
518*49ef7e06SGarrett D'Amore 
519*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
520*49ef7e06SGarrett D'Amore 
521*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(SFXGE_MAGIC_DMAQ_LABEL_WIDTH ==
522*49ef7e06SGarrett D'Amore 	    FSF_AZ_RX_EV_Q_LABEL_WIDTH);
523*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(SFXGE_MAGIC_DMAQ_LABEL_WIDTH ==
524*49ef7e06SGarrett D'Amore 	    FSF_AZ_TX_EV_Q_LABEL_WIDTH);
525*49ef7e06SGarrett D'Amore 
526*49ef7e06SGarrett D'Amore 	label = magic & SFXGE_MAGIC_DMAQ_LABEL_MASK;
527*49ef7e06SGarrett D'Amore 	magic &= ~SFXGE_MAGIC_DMAQ_LABEL_MASK;
528*49ef7e06SGarrett D'Amore 
529*49ef7e06SGarrett D'Amore 	switch (magic) {
530*49ef7e06SGarrett D'Amore 	case SFXGE_MAGIC_RX_QFLUSH_DONE: {
531*49ef7e06SGarrett D'Amore 		sfxge_rxq_t *srp = sp->s_srp[label];
532*49ef7e06SGarrett D'Amore 
533*49ef7e06SGarrett D'Amore 		if (srp != NULL) {
534*49ef7e06SGarrett D'Amore 			ASSERT3U(sep->se_index, ==, srp->sr_index);
535*49ef7e06SGarrett D'Amore 
536*49ef7e06SGarrett D'Amore 			sfxge_rx_qflush_done(srp);
537*49ef7e06SGarrett D'Amore 		}
538*49ef7e06SGarrett D'Amore 		break;
539*49ef7e06SGarrett D'Amore 	}
540*49ef7e06SGarrett D'Amore 	case SFXGE_MAGIC_RX_QFLUSH_FAILED: {
541*49ef7e06SGarrett D'Amore 		sfxge_rxq_t *srp = sp->s_srp[label];
542*49ef7e06SGarrett D'Amore 
543*49ef7e06SGarrett D'Amore 		if (srp != NULL) {
544*49ef7e06SGarrett D'Amore 			ASSERT3U(sep->se_index, ==, srp->sr_index);
545*49ef7e06SGarrett D'Amore 
546*49ef7e06SGarrett D'Amore 			sfxge_rx_qflush_failed(srp);
547*49ef7e06SGarrett D'Amore 		}
548*49ef7e06SGarrett D'Amore 		break;
549*49ef7e06SGarrett D'Amore 	}
550*49ef7e06SGarrett D'Amore 	case SFXGE_MAGIC_RX_QFPP_TRIM: {
551*49ef7e06SGarrett D'Amore 		sfxge_rxq_t *srp = sp->s_srp[label];
552*49ef7e06SGarrett D'Amore 
553*49ef7e06SGarrett D'Amore 		if (srp != NULL) {
554*49ef7e06SGarrett D'Amore 			ASSERT3U(sep->se_index, ==, srp->sr_index);
555*49ef7e06SGarrett D'Amore 
556*49ef7e06SGarrett D'Amore 			sfxge_rx_qfpp_trim(srp);
557*49ef7e06SGarrett D'Amore 		}
558*49ef7e06SGarrett D'Amore 		break;
559*49ef7e06SGarrett D'Amore 	}
560*49ef7e06SGarrett D'Amore 	case SFXGE_MAGIC_TX_QFLUSH_DONE: {
561*49ef7e06SGarrett D'Amore 		sfxge_txq_t *stp = sep->se_label_stp[label];
562*49ef7e06SGarrett D'Amore 
563*49ef7e06SGarrett D'Amore 		if (stp != NULL) {
564*49ef7e06SGarrett D'Amore 			ASSERT3U(sep->se_index, ==, stp->st_evq);
565*49ef7e06SGarrett D'Amore 
566*49ef7e06SGarrett D'Amore 			sfxge_tx_qflush_done(stp);
567*49ef7e06SGarrett D'Amore 		}
568*49ef7e06SGarrett D'Amore 		break;
569*49ef7e06SGarrett D'Amore 	}
570*49ef7e06SGarrett D'Amore 	default:
571*49ef7e06SGarrett D'Amore 		dev_err(dip, CE_NOTE,
572*49ef7e06SGarrett D'Amore 		    SFXGE_CMN_ERR "unknown software event 0x%x", magic);
573*49ef7e06SGarrett D'Amore 		break;
574*49ef7e06SGarrett D'Amore 	}
575*49ef7e06SGarrett D'Amore 
576*49ef7e06SGarrett D'Amore 	return (B_FALSE);
577*49ef7e06SGarrett D'Amore }
578*49ef7e06SGarrett D'Amore 
579*49ef7e06SGarrett D'Amore static boolean_t
sfxge_ev_sram(void * arg,uint32_t code)580*49ef7e06SGarrett D'Amore sfxge_ev_sram(void *arg, uint32_t code)
581*49ef7e06SGarrett D'Amore {
582*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(arg))
583*49ef7e06SGarrett D'Amore 
584*49ef7e06SGarrett D'Amore 	switch (code) {
585*49ef7e06SGarrett D'Amore 	case EFX_SRAM_UPDATE:
586*49ef7e06SGarrett D'Amore 		DTRACE_PROBE(sram_update);
587*49ef7e06SGarrett D'Amore 		break;
588*49ef7e06SGarrett D'Amore 
589*49ef7e06SGarrett D'Amore 	case EFX_SRAM_CLEAR:
590*49ef7e06SGarrett D'Amore 		DTRACE_PROBE(sram_clear);
591*49ef7e06SGarrett D'Amore 		break;
592*49ef7e06SGarrett D'Amore 
593*49ef7e06SGarrett D'Amore 	case EFX_SRAM_ILLEGAL_CLEAR:
594*49ef7e06SGarrett D'Amore 		DTRACE_PROBE(sram_illegal_clear);
595*49ef7e06SGarrett D'Amore 		break;
596*49ef7e06SGarrett D'Amore 
597*49ef7e06SGarrett D'Amore 	default:
598*49ef7e06SGarrett D'Amore 		ASSERT(B_FALSE);
599*49ef7e06SGarrett D'Amore 		break;
600*49ef7e06SGarrett D'Amore 	}
601*49ef7e06SGarrett D'Amore 
602*49ef7e06SGarrett D'Amore 	return (B_FALSE);
603*49ef7e06SGarrett D'Amore }
604*49ef7e06SGarrett D'Amore 
605*49ef7e06SGarrett D'Amore static boolean_t
sfxge_ev_timer(void * arg,uint32_t index)606*49ef7e06SGarrett D'Amore sfxge_ev_timer(void *arg, uint32_t index)
607*49ef7e06SGarrett D'Amore {
608*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(arg, index))
609*49ef7e06SGarrett D'Amore 
610*49ef7e06SGarrett D'Amore 	return (B_FALSE);
611*49ef7e06SGarrett D'Amore }
612*49ef7e06SGarrett D'Amore 
613*49ef7e06SGarrett D'Amore static boolean_t
sfxge_ev_wake_up(void * arg,uint32_t index)614*49ef7e06SGarrett D'Amore sfxge_ev_wake_up(void *arg, uint32_t index)
615*49ef7e06SGarrett D'Amore {
616*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(arg, index))
617*49ef7e06SGarrett D'Amore 
618*49ef7e06SGarrett D'Amore 	return (B_FALSE);
619*49ef7e06SGarrett D'Amore }
620*49ef7e06SGarrett D'Amore 
621*49ef7e06SGarrett D'Amore static boolean_t
sfxge_ev_link_change(void * arg,efx_link_mode_t link_mode)622*49ef7e06SGarrett D'Amore sfxge_ev_link_change(void *arg, efx_link_mode_t	link_mode)
623*49ef7e06SGarrett D'Amore {
624*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = arg;
625*49ef7e06SGarrett D'Amore 	sfxge_t *sp = sep->se_sp;
626*49ef7e06SGarrett D'Amore 
627*49ef7e06SGarrett D'Amore 	sfxge_mac_link_update(sp, link_mode);
628*49ef7e06SGarrett D'Amore 
629*49ef7e06SGarrett D'Amore 	return (B_FALSE);
630*49ef7e06SGarrett D'Amore }
631*49ef7e06SGarrett D'Amore 
632*49ef7e06SGarrett D'Amore static int
sfxge_ev_kstat_update(kstat_t * ksp,int rw)633*49ef7e06SGarrett D'Amore sfxge_ev_kstat_update(kstat_t *ksp, int rw)
634*49ef7e06SGarrett D'Amore {
635*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = ksp->ks_private;
636*49ef7e06SGarrett D'Amore 	kstat_named_t *knp;
637*49ef7e06SGarrett D'Amore 	int rc;
638*49ef7e06SGarrett D'Amore 
639*49ef7e06SGarrett D'Amore 	if (rw != KSTAT_READ) {
640*49ef7e06SGarrett D'Amore 		rc = EACCES;
641*49ef7e06SGarrett D'Amore 		goto fail1;
642*49ef7e06SGarrett D'Amore 	}
643*49ef7e06SGarrett D'Amore 
644*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
645*49ef7e06SGarrett D'Amore 
646*49ef7e06SGarrett D'Amore 	if (sep->se_state != SFXGE_EVQ_STARTED)
647*49ef7e06SGarrett D'Amore 		goto done;
648*49ef7e06SGarrett D'Amore 
649*49ef7e06SGarrett D'Amore 	efx_ev_qstats_update(sep->se_eep, sep->se_stat);
650*49ef7e06SGarrett D'Amore 
651*49ef7e06SGarrett D'Amore 	knp = ksp->ks_data;
652*49ef7e06SGarrett D'Amore 	knp += EV_NQSTATS;
653*49ef7e06SGarrett D'Amore 
654*49ef7e06SGarrett D'Amore 	knp->value.ui64 = sep->se_cpu_id;
655*49ef7e06SGarrett D'Amore 
656*49ef7e06SGarrett D'Amore done:
657*49ef7e06SGarrett D'Amore 	return (0);
658*49ef7e06SGarrett D'Amore 
659*49ef7e06SGarrett D'Amore fail1:
660*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
661*49ef7e06SGarrett D'Amore 
662*49ef7e06SGarrett D'Amore 	return (rc);
663*49ef7e06SGarrett D'Amore }
664*49ef7e06SGarrett D'Amore 
665*49ef7e06SGarrett D'Amore static int
sfxge_ev_kstat_init(sfxge_evq_t * sep)666*49ef7e06SGarrett D'Amore sfxge_ev_kstat_init(sfxge_evq_t *sep)
667*49ef7e06SGarrett D'Amore {
668*49ef7e06SGarrett D'Amore 	sfxge_t *sp = sep->se_sp;
669*49ef7e06SGarrett D'Amore 	unsigned int index = sep->se_index;
670*49ef7e06SGarrett D'Amore 	dev_info_t *dip = sp->s_dip;
671*49ef7e06SGarrett D'Amore 	kstat_t *ksp;
672*49ef7e06SGarrett D'Amore 	kstat_named_t *knp;
673*49ef7e06SGarrett D'Amore 	char name[MAXNAMELEN];
674*49ef7e06SGarrett D'Amore 	unsigned int id;
675*49ef7e06SGarrett D'Amore 	int rc;
676*49ef7e06SGarrett D'Amore 
677*49ef7e06SGarrett D'Amore 	/* Determine the name */
678*49ef7e06SGarrett D'Amore 	(void) snprintf(name, MAXNAMELEN - 1, "%s_evq%04d",
679*49ef7e06SGarrett D'Amore 	    ddi_driver_name(dip), index);
680*49ef7e06SGarrett D'Amore 
681*49ef7e06SGarrett D'Amore 	/* Create the set */
682*49ef7e06SGarrett D'Amore 	if ((ksp = kstat_create((char *)ddi_driver_name(dip),
683*49ef7e06SGarrett D'Amore 	    ddi_get_instance(dip), name, "queue", KSTAT_TYPE_NAMED,
684*49ef7e06SGarrett D'Amore 	    EV_NQSTATS + 1, 0)) == NULL) {
685*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
686*49ef7e06SGarrett D'Amore 		goto fail1;
687*49ef7e06SGarrett D'Amore 	}
688*49ef7e06SGarrett D'Amore 
689*49ef7e06SGarrett D'Amore 	sep->se_ksp = ksp;
690*49ef7e06SGarrett D'Amore 
691*49ef7e06SGarrett D'Amore 	ksp->ks_update = sfxge_ev_kstat_update;
692*49ef7e06SGarrett D'Amore 	ksp->ks_private = sep;
693*49ef7e06SGarrett D'Amore 	ksp->ks_lock = &(sep->se_lock);
694*49ef7e06SGarrett D'Amore 
695*49ef7e06SGarrett D'Amore 	/* Initialise the named stats */
696*49ef7e06SGarrett D'Amore 	sep->se_stat = knp = ksp->ks_data;
697*49ef7e06SGarrett D'Amore 	for (id = 0; id < EV_NQSTATS; id++) {
698*49ef7e06SGarrett D'Amore 		kstat_named_init(knp, (char *)efx_ev_qstat_name(sp->s_enp, id),
699*49ef7e06SGarrett D'Amore 		    KSTAT_DATA_UINT64);
700*49ef7e06SGarrett D'Amore 		knp++;
701*49ef7e06SGarrett D'Amore 	}
702*49ef7e06SGarrett D'Amore 
703*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "cpu", KSTAT_DATA_UINT64);
704*49ef7e06SGarrett D'Amore 
705*49ef7e06SGarrett D'Amore 	kstat_install(ksp);
706*49ef7e06SGarrett D'Amore 	return (0);
707*49ef7e06SGarrett D'Amore 
708*49ef7e06SGarrett D'Amore fail1:
709*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
710*49ef7e06SGarrett D'Amore 
711*49ef7e06SGarrett D'Amore 	return (rc);
712*49ef7e06SGarrett D'Amore }
713*49ef7e06SGarrett D'Amore 
714*49ef7e06SGarrett D'Amore static void
sfxge_ev_kstat_fini(sfxge_evq_t * sep)715*49ef7e06SGarrett D'Amore sfxge_ev_kstat_fini(sfxge_evq_t *sep)
716*49ef7e06SGarrett D'Amore {
717*49ef7e06SGarrett D'Amore 	/* Destroy the set */
718*49ef7e06SGarrett D'Amore 	kstat_delete(sep->se_ksp);
719*49ef7e06SGarrett D'Amore 	sep->se_ksp = NULL;
720*49ef7e06SGarrett D'Amore 	sep->se_stat = NULL;
721*49ef7e06SGarrett D'Amore }
722*49ef7e06SGarrett D'Amore 
pow2_ge(unsigned int n)723*49ef7e06SGarrett D'Amore inline unsigned pow2_ge(unsigned int n) {
724*49ef7e06SGarrett D'Amore 	unsigned int order = 0;
725*49ef7e06SGarrett D'Amore 	ASSERT3U(n, >, 0);
726*49ef7e06SGarrett D'Amore 	while ((1ul << order) < n) ++order;
727*49ef7e06SGarrett D'Amore 	return (1ul << (order));
728*49ef7e06SGarrett D'Amore }
729*49ef7e06SGarrett D'Amore 
730*49ef7e06SGarrett D'Amore static int
sfxge_ev_qinit(sfxge_t * sp,unsigned int index,unsigned int ev_batch)731*49ef7e06SGarrett D'Amore sfxge_ev_qinit(sfxge_t *sp, unsigned int index, unsigned int ev_batch)
732*49ef7e06SGarrett D'Amore {
733*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep;
734*49ef7e06SGarrett D'Amore 	int rc;
735*49ef7e06SGarrett D'Amore 
736*49ef7e06SGarrett D'Amore 	ASSERT3U(index, <, SFXGE_RX_SCALE_MAX);
737*49ef7e06SGarrett D'Amore 
738*49ef7e06SGarrett D'Amore 	sep = kmem_cache_alloc(index ? sp->s_eqXc : sp->s_eq0c, KM_SLEEP);
739*49ef7e06SGarrett D'Amore 	if (sep == NULL) {
740*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
741*49ef7e06SGarrett D'Amore 		goto fail1;
742*49ef7e06SGarrett D'Amore 	}
743*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_state, ==, SFXGE_EVQ_UNINITIALIZED);
744*49ef7e06SGarrett D'Amore 
745*49ef7e06SGarrett D'Amore 	sep->se_index = index;
746*49ef7e06SGarrett D'Amore 
747*49ef7e06SGarrett D'Amore 	mutex_init(&(sep->se_lock), NULL,
748*49ef7e06SGarrett D'Amore 	    MUTEX_DRIVER, DDI_INTR_PRI(sp->s_intr.si_intr_pri));
749*49ef7e06SGarrett D'Amore 
750*49ef7e06SGarrett D'Amore 	cv_init(&(sep->se_init_kv), NULL, CV_DRIVER, NULL);
751*49ef7e06SGarrett D'Amore 
752*49ef7e06SGarrett D'Amore 	/* Initialize the statistics */
753*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_ev_kstat_init(sep)) != 0)
754*49ef7e06SGarrett D'Amore 		goto fail2;
755*49ef7e06SGarrett D'Amore 
756*49ef7e06SGarrett D'Amore 	sep->se_state = SFXGE_EVQ_INITIALIZED;
757*49ef7e06SGarrett D'Amore 	sep->se_ev_batch = (uint16_t)ev_batch;
758*49ef7e06SGarrett D'Amore 	sp->s_sep[index] = sep;
759*49ef7e06SGarrett D'Amore 
760*49ef7e06SGarrett D'Amore 	return (0);
761*49ef7e06SGarrett D'Amore 
762*49ef7e06SGarrett D'Amore fail2:
763*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
764*49ef7e06SGarrett D'Amore 
765*49ef7e06SGarrett D'Amore 	sep->se_index = 0;
766*49ef7e06SGarrett D'Amore 
767*49ef7e06SGarrett D'Amore 	cv_destroy(&(sep->se_init_kv));
768*49ef7e06SGarrett D'Amore 	mutex_destroy(&(sep->se_lock));
769*49ef7e06SGarrett D'Amore 
770*49ef7e06SGarrett D'Amore 	kmem_cache_free(index ? sp->s_eqXc : sp->s_eq0c, sep);
771*49ef7e06SGarrett D'Amore 
772*49ef7e06SGarrett D'Amore fail1:
773*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
774*49ef7e06SGarrett D'Amore 
775*49ef7e06SGarrett D'Amore 	return (rc);
776*49ef7e06SGarrett D'Amore }
777*49ef7e06SGarrett D'Amore 
778*49ef7e06SGarrett D'Amore static int
sfxge_ev_qstart(sfxge_t * sp,unsigned int index)779*49ef7e06SGarrett D'Amore sfxge_ev_qstart(sfxge_t *sp, unsigned int index)
780*49ef7e06SGarrett D'Amore {
781*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
782*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
783*49ef7e06SGarrett D'Amore 	efx_nic_t *enp = sp->s_enp;
784*49ef7e06SGarrett D'Amore 	efx_ev_callbacks_t *eecp;
785*49ef7e06SGarrett D'Amore 	efsys_mem_t *esmp;
786*49ef7e06SGarrett D'Amore 	clock_t timeout;
787*49ef7e06SGarrett D'Amore 	int rc;
788*49ef7e06SGarrett D'Amore 	uint16_t evq_size = index ? sp->s_evqX_size : sp->s_evq0_size;
789*49ef7e06SGarrett D'Amore 
790*49ef7e06SGarrett D'Amore 	mutex_enter(&(sep->se_lock));
791*49ef7e06SGarrett D'Amore 	esmp = &(sep->se_mem);
792*49ef7e06SGarrett D'Amore 
793*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_state, ==, SFXGE_EVQ_INITIALIZED);
794*49ef7e06SGarrett D'Amore 
795*49ef7e06SGarrett D'Amore 	/* Set the memory to all ones */
796*49ef7e06SGarrett D'Amore 	(void) memset(esmp->esm_base, 0xff, EFX_EVQ_SIZE(evq_size));
797*49ef7e06SGarrett D'Amore 
798*49ef7e06SGarrett D'Amore 	/* Program the buffer table */
799*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_sram_buf_tbl_set(sp, sep->se_id, esmp,
800*49ef7e06SGarrett D'Amore 	    EFX_EVQ_NBUFS(evq_size))) != 0)
801*49ef7e06SGarrett D'Amore 		goto fail1;
802*49ef7e06SGarrett D'Amore 
803*49ef7e06SGarrett D'Amore 	/* Set up the event callbacks */
804*49ef7e06SGarrett D'Amore 	eecp = &(sep->se_eec);
805*49ef7e06SGarrett D'Amore 	eecp->eec_initialized = sfxge_ev_initialized;
806*49ef7e06SGarrett D'Amore 	eecp->eec_rx = sfxge_ev_rx;
807*49ef7e06SGarrett D'Amore 	eecp->eec_tx = sfxge_ev_tx;
808*49ef7e06SGarrett D'Amore 	eecp->eec_exception = sfxge_ev_exception;
809*49ef7e06SGarrett D'Amore 	eecp->eec_rxq_flush_done = sfxge_ev_rxq_flush_done;
810*49ef7e06SGarrett D'Amore 	eecp->eec_rxq_flush_failed = sfxge_ev_rxq_flush_failed;
811*49ef7e06SGarrett D'Amore 	eecp->eec_txq_flush_done = sfxge_ev_txq_flush_done;
812*49ef7e06SGarrett D'Amore 	eecp->eec_software = sfxge_ev_software;
813*49ef7e06SGarrett D'Amore 	eecp->eec_sram = sfxge_ev_sram;
814*49ef7e06SGarrett D'Amore 	eecp->eec_wake_up = sfxge_ev_wake_up;
815*49ef7e06SGarrett D'Amore 	eecp->eec_timer = sfxge_ev_timer;
816*49ef7e06SGarrett D'Amore 	eecp->eec_link_change = sfxge_ev_link_change;
817*49ef7e06SGarrett D'Amore 
818*49ef7e06SGarrett D'Amore 	/* Create the event queue */
819*49ef7e06SGarrett D'Amore 	if ((rc = efx_ev_qcreate(enp, index, esmp, evq_size, sep->se_id,
820*49ef7e06SGarrett D'Amore 	    &(sep->se_eep))) != 0)
821*49ef7e06SGarrett D'Amore 		goto fail2;
822*49ef7e06SGarrett D'Amore 
823*49ef7e06SGarrett D'Amore 	/* Set the default moderation */
824*49ef7e06SGarrett D'Amore 	if ((rc = efx_ev_qmoderate(sep->se_eep, sp->s_ev_moderation)) != 0)
825*49ef7e06SGarrett D'Amore 		goto fail3;
826*49ef7e06SGarrett D'Amore 
827*49ef7e06SGarrett D'Amore 	/* Check that interrupts are enabled at the NIC */
828*49ef7e06SGarrett D'Amore 	if (sip->si_state != SFXGE_INTR_STARTED) {
829*49ef7e06SGarrett D'Amore 		rc = EINVAL;
830*49ef7e06SGarrett D'Amore 		goto fail4;
831*49ef7e06SGarrett D'Amore 	}
832*49ef7e06SGarrett D'Amore 
833*49ef7e06SGarrett D'Amore 	sep->se_state = SFXGE_EVQ_STARTING;
834*49ef7e06SGarrett D'Amore 
835*49ef7e06SGarrett D'Amore 	/* Prime the event queue for interrupts */
836*49ef7e06SGarrett D'Amore 	if ((rc = efx_ev_qprime(sep->se_eep, sep->se_count)) != 0)
837*49ef7e06SGarrett D'Amore 		goto fail5;
838*49ef7e06SGarrett D'Amore 
839*49ef7e06SGarrett D'Amore 	/* Wait for the initialization event */
840*49ef7e06SGarrett D'Amore 	timeout = ddi_get_lbolt() + drv_usectohz(SFXGE_EV_QSTART_TIMEOUT_USEC);
841*49ef7e06SGarrett D'Amore 	while (sep->se_state != SFXGE_EVQ_STARTED) {
842*49ef7e06SGarrett D'Amore 		if (cv_timedwait(&(sep->se_init_kv), &(sep->se_lock),
843*49ef7e06SGarrett D'Amore 		    timeout) < 0) {
844*49ef7e06SGarrett D'Amore 			/* Timeout waiting for initialization */
845*49ef7e06SGarrett D'Amore 			dev_info_t *dip = sp->s_dip;
846*49ef7e06SGarrett D'Amore 
847*49ef7e06SGarrett D'Amore 			DTRACE_PROBE(timeout);
848*49ef7e06SGarrett D'Amore 			dev_err(dip, CE_NOTE,
849*49ef7e06SGarrett D'Amore 			    SFXGE_CMN_ERR "evq[%d] qstart timeout", index);
850*49ef7e06SGarrett D'Amore 
851*49ef7e06SGarrett D'Amore 			rc = ETIMEDOUT;
852*49ef7e06SGarrett D'Amore 			goto fail6;
853*49ef7e06SGarrett D'Amore 		}
854*49ef7e06SGarrett D'Amore 	}
855*49ef7e06SGarrett D'Amore 
856*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
857*49ef7e06SGarrett D'Amore 	return (0);
858*49ef7e06SGarrett D'Amore 
859*49ef7e06SGarrett D'Amore fail6:
860*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail6);
861*49ef7e06SGarrett D'Amore 
862*49ef7e06SGarrett D'Amore fail5:
863*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail5);
864*49ef7e06SGarrett D'Amore 
865*49ef7e06SGarrett D'Amore 	sep->se_state = SFXGE_EVQ_INITIALIZED;
866*49ef7e06SGarrett D'Amore 
867*49ef7e06SGarrett D'Amore fail4:
868*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail4);
869*49ef7e06SGarrett D'Amore 
870*49ef7e06SGarrett D'Amore fail3:
871*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
872*49ef7e06SGarrett D'Amore 
873*49ef7e06SGarrett D'Amore 	/* Destroy the event queue */
874*49ef7e06SGarrett D'Amore 	efx_ev_qdestroy(sep->se_eep);
875*49ef7e06SGarrett D'Amore 	sep->se_eep = NULL;
876*49ef7e06SGarrett D'Amore 
877*49ef7e06SGarrett D'Amore fail2:
878*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
879*49ef7e06SGarrett D'Amore 
880*49ef7e06SGarrett D'Amore 	/* Zero out the event handlers */
881*49ef7e06SGarrett D'Amore 	bzero(&(sep->se_eec), sizeof (efx_ev_callbacks_t));
882*49ef7e06SGarrett D'Amore 
883*49ef7e06SGarrett D'Amore 	/* Clear entries from the buffer table */
884*49ef7e06SGarrett D'Amore 	sfxge_sram_buf_tbl_clear(sp, sep->se_id, EFX_EVQ_NBUFS(evq_size));
885*49ef7e06SGarrett D'Amore 
886*49ef7e06SGarrett D'Amore fail1:
887*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
888*49ef7e06SGarrett D'Amore 
889*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
890*49ef7e06SGarrett D'Amore 
891*49ef7e06SGarrett D'Amore 	return (rc);
892*49ef7e06SGarrett D'Amore }
893*49ef7e06SGarrett D'Amore 
894*49ef7e06SGarrett D'Amore int
sfxge_ev_qpoll(sfxge_t * sp,unsigned int index)895*49ef7e06SGarrett D'Amore sfxge_ev_qpoll(sfxge_t *sp, unsigned int index)
896*49ef7e06SGarrett D'Amore {
897*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
898*49ef7e06SGarrett D'Amore 	processorid_t cpu_id;
899*49ef7e06SGarrett D'Amore 	int rc;
900*49ef7e06SGarrett D'Amore 	uint16_t evq_size = index ? sp->s_evqX_size : sp->s_evq0_size;
901*49ef7e06SGarrett D'Amore 
902*49ef7e06SGarrett D'Amore 	mutex_enter(&(sep->se_lock));
903*49ef7e06SGarrett D'Amore 
904*49ef7e06SGarrett D'Amore 	if (sep->se_state != SFXGE_EVQ_STARTING &&
905*49ef7e06SGarrett D'Amore 	    sep->se_state != SFXGE_EVQ_STARTED) {
906*49ef7e06SGarrett D'Amore 		rc = EINVAL;
907*49ef7e06SGarrett D'Amore 		goto fail1;
908*49ef7e06SGarrett D'Amore 	}
909*49ef7e06SGarrett D'Amore 
910*49ef7e06SGarrett D'Amore 	/* Make sure the CPU information is up to date */
911*49ef7e06SGarrett D'Amore 	cpu_id = CPU->cpu_id;
912*49ef7e06SGarrett D'Amore 
913*49ef7e06SGarrett D'Amore 	if (cpu_id != sep->se_cpu_id) {
914*49ef7e06SGarrett D'Amore 		sep->se_cpu_id = cpu_id;
915*49ef7e06SGarrett D'Amore 
916*49ef7e06SGarrett D'Amore 		/* sfxge_evq_t->se_lock held */
917*49ef7e06SGarrett D'Amore 		(void) ddi_taskq_dispatch(sp->s_tqp, sfxge_rx_scale_update, sp,
918*49ef7e06SGarrett D'Amore 		    DDI_NOSLEEP);
919*49ef7e06SGarrett D'Amore 	}
920*49ef7e06SGarrett D'Amore 
921*49ef7e06SGarrett D'Amore 	/* Synchronize the DMA memory for reading */
922*49ef7e06SGarrett D'Amore 	(void) ddi_dma_sync(sep->se_mem.esm_dma_handle,
923*49ef7e06SGarrett D'Amore 	    0,
924*49ef7e06SGarrett D'Amore 	    EFX_EVQ_SIZE(evq_size),
925*49ef7e06SGarrett D'Amore 	    DDI_DMA_SYNC_FORKERNEL);
926*49ef7e06SGarrett D'Amore 
927*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_rx, ==, 0);
928*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_tx, ==, 0);
929*49ef7e06SGarrett D'Amore 	ASSERT3P(sep->se_stp, ==, NULL);
930*49ef7e06SGarrett D'Amore 	ASSERT3P(sep->se_stpp, ==, &(sep->se_stp));
931*49ef7e06SGarrett D'Amore 
932*49ef7e06SGarrett D'Amore 	/* Poll the queue */
933*49ef7e06SGarrett D'Amore 	efx_ev_qpoll(sep->se_eep, &(sep->se_count), &(sep->se_eec),
934*49ef7e06SGarrett D'Amore 	    sep);
935*49ef7e06SGarrett D'Amore 
936*49ef7e06SGarrett D'Amore 	sep->se_rx = 0;
937*49ef7e06SGarrett D'Amore 	sep->se_tx = 0;
938*49ef7e06SGarrett D'Amore 
939*49ef7e06SGarrett D'Amore 	/* Perform any pending completion processing */
940*49ef7e06SGarrett D'Amore 	sfxge_ev_qcomplete(sep, B_TRUE);
941*49ef7e06SGarrett D'Amore 
942*49ef7e06SGarrett D'Amore 	/* Re-prime the event queue for interrupts */
943*49ef7e06SGarrett D'Amore 	if ((rc = efx_ev_qprime(sep->se_eep, sep->se_count)) != 0)
944*49ef7e06SGarrett D'Amore 		goto fail2;
945*49ef7e06SGarrett D'Amore 
946*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
947*49ef7e06SGarrett D'Amore 
948*49ef7e06SGarrett D'Amore 	return (0);
949*49ef7e06SGarrett D'Amore 
950*49ef7e06SGarrett D'Amore fail2:
951*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
952*49ef7e06SGarrett D'Amore fail1:
953*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
954*49ef7e06SGarrett D'Amore 
955*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
956*49ef7e06SGarrett D'Amore 
957*49ef7e06SGarrett D'Amore 	return (rc);
958*49ef7e06SGarrett D'Amore }
959*49ef7e06SGarrett D'Amore 
960*49ef7e06SGarrett D'Amore int
sfxge_ev_qprime(sfxge_t * sp,unsigned int index)961*49ef7e06SGarrett D'Amore sfxge_ev_qprime(sfxge_t *sp, unsigned int index)
962*49ef7e06SGarrett D'Amore {
963*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
964*49ef7e06SGarrett D'Amore 	int rc;
965*49ef7e06SGarrett D'Amore 
966*49ef7e06SGarrett D'Amore 	mutex_enter(&(sep->se_lock));
967*49ef7e06SGarrett D'Amore 
968*49ef7e06SGarrett D'Amore 	if (sep->se_state != SFXGE_EVQ_STARTING &&
969*49ef7e06SGarrett D'Amore 	    sep->se_state != SFXGE_EVQ_STARTED) {
970*49ef7e06SGarrett D'Amore 		rc = EINVAL;
971*49ef7e06SGarrett D'Amore 		goto fail1;
972*49ef7e06SGarrett D'Amore 	}
973*49ef7e06SGarrett D'Amore 
974*49ef7e06SGarrett D'Amore 	if ((rc = efx_ev_qprime(sep->se_eep, sep->se_count)) != 0)
975*49ef7e06SGarrett D'Amore 		goto fail2;
976*49ef7e06SGarrett D'Amore 
977*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
978*49ef7e06SGarrett D'Amore 
979*49ef7e06SGarrett D'Amore 	return (0);
980*49ef7e06SGarrett D'Amore 
981*49ef7e06SGarrett D'Amore fail2:
982*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
983*49ef7e06SGarrett D'Amore fail1:
984*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
985*49ef7e06SGarrett D'Amore 
986*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
987*49ef7e06SGarrett D'Amore 
988*49ef7e06SGarrett D'Amore 	return (rc);
989*49ef7e06SGarrett D'Amore }
990*49ef7e06SGarrett D'Amore 
991*49ef7e06SGarrett D'Amore 
992*49ef7e06SGarrett D'Amore int
sfxge_ev_qmoderate(sfxge_t * sp,unsigned int index,unsigned int us)993*49ef7e06SGarrett D'Amore sfxge_ev_qmoderate(sfxge_t *sp, unsigned int index, unsigned int us)
994*49ef7e06SGarrett D'Amore {
995*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
996*49ef7e06SGarrett D'Amore 	efx_evq_t *eep = sep->se_eep;
997*49ef7e06SGarrett D'Amore 
998*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_state, ==, SFXGE_EVQ_STARTED);
999*49ef7e06SGarrett D'Amore 
1000*49ef7e06SGarrett D'Amore 	return (efx_ev_qmoderate(eep, us));
1001*49ef7e06SGarrett D'Amore }
1002*49ef7e06SGarrett D'Amore 
1003*49ef7e06SGarrett D'Amore static void
sfxge_ev_qstop(sfxge_t * sp,unsigned int index)1004*49ef7e06SGarrett D'Amore sfxge_ev_qstop(sfxge_t *sp, unsigned int index)
1005*49ef7e06SGarrett D'Amore {
1006*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
1007*49ef7e06SGarrett D'Amore 	uint16_t evq_size;
1008*49ef7e06SGarrett D'Amore 
1009*49ef7e06SGarrett D'Amore 	mutex_enter(&(sep->se_lock));
1010*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_state, ==, SFXGE_EVQ_STARTED);
1011*49ef7e06SGarrett D'Amore 	sep->se_state = SFXGE_EVQ_INITIALIZED;
1012*49ef7e06SGarrett D'Amore 	evq_size = index ? sp->s_evqX_size : sp->s_evq0_size;
1013*49ef7e06SGarrett D'Amore 
1014*49ef7e06SGarrett D'Amore 	/* Clear the CPU information */
1015*49ef7e06SGarrett D'Amore 	sep->se_cpu_id = 0;
1016*49ef7e06SGarrett D'Amore 
1017*49ef7e06SGarrett D'Amore 	/* Clear the event count */
1018*49ef7e06SGarrett D'Amore 	sep->se_count = 0;
1019*49ef7e06SGarrett D'Amore 
1020*49ef7e06SGarrett D'Amore 	/* Reset the exception flag */
1021*49ef7e06SGarrett D'Amore 	sep->se_exception = B_FALSE;
1022*49ef7e06SGarrett D'Amore 
1023*49ef7e06SGarrett D'Amore 	/* Destroy the event queue */
1024*49ef7e06SGarrett D'Amore 	efx_ev_qdestroy(sep->se_eep);
1025*49ef7e06SGarrett D'Amore 	sep->se_eep = NULL;
1026*49ef7e06SGarrett D'Amore 
1027*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
1028*49ef7e06SGarrett D'Amore 
1029*49ef7e06SGarrett D'Amore 	/* Zero out the event handlers */
1030*49ef7e06SGarrett D'Amore 	bzero(&(sep->se_eec), sizeof (efx_ev_callbacks_t));
1031*49ef7e06SGarrett D'Amore 
1032*49ef7e06SGarrett D'Amore 	/* Clear entries from the buffer table */
1033*49ef7e06SGarrett D'Amore 	sfxge_sram_buf_tbl_clear(sp, sep->se_id, EFX_EVQ_NBUFS(evq_size));
1034*49ef7e06SGarrett D'Amore }
1035*49ef7e06SGarrett D'Amore 
1036*49ef7e06SGarrett D'Amore static void
sfxge_ev_qfini(sfxge_t * sp,unsigned int index)1037*49ef7e06SGarrett D'Amore sfxge_ev_qfini(sfxge_t *sp, unsigned int index)
1038*49ef7e06SGarrett D'Amore {
1039*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
1040*49ef7e06SGarrett D'Amore 
1041*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_state, ==, SFXGE_EVQ_INITIALIZED);
1042*49ef7e06SGarrett D'Amore 
1043*49ef7e06SGarrett D'Amore 	sp->s_sep[index] = NULL;
1044*49ef7e06SGarrett D'Amore 	sep->se_state = SFXGE_EVQ_UNINITIALIZED;
1045*49ef7e06SGarrett D'Amore 
1046*49ef7e06SGarrett D'Amore 	/* Tear down the statistics */
1047*49ef7e06SGarrett D'Amore 	sfxge_ev_kstat_fini(sep);
1048*49ef7e06SGarrett D'Amore 
1049*49ef7e06SGarrett D'Amore 	cv_destroy(&(sep->se_init_kv));
1050*49ef7e06SGarrett D'Amore 	mutex_destroy(&(sep->se_lock));
1051*49ef7e06SGarrett D'Amore 
1052*49ef7e06SGarrett D'Amore 	sep->se_index = 0;
1053*49ef7e06SGarrett D'Amore 
1054*49ef7e06SGarrett D'Amore 	kmem_cache_free(index ? sp->s_eqXc : sp->s_eq0c, sep);
1055*49ef7e06SGarrett D'Amore }
1056*49ef7e06SGarrett D'Amore 
1057*49ef7e06SGarrett D'Amore int
sfxge_ev_txlabel_alloc(sfxge_t * sp,unsigned int evq,sfxge_txq_t * stp,unsigned int * labelp)1058*49ef7e06SGarrett D'Amore sfxge_ev_txlabel_alloc(sfxge_t *sp, unsigned int evq, sfxge_txq_t *stp,
1059*49ef7e06SGarrett D'Amore     unsigned int *labelp)
1060*49ef7e06SGarrett D'Amore {
1061*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[evq];
1062*49ef7e06SGarrett D'Amore 	sfxge_txq_t **stpp;
1063*49ef7e06SGarrett D'Amore 	unsigned int label;
1064*49ef7e06SGarrett D'Amore 	int rc;
1065*49ef7e06SGarrett D'Amore 
1066*49ef7e06SGarrett D'Amore 	mutex_enter(&(sep->se_lock));
1067*49ef7e06SGarrett D'Amore 
1068*49ef7e06SGarrett D'Amore 	if (stp == NULL || labelp == NULL) {
1069*49ef7e06SGarrett D'Amore 		rc = EINVAL;
1070*49ef7e06SGarrett D'Amore 		goto fail1;
1071*49ef7e06SGarrett D'Amore 	}
1072*49ef7e06SGarrett D'Amore 
1073*49ef7e06SGarrett D'Amore 	stpp = NULL;
1074*49ef7e06SGarrett D'Amore 	for (label = 0; label < SFXGE_TX_NLABELS; label++) {
1075*49ef7e06SGarrett D'Amore 		if (sep->se_label_stp[label] == stp) {
1076*49ef7e06SGarrett D'Amore 			rc = EEXIST;
1077*49ef7e06SGarrett D'Amore 			goto fail2;
1078*49ef7e06SGarrett D'Amore 		}
1079*49ef7e06SGarrett D'Amore 		if ((stpp == NULL) && (sep->se_label_stp[label] == NULL)) {
1080*49ef7e06SGarrett D'Amore 			stpp = &sep->se_label_stp[label];
1081*49ef7e06SGarrett D'Amore 		}
1082*49ef7e06SGarrett D'Amore 	}
1083*49ef7e06SGarrett D'Amore 	if (stpp == NULL) {
1084*49ef7e06SGarrett D'Amore 		rc = ENOSPC;
1085*49ef7e06SGarrett D'Amore 		goto fail3;
1086*49ef7e06SGarrett D'Amore 	}
1087*49ef7e06SGarrett D'Amore 	*stpp = stp;
1088*49ef7e06SGarrett D'Amore 	label = stpp - sep->se_label_stp;
1089*49ef7e06SGarrett D'Amore 
1090*49ef7e06SGarrett D'Amore 	ASSERT3U(label, <, SFXGE_TX_NLABELS);
1091*49ef7e06SGarrett D'Amore 	*labelp = label;
1092*49ef7e06SGarrett D'Amore 
1093*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
1094*49ef7e06SGarrett D'Amore 	return (0);
1095*49ef7e06SGarrett D'Amore 
1096*49ef7e06SGarrett D'Amore fail3:
1097*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
1098*49ef7e06SGarrett D'Amore fail2:
1099*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
1100*49ef7e06SGarrett D'Amore fail1:
1101*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1102*49ef7e06SGarrett D'Amore 
1103*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
1104*49ef7e06SGarrett D'Amore 
1105*49ef7e06SGarrett D'Amore 	return (rc);
1106*49ef7e06SGarrett D'Amore }
1107*49ef7e06SGarrett D'Amore 
1108*49ef7e06SGarrett D'Amore 
1109*49ef7e06SGarrett D'Amore int
sfxge_ev_txlabel_free(sfxge_t * sp,unsigned int evq,sfxge_txq_t * stp,unsigned int label)1110*49ef7e06SGarrett D'Amore sfxge_ev_txlabel_free(sfxge_t *sp, unsigned int evq, sfxge_txq_t *stp,
1111*49ef7e06SGarrett D'Amore     unsigned int label)
1112*49ef7e06SGarrett D'Amore {
1113*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[evq];
1114*49ef7e06SGarrett D'Amore 	int rc;
1115*49ef7e06SGarrett D'Amore 
1116*49ef7e06SGarrett D'Amore 	mutex_enter(&(sep->se_lock));
1117*49ef7e06SGarrett D'Amore 
1118*49ef7e06SGarrett D'Amore 	if (stp == NULL || label > SFXGE_TX_NLABELS) {
1119*49ef7e06SGarrett D'Amore 		rc = EINVAL;
1120*49ef7e06SGarrett D'Amore 		goto fail1;
1121*49ef7e06SGarrett D'Amore 	}
1122*49ef7e06SGarrett D'Amore 
1123*49ef7e06SGarrett D'Amore 	if (sep->se_label_stp[label] != stp) {
1124*49ef7e06SGarrett D'Amore 		rc = EINVAL;
1125*49ef7e06SGarrett D'Amore 		goto fail2;
1126*49ef7e06SGarrett D'Amore 	}
1127*49ef7e06SGarrett D'Amore 	sep->se_label_stp[label] = NULL;
1128*49ef7e06SGarrett D'Amore 
1129*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
1130*49ef7e06SGarrett D'Amore 
1131*49ef7e06SGarrett D'Amore 	return (0);
1132*49ef7e06SGarrett D'Amore 
1133*49ef7e06SGarrett D'Amore fail2:
1134*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
1135*49ef7e06SGarrett D'Amore fail1:
1136*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1137*49ef7e06SGarrett D'Amore 
1138*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
1139*49ef7e06SGarrett D'Amore 
1140*49ef7e06SGarrett D'Amore 	return (rc);
1141*49ef7e06SGarrett D'Amore }
1142*49ef7e06SGarrett D'Amore 
1143*49ef7e06SGarrett D'Amore 
1144*49ef7e06SGarrett D'Amore static 	kmem_cache_t *
sfxge_ev_kmem_cache_create(sfxge_t * sp,const char * qname,int (* ctor)(void *,void *,int),void (* dtor)(void *,void *))1145*49ef7e06SGarrett D'Amore sfxge_ev_kmem_cache_create(sfxge_t *sp, const char *qname,
1146*49ef7e06SGarrett D'Amore     int (*ctor)(void *, void *, int), void (*dtor)(void *, void *))
1147*49ef7e06SGarrett D'Amore {
1148*49ef7e06SGarrett D'Amore 	char name[MAXNAMELEN];
1149*49ef7e06SGarrett D'Amore 	kmem_cache_t *eqc;
1150*49ef7e06SGarrett D'Amore 
1151*49ef7e06SGarrett D'Amore 	(void) snprintf(name, MAXNAMELEN - 1, "%s%d_%s_cache",
1152*49ef7e06SGarrett D'Amore 	    ddi_driver_name(sp->s_dip), ddi_get_instance(sp->s_dip), qname);
1153*49ef7e06SGarrett D'Amore 
1154*49ef7e06SGarrett D'Amore 	eqc = kmem_cache_create(name, sizeof (sfxge_evq_t),
1155*49ef7e06SGarrett D'Amore 	    SFXGE_CPU_CACHE_SIZE, ctor, dtor, NULL, sp, NULL, 0);
1156*49ef7e06SGarrett D'Amore 	ASSERT(eqc != NULL);
1157*49ef7e06SGarrett D'Amore 	return (eqc);
1158*49ef7e06SGarrett D'Amore }
1159*49ef7e06SGarrett D'Amore 
1160*49ef7e06SGarrett D'Amore int
sfxge_ev_init(sfxge_t * sp)1161*49ef7e06SGarrett D'Amore sfxge_ev_init(sfxge_t *sp)
1162*49ef7e06SGarrett D'Amore {
1163*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
1164*49ef7e06SGarrett D'Amore 	unsigned int evq0_size;
1165*49ef7e06SGarrett D'Amore 	unsigned int evqX_size;
1166*49ef7e06SGarrett D'Amore 	unsigned int ev_batch;
1167*49ef7e06SGarrett D'Amore 	int index;
1168*49ef7e06SGarrett D'Amore 	int rc;
1169*49ef7e06SGarrett D'Amore 
1170*49ef7e06SGarrett D'Amore 	ASSERT3U(sip->si_state, ==, SFXGE_INTR_INITIALIZED);
1171*49ef7e06SGarrett D'Amore 
1172*49ef7e06SGarrett D'Amore 	/*
1173*49ef7e06SGarrett D'Amore 	 * Must account for RXQ, TXQ(s); MCDI not event completed at present
1174*49ef7e06SGarrett D'Amore 	 * Note that common code does not completely fill descriptor queues
1175*49ef7e06SGarrett D'Amore 	 */
1176*49ef7e06SGarrett D'Amore 	evqX_size = sp->s_rxq_size + SFXGE_TX_NDESCS;
1177*49ef7e06SGarrett D'Amore 	evq0_size = evqX_size + SFXGE_TX_NDESCS; /* only IP checksum TXQ */
1178*49ef7e06SGarrett D'Amore 	evq0_size += SFXGE_TX_NDESCS; /* no checksums */
1179*49ef7e06SGarrett D'Amore 
1180*49ef7e06SGarrett D'Amore 	ASSERT3U(evqX_size, >=, EFX_EVQ_MINNEVS);
1181*49ef7e06SGarrett D'Amore 	ASSERT3U(evq0_size, >, evqX_size);
1182*49ef7e06SGarrett D'Amore 
1183*49ef7e06SGarrett D'Amore 	if (evq0_size > EFX_EVQ_MAXNEVS) {
1184*49ef7e06SGarrett D'Amore 		rc = EINVAL;
1185*49ef7e06SGarrett D'Amore 		goto fail1;
1186*49ef7e06SGarrett D'Amore 	}
1187*49ef7e06SGarrett D'Amore 
1188*49ef7e06SGarrett D'Amore 	sp->s_evq0_size = pow2_ge(evq0_size);
1189*49ef7e06SGarrett D'Amore 	sp->s_evqX_size = pow2_ge(evqX_size);
1190*49ef7e06SGarrett D'Amore 
1191*49ef7e06SGarrett D'Amore 	/* Read driver parameters */
1192*49ef7e06SGarrett D'Amore 	sp->s_ev_moderation = ddi_prop_get_int(DDI_DEV_T_ANY, sp->s_dip,
1193*49ef7e06SGarrett D'Amore 	    DDI_PROP_DONTPASS, "intr_moderation", SFXGE_DEFAULT_MODERATION);
1194*49ef7e06SGarrett D'Amore 
1195*49ef7e06SGarrett D'Amore 	ev_batch = ddi_prop_get_int(DDI_DEV_T_ANY, sp->s_dip,
1196*49ef7e06SGarrett D'Amore 	    DDI_PROP_DONTPASS, "ev_batch", SFXGE_EV_BATCH);
1197*49ef7e06SGarrett D'Amore 
1198*49ef7e06SGarrett D'Amore 	/*
1199*49ef7e06SGarrett D'Amore 	 * It is slightly peverse to have a cache for one item. But it allows
1200*49ef7e06SGarrett D'Amore 	 * for simple alignment control without increasing the allocation size
1201*49ef7e06SGarrett D'Amore 	 */
1202*49ef7e06SGarrett D'Amore 	sp->s_eq0c = sfxge_ev_kmem_cache_create(sp, "evq0", sfxge_ev_q0ctor,
1203*49ef7e06SGarrett D'Amore 	    sfxge_ev_q0dtor);
1204*49ef7e06SGarrett D'Amore 	sp->s_eqXc = sfxge_ev_kmem_cache_create(sp, "evqX", sfxge_ev_qXctor,
1205*49ef7e06SGarrett D'Amore 	    sfxge_ev_qXdtor);
1206*49ef7e06SGarrett D'Amore 
1207*49ef7e06SGarrett D'Amore 	/* Initialize the event queue(s) */
1208*49ef7e06SGarrett D'Amore 	for (index = 0; index < sip->si_nalloc; index++) {
1209*49ef7e06SGarrett D'Amore 		if ((rc = sfxge_ev_qinit(sp, index, ev_batch)) != 0)
1210*49ef7e06SGarrett D'Amore 			goto fail2;
1211*49ef7e06SGarrett D'Amore 	}
1212*49ef7e06SGarrett D'Amore 
1213*49ef7e06SGarrett D'Amore 	return (0);
1214*49ef7e06SGarrett D'Amore 
1215*49ef7e06SGarrett D'Amore fail2:
1216*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
1217*49ef7e06SGarrett D'Amore 
1218*49ef7e06SGarrett D'Amore 	while (--index >= 0)
1219*49ef7e06SGarrett D'Amore 		sfxge_ev_qfini(sp, index);
1220*49ef7e06SGarrett D'Amore 	sp->s_ev_moderation = 0;
1221*49ef7e06SGarrett D'Amore 
1222*49ef7e06SGarrett D'Amore fail1:
1223*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1224*49ef7e06SGarrett D'Amore 
1225*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_eqXc);
1226*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_eq0c);
1227*49ef7e06SGarrett D'Amore 	sp->s_eqXc = NULL;
1228*49ef7e06SGarrett D'Amore 	sp->s_eq0c = NULL;
1229*49ef7e06SGarrett D'Amore 
1230*49ef7e06SGarrett D'Amore 	return (rc);
1231*49ef7e06SGarrett D'Amore }
1232*49ef7e06SGarrett D'Amore 
1233*49ef7e06SGarrett D'Amore int
sfxge_ev_start(sfxge_t * sp)1234*49ef7e06SGarrett D'Amore sfxge_ev_start(sfxge_t *sp)
1235*49ef7e06SGarrett D'Amore {
1236*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
1237*49ef7e06SGarrett D'Amore 	efx_nic_t *enp = sp->s_enp;
1238*49ef7e06SGarrett D'Amore 	int index;
1239*49ef7e06SGarrett D'Amore 	int rc;
1240*49ef7e06SGarrett D'Amore 
1241*49ef7e06SGarrett D'Amore 	ASSERT3U(sip->si_state, ==, SFXGE_INTR_STARTED);
1242*49ef7e06SGarrett D'Amore 
1243*49ef7e06SGarrett D'Amore 	/* Initialize the event module */
1244*49ef7e06SGarrett D'Amore 	if ((rc = efx_ev_init(enp)) != 0)
1245*49ef7e06SGarrett D'Amore 		goto fail1;
1246*49ef7e06SGarrett D'Amore 
1247*49ef7e06SGarrett D'Amore 	/* Start the event queues */
1248*49ef7e06SGarrett D'Amore 	for (index = 0; index < sip->si_nalloc; index++) {
1249*49ef7e06SGarrett D'Amore 		if ((rc = sfxge_ev_qstart(sp, index)) != 0)
1250*49ef7e06SGarrett D'Amore 			goto fail2;
1251*49ef7e06SGarrett D'Amore 	}
1252*49ef7e06SGarrett D'Amore 
1253*49ef7e06SGarrett D'Amore 	return (0);
1254*49ef7e06SGarrett D'Amore 
1255*49ef7e06SGarrett D'Amore fail2:
1256*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
1257*49ef7e06SGarrett D'Amore 
1258*49ef7e06SGarrett D'Amore 	/* Stop the event queue(s) */
1259*49ef7e06SGarrett D'Amore 	while (--index >= 0)
1260*49ef7e06SGarrett D'Amore 		sfxge_ev_qstop(sp, index);
1261*49ef7e06SGarrett D'Amore 
1262*49ef7e06SGarrett D'Amore 	/* Tear down the event module */
1263*49ef7e06SGarrett D'Amore 	efx_ev_fini(enp);
1264*49ef7e06SGarrett D'Amore 
1265*49ef7e06SGarrett D'Amore fail1:
1266*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1267*49ef7e06SGarrett D'Amore 
1268*49ef7e06SGarrett D'Amore 	return (rc);
1269*49ef7e06SGarrett D'Amore }
1270*49ef7e06SGarrett D'Amore 
1271*49ef7e06SGarrett D'Amore void
sfxge_ev_moderation_get(sfxge_t * sp,unsigned int * usp)1272*49ef7e06SGarrett D'Amore sfxge_ev_moderation_get(sfxge_t *sp, unsigned int *usp)
1273*49ef7e06SGarrett D'Amore {
1274*49ef7e06SGarrett D'Amore 	*usp = sp->s_ev_moderation;
1275*49ef7e06SGarrett D'Amore }
1276*49ef7e06SGarrett D'Amore 
1277*49ef7e06SGarrett D'Amore int
sfxge_ev_moderation_set(sfxge_t * sp,unsigned int us)1278*49ef7e06SGarrett D'Amore sfxge_ev_moderation_set(sfxge_t *sp, unsigned int us)
1279*49ef7e06SGarrett D'Amore {
1280*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
1281*49ef7e06SGarrett D'Amore 	int index;
1282*49ef7e06SGarrett D'Amore 	int rc;
1283*49ef7e06SGarrett D'Amore 
1284*49ef7e06SGarrett D'Amore 	if (sip->si_state != SFXGE_INTR_STARTED)
1285*49ef7e06SGarrett D'Amore 		return (ENODEV);
1286*49ef7e06SGarrett D'Amore 
1287*49ef7e06SGarrett D'Amore 	for (index = 0; index < sip->si_nalloc; index++) {
1288*49ef7e06SGarrett D'Amore 		if ((rc = sfxge_ev_qmoderate(sp, index, us)) != 0)
1289*49ef7e06SGarrett D'Amore 			goto fail1;
1290*49ef7e06SGarrett D'Amore 	}
1291*49ef7e06SGarrett D'Amore 
1292*49ef7e06SGarrett D'Amore 	sp->s_ev_moderation = us;
1293*49ef7e06SGarrett D'Amore 	return (0);
1294*49ef7e06SGarrett D'Amore 
1295*49ef7e06SGarrett D'Amore fail1:
1296*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1297*49ef7e06SGarrett D'Amore 
1298*49ef7e06SGarrett D'Amore 	/*  The only error path is if the value to set to is invalid. */
1299*49ef7e06SGarrett D'Amore 	ASSERT3U(index, ==, 0);
1300*49ef7e06SGarrett D'Amore 
1301*49ef7e06SGarrett D'Amore 	return (rc);
1302*49ef7e06SGarrett D'Amore }
1303*49ef7e06SGarrett D'Amore 
1304*49ef7e06SGarrett D'Amore void
sfxge_ev_stop(sfxge_t * sp)1305*49ef7e06SGarrett D'Amore sfxge_ev_stop(sfxge_t *sp)
1306*49ef7e06SGarrett D'Amore {
1307*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
1308*49ef7e06SGarrett D'Amore 	efx_nic_t *enp = sp->s_enp;
1309*49ef7e06SGarrett D'Amore 	int index;
1310*49ef7e06SGarrett D'Amore 
1311*49ef7e06SGarrett D'Amore 	ASSERT3U(sip->si_state, ==, SFXGE_INTR_STARTED);
1312*49ef7e06SGarrett D'Amore 
1313*49ef7e06SGarrett D'Amore 	/* Stop the event queue(s) */
1314*49ef7e06SGarrett D'Amore 	index = sip->si_nalloc;
1315*49ef7e06SGarrett D'Amore 	while (--index >= 0)
1316*49ef7e06SGarrett D'Amore 		sfxge_ev_qstop(sp, index);
1317*49ef7e06SGarrett D'Amore 
1318*49ef7e06SGarrett D'Amore 	/* Tear down the event module */
1319*49ef7e06SGarrett D'Amore 	efx_ev_fini(enp);
1320*49ef7e06SGarrett D'Amore }
1321*49ef7e06SGarrett D'Amore 
1322*49ef7e06SGarrett D'Amore void
sfxge_ev_fini(sfxge_t * sp)1323*49ef7e06SGarrett D'Amore sfxge_ev_fini(sfxge_t *sp)
1324*49ef7e06SGarrett D'Amore {
1325*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
1326*49ef7e06SGarrett D'Amore 	int index;
1327*49ef7e06SGarrett D'Amore 
1328*49ef7e06SGarrett D'Amore 	ASSERT3U(sip->si_state, ==, SFXGE_INTR_INITIALIZED);
1329*49ef7e06SGarrett D'Amore 
1330*49ef7e06SGarrett D'Amore 	sp->s_ev_moderation = 0;
1331*49ef7e06SGarrett D'Amore 
1332*49ef7e06SGarrett D'Amore 	/* Tear down the event queue(s) */
1333*49ef7e06SGarrett D'Amore 	index = sip->si_nalloc;
1334*49ef7e06SGarrett D'Amore 	while (--index >= 0)
1335*49ef7e06SGarrett D'Amore 		sfxge_ev_qfini(sp, index);
1336*49ef7e06SGarrett D'Amore 
1337*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_eqXc);
1338*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_eq0c);
1339*49ef7e06SGarrett D'Amore 	sp->s_eqXc = NULL;
1340*49ef7e06SGarrett D'Amore 	sp->s_eq0c = NULL;
1341*49ef7e06SGarrett D'Amore }
1342