config root man

Current Path : /sys/amd64/compile/hs32/modules/usr/src/sys/modules/fxp/@/dev/oce/

FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64
Upload File :
Current File : //sys/amd64/compile/hs32/modules/usr/src/sys/modules/fxp/@/dev/oce/oce_queue.c

/*-
 * Copyright (C) 2012 Emulex
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the Emulex Corporation nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Contact Information:
 * freebsd-drivers@emulex.com
 *
 * Emulex
 * 3333 Susan Street
 * Costa Mesa, CA 92626
 */



/* $FreeBSD: release/9.1.0/sys/dev/oce/oce_queue.c 231663 2012-02-14 10:30:22Z luigi $ */


#include "oce_if.h"

/*****************************************************
 * local queue functions
 *****************************************************/

static struct oce_wq *oce_wq_init(POCE_SOFTC sc,
				  uint32_t q_len, uint32_t wq_type);
static int oce_wq_create(struct oce_wq *wq, struct oce_eq *eq);
static void oce_wq_free(struct oce_wq *wq);
static void oce_wq_del(struct oce_wq *wq);
static struct oce_rq *oce_rq_init(POCE_SOFTC sc,
				  uint32_t q_len,
				  uint32_t frag_size,
				  uint32_t mtu, uint32_t rss);
static int oce_rq_create(struct oce_rq *rq, uint32_t if_id, struct oce_eq *eq);
static void oce_rq_free(struct oce_rq *rq);
static void oce_rq_del(struct oce_rq *rq);
static struct oce_eq *oce_eq_create(POCE_SOFTC sc,
				    uint32_t q_len,
				    uint32_t item_size,
				    uint32_t eq_delay,
				    uint32_t vector);
static void oce_eq_del(struct oce_eq *eq);
static struct oce_mq *oce_mq_create(POCE_SOFTC sc,
				    struct oce_eq *eq, uint32_t q_len);
static void oce_mq_free(struct oce_mq *mq);
static int oce_destroy_q(POCE_SOFTC sc, struct oce_mbx
			 *mbx, size_t req_size, enum qtype qtype);
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);
static void oce_cq_del(POCE_SOFTC sc, struct oce_cq *cq);



/**
 * @brief	Create and initialize all the queues on the board
 * @param sc	software handle to the device
 * @returns 0	if successful, or error
 **/
int
oce_queue_init_all(POCE_SOFTC sc)
{
	int rc = 0, i, vector;
	struct oce_wq *wq;
	struct oce_rq *rq;

	/* alloc TX/RX queues */
	for_all_wq_queues(sc, wq, i) {
		sc->wq[i] = oce_wq_init(sc, sc->tx_ring_size,
					 NIC_WQ_TYPE_STANDARD);
		if (!sc->wq[i]) 
			goto error;
		
	}

	for_all_rq_queues(sc, rq, i) {
		sc->rq[i] = oce_rq_init(sc, sc->rx_ring_size, sc->rq_frag_size,
					OCE_MAX_JUMBO_FRAME_SIZE,
					(i == 0) ? 0 : sc->rss_enable);
		if (!sc->rq[i]) 
			goto error;
	}

	/* Create network interface on card */
	if (oce_create_nw_interface(sc))
		goto error;

	/* create all of the event queues */
	for (vector = 0; vector < sc->intr_count; vector++) {
		sc->eq[vector] = oce_eq_create(sc, EQ_LEN_1024, EQE_SIZE_4,
						 0, vector);
		if (!sc->eq[vector])
			goto error;
	}

	/* create Tx, Rx and mcc queues */
	for_all_wq_queues(sc, wq, i) {
		rc = oce_wq_create(wq, sc->eq[i]);
		if (rc)
			goto error;
		wq->queue_index = i;
		TASK_INIT(&wq->txtask, 1, oce_tx_task, wq);
	}

	for_all_rq_queues(sc, rq, i) {
		rc = oce_rq_create(rq, sc->if_id,
					sc->eq[(i == 0) ? 0:(i-1)]);
		if (rc)
			goto error;
		rq->queue_index = i;
	}

	sc->mq = oce_mq_create(sc, sc->eq[0], 64);
	if (!sc->mq)
		goto error;

	return rc;

error:
	oce_queue_release_all(sc);
	return 1;
}



