14d0e5007SSukumar Swaminathan /*
24d0e5007SSukumar Swaminathan  * CDDL HEADER START
34d0e5007SSukumar Swaminathan  *
44d0e5007SSukumar Swaminathan  * The contents of this file are subject to the terms of the
54d0e5007SSukumar Swaminathan  * Common Development and Distribution License (the "License").
64d0e5007SSukumar Swaminathan  * You may not use this file except in compliance with the License.
74d0e5007SSukumar Swaminathan  *
84d0e5007SSukumar Swaminathan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94d0e5007SSukumar Swaminathan  * or http://www.opensolaris.org/os/licensing.
104d0e5007SSukumar Swaminathan  * See the License for the specific language governing permissions
114d0e5007SSukumar Swaminathan  * and limitations under the License.
124d0e5007SSukumar Swaminathan  *
134d0e5007SSukumar Swaminathan  * When distributing Covered Code, include this CDDL HEADER in each
144d0e5007SSukumar Swaminathan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154d0e5007SSukumar Swaminathan  * If applicable, add the following below this CDDL HEADER, with the
164d0e5007SSukumar Swaminathan  * fields enclosed by brackets "[]" replaced with your own identifying
174d0e5007SSukumar Swaminathan  * information: Portions Copyright [yyyy] [name of copyright owner]
184d0e5007SSukumar Swaminathan  *
194d0e5007SSukumar Swaminathan  * CDDL HEADER END
204d0e5007SSukumar Swaminathan  */
214d0e5007SSukumar Swaminathan 
22*3abb112fSGarrett D'Amore /* Copyright © 2003-2011 Emulex. All rights reserved.  */
234d0e5007SSukumar Swaminathan 
244d0e5007SSukumar Swaminathan /*
254d0e5007SSukumar Swaminathan  * Source file containing the implementation of the Transmit
264d0e5007SSukumar Swaminathan  * Path
274d0e5007SSukumar Swaminathan  */
284d0e5007SSukumar Swaminathan 
294d0e5007SSukumar Swaminathan #include <oce_impl.h>
304d0e5007SSukumar Swaminathan 
314d0e5007SSukumar Swaminathan static void oce_free_wqed(struct oce_wq *wq,  oce_wqe_desc_t *wqed);
324d0e5007SSukumar Swaminathan static int oce_map_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed,
335b9d3151SSukumar Swaminathan     mblk_t *mp, uint32_t pkt_len);
344d0e5007SSukumar Swaminathan static int oce_bcopy_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp,
354d0e5007SSukumar Swaminathan     uint32_t pkt_len);
364d0e5007SSukumar Swaminathan static void oce_wqb_dtor(struct oce_wq *wq, oce_wq_bdesc_t *wqbd);
374d0e5007SSukumar Swaminathan static int oce_wqb_ctor(oce_wq_bdesc_t *wqbd, struct oce_wq *wq,
384d0e5007SSukumar Swaminathan     size_t size, int flags);
395b9d3151SSukumar Swaminathan static inline oce_wq_bdesc_t *oce_wqb_alloc(struct oce_wq *wq);
404d0e5007SSukumar Swaminathan static void oce_wqb_free(struct oce_wq *wq, oce_wq_bdesc_t *wqbd);
414d0e5007SSukumar Swaminathan 
425b9d3151SSukumar Swaminathan static void oce_wqmd_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd);
434d0e5007SSukumar Swaminathan static void oce_wqm_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd);
445b9d3151SSukumar Swaminathan static oce_wq_mdesc_t *oce_wqm_alloc(struct oce_wq *wq);
454d0e5007SSukumar Swaminathan static int oce_wqm_ctor(oce_wq_mdesc_t *wqmd, struct oce_wq *wq);
464d0e5007SSukumar Swaminathan static void oce_wqm_dtor(struct oce_wq *wq, oce_wq_mdesc_t *wqmd);
474d0e5007SSukumar Swaminathan static void oce_fill_ring_descs(struct oce_wq *wq, oce_wqe_desc_t *wqed);
484d0e5007SSukumar Swaminathan static void oce_remove_vtag(mblk_t *mp);
494d0e5007SSukumar Swaminathan static void oce_insert_vtag(mblk_t  *mp, uint16_t vlan_tag);
508d738d7dSSukumar Swaminathan static inline int oce_process_tx_compl(struct oce_wq *wq, boolean_t rearm);
518d738d7dSSukumar Swaminathan 
524d0e5007SSukumar Swaminathan 
534d0e5007SSukumar Swaminathan static ddi_dma_attr_t tx_map_dma_attr = {
545b9d3151SSukumar Swaminathan 	DMA_ATTR_V0,		/* version number */
554d0e5007SSukumar Swaminathan 	0x0000000000000000ull,	/* low address */
564d0e5007SSukumar Swaminathan 	0xFFFFFFFFFFFFFFFFull,	/* high address */
574d0e5007SSukumar Swaminathan 	0x0000000000010000ull,	/* dma counter max */
584d0e5007SSukumar Swaminathan 	OCE_TXMAP_ALIGN,	/* alignment */
598d738d7dSSukumar Swaminathan 	0x7FF,			/* burst sizes */
604d0e5007SSukumar Swaminathan 	0x00000001,		/* minimum transfer size */
614d0e5007SSukumar Swaminathan 	0x00000000FFFFFFFFull,	/* maximum transfer size */
624d0e5007SSukumar Swaminathan 	0xFFFFFFFFFFFFFFFFull,	/* maximum segment size */
634d0e5007SSukumar Swaminathan 	OCE_MAX_TXDMA_COOKIES,	/* scatter/gather list length */
644d0e5007SSukumar Swaminathan 	0x00000001,		/* granularity */
655b9d3151SSukumar Swaminathan 	DDI_DMA_FLAGERR		/* dma_attr_flags */
665b9d3151SSukumar Swaminathan };
675b9d3151SSukumar Swaminathan 
685b9d3151SSukumar Swaminathan 
695b9d3151SSukumar Swaminathan ddi_dma_attr_t oce_tx_dma_buf_attr = {
705b9d3151SSukumar Swaminathan 	DMA_ATTR_V0,		/* version number */
715b9d3151SSukumar Swaminathan 	0x0000000000000000ull,	/* low address */
725b9d3151SSukumar Swaminathan 	0xFFFFFFFFFFFFFFFFull,	/* high address */
735b9d3151SSukumar Swaminathan 	0x00000000FFFFFFFFull,	/* dma counter max */
745b9d3151SSukumar Swaminathan 	OCE_DMA_ALIGNMENT,	/* alignment */
755b9d3151SSukumar Swaminathan 	0x000007FF,		/* burst sizes */
765b9d3151SSukumar Swaminathan 	0x00000001,		/* minimum transfer size */
775b9d3151SSukumar Swaminathan 	0x00000000FFFFFFFFull,	/* maximum transfer size */
785b9d3151SSukumar Swaminathan 	0xFFFFFFFFFFFFFFFFull,	/* maximum segment size */
795b9d3151SSukumar Swaminathan 	1,			/* scatter/gather list length */
805b9d3151SSukumar Swaminathan 	0x00000001,		/* granularity */
815b9d3151SSukumar Swaminathan 	DDI_DMA_FLAGERR		/* dma_attr_flags */
824d0e5007SSukumar Swaminathan };
834d0e5007SSukumar Swaminathan 
844d0e5007SSukumar Swaminathan /*
854d0e5007SSukumar Swaminathan  * WQ map handle destructor
864d0e5007SSukumar Swaminathan  *
874d0e5007SSukumar Swaminathan  * wq - Pointer to WQ structure
884d0e5007SSukumar Swaminathan  * wqmd - pointer to WQE mapping handle descriptor
894d0e5007SSukumar Swaminathan  *
904d0e5007SSukumar Swaminathan  * return none
914d0e5007SSukumar Swaminathan  */
924d0e5007SSukumar Swaminathan 
934d0e5007SSukumar Swaminathan static void
oce_wqm_dtor(struct oce_wq * wq,oce_wq_mdesc_t * wqmd)944d0e5007SSukumar Swaminathan oce_wqm_dtor(struct oce_wq *wq, oce_wq_mdesc_t *wqmd)
954d0e5007SSukumar Swaminathan {
964d0e5007SSukumar Swaminathan 	_NOTE(ARGUNUSED(wq));
974d0e5007SSukumar Swaminathan 	/* Free the DMA handle */
984d0e5007SSukumar Swaminathan 	if (wqmd->dma_handle != NULL)
994d0e5007SSukumar Swaminathan 		(void) ddi_dma_free_handle(&(wqmd->dma_handle));
1004d0e5007SSukumar Swaminathan 	wqmd->dma_handle = NULL;
1014d0e5007SSukumar Swaminathan } /* oce_wqm_dtor */
1024d0e5007SSukumar Swaminathan 
1034d0e5007SSukumar Swaminathan /*
1044d0e5007SSukumar Swaminathan  * WQ map handles contructor
1054d0e5007SSukumar Swaminathan  *
1064d0e5007SSukumar Swaminathan  * wqmd - pointer to WQE mapping handle descriptor
1074d0e5007SSukumar Swaminathan  * wq - Pointer to WQ structure
1084d0e5007SSukumar Swaminathan  *
1094d0e5007SSukumar Swaminathan  * return DDI_SUCCESS=>success, DDI_FAILURE=>error
1104d0e5007SSukumar Swaminathan  */
1114d0e5007SSukumar Swaminathan static int
oce_wqm_ctor(oce_wq_mdesc_t * wqmd,struct oce_wq * wq)1124d0e5007SSukumar Swaminathan oce_wqm_ctor(oce_wq_mdesc_t *wqmd, struct oce_wq *wq)
1134d0e5007SSukumar Swaminathan {
1144d0e5007SSukumar Swaminathan 	struct oce_dev *dev;
1154d0e5007SSukumar Swaminathan 	int ret;
1164d0e5007SSukumar Swaminathan 
1174d0e5007SSukumar Swaminathan 	dev = wq->parent;
1184d0e5007SSukumar Swaminathan 	/* Allocate DMA handle */
1194d0e5007SSukumar Swaminathan 	ret = ddi_dma_alloc_handle(dev->dip, &tx_map_dma_attr,
12012d61dabSSukumar Swaminathan 	    DDI_DMA_DONTWAIT, NULL, &wqmd->dma_handle);
1214d0e5007SSukumar Swaminathan 
1224d0e5007SSukumar Swaminathan 	return (ret);
1234d0e5007SSukumar Swaminathan } /* oce_wqm_ctor */
1244d0e5007SSukumar Swaminathan 
1254d0e5007SSukumar Swaminathan /*
1264d0e5007SSukumar Swaminathan  * function to create WQ mapping handles cache
1274d0e5007SSukumar Swaminathan  *
1284d0e5007SSukumar Swaminathan  * wq - pointer to WQ structure
1294d0e5007SSukumar Swaminathan  *
1304d0e5007SSukumar Swaminathan  * return DDI_SUCCESS=>success, DDI_FAILURE=>error
1314d0e5007SSukumar Swaminathan  */
1324d0e5007SSukumar Swaminathan int
oce_wqm_cache_create(struct oce_wq * wq)1334d0e5007SSukumar Swaminathan oce_wqm_cache_create(struct oce_wq *wq)
1344d0e5007SSukumar Swaminathan {
1354d0e5007SSukumar Swaminathan 	struct oce_dev *dev = wq->parent;
1364d0e5007SSukumar Swaminathan 	int size;
1374d0e5007SSukumar Swaminathan 	int cnt;
1384d0e5007SSukumar Swaminathan 	int ret;
1394d0e5007SSukumar Swaminathan 
1404d0e5007SSukumar Swaminathan 	size = wq->cfg.nhdl * sizeof (oce_wq_mdesc_t);
14112d61dabSSukumar Swaminathan 	wq->wq_mdesc_array = kmem_zalloc(size, KM_NOSLEEP);
14212d61dabSSukumar Swaminathan 	if (wq->wq_mdesc_array == NULL) {
14312d61dabSSukumar Swaminathan 		return (DDI_FAILURE);
14412d61dabSSukumar Swaminathan 	}
1454d0e5007SSukumar Swaminathan 
1464d0e5007SSukumar Swaminathan 	/* Create the free buffer list */
1474d0e5007SSukumar Swaminathan 	OCE_LIST_CREATE(&wq->wq_mdesc_list, DDI_INTR_PRI(dev->intr_pri));
1484d0e5007SSukumar Swaminathan 
1494d0e5007SSukumar Swaminathan 	for (cnt = 0; cnt < wq->cfg.nhdl; cnt++) {
1504d0e5007SSukumar Swaminathan 		ret = oce_wqm_ctor(&wq->wq_mdesc_array[cnt], wq);
1514d0e5007SSukumar Swaminathan 		if (ret != DDI_SUCCESS) {
1524d0e5007SSukumar Swaminathan 			goto wqm_fail;
1534d0e5007SSukumar Swaminathan 		}
1544d0e5007SSukumar Swaminathan 		OCE_LIST_INSERT_TAIL(&wq->wq_mdesc_list,
1554d0e5007SSukumar Swaminathan 		    &wq->wq_mdesc_array[cnt]);
1564d0e5007SSukumar Swaminathan 	}
1574d0e5007SSukumar Swaminathan 	return (DDI_SUCCESS);
1584d0e5007SSukumar Swaminathan 
1594d0e5007SSukumar Swaminathan wqm_fail:
1604d0e5007SSukumar Swaminathan 	oce_wqm_cache_destroy(wq);
1614d0e5007SSukumar Swaminathan 	return (DDI_FAILURE);
1624d0e5007SSukumar Swaminathan }
1634d0e5007SSukumar Swaminathan 
1644d0e5007SSukumar Swaminathan /*
1654d0e5007SSukumar Swaminathan  * function to destroy WQ mapping handles cache
1664d0e5007SSukumar Swaminathan  *
1674d0e5007SSukumar Swaminathan  * wq - pointer to WQ structure
1684d0e5007SSukumar Swaminathan  *
1694d0e5007SSukumar Swaminathan  * return none
1704d0e5007SSukumar Swaminathan  */
1714d0e5007SSukumar Swaminathan void
oce_wqm_cache_destroy(struct oce_wq * wq)1724d0e5007SSukumar Swaminathan oce_wqm_cache_destroy(struct oce_wq *wq)
1734d0e5007SSukumar Swaminathan {
1744d0e5007SSukumar Swaminathan 	oce_wq_mdesc_t *wqmd;
1754d0e5007SSukumar Swaminathan 
1764d0e5007SSukumar Swaminathan 	while ((wqmd = OCE_LIST_REM_HEAD(&wq->wq_mdesc_list)) != NULL) {
1774d0e5007SSukumar Swaminathan 		oce_wqm_dtor(wq, wqmd);
1784d0e5007SSukumar Swaminathan 	}
1794d0e5007SSukumar Swaminathan 
1804d0e5007SSukumar Swaminathan 	kmem_free(wq->wq_mdesc_array,
1814d0e5007SSukumar Swaminathan 	    wq->cfg.nhdl * sizeof (oce_wq_mdesc_t));
1824d0e5007SSukumar Swaminathan 
1834d0e5007SSukumar Swaminathan 	OCE_LIST_DESTROY(&wq->wq_mdesc_list);
1844d0e5007SSukumar Swaminathan }
1854d0e5007SSukumar Swaminathan 
1864d0e5007SSukumar Swaminathan /*
1874d0e5007SSukumar Swaminathan  * function to create  WQ buffer cache
1884d0e5007SSukumar Swaminathan  *
1894d0e5007SSukumar Swaminathan  * wq - pointer to WQ structure
1904d0e5007SSukumar Swaminathan  * buf_size - size of the buffer
1914d0e5007SSukumar Swaminathan  *
1924d0e5007SSukumar Swaminathan  * return DDI_SUCCESS=>success, DDI_FAILURE=>error
1934d0e5007SSukumar Swaminathan  */
1944d0e5007SSukumar Swaminathan int
oce_wqb_cache_create(struct oce_wq * wq,size_t buf_size)1954d0e5007SSukumar Swaminathan oce_wqb_cache_create(struct oce_wq *wq, size_t buf_size)
1964d0e5007SSukumar Swaminathan {
1974d0e5007SSukumar Swaminathan 	struct oce_dev *dev = wq->parent;
1984d0e5007SSukumar Swaminathan 	int size;
1994d0e5007SSukumar Swaminathan 	int cnt;
2004d0e5007SSukumar Swaminathan 	int ret;
2014d0e5007SSukumar Swaminathan 
2024d0e5007SSukumar Swaminathan 	size = wq->cfg.nbufs * sizeof (oce_wq_bdesc_t);
20312d61dabSSukumar Swaminathan 	wq->wq_bdesc_array = kmem_zalloc(size, KM_NOSLEEP);
20412d61dabSSukumar Swaminathan 	if (wq->wq_bdesc_array == NULL) {
20512d61dabSSukumar Swaminathan 		return (DDI_FAILURE);
20612d61dabSSukumar Swaminathan 	}
2074d0e5007SSukumar Swaminathan 
2084d0e5007SSukumar Swaminathan 	/* Create the free buffer list */
2094d0e5007SSukumar Swaminathan 	OCE_LIST_CREATE(&wq->wq_buf_list, DDI_INTR_PRI(dev->intr_pri));
2104d0e5007SSukumar Swaminathan 
2114d0e5007SSukumar Swaminathan 	for (cnt = 0; cnt <  wq->cfg.nbufs; cnt++) {
2124d0e5007SSukumar Swaminathan 		ret = oce_wqb_ctor(&wq->wq_bdesc_array[cnt],
2134d0e5007SSukumar Swaminathan 		    wq, buf_size, DDI_DMA_STREAMING);
2144d0e5007SSukumar Swaminathan 		if (ret != DDI_SUCCESS) {
2154d0e5007SSukumar Swaminathan 			goto wqb_fail;
2164d0e5007SSukumar Swaminathan 		}
2174d0e5007SSukumar Swaminathan 		OCE_LIST_INSERT_TAIL(&wq->wq_buf_list,
2184d0e5007SSukumar Swaminathan 		    &wq->wq_bdesc_array[cnt]);
2194d0e5007SSukumar Swaminathan 	}
2204d0e5007SSukumar Swaminathan 	return (DDI_SUCCESS);
2214d0e5007SSukumar Swaminathan 
2224d0e5007SSukumar Swaminathan wqb_fail:
2234d0e5007SSukumar Swaminathan 	oce_wqb_cache_destroy(wq);
2244d0e5007SSukumar Swaminathan 	return (DDI_FAILURE);
2254d0e5007SSukumar Swaminathan }
2264d0e5007SSukumar Swaminathan 
2274d0e5007SSukumar Swaminathan /*
2284d0e5007SSukumar Swaminathan  * function to destroy WQ buffer cache
2294d0e5007SSukumar Swaminathan  *
2304d0e5007SSukumar Swaminathan  * wq - pointer to WQ structure
2314d0e5007SSukumar Swaminathan  *
2324d0e5007SSukumar Swaminathan  * return none
2334d0e5007SSukumar Swaminathan  */
2344d0e5007SSukumar Swaminathan void
oce_wqb_cache_destroy(struct oce_wq * wq)2354d0e5007SSukumar Swaminathan oce_wqb_cache_destroy(struct oce_wq *wq)
2364d0e5007SSukumar Swaminathan {
2374d0e5007SSukumar Swaminathan 	oce_wq_bdesc_t *wqbd;
2384d0e5007SSukumar Swaminathan 	while ((wqbd = OCE_LIST_REM_HEAD(&wq->wq_buf_list)) != NULL) {
2394d0e5007SSukumar Swaminathan 		oce_wqb_dtor(wq, wqbd);
2404d0e5007SSukumar Swaminathan 	}
2414d0e5007SSukumar Swaminathan 	kmem_free(wq->wq_bdesc_array,
2424d0e5007SSukumar Swaminathan 	    wq->cfg.nbufs * sizeof (oce_wq_bdesc_t));
2434d0e5007SSukumar Swaminathan 	OCE_LIST_DESTROY(&wq->wq_buf_list);
2444d0e5007SSukumar Swaminathan }
2454d0e5007SSukumar Swaminathan 
2464d0e5007SSukumar Swaminathan /*
2474d0e5007SSukumar Swaminathan  * WQ buffer constructor
2484d0e5007SSukumar Swaminathan  *
2494d0e5007SSukumar Swaminathan  * wqbd - pointer to WQ buffer descriptor
2504d0e5007SSukumar Swaminathan  * wq - pointer to WQ structure
2514d0e5007SSukumar Swaminathan  * size - size of the buffer
2524d0e5007SSukumar Swaminathan  * flags - KM_SLEEP or KM_NOSLEEP
2534d0e5007SSukumar Swaminathan  *
2544d0e5007SSukumar Swaminathan  * return DDI_SUCCESS=>success, DDI_FAILURE=>error
2554d0e5007SSukumar Swaminathan  */
2564d0e5007SSukumar Swaminathan static int
oce_wqb_ctor(oce_wq_bdesc_t * wqbd,struct oce_wq * wq,size_t size,int flags)2574d0e5007SSukumar Swaminathan oce_wqb_ctor(oce_wq_bdesc_t *wqbd, struct oce_wq *wq, size_t size, int flags)
2584d0e5007SSukumar Swaminathan {
2594d0e5007SSukumar Swaminathan 	struct oce_dev *dev;
2604d0e5007SSukumar Swaminathan 	dev = wq->parent;
2615b9d3151SSukumar Swaminathan 
2625b9d3151SSukumar Swaminathan 	wqbd->wqb = oce_alloc_dma_buffer(dev, size, &oce_tx_dma_buf_attr,
2635b9d3151SSukumar Swaminathan 	    flags);
2644d0e5007SSukumar Swaminathan 	if (wqbd->wqb == NULL) {
2654d0e5007SSukumar Swaminathan 		return (DDI_FAILURE);
2664d0e5007SSukumar Swaminathan 	}
2674d0e5007SSukumar Swaminathan 	wqbd->frag_addr.dw.addr_lo = ADDR_LO(wqbd->wqb->addr);
2684d0e5007SSukumar Swaminathan 	wqbd->frag_addr.dw.addr_hi = ADDR_HI(wqbd->wqb->addr);
2694d0e5007SSukumar Swaminathan 	return (DDI_SUCCESS);
2704d0e5007SSukumar Swaminathan }
2714d0e5007SSukumar Swaminathan 
2724d0e5007SSukumar Swaminathan /*
2734d0e5007SSukumar Swaminathan  * WQ buffer destructor
2744d0e5007SSukumar Swaminathan  *
2754d0e5007SSukumar Swaminathan  * wq - pointer to WQ structure
2764d0e5007SSukumar Swaminathan  * wqbd - pointer to WQ buffer descriptor
2774d0e5007SSukumar Swaminathan  *
2784d0e5007SSukumar Swaminathan  * return none
2794d0e5007SSukumar Swaminathan  */
2804d0e5007SSukumar Swaminathan static void
oce_wqb_dtor(struct oce_wq * wq,oce_wq_bdesc_t * wqbd)2814d0e5007SSukumar Swaminathan oce_wqb_dtor(struct oce_wq *wq, oce_wq_bdesc_t *wqbd)
2824d0e5007SSukumar Swaminathan {
2834d0e5007SSukumar Swaminathan 	oce_free_dma_buffer(wq->parent, wqbd->wqb);
2844d0e5007SSukumar Swaminathan }
2854d0e5007SSukumar Swaminathan 
2864d0e5007SSukumar Swaminathan /*
2874d0e5007SSukumar Swaminathan  * function to alloc   WQE buffer descriptor
2884d0e5007SSukumar Swaminathan  *
2894d0e5007SSukumar Swaminathan  * wq - pointer to WQ structure
2904d0e5007SSukumar Swaminathan  *
2914d0e5007SSukumar Swaminathan  * return pointer to WQE buffer descriptor
2924d0e5007SSukumar Swaminathan  */
2934d0e5007SSukumar Swaminathan static inline oce_wq_bdesc_t *
oce_wqb_alloc(struct oce_wq * wq)2944d0e5007SSukumar Swaminathan oce_wqb_alloc(struct oce_wq *wq)
2954d0e5007SSukumar Swaminathan {
2965b9d3151SSukumar Swaminathan 	return (OCE_LIST_REM_HEAD(&wq->wq_buf_list));
2974d0e5007SSukumar Swaminathan }
2984d0e5007SSukumar Swaminathan 
2994d0e5007SSukumar Swaminathan /*
3004d0e5007SSukumar Swaminathan  * function to free   WQE buffer descriptor
3014d0e5007SSukumar Swaminathan  *
3024d0e5007SSukumar Swaminathan  * wq - pointer to WQ structure
3034d0e5007SSukumar Swaminathan  * wqbd - pointer to WQ buffer descriptor
3044d0e5007SSukumar Swaminathan  *
3054d0e5007SSukumar Swaminathan  * return none
3064d0e5007SSukumar Swaminathan  */
3074d0e5007SSukumar Swaminathan static inline void
oce_wqb_free(struct oce_wq * wq,oce_wq_bdesc_t * wqbd)3084d0e5007SSukumar Swaminathan oce_wqb_free(struct oce_wq *wq, oce_wq_bdesc_t *wqbd)
3094d0e5007SSukumar Swaminathan {
3104d0e5007SSukumar Swaminathan 	OCE_LIST_INSERT_TAIL(&wq->wq_buf_list, wqbd);
3114d0e5007SSukumar Swaminathan } /* oce_wqb_free */
3124d0e5007SSukumar Swaminathan 
3134d0e5007SSukumar Swaminathan /*
3144d0e5007SSukumar Swaminathan  * function to allocate   WQE mapping descriptor
3154d0e5007SSukumar Swaminathan  *
3164d0e5007SSukumar Swaminathan  * wq - pointer to WQ structure
3174d0e5007SSukumar Swaminathan  *
3184d0e5007SSukumar Swaminathan  * return pointer to WQE mapping descriptor
3194d0e5007SSukumar Swaminathan  */
3204d0e5007SSukumar Swaminathan static inline oce_wq_mdesc_t *
oce_wqm_alloc(struct oce_wq * wq)3214d0e5007SSukumar Swaminathan oce_wqm_alloc(struct oce_wq *wq)
3224d0e5007SSukumar Swaminathan {
3235b9d3151SSukumar Swaminathan 	return (OCE_LIST_REM_HEAD(&wq->wq_mdesc_list));
3244d0e5007SSukumar Swaminathan } /* oce_wqm_alloc */
3254d0e5007SSukumar Swaminathan 
3264d0e5007SSukumar Swaminathan /*
3274d0e5007SSukumar Swaminathan  * function to insert	WQE mapping descriptor to the list
3284d0e5007SSukumar Swaminathan  *
3294d0e5007SSukumar Swaminathan  * wq - pointer to WQ structure
3304d0e5007SSukumar Swaminathan  * wqmd - Pointer to WQ mapping descriptor
3314d0e5007SSukumar Swaminathan  *
3324d0e5007SSukumar Swaminathan  * return none
3334d0e5007SSukumar Swaminathan  */
3344d0e5007SSukumar Swaminathan static inline void
oce_wqm_free(struct oce_wq * wq,oce_wq_mdesc_t * wqmd)3354d0e5007SSukumar Swaminathan oce_wqm_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd)
3364d0e5007SSukumar Swaminathan {
3374d0e5007SSukumar Swaminathan 	OCE_LIST_INSERT_TAIL(&wq->wq_mdesc_list, wqmd);
3384d0e5007SSukumar Swaminathan }
3394d0e5007SSukumar Swaminathan 
3404d0e5007SSukumar Swaminathan /*
3414d0e5007SSukumar Swaminathan  * function to free  WQE mapping descriptor
3424d0e5007SSukumar Swaminathan  *
3434d0e5007SSukumar Swaminathan  * wq - pointer to WQ structure
3444d0e5007SSukumar Swaminathan  * wqmd - Pointer to WQ mapping descriptor
3454d0e5007SSukumar Swaminathan  *
3464d0e5007SSukumar Swaminathan  * return none
3474d0e5007SSukumar Swaminathan  */
3484d0e5007SSukumar Swaminathan static void
oce_wqmd_free(struct oce_wq * wq,oce_wq_mdesc_t * wqmd)3495b9d3151SSukumar Swaminathan oce_wqmd_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd)
3504d0e5007SSukumar Swaminathan {
3515b9d3151SSukumar Swaminathan 	if (wqmd == NULL) {
3524d0e5007SSukumar Swaminathan 		return;
3534d0e5007SSukumar Swaminathan 	}
3545b9d3151SSukumar Swaminathan 	(void) ddi_dma_unbind_handle(wqmd->dma_handle);
3555b9d3151SSukumar Swaminathan 	oce_wqm_free(wq, wqmd);
3564d0e5007SSukumar Swaminathan }
3574d0e5007SSukumar Swaminathan 
3584d0e5007SSukumar Swaminathan /*
3594d0e5007SSukumar Swaminathan  * WQED kmem_cache constructor
3604d0e5007SSukumar Swaminathan  *
3614d0e5007SSukumar Swaminathan  * buf - pointer to WQE descriptor
3624d0e5007SSukumar Swaminathan  *
3634d0e5007SSukumar Swaminathan  * return DDI_SUCCESS
3644d0e5007SSukumar Swaminathan  */
3654d0e5007SSukumar Swaminathan int
oce_wqe_desc_ctor(void * buf,void * arg,int kmflags)3664d0e5007SSukumar Swaminathan oce_wqe_desc_ctor(void *buf, void *arg, int kmflags)
3674d0e5007SSukumar Swaminathan {
3685b9d3151SSukumar Swaminathan 	_NOTE(ARGUNUSED(buf));
3694d0e5007SSukumar Swaminathan 	_NOTE(ARGUNUSED(arg));
3704d0e5007SSukumar Swaminathan 	_NOTE(ARGUNUSED(kmflags));
3714d0e5007SSukumar Swaminathan 
3724d0e5007SSukumar Swaminathan 	return (DDI_SUCCESS);
3734d0e5007SSukumar Swaminathan }
3744d0e5007SSukumar Swaminathan 
3754d0e5007SSukumar Swaminathan /*
3764d0e5007SSukumar Swaminathan  * WQED kmem_cache destructor
3774d0e5007SSukumar Swaminathan  *
3784d0e5007SSukumar Swaminathan  * buf - pointer to WQE descriptor
3794d0e5007SSukumar Swaminathan  *
3804d0e5007SSukumar Swaminathan  * return none
3814d0e5007SSukumar Swaminathan  */
3824d0e5007SSukumar Swaminathan void
oce_wqe_desc_dtor(void * buf,void * arg)3834d0e5007SSukumar Swaminathan oce_wqe_desc_dtor(void *buf, void *arg)
3844d0e5007SSukumar Swaminathan {
3854d0e5007SSukumar Swaminathan 	_NOTE(ARGUNUSED(buf));
3864d0e5007SSukumar Swaminathan 	_NOTE(ARGUNUSED(arg));
3874d0e5007SSukumar Swaminathan }
3884d0e5007SSukumar Swaminathan 
3894d0e5007SSukumar Swaminathan /*
3904d0e5007SSukumar Swaminathan  * function to choose a WQ given a mblk depending on priority, flowID etc.
3914d0e5007SSukumar Swaminathan  *
3924d0e5007SSukumar Swaminathan  * dev - software handle to device
3935b9d3151SSukumar Swaminathan  * mp - the mblk to send
3944d0e5007SSukumar Swaminathan  *
3954d0e5007SSukumar Swaminathan  * return pointer to the WQ selected
3964d0e5007SSukumar Swaminathan  */
3975b9d3151SSukumar Swaminathan static uint8_t oce_tx_hash_policy = 0x4;
3984d0e5007SSukumar Swaminathan struct oce_wq *
oce_get_wq(struct oce_dev * dev,mblk_t * mp)3995b9d3151SSukumar Swaminathan oce_get_wq(struct oce_dev *dev, mblk_t *mp)
4004d0e5007SSukumar Swaminathan {
4015b9d3151SSukumar Swaminathan 	struct oce_wq *wq;
4025b9d3151SSukumar Swaminathan 	int qidx = 0;
4035b9d3151SSukumar Swaminathan 	if (dev->nwqs > 1) {
4045b9d3151SSukumar Swaminathan 		qidx = mac_pkt_hash(DL_ETHER, mp, oce_tx_hash_policy, B_TRUE);
4055b9d3151SSukumar Swaminathan 		qidx = qidx % dev->nwqs;
4065b9d3151SSukumar Swaminathan 
4075b9d3151SSukumar Swaminathan 	} else {
4085b9d3151SSukumar Swaminathan 		qidx = 0;
4095b9d3151SSukumar Swaminathan 	}
4105b9d3151SSukumar Swaminathan 	wq = dev->wq[qidx];
4114d0e5007SSukumar Swaminathan 	/* for the time being hardcode */
4125b9d3151SSukumar Swaminathan 	return (wq);
4134d0e5007SSukumar Swaminathan } /* oce_get_wq */
4144d0e5007SSukumar Swaminathan 
4154d0e5007SSukumar Swaminathan /*
4164d0e5007SSukumar Swaminathan  * function to populate the single WQE
4174d0e5007SSukumar Swaminathan  *
4184d0e5007SSukumar Swaminathan  * wq - pointer to wq
4194d0e5007SSukumar Swaminathan  * wqed - pointer to WQ entry  descriptor
4204d0e5007SSukumar Swaminathan  *
4214d0e5007SSukumar Swaminathan  * return none
4224d0e5007SSukumar Swaminathan  */
4234d0e5007SSukumar Swaminathan #pragma inline(oce_fill_ring_descs)
4244d0e5007SSukumar Swaminathan static void
oce_fill_ring_descs(struct oce_wq * wq,oce_wqe_desc_t * wqed)4254d0e5007SSukumar Swaminathan oce_fill_ring_descs(struct oce_wq *wq, oce_wqe_desc_t *wqed)
4264d0e5007SSukumar Swaminathan {
4274d0e5007SSukumar Swaminathan 
4284d0e5007SSukumar Swaminathan 	struct oce_nic_frag_wqe *wqe;
4294d0e5007SSukumar Swaminathan 	int i;
4304d0e5007SSukumar Swaminathan 	/* Copy the precreate WQE descs to the ring desc */
4314d0e5007SSukumar Swaminathan 	for (i = 0; i < wqed->wqe_cnt; i++) {
4324d0e5007SSukumar Swaminathan 		wqe = RING_GET_PRODUCER_ITEM_VA(wq->ring,
4334d0e5007SSukumar Swaminathan 		    struct oce_nic_frag_wqe);
4344d0e5007SSukumar Swaminathan 
4354d0e5007SSukumar Swaminathan 		bcopy(&wqed->frag[i], wqe, NIC_WQE_SIZE);
4364d0e5007SSukumar Swaminathan 		RING_PUT(wq->ring, 1);
4374d0e5007SSukumar Swaminathan 	}
4384d0e5007SSukumar Swaminathan } /* oce_fill_ring_descs */
4394d0e5007SSukumar Swaminathan 
4404d0e5007SSukumar Swaminathan /*
4414d0e5007SSukumar Swaminathan  * function to copy the packet to preallocated Tx buffer
4424d0e5007SSukumar Swaminathan  *
4434d0e5007SSukumar Swaminathan  * wq - pointer to WQ
4444d0e5007SSukumar Swaminathan  * wqed - Pointer to WQE descriptor
4454d0e5007SSukumar Swaminathan  * mp - Pointer to packet chain
4464d0e5007SSukumar Swaminathan  * pktlen - Size of the packet
4474d0e5007SSukumar Swaminathan  *
4484d0e5007SSukumar Swaminathan  * return 0=>success, error code otherwise
4494d0e5007SSukumar Swaminathan  */
4504d0e5007SSukumar Swaminathan static int
oce_bcopy_wqe(struct oce_wq * wq,oce_wqe_desc_t * wqed,mblk_t * mp,uint32_t pkt_len)4514d0e5007SSukumar Swaminathan oce_bcopy_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp,
4524d0e5007SSukumar Swaminathan     uint32_t pkt_len)
4534d0e5007SSukumar Swaminathan {
4544d0e5007SSukumar Swaminathan 	oce_wq_bdesc_t *wqbd;
4554d0e5007SSukumar Swaminathan 	caddr_t buf_va;
4564d0e5007SSukumar Swaminathan 	struct oce_dev *dev = wq->parent;
4575b9d3151SSukumar Swaminathan 	int len = 0;
4584d0e5007SSukumar Swaminathan 
4594d0e5007SSukumar Swaminathan 	wqbd = oce_wqb_alloc(wq);
4604d0e5007SSukumar Swaminathan 	if (wqbd == NULL) {
4614d0e5007SSukumar Swaminathan 		atomic_inc_32(&dev->tx_noxmtbuf);
4624d0e5007SSukumar Swaminathan 		oce_log(dev, CE_WARN, MOD_TX, "%s",
4634d0e5007SSukumar Swaminathan 		    "wqb pool empty");
4644d0e5007SSukumar Swaminathan 		return (ENOMEM);
4654d0e5007SSukumar Swaminathan 	}
4664d0e5007SSukumar Swaminathan 
4674d0e5007SSukumar Swaminathan 	/* create a fragment wqe for the packet */
4685b9d3151SSukumar Swaminathan 	wqed->frag[wqed->frag_idx].u0.s.frag_pa_hi = wqbd->frag_addr.dw.addr_hi;
4695b9d3151SSukumar Swaminathan 	wqed->frag[wqed->frag_idx].u0.s.frag_pa_lo = wqbd->frag_addr.dw.addr_lo;
4704d0e5007SSukumar Swaminathan 	buf_va = DBUF_VA(wqbd->wqb);
4714d0e5007SSukumar Swaminathan 
4724d0e5007SSukumar Swaminathan 	/* copy pkt into buffer */
4735b9d3151SSukumar Swaminathan 	for (len = 0; mp != NULL && len < pkt_len; mp = mp->b_cont) {
4744d0e5007SSukumar Swaminathan 		bcopy(mp->b_rptr, buf_va, MBLKL(mp));
4754d0e5007SSukumar Swaminathan 		buf_va += MBLKL(mp);
4765b9d3151SSukumar Swaminathan 		len += MBLKL(mp);
4774d0e5007SSukumar Swaminathan 	}
4784d0e5007SSukumar Swaminathan 
4794d0e5007SSukumar Swaminathan 	(void) ddi_dma_sync(DBUF_DHDL(wqbd->wqb), 0, pkt_len,
4804d0e5007SSukumar Swaminathan 	    DDI_DMA_SYNC_FORDEV);
4814d0e5007SSukumar Swaminathan 
4824d0e5007SSukumar Swaminathan 	if (oce_fm_check_dma_handle(dev, DBUF_DHDL(wqbd->wqb))) {
4834d0e5007SSukumar Swaminathan 		ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
4844d0e5007SSukumar Swaminathan 		/* Free the buffer */
4854d0e5007SSukumar Swaminathan 		oce_wqb_free(wq, wqbd);
4864d0e5007SSukumar Swaminathan 		return (EIO);
4874d0e5007SSukumar Swaminathan 	}
4885b9d3151SSukumar Swaminathan 	wqed->frag[wqed->frag_idx].u0.s.frag_len   =  pkt_len;
4895b9d3151SSukumar Swaminathan 	wqed->hdesc[wqed->nhdl].hdl = (void *)(wqbd);
4905b9d3151SSukumar Swaminathan 	wqed->hdesc[wqed->nhdl].type = COPY_WQE;
4915b9d3151SSukumar Swaminathan 	wqed->frag_cnt++;
4925b9d3151SSukumar Swaminathan 	wqed->frag_idx++;
4935b9d3151SSukumar Swaminathan 	wqed->nhdl++;
4944d0e5007SSukumar Swaminathan 	return (0);
4954d0e5007SSukumar Swaminathan } /* oce_bcopy_wqe */
4964d0e5007SSukumar Swaminathan 
4974d0e5007SSukumar Swaminathan /*
4984d0e5007SSukumar Swaminathan  * function to copy the packet or dma map on the fly depending on size
4994d0e5007SSukumar Swaminathan  *
5004d0e5007SSukumar Swaminathan  * wq - pointer to WQ
5014d0e5007SSukumar Swaminathan  * wqed - Pointer to WQE descriptor
5024d0e5007SSukumar Swaminathan  * mp - Pointer to packet chain
5034d0e5007SSukumar Swaminathan  *
5044d0e5007SSukumar Swaminathan  * return DDI_SUCCESS=>success, DDI_FAILURE=>error
5054d0e5007SSukumar Swaminathan  */
5064d0e5007SSukumar Swaminathan static  int
oce_map_wqe(struct oce_wq * wq,oce_wqe_desc_t * wqed,mblk_t * mp,uint32_t pkt_len)5075b9d3151SSukumar Swaminathan oce_map_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp,
5085b9d3151SSukumar Swaminathan     uint32_t pkt_len)
5094d0e5007SSukumar Swaminathan {
5104d0e5007SSukumar Swaminathan 	ddi_dma_cookie_t cookie;
5114d0e5007SSukumar Swaminathan 	oce_wq_mdesc_t *wqmd;
5124d0e5007SSukumar Swaminathan 	uint32_t ncookies;
5134d0e5007SSukumar Swaminathan 	int ret;
5144d0e5007SSukumar Swaminathan 	struct oce_dev *dev = wq->parent;
5154d0e5007SSukumar Swaminathan 
5165b9d3151SSukumar Swaminathan 	wqmd = oce_wqm_alloc(wq);
5175b9d3151SSukumar Swaminathan 	if (wqmd == NULL) {
5185b9d3151SSukumar Swaminathan 		oce_log(dev, CE_WARN, MOD_TX, "%s",
5195b9d3151SSukumar Swaminathan 		    "wqm pool empty");
5205b9d3151SSukumar Swaminathan 		return (ENOMEM);
5215b9d3151SSukumar Swaminathan 	}
5224d0e5007SSukumar Swaminathan 
5235b9d3151SSukumar Swaminathan 	ret = ddi_dma_addr_bind_handle(wqmd->dma_handle,
5245b9d3151SSukumar Swaminathan 	    (struct as *)0, (caddr_t)mp->b_rptr,
5255b9d3151SSukumar Swaminathan 	    pkt_len, DDI_DMA_WRITE | DDI_DMA_STREAMING,
5265b9d3151SSukumar Swaminathan 	    DDI_DMA_DONTWAIT, NULL, &cookie, &ncookies);
5275b9d3151SSukumar Swaminathan 	if (ret != DDI_DMA_MAPPED) {
5285b9d3151SSukumar Swaminathan 		oce_log(dev, CE_WARN, MOD_TX, "MAP FAILED %d",
5295b9d3151SSukumar Swaminathan 		    ret);
5305b9d3151SSukumar Swaminathan 		/* free the last one */
5315b9d3151SSukumar Swaminathan 		oce_wqm_free(wq, wqmd);
5325b9d3151SSukumar Swaminathan 		return (ENOMEM);
5335b9d3151SSukumar Swaminathan 	}
5345b9d3151SSukumar Swaminathan 	do {
5355b9d3151SSukumar Swaminathan 		wqed->frag[wqed->frag_idx].u0.s.frag_pa_hi =
5365b9d3151SSukumar Swaminathan 		    ADDR_HI(cookie.dmac_laddress);
5375b9d3151SSukumar Swaminathan 		wqed->frag[wqed->frag_idx].u0.s.frag_pa_lo =
5385b9d3151SSukumar Swaminathan 		    ADDR_LO(cookie.dmac_laddress);
5395b9d3151SSukumar Swaminathan 		wqed->frag[wqed->frag_idx].u0.s.frag_len =
5405b9d3151SSukumar Swaminathan 		    (uint32_t)cookie.dmac_size;
5415b9d3151SSukumar Swaminathan 		wqed->frag_cnt++;
5425b9d3151SSukumar Swaminathan 		wqed->frag_idx++;
5435b9d3151SSukumar Swaminathan 		if (--ncookies > 0)
5445b9d3151SSukumar Swaminathan 			ddi_dma_nextcookie(wqmd->dma_handle,
5455b9d3151SSukumar Swaminathan 			    &cookie);
5464d0e5007SSukumar Swaminathan 			else break;
5475b9d3151SSukumar Swaminathan 	} while (ncookies > 0);
54812d61dabSSukumar Swaminathan 
5495b9d3151SSukumar Swaminathan 	wqed->hdesc[wqed->nhdl].hdl = (void *)wqmd;
5505b9d3151SSukumar Swaminathan 	wqed->hdesc[wqed->nhdl].type = MAPPED_WQE;
5515b9d3151SSukumar Swaminathan 	wqed->nhdl++;
5524d0e5007SSukumar Swaminathan 	return (0);
5534d0e5007SSukumar Swaminathan } /* oce_map_wqe */
5544d0e5007SSukumar Swaminathan 
5558d738d7dSSukumar Swaminathan static inline int
oce_process_tx_compl(struct oce_wq * wq,boolean_t rearm)5568d738d7dSSukumar Swaminathan oce_process_tx_compl(struct oce_wq *wq, boolean_t rearm)
5574d0e5007SSukumar Swaminathan {
5584d0e5007SSukumar Swaminathan 	struct oce_nic_tx_cqe *cqe;
5594d0e5007SSukumar Swaminathan 	uint16_t num_cqe = 0;
5604d0e5007SSukumar Swaminathan 	struct oce_cq *cq;
5614d0e5007SSukumar Swaminathan 	oce_wqe_desc_t *wqed;
5624d0e5007SSukumar Swaminathan 	int wqe_freed = 0;
5638d738d7dSSukumar Swaminathan 	struct oce_dev *dev;
5644d0e5007SSukumar Swaminathan 
5654d0e5007SSukumar Swaminathan 	cq  = wq->cq;
5664d0e5007SSukumar Swaminathan 	dev = wq->parent;
56712d61dabSSukumar Swaminathan 	(void) ddi_dma_sync(cq->ring->dbuf->dma_handle, 0, 0,
56812d61dabSSukumar Swaminathan 	    DDI_DMA_SYNC_FORKERNEL);
56912d61dabSSukumar Swaminathan 
5708d738d7dSSukumar Swaminathan 	mutex_enter(&wq->txc_lock);
5714d0e5007SSukumar Swaminathan 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
5724d0e5007SSukumar Swaminathan 	while (WQ_CQE_VALID(cqe)) {
5734d0e5007SSukumar Swaminathan 
5744d0e5007SSukumar Swaminathan 		DW_SWAP(u32ptr(cqe), sizeof (struct oce_nic_tx_cqe));
5754d0e5007SSukumar Swaminathan 
5764d0e5007SSukumar Swaminathan 		/* update stats */
5774d0e5007SSukumar Swaminathan 		if (cqe->u0.s.status != 0) {
5784d0e5007SSukumar Swaminathan 			atomic_inc_32(&dev->tx_errors);
5794d0e5007SSukumar Swaminathan 		}
5804d0e5007SSukumar Swaminathan 
5814d0e5007SSukumar Swaminathan 		/* complete the WQEs */
5824d0e5007SSukumar Swaminathan 		wqed = OCE_LIST_REM_HEAD(&wq->wqe_desc_list);
5834d0e5007SSukumar Swaminathan 
5844d0e5007SSukumar Swaminathan 		wqe_freed = wqed->wqe_cnt;
5854d0e5007SSukumar Swaminathan 		oce_free_wqed(wq, wqed);
5864d0e5007SSukumar Swaminathan 		RING_GET(wq->ring, wqe_freed);
5874d0e5007SSukumar Swaminathan 		atomic_add_32(&wq->wq_free, wqe_freed);
5884d0e5007SSukumar Swaminathan 		/* clear the valid bit and progress cqe */
5894d0e5007SSukumar Swaminathan 		WQ_CQE_INVALIDATE(cqe);
5904d0e5007SSukumar Swaminathan 		RING_GET(cq->ring, 1);
5914d0e5007SSukumar Swaminathan 		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring,
5924d0e5007SSukumar Swaminathan 		    struct oce_nic_tx_cqe);
5934d0e5007SSukumar Swaminathan 		num_cqe++;
5944d0e5007SSukumar Swaminathan 	} /* for all valid CQE */
5958d738d7dSSukumar Swaminathan 	mutex_exit(&wq->txc_lock);
5968d738d7dSSukumar Swaminathan 	if (num_cqe)
5978d738d7dSSukumar Swaminathan 		oce_arm_cq(wq->parent, cq->cq_id, num_cqe, rearm);
5988d738d7dSSukumar Swaminathan 	return (num_cqe);
5998d738d7dSSukumar Swaminathan } /* oce_process_tx_completion */
6004d0e5007SSukumar Swaminathan 
6018d738d7dSSukumar Swaminathan /*
6028d738d7dSSukumar Swaminathan  * function to drain a TxCQ and process its CQEs
6038d738d7dSSukumar Swaminathan  *
6048d738d7dSSukumar Swaminathan  * dev - software handle to the device
6058d738d7dSSukumar Swaminathan  * cq - pointer to the cq to drain
6068d738d7dSSukumar Swaminathan  *
6078d738d7dSSukumar Swaminathan  * return the number of CQEs processed
6088d738d7dSSukumar Swaminathan  */
6098d738d7dSSukumar Swaminathan uint16_t
oce_drain_wq_cq(void * arg)6108d738d7dSSukumar Swaminathan oce_drain_wq_cq(void *arg)
6118d738d7dSSukumar Swaminathan {
6128d738d7dSSukumar Swaminathan 	uint16_t num_cqe = 0;
6138d738d7dSSukumar Swaminathan 	struct oce_dev *dev;
6148d738d7dSSukumar Swaminathan 	struct oce_wq *wq;
6154d0e5007SSukumar Swaminathan 
6168d738d7dSSukumar Swaminathan 	wq = (struct oce_wq *)arg;
6178d738d7dSSukumar Swaminathan 	dev = wq->parent;
6184d0e5007SSukumar Swaminathan 
6198d738d7dSSukumar Swaminathan 	/* do while we do not reach a cqe that is not valid */
6208d738d7dSSukumar Swaminathan 	num_cqe = oce_process_tx_compl(wq, B_FALSE);
6214d0e5007SSukumar Swaminathan 
6224d0e5007SSukumar Swaminathan 	/* check if we need to restart Tx */
6234d0e5007SSukumar Swaminathan 	if (wq->resched && num_cqe) {
6244d0e5007SSukumar Swaminathan 		wq->resched = B_FALSE;
6254d0e5007SSukumar Swaminathan 		mac_tx_update(dev->mac_handle);
6268d738d7dSSukumar Swaminathan 	}
6274d0e5007SSukumar Swaminathan 
6284d0e5007SSukumar Swaminathan 	return (num_cqe);
6294d0e5007SSukumar Swaminathan } /* oce_process_wq_cqe */
6304d0e5007SSukumar Swaminathan 
6314d0e5007SSukumar Swaminathan /*
6324d0e5007SSukumar Swaminathan  * function to insert vtag to packet
6334d0e5007SSukumar Swaminathan  *
6344d0e5007SSukumar Swaminathan  * mp - mblk pointer
6354d0e5007SSukumar Swaminathan  * vlan_tag - tag to be inserted
6364d0e5007SSukumar Swaminathan  *
6374d0e5007SSukumar Swaminathan  * return none
6384d0e5007SSukumar Swaminathan  */
6394d0e5007SSukumar Swaminathan static inline void
oce_insert_vtag(mblk_t * mp,uint16_t vlan_tag)6404d0e5007SSukumar Swaminathan oce_insert_vtag(mblk_t *mp, uint16_t vlan_tag)
6414d0e5007SSukumar Swaminathan {
6424d0e5007SSukumar Swaminathan 	struct ether_vlan_header  *evh;
643*3abb112fSGarrett D'Amore 	(void) memmove(mp->b_rptr - VTAG_SIZE,
6444d0e5007SSukumar Swaminathan 	    mp->b_rptr, 2 * ETHERADDRL);
645*3abb112fSGarrett D'Amore 	mp->b_rptr -= VTAG_SIZE;
6464d0e5007SSukumar Swaminathan 	evh = (struct ether_vlan_header *)(void *)mp->b_rptr;
6474d0e5007SSukumar Swaminathan 	evh->ether_tpid = htons(VLAN_TPID);
6484d0e5007SSukumar Swaminathan 	evh->ether_tci = htons(vlan_tag);
6494d0e5007SSukumar Swaminathan }
6504d0e5007SSukumar Swaminathan 
6514d0e5007SSukumar Swaminathan /*
6524d0e5007SSukumar Swaminathan  * function to strip  vtag from packet
6534d0e5007SSukumar Swaminathan  *
6544d0e5007SSukumar Swaminathan  * mp - mblk pointer
6554d0e5007SSukumar Swaminathan  *
6564d0e5007SSukumar Swaminathan  * return none
6574d0e5007SSukumar Swaminathan  */
6584d0e5007SSukumar Swaminathan 
6594d0e5007SSukumar Swaminathan static inline void
oce_remove_vtag(mblk_t * mp)6604d0e5007SSukumar Swaminathan oce_remove_vtag(mblk_t *mp)
6614d0e5007SSukumar Swaminathan {
662*3abb112fSGarrett D'Amore 	(void) memmove(mp->b_rptr + VTAG_SIZE, mp->b_rptr,
6634d0e5007SSukumar Swaminathan 	    ETHERADDRL * 2);
664*3abb112fSGarrett D'Amore 	mp->b_rptr += VTAG_SIZE;
6654d0e5007SSukumar Swaminathan }
6664d0e5007SSukumar Swaminathan 
6674d0e5007SSukumar Swaminathan /*
6684d0e5007SSukumar Swaminathan  * function to xmit  Single packet over the wire
6694d0e5007SSukumar Swaminathan  *
6704d0e5007SSukumar Swaminathan  * wq - pointer to WQ
6714d0e5007SSukumar Swaminathan  * mp - Pointer to packet chain
6724d0e5007SSukumar Swaminathan  *
6734d0e5007SSukumar Swaminathan  * return pointer to the packet
6744d0e5007SSukumar Swaminathan  */
6754d0e5007SSukumar Swaminathan mblk_t *
oce_send_packet(struct oce_wq * wq,mblk_t * mp)6764d0e5007SSukumar Swaminathan oce_send_packet(struct oce_wq *wq, mblk_t *mp)
6774d0e5007SSukumar Swaminathan {
6784d0e5007SSukumar Swaminathan 	struct oce_nic_hdr_wqe *wqeh;
6794d0e5007SSukumar Swaminathan 	struct oce_dev *dev;
6804d0e5007SSukumar Swaminathan 	struct ether_header *eh;
6814d0e5007SSukumar Swaminathan 	struct ether_vlan_header *evh;
6824d0e5007SSukumar Swaminathan 	int32_t num_wqes;
6834d0e5007SSukumar Swaminathan 	uint16_t etype;
6844d0e5007SSukumar Swaminathan 	uint32_t ip_offset;
6858d738d7dSSukumar Swaminathan 	uint32_t csum_flags = 0;
6864d0e5007SSukumar Swaminathan 	boolean_t use_copy = B_FALSE;
6874d0e5007SSukumar Swaminathan 	boolean_t tagged   = B_FALSE;
6884d0e5007SSukumar Swaminathan 	uint16_t  vlan_tag;
6894d0e5007SSukumar Swaminathan 	uint32_t  reg_value = 0;
6904d0e5007SSukumar Swaminathan 	oce_wqe_desc_t *wqed = NULL;
6914d0e5007SSukumar Swaminathan 	mblk_t *nmp = NULL;
6924d0e5007SSukumar Swaminathan 	mblk_t *tmp = NULL;
6934d0e5007SSukumar Swaminathan 	uint32_t pkt_len = 0;
6944d0e5007SSukumar Swaminathan 	int num_mblks = 0;
6954d0e5007SSukumar Swaminathan 	int ret = 0;
6968d738d7dSSukumar Swaminathan 	uint32_t mss = 0;
6975b9d3151SSukumar Swaminathan 	uint32_t flags = 0;
6985b9d3151SSukumar Swaminathan 	int len = 0;
6994d0e5007SSukumar Swaminathan 
7004d0e5007SSukumar Swaminathan 	/* retrieve the adap priv struct ptr */
7014d0e5007SSukumar Swaminathan 	dev = wq->parent;
7024d0e5007SSukumar Swaminathan 
7038d738d7dSSukumar Swaminathan 	/* check if we have enough free slots */
7045b9d3151SSukumar Swaminathan 	if (wq->wq_free < dev->tx_reclaim_threshold) {
7058d738d7dSSukumar Swaminathan 		(void) oce_process_tx_compl(wq, B_FALSE);
7068d738d7dSSukumar Swaminathan 	}
7078d738d7dSSukumar Swaminathan 	if (wq->wq_free < OCE_MAX_TX_HDL) {
7088d738d7dSSukumar Swaminathan 		return (mp);
7098d738d7dSSukumar Swaminathan 	}
7108d738d7dSSukumar Swaminathan 
7114d0e5007SSukumar Swaminathan 	/* check if we should copy */
7124d0e5007SSukumar Swaminathan 	for (tmp = mp; tmp != NULL; tmp = tmp->b_cont) {
7134d0e5007SSukumar Swaminathan 		pkt_len += MBLKL(tmp);
7144d0e5007SSukumar Swaminathan 		num_mblks++;
7154d0e5007SSukumar Swaminathan 	}
7168d738d7dSSukumar Swaminathan 
7175b9d3151SSukumar Swaminathan 	if (pkt_len == 0 || num_mblks == 0) {
7185b9d3151SSukumar Swaminathan 		freemsg(mp);
7195b9d3151SSukumar Swaminathan 		return (NULL);
7205b9d3151SSukumar Swaminathan 	}
7215b9d3151SSukumar Swaminathan 
7225b9d3151SSukumar Swaminathan 	/* retrieve LSO information */
7230dc2366fSVenugopal Iyer 	mac_lso_get(mp, &mss, &flags);
7248d738d7dSSukumar Swaminathan 
7254d0e5007SSukumar Swaminathan 	/* get the offload flags */
7260dc2366fSVenugopal Iyer 	mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &csum_flags);
7274d0e5007SSukumar Swaminathan 
7285b9d3151SSukumar Swaminathan 	/* restrict the mapped segment to wat we support */
7295b9d3151SSukumar Swaminathan 	if (num_mblks  > OCE_MAX_TX_HDL) {
7305b9d3151SSukumar Swaminathan 		nmp = msgpullup(mp, -1);
7315b9d3151SSukumar Swaminathan 		if (nmp == NULL) {
7325b9d3151SSukumar Swaminathan 			atomic_inc_32(&wq->pkt_drops);
7334d0e5007SSukumar Swaminathan 			freemsg(mp);
7345b9d3151SSukumar Swaminathan 			return (NULL);
7354d0e5007SSukumar Swaminathan 		}
7365b9d3151SSukumar Swaminathan 		/* Reset it to new collapsed mp */
7375b9d3151SSukumar Swaminathan 		freemsg(mp);
7385b9d3151SSukumar Swaminathan 		mp = nmp;
7394d0e5007SSukumar Swaminathan 	}
7404d0e5007SSukumar Swaminathan 
7414d0e5007SSukumar Swaminathan 	/* Get the packet descriptor for Tx */
7424d0e5007SSukumar Swaminathan 	wqed = kmem_cache_alloc(wq->wqed_cache, KM_NOSLEEP);
7434d0e5007SSukumar Swaminathan 	if (wqed == NULL) {
7444d0e5007SSukumar Swaminathan 		atomic_inc_32(&wq->pkt_drops);
7454d0e5007SSukumar Swaminathan 		freemsg(mp);
7464d0e5007SSukumar Swaminathan 		return (NULL);
7474d0e5007SSukumar Swaminathan 	}
7484d0e5007SSukumar Swaminathan 	eh = (struct ether_header *)(void *)mp->b_rptr;
7494d0e5007SSukumar Swaminathan 	if (ntohs(eh->ether_type) == VLAN_TPID) {
7504d0e5007SSukumar Swaminathan 		evh = (struct ether_vlan_header *)(void *)mp->b_rptr;
7514d0e5007SSukumar Swaminathan 		tagged = B_TRUE;
7524d0e5007SSukumar Swaminathan 		etype = ntohs(evh->ether_type);
7534d0e5007SSukumar Swaminathan 		ip_offset = sizeof (struct ether_vlan_header);
754*3abb112fSGarrett D'Amore 		pkt_len -= VTAG_SIZE;
7554d0e5007SSukumar Swaminathan 		vlan_tag = ntohs(evh->ether_tci);
7564d0e5007SSukumar Swaminathan 		oce_remove_vtag(mp);
7574d0e5007SSukumar Swaminathan 	} else {
7584d0e5007SSukumar Swaminathan 		etype = ntohs(eh->ether_type);
7594d0e5007SSukumar Swaminathan 		ip_offset = sizeof (struct ether_header);
7604d0e5007SSukumar Swaminathan 	}
7614d0e5007SSukumar Swaminathan 
7624d0e5007SSukumar Swaminathan 	/* Save the WQ pointer */
7634d0e5007SSukumar Swaminathan 	wqed->wq = wq;
7645b9d3151SSukumar Swaminathan 	wqed->frag_idx = 1; /* index zero is always header */
7655b9d3151SSukumar Swaminathan 	wqed->frag_cnt = 0;
7665b9d3151SSukumar Swaminathan 	wqed->nhdl = 0;
7675b9d3151SSukumar Swaminathan 	wqed->mp = NULL;
7685b9d3151SSukumar Swaminathan 	OCE_LIST_LINK_INIT(&wqed->link);
7695b9d3151SSukumar Swaminathan 
7705b9d3151SSukumar Swaminathan 	/* If entire packet is less than the copy limit  just do copy */
7715b9d3151SSukumar Swaminathan 	if (pkt_len < dev->tx_bcopy_limit) {
7725b9d3151SSukumar Swaminathan 		use_copy = B_TRUE;
7734d0e5007SSukumar Swaminathan 		ret = oce_bcopy_wqe(wq, wqed, mp, pkt_len);
7744d0e5007SSukumar Swaminathan 	} else {
7755b9d3151SSukumar Swaminathan 		/* copy or dma map the individual fragments */
7765b9d3151SSukumar Swaminathan 		for (nmp = mp; nmp != NULL; nmp = nmp->b_cont) {
7775b9d3151SSukumar Swaminathan 			len = MBLKL(nmp);
7785b9d3151SSukumar Swaminathan 			if (len == 0) {
7795b9d3151SSukumar Swaminathan 				continue;
7805b9d3151SSukumar Swaminathan 			}
7815b9d3151SSukumar Swaminathan 			if (len < dev->tx_bcopy_limit) {
7825b9d3151SSukumar Swaminathan 				ret = oce_bcopy_wqe(wq, wqed, nmp, len);
7835b9d3151SSukumar Swaminathan 			} else {
7845b9d3151SSukumar Swaminathan 				ret = oce_map_wqe(wq, wqed, nmp, len);
7855b9d3151SSukumar Swaminathan 			}
7865b9d3151SSukumar Swaminathan 			if (ret != 0)
7875b9d3151SSukumar Swaminathan 				break;
7885b9d3151SSukumar Swaminathan 		}
7894d0e5007SSukumar Swaminathan 	}
7904d0e5007SSukumar Swaminathan 
7914d0e5007SSukumar Swaminathan 	/*
7924d0e5007SSukumar Swaminathan 	 * Any failure other than insufficient Q entries
7934d0e5007SSukumar Swaminathan 	 * drop the packet
7944d0e5007SSukumar Swaminathan 	 */
7954d0e5007SSukumar Swaminathan 	if (ret != 0) {
7965b9d3151SSukumar Swaminathan 		oce_free_wqed(wq, wqed);
7974d0e5007SSukumar Swaminathan 		atomic_inc_32(&wq->pkt_drops);
7984d0e5007SSukumar Swaminathan 		freemsg(mp);
7994d0e5007SSukumar Swaminathan 		return (NULL);
8004d0e5007SSukumar Swaminathan 	}
8014d0e5007SSukumar Swaminathan 
8024d0e5007SSukumar Swaminathan 	wqeh = (struct oce_nic_hdr_wqe *)&wqed->frag[0];
8035b9d3151SSukumar Swaminathan 	bzero(wqeh, sizeof (struct oce_nic_hdr_wqe));
8044d0e5007SSukumar Swaminathan 
8054d0e5007SSukumar Swaminathan 	/* fill rest of wqe header fields based on packet */
8068d738d7dSSukumar Swaminathan 	if (flags & HW_LSO) {
8074d0e5007SSukumar Swaminathan 		wqeh->u0.s.lso = B_TRUE;
8088d738d7dSSukumar Swaminathan 		wqeh->u0.s.lso_mss = mss;
8094d0e5007SSukumar Swaminathan 	}
8104d0e5007SSukumar Swaminathan 	if (csum_flags & HCK_FULLCKSUM) {
8114d0e5007SSukumar Swaminathan 		uint8_t *proto;
8124d0e5007SSukumar Swaminathan 		if (etype == ETHERTYPE_IP) {
8134d0e5007SSukumar Swaminathan 			proto = (uint8_t *)(void *)
8144d0e5007SSukumar Swaminathan 			    (mp->b_rptr + ip_offset);
8154d0e5007SSukumar Swaminathan 			if (proto[9] == 6)
8164d0e5007SSukumar Swaminathan 				/* IPPROTO_TCP */
8174d0e5007SSukumar Swaminathan 				wqeh->u0.s.tcpcs = B_TRUE;
8184d0e5007SSukumar Swaminathan 			else if (proto[9] == 17)
8194d0e5007SSukumar Swaminathan 				/* IPPROTO_UDP */
8204d0e5007SSukumar Swaminathan 				wqeh->u0.s.udpcs = B_TRUE;
8214d0e5007SSukumar Swaminathan 		}
8224d0e5007SSukumar Swaminathan 	}
8234d0e5007SSukumar Swaminathan 
8244d0e5007SSukumar Swaminathan 	if (csum_flags & HCK_IPV4_HDRCKSUM)
8254d0e5007SSukumar Swaminathan 		wqeh->u0.s.ipcs = B_TRUE;
8264d0e5007SSukumar Swaminathan 	if (tagged) {
8274d0e5007SSukumar Swaminathan 		wqeh->u0.s.vlan = B_TRUE;
8284d0e5007SSukumar Swaminathan 		wqeh->u0.s.vlan_tag = vlan_tag;
8294d0e5007SSukumar Swaminathan 	}
8304d0e5007SSukumar Swaminathan 
8314d0e5007SSukumar Swaminathan 	wqeh->u0.s.complete = B_TRUE;
8324d0e5007SSukumar Swaminathan 	wqeh->u0.s.event = B_TRUE;
8334d0e5007SSukumar Swaminathan 	wqeh->u0.s.crc = B_TRUE;
8344d0e5007SSukumar Swaminathan 	wqeh->u0.s.total_length = pkt_len;
8354d0e5007SSukumar Swaminathan 
8365b9d3151SSukumar Swaminathan 	num_wqes = wqed->frag_cnt + 1;
8374d0e5007SSukumar Swaminathan 
8384d0e5007SSukumar Swaminathan 	/* h/w expects even no. of WQEs */
8395b9d3151SSukumar Swaminathan 	if (num_wqes & 0x1) {
8405b9d3151SSukumar Swaminathan 		bzero(&wqed->frag[num_wqes], sizeof (struct oce_nic_frag_wqe));
8414d0e5007SSukumar Swaminathan 		num_wqes++;
8425b9d3151SSukumar Swaminathan 	}
8434d0e5007SSukumar Swaminathan 	wqed->wqe_cnt = (uint16_t)num_wqes;
8444d0e5007SSukumar Swaminathan 	wqeh->u0.s.num_wqe = num_wqes;
8454d0e5007SSukumar Swaminathan 	DW_SWAP(u32ptr(&wqed->frag[0]), (wqed->wqe_cnt * NIC_WQE_SIZE));
8464d0e5007SSukumar Swaminathan 
8478d738d7dSSukumar Swaminathan 	mutex_enter(&wq->tx_lock);
8484d0e5007SSukumar Swaminathan 	if (num_wqes > wq->wq_free) {
8494d0e5007SSukumar Swaminathan 		atomic_inc_32(&wq->tx_deferd);
8508d738d7dSSukumar Swaminathan 		mutex_exit(&wq->tx_lock);
8514d0e5007SSukumar Swaminathan 		goto wqe_fail;
8524d0e5007SSukumar Swaminathan 	}
8534d0e5007SSukumar Swaminathan 	atomic_add_32(&wq->wq_free, -num_wqes);
8544d0e5007SSukumar Swaminathan 
8554d0e5007SSukumar Swaminathan 	/* fill the wq for adapter */
8564d0e5007SSukumar Swaminathan 	oce_fill_ring_descs(wq, wqed);
8574d0e5007SSukumar Swaminathan 
858*3abb112fSGarrett D'Amore 	/* Set the mp pointer in the wqe descriptor */
859*3abb112fSGarrett D'Amore 	if (use_copy == B_FALSE) {
860*3abb112fSGarrett D'Amore 		wqed->mp = mp;
861*3abb112fSGarrett D'Amore 	}
8624d0e5007SSukumar Swaminathan 	/* Add the packet desc to list to be retrieved during cmpl */
8634d0e5007SSukumar Swaminathan 	OCE_LIST_INSERT_TAIL(&wq->wqe_desc_list,  wqed);
86412d61dabSSukumar Swaminathan 	(void) ddi_dma_sync(wq->ring->dbuf->dma_handle, 0, 0,
86512d61dabSSukumar Swaminathan 	    DDI_DMA_SYNC_FORDEV);
8664d0e5007SSukumar Swaminathan 
8674d0e5007SSukumar Swaminathan 	/* ring tx doorbell */
8684d0e5007SSukumar Swaminathan 	reg_value = (num_wqes << 16) | wq->wq_id;
8694d0e5007SSukumar Swaminathan 	/* Ring the door bell  */
8704d0e5007SSukumar Swaminathan 	OCE_DB_WRITE32(dev, PD_TXULP_DB, reg_value);
8715b9d3151SSukumar Swaminathan 	mutex_exit(&wq->tx_lock);
87212d61dabSSukumar Swaminathan 	if (oce_fm_check_acc_handle(dev, dev->db_handle) != DDI_FM_OK) {
87312d61dabSSukumar Swaminathan 		ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
87412d61dabSSukumar Swaminathan 	}
8754d0e5007SSukumar Swaminathan 
8764d0e5007SSukumar Swaminathan 	/* free mp if copied or packet chain collapsed */
8774d0e5007SSukumar Swaminathan 	if (use_copy == B_TRUE) {
8784d0e5007SSukumar Swaminathan 		freemsg(mp);
879*3abb112fSGarrett D'Amore 	}
8804d0e5007SSukumar Swaminathan 	return (NULL);
8814d0e5007SSukumar Swaminathan 
8824d0e5007SSukumar Swaminathan wqe_fail:
8834d0e5007SSukumar Swaminathan 
8844d0e5007SSukumar Swaminathan 	if (tagged) {
8854d0e5007SSukumar Swaminathan 		oce_insert_vtag(mp, vlan_tag);
8864d0e5007SSukumar Swaminathan 	}
8874d0e5007SSukumar Swaminathan 	oce_free_wqed(wq, wqed);
8884d0e5007SSukumar Swaminathan 	return (mp);
8894d0e5007SSukumar Swaminathan } /* oce_send_packet */
8904d0e5007SSukumar Swaminathan 
8914d0e5007SSukumar Swaminathan /*
8924d0e5007SSukumar Swaminathan  * function to free the WQE descriptor
8934d0e5007SSukumar Swaminathan  *
8944d0e5007SSukumar Swaminathan  * wq - pointer to WQ
8954d0e5007SSukumar Swaminathan  * wqed - Pointer to WQE descriptor
8964d0e5007SSukumar Swaminathan  *
8974d0e5007SSukumar Swaminathan  * return none
8984d0e5007SSukumar Swaminathan  */
8994d0e5007SSukumar Swaminathan #pragma inline(oce_free_wqed)
9004d0e5007SSukumar Swaminathan static void
oce_free_wqed(struct oce_wq * wq,oce_wqe_desc_t * wqed)9014d0e5007SSukumar Swaminathan oce_free_wqed(struct oce_wq *wq, oce_wqe_desc_t *wqed)
9024d0e5007SSukumar Swaminathan {
9035b9d3151SSukumar Swaminathan 	int i = 0;
9044d0e5007SSukumar Swaminathan 	if (wqed == NULL) {
9054d0e5007SSukumar Swaminathan 		return;
9064d0e5007SSukumar Swaminathan 	}
9074d0e5007SSukumar Swaminathan 
9085b9d3151SSukumar Swaminathan 	for (i = 0; i < wqed->nhdl; i++) {
9095b9d3151SSukumar Swaminathan 		if (wqed->hdesc[i].type == COPY_WQE) {
9105b9d3151SSukumar Swaminathan 		oce_wqb_free(wq, wqed->hdesc[i].hdl);
9115b9d3151SSukumar Swaminathan 		} else 	if (wqed->hdesc[i].type == MAPPED_WQE) {
9125b9d3151SSukumar Swaminathan 			oce_wqmd_free(wq, wqed->hdesc[i].hdl);
9135b9d3151SSukumar Swaminathan 		}
9145b9d3151SSukumar Swaminathan 	}
9154d0e5007SSukumar Swaminathan 	if (wqed->mp)
9164d0e5007SSukumar Swaminathan 		freemsg(wqed->mp);
9174d0e5007SSukumar Swaminathan 	kmem_cache_free(wq->wqed_cache, wqed);
9184d0e5007SSukumar Swaminathan } /* oce_free_wqed */
9194d0e5007SSukumar Swaminathan 
9204d0e5007SSukumar Swaminathan /*
9214d0e5007SSukumar Swaminathan  * function to start the WQ
9224d0e5007SSukumar Swaminathan  *
9234d0e5007SSukumar Swaminathan  * wq - pointer to WQ
9244d0e5007SSukumar Swaminathan  *
9254d0e5007SSukumar Swaminathan  * return DDI_SUCCESS
9264d0e5007SSukumar Swaminathan  */
9274d0e5007SSukumar Swaminathan 
9284d0e5007SSukumar Swaminathan int
oce_start_wq(struct oce_wq * wq)9294d0e5007SSukumar Swaminathan oce_start_wq(struct oce_wq *wq)
9304d0e5007SSukumar Swaminathan {
9318d738d7dSSukumar Swaminathan 	_NOTE(ARGUNUSED(wq));
9324d0e5007SSukumar Swaminathan 	return (DDI_SUCCESS);
9334d0e5007SSukumar Swaminathan } /* oce_start_wq */
9344d0e5007SSukumar Swaminathan 
9354d0e5007SSukumar Swaminathan /*
9364d0e5007SSukumar Swaminathan  * function to stop  the WQ
9374d0e5007SSukumar Swaminathan  *
9384d0e5007SSukumar Swaminathan  * wq - pointer to WQ
9394d0e5007SSukumar Swaminathan  *
9404d0e5007SSukumar Swaminathan  * return none
9414d0e5007SSukumar Swaminathan  */
9424d0e5007SSukumar Swaminathan void
oce_clean_wq(struct oce_wq * wq)9438d738d7dSSukumar Swaminathan oce_clean_wq(struct oce_wq *wq)
9444d0e5007SSukumar Swaminathan {
9454d0e5007SSukumar Swaminathan 	oce_wqe_desc_t *wqed;
9468d738d7dSSukumar Swaminathan 	int ti;
9474d0e5007SSukumar Swaminathan 
9484d0e5007SSukumar Swaminathan 	/* Wait for already posted Tx to complete */
9498d738d7dSSukumar Swaminathan 
9508d738d7dSSukumar Swaminathan 	for (ti = 0; ti < DEFAULT_DRAIN_TIME; ti++) {
9518d738d7dSSukumar Swaminathan 		(void) oce_process_tx_compl(wq, B_FALSE);
9528d738d7dSSukumar Swaminathan 		OCE_MSDELAY(1);
9534d0e5007SSukumar Swaminathan 	}
9544d0e5007SSukumar Swaminathan 
9554d0e5007SSukumar Swaminathan 	/* Free the remaining descriptors */
9564d0e5007SSukumar Swaminathan 	while ((wqed = OCE_LIST_REM_HEAD(&wq->wqe_desc_list)) != NULL) {
9574d0e5007SSukumar Swaminathan 		atomic_add_32(&wq->wq_free, wqed->wqe_cnt);
9584d0e5007SSukumar Swaminathan 		oce_free_wqed(wq, wqed);
9594d0e5007SSukumar Swaminathan 	}
9604d0e5007SSukumar Swaminathan 	oce_drain_eq(wq->cq->eq);
9614d0e5007SSukumar Swaminathan } /* oce_stop_wq */
9624d0e5007SSukumar Swaminathan 
9634d0e5007SSukumar Swaminathan /*
9644d0e5007SSukumar Swaminathan  * function to set the tx mapping handle fma attr
9654d0e5007SSukumar Swaminathan  *
9664d0e5007SSukumar Swaminathan  * fm_caps - capability flags
9674d0e5007SSukumar Swaminathan  *
9684d0e5007SSukumar Swaminathan  * return none
9694d0e5007SSukumar Swaminathan  */
9704d0e5007SSukumar Swaminathan 
9714d0e5007SSukumar Swaminathan void
oce_set_tx_map_dma_fma_flags(int fm_caps)9724d0e5007SSukumar Swaminathan oce_set_tx_map_dma_fma_flags(int fm_caps)
9734d0e5007SSukumar Swaminathan {
9744d0e5007SSukumar Swaminathan 	if (fm_caps == DDI_FM_NOT_CAPABLE) {
9754d0e5007SSukumar Swaminathan 		return;
9764d0e5007SSukumar Swaminathan 	}
9774d0e5007SSukumar Swaminathan 
9784d0e5007SSukumar Swaminathan 	if (DDI_FM_DMA_ERR_CAP(fm_caps)) {
9794d0e5007SSukumar Swaminathan 		tx_map_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
9804d0e5007SSukumar Swaminathan 	} else {
9814d0e5007SSukumar Swaminathan 		tx_map_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
9824d0e5007SSukumar Swaminathan 	}
9834d0e5007SSukumar Swaminathan } /* oce_set_tx_map_dma_fma_flags */
984