xref: /onnv-gate/usr/src/uts/common/io/fibre-channel/fca/oce/oce_buf.c (revision 13020:1b6086d6d5a1)
111374SSukumar.Swaminathan@Sun.COM /*
211374SSukumar.Swaminathan@Sun.COM  * CDDL HEADER START
311374SSukumar.Swaminathan@Sun.COM  *
411374SSukumar.Swaminathan@Sun.COM  * The contents of this file are subject to the terms of the
511374SSukumar.Swaminathan@Sun.COM  * Common Development and Distribution License (the "License").
611374SSukumar.Swaminathan@Sun.COM  * You may not use this file except in compliance with the License.
711374SSukumar.Swaminathan@Sun.COM  *
811374SSukumar.Swaminathan@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911374SSukumar.Swaminathan@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011374SSukumar.Swaminathan@Sun.COM  * See the License for the specific language governing permissions
1111374SSukumar.Swaminathan@Sun.COM  * and limitations under the License.
1211374SSukumar.Swaminathan@Sun.COM  *
1311374SSukumar.Swaminathan@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411374SSukumar.Swaminathan@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511374SSukumar.Swaminathan@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611374SSukumar.Swaminathan@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711374SSukumar.Swaminathan@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811374SSukumar.Swaminathan@Sun.COM  *
1911374SSukumar.Swaminathan@Sun.COM  * CDDL HEADER END
2011374SSukumar.Swaminathan@Sun.COM  */
2111374SSukumar.Swaminathan@Sun.COM 
2211374SSukumar.Swaminathan@Sun.COM /*
2312043SSukumar.Swaminathan@Sun.COM  * Copyright 2010 Emulex.  All rights reserved.
2411374SSukumar.Swaminathan@Sun.COM  * Use is subject to license terms.
2511374SSukumar.Swaminathan@Sun.COM  */
2611374SSukumar.Swaminathan@Sun.COM 
2711374SSukumar.Swaminathan@Sun.COM /*
2811374SSukumar.Swaminathan@Sun.COM  * Source file containing the implementation of Driver buffer management
2911374SSukumar.Swaminathan@Sun.COM  * and related helper functions
3011374SSukumar.Swaminathan@Sun.COM  */
3111374SSukumar.Swaminathan@Sun.COM #include <oce_impl.h>
3211374SSukumar.Swaminathan@Sun.COM 
3311374SSukumar.Swaminathan@Sun.COM static ddi_dma_attr_t oce_dma_buf_attr = {
3411374SSukumar.Swaminathan@Sun.COM 	DMA_ATTR_V0,		/* version number */
3511374SSukumar.Swaminathan@Sun.COM 	0x0000000000000000ull,	/* low address */
3611374SSukumar.Swaminathan@Sun.COM 	0xFFFFFFFFFFFFFFFFull,	/* high address */
3711374SSukumar.Swaminathan@Sun.COM 	0x00000000FFFFFFFFull,	/* dma counter max */
3811374SSukumar.Swaminathan@Sun.COM 	OCE_DMA_ALIGNMENT,	/* alignment */
3911374SSukumar.Swaminathan@Sun.COM 	0x00000FFF,		/* burst sizes */
4011374SSukumar.Swaminathan@Sun.COM 	0x00000001,		/* minimum transfer size */
4111374SSukumar.Swaminathan@Sun.COM 	0x00000000FFFFFFFFull,	/* maximum transfer size */
4211374SSukumar.Swaminathan@Sun.COM 	0xFFFFFFFFFFFFFFFFull,	/* maximum segment size */
4311374SSukumar.Swaminathan@Sun.COM 	1,			/* scatter/gather list length */
4411374SSukumar.Swaminathan@Sun.COM 	0x00000001,		/* granularity */
4511374SSukumar.Swaminathan@Sun.COM 	0			/* DMA flags */
4611374SSukumar.Swaminathan@Sun.COM };
4711374SSukumar.Swaminathan@Sun.COM 
4811374SSukumar.Swaminathan@Sun.COM static ddi_device_acc_attr_t oce_dma_buf_accattr = {
4911374SSukumar.Swaminathan@Sun.COM 	DDI_DEVICE_ATTR_V0,
5011374SSukumar.Swaminathan@Sun.COM 	DDI_NEVERSWAP_ACC,
5111374SSukumar.Swaminathan@Sun.COM 	DDI_STRICTORDER_ACC,
5211374SSukumar.Swaminathan@Sun.COM };
5311374SSukumar.Swaminathan@Sun.COM 
5411374SSukumar.Swaminathan@Sun.COM 
5511374SSukumar.Swaminathan@Sun.COM /*
5611374SSukumar.Swaminathan@Sun.COM  * function to allocate a dma buffer for mapping memory va-pa
5711374SSukumar.Swaminathan@Sun.COM  *
5811374SSukumar.Swaminathan@Sun.COM  * dev - software handle to device
5911374SSukumar.Swaminathan@Sun.COM  * size - size of the memory to map
6011374SSukumar.Swaminathan@Sun.COM  * flags - DDI_DMA_CONSISTENT/DDI_DMA_STREAMING
6111374SSukumar.Swaminathan@Sun.COM  *
6211374SSukumar.Swaminathan@Sun.COM  * return pointer to a oce_dma_buf_t structure handling the map
6311374SSukumar.Swaminathan@Sun.COM  *      NULL => failure
6411374SSukumar.Swaminathan@Sun.COM  */
6511374SSukumar.Swaminathan@Sun.COM oce_dma_buf_t *
oce_alloc_dma_buffer(struct oce_dev * dev,uint32_t size,ddi_dma_attr_t * dma_attr,uint32_t flags)6611374SSukumar.Swaminathan@Sun.COM oce_alloc_dma_buffer(struct oce_dev *dev,
67*13020SSukumar.Swaminathan@Sun.COM     uint32_t size, ddi_dma_attr_t *dma_attr, uint32_t flags)
6811374SSukumar.Swaminathan@Sun.COM {
6911374SSukumar.Swaminathan@Sun.COM 	oce_dma_buf_t  *dbuf;
7011374SSukumar.Swaminathan@Sun.COM 	ddi_dma_cookie_t cookie;
7111374SSukumar.Swaminathan@Sun.COM 	uint32_t count;
7211374SSukumar.Swaminathan@Sun.COM 	size_t actual_len;
7311374SSukumar.Swaminathan@Sun.COM 	int ret = 0;
7411374SSukumar.Swaminathan@Sun.COM 
7511374SSukumar.Swaminathan@Sun.COM 	ASSERT(size > 0);
76*13020SSukumar.Swaminathan@Sun.COM 	/* if NULL use default */
77*13020SSukumar.Swaminathan@Sun.COM 	if (dma_attr == NULL) {
78*13020SSukumar.Swaminathan@Sun.COM 		dma_attr = &oce_dma_buf_attr;
79*13020SSukumar.Swaminathan@Sun.COM 	}
8011374SSukumar.Swaminathan@Sun.COM 
8111723SSukumar.Swaminathan@Sun.COM 	dbuf = kmem_zalloc(sizeof (oce_dma_buf_t), KM_NOSLEEP);
8211723SSukumar.Swaminathan@Sun.COM 	if (dbuf == NULL) {
8311723SSukumar.Swaminathan@Sun.COM 		return (NULL);
8411723SSukumar.Swaminathan@Sun.COM 	}
8511374SSukumar.Swaminathan@Sun.COM 
8611374SSukumar.Swaminathan@Sun.COM 	/* allocate dma handle */
87*13020SSukumar.Swaminathan@Sun.COM 	ret = ddi_dma_alloc_handle(dev->dip, dma_attr,
8811723SSukumar.Swaminathan@Sun.COM 	    DDI_DMA_DONTWAIT, NULL, &dbuf->dma_handle);
8911374SSukumar.Swaminathan@Sun.COM 	if (ret != DDI_SUCCESS) {
9011374SSukumar.Swaminathan@Sun.COM 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
9111374SSukumar.Swaminathan@Sun.COM 		    "Failed to allocate DMA handle");
92*13020SSukumar.Swaminathan@Sun.COM 		goto handle_fail;
9311374SSukumar.Swaminathan@Sun.COM 	}
9411374SSukumar.Swaminathan@Sun.COM 	/* allocate the DMA-able memory */
9511374SSukumar.Swaminathan@Sun.COM 	ret = ddi_dma_mem_alloc(dbuf->dma_handle, size, &oce_dma_buf_accattr,
9611723SSukumar.Swaminathan@Sun.COM 	    flags, DDI_DMA_DONTWAIT, NULL, &dbuf->base,
9711374SSukumar.Swaminathan@Sun.COM 	    &actual_len, &dbuf->acc_handle);
9811374SSukumar.Swaminathan@Sun.COM 	if (ret != DDI_SUCCESS) {
9911374SSukumar.Swaminathan@Sun.COM 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
10011374SSukumar.Swaminathan@Sun.COM 		    "Failed to allocate DMA memory");
10111374SSukumar.Swaminathan@Sun.COM 		goto alloc_fail;
10211374SSukumar.Swaminathan@Sun.COM 	}
10311374SSukumar.Swaminathan@Sun.COM 
10411374SSukumar.Swaminathan@Sun.COM 	/* bind handle */
10511374SSukumar.Swaminathan@Sun.COM 	ret = ddi_dma_addr_bind_handle(dbuf->dma_handle,
10611374SSukumar.Swaminathan@Sun.COM 	    (struct as *)0, dbuf->base, actual_len,
10711374SSukumar.Swaminathan@Sun.COM 	    DDI_DMA_RDWR | flags,
10811723SSukumar.Swaminathan@Sun.COM 	    DDI_DMA_DONTWAIT, NULL, &cookie, &count);
10911374SSukumar.Swaminathan@Sun.COM 	if (ret != DDI_DMA_MAPPED) {
11011374SSukumar.Swaminathan@Sun.COM 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
11111374SSukumar.Swaminathan@Sun.COM 		    "Failed to bind dma handle");
112*13020SSukumar.Swaminathan@Sun.COM 		goto bind_fail;
11311374SSukumar.Swaminathan@Sun.COM 	}
11411374SSukumar.Swaminathan@Sun.COM 	bzero(dbuf->base, actual_len);
11511374SSukumar.Swaminathan@Sun.COM 	dbuf->addr = cookie.dmac_laddress;
11611374SSukumar.Swaminathan@Sun.COM 	dbuf->size = actual_len;
11711374SSukumar.Swaminathan@Sun.COM 	/* usable length */
11811374SSukumar.Swaminathan@Sun.COM 	dbuf->len  = size;
11911374SSukumar.Swaminathan@Sun.COM 	dbuf->num_pages = OCE_NUM_PAGES(size);
12011374SSukumar.Swaminathan@Sun.COM 	return (dbuf);
121*13020SSukumar.Swaminathan@Sun.COM 
122*13020SSukumar.Swaminathan@Sun.COM bind_fail:
123*13020SSukumar.Swaminathan@Sun.COM 	ddi_dma_mem_free(&dbuf->acc_handle);
12411374SSukumar.Swaminathan@Sun.COM alloc_fail:
125*13020SSukumar.Swaminathan@Sun.COM 	ddi_dma_free_handle(&dbuf->dma_handle);
126*13020SSukumar.Swaminathan@Sun.COM handle_fail:
127*13020SSukumar.Swaminathan@Sun.COM 	kmem_free(dbuf, sizeof (oce_dma_buf_t));
12811374SSukumar.Swaminathan@Sun.COM 	return (NULL);
12911374SSukumar.Swaminathan@Sun.COM } /* oce_dma_alloc_buffer */
13011374SSukumar.Swaminathan@Sun.COM 
13111374SSukumar.Swaminathan@Sun.COM /*
13211374SSukumar.Swaminathan@Sun.COM  * function to delete a dma buffer
13311374SSukumar.Swaminathan@Sun.COM  *
13411374SSukumar.Swaminathan@Sun.COM  * dev - software handle to device
13511374SSukumar.Swaminathan@Sun.COM  * dbuf - dma obj  to delete
13611374SSukumar.Swaminathan@Sun.COM  *
13711374SSukumar.Swaminathan@Sun.COM  * return none
13811374SSukumar.Swaminathan@Sun.COM  */
13911374SSukumar.Swaminathan@Sun.COM void
oce_free_dma_buffer(struct oce_dev * dev,oce_dma_buf_t * dbuf)14011374SSukumar.Swaminathan@Sun.COM oce_free_dma_buffer(struct oce_dev *dev, oce_dma_buf_t *dbuf)
14111374SSukumar.Swaminathan@Sun.COM {
14211374SSukumar.Swaminathan@Sun.COM 	_NOTE(ARGUNUSED(dev));
14311374SSukumar.Swaminathan@Sun.COM 
14411374SSukumar.Swaminathan@Sun.COM 	if (dbuf == NULL) {
14511374SSukumar.Swaminathan@Sun.COM 		return;
14611374SSukumar.Swaminathan@Sun.COM 	}
14711374SSukumar.Swaminathan@Sun.COM 	if (dbuf->dma_handle != NULL) {
14811374SSukumar.Swaminathan@Sun.COM 		(void) ddi_dma_unbind_handle(dbuf->dma_handle);
14911374SSukumar.Swaminathan@Sun.COM 	}
15011374SSukumar.Swaminathan@Sun.COM 	if (dbuf->acc_handle != NULL) {
15111374SSukumar.Swaminathan@Sun.COM 		ddi_dma_mem_free(&dbuf->acc_handle);
15211374SSukumar.Swaminathan@Sun.COM 	}
15311374SSukumar.Swaminathan@Sun.COM 	if (dbuf->dma_handle != NULL) {
15411374SSukumar.Swaminathan@Sun.COM 		ddi_dma_free_handle(&dbuf->dma_handle);
15511374SSukumar.Swaminathan@Sun.COM 	}
15611374SSukumar.Swaminathan@Sun.COM 	kmem_free(dbuf, sizeof (oce_dma_buf_t));
15711374SSukumar.Swaminathan@Sun.COM } /* oce_free_dma_buffer */
15811374SSukumar.Swaminathan@Sun.COM 
15911374SSukumar.Swaminathan@Sun.COM /*
16011374SSukumar.Swaminathan@Sun.COM  * function to create a ring buffer
16111374SSukumar.Swaminathan@Sun.COM  *
16211374SSukumar.Swaminathan@Sun.COM  * dev - software handle to the device
16311374SSukumar.Swaminathan@Sun.COM  * num_items - number of items in the ring
16411374SSukumar.Swaminathan@Sun.COM  * item_size - size of an individual item in the ring
16511374SSukumar.Swaminathan@Sun.COM  * flags - DDI_DMA_CONSISTENT/DDI_DMA_STREAMING for ring memory
16611374SSukumar.Swaminathan@Sun.COM  *
16711374SSukumar.Swaminathan@Sun.COM  * return pointer to a ring_buffer structure, NULL on failure
16811374SSukumar.Swaminathan@Sun.COM  */
16911374SSukumar.Swaminathan@Sun.COM oce_ring_buffer_t *
create_ring_buffer(struct oce_dev * dev,uint32_t num_items,uint32_t item_size,uint32_t flags)17011374SSukumar.Swaminathan@Sun.COM create_ring_buffer(struct oce_dev *dev,
17111374SSukumar.Swaminathan@Sun.COM     uint32_t num_items, uint32_t item_size, uint32_t flags)
17211374SSukumar.Swaminathan@Sun.COM {
17311374SSukumar.Swaminathan@Sun.COM 	oce_ring_buffer_t *ring;
17411374SSukumar.Swaminathan@Sun.COM 	uint32_t size;
17511374SSukumar.Swaminathan@Sun.COM 
17611374SSukumar.Swaminathan@Sun.COM 	/* allocate the ring buffer */
17711723SSukumar.Swaminathan@Sun.COM 	ring = kmem_zalloc(sizeof (oce_ring_buffer_t), KM_NOSLEEP);
17811723SSukumar.Swaminathan@Sun.COM 	if (ring == NULL) {
17911723SSukumar.Swaminathan@Sun.COM 		return (NULL);
18011723SSukumar.Swaminathan@Sun.COM 	}
18111374SSukumar.Swaminathan@Sun.COM 
18211374SSukumar.Swaminathan@Sun.COM 	/* get the dbuf defining the ring */
18311374SSukumar.Swaminathan@Sun.COM 	size = num_items * item_size;
184*13020SSukumar.Swaminathan@Sun.COM 	ring->dbuf = oce_alloc_dma_buffer(dev, size, NULL, flags);
18511374SSukumar.Swaminathan@Sun.COM 	if (ring->dbuf  == NULL) {
18611374SSukumar.Swaminathan@Sun.COM 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
18711374SSukumar.Swaminathan@Sun.COM 		    "Ring buffer allocation failed");
18811374SSukumar.Swaminathan@Sun.COM 		goto dbuf_fail;
18911374SSukumar.Swaminathan@Sun.COM 	}
19011374SSukumar.Swaminathan@Sun.COM 
19111374SSukumar.Swaminathan@Sun.COM 	/* fill the rest of the ring */
19211374SSukumar.Swaminathan@Sun.COM 	ring->num_items = num_items;
19311374SSukumar.Swaminathan@Sun.COM 	ring->item_size = item_size;
19411374SSukumar.Swaminathan@Sun.COM 	ring->num_used  = 0;
19511374SSukumar.Swaminathan@Sun.COM 	return (ring);
19611374SSukumar.Swaminathan@Sun.COM 
19711374SSukumar.Swaminathan@Sun.COM dbuf_fail:
19811374SSukumar.Swaminathan@Sun.COM 	kmem_free(ring, sizeof (oce_ring_buffer_t));
19911374SSukumar.Swaminathan@Sun.COM 	return (NULL);
20011374SSukumar.Swaminathan@Sun.COM } /* create_ring_buffer */
20111374SSukumar.Swaminathan@Sun.COM 
20211374SSukumar.Swaminathan@Sun.COM /*
20311374SSukumar.Swaminathan@Sun.COM  * function to destroy a ring buffer
20411374SSukumar.Swaminathan@Sun.COM  *
20511374SSukumar.Swaminathan@Sun.COM  * dev - software handle to teh device
20611374SSukumar.Swaminathan@Sun.COM  * ring - the ring buffer to delete
20711374SSukumar.Swaminathan@Sun.COM  *
20811374SSukumar.Swaminathan@Sun.COM  * return none
20911374SSukumar.Swaminathan@Sun.COM  */
21011374SSukumar.Swaminathan@Sun.COM void
destroy_ring_buffer(struct oce_dev * dev,oce_ring_buffer_t * ring)21111374SSukumar.Swaminathan@Sun.COM destroy_ring_buffer(struct oce_dev *dev, oce_ring_buffer_t *ring)
21211374SSukumar.Swaminathan@Sun.COM {
21311374SSukumar.Swaminathan@Sun.COM 	ASSERT(dev != NULL);
21411374SSukumar.Swaminathan@Sun.COM 	ASSERT(ring !=  NULL);
21511374SSukumar.Swaminathan@Sun.COM 
21611374SSukumar.Swaminathan@Sun.COM 	/* free the dbuf associated with the ring */
21711374SSukumar.Swaminathan@Sun.COM 	oce_free_dma_buffer(dev, ring->dbuf);
21811374SSukumar.Swaminathan@Sun.COM 	ring->dbuf = NULL;
21911374SSukumar.Swaminathan@Sun.COM 
22011374SSukumar.Swaminathan@Sun.COM 	/* free the ring itself */
22111374SSukumar.Swaminathan@Sun.COM 	kmem_free(ring, sizeof (oce_ring_buffer_t));
22211374SSukumar.Swaminathan@Sun.COM } /* destroy_ring_buffer */
22311374SSukumar.Swaminathan@Sun.COM 
22411374SSukumar.Swaminathan@Sun.COM 
22511374SSukumar.Swaminathan@Sun.COM /*
22611374SSukumar.Swaminathan@Sun.COM  * function to enable the fma flags
22711374SSukumar.Swaminathan@Sun.COM  * fm_caps - FM capability flags
22811374SSukumar.Swaminathan@Sun.COM  *
22911374SSukumar.Swaminathan@Sun.COM  * return none
23011374SSukumar.Swaminathan@Sun.COM  */
23111374SSukumar.Swaminathan@Sun.COM 
23211374SSukumar.Swaminathan@Sun.COM void
oce_set_dma_fma_flags(int fm_caps)23311374SSukumar.Swaminathan@Sun.COM oce_set_dma_fma_flags(int fm_caps)
23411374SSukumar.Swaminathan@Sun.COM {
23511374SSukumar.Swaminathan@Sun.COM 	if (fm_caps == DDI_FM_NOT_CAPABLE) {
23611374SSukumar.Swaminathan@Sun.COM 		return;
23711374SSukumar.Swaminathan@Sun.COM 	}
23811374SSukumar.Swaminathan@Sun.COM 
23912043SSukumar.Swaminathan@Sun.COM 	oce_dma_buf_accattr.devacc_attr_access = DDI_DEFAULT_ACC;
24011374SSukumar.Swaminathan@Sun.COM 
24111374SSukumar.Swaminathan@Sun.COM 	if (DDI_FM_DMA_ERR_CAP(fm_caps)) {
24211374SSukumar.Swaminathan@Sun.COM 		oce_dma_buf_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
24311374SSukumar.Swaminathan@Sun.COM 
24411374SSukumar.Swaminathan@Sun.COM 	} else {
24511374SSukumar.Swaminathan@Sun.COM 		oce_dma_buf_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
24611374SSukumar.Swaminathan@Sun.COM 
24711374SSukumar.Swaminathan@Sun.COM 	}
24811374SSukumar.Swaminathan@Sun.COM } /* oce_set_dma_fma_flags */
249