/**
 * @brief Releases all mailbox queues created
 * @param sc		software handle to the device
 */
void
oce_queue_release_all(POCE_SOFTC sc)
{
	int i = 0;
	struct oce_wq *wq;
	struct oce_rq *rq;
	struct oce_eq *eq;

	for_all_rq_queues(sc, rq, i) {
		if (rq) {
			oce_rq_del(sc->rq[i]);
			oce_rq_free(sc->rq[i]);
		}
	}

	for_all_wq_queues(sc, wq, i) {
		if (wq) {
			oce_wq_del(sc->wq[i]);
			oce_wq_free(sc->wq[i]);
		}
	}

	if (sc->mq)
		oce_mq_free(sc->mq);

	for_all_evnt_queues(sc, eq, i) {
		if (eq)
			oce_eq_del(sc->eq[i]);
	}
}



/**
 * @brief 		Function to create a WQ for NIC Tx
 * @param sc 		software handle to the device
 * @param qlen		number of entries in the queue
 * @param wq_type	work queue type
 * @returns		the pointer to the WQ created or NULL on failure
 */
static struct
oce_wq *oce_wq_init(POCE_SOFTC sc, uint32_t q_len, uint32_t wq_type)
{
	struct oce_wq *wq;
	int rc = 0, i;

	/* q_len must be min 256 and max 2k */
	if (q_len < 256 || q_len > 2048) {
		device_printf(sc->dev,
			  "Invalid q length. Must be "
			  "[256, 2000]: 0x%x\n", q_len);
		return NULL;
	}

	/* allocate wq */
	wq = malloc(sizeof(struct oce_wq), M_DEVBUF, M_NOWAIT | M_ZERO);
	if (!wq)
		return NULL;

	/* Set the wq config */
	wq->cfg.q_len = q_len;
	wq->cfg.wq_type = (uint8_t) wq_type;
	wq->cfg.eqd = OCE_DEFAULT_WQ_EQD;
	wq->cfg.nbufs = 2 * wq->cfg.q_len;
	wq->cfg.nhdl = 2 * wq->cfg.q_len;

	wq->parent = (void *)sc;

	rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev),
				1, 0,
				BUS_SPACE_MAXADDR,
				BUS_SPACE_MAXADDR,
				NULL, NULL,
				OCE_MAX_TX_SIZE,
				OCE_MAX_TX_ELEMENTS,
				PAGE_SIZE, 0, NULL, NULL, &wq->tag);

	if (rc)
		goto free_wq;


	for (i = 0; i < OCE_WQ_PACKET_ARRAY_SIZE; i++) {
		rc = bus_dmamap_create(wq->tag, 0, &wq->pckts[i].map);
		if (rc) 
			goto free_wq;
	}

	wq->ring = oce_create_ring_buffer(sc, q_len, NIC_WQE_SIZE);
	if (!wq->ring)
		goto free_wq;


	LOCK_CREATE(&wq->tx_lock, "TX_lock");
	
#if __FreeBSD_version >= 800000
	/* Allocate buf ring for multiqueue*/
	wq->br = buf_ring_alloc(4096, M_DEVBUF,
			M_WAITOK, &wq->tx_lock.mutex);
	if (!wq->br)
		goto free_wq;
#endif
	return wq;


free_wq:
	device_printf(sc->dev, "Create WQ failed\n");
	oce_wq_free(wq);
	return NULL;
}



/**
 * @brief 		Frees the work queue
 * @param wq		pointer to work queue to free
 */
static void
oce_wq_free(struct oce_wq *wq)
{
	POCE_SOFTC sc = (POCE_SOFTC) wq->parent;
	int i;

	taskqueue_drain(taskqueue_swi, &wq->txtask);

	if (wq->ring != NULL) {
		oce_destroy_ring_buffer(sc, wq->ring);
		wq->ring = NULL;
	}

	for (i = 0; i < OCE_WQ_PACKET_ARRAY_SIZE; i++) {
		if (wq->pckts[i].map != NULL) {
			bus_dmamap_unload(wq->tag, wq->pckts[i].map);
			bus_dmamap_destroy(wq->tag, wq->pckts[i].map);
			wq->pckts[i].map = NULL;
		}
	}

	if (wq->tag != NULL)
		bus_dma_tag_destroy(wq->tag);
	if (wq->br != NULL)
		buf_ring_free(wq->br, M_DEVBUF);

	LOCK_DESTROY(&wq->tx_lock);
	free(wq, M_DEVBUF);
}



