xref: /dragonfly/sys/dev/netif/oce/oce_queue.c (revision 030b0c8c)
1229aec1cSSascha Wildner /*-
2*c976b08eSSascha Wildner  * Copyright (C) 2013 Emulex
3229aec1cSSascha Wildner  * All rights reserved.
4229aec1cSSascha Wildner  *
5229aec1cSSascha Wildner  * Redistribution and use in source and binary forms, with or without
6229aec1cSSascha Wildner  * modification, are permitted provided that the following conditions are met:
7229aec1cSSascha Wildner  *
8229aec1cSSascha Wildner  * 1. Redistributions of source code must retain the above copyright notice,
9229aec1cSSascha Wildner  *    this list of conditions and the following disclaimer.
10229aec1cSSascha Wildner  *
11229aec1cSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
12229aec1cSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
13229aec1cSSascha Wildner  *    documentation and/or other materials provided with the distribution.
14229aec1cSSascha Wildner  *
15229aec1cSSascha Wildner  * 3. Neither the name of the Emulex Corporation nor the names of its
16229aec1cSSascha Wildner  *    contributors may be used to endorse or promote products derived from
17229aec1cSSascha Wildner  *    this software without specific prior written permission.
18229aec1cSSascha Wildner  *
19229aec1cSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20229aec1cSSascha Wildner  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21229aec1cSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22229aec1cSSascha Wildner  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23229aec1cSSascha Wildner  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24229aec1cSSascha Wildner  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25229aec1cSSascha Wildner  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26229aec1cSSascha Wildner  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27229aec1cSSascha Wildner  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28229aec1cSSascha Wildner  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29229aec1cSSascha Wildner  * POSSIBILITY OF SUCH DAMAGE.
30229aec1cSSascha Wildner  *
31229aec1cSSascha Wildner  * Contact Information:
32229aec1cSSascha Wildner  * freebsd-drivers@emulex.com
33229aec1cSSascha Wildner  *
34229aec1cSSascha Wildner  * Emulex
35229aec1cSSascha Wildner  * 3333 Susan Street
36229aec1cSSascha Wildner  * Costa Mesa, CA 92626
37229aec1cSSascha Wildner  */
38229aec1cSSascha Wildner 
39229aec1cSSascha Wildner 
40229aec1cSSascha Wildner 
41*c976b08eSSascha Wildner /* $FreeBSD: src/sys/dev/oce/oce_queue.c,v 1.5 2013/07/07 00:30:13 svnexp Exp $ */
42229aec1cSSascha Wildner 
43229aec1cSSascha Wildner 
44229aec1cSSascha Wildner #include "oce_if.h"
45229aec1cSSascha Wildner 
46229aec1cSSascha Wildner /*****************************************************
47229aec1cSSascha Wildner  * local queue functions
48229aec1cSSascha Wildner  *****************************************************/
49229aec1cSSascha Wildner 
50229aec1cSSascha Wildner static struct oce_wq *oce_wq_init(POCE_SOFTC sc,
51229aec1cSSascha Wildner 				  uint32_t q_len, uint32_t wq_type);
52229aec1cSSascha Wildner static int oce_wq_create(struct oce_wq *wq, struct oce_eq *eq);
53229aec1cSSascha Wildner static void oce_wq_free(struct oce_wq *wq);
54229aec1cSSascha Wildner static void oce_wq_del(struct oce_wq *wq);
55229aec1cSSascha Wildner static struct oce_rq *oce_rq_init(POCE_SOFTC sc,
56229aec1cSSascha Wildner 				  uint32_t q_len,
57229aec1cSSascha Wildner 				  uint32_t frag_size,
58229aec1cSSascha Wildner 				  uint32_t mtu, uint32_t rss);
59229aec1cSSascha Wildner static int oce_rq_create(struct oce_rq *rq, uint32_t if_id, struct oce_eq *eq);
60229aec1cSSascha Wildner static void oce_rq_free(struct oce_rq *rq);
61229aec1cSSascha Wildner static void oce_rq_del(struct oce_rq *rq);
62229aec1cSSascha Wildner static struct oce_eq *oce_eq_create(POCE_SOFTC sc,
63229aec1cSSascha Wildner 				    uint32_t q_len,
64229aec1cSSascha Wildner 				    uint32_t item_size,
65229aec1cSSascha Wildner 				    uint32_t eq_delay,
66229aec1cSSascha Wildner 				    uint32_t vector);
67229aec1cSSascha Wildner static void oce_eq_del(struct oce_eq *eq);
68229aec1cSSascha Wildner static struct oce_mq *oce_mq_create(POCE_SOFTC sc,
69229aec1cSSascha Wildner 				    struct oce_eq *eq, uint32_t q_len);
70229aec1cSSascha Wildner static void oce_mq_free(struct oce_mq *mq);
71229aec1cSSascha Wildner static int oce_destroy_q(POCE_SOFTC sc, struct oce_mbx
72229aec1cSSascha Wildner 			 *mbx, size_t req_size, enum qtype qtype);
73229aec1cSSascha Wildner struct oce_cq *oce_cq_create(POCE_SOFTC sc,
74229aec1cSSascha Wildner 			     struct oce_eq *eq,
75229aec1cSSascha Wildner 			     uint32_t q_len,
76229aec1cSSascha Wildner 			     uint32_t item_size,
77229aec1cSSascha Wildner 			     uint32_t sol_event,
78229aec1cSSascha Wildner 			     uint32_t is_eventable,
79229aec1cSSascha Wildner 			     uint32_t nodelay, uint32_t ncoalesce);
80229aec1cSSascha Wildner static void oce_cq_del(POCE_SOFTC sc, struct oce_cq *cq);
81229aec1cSSascha Wildner 
82229aec1cSSascha Wildner 
83229aec1cSSascha Wildner 
84229aec1cSSascha Wildner /**
85229aec1cSSascha Wildner  * @brief	Create and initialize all the queues on the board
86229aec1cSSascha Wildner  * @param sc	software handle to the device
87229aec1cSSascha Wildner  * @returns 0	if successful, or error
88229aec1cSSascha Wildner  **/
89229aec1cSSascha Wildner int
oce_queue_init_all(POCE_SOFTC sc)90229aec1cSSascha Wildner oce_queue_init_all(POCE_SOFTC sc)
91229aec1cSSascha Wildner {
92229aec1cSSascha Wildner 	int rc = 0, i, vector;
93229aec1cSSascha Wildner 	struct oce_wq *wq;
94229aec1cSSascha Wildner 	struct oce_rq *rq;
95229aec1cSSascha Wildner 	struct oce_aic_obj *aic;
96229aec1cSSascha Wildner 
97229aec1cSSascha Wildner 	/* alloc TX/RX queues */
98229aec1cSSascha Wildner 	for_all_wq_queues(sc, wq, i) {
99229aec1cSSascha Wildner 		sc->wq[i] = oce_wq_init(sc, sc->tx_ring_size,
100229aec1cSSascha Wildner 					 NIC_WQ_TYPE_STANDARD);
101229aec1cSSascha Wildner 		if (!sc->wq[i])
102229aec1cSSascha Wildner 			goto error;
103229aec1cSSascha Wildner 
104229aec1cSSascha Wildner 	}
105229aec1cSSascha Wildner 
106229aec1cSSascha Wildner 	for_all_rq_queues(sc, rq, i) {
107229aec1cSSascha Wildner 		sc->rq[i] = oce_rq_init(sc, sc->rx_ring_size, sc->rq_frag_size,
108229aec1cSSascha Wildner 					OCE_MAX_JUMBO_FRAME_SIZE,
109*c976b08eSSascha Wildner 					(i == 0) ? 0 : is_rss_enabled(sc));
110229aec1cSSascha Wildner 		if (!sc->rq[i])
111229aec1cSSascha Wildner 			goto error;
112229aec1cSSascha Wildner 	}
113229aec1cSSascha Wildner 
114229aec1cSSascha Wildner 	/* Create network interface on card */
115229aec1cSSascha Wildner 	if (oce_create_nw_interface(sc))
116229aec1cSSascha Wildner 		goto error;
117229aec1cSSascha Wildner 
118229aec1cSSascha Wildner 	/* create all of the event queues */
119229aec1cSSascha Wildner 	for (vector = 0; vector < sc->intr_count; vector++) {
120229aec1cSSascha Wildner 		/* setup aic defaults for each event queue */
121229aec1cSSascha Wildner 		aic = &sc->aic_obj[vector];
122229aec1cSSascha Wildner 		aic->max_eqd = OCE_MAX_EQD;
123229aec1cSSascha Wildner 		aic->min_eqd = OCE_MIN_EQD;
124229aec1cSSascha Wildner 		aic->et_eqd = OCE_MIN_EQD;
125229aec1cSSascha Wildner 		aic->enable = TRUE;
126229aec1cSSascha Wildner 
127229aec1cSSascha Wildner 		sc->eq[vector] = oce_eq_create(sc, EQ_LEN_1024, EQE_SIZE_4,
128229aec1cSSascha Wildner 						 0, vector);
129229aec1cSSascha Wildner 		if (!sc->eq[vector])
130229aec1cSSascha Wildner 			goto error;
131229aec1cSSascha Wildner 	}
132229aec1cSSascha Wildner 
133229aec1cSSascha Wildner 	/* create Tx, Rx and mcc queues */
134229aec1cSSascha Wildner 	for_all_wq_queues(sc, wq, i) {
135229aec1cSSascha Wildner 		rc = oce_wq_create(wq, sc->eq[i]);
136229aec1cSSascha Wildner 		if (rc)
137229aec1cSSascha Wildner 			goto error;
138229aec1cSSascha Wildner 		wq->queue_index = i;
139229aec1cSSascha Wildner 		TASK_INIT(&wq->txtask, 1, oce_tx_task, wq);
140229aec1cSSascha Wildner 	}
141229aec1cSSascha Wildner 
142229aec1cSSascha Wildner 	for_all_rq_queues(sc, rq, i) {
143229aec1cSSascha Wildner 		rc = oce_rq_create(rq, sc->if_id,
144229aec1cSSascha Wildner 					sc->eq[(i == 0) ? 0:(i-1)]);
145229aec1cSSascha Wildner 		if (rc)
146229aec1cSSascha Wildner 			goto error;
147229aec1cSSascha Wildner 		rq->queue_index = i;
148229aec1cSSascha Wildner 	}
149229aec1cSSascha Wildner 
150229aec1cSSascha Wildner 	sc->mq = oce_mq_create(sc, sc->eq[0], 64);
151229aec1cSSascha Wildner 	if (!sc->mq)
152229aec1cSSascha Wildner 		goto error;
153229aec1cSSascha Wildner 
154229aec1cSSascha Wildner 	return rc;
155229aec1cSSascha Wildner 
156229aec1cSSascha Wildner error:
157229aec1cSSascha Wildner 	oce_queue_release_all(sc);
158229aec1cSSascha Wildner 	return 1;
159229aec1cSSascha Wildner }
160229aec1cSSascha Wildner 
161229aec1cSSascha Wildner 
162229aec1cSSascha Wildner 
163229aec1cSSascha Wildner /**
164229aec1cSSascha Wildner  * @brief Releases all mailbox queues created
165229aec1cSSascha Wildner  * @param sc		software handle to the device
166229aec1cSSascha Wildner  */
167229aec1cSSascha Wildner void
oce_queue_release_all(POCE_SOFTC sc)168229aec1cSSascha Wildner oce_queue_release_all(POCE_SOFTC sc)
169229aec1cSSascha Wildner {
170229aec1cSSascha Wildner 	int i = 0;
171229aec1cSSascha Wildner 	struct oce_wq *wq;
172229aec1cSSascha Wildner 	struct oce_rq *rq;
173229aec1cSSascha Wildner 	struct oce_eq *eq;
174229aec1cSSascha Wildner 
175229aec1cSSascha Wildner 	for_all_rq_queues(sc, rq, i) {
176229aec1cSSascha Wildner 		if (rq) {
177229aec1cSSascha Wildner 			oce_rq_del(sc->rq[i]);
178229aec1cSSascha Wildner 			oce_rq_free(sc->rq[i]);
179229aec1cSSascha Wildner 		}
180229aec1cSSascha Wildner 	}
181229aec1cSSascha Wildner 
182229aec1cSSascha Wildner 	for_all_wq_queues(sc, wq, i) {
183229aec1cSSascha Wildner 		if (wq) {
184229aec1cSSascha Wildner 			oce_wq_del(sc->wq[i]);
185229aec1cSSascha Wildner 			oce_wq_free(sc->wq[i]);
186229aec1cSSascha Wildner 		}
187229aec1cSSascha Wildner 	}
188229aec1cSSascha Wildner 
189229aec1cSSascha Wildner 	if (sc->mq)
190229aec1cSSascha Wildner 		oce_mq_free(sc->mq);
191229aec1cSSascha Wildner 
192229aec1cSSascha Wildner 	for_all_evnt_queues(sc, eq, i) {
193229aec1cSSascha Wildner 		if (eq)
194229aec1cSSascha Wildner 			oce_eq_del(sc->eq[i]);
195229aec1cSSascha Wildner 	}
196229aec1cSSascha Wildner }
197229aec1cSSascha Wildner 
198229aec1cSSascha Wildner 
199229aec1cSSascha Wildner 
200229aec1cSSascha Wildner /**
201229aec1cSSascha Wildner  * @brief 		Function to create a WQ for NIC Tx
202229aec1cSSascha Wildner  * @param sc 		software handle to the device
203229aec1cSSascha Wildner  * @param qlen		number of entries in the queue
204229aec1cSSascha Wildner  * @param wq_type	work queue type
205229aec1cSSascha Wildner  * @returns		the pointer to the WQ created or NULL on failure
206229aec1cSSascha Wildner  */
207229aec1cSSascha Wildner static struct
oce_wq_init(POCE_SOFTC sc,uint32_t q_len,uint32_t wq_type)208229aec1cSSascha Wildner oce_wq *oce_wq_init(POCE_SOFTC sc, uint32_t q_len, uint32_t wq_type)
209229aec1cSSascha Wildner {
210229aec1cSSascha Wildner 	struct oce_wq *wq;
211229aec1cSSascha Wildner 	int rc = 0, i;
212229aec1cSSascha Wildner 
213229aec1cSSascha Wildner 	/* q_len must be min 256 and max 2k */
214229aec1cSSascha Wildner 	if (q_len < 256 || q_len > 2048) {
215229aec1cSSascha Wildner 		device_printf(sc->dev,
216229aec1cSSascha Wildner 			  "Invalid q length. Must be "
217229aec1cSSascha Wildner 			  "[256, 2000]: 0x%x\n", q_len);
218229aec1cSSascha Wildner 		return NULL;
219229aec1cSSascha Wildner 	}
220229aec1cSSascha Wildner 
221229aec1cSSascha Wildner 	/* allocate wq */
222229aec1cSSascha Wildner 	wq = kmalloc(sizeof(struct oce_wq), M_DEVBUF, M_NOWAIT | M_ZERO);
223229aec1cSSascha Wildner 	if (!wq)
224229aec1cSSascha Wildner 		return NULL;
225229aec1cSSascha Wildner 
226229aec1cSSascha Wildner 	/* Set the wq config */
227229aec1cSSascha Wildner 	wq->cfg.q_len = q_len;
228229aec1cSSascha Wildner 	wq->cfg.wq_type = (uint8_t) wq_type;
229229aec1cSSascha Wildner 	wq->cfg.eqd = OCE_DEFAULT_WQ_EQD;
230229aec1cSSascha Wildner 	wq->cfg.nbufs = 2 * wq->cfg.q_len;
231229aec1cSSascha Wildner 	wq->cfg.nhdl = 2 * wq->cfg.q_len;
232229aec1cSSascha Wildner 
233229aec1cSSascha Wildner 	wq->parent = (void *)sc;
234229aec1cSSascha Wildner 
235229aec1cSSascha Wildner 	rc = bus_dma_tag_create(NULL,
236229aec1cSSascha Wildner 				1, 0,
237229aec1cSSascha Wildner 				BUS_SPACE_MAXADDR,
238229aec1cSSascha Wildner 				BUS_SPACE_MAXADDR,
239229aec1cSSascha Wildner 				OCE_MAX_TX_SIZE,
240229aec1cSSascha Wildner 				OCE_MAX_TX_ELEMENTS,
241229aec1cSSascha Wildner 				PAGE_SIZE, 0, &wq->tag);
242229aec1cSSascha Wildner 
243229aec1cSSascha Wildner 	if (rc)
244229aec1cSSascha Wildner 		goto free_wq;
245229aec1cSSascha Wildner 
246229aec1cSSascha Wildner 
247229aec1cSSascha Wildner 	for (i = 0; i < OCE_WQ_PACKET_ARRAY_SIZE; i++) {
248229aec1cSSascha Wildner 		rc = bus_dmamap_create(wq->tag, 0, &wq->pckts[i].map);
249229aec1cSSascha Wildner 		if (rc)
250229aec1cSSascha Wildner 			goto free_wq;
251229aec1cSSascha Wildner 	}
252229aec1cSSascha Wildner 
253229aec1cSSascha Wildner 	wq->ring = oce_create_ring_buffer(sc, q_len, NIC_WQE_SIZE);
254229aec1cSSascha Wildner 	if (!wq->ring)
255229aec1cSSascha Wildner 		goto free_wq;
256229aec1cSSascha Wildner 
257229aec1cSSascha Wildner 
258229aec1cSSascha Wildner 	LOCK_CREATE(&wq->tx_lock, "TX_lock");
259229aec1cSSascha Wildner 
260229aec1cSSascha Wildner #if 0 /* XXX swildner: MULTIQUEUE */
261229aec1cSSascha Wildner 	/* Allocate buf ring for multiqueue*/
262229aec1cSSascha Wildner 	wq->br = buf_ring_alloc(4096, M_DEVBUF,
263229aec1cSSascha Wildner 			M_WAITOK, &wq->tx_lock.mutex);
264229aec1cSSascha Wildner 	if (!wq->br)
265229aec1cSSascha Wildner 		goto free_wq;
266229aec1cSSascha Wildner #endif
267229aec1cSSascha Wildner 	return wq;
268229aec1cSSascha Wildner 
269229aec1cSSascha Wildner 
270229aec1cSSascha Wildner free_wq:
271229aec1cSSascha Wildner 	device_printf(sc->dev, "Create WQ failed\n");
272229aec1cSSascha Wildner 	oce_wq_free(wq);
273229aec1cSSascha Wildner 	return NULL;
274229aec1cSSascha Wildner }
275229aec1cSSascha Wildner 
276229aec1cSSascha Wildner 
277229aec1cSSascha Wildner 
278229aec1cSSascha Wildner /**
279229aec1cSSascha Wildner  * @brief 		Frees the work queue
280229aec1cSSascha Wildner  * @param wq		pointer to work queue to free
281229aec1cSSascha Wildner  */
282229aec1cSSascha Wildner static void
oce_wq_free(struct oce_wq * wq)283229aec1cSSascha Wildner oce_wq_free(struct oce_wq *wq)
284229aec1cSSascha Wildner {
285229aec1cSSascha Wildner 	POCE_SOFTC sc = (POCE_SOFTC) wq->parent;
286229aec1cSSascha Wildner 	int i;
287229aec1cSSascha Wildner 
288229aec1cSSascha Wildner 	taskqueue_drain(taskqueue_swi, &wq->txtask);
289229aec1cSSascha Wildner 
290229aec1cSSascha Wildner 	if (wq->ring != NULL) {
291229aec1cSSascha Wildner 		oce_destroy_ring_buffer(sc, wq->ring);
292229aec1cSSascha Wildner 		wq->ring = NULL;
293229aec1cSSascha Wildner 	}
294229aec1cSSascha Wildner 
295229aec1cSSascha Wildner 	for (i = 0; i < OCE_WQ_PACKET_ARRAY_SIZE; i++) {
296229aec1cSSascha Wildner 		if (wq->pckts[i].map != NULL) {
297229aec1cSSascha Wildner 			bus_dmamap_unload(wq->tag, wq->pckts[i].map);
298229aec1cSSascha Wildner 			bus_dmamap_destroy(wq->tag, wq->pckts[i].map);
299229aec1cSSascha Wildner 			wq->pckts[i].map = NULL;
300229aec1cSSascha Wildner 		}
301229aec1cSSascha Wildner 	}
302229aec1cSSascha Wildner 
303229aec1cSSascha Wildner 	if (wq->tag != NULL)
304229aec1cSSascha Wildner 		bus_dma_tag_destroy(wq->tag);
305229aec1cSSascha Wildner #if 0 /* XXX swildner: MULTIQUEUE */
306229aec1cSSascha Wildner 	if (wq->br != NULL)
307229aec1cSSascha Wildner 		buf_ring_free(wq->br, M_DEVBUF);
308229aec1cSSascha Wildner #endif
309229aec1cSSascha Wildner 
310229aec1cSSascha Wildner 	LOCK_DESTROY(&wq->tx_lock);
311229aec1cSSascha Wildner 	kfree(wq, M_DEVBUF);
312229aec1cSSascha Wildner }
313229aec1cSSascha Wildner 
314229aec1cSSascha Wildner 
315229aec1cSSascha Wildner 
316229aec1cSSascha Wildner /**
317229aec1cSSascha Wildner  * @brief 		Create a work queue
318229aec1cSSascha Wildner  * @param wq		pointer to work queue
319229aec1cSSascha Wildner  * @param eq		pointer to associated event queue
320229aec1cSSascha Wildner  */
321229aec1cSSascha Wildner static int
oce_wq_create(struct oce_wq * wq,struct oce_eq * eq)322229aec1cSSascha Wildner oce_wq_create(struct oce_wq *wq, struct oce_eq *eq)
323229aec1cSSascha Wildner {
324229aec1cSSascha Wildner 	POCE_SOFTC sc = wq->parent;
325229aec1cSSascha Wildner 	struct oce_cq *cq;
326229aec1cSSascha Wildner 	int rc = 0;
327229aec1cSSascha Wildner 
328229aec1cSSascha Wildner 	/* create the CQ */
329229aec1cSSascha Wildner 	cq = oce_cq_create(sc,
330229aec1cSSascha Wildner 			   eq,
331229aec1cSSascha Wildner 			   CQ_LEN_1024,
332229aec1cSSascha Wildner 			   sizeof(struct oce_nic_tx_cqe), 0, 1, 0, 3);
333229aec1cSSascha Wildner 	if (!cq)
334229aec1cSSascha Wildner 		return ENXIO;
335229aec1cSSascha Wildner 
336229aec1cSSascha Wildner 
337229aec1cSSascha Wildner 	wq->cq = cq;
338229aec1cSSascha Wildner 
339229aec1cSSascha Wildner 	rc = oce_mbox_create_wq(wq);
340229aec1cSSascha Wildner 	if (rc)
341229aec1cSSascha Wildner 		goto error;
342229aec1cSSascha Wildner 
343229aec1cSSascha Wildner 	wq->qstate = QCREATED;
344229aec1cSSascha Wildner 	wq->wq_free = wq->cfg.q_len;
345229aec1cSSascha Wildner 	wq->ring->cidx = 0;
346229aec1cSSascha Wildner 	wq->ring->pidx = 0;
347229aec1cSSascha Wildner 
348229aec1cSSascha Wildner 	eq->cq[eq->cq_valid] = cq;
349229aec1cSSascha Wildner 	eq->cq_valid++;
350229aec1cSSascha Wildner 	cq->cb_arg = wq;
351229aec1cSSascha Wildner 	cq->cq_handler = oce_wq_handler;
352229aec1cSSascha Wildner 
353229aec1cSSascha Wildner 	return 0;
354229aec1cSSascha Wildner 
355229aec1cSSascha Wildner error:
356229aec1cSSascha Wildner 	device_printf(sc->dev, "WQ create failed\n");
357229aec1cSSascha Wildner 	oce_wq_del(wq);
358229aec1cSSascha Wildner 	return rc;
359229aec1cSSascha Wildner }
360229aec1cSSascha Wildner 
361229aec1cSSascha Wildner 
362229aec1cSSascha Wildner 
363229aec1cSSascha Wildner 
364229aec1cSSascha Wildner /**
365229aec1cSSascha Wildner  * @brief 		Delete a work queue
366229aec1cSSascha Wildner  * @param wq		pointer to work queue
367229aec1cSSascha Wildner  */
368229aec1cSSascha Wildner static void
oce_wq_del(struct oce_wq * wq)369229aec1cSSascha Wildner oce_wq_del(struct oce_wq *wq)
370229aec1cSSascha Wildner {
371229aec1cSSascha Wildner 	struct oce_mbx mbx;
372229aec1cSSascha Wildner 	struct mbx_delete_nic_wq *fwcmd;
373229aec1cSSascha Wildner 	POCE_SOFTC sc = (POCE_SOFTC) wq->parent;
374229aec1cSSascha Wildner 
375229aec1cSSascha Wildner 	if (wq->qstate == QCREATED) {
376229aec1cSSascha Wildner 		bzero(&mbx, sizeof(struct oce_mbx));
377229aec1cSSascha Wildner 		/* now fill the command */
378229aec1cSSascha Wildner 		fwcmd = (struct mbx_delete_nic_wq *)&mbx.payload;
379229aec1cSSascha Wildner 		fwcmd->params.req.wq_id = wq->wq_id;
380229aec1cSSascha Wildner 		(void)oce_destroy_q(sc, &mbx,
381229aec1cSSascha Wildner 				sizeof(struct mbx_delete_nic_wq), QTYPE_WQ);
382229aec1cSSascha Wildner 		wq->qstate = QDELETED;
383229aec1cSSascha Wildner 	}
384229aec1cSSascha Wildner 
385229aec1cSSascha Wildner 	if (wq->cq != NULL) {
386229aec1cSSascha Wildner 		oce_cq_del(sc, wq->cq);
387229aec1cSSascha Wildner 		wq->cq = NULL;
388229aec1cSSascha Wildner 	}
389229aec1cSSascha Wildner }
390229aec1cSSascha Wildner 
391229aec1cSSascha Wildner 
392229aec1cSSascha Wildner 
393229aec1cSSascha Wildner /**
394229aec1cSSascha Wildner  * @brief 		function to allocate receive queue resources
395229aec1cSSascha Wildner  * @param sc		software handle to the device
396229aec1cSSascha Wildner  * @param q_len		length of receive queue
397229aec1cSSascha Wildner  * @param frag_size	size of an receive queue fragment
398229aec1cSSascha Wildner  * @param mtu		maximum transmission unit
399229aec1cSSascha Wildner  * @param rss		is-rss-queue flag
400229aec1cSSascha Wildner  * @returns		the pointer to the RQ created or NULL on failure
401229aec1cSSascha Wildner  */
402229aec1cSSascha Wildner static struct
oce_rq_init(POCE_SOFTC sc,uint32_t q_len,uint32_t frag_size,uint32_t mtu,uint32_t rss)403229aec1cSSascha Wildner oce_rq *oce_rq_init(POCE_SOFTC sc,
404229aec1cSSascha Wildner 				  uint32_t q_len,
405229aec1cSSascha Wildner 				  uint32_t frag_size,
406229aec1cSSascha Wildner 				  uint32_t mtu, uint32_t rss)
407229aec1cSSascha Wildner {
408229aec1cSSascha Wildner 	struct oce_rq *rq;
409229aec1cSSascha Wildner 	int rc = 0, i;
410229aec1cSSascha Wildner 
411229aec1cSSascha Wildner 	if (OCE_LOG2(frag_size) <= 0)
412229aec1cSSascha Wildner 		return NULL;
413229aec1cSSascha Wildner 
414229aec1cSSascha Wildner 	if ((q_len == 0) || (q_len > 1024))
415229aec1cSSascha Wildner 		return NULL;
416229aec1cSSascha Wildner 
417229aec1cSSascha Wildner 	/* allocate the rq */
418229aec1cSSascha Wildner 	rq = kmalloc(sizeof(struct oce_rq), M_DEVBUF, M_NOWAIT | M_ZERO);
419229aec1cSSascha Wildner 	if (!rq)
420229aec1cSSascha Wildner 		return NULL;
421229aec1cSSascha Wildner 
422229aec1cSSascha Wildner 
423229aec1cSSascha Wildner 	rq->cfg.q_len = q_len;
424229aec1cSSascha Wildner 	rq->cfg.frag_size = frag_size;
425229aec1cSSascha Wildner 	rq->cfg.mtu = mtu;
426229aec1cSSascha Wildner 	rq->cfg.eqd = 0;
427229aec1cSSascha Wildner #if 0 /* XXX swildner: LRO */
428229aec1cSSascha Wildner 	rq->lro_pkts_queued = 0;
429229aec1cSSascha Wildner #endif
430229aec1cSSascha Wildner 	rq->cfg.is_rss_queue = rss;
431229aec1cSSascha Wildner 	rq->packets_in = 0;
432229aec1cSSascha Wildner         rq->packets_out = 0;
433229aec1cSSascha Wildner         rq->pending = 0;
434229aec1cSSascha Wildner 
435229aec1cSSascha Wildner 	rq->parent = (void *)sc;
436229aec1cSSascha Wildner 
437229aec1cSSascha Wildner 	rc = bus_dma_tag_create(NULL,
438229aec1cSSascha Wildner 				1, 0,
439229aec1cSSascha Wildner 				BUS_SPACE_MAXADDR,
440229aec1cSSascha Wildner 				BUS_SPACE_MAXADDR,
441229aec1cSSascha Wildner 				OCE_MAX_RX_SIZE,
442229aec1cSSascha Wildner 				1, PAGE_SIZE, 0, &rq->tag);
443229aec1cSSascha Wildner 
444229aec1cSSascha Wildner 	if (rc)
445229aec1cSSascha Wildner 		goto free_rq;
446229aec1cSSascha Wildner 
447229aec1cSSascha Wildner 	for (i = 0; i < OCE_RQ_PACKET_ARRAY_SIZE; i++) {
448229aec1cSSascha Wildner 		rc = bus_dmamap_create(rq->tag, 0, &rq->pckts[i].map);
449229aec1cSSascha Wildner 		if (rc)
450229aec1cSSascha Wildner 			goto free_rq;
451229aec1cSSascha Wildner 	}
452229aec1cSSascha Wildner 
453229aec1cSSascha Wildner 	/* create the ring buffer */
454229aec1cSSascha Wildner 	rq->ring = oce_create_ring_buffer(sc, q_len,
455229aec1cSSascha Wildner 				 sizeof(struct oce_nic_rqe));
456229aec1cSSascha Wildner 	if (!rq->ring)
457229aec1cSSascha Wildner 		goto free_rq;
458229aec1cSSascha Wildner 
459229aec1cSSascha Wildner 	LOCK_CREATE(&rq->rx_lock, "RX_lock");
460229aec1cSSascha Wildner 
461229aec1cSSascha Wildner 	return rq;
462229aec1cSSascha Wildner 
463229aec1cSSascha Wildner free_rq:
464229aec1cSSascha Wildner 	device_printf(sc->dev, "Create RQ failed\n");
465229aec1cSSascha Wildner 	oce_rq_free(rq);
466229aec1cSSascha Wildner 	return NULL;
467229aec1cSSascha Wildner }
468229aec1cSSascha Wildner 
469229aec1cSSascha Wildner 
470229aec1cSSascha Wildner 
471229aec1cSSascha Wildner 
472229aec1cSSascha Wildner /**
473229aec1cSSascha Wildner  * @brief 		Free a receive queue
474229aec1cSSascha Wildner  * @param rq		pointer to receive queue
475229aec1cSSascha Wildner  */
476229aec1cSSascha Wildner static void
oce_rq_free(struct oce_rq * rq)477229aec1cSSascha Wildner oce_rq_free(struct oce_rq *rq)
478229aec1cSSascha Wildner {
479229aec1cSSascha Wildner 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
480229aec1cSSascha Wildner 	int i = 0 ;
481229aec1cSSascha Wildner 
482229aec1cSSascha Wildner 	if (rq->ring != NULL) {
483229aec1cSSascha Wildner 		oce_destroy_ring_buffer(sc, rq->ring);
484229aec1cSSascha Wildner 		rq->ring = NULL;
485229aec1cSSascha Wildner 	}
486229aec1cSSascha Wildner 	for (i = 0; i < OCE_RQ_PACKET_ARRAY_SIZE; i++) {
487229aec1cSSascha Wildner 		if (rq->pckts[i].map != NULL) {
488229aec1cSSascha Wildner 			bus_dmamap_unload(rq->tag, rq->pckts[i].map);
489229aec1cSSascha Wildner 			bus_dmamap_destroy(rq->tag, rq->pckts[i].map);
490229aec1cSSascha Wildner 			rq->pckts[i].map = NULL;
491229aec1cSSascha Wildner 		}
492229aec1cSSascha Wildner 		if (rq->pckts[i].mbuf) {
493229aec1cSSascha Wildner 			m_free(rq->pckts[i].mbuf);
494229aec1cSSascha Wildner 			rq->pckts[i].mbuf = NULL;
495229aec1cSSascha Wildner 		}
496229aec1cSSascha Wildner 	}
497229aec1cSSascha Wildner 
498229aec1cSSascha Wildner 	if (rq->tag != NULL)
499229aec1cSSascha Wildner 		bus_dma_tag_destroy(rq->tag);
500229aec1cSSascha Wildner 
501229aec1cSSascha Wildner 	LOCK_DESTROY(&rq->rx_lock);
502229aec1cSSascha Wildner 	kfree(rq, M_DEVBUF);
503229aec1cSSascha Wildner }
504229aec1cSSascha Wildner 
505229aec1cSSascha Wildner 
506229aec1cSSascha Wildner 
507229aec1cSSascha Wildner 
508229aec1cSSascha Wildner /**
509229aec1cSSascha Wildner  * @brief 		Create a receive queue
510229aec1cSSascha Wildner  * @param rq 		receive queue
511229aec1cSSascha Wildner  * @param if_id		interface identifier index`
512229aec1cSSascha Wildner  * @param eq		pointer to event queue
513229aec1cSSascha Wildner  */
514229aec1cSSascha Wildner static int
oce_rq_create(struct oce_rq * rq,uint32_t if_id,struct oce_eq * eq)515229aec1cSSascha Wildner oce_rq_create(struct oce_rq *rq, uint32_t if_id, struct oce_eq *eq)
516229aec1cSSascha Wildner {
517229aec1cSSascha Wildner 	POCE_SOFTC sc = rq->parent;
518229aec1cSSascha Wildner 	struct oce_cq *cq;
519229aec1cSSascha Wildner 
520229aec1cSSascha Wildner 	cq = oce_cq_create(sc,
521229aec1cSSascha Wildner 			   eq,
522229aec1cSSascha Wildner 			   CQ_LEN_1024,
523229aec1cSSascha Wildner 			   sizeof(struct oce_nic_rx_cqe), 0, 1, 0, 3);
524229aec1cSSascha Wildner 	if (!cq)
525229aec1cSSascha Wildner 		return ENXIO;
526229aec1cSSascha Wildner 
527229aec1cSSascha Wildner 	rq->cq = cq;
528229aec1cSSascha Wildner 	rq->cfg.if_id = if_id;
529229aec1cSSascha Wildner 
530229aec1cSSascha Wildner 	/* Dont create RQ here. Create in if_activate */
531229aec1cSSascha Wildner 	rq->qstate     = 0;
532229aec1cSSascha Wildner 	rq->ring->cidx = 0;
533229aec1cSSascha Wildner 	rq->ring->pidx = 0;
534229aec1cSSascha Wildner 	eq->cq[eq->cq_valid] = cq;
535229aec1cSSascha Wildner 	eq->cq_valid++;
536229aec1cSSascha Wildner 	cq->cb_arg = rq;
537229aec1cSSascha Wildner 	cq->cq_handler = oce_rq_handler;
538229aec1cSSascha Wildner 
539229aec1cSSascha Wildner 	return 0;
540229aec1cSSascha Wildner 
541229aec1cSSascha Wildner }
542229aec1cSSascha Wildner 
543229aec1cSSascha Wildner 
544229aec1cSSascha Wildner 
545229aec1cSSascha Wildner 
546229aec1cSSascha Wildner /**
547229aec1cSSascha Wildner  * @brief 		Delete a receive queue
548229aec1cSSascha Wildner  * @param rq		receive queue
549229aec1cSSascha Wildner  */
550229aec1cSSascha Wildner static void
oce_rq_del(struct oce_rq * rq)551229aec1cSSascha Wildner oce_rq_del(struct oce_rq *rq)
552229aec1cSSascha Wildner {
553229aec1cSSascha Wildner 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
554229aec1cSSascha Wildner 	struct oce_mbx mbx;
555229aec1cSSascha Wildner 	struct mbx_delete_nic_rq *fwcmd;
556229aec1cSSascha Wildner 
557229aec1cSSascha Wildner 	if (rq->qstate == QCREATED) {
558229aec1cSSascha Wildner 		bzero(&mbx, sizeof(mbx));
559229aec1cSSascha Wildner 
560229aec1cSSascha Wildner 		fwcmd = (struct mbx_delete_nic_rq *)&mbx.payload;
561229aec1cSSascha Wildner 		fwcmd->params.req.rq_id = rq->rq_id;
562229aec1cSSascha Wildner 		(void)oce_destroy_q(sc, &mbx,
563229aec1cSSascha Wildner 				sizeof(struct mbx_delete_nic_rq), QTYPE_RQ);
564229aec1cSSascha Wildner 		rq->qstate = QDELETED;
565229aec1cSSascha Wildner 	}
566229aec1cSSascha Wildner 
567229aec1cSSascha Wildner 	if (rq->cq != NULL) {
568229aec1cSSascha Wildner 		oce_cq_del(sc, rq->cq);
569229aec1cSSascha Wildner 		rq->cq = NULL;
570229aec1cSSascha Wildner 	}
571229aec1cSSascha Wildner }
572229aec1cSSascha Wildner 
573229aec1cSSascha Wildner 
574229aec1cSSascha Wildner 
575229aec1cSSascha Wildner /**
576229aec1cSSascha Wildner  * @brief		function to create an event queue
577229aec1cSSascha Wildner  * @param sc		software handle to the device
578229aec1cSSascha Wildner  * @param q_len		length of event queue
579229aec1cSSascha Wildner  * @param item_size	size of an event queue item
580229aec1cSSascha Wildner  * @param eq_delay	event queue delay
581229aec1cSSascha Wildner  * @retval eq      	success, pointer to event queue
582229aec1cSSascha Wildner  * @retval NULL		failure
583229aec1cSSascha Wildner  */
584229aec1cSSascha Wildner static struct
oce_eq_create(POCE_SOFTC sc,uint32_t q_len,uint32_t item_size,uint32_t eq_delay,uint32_t vector)585229aec1cSSascha Wildner oce_eq *oce_eq_create(POCE_SOFTC sc, uint32_t q_len,
586229aec1cSSascha Wildner 				    uint32_t item_size,
587229aec1cSSascha Wildner 				    uint32_t eq_delay,
588229aec1cSSascha Wildner 				    uint32_t vector)
589229aec1cSSascha Wildner {
590229aec1cSSascha Wildner 	struct oce_eq *eq;
591229aec1cSSascha Wildner 	int rc = 0;
592229aec1cSSascha Wildner 
593229aec1cSSascha Wildner 	/* allocate an eq */
594229aec1cSSascha Wildner 	eq = kmalloc(sizeof(struct oce_eq), M_DEVBUF, M_NOWAIT | M_ZERO);
595229aec1cSSascha Wildner 	if (eq == NULL)
596229aec1cSSascha Wildner 		return NULL;
597229aec1cSSascha Wildner 
598229aec1cSSascha Wildner 	eq->parent = (void *)sc;
599229aec1cSSascha Wildner 	eq->eq_id = 0xffff;
600229aec1cSSascha Wildner 	eq->ring = oce_create_ring_buffer(sc, q_len, item_size);
601229aec1cSSascha Wildner 	if (!eq->ring)
602229aec1cSSascha Wildner 		goto free_eq;
603229aec1cSSascha Wildner 
604229aec1cSSascha Wildner 	eq->eq_cfg.q_len = q_len;
605229aec1cSSascha Wildner 	eq->eq_cfg.item_size = item_size;
606229aec1cSSascha Wildner 	eq->eq_cfg.cur_eqd = (uint8_t) eq_delay;
607229aec1cSSascha Wildner 
608229aec1cSSascha Wildner 	rc = oce_mbox_create_eq(eq);
609229aec1cSSascha Wildner 	if (rc)
610229aec1cSSascha Wildner 		goto free_eq;
611229aec1cSSascha Wildner 
612229aec1cSSascha Wildner 	sc->intrs[sc->neqs++].eq = eq;
613229aec1cSSascha Wildner 
614229aec1cSSascha Wildner 	return eq;
615229aec1cSSascha Wildner 
616229aec1cSSascha Wildner free_eq:
617229aec1cSSascha Wildner 	oce_eq_del(eq);
618229aec1cSSascha Wildner 	return NULL;
619229aec1cSSascha Wildner }
620229aec1cSSascha Wildner 
621229aec1cSSascha Wildner 
622229aec1cSSascha Wildner 
623229aec1cSSascha Wildner 
624229aec1cSSascha Wildner /**
625229aec1cSSascha Wildner  * @brief 		Function to delete an event queue
626229aec1cSSascha Wildner  * @param eq		pointer to an event queue
627229aec1cSSascha Wildner  */
628229aec1cSSascha Wildner static void
oce_eq_del(struct oce_eq * eq)629229aec1cSSascha Wildner oce_eq_del(struct oce_eq *eq)
630229aec1cSSascha Wildner {
631229aec1cSSascha Wildner 	struct oce_mbx mbx;
632229aec1cSSascha Wildner 	struct mbx_destroy_common_eq *fwcmd;
633229aec1cSSascha Wildner 	POCE_SOFTC sc = (POCE_SOFTC) eq->parent;
634229aec1cSSascha Wildner 
635229aec1cSSascha Wildner 	if (eq->eq_id != 0xffff) {
636229aec1cSSascha Wildner 		bzero(&mbx, sizeof(mbx));
637229aec1cSSascha Wildner 		fwcmd = (struct mbx_destroy_common_eq *)&mbx.payload;
638229aec1cSSascha Wildner 		fwcmd->params.req.id = eq->eq_id;
639229aec1cSSascha Wildner 		(void)oce_destroy_q(sc, &mbx,
640229aec1cSSascha Wildner 			sizeof(struct mbx_destroy_common_eq), QTYPE_EQ);
641229aec1cSSascha Wildner 	}
642229aec1cSSascha Wildner 
643229aec1cSSascha Wildner 	if (eq->ring != NULL) {
644229aec1cSSascha Wildner 		oce_destroy_ring_buffer(sc, eq->ring);
645229aec1cSSascha Wildner 		eq->ring = NULL;
646229aec1cSSascha Wildner 	}
647229aec1cSSascha Wildner 
648229aec1cSSascha Wildner 	kfree(eq, M_DEVBUF);
649229aec1cSSascha Wildner 
650229aec1cSSascha Wildner }
651229aec1cSSascha Wildner 
652229aec1cSSascha Wildner 
653229aec1cSSascha Wildner 
654229aec1cSSascha Wildner 
655229aec1cSSascha Wildner /**
656229aec1cSSascha Wildner  * @brief		Function to create an MQ
657229aec1cSSascha Wildner  * @param sc		software handle to the device
658229aec1cSSascha Wildner  * @param eq		the EQ to associate with the MQ for event notification
659229aec1cSSascha Wildner  * @param q_len		the number of entries to create in the MQ
660229aec1cSSascha Wildner  * @returns		pointer to the created MQ, failure otherwise
661229aec1cSSascha Wildner  */
662229aec1cSSascha Wildner static struct oce_mq *
oce_mq_create(POCE_SOFTC sc,struct oce_eq * eq,uint32_t q_len)663229aec1cSSascha Wildner oce_mq_create(POCE_SOFTC sc, struct oce_eq *eq, uint32_t q_len)
664229aec1cSSascha Wildner {
665229aec1cSSascha Wildner 	struct oce_mbx mbx;
666229aec1cSSascha Wildner 	struct mbx_create_common_mq_ex *fwcmd = NULL;
667229aec1cSSascha Wildner 	struct oce_mq *mq = NULL;
668229aec1cSSascha Wildner 	int rc = 0;
669229aec1cSSascha Wildner 	struct oce_cq *cq;
670229aec1cSSascha Wildner 	oce_mq_ext_ctx_t *ctx;
671229aec1cSSascha Wildner 	uint32_t num_pages;
672229aec1cSSascha Wildner 	uint32_t page_size;
673229aec1cSSascha Wildner 	int version;
674229aec1cSSascha Wildner 
675229aec1cSSascha Wildner 	cq = oce_cq_create(sc, eq, CQ_LEN_256,
676229aec1cSSascha Wildner 			sizeof(struct oce_mq_cqe), 1, 1, 0, 0);
677229aec1cSSascha Wildner 	if (!cq)
678229aec1cSSascha Wildner 		return NULL;
679229aec1cSSascha Wildner 
680229aec1cSSascha Wildner 	/* allocate the mq */
681229aec1cSSascha Wildner 	mq = kmalloc(sizeof(struct oce_mq), M_DEVBUF, M_NOWAIT | M_ZERO);
682229aec1cSSascha Wildner 	if (!mq) {
683229aec1cSSascha Wildner 		oce_cq_del(sc, cq);
684229aec1cSSascha Wildner 		goto error;
685229aec1cSSascha Wildner 	}
686229aec1cSSascha Wildner 
687229aec1cSSascha Wildner 	mq->parent = sc;
688229aec1cSSascha Wildner 
689229aec1cSSascha Wildner 	mq->ring = oce_create_ring_buffer(sc, q_len, sizeof(struct oce_mbx));
690229aec1cSSascha Wildner 	if (!mq->ring)
691229aec1cSSascha Wildner 		goto error;
692229aec1cSSascha Wildner 
693229aec1cSSascha Wildner 	bzero(&mbx, sizeof(struct oce_mbx));
694229aec1cSSascha Wildner 
695229aec1cSSascha Wildner 	IS_XE201(sc) ? (version = OCE_MBX_VER_V1) : (version = OCE_MBX_VER_V0);
696229aec1cSSascha Wildner 	fwcmd = (struct mbx_create_common_mq_ex *)&mbx.payload;
697229aec1cSSascha Wildner 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
698229aec1cSSascha Wildner 				MBX_SUBSYSTEM_COMMON,
699229aec1cSSascha Wildner 				OPCODE_COMMON_CREATE_MQ_EXT,
700229aec1cSSascha Wildner 				MBX_TIMEOUT_SEC,
701229aec1cSSascha Wildner 				sizeof(struct mbx_create_common_mq_ex),
702229aec1cSSascha Wildner 				version);
703229aec1cSSascha Wildner 
704229aec1cSSascha Wildner 	num_pages = oce_page_list(mq->ring, &fwcmd->params.req.pages[0]);
705229aec1cSSascha Wildner 	page_size = mq->ring->num_items * mq->ring->item_size;
706229aec1cSSascha Wildner 
707229aec1cSSascha Wildner 	ctx = &fwcmd->params.req.context;
708229aec1cSSascha Wildner 
709229aec1cSSascha Wildner 	if (IS_XE201(sc)) {
710229aec1cSSascha Wildner 		ctx->v1.num_pages = num_pages;
711229aec1cSSascha Wildner 		ctx->v1.ring_size = OCE_LOG2(q_len) + 1;
712229aec1cSSascha Wildner 		ctx->v1.cq_id = cq->cq_id;
713229aec1cSSascha Wildner 		ctx->v1.valid = 1;
714229aec1cSSascha Wildner 		ctx->v1.async_cq_id = cq->cq_id;
715229aec1cSSascha Wildner 		ctx->v1.async_cq_valid = 1;
716229aec1cSSascha Wildner 		/* Subscribe to Link State and Group 5 Events(bits 1 & 5 set) */
717229aec1cSSascha Wildner 		ctx->v1.async_evt_bitmap |= LE_32(0x00000022);
718229aec1cSSascha Wildner 		ctx->v1.async_evt_bitmap |= LE_32(1 << ASYNC_EVENT_CODE_DEBUG);
719229aec1cSSascha Wildner 		ctx->v1.async_evt_bitmap |=
720229aec1cSSascha Wildner 					LE_32(1 << ASYNC_EVENT_CODE_SLIPORT);
721229aec1cSSascha Wildner 	}
722229aec1cSSascha Wildner 	else {
723229aec1cSSascha Wildner 		ctx->v0.num_pages = num_pages;
724229aec1cSSascha Wildner 		ctx->v0.cq_id = cq->cq_id;
725229aec1cSSascha Wildner 		ctx->v0.ring_size = OCE_LOG2(q_len) + 1;
726229aec1cSSascha Wildner 		ctx->v0.valid = 1;
727229aec1cSSascha Wildner 		/* Subscribe to Link State and Group5 Events(bits 1 & 5 set) */
728229aec1cSSascha Wildner 		ctx->v0.async_evt_bitmap = 0xffffffff;
729229aec1cSSascha Wildner 	}
730229aec1cSSascha Wildner 
731229aec1cSSascha Wildner 	mbx.u0.s.embedded = 1;
732229aec1cSSascha Wildner 	mbx.payload_length = sizeof(struct mbx_create_common_mq_ex);
733229aec1cSSascha Wildner 	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
734229aec1cSSascha Wildner 
735229aec1cSSascha Wildner 	rc = oce_mbox_post(sc, &mbx, NULL);
736229aec1cSSascha Wildner 	if (!rc)
737229aec1cSSascha Wildner                 rc = fwcmd->hdr.u0.rsp.status;
738229aec1cSSascha Wildner 	if (rc) {
739229aec1cSSascha Wildner 		device_printf(sc->dev,"%s failed - cmd status: %d\n",
740229aec1cSSascha Wildner 			      __FUNCTION__, rc);
741229aec1cSSascha Wildner 		goto error;
742229aec1cSSascha Wildner 	}
743229aec1cSSascha Wildner 	mq->mq_id = LE_16(fwcmd->params.rsp.mq_id);
744229aec1cSSascha Wildner 	mq->cq = cq;
745229aec1cSSascha Wildner 	eq->cq[eq->cq_valid] = cq;
746229aec1cSSascha Wildner 	eq->cq_valid++;
747229aec1cSSascha Wildner 	mq->cq->eq = eq;
748229aec1cSSascha Wildner 	mq->cfg.q_len = (uint8_t) q_len;
749229aec1cSSascha Wildner 	mq->cfg.eqd = 0;
750229aec1cSSascha Wildner 	mq->qstate = QCREATED;
751229aec1cSSascha Wildner 
752229aec1cSSascha Wildner 	mq->cq->cb_arg = mq;
753229aec1cSSascha Wildner 	mq->cq->cq_handler = oce_mq_handler;
754229aec1cSSascha Wildner 
755229aec1cSSascha Wildner 	return mq;
756229aec1cSSascha Wildner 
757229aec1cSSascha Wildner error:
758229aec1cSSascha Wildner 	device_printf(sc->dev, "MQ create failed\n");
759229aec1cSSascha Wildner 	oce_mq_free(mq);
760229aec1cSSascha Wildner 	mq = NULL;
761229aec1cSSascha Wildner 	return mq;
762229aec1cSSascha Wildner }
763229aec1cSSascha Wildner 
764229aec1cSSascha Wildner 
765229aec1cSSascha Wildner 
766229aec1cSSascha Wildner 
767229aec1cSSascha Wildner 
768229aec1cSSascha Wildner /**
769229aec1cSSascha Wildner  * @brief		Function to free a mailbox queue
770229aec1cSSascha Wildner  * @param mq		pointer to a mailbox queue
771229aec1cSSascha Wildner  */
772229aec1cSSascha Wildner static void
oce_mq_free(struct oce_mq * mq)773229aec1cSSascha Wildner oce_mq_free(struct oce_mq *mq)
774229aec1cSSascha Wildner {
775229aec1cSSascha Wildner 	POCE_SOFTC sc = (POCE_SOFTC) mq->parent;
776229aec1cSSascha Wildner 	struct oce_mbx mbx;
777229aec1cSSascha Wildner 	struct mbx_destroy_common_mq *fwcmd;
778229aec1cSSascha Wildner 
779229aec1cSSascha Wildner 	if (!mq)
780229aec1cSSascha Wildner 		return;
781229aec1cSSascha Wildner 
782229aec1cSSascha Wildner 	if (mq->ring != NULL) {
783229aec1cSSascha Wildner 		oce_destroy_ring_buffer(sc, mq->ring);
784229aec1cSSascha Wildner 		mq->ring = NULL;
785229aec1cSSascha Wildner 		if (mq->qstate == QCREATED) {
786229aec1cSSascha Wildner 			bzero(&mbx, sizeof (struct oce_mbx));
787229aec1cSSascha Wildner 			fwcmd = (struct mbx_destroy_common_mq *)&mbx.payload;
788229aec1cSSascha Wildner 			fwcmd->params.req.id = mq->mq_id;
789229aec1cSSascha Wildner 			(void) oce_destroy_q(sc, &mbx,
790229aec1cSSascha Wildner 				sizeof (struct mbx_destroy_common_mq),
791229aec1cSSascha Wildner 				QTYPE_MQ);
792229aec1cSSascha Wildner 		}
793229aec1cSSascha Wildner 		mq->qstate = QDELETED;
794229aec1cSSascha Wildner 	}
795229aec1cSSascha Wildner 
796229aec1cSSascha Wildner 	if (mq->cq != NULL) {
797229aec1cSSascha Wildner 		oce_cq_del(sc, mq->cq);
798229aec1cSSascha Wildner 		mq->cq = NULL;
799229aec1cSSascha Wildner 	}
800229aec1cSSascha Wildner 
801229aec1cSSascha Wildner 	kfree(mq, M_DEVBUF);
802229aec1cSSascha Wildner 	mq = NULL;
803229aec1cSSascha Wildner }
804229aec1cSSascha Wildner 
805229aec1cSSascha Wildner 
806229aec1cSSascha Wildner 
807229aec1cSSascha Wildner /**
808229aec1cSSascha Wildner  * @brief		Function to delete a EQ, CQ, MQ, WQ or RQ
809229aec1cSSascha Wildner  * @param sc		sofware handle to the device
810229aec1cSSascha Wildner  * @param mbx		mailbox command to send to the fw to delete the queue
811229aec1cSSascha Wildner  *			(mbx contains the queue information to delete)
812229aec1cSSascha Wildner  * @param req_size	the size of the mbx payload dependent on the qtype
813229aec1cSSascha Wildner  * @param qtype		the type of queue i.e. EQ, CQ, MQ, WQ or RQ
814229aec1cSSascha Wildner  * @returns 		0 on success, failure otherwise
815229aec1cSSascha Wildner  */
816229aec1cSSascha Wildner static int
oce_destroy_q(POCE_SOFTC sc,struct oce_mbx * mbx,size_t req_size,enum qtype qtype)817229aec1cSSascha Wildner oce_destroy_q(POCE_SOFTC sc, struct oce_mbx *mbx, size_t req_size,
818229aec1cSSascha Wildner 		enum qtype qtype)
819229aec1cSSascha Wildner {
820229aec1cSSascha Wildner 	struct mbx_hdr *hdr = (struct mbx_hdr *)&mbx->payload;
821229aec1cSSascha Wildner 	int opcode;
822229aec1cSSascha Wildner 	int subsys;
823229aec1cSSascha Wildner 	int rc = 0;
824229aec1cSSascha Wildner 
825229aec1cSSascha Wildner 	switch (qtype) {
826229aec1cSSascha Wildner 	case QTYPE_EQ:
827229aec1cSSascha Wildner 		opcode = OPCODE_COMMON_DESTROY_EQ;
828229aec1cSSascha Wildner 		subsys = MBX_SUBSYSTEM_COMMON;
829229aec1cSSascha Wildner 		break;
830229aec1cSSascha Wildner 	case QTYPE_CQ:
831229aec1cSSascha Wildner 		opcode = OPCODE_COMMON_DESTROY_CQ;
832229aec1cSSascha Wildner 		subsys = MBX_SUBSYSTEM_COMMON;
833229aec1cSSascha Wildner 		break;
834229aec1cSSascha Wildner 	case QTYPE_MQ:
835229aec1cSSascha Wildner 		opcode = OPCODE_COMMON_DESTROY_MQ;
836229aec1cSSascha Wildner 		subsys = MBX_SUBSYSTEM_COMMON;
837229aec1cSSascha Wildner 		break;
838229aec1cSSascha Wildner 	case QTYPE_WQ:
839229aec1cSSascha Wildner 		opcode = NIC_DELETE_WQ;
840229aec1cSSascha Wildner 		subsys = MBX_SUBSYSTEM_NIC;
841229aec1cSSascha Wildner 		break;
842229aec1cSSascha Wildner 	case QTYPE_RQ:
843229aec1cSSascha Wildner 		opcode = NIC_DELETE_RQ;
844229aec1cSSascha Wildner 		subsys = MBX_SUBSYSTEM_NIC;
845229aec1cSSascha Wildner 		break;
846229aec1cSSascha Wildner 	default:
847229aec1cSSascha Wildner 		return EINVAL;
848229aec1cSSascha Wildner 	}
849229aec1cSSascha Wildner 
850229aec1cSSascha Wildner 	mbx_common_req_hdr_init(hdr, 0, 0, subsys,
851229aec1cSSascha Wildner 				opcode, MBX_TIMEOUT_SEC, req_size,
852229aec1cSSascha Wildner 				OCE_MBX_VER_V0);
853229aec1cSSascha Wildner 
854229aec1cSSascha Wildner 	mbx->u0.s.embedded = 1;
855229aec1cSSascha Wildner 	mbx->payload_length = (uint32_t) req_size;
856229aec1cSSascha Wildner 	DW_SWAP(u32ptr(mbx), mbx->payload_length + OCE_BMBX_RHDR_SZ);
857229aec1cSSascha Wildner 
858229aec1cSSascha Wildner 	rc = oce_mbox_post(sc, mbx, NULL);
859229aec1cSSascha Wildner 	if (!rc)
860229aec1cSSascha Wildner                 rc = hdr->u0.rsp.status;
861229aec1cSSascha Wildner 	if (rc)
862229aec1cSSascha Wildner 		device_printf(sc->dev,"%s failed - cmd status: %d\n",
863229aec1cSSascha Wildner 			      __FUNCTION__, rc);
864229aec1cSSascha Wildner 	return rc;
865229aec1cSSascha Wildner }
866229aec1cSSascha Wildner 
867229aec1cSSascha Wildner 
868229aec1cSSascha Wildner 
869229aec1cSSascha Wildner /**
870229aec1cSSascha Wildner  * @brief		Function to create a completion queue
871229aec1cSSascha Wildner  * @param sc		software handle to the device
872229aec1cSSascha Wildner  * @param eq		optional eq to be associated with to the cq
873229aec1cSSascha Wildner  * @param q_len		length of completion queue
874229aec1cSSascha Wildner  * @param item_size	size of completion queue items
875229aec1cSSascha Wildner  * @param sol_event	command context event
876229aec1cSSascha Wildner  * @param is_eventable	event table
877229aec1cSSascha Wildner  * @param nodelay	no delay flag
878229aec1cSSascha Wildner  * @param ncoalesce	no coalescence flag
879229aec1cSSascha Wildner  * @returns 		pointer to the cq created, NULL on failure
880229aec1cSSascha Wildner  */
881229aec1cSSascha Wildner struct oce_cq *
oce_cq_create(POCE_SOFTC sc,struct oce_eq * eq,uint32_t q_len,uint32_t item_size,uint32_t sol_event,uint32_t is_eventable,uint32_t nodelay,uint32_t ncoalesce)882229aec1cSSascha Wildner oce_cq_create(POCE_SOFTC sc, struct oce_eq *eq,
883229aec1cSSascha Wildner 			     uint32_t q_len,
884229aec1cSSascha Wildner 			     uint32_t item_size,
885229aec1cSSascha Wildner 			     uint32_t sol_event,
886229aec1cSSascha Wildner 			     uint32_t is_eventable,
887229aec1cSSascha Wildner 			     uint32_t nodelay, uint32_t ncoalesce)
888229aec1cSSascha Wildner {
889229aec1cSSascha Wildner 	struct oce_cq *cq = NULL;
890229aec1cSSascha Wildner 	int rc = 0;
891229aec1cSSascha Wildner 
892229aec1cSSascha Wildner 	cq = kmalloc(sizeof(struct oce_cq), M_DEVBUF, M_NOWAIT | M_ZERO);
893229aec1cSSascha Wildner 	if (!cq)
894229aec1cSSascha Wildner 		return NULL;
895229aec1cSSascha Wildner 
896229aec1cSSascha Wildner 	cq->ring = oce_create_ring_buffer(sc, q_len, item_size);
897229aec1cSSascha Wildner 	if (!cq->ring)
898229aec1cSSascha Wildner 		goto error;
899229aec1cSSascha Wildner 
900229aec1cSSascha Wildner 	cq->parent = sc;
901229aec1cSSascha Wildner 	cq->eq = eq;
902229aec1cSSascha Wildner 	cq->cq_cfg.q_len = q_len;
903229aec1cSSascha Wildner 	cq->cq_cfg.item_size = item_size;
904229aec1cSSascha Wildner 	cq->cq_cfg.nodelay = (uint8_t) nodelay;
905229aec1cSSascha Wildner 
906229aec1cSSascha Wildner 	rc = oce_mbox_cq_create(cq, ncoalesce, is_eventable);
907229aec1cSSascha Wildner 	if (rc)
908229aec1cSSascha Wildner 		goto error;
909229aec1cSSascha Wildner 
910229aec1cSSascha Wildner 	sc->cq[sc->ncqs++] = cq;
911229aec1cSSascha Wildner 
912229aec1cSSascha Wildner 	return cq;
913229aec1cSSascha Wildner 
914229aec1cSSascha Wildner error:
915229aec1cSSascha Wildner 	device_printf(sc->dev, "CQ create failed\n");
916229aec1cSSascha Wildner 	oce_cq_del(sc, cq);
917229aec1cSSascha Wildner 	return NULL;
918229aec1cSSascha Wildner }
919229aec1cSSascha Wildner 
920229aec1cSSascha Wildner 
921229aec1cSSascha Wildner 
922229aec1cSSascha Wildner /**
923229aec1cSSascha Wildner  * @brief		Deletes the completion queue
924229aec1cSSascha Wildner  * @param sc		software handle to the device
925229aec1cSSascha Wildner  * @param cq		pointer to a completion queue
926229aec1cSSascha Wildner  */
927229aec1cSSascha Wildner static void
oce_cq_del(POCE_SOFTC sc,struct oce_cq * cq)928229aec1cSSascha Wildner oce_cq_del(POCE_SOFTC sc, struct oce_cq *cq)
929229aec1cSSascha Wildner {
930229aec1cSSascha Wildner 	struct oce_mbx mbx;
931229aec1cSSascha Wildner 	struct mbx_destroy_common_cq *fwcmd;
932229aec1cSSascha Wildner 
933229aec1cSSascha Wildner 	if (cq->ring != NULL) {
934229aec1cSSascha Wildner 
935229aec1cSSascha Wildner 		bzero(&mbx, sizeof(struct oce_mbx));
936229aec1cSSascha Wildner 		/* now fill the command */
937229aec1cSSascha Wildner 		fwcmd = (struct mbx_destroy_common_cq *)&mbx.payload;
938229aec1cSSascha Wildner 		fwcmd->params.req.id = cq->cq_id;
939229aec1cSSascha Wildner 		(void)oce_destroy_q(sc, &mbx,
940229aec1cSSascha Wildner 			sizeof(struct mbx_destroy_common_cq), QTYPE_CQ);
941229aec1cSSascha Wildner 		/*NOW destroy the ring */
942229aec1cSSascha Wildner 		oce_destroy_ring_buffer(sc, cq->ring);
943229aec1cSSascha Wildner 		cq->ring = NULL;
944229aec1cSSascha Wildner 	}
945229aec1cSSascha Wildner 
946229aec1cSSascha Wildner 	kfree(cq, M_DEVBUF);
947229aec1cSSascha Wildner 	cq = NULL;
948229aec1cSSascha Wildner }
949229aec1cSSascha Wildner 
950229aec1cSSascha Wildner 
951229aec1cSSascha Wildner 
952229aec1cSSascha Wildner /**
953229aec1cSSascha Wildner  * @brief		Start a receive queue
954229aec1cSSascha Wildner  * @param rq		pointer to a receive queue
955229aec1cSSascha Wildner  */
956229aec1cSSascha Wildner int
oce_start_rq(struct oce_rq * rq)957229aec1cSSascha Wildner oce_start_rq(struct oce_rq *rq)
958229aec1cSSascha Wildner {
959229aec1cSSascha Wildner 	int rc;
960229aec1cSSascha Wildner 
961229aec1cSSascha Wildner 	rc = oce_alloc_rx_bufs(rq, rq->cfg.q_len);
962229aec1cSSascha Wildner 
963229aec1cSSascha Wildner 	if (rc == 0)
964229aec1cSSascha Wildner 		oce_arm_cq(rq->parent, rq->cq->cq_id, 0, TRUE);
965229aec1cSSascha Wildner 	return rc;
966229aec1cSSascha Wildner }
967229aec1cSSascha Wildner 
968229aec1cSSascha Wildner 
969229aec1cSSascha Wildner 
970229aec1cSSascha Wildner /**
971229aec1cSSascha Wildner  * @brief		Start a work queue
972229aec1cSSascha Wildner  * @param wq		pointer to a work queue
973229aec1cSSascha Wildner  */
974229aec1cSSascha Wildner int
oce_start_wq(struct oce_wq * wq)975229aec1cSSascha Wildner oce_start_wq(struct oce_wq *wq)
976229aec1cSSascha Wildner {
977229aec1cSSascha Wildner 	oce_arm_cq(wq->parent, wq->cq->cq_id, 0, TRUE);
978229aec1cSSascha Wildner 	return 0;
979229aec1cSSascha Wildner }
980229aec1cSSascha Wildner 
981229aec1cSSascha Wildner 
982229aec1cSSascha Wildner 
983229aec1cSSascha Wildner /**
984229aec1cSSascha Wildner  * @brief		Start a mailbox queue
985229aec1cSSascha Wildner  * @param mq		pointer to a mailbox queue
986229aec1cSSascha Wildner  */
987229aec1cSSascha Wildner int
oce_start_mq(struct oce_mq * mq)988229aec1cSSascha Wildner oce_start_mq(struct oce_mq *mq)
989229aec1cSSascha Wildner {
990229aec1cSSascha Wildner 	oce_arm_cq(mq->parent, mq->cq->cq_id, 0, TRUE);
991229aec1cSSascha Wildner 	return 0;
992229aec1cSSascha Wildner }
993229aec1cSSascha Wildner 
994229aec1cSSascha Wildner 
995229aec1cSSascha Wildner 
996229aec1cSSascha Wildner /**
997229aec1cSSascha Wildner  * @brief		Function to arm an EQ so that it can generate events
998229aec1cSSascha Wildner  * @param sc		software handle to the device
999229aec1cSSascha Wildner  * @param qid		id of the EQ returned by the fw at the time of creation
1000229aec1cSSascha Wildner  * @param npopped	number of EQEs to arm
1001229aec1cSSascha Wildner  * @param rearm		rearm bit enable/disable
1002229aec1cSSascha Wildner  * @param clearint	bit to clear the interrupt condition because of which
1003229aec1cSSascha Wildner  *			EQEs are generated
1004229aec1cSSascha Wildner  */
1005229aec1cSSascha Wildner void
oce_arm_eq(POCE_SOFTC sc,int16_t qid,int npopped,uint32_t rearm,uint32_t clearint)1006229aec1cSSascha Wildner oce_arm_eq(POCE_SOFTC sc,
1007229aec1cSSascha Wildner 	   int16_t qid, int npopped, uint32_t rearm, uint32_t clearint)
1008229aec1cSSascha Wildner {
1009229aec1cSSascha Wildner 	eq_db_t eq_db = { 0 };
1010229aec1cSSascha Wildner 
1011229aec1cSSascha Wildner 	eq_db.bits.rearm = rearm;
1012229aec1cSSascha Wildner 	eq_db.bits.event = 1;
1013229aec1cSSascha Wildner 	eq_db.bits.num_popped = npopped;
1014229aec1cSSascha Wildner 	eq_db.bits.clrint = clearint;
1015229aec1cSSascha Wildner 	eq_db.bits.qid = qid;
1016229aec1cSSascha Wildner 	OCE_WRITE_REG32(sc, db, PD_EQ_DB, eq_db.dw0);
1017229aec1cSSascha Wildner 
1018229aec1cSSascha Wildner }
1019229aec1cSSascha Wildner 
1020229aec1cSSascha Wildner 
1021229aec1cSSascha Wildner 
1022229aec1cSSascha Wildner 
1023229aec1cSSascha Wildner /**
1024229aec1cSSascha Wildner  * @brief		Function to arm a CQ with CQEs
1025229aec1cSSascha Wildner  * @param sc		software handle to the device
1026229aec1cSSascha Wildner  * @param qid		id of the CQ returned by the fw at the time of creation
1027229aec1cSSascha Wildner  * @param npopped	number of CQEs to arm
1028229aec1cSSascha Wildner  * @param rearm		rearm bit enable/disable
1029229aec1cSSascha Wildner  */
oce_arm_cq(POCE_SOFTC sc,int16_t qid,int npopped,uint32_t rearm)1030229aec1cSSascha Wildner void oce_arm_cq(POCE_SOFTC sc, int16_t qid, int npopped, uint32_t rearm)
1031229aec1cSSascha Wildner {
1032229aec1cSSascha Wildner 	cq_db_t cq_db = { 0 };
1033229aec1cSSascha Wildner 
1034229aec1cSSascha Wildner 	cq_db.bits.rearm = rearm;
1035229aec1cSSascha Wildner 	cq_db.bits.num_popped = npopped;
1036229aec1cSSascha Wildner 	cq_db.bits.event = 0;
1037229aec1cSSascha Wildner 	cq_db.bits.qid = qid;
1038229aec1cSSascha Wildner 	OCE_WRITE_REG32(sc, db, PD_CQ_DB, cq_db.dw0);
1039229aec1cSSascha Wildner 
1040229aec1cSSascha Wildner }
1041229aec1cSSascha Wildner 
1042229aec1cSSascha Wildner 
1043229aec1cSSascha Wildner 
1044229aec1cSSascha Wildner 
1045229aec1cSSascha Wildner /*
1046229aec1cSSascha Wildner  * @brief		function to cleanup the eqs used during stop
1047229aec1cSSascha Wildner  * @param eq		pointer to event queue structure
1048229aec1cSSascha Wildner  * @returns		the number of EQs processed
1049229aec1cSSascha Wildner  */
1050229aec1cSSascha Wildner void
oce_drain_eq(struct oce_eq * eq)1051229aec1cSSascha Wildner oce_drain_eq(struct oce_eq *eq)
1052229aec1cSSascha Wildner {
1053229aec1cSSascha Wildner 
1054229aec1cSSascha Wildner 	struct oce_eqe *eqe;
1055229aec1cSSascha Wildner 	uint16_t num_eqe = 0;
1056229aec1cSSascha Wildner 	POCE_SOFTC sc = eq->parent;
1057229aec1cSSascha Wildner 
1058229aec1cSSascha Wildner 	do {
1059229aec1cSSascha Wildner 		eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
1060229aec1cSSascha Wildner 		if (eqe->evnt == 0)
1061229aec1cSSascha Wildner 			break;
1062229aec1cSSascha Wildner 		eqe->evnt = 0;
1063229aec1cSSascha Wildner 		bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
1064229aec1cSSascha Wildner 					BUS_DMASYNC_POSTWRITE);
1065229aec1cSSascha Wildner 		num_eqe++;
1066229aec1cSSascha Wildner 		RING_GET(eq->ring, 1);
1067229aec1cSSascha Wildner 
1068229aec1cSSascha Wildner 	} while (TRUE);
1069229aec1cSSascha Wildner 
1070229aec1cSSascha Wildner 	oce_arm_eq(sc, eq->eq_id, num_eqe, FALSE, TRUE);
1071229aec1cSSascha Wildner 
1072229aec1cSSascha Wildner }
1073229aec1cSSascha Wildner 
1074229aec1cSSascha Wildner 
1075229aec1cSSascha Wildner 
1076229aec1cSSascha Wildner void
oce_drain_wq_cq(struct oce_wq * wq)1077229aec1cSSascha Wildner oce_drain_wq_cq(struct oce_wq *wq)
1078229aec1cSSascha Wildner {
1079229aec1cSSascha Wildner         POCE_SOFTC sc = wq->parent;
1080229aec1cSSascha Wildner         struct oce_cq *cq = wq->cq;
1081229aec1cSSascha Wildner         struct oce_nic_tx_cqe *cqe;
1082229aec1cSSascha Wildner         int num_cqes = 0;
1083229aec1cSSascha Wildner 
1084229aec1cSSascha Wildner 	bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map,
1085229aec1cSSascha Wildner 				 BUS_DMASYNC_POSTWRITE);
1086229aec1cSSascha Wildner 
1087229aec1cSSascha Wildner 	do {
1088229aec1cSSascha Wildner 		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
1089229aec1cSSascha Wildner 		if (cqe->u0.dw[3] == 0)
1090229aec1cSSascha Wildner 			break;
1091229aec1cSSascha Wildner 		cqe->u0.dw[3] = 0;
1092229aec1cSSascha Wildner 		bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map,
1093229aec1cSSascha Wildner 				 BUS_DMASYNC_POSTWRITE);
1094229aec1cSSascha Wildner 		RING_GET(cq->ring, 1);
1095229aec1cSSascha Wildner 		num_cqes++;
1096229aec1cSSascha Wildner 
1097229aec1cSSascha Wildner 	} while (TRUE);
1098229aec1cSSascha Wildner 
1099229aec1cSSascha Wildner 	oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
1100229aec1cSSascha Wildner 
1101229aec1cSSascha Wildner }
1102229aec1cSSascha Wildner 
1103229aec1cSSascha Wildner 
1104229aec1cSSascha Wildner /*
1105229aec1cSSascha Wildner  * @brief		function to drain a MCQ and process its CQEs
1106229aec1cSSascha Wildner  * @param dev		software handle to the device
1107229aec1cSSascha Wildner  * @param cq		pointer to the cq to drain
1108229aec1cSSascha Wildner  * @returns		the number of CQEs processed
1109229aec1cSSascha Wildner  */
1110229aec1cSSascha Wildner void
oce_drain_mq_cq(void * arg)1111229aec1cSSascha Wildner oce_drain_mq_cq(void *arg)
1112229aec1cSSascha Wildner {
1113229aec1cSSascha Wildner 	/* TODO: additional code. */
1114229aec1cSSascha Wildner 	return;
1115229aec1cSSascha Wildner }
1116229aec1cSSascha Wildner 
1117229aec1cSSascha Wildner 
1118229aec1cSSascha Wildner 
1119229aec1cSSascha Wildner /**
1120229aec1cSSascha Wildner  * @brief		function to process a Recieve queue
1121229aec1cSSascha Wildner  * @param arg		pointer to the RQ to charge
1122229aec1cSSascha Wildner  * @return		number of cqes processed
1123229aec1cSSascha Wildner  */
1124229aec1cSSascha Wildner void
oce_drain_rq_cq(struct oce_rq * rq)1125229aec1cSSascha Wildner oce_drain_rq_cq(struct oce_rq *rq)
1126229aec1cSSascha Wildner {
1127229aec1cSSascha Wildner 	struct oce_nic_rx_cqe *cqe;
1128229aec1cSSascha Wildner 	uint16_t num_cqe = 0;
1129229aec1cSSascha Wildner 	struct oce_cq  *cq;
1130229aec1cSSascha Wildner 	POCE_SOFTC sc;
1131229aec1cSSascha Wildner 
1132229aec1cSSascha Wildner 	sc = rq->parent;
1133229aec1cSSascha Wildner 	cq = rq->cq;
1134229aec1cSSascha Wildner 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
1135229aec1cSSascha Wildner 	/* dequeue till you reach an invalid cqe */
1136229aec1cSSascha Wildner 	while (RQ_CQE_VALID(cqe)) {
1137229aec1cSSascha Wildner 		RQ_CQE_INVALIDATE(cqe);
1138229aec1cSSascha Wildner 		RING_GET(cq->ring, 1);
1139229aec1cSSascha Wildner 		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring,
1140229aec1cSSascha Wildner 		    struct oce_nic_rx_cqe);
1141229aec1cSSascha Wildner 		num_cqe++;
1142229aec1cSSascha Wildner 	}
1143229aec1cSSascha Wildner 	oce_arm_cq(sc, cq->cq_id, num_cqe, FALSE);
1144229aec1cSSascha Wildner 
1145229aec1cSSascha Wildner 	return;
1146229aec1cSSascha Wildner }
1147229aec1cSSascha Wildner 
1148229aec1cSSascha Wildner 
1149229aec1cSSascha Wildner void
oce_free_posted_rxbuf(struct oce_rq * rq)1150229aec1cSSascha Wildner oce_free_posted_rxbuf(struct oce_rq *rq)
1151229aec1cSSascha Wildner {
1152229aec1cSSascha Wildner 	struct oce_packet_desc *pd;
1153229aec1cSSascha Wildner 
1154229aec1cSSascha Wildner 	while (rq->pending) {
1155229aec1cSSascha Wildner 
1156229aec1cSSascha Wildner 		pd = &rq->pckts[rq->packets_out];
1157229aec1cSSascha Wildner 		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
1158229aec1cSSascha Wildner 		bus_dmamap_unload(rq->tag, pd->map);
1159229aec1cSSascha Wildner 		if (pd->mbuf != NULL) {
1160229aec1cSSascha Wildner 			m_freem(pd->mbuf);
1161229aec1cSSascha Wildner 			pd->mbuf = NULL;
1162229aec1cSSascha Wildner 		}
1163229aec1cSSascha Wildner 
1164229aec1cSSascha Wildner 		if ((rq->packets_out + 1) == OCE_RQ_PACKET_ARRAY_SIZE)
1165229aec1cSSascha Wildner 			rq->packets_out = 0;
1166229aec1cSSascha Wildner 		else
1167229aec1cSSascha Wildner 			rq->packets_out++;
1168229aec1cSSascha Wildner 
1169229aec1cSSascha Wildner                 rq->pending--;
1170229aec1cSSascha Wildner 	}
1171229aec1cSSascha Wildner 
1172229aec1cSSascha Wildner }
1173229aec1cSSascha Wildner 
1174229aec1cSSascha Wildner void
oce_stop_rx(POCE_SOFTC sc)1175229aec1cSSascha Wildner oce_stop_rx(POCE_SOFTC sc)
1176229aec1cSSascha Wildner {
1177229aec1cSSascha Wildner 	struct oce_mbx mbx;
1178229aec1cSSascha Wildner 	struct mbx_delete_nic_rq *fwcmd;
1179229aec1cSSascha Wildner 	struct oce_rq *rq;
1180229aec1cSSascha Wildner 	int i = 0;
1181229aec1cSSascha Wildner 
1182229aec1cSSascha Wildner 	for_all_rq_queues(sc, rq, i) {
1183229aec1cSSascha Wildner 		if (rq->qstate == QCREATED) {
1184229aec1cSSascha Wildner 			/* Delete rxq in firmware */
1185229aec1cSSascha Wildner 
1186229aec1cSSascha Wildner 			bzero(&mbx, sizeof(mbx));
1187229aec1cSSascha Wildner 			fwcmd = (struct mbx_delete_nic_rq *)&mbx.payload;
1188229aec1cSSascha Wildner 			fwcmd->params.req.rq_id = rq->rq_id;
1189229aec1cSSascha Wildner 
1190229aec1cSSascha Wildner 			(void)oce_destroy_q(sc, &mbx,
1191229aec1cSSascha Wildner 				sizeof(struct mbx_delete_nic_rq), QTYPE_RQ);
1192229aec1cSSascha Wildner 
1193229aec1cSSascha Wildner 			rq->qstate = QDELETED;
1194229aec1cSSascha Wildner 
1195229aec1cSSascha Wildner 			DELAY(1);
1196229aec1cSSascha Wildner 
1197229aec1cSSascha Wildner 			/* Free posted RX buffers that are not used */
1198229aec1cSSascha Wildner 			oce_free_posted_rxbuf(rq);
1199229aec1cSSascha Wildner 
1200229aec1cSSascha Wildner 		}
1201229aec1cSSascha Wildner 	}
1202229aec1cSSascha Wildner }
1203229aec1cSSascha Wildner 
1204229aec1cSSascha Wildner 
1205229aec1cSSascha Wildner 
1206229aec1cSSascha Wildner int
oce_start_rx(POCE_SOFTC sc)1207229aec1cSSascha Wildner oce_start_rx(POCE_SOFTC sc)
1208229aec1cSSascha Wildner {
1209229aec1cSSascha Wildner 	struct oce_rq *rq;
1210229aec1cSSascha Wildner 	int rc = 0, i;
1211229aec1cSSascha Wildner 
1212229aec1cSSascha Wildner 	for_all_rq_queues(sc, rq, i) {
1213229aec1cSSascha Wildner 		if (rq->qstate == QCREATED)
1214229aec1cSSascha Wildner 			continue;
1215229aec1cSSascha Wildner 		rc = oce_mbox_create_rq(rq);
1216229aec1cSSascha Wildner 		if (rc)
1217229aec1cSSascha Wildner 			goto error;
1218229aec1cSSascha Wildner 		/* reset queue pointers */
1219229aec1cSSascha Wildner 		rq->qstate 	 = QCREATED;
1220229aec1cSSascha Wildner 		rq->pending	 = 0;
1221229aec1cSSascha Wildner 		rq->ring->cidx	 = 0;
1222229aec1cSSascha Wildner 		rq->ring->pidx	 = 0;
1223229aec1cSSascha Wildner 		rq->packets_in	 = 0;
1224229aec1cSSascha Wildner 		rq->packets_out	 = 0;
1225229aec1cSSascha Wildner 	}
1226229aec1cSSascha Wildner 
1227229aec1cSSascha Wildner 	DELAY(1);
1228229aec1cSSascha Wildner 
1229229aec1cSSascha Wildner 	/* RSS config */
1230*c976b08eSSascha Wildner 	if (is_rss_enabled(sc)) {
1231229aec1cSSascha Wildner 		rc = oce_config_nic_rss(sc, (uint8_t) sc->if_id, RSS_ENABLE);
1232229aec1cSSascha Wildner 		if (rc)
1233229aec1cSSascha Wildner 			goto error;
1234229aec1cSSascha Wildner 
1235229aec1cSSascha Wildner 	}
1236229aec1cSSascha Wildner 
1237229aec1cSSascha Wildner 	return rc;
1238229aec1cSSascha Wildner error:
1239229aec1cSSascha Wildner 	device_printf(sc->dev, "Start RX failed\n");
1240229aec1cSSascha Wildner 	return rc;
1241229aec1cSSascha Wildner 
1242229aec1cSSascha Wildner }
1243