1283514Sarybchik/*-
2301388Sarybchik * Copyright (c) 2012-2016 Solarflare Communications Inc.
3283514Sarybchik * All rights reserved.
4283514Sarybchik *
5283514Sarybchik * Redistribution and use in source and binary forms, with or without
6283514Sarybchik * modification, are permitted provided that the following conditions are met:
7283514Sarybchik *
8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9283514Sarybchik *    this list of conditions and the following disclaimer.
10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11283514Sarybchik *    this list of conditions and the following disclaimer in the documentation
12283514Sarybchik *    and/or other materials provided with the distribution.
13283514Sarybchik *
14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25283514Sarybchik *
26283514Sarybchik * The views and conclusions contained in the software and documentation are
27283514Sarybchik * those of the authors and should not be interpreted as representing official
28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29283514Sarybchik */
30283514Sarybchik
31283514Sarybchik#include <sys/cdefs.h>
32283514Sarybchik__FBSDID("$FreeBSD: stable/10/sys/dev/sfxge/common/ef10_ev.c 342516 2018-12-26 10:25:01Z arybchik $");
33283514Sarybchik
34283514Sarybchik#include "efx.h"
35283514Sarybchik#include "efx_impl.h"
36283514Sarybchik#if EFSYS_OPT_MON_STATS
37283514Sarybchik#include "mcdi_mon.h"
38283514Sarybchik#endif
39283514Sarybchik
40299596Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
41283514Sarybchik
42283514Sarybchik#if EFSYS_OPT_QSTATS
43283514Sarybchik#define	EFX_EV_QSTAT_INCR(_eep, _stat)					\
44283514Sarybchik	do {								\
45283514Sarybchik		(_eep)->ee_stat[_stat]++;				\
46283514Sarybchik	_NOTE(CONSTANTCONDITION)					\
47283514Sarybchik	} while (B_FALSE)
48283514Sarybchik#else
49283514Sarybchik#define	EFX_EV_QSTAT_INCR(_eep, _stat)
50283514Sarybchik#endif
51283514Sarybchik
52311094Sarybchik/*
53311094Sarybchik * Non-interrupting event queue requires interrrupting event queue to
54311094Sarybchik * refer to for wake-up events even if wake ups are never used.
55311094Sarybchik * It could be even non-allocated event queue.
56311094Sarybchik */
57311094Sarybchik#define	EFX_EF10_ALWAYS_INTERRUPTING_EVQ_INDEX	(0)
58283514Sarybchik
59283514Sarybchikstatic	__checkReturn	boolean_t
60293752Sarybchikef10_ev_rx(
61283514Sarybchik	__in		efx_evq_t *eep,
62283514Sarybchik	__in		efx_qword_t *eqp,
63283514Sarybchik	__in		const efx_ev_callbacks_t *eecp,
64283514Sarybchik	__in_opt	void *arg);
65283514Sarybchik
66283514Sarybchikstatic	__checkReturn	boolean_t
67293752Sarybchikef10_ev_tx(
68283514Sarybchik	__in		efx_evq_t *eep,
69283514Sarybchik	__in		efx_qword_t *eqp,
70283514Sarybchik	__in		const efx_ev_callbacks_t *eecp,
71283514Sarybchik	__in_opt	void *arg);
72283514Sarybchik
73283514Sarybchikstatic	__checkReturn	boolean_t
74293752Sarybchikef10_ev_driver(
75283514Sarybchik	__in		efx_evq_t *eep,
76283514Sarybchik	__in		efx_qword_t *eqp,
77283514Sarybchik	__in		const efx_ev_callbacks_t *eecp,
78283514Sarybchik	__in_opt	void *arg);
79283514Sarybchik
80283514Sarybchikstatic	__checkReturn	boolean_t
81293752Sarybchikef10_ev_drv_gen(
82283514Sarybchik	__in		efx_evq_t *eep,
83283514Sarybchik	__in		efx_qword_t *eqp,
84283514Sarybchik	__in		const efx_ev_callbacks_t *eecp,
85283514Sarybchik	__in_opt	void *arg);
86283514Sarybchik
87283514Sarybchikstatic	__checkReturn	boolean_t
88293752Sarybchikef10_ev_mcdi(
89283514Sarybchik	__in		efx_evq_t *eep,
90283514Sarybchik	__in		efx_qword_t *eqp,
91283514Sarybchik	__in		const efx_ev_callbacks_t *eecp,
92283514Sarybchik	__in_opt	void *arg);
93283514Sarybchik
94283514Sarybchik
95291436Sarybchikstatic	__checkReturn	efx_rc_t
96301983Sarybchikefx_mcdi_set_evq_tmr(
97301983Sarybchik	__in		efx_nic_t *enp,
98301983Sarybchik	__in		uint32_t instance,
99301983Sarybchik	__in		uint32_t mode,
100301983Sarybchik	__in		uint32_t timer_ns)
101301983Sarybchik{
102301983Sarybchik	efx_mcdi_req_t req;
103342516Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SET_EVQ_TMR_IN_LEN,
104342516Sarybchik		MC_CMD_SET_EVQ_TMR_OUT_LEN);
105301983Sarybchik	efx_rc_t rc;
106301983Sarybchik
107301983Sarybchik	req.emr_cmd = MC_CMD_SET_EVQ_TMR;
108301983Sarybchik	req.emr_in_buf = payload;
109301983Sarybchik	req.emr_in_length = MC_CMD_SET_EVQ_TMR_IN_LEN;
110301983Sarybchik	req.emr_out_buf = payload;
111301983Sarybchik	req.emr_out_length = MC_CMD_SET_EVQ_TMR_OUT_LEN;
112301983Sarybchik
113301983Sarybchik	MCDI_IN_SET_DWORD(req, SET_EVQ_TMR_IN_INSTANCE, instance);
114301983Sarybchik	MCDI_IN_SET_DWORD(req, SET_EVQ_TMR_IN_TMR_LOAD_REQ_NS, timer_ns);
115301983Sarybchik	MCDI_IN_SET_DWORD(req, SET_EVQ_TMR_IN_TMR_RELOAD_REQ_NS, timer_ns);
116301983Sarybchik	MCDI_IN_SET_DWORD(req, SET_EVQ_TMR_IN_TMR_MODE, mode);
117301983Sarybchik
118301983Sarybchik	efx_mcdi_execute(enp, &req);
119301983Sarybchik
120301983Sarybchik	if (req.emr_rc != 0) {
121301983Sarybchik		rc = req.emr_rc;
122301983Sarybchik		goto fail1;
123301983Sarybchik	}
124301983Sarybchik
125301983Sarybchik	if (req.emr_out_length_used < MC_CMD_SET_EVQ_TMR_OUT_LEN) {
126301983Sarybchik		rc = EMSGSIZE;
127301983Sarybchik		goto fail2;
128301983Sarybchik	}
129301983Sarybchik
130301983Sarybchik	return (0);
131301983Sarybchik
132301983Sarybchikfail2:
133301983Sarybchik	EFSYS_PROBE(fail2);
134301983Sarybchikfail1:
135301983Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
136301983Sarybchik
137301983Sarybchik	return (rc);
138301983Sarybchik}
139301983Sarybchik
140301983Sarybchikstatic	__checkReturn	efx_rc_t
141283514Sarybchikefx_mcdi_init_evq(
142283514Sarybchik	__in		efx_nic_t *enp,
143283514Sarybchik	__in		unsigned int instance,
144283514Sarybchik	__in		efsys_mem_t *esmp,
145283514Sarybchik	__in		size_t nevs,
146301980Sarybchik	__in		uint32_t irq,
147301986Sarybchik	__in		uint32_t us,
148311070Sarybchik	__in		uint32_t flags,
149301986Sarybchik	__in		boolean_t low_latency)
150283514Sarybchik{
151283514Sarybchik	efx_mcdi_req_t req;
152342516Sarybchik	EFX_MCDI_DECLARE_BUF(payload,
153342516Sarybchik		MC_CMD_INIT_EVQ_IN_LEN(EFX_EVQ_NBUFS(EFX_EVQ_MAXNEVS)),
154342516Sarybchik		MC_CMD_INIT_EVQ_OUT_LEN);
155283514Sarybchik	efx_qword_t *dma_addr;
156283514Sarybchik	uint64_t addr;
157283514Sarybchik	int npages;
158283514Sarybchik	int i;
159311094Sarybchik	boolean_t interrupting;
160301986Sarybchik	int ev_cut_through;
161291436Sarybchik	efx_rc_t rc;
162283514Sarybchik
163283514Sarybchik	npages = EFX_EVQ_NBUFS(nevs);
164283514Sarybchik	if (MC_CMD_INIT_EVQ_IN_LEN(npages) > MC_CMD_INIT_EVQ_IN_LENMAX) {
165283514Sarybchik		rc = EINVAL;
166283514Sarybchik		goto fail1;
167283514Sarybchik	}
168283514Sarybchik
169283514Sarybchik	req.emr_cmd = MC_CMD_INIT_EVQ;
170283514Sarybchik	req.emr_in_buf = payload;
171283514Sarybchik	req.emr_in_length = MC_CMD_INIT_EVQ_IN_LEN(npages);
172283514Sarybchik	req.emr_out_buf = payload;
173283514Sarybchik	req.emr_out_length = MC_CMD_INIT_EVQ_OUT_LEN;
174283514Sarybchik
175283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_SIZE, nevs);
176283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_INSTANCE, instance);
177283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_IRQ_NUM, irq);
178283514Sarybchik
179311094Sarybchik	interrupting = ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) ==
180311094Sarybchik	    EFX_EVQ_FLAGS_NOTIFY_INTERRUPT);
181311094Sarybchik
182283514Sarybchik	/*
183301986Sarybchik	 * On Huntington RX and TX event batching can only be requested together
184301986Sarybchik	 * (even if the datapath firmware doesn't actually support RX
185301986Sarybchik	 * batching). If event cut through is enabled no RX batching will occur.
186283514Sarybchik	 *
187301986Sarybchik	 * So always enable RX and TX event batching, and enable event cut
188301986Sarybchik	 * through if we want low latency operation.
189283514Sarybchik	 */
190311070Sarybchik	switch (flags & EFX_EVQ_FLAGS_TYPE_MASK) {
191311070Sarybchik	case EFX_EVQ_FLAGS_TYPE_AUTO:
192311070Sarybchik		ev_cut_through = low_latency ? 1 : 0;
193311070Sarybchik		break;
194311070Sarybchik	case EFX_EVQ_FLAGS_TYPE_THROUGHPUT:
195311070Sarybchik		ev_cut_through = 0;
196311070Sarybchik		break;
197311070Sarybchik	case EFX_EVQ_FLAGS_TYPE_LOW_LATENCY:
198311070Sarybchik		ev_cut_through = 1;
199311070Sarybchik		break;
200311070Sarybchik	default:
201311070Sarybchik		rc = EINVAL;
202311070Sarybchik		goto fail2;
203311070Sarybchik	}
204283514Sarybchik	MCDI_IN_POPULATE_DWORD_6(req, INIT_EVQ_IN_FLAGS,
205311094Sarybchik	    INIT_EVQ_IN_FLAG_INTERRUPTING, interrupting,
206283514Sarybchik	    INIT_EVQ_IN_FLAG_RPTR_DOS, 0,
207283514Sarybchik	    INIT_EVQ_IN_FLAG_INT_ARMD, 0,
208301986Sarybchik	    INIT_EVQ_IN_FLAG_CUT_THRU, ev_cut_through,
209283514Sarybchik	    INIT_EVQ_IN_FLAG_RX_MERGE, 1,
210283514Sarybchik	    INIT_EVQ_IN_FLAG_TX_MERGE, 1);
211283514Sarybchik
212301984Sarybchik	/* If the value is zero then disable the timer */
213301980Sarybchik	if (us == 0) {
214301980Sarybchik		MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_MODE,
215301980Sarybchik		    MC_CMD_INIT_EVQ_IN_TMR_MODE_DIS);
216301980Sarybchik		MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_LOAD, 0);
217301980Sarybchik		MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_RELOAD, 0);
218301980Sarybchik	} else {
219301984Sarybchik		unsigned int ticks;
220283514Sarybchik
221301984Sarybchik		if ((rc = efx_ev_usecs_to_ticks(enp, us, &ticks)) != 0)
222311070Sarybchik			goto fail3;
223301980Sarybchik
224301980Sarybchik		MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_MODE,
225301980Sarybchik		    MC_CMD_INIT_EVQ_IN_TMR_INT_HLDOFF);
226301984Sarybchik		MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_LOAD, ticks);
227301984Sarybchik		MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_RELOAD, ticks);
228301980Sarybchik	}
229301980Sarybchik
230283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_COUNT_MODE,
231283514Sarybchik	    MC_CMD_INIT_EVQ_IN_COUNT_MODE_DIS);
232283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_COUNT_THRSHLD, 0);
233283514Sarybchik
234283514Sarybchik	dma_addr = MCDI_IN2(req, efx_qword_t, INIT_EVQ_IN_DMA_ADDR);
235283514Sarybchik	addr = EFSYS_MEM_ADDR(esmp);
236283514Sarybchik
237283514Sarybchik	for (i = 0; i < npages; i++) {
238283514Sarybchik		EFX_POPULATE_QWORD_2(*dma_addr,
239283514Sarybchik		    EFX_DWORD_1, (uint32_t)(addr >> 32),
240283514Sarybchik		    EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
241283514Sarybchik
242283514Sarybchik		dma_addr++;
243283514Sarybchik		addr += EFX_BUF_SIZE;
244283514Sarybchik	}
245283514Sarybchik
246283514Sarybchik	efx_mcdi_execute(enp, &req);
247283514Sarybchik
248283514Sarybchik	if (req.emr_rc != 0) {
249283514Sarybchik		rc = req.emr_rc;
250311070Sarybchik		goto fail4;
251283514Sarybchik	}
252283514Sarybchik
253283514Sarybchik	if (req.emr_out_length_used < MC_CMD_INIT_EVQ_OUT_LEN) {
254283514Sarybchik		rc = EMSGSIZE;
255311070Sarybchik		goto fail5;
256283514Sarybchik	}
257283514Sarybchik
258301375Sarybchik	/* NOTE: ignore the returned IRQ param as firmware does not set it. */
259283514Sarybchik
260283514Sarybchik	return (0);
261283514Sarybchik
262311070Sarybchikfail5:
263311070Sarybchik	EFSYS_PROBE(fail5);
264301984Sarybchikfail4:
265301984Sarybchik	EFSYS_PROBE(fail4);
266283514Sarybchikfail3:
267283514Sarybchik	EFSYS_PROBE(fail3);
268283514Sarybchikfail2:
269283514Sarybchik	EFSYS_PROBE(fail2);
270283514Sarybchikfail1:
271291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
272283514Sarybchik
273283514Sarybchik	return (rc);
274283514Sarybchik}
275283514Sarybchik
276301986Sarybchik
277291436Sarybchikstatic	__checkReturn	efx_rc_t
278301986Sarybchikefx_mcdi_init_evq_v2(
279301986Sarybchik	__in		efx_nic_t *enp,
280301986Sarybchik	__in		unsigned int instance,
281301986Sarybchik	__in		efsys_mem_t *esmp,
282301986Sarybchik	__in		size_t nevs,
283301986Sarybchik	__in		uint32_t irq,
284311070Sarybchik	__in		uint32_t us,
285311070Sarybchik	__in		uint32_t flags)
286301986Sarybchik{
287301986Sarybchik	efx_mcdi_req_t req;
288342516Sarybchik	EFX_MCDI_DECLARE_BUF(payload,
289342516Sarybchik		MC_CMD_INIT_EVQ_V2_IN_LEN(EFX_EVQ_NBUFS(EFX_EVQ_MAXNEVS)),
290342516Sarybchik		MC_CMD_INIT_EVQ_V2_OUT_LEN);
291311094Sarybchik	boolean_t interrupting;
292311070Sarybchik	unsigned int evq_type;
293301986Sarybchik	efx_qword_t *dma_addr;
294301986Sarybchik	uint64_t addr;
295301986Sarybchik	int npages;
296301986Sarybchik	int i;
297301986Sarybchik	efx_rc_t rc;
298301986Sarybchik
299301986Sarybchik	npages = EFX_EVQ_NBUFS(nevs);
300301986Sarybchik	if (MC_CMD_INIT_EVQ_V2_IN_LEN(npages) > MC_CMD_INIT_EVQ_V2_IN_LENMAX) {
301301986Sarybchik		rc = EINVAL;
302301986Sarybchik		goto fail1;
303301986Sarybchik	}
304301986Sarybchik
305301986Sarybchik	req.emr_cmd = MC_CMD_INIT_EVQ;
306301986Sarybchik	req.emr_in_buf = payload;
307301986Sarybchik	req.emr_in_length = MC_CMD_INIT_EVQ_V2_IN_LEN(npages);
308301986Sarybchik	req.emr_out_buf = payload;
309301986Sarybchik	req.emr_out_length = MC_CMD_INIT_EVQ_V2_OUT_LEN;
310301986Sarybchik
311301986Sarybchik	MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_SIZE, nevs);
312301986Sarybchik	MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_INSTANCE, instance);
313301986Sarybchik	MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_IRQ_NUM, irq);
314301986Sarybchik
315311094Sarybchik	interrupting = ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) ==
316311094Sarybchik	    EFX_EVQ_FLAGS_NOTIFY_INTERRUPT);
317311094Sarybchik
318311070Sarybchik	switch (flags & EFX_EVQ_FLAGS_TYPE_MASK) {
319311070Sarybchik	case EFX_EVQ_FLAGS_TYPE_AUTO:
320311070Sarybchik		evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_AUTO;
321311070Sarybchik		break;
322311070Sarybchik	case EFX_EVQ_FLAGS_TYPE_THROUGHPUT:
323311070Sarybchik		evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_THROUGHPUT;
324311070Sarybchik		break;
325311070Sarybchik	case EFX_EVQ_FLAGS_TYPE_LOW_LATENCY:
326311070Sarybchik		evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_LOW_LATENCY;
327311070Sarybchik		break;
328311070Sarybchik	default:
329311070Sarybchik		rc = EINVAL;
330311070Sarybchik		goto fail2;
331311070Sarybchik	}
332301986Sarybchik	MCDI_IN_POPULATE_DWORD_4(req, INIT_EVQ_V2_IN_FLAGS,
333311094Sarybchik	    INIT_EVQ_V2_IN_FLAG_INTERRUPTING, interrupting,
334301986Sarybchik	    INIT_EVQ_V2_IN_FLAG_RPTR_DOS, 0,
335301986Sarybchik	    INIT_EVQ_V2_IN_FLAG_INT_ARMD, 0,
336311070Sarybchik	    INIT_EVQ_V2_IN_FLAG_TYPE, evq_type);
337301986Sarybchik
338301986Sarybchik	/* If the value is zero then disable the timer */
339301986Sarybchik	if (us == 0) {
340301986Sarybchik		MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_MODE,
341301986Sarybchik		    MC_CMD_INIT_EVQ_V2_IN_TMR_MODE_DIS);
342301986Sarybchik		MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_LOAD, 0);
343301986Sarybchik		MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_RELOAD, 0);
344301986Sarybchik	} else {
345301986Sarybchik		unsigned int ticks;
346301986Sarybchik
347301986Sarybchik		if ((rc = efx_ev_usecs_to_ticks(enp, us, &ticks)) != 0)
348311070Sarybchik			goto fail3;
349301986Sarybchik
350301986Sarybchik		MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_MODE,
351301986Sarybchik		    MC_CMD_INIT_EVQ_V2_IN_TMR_INT_HLDOFF);
352301986Sarybchik		MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_LOAD, ticks);
353301986Sarybchik		MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_RELOAD, ticks);
354301986Sarybchik	}
355301986Sarybchik
356301986Sarybchik	MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_COUNT_MODE,
357301986Sarybchik	    MC_CMD_INIT_EVQ_V2_IN_COUNT_MODE_DIS);
358301986Sarybchik	MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_COUNT_THRSHLD, 0);
359301986Sarybchik
360301986Sarybchik	dma_addr = MCDI_IN2(req, efx_qword_t, INIT_EVQ_V2_IN_DMA_ADDR);
361301986Sarybchik	addr = EFSYS_MEM_ADDR(esmp);
362301986Sarybchik
363301986Sarybchik	for (i = 0; i < npages; i++) {
364301986Sarybchik		EFX_POPULATE_QWORD_2(*dma_addr,
365301986Sarybchik		    EFX_DWORD_1, (uint32_t)(addr >> 32),
366301986Sarybchik		    EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
367301986Sarybchik
368301986Sarybchik		dma_addr++;
369301986Sarybchik		addr += EFX_BUF_SIZE;
370301986Sarybchik	}
371301986Sarybchik
372301986Sarybchik	efx_mcdi_execute(enp, &req);
373301986Sarybchik
374301986Sarybchik	if (req.emr_rc != 0) {
375301986Sarybchik		rc = req.emr_rc;
376311070Sarybchik		goto fail4;
377301986Sarybchik	}
378301986Sarybchik
379301986Sarybchik	if (req.emr_out_length_used < MC_CMD_INIT_EVQ_V2_OUT_LEN) {
380301986Sarybchik		rc = EMSGSIZE;
381311070Sarybchik		goto fail5;
382301986Sarybchik	}
383301986Sarybchik
384301986Sarybchik	/* NOTE: ignore the returned IRQ param as firmware does not set it. */
385301986Sarybchik
386301986Sarybchik	EFSYS_PROBE1(mcdi_evq_flags, uint32_t,
387301986Sarybchik		    MCDI_OUT_DWORD(req, INIT_EVQ_V2_OUT_FLAGS));
388301986Sarybchik
389301986Sarybchik	return (0);
390301986Sarybchik
391311070Sarybchikfail5:
392311070Sarybchik	EFSYS_PROBE(fail5);
393301986Sarybchikfail4:
394301986Sarybchik	EFSYS_PROBE(fail4);
395301986Sarybchikfail3:
396301986Sarybchik	EFSYS_PROBE(fail3);
397301986Sarybchikfail2:
398301986Sarybchik	EFSYS_PROBE(fail2);
399301986Sarybchikfail1:
400301986Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
401301986Sarybchik
402301986Sarybchik	return (rc);
403301986Sarybchik}
404301986Sarybchik
405301986Sarybchikstatic	__checkReturn	efx_rc_t
406283514Sarybchikefx_mcdi_fini_evq(
407283514Sarybchik	__in		efx_nic_t *enp,
408283514Sarybchik	__in		uint32_t instance)
409283514Sarybchik{
410283514Sarybchik	efx_mcdi_req_t req;
411342516Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_EVQ_IN_LEN,
412342516Sarybchik		MC_CMD_FINI_EVQ_OUT_LEN);
413291436Sarybchik	efx_rc_t rc;
414283514Sarybchik
415283514Sarybchik	req.emr_cmd = MC_CMD_FINI_EVQ;
416283514Sarybchik	req.emr_in_buf = payload;
417283514Sarybchik	req.emr_in_length = MC_CMD_FINI_EVQ_IN_LEN;
418283514Sarybchik	req.emr_out_buf = payload;
419283514Sarybchik	req.emr_out_length = MC_CMD_FINI_EVQ_OUT_LEN;
420283514Sarybchik
421283514Sarybchik	MCDI_IN_SET_DWORD(req, FINI_EVQ_IN_INSTANCE, instance);
422283514Sarybchik
423301378Sarybchik	efx_mcdi_execute_quiet(enp, &req);
424283514Sarybchik
425283514Sarybchik	if (req.emr_rc != 0) {
426283514Sarybchik		rc = req.emr_rc;
427283514Sarybchik		goto fail1;
428283514Sarybchik	}
429283514Sarybchik
430283514Sarybchik	return (0);
431283514Sarybchik
432283514Sarybchikfail1:
433342483Sarybchik	/*
434342483Sarybchik	 * EALREADY is not an error, but indicates that the MC has rebooted and
435342483Sarybchik	 * that the EVQ has already been destroyed.
436342483Sarybchik	 */
437342483Sarybchik	if (rc != EALREADY)
438342483Sarybchik		EFSYS_PROBE1(fail1, efx_rc_t, rc);
439283514Sarybchik
440283514Sarybchik	return (rc);
441283514Sarybchik}
442283514Sarybchik
443283514Sarybchik
444283514Sarybchik
445291436Sarybchik	__checkReturn	efx_rc_t
446293752Sarybchikef10_ev_init(
447283514Sarybchik	__in		efx_nic_t *enp)
448283514Sarybchik{
449283514Sarybchik	_NOTE(ARGUNUSED(enp))
450283514Sarybchik	return (0);
451283514Sarybchik}
452283514Sarybchik
453283514Sarybchik			void
454293752Sarybchikef10_ev_fini(
455283514Sarybchik	__in		efx_nic_t *enp)
456283514Sarybchik{
457283514Sarybchik	_NOTE(ARGUNUSED(enp))
458283514Sarybchik}
459283514Sarybchik
460291436Sarybchik	__checkReturn	efx_rc_t
461293752Sarybchikef10_ev_qcreate(
462283514Sarybchik	__in		efx_nic_t *enp,
463283514Sarybchik	__in		unsigned int index,
464283514Sarybchik	__in		efsys_mem_t *esmp,
465283514Sarybchik	__in		size_t n,
466283514Sarybchik	__in		uint32_t id,
467301980Sarybchik	__in		uint32_t us,
468311070Sarybchik	__in		uint32_t flags,
469283514Sarybchik	__in		efx_evq_t *eep)
470283514Sarybchik{
471283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
472283514Sarybchik	uint32_t irq;
473291436Sarybchik	efx_rc_t rc;
474283514Sarybchik
475283514Sarybchik	_NOTE(ARGUNUSED(id))	/* buftbl id managed by MC */
476283514Sarybchik	EFX_STATIC_ASSERT(ISP2(EFX_EVQ_MAXNEVS));
477283514Sarybchik	EFX_STATIC_ASSERT(ISP2(EFX_EVQ_MINNEVS));
478283514Sarybchik
479283514Sarybchik	if (!ISP2(n) || (n < EFX_EVQ_MINNEVS) || (n > EFX_EVQ_MAXNEVS)) {
480283514Sarybchik		rc = EINVAL;
481283514Sarybchik		goto fail1;
482283514Sarybchik	}
483283514Sarybchik
484283514Sarybchik	if (index >= encp->enc_evq_limit) {
485283514Sarybchik		rc = EINVAL;
486283514Sarybchik		goto fail2;
487283514Sarybchik	}
488283514Sarybchik
489301980Sarybchik	if (us > encp->enc_evq_timer_max_us) {
490301980Sarybchik		rc = EINVAL;
491301980Sarybchik		goto fail3;
492301980Sarybchik	}
493301980Sarybchik
494283514Sarybchik	/* Set up the handler table */
495293752Sarybchik	eep->ee_rx	= ef10_ev_rx;
496293752Sarybchik	eep->ee_tx	= ef10_ev_tx;
497293752Sarybchik	eep->ee_driver	= ef10_ev_driver;
498293752Sarybchik	eep->ee_drv_gen	= ef10_ev_drv_gen;
499293752Sarybchik	eep->ee_mcdi	= ef10_ev_mcdi;
500283514Sarybchik
501301375Sarybchik	/* Set up the event queue */
502311094Sarybchik	/* INIT_EVQ expects function-relative vector number */
503311094Sarybchik	if ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) ==
504311094Sarybchik	    EFX_EVQ_FLAGS_NOTIFY_INTERRUPT) {
505311094Sarybchik		irq = index;
506311094Sarybchik	} else if (index == EFX_EF10_ALWAYS_INTERRUPTING_EVQ_INDEX) {
507311094Sarybchik		irq = index;
508311094Sarybchik		flags = (flags & ~EFX_EVQ_FLAGS_NOTIFY_MASK) |
509311094Sarybchik		    EFX_EVQ_FLAGS_NOTIFY_INTERRUPT;
510311094Sarybchik	} else {
511311094Sarybchik		irq = EFX_EF10_ALWAYS_INTERRUPTING_EVQ_INDEX;
512311094Sarybchik	}
513301386Sarybchik
514301386Sarybchik	/*
515301386Sarybchik	 * Interrupts may be raised for events immediately after the queue is
516301386Sarybchik	 * created. See bug58606.
517301386Sarybchik	 */
518283514Sarybchik
519301986Sarybchik	if (encp->enc_init_evq_v2_supported) {
520301986Sarybchik		/*
521301986Sarybchik		 * On Medford the low latency license is required to enable RX
522311070Sarybchik		 * and event cut through and to disable RX batching.  If event
523311070Sarybchik		 * queue type in flags is auto, we let the firmware decide the
524311070Sarybchik		 * settings to use. If the adapter has a low latency license,
525311070Sarybchik		 * it will choose the best settings for low latency, otherwise
526311070Sarybchik		 * it will choose the best settings for throughput.
527301986Sarybchik		 */
528311070Sarybchik		rc = efx_mcdi_init_evq_v2(enp, index, esmp, n, irq, us, flags);
529301986Sarybchik		if (rc != 0)
530301986Sarybchik			goto fail4;
531301986Sarybchik	} else {
532301986Sarybchik		/*
533311070Sarybchik		 * On Huntington we need to specify the settings to use.
534311070Sarybchik		 * If event queue type in flags is auto, we favour throughput
535311070Sarybchik		 * if the adapter is running virtualization supporting firmware
536311070Sarybchik		 * (i.e. the full featured firmware variant)
537311070Sarybchik		 * and latency otherwise. The Ethernet Virtual Bridging
538311070Sarybchik		 * capability is used to make this decision. (Note though that
539311070Sarybchik		 * the low latency firmware variant is also best for
540311070Sarybchik		 * throughput and corresponding type should be specified
541311070Sarybchik		 * to choose it.)
542301986Sarybchik		 */
543311070Sarybchik		boolean_t low_latency = encp->enc_datapath_cap_evb ? 0 : 1;
544311070Sarybchik		rc = efx_mcdi_init_evq(enp, index, esmp, n, irq, us, flags,
545311070Sarybchik		    low_latency);
546301986Sarybchik		if (rc != 0)
547301986Sarybchik			goto fail5;
548301986Sarybchik	}
549301986Sarybchik
550283514Sarybchik	return (0);
551283514Sarybchik
552301986Sarybchikfail5:
553301986Sarybchik	EFSYS_PROBE(fail5);
554301980Sarybchikfail4:
555301980Sarybchik	EFSYS_PROBE(fail4);
556283514Sarybchikfail3:
557283514Sarybchik	EFSYS_PROBE(fail3);
558283514Sarybchikfail2:
559283514Sarybchik	EFSYS_PROBE(fail2);
560283514Sarybchikfail1:
561291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
562283514Sarybchik
563283514Sarybchik	return (rc);
564283514Sarybchik}
565283514Sarybchik
566283514Sarybchik			void
567293752Sarybchikef10_ev_qdestroy(
568283514Sarybchik	__in		efx_evq_t *eep)
569283514Sarybchik{
570283514Sarybchik	efx_nic_t *enp = eep->ee_enp;
571283514Sarybchik
572293752Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
573293752Sarybchik	    enp->en_family == EFX_FAMILY_MEDFORD);
574283514Sarybchik
575342502Sarybchik	(void) efx_mcdi_fini_evq(enp, eep->ee_index);
576283514Sarybchik}
577283514Sarybchik
578291436Sarybchik	__checkReturn	efx_rc_t
579293752Sarybchikef10_ev_qprime(
580283514Sarybchik	__in		efx_evq_t *eep,
581283514Sarybchik	__in		unsigned int count)
582283514Sarybchik{
583283514Sarybchik	efx_nic_t *enp = eep->ee_enp;
584283514Sarybchik	uint32_t rptr;
585283514Sarybchik	efx_dword_t dword;
586283514Sarybchik
587283514Sarybchik	rptr = count & eep->ee_mask;
588283514Sarybchik
589283514Sarybchik	if (enp->en_nic_cfg.enc_bug35388_workaround) {
590283514Sarybchik		EFX_STATIC_ASSERT(EFX_EVQ_MINNEVS >
591283514Sarybchik		    (1 << ERF_DD_EVQ_IND_RPTR_WIDTH));
592283514Sarybchik		EFX_STATIC_ASSERT(EFX_EVQ_MAXNEVS <
593283514Sarybchik		    (1 << 2 * ERF_DD_EVQ_IND_RPTR_WIDTH));
594283514Sarybchik
595283514Sarybchik		EFX_POPULATE_DWORD_2(dword,
596283514Sarybchik		    ERF_DD_EVQ_IND_RPTR_FLAGS,
597283514Sarybchik		    EFE_DD_EVQ_IND_RPTR_FLAGS_HIGH,
598283514Sarybchik		    ERF_DD_EVQ_IND_RPTR,
599283514Sarybchik		    (rptr >> ERF_DD_EVQ_IND_RPTR_WIDTH));
600283514Sarybchik		EFX_BAR_TBL_WRITED(enp, ER_DD_EVQ_INDIRECT, eep->ee_index,
601283514Sarybchik		    &dword, B_FALSE);
602283514Sarybchik
603283514Sarybchik		EFX_POPULATE_DWORD_2(dword,
604283514Sarybchik		    ERF_DD_EVQ_IND_RPTR_FLAGS,
605283514Sarybchik		    EFE_DD_EVQ_IND_RPTR_FLAGS_LOW,
606283514Sarybchik		    ERF_DD_EVQ_IND_RPTR,
607283514Sarybchik		    rptr & ((1 << ERF_DD_EVQ_IND_RPTR_WIDTH) - 1));
608283514Sarybchik		EFX_BAR_TBL_WRITED(enp, ER_DD_EVQ_INDIRECT, eep->ee_index,
609283514Sarybchik		    &dword, B_FALSE);
610283514Sarybchik	} else {
611283514Sarybchik		EFX_POPULATE_DWORD_1(dword, ERF_DZ_EVQ_RPTR, rptr);
612283514Sarybchik		EFX_BAR_TBL_WRITED(enp, ER_DZ_EVQ_RPTR_REG, eep->ee_index,
613283514Sarybchik		    &dword, B_FALSE);
614283514Sarybchik	}
615283514Sarybchik
616283514Sarybchik	return (0);
617283514Sarybchik}
618283514Sarybchik
619291436Sarybchikstatic	__checkReturn	efx_rc_t
620283514Sarybchikefx_mcdi_driver_event(
621283514Sarybchik	__in		efx_nic_t *enp,
622283514Sarybchik	__in		uint32_t evq,
623283514Sarybchik	__in		efx_qword_t data)
624283514Sarybchik{
625283514Sarybchik	efx_mcdi_req_t req;
626342516Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_DRIVER_EVENT_IN_LEN,
627342516Sarybchik		MC_CMD_DRIVER_EVENT_OUT_LEN);
628291436Sarybchik	efx_rc_t rc;
629283514Sarybchik
630283514Sarybchik	req.emr_cmd = MC_CMD_DRIVER_EVENT;
631283514Sarybchik	req.emr_in_buf = payload;
632283514Sarybchik	req.emr_in_length = MC_CMD_DRIVER_EVENT_IN_LEN;
633283514Sarybchik	req.emr_out_buf = payload;
634283514Sarybchik	req.emr_out_length = MC_CMD_DRIVER_EVENT_OUT_LEN;
635283514Sarybchik
636283514Sarybchik	MCDI_IN_SET_DWORD(req, DRIVER_EVENT_IN_EVQ, evq);
637283514Sarybchik
638283514Sarybchik	MCDI_IN_SET_DWORD(req, DRIVER_EVENT_IN_DATA_LO,
639283514Sarybchik	    EFX_QWORD_FIELD(data, EFX_DWORD_0));
640283514Sarybchik	MCDI_IN_SET_DWORD(req, DRIVER_EVENT_IN_DATA_HI,
641283514Sarybchik	    EFX_QWORD_FIELD(data, EFX_DWORD_1));
642283514Sarybchik
643283514Sarybchik	efx_mcdi_execute(enp, &req);
644283514Sarybchik
645283514Sarybchik	if (req.emr_rc != 0) {
646283514Sarybchik		rc = req.emr_rc;
647283514Sarybchik		goto fail1;
648283514Sarybchik	}
649283514Sarybchik
650283514Sarybchik	return (0);
651283514Sarybchik
652283514Sarybchikfail1:
653291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
654283514Sarybchik
655283514Sarybchik	return (rc);
656283514Sarybchik}
657283514Sarybchik
658283514Sarybchik			void
659293752Sarybchikef10_ev_qpost(
660283514Sarybchik	__in	efx_evq_t *eep,
661283514Sarybchik	__in	uint16_t data)
662283514Sarybchik{
663283514Sarybchik	efx_nic_t *enp = eep->ee_enp;
664283514Sarybchik	efx_qword_t event;
665283514Sarybchik
666283514Sarybchik	EFX_POPULATE_QWORD_3(event,
667283514Sarybchik	    ESF_DZ_DRV_CODE, ESE_DZ_EV_CODE_DRV_GEN_EV,
668283514Sarybchik	    ESF_DZ_DRV_SUB_CODE, 0,
669283514Sarybchik	    ESF_DZ_DRV_SUB_DATA_DW0, (uint32_t)data);
670283514Sarybchik
671283514Sarybchik	(void) efx_mcdi_driver_event(enp, eep->ee_index, event);
672283514Sarybchik}
673283514Sarybchik
674291436Sarybchik	__checkReturn	efx_rc_t
675293752Sarybchikef10_ev_qmoderate(
676283514Sarybchik	__in		efx_evq_t *eep,
677283514Sarybchik	__in		unsigned int us)
678283514Sarybchik{
679283514Sarybchik	efx_nic_t *enp = eep->ee_enp;
680283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
681283514Sarybchik	efx_dword_t dword;
682301984Sarybchik	uint32_t mode;
683291436Sarybchik	efx_rc_t rc;
684283514Sarybchik
685301983Sarybchik	/* Check that hardware and MCDI use the same timer MODE values */
686301983Sarybchik	EFX_STATIC_ASSERT(FFE_CZ_TIMER_MODE_DIS ==
687301983Sarybchik	    MC_CMD_SET_EVQ_TMR_IN_TIMER_MODE_DIS);
688301983Sarybchik	EFX_STATIC_ASSERT(FFE_CZ_TIMER_MODE_IMMED_START ==
689301983Sarybchik	    MC_CMD_SET_EVQ_TMR_IN_TIMER_MODE_IMMED_START);
690301983Sarybchik	EFX_STATIC_ASSERT(FFE_CZ_TIMER_MODE_TRIG_START ==
691301983Sarybchik	    MC_CMD_SET_EVQ_TMR_IN_TIMER_MODE_TRIG_START);
692301983Sarybchik	EFX_STATIC_ASSERT(FFE_CZ_TIMER_MODE_INT_HLDOFF ==
693301983Sarybchik	    MC_CMD_SET_EVQ_TMR_IN_TIMER_MODE_INT_HLDOFF);
694301983Sarybchik
695283514Sarybchik	if (us > encp->enc_evq_timer_max_us) {
696283514Sarybchik		rc = EINVAL;
697283514Sarybchik		goto fail1;
698283514Sarybchik	}
699283514Sarybchik
700283514Sarybchik	/* If the value is zero then disable the timer */
701283514Sarybchik	if (us == 0) {
702283514Sarybchik		mode = FFE_CZ_TIMER_MODE_DIS;
703283514Sarybchik	} else {
704301983Sarybchik		mode = FFE_CZ_TIMER_MODE_INT_HLDOFF;
705301983Sarybchik	}
706301983Sarybchik
707301983Sarybchik	if (encp->enc_bug61265_workaround) {
708301984Sarybchik		uint32_t ns = us * 1000;
709301984Sarybchik
710301984Sarybchik		rc = efx_mcdi_set_evq_tmr(enp, eep->ee_index, mode, ns);
711301983Sarybchik		if (rc != 0)
712301983Sarybchik			goto fail2;
713301983Sarybchik	} else {
714301984Sarybchik		unsigned int ticks;
715283514Sarybchik
716301984Sarybchik		if ((rc = efx_ev_usecs_to_ticks(enp, us, &ticks)) != 0)
717301984Sarybchik			goto fail3;
718283514Sarybchik
719301983Sarybchik		if (encp->enc_bug35388_workaround) {
720301983Sarybchik			EFX_POPULATE_DWORD_3(dword,
721301983Sarybchik			    ERF_DD_EVQ_IND_TIMER_FLAGS,
722301983Sarybchik			    EFE_DD_EVQ_IND_TIMER_FLAGS,
723301983Sarybchik			    ERF_DD_EVQ_IND_TIMER_MODE, mode,
724301984Sarybchik			    ERF_DD_EVQ_IND_TIMER_VAL, ticks);
725301983Sarybchik			EFX_BAR_TBL_WRITED(enp, ER_DD_EVQ_INDIRECT,
726301983Sarybchik			    eep->ee_index, &dword, 0);
727301983Sarybchik		} else {
728301983Sarybchik			EFX_POPULATE_DWORD_2(dword,
729301983Sarybchik			    ERF_DZ_TC_TIMER_MODE, mode,
730301984Sarybchik			    ERF_DZ_TC_TIMER_VAL, ticks);
731301983Sarybchik			EFX_BAR_TBL_WRITED(enp, ER_DZ_EVQ_TMR_REG,
732301983Sarybchik			    eep->ee_index, &dword, 0);
733301983Sarybchik		}
734283514Sarybchik	}
735283514Sarybchik
736283514Sarybchik	return (0);
737283514Sarybchik
738301984Sarybchikfail3:
739301984Sarybchik	EFSYS_PROBE(fail3);
740301983Sarybchikfail2:
741301983Sarybchik	EFSYS_PROBE(fail2);
742283514Sarybchikfail1:
743291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
744283514Sarybchik
745283514Sarybchik	return (rc);
746283514Sarybchik}
747283514Sarybchik
748283514Sarybchik
749283514Sarybchik#if EFSYS_OPT_QSTATS
750283514Sarybchik			void
751293752Sarybchikef10_ev_qstats_update(
752283514Sarybchik	__in				efx_evq_t *eep,
753283514Sarybchik	__inout_ecount(EV_NQSTATS)	efsys_stat_t *stat)
754283514Sarybchik{
755283514Sarybchik	unsigned int id;
756283514Sarybchik
757283514Sarybchik	for (id = 0; id < EV_NQSTATS; id++) {
758283514Sarybchik		efsys_stat_t *essp = &stat[id];
759283514Sarybchik
760283514Sarybchik		EFSYS_STAT_INCR(essp, eep->ee_stat[id]);
761283514Sarybchik		eep->ee_stat[id] = 0;
762283514Sarybchik	}
763283514Sarybchik}
764283514Sarybchik#endif /* EFSYS_OPT_QSTATS */
765283514Sarybchik
766283514Sarybchik
767283514Sarybchikstatic	__checkReturn	boolean_t
768293752Sarybchikef10_ev_rx(
769283514Sarybchik	__in		efx_evq_t *eep,
770283514Sarybchik	__in		efx_qword_t *eqp,
771283514Sarybchik	__in		const efx_ev_callbacks_t *eecp,
772283514Sarybchik	__in_opt	void *arg)
773283514Sarybchik{
774283514Sarybchik	efx_nic_t *enp = eep->ee_enp;
775283514Sarybchik	uint32_t size;
776283514Sarybchik	uint32_t label;
777294310Sarybchik	uint32_t mac_class;
778283514Sarybchik	uint32_t eth_tag_class;
779283514Sarybchik	uint32_t l3_class;
780283514Sarybchik	uint32_t l4_class;
781283514Sarybchik	uint32_t next_read_lbits;
782283514Sarybchik	uint16_t flags;
783294310Sarybchik	boolean_t cont;
784283514Sarybchik	boolean_t should_abort;
785283514Sarybchik	efx_evq_rxq_state_t *eersp;
786283514Sarybchik	unsigned int desc_count;
787283514Sarybchik	unsigned int last_used_id;
788283514Sarybchik
789283514Sarybchik	EFX_EV_QSTAT_INCR(eep, EV_RX);
790283514Sarybchik
791283514Sarybchik	/* Discard events after RXQ/TXQ errors */
792283514Sarybchik	if (enp->en_reset_flags & (EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR))
793283514Sarybchik		return (B_FALSE);
794283514Sarybchik
795294310Sarybchik	/* Basic packet information */
796294310Sarybchik	size = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_BYTES);
797294310Sarybchik	next_read_lbits = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_DSC_PTR_LBITS);
798294310Sarybchik	label = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_QLABEL);
799294310Sarybchik	eth_tag_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_ETH_TAG_CLASS);
800294310Sarybchik	mac_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_MAC_CLASS);
801294310Sarybchik	l3_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_L3_CLASS);
802294310Sarybchik	l4_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_L4_CLASS);
803294310Sarybchik	cont = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_CONT);
804283514Sarybchik
805283514Sarybchik	if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_DROP_EVENT) != 0) {
806283514Sarybchik		/* Drop this event */
807283514Sarybchik		return (B_FALSE);
808283514Sarybchik	}
809283514Sarybchik	flags = 0;
810283514Sarybchik
811294310Sarybchik	if (cont != 0) {
812283514Sarybchik		/*
813291747Sarybchik		 * This may be part of a scattered frame, or it may be a
814291747Sarybchik		 * truncated frame if scatter is disabled on this RXQ.
815291747Sarybchik		 * Overlength frames can be received if e.g. a VF is configured
816291747Sarybchik		 * for 1500 MTU but connected to a port set to 9000 MTU
817291747Sarybchik		 * (see bug56567).
818283514Sarybchik		 * FIXME: There is not yet any driver that supports scatter on
819283514Sarybchik		 * Huntington.  Scatter support is required for OSX.
820283514Sarybchik		 */
821283514Sarybchik		flags |= EFX_PKT_CONT;
822283514Sarybchik	}
823283514Sarybchik
824294310Sarybchik	if (mac_class == ESE_DZ_MAC_CLASS_UCAST)
825283514Sarybchik		flags |= EFX_PKT_UNICAST;
826283514Sarybchik
827283514Sarybchik	/* Increment the count of descriptors read */
828283514Sarybchik	eersp = &eep->ee_rxq_state[label];
829283514Sarybchik	desc_count = (next_read_lbits - eersp->eers_rx_read_ptr) &
830283514Sarybchik	    EFX_MASK32(ESF_DZ_RX_DSC_PTR_LBITS);
831283514Sarybchik	eersp->eers_rx_read_ptr += desc_count;
832283514Sarybchik
833283514Sarybchik	/*
834283514Sarybchik	 * FIXME: add error checking to make sure this a batched event.
835283514Sarybchik	 * This could also be an aborted scatter, see Bug36629.
836283514Sarybchik	 */
837283514Sarybchik	if (desc_count > 1) {
838283514Sarybchik		EFX_EV_QSTAT_INCR(eep, EV_RX_BATCH);
839283514Sarybchik		flags |= EFX_PKT_PREFIX_LEN;
840283514Sarybchik	}
841283514Sarybchik
842283514Sarybchik	/* Calculate the index of the the last descriptor consumed */
843283514Sarybchik	last_used_id = (eersp->eers_rx_read_ptr - 1) & eersp->eers_rx_mask;
844283514Sarybchik
845294310Sarybchik	/* Check for errors that invalidate checksum and L3/L4 fields */
846294310Sarybchik	if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_ECC_ERR) != 0) {
847294310Sarybchik		/* RX frame truncated (error flag is misnamed) */
848294310Sarybchik		EFX_EV_QSTAT_INCR(eep, EV_RX_FRM_TRUNC);
849294310Sarybchik		flags |= EFX_DISCARD;
850294310Sarybchik		goto deliver;
851283514Sarybchik	}
852294310Sarybchik	if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_ECRC_ERR) != 0) {
853294310Sarybchik		/* Bad Ethernet frame CRC */
854294310Sarybchik		EFX_EV_QSTAT_INCR(eep, EV_RX_ETH_CRC_ERR);
855294310Sarybchik		flags |= EFX_DISCARD;
856294310Sarybchik		goto deliver;
857294310Sarybchik	}
858294310Sarybchik	if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_PARSE_INCOMPLETE)) {
859294310Sarybchik		/*
860294310Sarybchik		 * Hardware parse failed, due to malformed headers
861294310Sarybchik		 * or headers that are too long for the parser.
862294310Sarybchik		 * Headers and checksums must be validated by the host.
863294310Sarybchik		 */
864311050Sarybchik		/* TODO: EFX_EV_QSTAT_INCR(eep, EV_RX_PARSE_INCOMPLETE); */
865294310Sarybchik		goto deliver;
866294310Sarybchik	}
867283514Sarybchik
868294310Sarybchik	if ((eth_tag_class == ESE_DZ_ETH_TAG_CLASS_VLAN1) ||
869294310Sarybchik	    (eth_tag_class == ESE_DZ_ETH_TAG_CLASS_VLAN2)) {
870283514Sarybchik		flags |= EFX_PKT_VLAN_TAGGED;
871283514Sarybchik	}
872283514Sarybchik
873283514Sarybchik	switch (l3_class) {
874294310Sarybchik	case ESE_DZ_L3_CLASS_IP4:
875294310Sarybchik	case ESE_DZ_L3_CLASS_IP4_FRAG:
876294310Sarybchik		flags |= EFX_PKT_IPV4;
877294310Sarybchik		if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_IPCKSUM_ERR)) {
878294310Sarybchik			EFX_EV_QSTAT_INCR(eep, EV_RX_IPV4_HDR_CHKSUM_ERR);
879294310Sarybchik		} else {
880294310Sarybchik			flags |= EFX_CKSUM_IPV4;
881294310Sarybchik		}
882283514Sarybchik
883294310Sarybchik		if (l4_class == ESE_DZ_L4_CLASS_TCP) {
884294310Sarybchik			EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_IPV4);
885294310Sarybchik			flags |= EFX_PKT_TCP;
886294310Sarybchik		} else if (l4_class == ESE_DZ_L4_CLASS_UDP) {
887294310Sarybchik			EFX_EV_QSTAT_INCR(eep, EV_RX_UDP_IPV4);
888294310Sarybchik			flags |= EFX_PKT_UDP;
889294310Sarybchik		} else {
890294310Sarybchik			EFX_EV_QSTAT_INCR(eep, EV_RX_OTHER_IPV4);
891294310Sarybchik		}
892283514Sarybchik		break;
893283514Sarybchik
894294310Sarybchik	case ESE_DZ_L3_CLASS_IP6:
895283514Sarybchik	case ESE_DZ_L3_CLASS_IP6_FRAG:
896283514Sarybchik		flags |= EFX_PKT_IPV6;
897283514Sarybchik
898294310Sarybchik		if (l4_class == ESE_DZ_L4_CLASS_TCP) {
899294310Sarybchik			EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_IPV6);
900294310Sarybchik			flags |= EFX_PKT_TCP;
901294310Sarybchik		} else if (l4_class == ESE_DZ_L4_CLASS_UDP) {
902294310Sarybchik			EFX_EV_QSTAT_INCR(eep, EV_RX_UDP_IPV6);
903294310Sarybchik			flags |= EFX_PKT_UDP;
904294310Sarybchik		} else {
905294310Sarybchik			EFX_EV_QSTAT_INCR(eep, EV_RX_OTHER_IPV6);
906294310Sarybchik		}
907283514Sarybchik		break;
908283514Sarybchik
909283514Sarybchik	default:
910294310Sarybchik		EFX_EV_QSTAT_INCR(eep, EV_RX_NON_IP);
911283514Sarybchik		break;
912283514Sarybchik	}
913283514Sarybchik
914294310Sarybchik	if (flags & (EFX_PKT_TCP | EFX_PKT_UDP)) {
915294310Sarybchik		if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_TCPUDP_CKSUM_ERR)) {
916294310Sarybchik			EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_UDP_CHKSUM_ERR);
917294310Sarybchik		} else {
918283514Sarybchik			flags |= EFX_CKSUM_TCPUDP;
919294310Sarybchik		}
920283514Sarybchik	}
921283514Sarybchik
922294310Sarybchikdeliver:
923283514Sarybchik	/* If we're not discarding the packet then it is ok */
924283514Sarybchik	if (~flags & EFX_DISCARD)
925283514Sarybchik		EFX_EV_QSTAT_INCR(eep, EV_RX_OK);
926283514Sarybchik
927283514Sarybchik	EFSYS_ASSERT(eecp->eec_rx != NULL);
928283514Sarybchik	should_abort = eecp->eec_rx(arg, label, last_used_id, size, flags);
929283514Sarybchik
930283514Sarybchik	return (should_abort);
931283514Sarybchik}
932283514Sarybchik
933283514Sarybchikstatic	__checkReturn	boolean_t
934293752Sarybchikef10_ev_tx(
935283514Sarybchik	__in		efx_evq_t *eep,
936283514Sarybchik	__in		efx_qword_t *eqp,
937283514Sarybchik	__in		const efx_ev_callbacks_t *eecp,
938283514Sarybchik	__in_opt	void *arg)
939283514Sarybchik{
940283514Sarybchik	efx_nic_t *enp = eep->ee_enp;
941283514Sarybchik	uint32_t id;
942283514Sarybchik	uint32_t label;
943283514Sarybchik	boolean_t should_abort;
944283514Sarybchik
945283514Sarybchik	EFX_EV_QSTAT_INCR(eep, EV_TX);
946283514Sarybchik
947283514Sarybchik	/* Discard events after RXQ/TXQ errors */
948283514Sarybchik	if (enp->en_reset_flags & (EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR))
949283514Sarybchik		return (B_FALSE);
950283514Sarybchik
951283514Sarybchik	if (EFX_QWORD_FIELD(*eqp, ESF_DZ_TX_DROP_EVENT) != 0) {
952283514Sarybchik		/* Drop this event */
953283514Sarybchik		return (B_FALSE);
954283514Sarybchik	}
955283514Sarybchik
956283514Sarybchik	/* Per-packet TX completion (was per-descriptor for Falcon/Siena) */
957283514Sarybchik	id = EFX_QWORD_FIELD(*eqp, ESF_DZ_TX_DESCR_INDX);
958283514Sarybchik	label = EFX_QWORD_FIELD(*eqp, ESF_DZ_TX_QLABEL);
959283514Sarybchik
960283514Sarybchik	EFSYS_PROBE2(tx_complete, uint32_t, label, uint32_t, id);
961283514Sarybchik
962283514Sarybchik	EFSYS_ASSERT(eecp->eec_tx != NULL);
963283514Sarybchik	should_abort = eecp->eec_tx(arg, label, id);
964283514Sarybchik
965283514Sarybchik	return (should_abort);
966283514Sarybchik}
967283514Sarybchik
968283514Sarybchikstatic	__checkReturn	boolean_t
969293752Sarybchikef10_ev_driver(
970283514Sarybchik	__in		efx_evq_t *eep,
971283514Sarybchik	__in		efx_qword_t *eqp,
972283514Sarybchik	__in		const efx_ev_callbacks_t *eecp,
973283514Sarybchik	__in_opt	void *arg)
974283514Sarybchik{
975283514Sarybchik	unsigned int code;
976283514Sarybchik	boolean_t should_abort;
977283514Sarybchik
978283514Sarybchik	EFX_EV_QSTAT_INCR(eep, EV_DRIVER);
979283514Sarybchik	should_abort = B_FALSE;
980283514Sarybchik
981283514Sarybchik	code = EFX_QWORD_FIELD(*eqp, ESF_DZ_DRV_SUB_CODE);
982283514Sarybchik	switch (code) {
983283514Sarybchik	case ESE_DZ_DRV_TIMER_EV: {
984283514Sarybchik		uint32_t id;
985283514Sarybchik
986283514Sarybchik		id = EFX_QWORD_FIELD(*eqp, ESF_DZ_DRV_TMR_ID);
987283514Sarybchik
988283514Sarybchik		EFSYS_ASSERT(eecp->eec_timer != NULL);
989283514Sarybchik		should_abort = eecp->eec_timer(arg, id);
990283514Sarybchik		break;
991283514Sarybchik	}
992283514Sarybchik
993283514Sarybchik	case ESE_DZ_DRV_WAKE_UP_EV: {
994283514Sarybchik		uint32_t id;
995283514Sarybchik
996283514Sarybchik		id = EFX_QWORD_FIELD(*eqp, ESF_DZ_DRV_EVQ_ID);
997283514Sarybchik
998283514Sarybchik		EFSYS_ASSERT(eecp->eec_wake_up != NULL);
999283514Sarybchik		should_abort = eecp->eec_wake_up(arg, id);
1000283514Sarybchik		break;
1001283514Sarybchik	}
1002283514Sarybchik
1003283514Sarybchik	case ESE_DZ_DRV_START_UP_EV:
1004283514Sarybchik		EFSYS_ASSERT(eecp->eec_initialized != NULL);
1005283514Sarybchik		should_abort = eecp->eec_initialized(arg);
1006283514Sarybchik		break;
1007283514Sarybchik
1008283514Sarybchik	default:
1009283514Sarybchik		EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index,
1010283514Sarybchik		    uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1),
1011283514Sarybchik		    uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0));
1012283514Sarybchik		break;
1013283514Sarybchik	}
1014283514Sarybchik
1015283514Sarybchik	return (should_abort);
1016283514Sarybchik}
1017283514Sarybchik
1018283514Sarybchikstatic	__checkReturn	boolean_t
1019293752Sarybchikef10_ev_drv_gen(
1020283514Sarybchik	__in		efx_evq_t *eep,
1021283514Sarybchik	__in		efx_qword_t *eqp,
1022283514Sarybchik	__in		const efx_ev_callbacks_t *eecp,
1023283514Sarybchik	__in_opt	void *arg)
1024283514Sarybchik{
1025283514Sarybchik	uint32_t data;
1026283514Sarybchik	boolean_t should_abort;
1027283514Sarybchik
1028283514Sarybchik	EFX_EV_QSTAT_INCR(eep, EV_DRV_GEN);
1029283514Sarybchik	should_abort = B_FALSE;
1030283514Sarybchik
1031283514Sarybchik	data = EFX_QWORD_FIELD(*eqp, ESF_DZ_DRV_SUB_DATA_DW0);
1032283514Sarybchik	if (data >= ((uint32_t)1 << 16)) {
1033283514Sarybchik		EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index,
1034283514Sarybchik		    uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1),
1035283514Sarybchik		    uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0));
1036283514Sarybchik
1037283514Sarybchik		return (B_TRUE);
1038283514Sarybchik	}
1039283514Sarybchik
1040283514Sarybchik	EFSYS_ASSERT(eecp->eec_software != NULL);
1041283514Sarybchik	should_abort = eecp->eec_software(arg, (uint16_t)data);
1042283514Sarybchik
1043283514Sarybchik	return (should_abort);
1044283514Sarybchik}
1045283514Sarybchik
1046283514Sarybchikstatic	__checkReturn	boolean_t
1047293752Sarybchikef10_ev_mcdi(
1048283514Sarybchik	__in		efx_evq_t *eep,
1049283514Sarybchik	__in		efx_qword_t *eqp,
1050283514Sarybchik	__in		const efx_ev_callbacks_t *eecp,
1051283514Sarybchik	__in_opt	void *arg)
1052283514Sarybchik{
1053283514Sarybchik	efx_nic_t *enp = eep->ee_enp;
1054311062Sarybchik	unsigned int code;
1055283514Sarybchik	boolean_t should_abort = B_FALSE;
1056283514Sarybchik
1057283514Sarybchik	EFX_EV_QSTAT_INCR(eep, EV_MCDI_RESPONSE);
1058283514Sarybchik
1059283514Sarybchik	code = EFX_QWORD_FIELD(*eqp, MCDI_EVENT_CODE);
1060283514Sarybchik	switch (code) {
1061283514Sarybchik	case MCDI_EVENT_CODE_BADSSERT:
1062283514Sarybchik		efx_mcdi_ev_death(enp, EINTR);
1063283514Sarybchik		break;
1064283514Sarybchik
1065283514Sarybchik	case MCDI_EVENT_CODE_CMDDONE:
1066283514Sarybchik		efx_mcdi_ev_cpl(enp,
1067283514Sarybchik		    MCDI_EV_FIELD(eqp, CMDDONE_SEQ),
1068283514Sarybchik		    MCDI_EV_FIELD(eqp, CMDDONE_DATALEN),
1069283514Sarybchik		    MCDI_EV_FIELD(eqp, CMDDONE_ERRNO));
1070283514Sarybchik		break;
1071283514Sarybchik
1072292051Sarybchik#if EFSYS_OPT_MCDI_PROXY_AUTH
1073292051Sarybchik	case MCDI_EVENT_CODE_PROXY_RESPONSE:
1074292051Sarybchik		/*
1075292051Sarybchik		 * This event notifies a function that an authorization request
1076292051Sarybchik		 * has been processed. If the request was authorized then the
1077292051Sarybchik		 * function can now re-send the original MCDI request.
1078292051Sarybchik		 * See SF-113652-SW "SR-IOV Proxied Network Access Control".
1079292051Sarybchik		 */
1080292051Sarybchik		efx_mcdi_ev_proxy_response(enp,
1081292051Sarybchik		    MCDI_EV_FIELD(eqp, PROXY_RESPONSE_HANDLE),
1082292051Sarybchik		    MCDI_EV_FIELD(eqp, PROXY_RESPONSE_RC));
1083292051Sarybchik		break;
1084292051Sarybchik#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
1085292051Sarybchik
1086283514Sarybchik	case MCDI_EVENT_CODE_LINKCHANGE: {
1087283514Sarybchik		efx_link_mode_t link_mode;
1088283514Sarybchik
1089294091Sarybchik		ef10_phy_link_ev(enp, eqp, &link_mode);
1090283514Sarybchik		should_abort = eecp->eec_link_change(arg, link_mode);
1091283514Sarybchik		break;
1092283514Sarybchik	}
1093283514Sarybchik
1094283514Sarybchik	case MCDI_EVENT_CODE_SENSOREVT: {
1095283514Sarybchik#if EFSYS_OPT_MON_STATS
1096283514Sarybchik		efx_mon_stat_t id;
1097283514Sarybchik		efx_mon_stat_value_t value;
1098291436Sarybchik		efx_rc_t rc;
1099283514Sarybchik
1100283514Sarybchik		/* Decode monitor stat for MCDI sensor (if supported) */
1101283514Sarybchik		if ((rc = mcdi_mon_ev(enp, eqp, &id, &value)) == 0) {
1102283514Sarybchik			/* Report monitor stat change */
1103283514Sarybchik			should_abort = eecp->eec_monitor(arg, id, value);
1104283514Sarybchik		} else if (rc == ENOTSUP) {
1105283514Sarybchik			should_abort = eecp->eec_exception(arg,
1106283514Sarybchik				EFX_EXCEPTION_UNKNOWN_SENSOREVT,
1107283514Sarybchik				MCDI_EV_FIELD(eqp, DATA));
1108283514Sarybchik		} else {
1109283514Sarybchik			EFSYS_ASSERT(rc == ENODEV);	/* Wrong port */
1110283514Sarybchik		}
1111283514Sarybchik#endif
1112283514Sarybchik		break;
1113283514Sarybchik	}
1114283514Sarybchik
1115283514Sarybchik	case MCDI_EVENT_CODE_SCHEDERR:
1116283514Sarybchik		/* Informational only */
1117283514Sarybchik		break;
1118283514Sarybchik
1119283514Sarybchik	case MCDI_EVENT_CODE_REBOOT:
1120283514Sarybchik		/* Falcon/Siena only (should not been seen with Huntington). */
1121283514Sarybchik		efx_mcdi_ev_death(enp, EIO);
1122283514Sarybchik		break;
1123283514Sarybchik
1124283514Sarybchik	case MCDI_EVENT_CODE_MC_REBOOT:
1125283514Sarybchik		/* MC_REBOOT event is used for Huntington (EF10) and later. */
1126283514Sarybchik		efx_mcdi_ev_death(enp, EIO);
1127283514Sarybchik		break;
1128283514Sarybchik
1129283514Sarybchik	case MCDI_EVENT_CODE_MAC_STATS_DMA:
1130283514Sarybchik#if EFSYS_OPT_MAC_STATS
1131283514Sarybchik		if (eecp->eec_mac_stats != NULL) {
1132283514Sarybchik			eecp->eec_mac_stats(arg,
1133283514Sarybchik			    MCDI_EV_FIELD(eqp, MAC_STATS_DMA_GENERATION));
1134283514Sarybchik		}
1135283514Sarybchik#endif
1136283514Sarybchik		break;
1137283514Sarybchik
1138283514Sarybchik	case MCDI_EVENT_CODE_FWALERT: {
1139283514Sarybchik		uint32_t reason = MCDI_EV_FIELD(eqp, FWALERT_REASON);
1140283514Sarybchik
1141283514Sarybchik		if (reason == MCDI_EVENT_FWALERT_REASON_SRAM_ACCESS)
1142283514Sarybchik			should_abort = eecp->eec_exception(arg,
1143283514Sarybchik				EFX_EXCEPTION_FWALERT_SRAM,
1144283514Sarybchik				MCDI_EV_FIELD(eqp, FWALERT_DATA));
1145283514Sarybchik		else
1146283514Sarybchik			should_abort = eecp->eec_exception(arg,
1147283514Sarybchik				EFX_EXCEPTION_UNKNOWN_FWALERT,
1148283514Sarybchik				MCDI_EV_FIELD(eqp, DATA));
1149283514Sarybchik		break;
1150283514Sarybchik	}
1151283514Sarybchik
1152283514Sarybchik	case MCDI_EVENT_CODE_TX_ERR: {
1153283514Sarybchik		/*
1154283514Sarybchik		 * After a TXQ error is detected, firmware sends a TX_ERR event.
1155283514Sarybchik		 * This may be followed by TX completions (which we discard),
1156283514Sarybchik		 * and then finally by a TX_FLUSH event. Firmware destroys the
1157283514Sarybchik		 * TXQ automatically after sending the TX_FLUSH event.
1158283514Sarybchik		 */
1159283514Sarybchik		enp->en_reset_flags |= EFX_RESET_TXQ_ERR;
1160283514Sarybchik
1161301371Sarybchik		EFSYS_PROBE2(tx_descq_err,
1162301371Sarybchik			    uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1),
1163301371Sarybchik			    uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0));
1164283514Sarybchik
1165283514Sarybchik		/* Inform the driver that a reset is required. */
1166283514Sarybchik		eecp->eec_exception(arg, EFX_EXCEPTION_TX_ERROR,
1167283514Sarybchik		    MCDI_EV_FIELD(eqp, TX_ERR_DATA));
1168283514Sarybchik		break;
1169283514Sarybchik	}
1170283514Sarybchik
1171283514Sarybchik	case MCDI_EVENT_CODE_TX_FLUSH: {
1172283514Sarybchik		uint32_t txq_index = MCDI_EV_FIELD(eqp, TX_FLUSH_TXQ);
1173283514Sarybchik
1174283514Sarybchik		/*
1175283514Sarybchik		 * EF10 firmware sends two TX_FLUSH events: one to the txq's
1176283514Sarybchik		 * event queue, and one to evq 0 (with TX_FLUSH_TO_DRIVER set).
1177283514Sarybchik		 * We want to wait for all completions, so ignore the events
1178283514Sarybchik		 * with TX_FLUSH_TO_DRIVER.
1179283514Sarybchik		 */
1180283514Sarybchik		if (MCDI_EV_FIELD(eqp, TX_FLUSH_TO_DRIVER) != 0) {
1181283514Sarybchik			should_abort = B_FALSE;
1182283514Sarybchik			break;
1183283514Sarybchik		}
1184283514Sarybchik
1185283514Sarybchik		EFX_EV_QSTAT_INCR(eep, EV_DRIVER_TX_DESCQ_FLS_DONE);
1186283514Sarybchik
1187283514Sarybchik		EFSYS_PROBE1(tx_descq_fls_done, uint32_t, txq_index);
1188283514Sarybchik
1189283514Sarybchik		EFSYS_ASSERT(eecp->eec_txq_flush_done != NULL);
1190283514Sarybchik		should_abort = eecp->eec_txq_flush_done(arg, txq_index);
1191283514Sarybchik		break;
1192283514Sarybchik	}
1193283514Sarybchik
1194283514Sarybchik	case MCDI_EVENT_CODE_RX_ERR: {
1195283514Sarybchik		/*
1196283514Sarybchik		 * After an RXQ error is detected, firmware sends an RX_ERR
1197283514Sarybchik		 * event. This may be followed by RX events (which we discard),
1198283514Sarybchik		 * and then finally by an RX_FLUSH event. Firmware destroys the
1199283514Sarybchik		 * RXQ automatically after sending the RX_FLUSH event.
1200283514Sarybchik		 */
1201283514Sarybchik		enp->en_reset_flags |= EFX_RESET_RXQ_ERR;
1202283514Sarybchik
1203301371Sarybchik		EFSYS_PROBE2(rx_descq_err,
1204301371Sarybchik			    uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1),
1205301371Sarybchik			    uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0));
1206283514Sarybchik
1207283514Sarybchik		/* Inform the driver that a reset is required. */
1208283514Sarybchik		eecp->eec_exception(arg, EFX_EXCEPTION_RX_ERROR,
1209283514Sarybchik		    MCDI_EV_FIELD(eqp, RX_ERR_DATA));
1210283514Sarybchik		break;
1211283514Sarybchik	}
1212283514Sarybchik
1213283514Sarybchik	case MCDI_EVENT_CODE_RX_FLUSH: {
1214283514Sarybchik		uint32_t rxq_index = MCDI_EV_FIELD(eqp, RX_FLUSH_RXQ);
1215283514Sarybchik
1216283514Sarybchik		/*
1217283514Sarybchik		 * EF10 firmware sends two RX_FLUSH events: one to the rxq's
1218283514Sarybchik		 * event queue, and one to evq 0 (with RX_FLUSH_TO_DRIVER set).
1219283514Sarybchik		 * We want to wait for all completions, so ignore the events
1220283514Sarybchik		 * with RX_FLUSH_TO_DRIVER.
1221283514Sarybchik		 */
1222283514Sarybchik		if (MCDI_EV_FIELD(eqp, RX_FLUSH_TO_DRIVER) != 0) {
1223283514Sarybchik			should_abort = B_FALSE;
1224283514Sarybchik			break;
1225283514Sarybchik		}
1226283514Sarybchik
1227283514Sarybchik		EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DESCQ_FLS_DONE);
1228283514Sarybchik
1229283514Sarybchik		EFSYS_PROBE1(rx_descq_fls_done, uint32_t, rxq_index);
1230283514Sarybchik
1231283514Sarybchik		EFSYS_ASSERT(eecp->eec_rxq_flush_done != NULL);
1232283514Sarybchik		should_abort = eecp->eec_rxq_flush_done(arg, rxq_index);
1233283514Sarybchik		break;
1234283514Sarybchik	}
1235283514Sarybchik
1236283514Sarybchik	default:
1237283514Sarybchik		EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index,
1238283514Sarybchik		    uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1),
1239283514Sarybchik		    uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0));
1240283514Sarybchik		break;
1241283514Sarybchik	}
1242283514Sarybchik
1243283514Sarybchik	return (should_abort);
1244283514Sarybchik}
1245283514Sarybchik
1246283514Sarybchik		void
1247293752Sarybchikef10_ev_rxlabel_init(
1248283514Sarybchik	__in		efx_evq_t *eep,
1249283514Sarybchik	__in		efx_rxq_t *erp,
1250283514Sarybchik	__in		unsigned int label)
1251283514Sarybchik{
1252283514Sarybchik	efx_evq_rxq_state_t *eersp;
1253283514Sarybchik
1254283514Sarybchik	EFSYS_ASSERT3U(label, <, EFX_ARRAY_SIZE(eep->ee_rxq_state));
1255283514Sarybchik	eersp = &eep->ee_rxq_state[label];
1256283514Sarybchik
1257283514Sarybchik	EFSYS_ASSERT3U(eersp->eers_rx_mask, ==, 0);
1258283514Sarybchik
1259283514Sarybchik	eersp->eers_rx_read_ptr = 0;
1260283514Sarybchik	eersp->eers_rx_mask = erp->er_mask;
1261283514Sarybchik}
1262283514Sarybchik
1263283514Sarybchik		void
1264293752Sarybchikef10_ev_rxlabel_fini(
1265283514Sarybchik	__in		efx_evq_t *eep,
1266283514Sarybchik	__in		unsigned int label)
1267283514Sarybchik{
1268283514Sarybchik	efx_evq_rxq_state_t *eersp;
1269283514Sarybchik
1270283514Sarybchik	EFSYS_ASSERT3U(label, <, EFX_ARRAY_SIZE(eep->ee_rxq_state));
1271283514Sarybchik	eersp = &eep->ee_rxq_state[label];
1272283514Sarybchik
1273283514Sarybchik	EFSYS_ASSERT3U(eersp->eers_rx_mask, !=, 0);
1274283514Sarybchik
1275283514Sarybchik	eersp->eers_rx_read_ptr = 0;
1276283514Sarybchik	eersp->eers_rx_mask = 0;
1277283514Sarybchik}
1278283514Sarybchik
1279299596Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
1280