/**
 * @brief 		Create a work queue
 * @param wq		pointer to work queue
 * @param eq		pointer to associated event queue
 */
static int
oce_wq_create(struct oce_wq *wq, struct oce_eq *eq)
{
	POCE_SOFTC sc = wq->parent;
	struct oce_cq *cq;
	int rc = 0;

	/* create the CQ */
	cq = oce_cq_create(sc,
			   eq,
			   CQ_LEN_1024,
			   sizeof(struct oce_nic_tx_cqe), 0, 1, 0, 3);
	if (!cq)
		return ENXIO;


	wq->cq = cq;

	rc = oce_mbox_create_wq(wq);
	if (rc)
		goto error;

	wq->qstate = QCREATED;
	wq->wq_free = wq->cfg.q_len;
	wq->ring->cidx = 0;
	wq->ring->pidx = 0;

	eq->cq[eq->cq_valid] = cq;
	eq->cq_valid++;
	cq->cb_arg = wq;
	cq->cq_handler = oce_wq_handler;

	return 0;

error:
	device_printf(sc->dev, "WQ create failed\n");
	oce_wq_del(wq);
	return rc;
}




/**
 * @brief 		Delete a work queue
 * @param wq		pointer to work queue
 */
static void
oce_wq_del(struct oce_wq *wq)
{
	struct oce_mbx mbx;
	struct mbx_delete_nic_wq *fwcmd;
	POCE_SOFTC sc = (POCE_SOFTC) wq->parent;

	if (wq->qstate == QCREATED) {
		bzero(&mbx, sizeof(struct oce_mbx));
		/* now fill the command */
		fwcmd = (struct mbx_delete_nic_wq *)&mbx.payload;
		fwcmd->params.req.wq_id = wq->wq_id;
		(void)oce_destroy_q(sc, &mbx,
				sizeof(struct mbx_delete_nic_wq), QTYPE_WQ);
		wq->qstate = QDELETED;
	}

	if (wq->cq != NULL) {
		oce_cq_del(sc, wq->cq);
		wq->cq = NULL;
	}
}



/**
 * @brief 		function to allocate receive queue resources
 * @param sc		software handle to the device
 * @param q_len		length of receive queue
 * @param frag_size	size of an receive queue fragment
 * @param mtu		maximum transmission unit
 * @param rss		is-rss-queue flag
 * @returns		the pointer to the RQ created or NULL on failure
 */
static struct
oce_rq *oce_rq_init(POCE_SOFTC sc,
				  uint32_t q_len,
				  uint32_t frag_size,
				  uint32_t mtu, uint32_t rss)
{
	struct oce_rq *rq;
	int rc = 0, i;

	if (OCE_LOG2(frag_size) <= 0)
		return NULL;
	
	if ((q_len == 0) || (q_len > 1024))
		return NULL;

	/* allocate the rq */
	rq = malloc(sizeof(struct oce_rq), M_DEVBUF, M_NOWAIT | M_ZERO);
	if (!rq) 
		return NULL;

	
	rq->cfg.q_len = q_len;
	rq->cfg.frag_size = frag_size;
	rq->cfg.mtu = mtu;
	rq->cfg.eqd = 0;
	rq->lro_pkts_queued = 0;
	rq->cfg.is_rss_queue = rss;
	rq->packets_in = 0;
        rq->packets_out = 0;
        rq->pending = 0;

	rq->parent = (void *)sc;

	rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev),
				1, 0,
				BUS_SPACE_MAXADDR,
				BUS_SPACE_MAXADDR,
				NULL, NULL,
				OCE_MAX_RX_SIZE,
				1, PAGE_SIZE, 0, NULL, NULL, &rq->tag);

	if (rc)
		goto free_rq;

	for (i = 0; i < OCE_RQ_PACKET_ARRAY_SIZE; i++) {
		rc = bus_dmamap_create(rq->tag, 0, &rq->pckts[i].map);
		if (rc)
			goto free_rq;
	}

	/* create the ring buffer */
	rq->ring = oce_create_ring_buffer(sc, q_len,
				 sizeof(struct oce_nic_rqe));
	if (!rq->ring)
		goto free_rq;

	LOCK_CREATE(&rq->rx_lock, "RX_lock");

	return rq;

