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 Driver buffer management
264d0e5007SSukumar Swaminathan  * and related helper functions
274d0e5007SSukumar Swaminathan  */
284d0e5007SSukumar Swaminathan #include <oce_impl.h>
294d0e5007SSukumar Swaminathan 
304d0e5007SSukumar Swaminathan static ddi_dma_attr_t oce_dma_buf_attr = {
314d0e5007SSukumar Swaminathan 	DMA_ATTR_V0,		/* version number */
324d0e5007SSukumar Swaminathan 	0x0000000000000000ull,	/* low address */
334d0e5007SSukumar Swaminathan 	0xFFFFFFFFFFFFFFFFull,	/* high address */
344d0e5007SSukumar Swaminathan 	0x00000000FFFFFFFFull,	/* dma counter max */
354d0e5007SSukumar Swaminathan 	OCE_DMA_ALIGNMENT,	/* alignment */
364d0e5007SSukumar Swaminathan 	0x00000FFF,		/* burst sizes */
374d0e5007SSukumar Swaminathan 	0x00000001,		/* minimum transfer size */
384d0e5007SSukumar Swaminathan 	0x00000000FFFFFFFFull,	/* maximum transfer size */
394d0e5007SSukumar Swaminathan 	0xFFFFFFFFFFFFFFFFull,	/* maximum segment size */
404d0e5007SSukumar Swaminathan 	1,			/* scatter/gather list length */
414d0e5007SSukumar Swaminathan 	0x00000001,		/* granularity */
424d0e5007SSukumar Swaminathan 	0			/* DMA flags */
434d0e5007SSukumar Swaminathan };
444d0e5007SSukumar Swaminathan 
454d0e5007SSukumar Swaminathan static ddi_device_acc_attr_t oce_dma_buf_accattr = {
464d0e5007SSukumar Swaminathan 	DDI_DEVICE_ATTR_V0,
474d0e5007SSukumar Swaminathan 	DDI_NEVERSWAP_ACC,
484d0e5007SSukumar Swaminathan 	DDI_STRICTORDER_ACC,
494d0e5007SSukumar Swaminathan };
504d0e5007SSukumar Swaminathan 
514d0e5007SSukumar Swaminathan 
524d0e5007SSukumar Swaminathan /*
534d0e5007SSukumar Swaminathan  * function to allocate a dma buffer for mapping memory va-pa
544d0e5007SSukumar Swaminathan  *
554d0e5007SSukumar Swaminathan  * dev - software handle to device
564d0e5007SSukumar Swaminathan  * size - size of the memory to map
574d0e5007SSukumar Swaminathan  * flags - DDI_DMA_CONSISTENT/DDI_DMA_STREAMING
584d0e5007SSukumar Swaminathan  *
594d0e5007SSukumar Swaminathan  * return pointer to a oce_dma_buf_t structure handling the map
604d0e5007SSukumar Swaminathan  *      NULL => failure
614d0e5007SSukumar Swaminathan  */
624d0e5007SSukumar Swaminathan oce_dma_buf_t *
oce_alloc_dma_buffer(struct oce_dev * dev,uint32_t size,ddi_dma_attr_t * dma_attr,uint32_t flags)634d0e5007SSukumar Swaminathan oce_alloc_dma_buffer(struct oce_dev *dev,
645b9d3151SSukumar Swaminathan     uint32_t size, ddi_dma_attr_t *dma_attr, uint32_t flags)
654d0e5007SSukumar Swaminathan {
664d0e5007SSukumar Swaminathan 	oce_dma_buf_t  *dbuf;
674d0e5007SSukumar Swaminathan 	ddi_dma_cookie_t cookie;
684d0e5007SSukumar Swaminathan 	uint32_t count;
694d0e5007SSukumar Swaminathan 	size_t actual_len;
704d0e5007SSukumar Swaminathan 	int ret = 0;
714d0e5007SSukumar Swaminathan 
724d0e5007SSukumar Swaminathan 	ASSERT(size > 0);
735b9d3151SSukumar Swaminathan 	/* if NULL use default */
745b9d3151SSukumar Swaminathan 	if (dma_attr == NULL) {
755b9d3151SSukumar Swaminathan 		dma_attr = &oce_dma_buf_attr;
765b9d3151SSukumar Swaminathan 	}
774d0e5007SSukumar Swaminathan 
788d738d7dSSukumar Swaminathan 	dbuf = kmem_zalloc(sizeof (oce_dma_buf_t), KM_NOSLEEP);
798d738d7dSSukumar Swaminathan 	if (dbuf == NULL) {
808d738d7dSSukumar Swaminathan 		return (NULL);
818d738d7dSSukumar Swaminathan 	}
824d0e5007SSukumar Swaminathan 
834d0e5007SSukumar Swaminathan 	/* allocate dma handle */
845b9d3151SSukumar Swaminathan 	ret = ddi_dma_alloc_handle(dev->dip, dma_attr,
858d738d7dSSukumar Swaminathan 	    DDI_DMA_DONTWAIT, NULL, &dbuf->dma_handle);
864d0e5007SSukumar Swaminathan 	if (ret != DDI_SUCCESS) {
874d0e5007SSukumar Swaminathan 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
884d0e5007SSukumar Swaminathan 		    "Failed to allocate DMA handle");
895b9d3151SSukumar Swaminathan 		goto handle_fail;
904d0e5007SSukumar Swaminathan 	}
914d0e5007SSukumar Swaminathan 	/* allocate the DMA-able memory */
924d0e5007SSukumar Swaminathan 	ret = ddi_dma_mem_alloc(dbuf->dma_handle, size, &oce_dma_buf_accattr,
938d738d7dSSukumar Swaminathan 	    flags, DDI_DMA_DONTWAIT, NULL, &dbuf->base,
944d0e5007SSukumar Swaminathan 	    &actual_len, &dbuf->acc_handle);
954d0e5007SSukumar Swaminathan 	if (ret != DDI_SUCCESS) {
964d0e5007SSukumar Swaminathan 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
974d0e5007SSukumar Swaminathan 		    "Failed to allocate DMA memory");
984d0e5007SSukumar Swaminathan 		goto alloc_fail;
994d0e5007SSukumar Swaminathan 	}
1004d0e5007SSukumar Swaminathan 
1014d0e5007SSukumar Swaminathan 	/* bind handle */
1024d0e5007SSukumar Swaminathan 	ret = ddi_dma_addr_bind_handle(dbuf->dma_handle,
1034d0e5007SSukumar Swaminathan 	    (struct as *)0, dbuf->base, actual_len,
1044d0e5007SSukumar Swaminathan 	    DDI_DMA_RDWR | flags,
1058d738d7dSSukumar Swaminathan 	    DDI_DMA_DONTWAIT, NULL, &cookie, &count);
1064d0e5007SSukumar Swaminathan 	if (ret != DDI_DMA_MAPPED) {
1074d0e5007SSukumar Swaminathan 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
1084d0e5007SSukumar Swaminathan 		    "Failed to bind dma handle");
1095b9d3151SSukumar Swaminathan 		goto bind_fail;
1104d0e5007SSukumar Swaminathan 	}
1114d0e5007SSukumar Swaminathan 	bzero(dbuf->base, actual_len);
1124d0e5007SSukumar Swaminathan 	dbuf->addr = cookie.dmac_laddress;
1134d0e5007SSukumar Swaminathan 	dbuf->size = actual_len;
1144d0e5007SSukumar Swaminathan 	/* usable length */
1154d0e5007SSukumar Swaminathan 	dbuf->len  = size;
1164d0e5007SSukumar Swaminathan 	dbuf->num_pages = OCE_NUM_PAGES(size);
1174d0e5007SSukumar Swaminathan 	return (dbuf);
1185b9d3151SSukumar Swaminathan 
1195b9d3151SSukumar Swaminathan bind_fail:
1205b9d3151SSukumar Swaminathan 	ddi_dma_mem_free(&dbuf->acc_handle);
1214d0e5007SSukumar Swaminathan alloc_fail:
1225b9d3151SSukumar Swaminathan 	ddi_dma_free_handle(&dbuf->dma_handle);
1235b9d3151SSukumar Swaminathan handle_fail:
1245b9d3151SSukumar Swaminathan 	kmem_free(dbuf, sizeof (oce_dma_buf_t));
1254d0e5007SSukumar Swaminathan 	return (NULL);
1264d0e5007SSukumar Swaminathan } /* oce_dma_alloc_buffer */
1274d0e5007SSukumar Swaminathan 
1284d0e5007SSukumar Swaminathan /*
1294d0e5007SSukumar Swaminathan  * function to delete a dma buffer
1304d0e5007SSukumar Swaminathan  *
1314d0e5007SSukumar Swaminathan  * dev - software handle to device
1324d0e5007SSukumar Swaminathan  * dbuf - dma obj  to delete
1334d0e5007SSukumar Swaminathan  *
1344d0e5007SSukumar Swaminathan  * return none
1354d0e5007SSukumar Swaminathan  */
1364d0e5007SSukumar Swaminathan void
oce_free_dma_buffer(struct oce_dev * dev,oce_dma_buf_t * dbuf)1374d0e5007SSukumar Swaminathan oce_free_dma_buffer(struct oce_dev *dev, oce_dma_buf_t *dbuf)
1384d0e5007SSukumar Swaminathan {
1394d0e5007SSukumar Swaminathan 	_NOTE(ARGUNUSED(dev));
1404d0e5007SSukumar Swaminathan 
1414d0e5007SSukumar Swaminathan 	if (dbuf == NULL) {
1424d0e5007SSukumar Swaminathan 		return;
1434d0e5007SSukumar Swaminathan 	}
1444d0e5007SSukumar Swaminathan 	if (dbuf->dma_handle != NULL) {
1454d0e5007SSukumar Swaminathan 		(void) ddi_dma_unbind_handle(dbuf->dma_handle);
1464d0e5007SSukumar Swaminathan 	}
1474d0e5007SSukumar Swaminathan 	if (dbuf->acc_handle != NULL) {
1484d0e5007SSukumar Swaminathan 		ddi_dma_mem_free(&dbuf->acc_handle);
1494d0e5007SSukumar Swaminathan 	}
1504d0e5007SSukumar Swaminathan 	if (dbuf->dma_handle != NULL) {
1514d0e5007SSukumar Swaminathan 		ddi_dma_free_handle(&dbuf->dma_handle);
1524d0e5007SSukumar Swaminathan 	}
1534d0e5007SSukumar Swaminathan 	kmem_free(dbuf, sizeof (oce_dma_buf_t));
1544d0e5007SSukumar Swaminathan } /* oce_free_dma_buffer */
1554d0e5007SSukumar Swaminathan 
1564d0e5007SSukumar Swaminathan /*
1574d0e5007SSukumar Swaminathan  * function to create a ring buffer
1584d0e5007SSukumar Swaminathan  *
1594d0e5007SSukumar Swaminathan  * dev - software handle to the device
1604d0e5007SSukumar Swaminathan  * num_items - number of items in the ring
1614d0e5007SSukumar Swaminathan  * item_size - size of an individual item in the ring
1624d0e5007SSukumar Swaminathan  * flags - DDI_DMA_CONSISTENT/DDI_DMA_STREAMING for ring memory
1634d0e5007SSukumar Swaminathan  *
1644d0e5007SSukumar Swaminathan  * return pointer to a ring_buffer structure, NULL on failure
1654d0e5007SSukumar Swaminathan  */
1664d0e5007SSukumar Swaminathan oce_ring_buffer_t *
create_ring_buffer(struct oce_dev * dev,uint32_t num_items,uint32_t item_size,uint32_t flags)1674d0e5007SSukumar Swaminathan create_ring_buffer(struct oce_dev *dev,
1684d0e5007SSukumar Swaminathan     uint32_t num_items, uint32_t item_size, uint32_t flags)
1694d0e5007SSukumar Swaminathan {
1704d0e5007SSukumar Swaminathan 	oce_ring_buffer_t *ring;
1714d0e5007SSukumar Swaminathan 	uint32_t size;
1724d0e5007SSukumar Swaminathan 
1734d0e5007SSukumar Swaminathan 	/* allocate the ring buffer */
1748d738d7dSSukumar Swaminathan 	ring = kmem_zalloc(sizeof (oce_ring_buffer_t), KM_NOSLEEP);
1758d738d7dSSukumar Swaminathan 	if (ring == NULL) {
1768d738d7dSSukumar Swaminathan 		return (NULL);
1778d738d7dSSukumar Swaminathan 	}
1784d0e5007SSukumar Swaminathan 
1794d0e5007SSukumar Swaminathan 	/* get the dbuf defining the ring */
1804d0e5007SSukumar Swaminathan 	size = num_items * item_size;
1815b9d3151SSukumar Swaminathan 	ring->dbuf = oce_alloc_dma_buffer(dev, size, NULL, flags);
1824d0e5007SSukumar Swaminathan 	if (ring->dbuf  == NULL) {
1834d0e5007SSukumar Swaminathan 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
1844d0e5007SSukumar Swaminathan 		    "Ring buffer allocation failed");
1854d0e5007SSukumar Swaminathan 		goto dbuf_fail;
1864d0e5007SSukumar Swaminathan 	}
1874d0e5007SSukumar Swaminathan 
1884d0e5007SSukumar Swaminathan 	/* fill the rest of the ring */
1894d0e5007SSukumar Swaminathan 	ring->num_items = num_items;
1904d0e5007SSukumar Swaminathan 	ring->item_size = item_size;
1914d0e5007SSukumar Swaminathan 	ring->num_used  = 0;
1924d0e5007SSukumar Swaminathan 	return (ring);
1934d0e5007SSukumar Swaminathan 
1944d0e5007SSukumar Swaminathan dbuf_fail:
1954d0e5007SSukumar Swaminathan 	kmem_free(ring, sizeof (oce_ring_buffer_t));
1964d0e5007SSukumar Swaminathan 	return (NULL);
1974d0e5007SSukumar Swaminathan } /* create_ring_buffer */
1984d0e5007SSukumar Swaminathan 
1994d0e5007SSukumar Swaminathan /*
2004d0e5007SSukumar Swaminathan  * function to destroy a ring buffer
2014d0e5007SSukumar Swaminathan  *
2024d0e5007SSukumar Swaminathan  * dev - software handle to teh device
2034d0e5007SSukumar Swaminathan  * ring - the ring buffer to delete
2044d0e5007SSukumar Swaminathan  *
2054d0e5007SSukumar Swaminathan  * return none
2064d0e5007SSukumar Swaminathan  */
2074d0e5007SSukumar Swaminathan void
destroy_ring_buffer(struct oce_dev * dev,oce_ring_buffer_t * ring)2084d0e5007SSukumar Swaminathan destroy_ring_buffer(struct oce_dev *dev, oce_ring_buffer_t *ring)
2094d0e5007SSukumar Swaminathan {
2104d0e5007SSukumar Swaminathan 	ASSERT(dev != NULL);
2114d0e5007SSukumar Swaminathan 	ASSERT(ring !=  NULL);
2124d0e5007SSukumar Swaminathan 
2134d0e5007SSukumar Swaminathan 	/* free the dbuf associated with the ring */
2144d0e5007SSukumar Swaminathan 	oce_free_dma_buffer(dev, ring->dbuf);
2154d0e5007SSukumar Swaminathan 	ring->dbuf = NULL;
2164d0e5007SSukumar Swaminathan 
2174d0e5007SSukumar Swaminathan 	/* free the ring itself */
2184d0e5007SSukumar Swaminathan 	kmem_free(ring, sizeof (oce_ring_buffer_t));
2194d0e5007SSukumar Swaminathan } /* destroy_ring_buffer */
2204d0e5007SSukumar Swaminathan 
2214d0e5007SSukumar Swaminathan 
2224d0e5007SSukumar Swaminathan /*
2234d0e5007SSukumar Swaminathan  * function to enable the fma flags
2244d0e5007SSukumar Swaminathan  * fm_caps - FM capability flags
2254d0e5007SSukumar Swaminathan  *
2264d0e5007SSukumar Swaminathan  * return none
2274d0e5007SSukumar Swaminathan  */
2284d0e5007SSukumar Swaminathan 
2294d0e5007SSukumar Swaminathan void
oce_set_dma_fma_flags(int fm_caps)2304d0e5007SSukumar Swaminathan oce_set_dma_fma_flags(int fm_caps)
2314d0e5007SSukumar Swaminathan {
2324d0e5007SSukumar Swaminathan 	if (fm_caps == DDI_FM_NOT_CAPABLE) {
2334d0e5007SSukumar Swaminathan 		return;
2344d0e5007SSukumar Swaminathan 	}
2354d0e5007SSukumar Swaminathan 
23612d61dabSSukumar Swaminathan 	oce_dma_buf_accattr.devacc_attr_access = DDI_DEFAULT_ACC;
2374d0e5007SSukumar Swaminathan 
2384d0e5007SSukumar Swaminathan 	if (DDI_FM_DMA_ERR_CAP(fm_caps)) {
2394d0e5007SSukumar Swaminathan 		oce_dma_buf_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
2404d0e5007SSukumar Swaminathan 
2414d0e5007SSukumar Swaminathan 	} else {
2424d0e5007SSukumar Swaminathan 		oce_dma_buf_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
2434d0e5007SSukumar Swaminathan 
2444d0e5007SSukumar Swaminathan 	}
2454d0e5007SSukumar Swaminathan } /* oce_set_dma_fma_flags */
246