free_rq:
	device_printf(sc->dev, "Create RQ failed\n");
	oce_rq_free(rq);
	return NULL;
}




/**
 * @brief 		Free a receive queue
 * @param rq		pointer to receive queue
 */
static void
oce_rq_free(struct oce_rq *rq)
{
	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
	int i = 0 ;

	if (rq->ring != NULL) {
		oce_destroy_ring_buffer(sc, rq->ring);
		rq->ring = NULL;
	}
	for (i = 0; i < OCE_RQ_PACKET_ARRAY_SIZE; i++) {
		if (rq->pckts[i].map != NULL) {
			bus_dmamap_unload(rq->tag, rq->pckts[i].map);
			bus_dmamap_destroy(rq->tag, rq->pckts[i].map);
			rq->pckts[i].map = NULL;
		}
		if (rq->pckts[i].mbuf) {
			m_free(rq->pckts[i].mbuf);
			rq->pckts[i].mbuf = NULL;
		}
	}

	if (rq->tag != NULL)
		bus_dma_tag_destroy(rq->tag);

	LOCK_DESTROY(&rq->rx_lock);
	free(rq, M_DEVBUF);
}




/**
 * @brief 		Create a receive queue
 * @param rq 		receive queue
 * @param if_id		interface identifier index`
 * @param eq		pointer to event queue
 */
static int
oce_rq_create(struct oce_rq *rq, uint32_t if_id, struct oce_eq *eq)
{
	POCE_SOFTC sc = rq->parent;
	struct oce_cq *cq;

	cq = oce_cq_create(sc,
			   eq,
			   CQ_LEN_1024,
			   sizeof(struct oce_nic_rx_cqe), 0, 1, 0, 3);
	if (!cq)
		return ENXIO;

	rq->cq = cq;
	rq->cfg.if_id = if_id;

	/* Dont create RQ here. Create in if_activate */
	rq->qstate     = 0;
	rq->ring->cidx = 0;
	rq->ring->pidx = 0;
	eq->cq[eq->cq_valid] = cq;
	eq->cq_valid++;
	cq->cb_arg = rq;
	cq->cq_handler = oce_rq_handler;

	return 0;

}




/**
 * @brief 		Delete a receive queue
 * @param rq		receive queue
 */
static void
oce_rq_del(struct oce_rq *rq)
{
	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
	struct oce_mbx mbx;
	struct mbx_delete_nic_rq *fwcmd;

	if (rq->qstate == QCREATED) {
		bzero(&mbx, sizeof(mbx));

		fwcmd = (struct mbx_delete_nic_rq *)&mbx.payload;
		fwcmd->params.req.rq_id = rq->rq_id;
		(void)oce_destroy_q(sc, &mbx,
				sizeof(struct mbx_delete_nic_rq), QTYPE_RQ);
		rq->qstate = QDELETED;
	}

	if (rq->cq != NULL) {
		oce_cq_del(sc, rq->cq);
		rq->cq = NULL;
	}
}



/**
 * @brief		function to create an event queue
 * @param sc		software handle to the device
 * @param q_len		length of event queue
 * @param item_size	size of an event queue item
 * @param eq_delay	event queue delay
 * @retval eq      	success, pointer to event queue
 * @retval NULL		failure
 */
static struct
oce_eq *oce_eq_create(POCE_SOFTC sc, uint32_t q_len,
				    uint32_t item_size,
				    uint32_t eq_delay,
				    uint32_t vector)
{
	struct oce_eq *eq;
	int rc = 0;

	/* allocate an eq */
	eq = malloc(sizeof(struct oce_eq), M_DEVBUF, M_NOWAIT | M_ZERO);
	if (eq == NULL)
		return NULL;

	eq->parent = (void *)sc;
	eq->eq_id = 0xffff;
	eq->ring = oce_create_ring_buffer(sc, q_len, item_size);
	if (!eq->ring)
		goto free_eq;
	
	eq->eq_cfg.q_len = q_len;
	eq->eq_cfg.item_size = item_size;
	eq->eq_cfg.cur_eqd = (uint8_t) eq_delay;

	rc = oce_mbox_create_eq(eq);
	if (rc)
		goto free_eq;

	sc->intrs[sc->neqs++].eq = eq;

	return eq;

free_eq:
	oce_eq_del(eq);
	return NULL;
}




/**
 * @brief 		Function to delete an event queue
 * @param eq		pointer to an event queue
 */
static void
oce_eq_del(struct oce_eq *eq)
{
	struct oce_mbx mbx;
	struct mbx_destroy_common_eq *fwcmd;
	POCE_SOFTC sc = (POCE_SOFTC) eq->parent;

	if (eq->eq_id != 0xffff) {
		bzero(&mbx, sizeof(mbx));
		fwcmd = (struct mbx_destroy_common_eq *)&mbx.payload;
		fwcmd->params.req.id = eq->eq_id;
		(void)oce_destroy_q(sc, &mbx,
			sizeof(struct mbx_destroy_common_eq), QTYPE_EQ);
	}

	if (eq->ring != NULL) {
		oce_destroy_ring_buffer(sc, eq->ring);
		eq->ring = NULL;
	}

	free(eq, M_DEVBUF);

}




/**
 * @brief		Function to create an MQ
 * @param sc		software handle to the device
 * @param eq		the EQ to associate with the MQ for event notification
 * @param q_len		the number of entries to create in the MQ
 * @returns		pointer to the created MQ, failure otherwise
 */
static struct oce_mq *
oce_mq_create(POCE_SOFTC sc, struct oce_eq *eq, uint32_t q_len)
{
	struct oce_mbx mbx;
	struct mbx_create_common_mq *fwcmd = NULL;
	struct oce_mq *mq = NULL;
	int rc = 0;
	struct oce_cq *cq;
	oce_mq_ctx_t *ctx;
	uint32_t num_pages;
	uint32_t page_size;
	uint32_t version;


	cq = oce_cq_create(sc, eq, CQ_LEN_256,
			sizeof(struct oce_mq_cqe), 1, 1, 0, 0);
	if (!cq)
		return NULL;

	/* allocate the mq */
	mq = malloc(sizeof(struct oce_mq), M_DEVBUF, M_NOWAIT | M_ZERO);
	if (!mq) {
		oce_cq_del(sc, cq);
		goto error;
	}

	mq->parent = sc;

	mq->ring = oce_create_ring_buffer(sc, q_len, sizeof(struct oce_mbx));
	if (!mq->ring)
		goto error;

	bzero(&mbx, sizeof(struct oce_mbx));

	fwcmd = (struct mbx_create_common_mq *)&mbx.payload;
	version = OCE_MBX_VER_V0;
	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
				MBX_SUBSYSTEM_COMMON,
				OPCODE_COMMON_CREATE_MQ,
				MBX_TIMEOUT_SEC,
				sizeof(struct mbx_create_common_mq),
				version);

	num_pages = oce_page_list(mq->ring, &fwcmd->params.req.pages[0]);
	page_size = mq->ring->num_items * mq->ring->item_size;

	ctx = &fwcmd->params.req.context;
	ctx->v0.num_pages = num_pages;
	ctx->v0.cq_id = cq->cq_id;
	ctx->v0.ring_size = OCE_LOG2(q_len) + 1;
	ctx->v0.valid = 1;

	mbx.u0.s.embedded = 1;
	mbx.payload_length = sizeof(struct mbx_create_common_mq);
	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);

	rc = oce_mbox_post(sc, &mbx, NULL);
	if (rc)
		goto error;

	mq->mq_id = LE_16(fwcmd->params.rsp.mq_id);
	mq->cq = cq;
	eq->cq[eq->cq_valid] = cq;
	eq->cq_valid++;
	mq->cq->eq = eq;
	mq->cfg.q_len = (uint8_t) q_len;
	mq->cfg.eqd = 0;
	mq->qstate = QCREATED;

	mq->cq->cb_arg = mq;
	mq->cq->cq_handler = oce_mq_handler;

	return mq;

error:
	device_printf(sc->dev, "MQ create failed\n");
	oce_mq_free(mq);
	mq = NULL;
	return mq;
}





/**
 * @brief		Function to free a mailbox queue
 * @param mq		pointer to a mailbox queue
 */
static void
oce_mq_free(struct oce_mq *mq)
{
	POCE_SOFTC sc = (POCE_SOFTC) mq->parent;
	struct oce_mbx mbx;
	struct mbx_destroy_common_mq *fwcmd;

	if (!mq)
		return;

	if (mq->ring != NULL) {
		oce_destroy_ring_buffer(sc, mq->ring);
		mq->ring = NULL;
		if (mq->qstate == QCREATED) {
			bzero(&mbx, sizeof (struct oce_mbx));
			fwcmd = (struct mbx_destroy_common_mq *)&mbx.payload;
			fwcmd->params.req.id = mq->mq_id;
			(void) oce_destroy_q(sc, &mbx,
				sizeof (struct mbx_destroy_common_mq),
				QTYPE_MQ);
		}
		mq->qstate = QDELETED;
	}

	if (mq->cq != NULL) {
		oce_cq_del(sc, mq->cq);
		mq->cq = NULL;
	}

	free(mq, M_DEVBUF);
	mq = NULL;
}



/**
 * @brief		Function to delete a EQ, CQ, MQ, WQ or RQ
 * @param sc		sofware handle to the device
 * @param mbx		mailbox command to send to the fw to delete the queue
 *			(mbx contains the queue information to delete)
 * @param req_size	the size of the mbx payload dependent on the qtype
 * @param qtype		the type of queue i.e. EQ, CQ, MQ, WQ or RQ
 * @returns 		0 on success, failure otherwise
 */
static int
oce_destroy_q(POCE_SOFTC sc, struct oce_mbx *mbx, size_t req_size,
		enum qtype qtype)
{
	struct mbx_hdr *hdr = (struct mbx_hdr *)&mbx->payload;
	int opcode;
	int subsys;
	int rc = 0;

	switch (qtype) {
	case QTYPE_EQ:
		opcode = OPCODE_COMMON_DESTROY_EQ;
		subsys = MBX_SUBSYSTEM_COMMON;
		break;
	case QTYPE_CQ:
		opcode = OPCODE_COMMON_DESTROY_CQ;
		subsys = MBX_SUBSYSTEM_COMMON;
		break;
	case QTYPE_MQ:
		opcode = OPCODE_COMMON_DESTROY_MQ;
		subsys = MBX_SUBSYSTEM_COMMON;
		break;
	case QTYPE_WQ:
		opcode = NIC_DELETE_WQ;
		subsys = MBX_SUBSYSTEM_NIC;
		break;
	case QTYPE_RQ:
		opcode = NIC_DELETE_RQ;
		subsys = MBX_SUBSYSTEM_NIC;
		break;
	default:
		return EINVAL;
	}

	mbx_common_req_hdr_init(hdr, 0, 0, subsys,
				opcode, MBX_TIMEOUT_SEC, req_size,
				OCE_MBX_VER_V0);

	mbx->u0.s.embedded = 1;
	mbx->payload_length = (uint32_t) req_size;
	DW_SWAP(u32ptr(mbx), mbx->payload_length + OCE_BMBX_RHDR_SZ);

	rc = oce_mbox_post(sc, mbx, NULL);

	if (rc != 0)
		device_printf(sc->dev, "Failed to del q\n");

	return rc;
}



/**
 * @brief		Function to create a completion queue
 * @param sc		software handle to the device
 * @param eq		optional eq to be associated with to the cq
 * @param q_len		length of completion queue
 * @param item_size	size of completion queue items
 * @param sol_event	command context event
 * @param is_eventable	event table
 * @param nodelay	no delay flag
 * @param ncoalesce	no coalescence flag
 * @returns 		pointer to the cq created, NULL on failure
 */
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)
{
	struct oce_cq *cq = NULL;
	int rc = 0;

	cq = malloc(sizeof(struct oce_cq), M_DEVBUF, M_NOWAIT | M_ZERO);
	if (!cq)
		return NULL;

	cq->ring = oce_create_ring_buffer(sc, q_len, item_size);
	if (!cq->ring)
		goto error;
	
	cq->parent = sc;
	cq->eq = eq;
	cq->cq_cfg.q_len = q_len;
	cq->cq_cfg.item_size = item_size;
	cq->cq_cfg.nodelay = (uint8_t) nodelay;

	rc = oce_mbox_cq_create(cq, ncoalesce, is_eventable);
	if (rc)
		goto error;

	sc->cq[sc->ncqs++] = cq;

	return cq;

error:
	device_printf(sc->dev, "CQ create failed\n");
	oce_cq_del(sc, cq);
	return NULL;
}



/**
 * @brief		Deletes the completion queue
 * @param sc		software handle to the device
 * @param cq		pointer to a completion queue
 */
static void 
oce_cq_del(POCE_SOFTC sc, struct oce_cq *cq)
{
	struct oce_mbx mbx;
	struct mbx_destroy_common_cq *fwcmd;

	if (cq->ring != NULL) {

		bzero(&mbx, sizeof(struct oce_mbx));
		/* now fill the command */
		fwcmd = (struct mbx_destroy_common_cq *)&mbx.payload;
		fwcmd->params.req.id = cq->cq_id;
		(void)oce_destroy_q(sc, &mbx,
			sizeof(struct mbx_destroy_common_cq), QTYPE_CQ);
		/*NOW destroy the ring */
		oce_destroy_ring_buffer(sc, cq->ring);
		cq->ring = NULL;
	}

	free(cq, M_DEVBUF);
	cq = NULL;
}



/**
 * @brief		Start a receive queue
 * @param rq		pointer to a receive queue
 */
int
oce_start_rq(struct oce_rq *rq)
{
	int rc;

	rc = oce_alloc_rx_bufs(rq, rq->cfg.q_len);

	if (rc == 0)
		oce_arm_cq(rq->parent, rq->cq->cq_id, 0, TRUE);
	return rc;
}



/**
 * @brief		Start a work queue
 * @param wq		pointer to a work queue
 */
int
oce_start_wq(struct oce_wq *wq)
{
	oce_arm_cq(wq->parent, wq->cq->cq_id, 0, TRUE);
	return 0;
}



/**
 * @brief		Start a mailbox queue
 * @param mq		pointer to a mailbox queue
 */
int
oce_start_mq(struct oce_mq *mq)
{
	oce_arm_cq(mq->parent, mq->cq->cq_id, 0, TRUE);
	return 0;
}



/**
 * @brief		Function to arm an EQ so that it can generate events
 * @param sc		software handle to the device
 * @param qid		id of the EQ returned by the fw at the time of creation
 * @param npopped	number of EQEs to arm
 * @param rearm		rearm bit enable/disable
 * @param clearint	bit to clear the interrupt condition because of which
 *			EQEs are generated
 */
void
oce_arm_eq(POCE_SOFTC sc,
	   int16_t qid, int npopped, uint32_t rearm, uint32_t clearint)
{
	eq_db_t eq_db = { 0 };

	eq_db.bits.rearm = rearm;
	eq_db.bits.event = 1;
	eq_db.bits.num_popped = npopped;
	eq_db.bits.clrint = clearint;
	eq_db.bits.qid = qid;
	OCE_WRITE_REG32(sc, db, PD_EQ_DB, eq_db.dw0);

}




/**
 * @brief		Function to arm a CQ with CQEs
 * @param sc		software handle to the device
 * @param qid		id of the CQ returned by the fw at the time of creation
 * @param npopped	number of CQEs to arm
 * @param rearm		rearm bit enable/disable
 */
void oce_arm_cq(POCE_SOFTC sc, int16_t qid, int npopped, uint32_t rearm)
{
	cq_db_t cq_db = { 0 };

	cq_db.bits.rearm = rearm;
	cq_db.bits.num_popped = npopped;
	cq_db.bits.event = 0;
	cq_db.bits.qid = qid;
	OCE_WRITE_REG32(sc, db, PD_CQ_DB, cq_db.dw0);

}




/*
 * @brief		function to cleanup the eqs used during stop
 * @param eq		pointer to event queue structure
 * @returns		the number of EQs processed
 */
void
oce_drain_eq(struct oce_eq *eq)
{

	struct oce_eqe *eqe;
	uint16_t num_eqe = 0;
	POCE_SOFTC sc = eq->parent;

	do {
		eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
		if (eqe->evnt == 0)
			break;
		eqe->evnt = 0;
		bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
					BUS_DMASYNC_POSTWRITE);
		num_eqe++;
		RING_GET(eq->ring, 1);

	} while (TRUE);

	oce_arm_eq(sc, eq->eq_id, num_eqe, FALSE, TRUE);
	
}



void
oce_drain_wq_cq(struct oce_wq *wq)
{
        POCE_SOFTC sc = wq->parent;
        struct oce_cq *cq = wq->cq;
        struct oce_nic_tx_cqe *cqe;
        int num_cqes = 0;

	bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map,
				 BUS_DMASYNC_POSTWRITE);

	do {
		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
		if (cqe->u0.dw[3] == 0)
			break;			
		cqe->u0.dw[3] = 0;
		bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map,
				 BUS_DMASYNC_POSTWRITE);
		RING_GET(cq->ring, 1);
		num_cqes++;

	} while (TRUE);

	oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);

}


/*
 * @brief		function to drain a MCQ and process its CQEs
 * @param dev		software handle to the device
 * @param cq		pointer to the cq to drain
 * @returns		the number of CQEs processed
 */
void
oce_drain_mq_cq(void *arg)
{
	/* TODO: additional code. */
	return;
}



/**
 * @brief		function to process a Recieve queue
 * @param arg		pointer to the RQ to charge
 * @return		number of cqes processed
 */
void
oce_drain_rq_cq(struct oce_rq *rq)
{
	struct oce_nic_rx_cqe *cqe;
	uint16_t num_cqe = 0;
	struct oce_cq  *cq;
	POCE_SOFTC sc;

	sc = rq->parent;
	cq = rq->cq;
	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
	/* dequeue till you reach an invalid cqe */
	while (RQ_CQE_VALID(cqe)) {
		RQ_CQE_INVALIDATE(cqe);
		RING_GET(cq->ring, 1);
		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring,
		    struct oce_nic_rx_cqe);
		num_cqe++;
	}
	oce_arm_cq(sc, cq->cq_id, num_cqe, FALSE);

	return;
}


void
oce_free_posted_rxbuf(struct oce_rq *rq)
{
	struct oce_packet_desc *pd;
	
	while (rq->pending) {

		pd = &rq->pckts[rq->packets_out];
		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
		bus_dmamap_unload(rq->tag, pd->map);
		if (pd->mbuf != NULL) {
			m_freem(pd->mbuf);
			pd->mbuf = NULL;
		}

		if ((rq->packets_out + 1) == OCE_RQ_PACKET_ARRAY_SIZE)
			rq->packets_out = 0;
		else
			rq->packets_out++;

                rq->pending--;
	}

}

void
oce_stop_rx(POCE_SOFTC sc)
{
	struct oce_mbx mbx;
	struct mbx_delete_nic_rq *fwcmd;
	struct oce_rq *rq;
	int i = 0;

	for_all_rq_queues(sc, rq, i) {
		if (rq->qstate == QCREATED) {
			/* Delete rxq in firmware */

			bzero(&mbx, sizeof(mbx));
			fwcmd = (struct mbx_delete_nic_rq *)&mbx.payload;
			fwcmd->params.req.rq_id = rq->rq_id;

			(void)oce_destroy_q(sc, &mbx, 
				sizeof(struct mbx_delete_nic_rq), QTYPE_RQ);

			rq->qstate = QDELETED;

			DELAY(1);

			/* Free posted RX buffers that are not used */
			oce_free_posted_rxbuf(rq);
			
		}
	}
}



int
oce_start_rx(POCE_SOFTC sc)
{
	struct oce_rq *rq;
	int rc = 0, i;
	
	for_all_rq_queues(sc, rq, i) {
		if (rq->qstate == QCREATED)
			continue;
		rc = oce_mbox_create_rq(rq);
		if (rc)
			goto error;
		/* reset queue pointers */
		rq->qstate 	 = QCREATED;
		rq->pending	 = 0;
		rq->ring->cidx	 = 0;
		rq->ring->pidx	 = 0;
		rq->packets_in	 = 0;
		rq->packets_out	 = 0;
	}

	DELAY(1);
	
	/* RSS config */
	if (sc->rss_enable) {
		rc = oce_config_nic_rss(sc, (uint8_t) sc->if_id, RSS_ENABLE);
		if (rc)
			goto error;

	}

	return rc;
error:
	device_printf(sc->dev, "Start RX failed\n");
	return rc;

}




Man Man