xref: /onnv-gate/usr/src/uts/common/io/xge/hal/xgehal/xgehal-mm.c (revision 6937:a5e2c8b5c817)
11256Syl150051 /*
21256Syl150051  * CDDL HEADER START
31256Syl150051  *
41256Syl150051  * The contents of this file are subject to the terms of the
51256Syl150051  * Common Development and Distribution License (the "License").
61256Syl150051  * You may not use this file except in compliance with the License.
71256Syl150051  *
81256Syl150051  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91256Syl150051  * or http://www.opensolaris.org/os/licensing.
101256Syl150051  * See the License for the specific language governing permissions
111256Syl150051  * and limitations under the License.
121256Syl150051  *
131256Syl150051  * When distributing Covered Code, include this CDDL HEADER in each
141256Syl150051  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151256Syl150051  * If applicable, add the following below this CDDL HEADER, with the
161256Syl150051  * fields enclosed by brackets "[]" replaced with your own identifying
171256Syl150051  * information: Portions Copyright [yyyy] [name of copyright owner]
181256Syl150051  *
191256Syl150051  * CDDL HEADER END
201256Syl150051  *
21*3115Syl150051  * Copyright (c) 2002-2006 Neterion, Inc.
221256Syl150051  */
231256Syl150051 
241256Syl150051 #include "xge-os-pal.h"
251256Syl150051 #include "xgehal-mm.h"
261256Syl150051 #include "xge-debug.h"
271256Syl150051 
281256Syl150051 /*
291256Syl150051  * __hal_mempool_grow
301256Syl150051  *
311256Syl150051  * Will resize mempool up to %num_allocate value.
321256Syl150051  */
331256Syl150051 xge_hal_status_e
__hal_mempool_grow(xge_hal_mempool_t * mempool,int num_allocate,int * num_allocated)341256Syl150051 __hal_mempool_grow(xge_hal_mempool_t *mempool, int num_allocate,
351256Syl150051 		int *num_allocated)
361256Syl150051 {
371256Syl150051 	int i, first_time = mempool->memblocks_allocated == 0 ? 1 : 0;
381256Syl150051 	int n_items = mempool->items_per_memblock;
391256Syl150051 
401256Syl150051 	*num_allocated = 0;
411256Syl150051 
421256Syl150051 	if ((mempool->memblocks_allocated + num_allocate) >
431256Syl150051 						mempool->memblocks_max) {
441256Syl150051 		xge_debug_mm(XGE_ERR, "%s",
451256Syl150051 			      "__hal_mempool_grow: can grow anymore");
461256Syl150051 		return XGE_HAL_ERR_OUT_OF_MEMORY;
471256Syl150051 	}
481256Syl150051 
491256Syl150051 	for (i = mempool->memblocks_allocated;
501256Syl150051 	     i < mempool->memblocks_allocated + num_allocate; i++) {
511256Syl150051 		int j;
521256Syl150051 		int is_last =
531256Syl150051 			((mempool->memblocks_allocated+num_allocate-1) == i);
541256Syl150051 		xge_hal_mempool_dma_t *dma_object =
551256Syl150051 			mempool->memblocks_dma_arr + i;
561256Syl150051 		void *the_memblock;
571256Syl150051 		int dma_flags;
581256Syl150051 
591256Syl150051 		dma_flags = XGE_OS_DMA_CACHELINE_ALIGNED;
601256Syl150051 #ifdef XGE_HAL_DMA_DTR_CONSISTENT
611256Syl150051 		dma_flags |= XGE_OS_DMA_CONSISTENT;
621256Syl150051 #else
631256Syl150051 		dma_flags |= XGE_OS_DMA_STREAMING;
641256Syl150051 #endif
651256Syl150051 
661256Syl150051 		/* allocate DMA-capable memblock */
671256Syl150051 		mempool->memblocks_arr[i] = xge_os_dma_malloc(mempool->pdev,
681256Syl150051 					        mempool->memblock_size,
691256Syl150051 						dma_flags,
701256Syl150051 					        &dma_object->handle,
711256Syl150051 					        &dma_object->acc_handle);
721256Syl150051 		if (mempool->memblocks_arr[i] == NULL) {
731256Syl150051 			xge_debug_mm(XGE_ERR,
741256Syl150051 				      "memblock[%d]: out of DMA memory", i);
751256Syl150051 			return XGE_HAL_ERR_OUT_OF_MEMORY;
761256Syl150051 		}
771256Syl150051 		xge_os_memzero(mempool->memblocks_arr[i],
781256Syl150051 		mempool->memblock_size);
791256Syl150051 		the_memblock = mempool->memblocks_arr[i];
801256Syl150051 
811256Syl150051 		/* allocate memblock's private part. Each DMA memblock
821256Syl150051 		 * has a space allocated for item's private usage upon
831256Syl150051 		 * mempool's user request. Each time mempool grows, it will
841256Syl150051 		 * allocate new memblock and its private part at once.
851256Syl150051 		 * This helps to minimize memory usage a lot. */
861256Syl150051 		mempool->memblocks_priv_arr[i] = xge_os_malloc(mempool->pdev,
871256Syl150051 					mempool->items_priv_size * n_items);
881256Syl150051 		if (mempool->memblocks_priv_arr[i] == NULL) {
891256Syl150051 			xge_os_dma_free(mempool->pdev,
901256Syl150051 				      the_memblock,
911256Syl150051 				      mempool->memblock_size,
921256Syl150051 				      &dma_object->acc_handle,
931256Syl150051 				      &dma_object->handle);
941256Syl150051 			xge_debug_mm(XGE_ERR,
951256Syl150051 			        "memblock_priv[%d]: out of virtual memory, "
961256Syl150051 			        "requested %d(%d:%d) bytes", i,
971256Syl150051 				mempool->items_priv_size * n_items,
981256Syl150051 				mempool->items_priv_size, n_items);
991256Syl150051 			return XGE_HAL_ERR_OUT_OF_MEMORY;
1001256Syl150051 		}
1011256Syl150051 		xge_os_memzero(mempool->memblocks_priv_arr[i],
1021256Syl150051 			     mempool->items_priv_size * n_items);
1031256Syl150051 
1041256Syl150051 		/* map memblock to physical memory */
1051256Syl150051 		dma_object->addr = xge_os_dma_map(mempool->pdev,
1061256Syl150051 		                                dma_object->handle,
1071256Syl150051 						the_memblock,
1081256Syl150051 						mempool->memblock_size,
1091256Syl150051 						XGE_OS_DMA_DIR_BIDIRECTIONAL,
1101256Syl150051 #ifdef XGE_HAL_DMA_DTR_CONSISTENT
1111256Syl150051 					        XGE_OS_DMA_CONSISTENT
1121256Syl150051 #else
1131256Syl150051 					        XGE_OS_DMA_STREAMING
1141256Syl150051 #endif
1151256Syl150051                                                 );
1161256Syl150051 		if (dma_object->addr == XGE_OS_INVALID_DMA_ADDR) {
1171256Syl150051 			xge_os_free(mempool->pdev, mempool->memblocks_priv_arr[i],
1181256Syl150051 				  mempool->items_priv_size *
1191256Syl150051 					n_items);
1201256Syl150051 			xge_os_dma_free(mempool->pdev,
1211256Syl150051 				      the_memblock,
1221256Syl150051 				      mempool->memblock_size,
1231256Syl150051 				      &dma_object->acc_handle,
1241256Syl150051 				      &dma_object->handle);
1251256Syl150051 			return XGE_HAL_ERR_OUT_OF_MAPPING;
1261256Syl150051 		}
1271256Syl150051 
1281256Syl150051 		/* fill the items hash array */
1291256Syl150051 		for (j=0; j<n_items; j++) {
1301256Syl150051 			int index = i*n_items + j;
1311256Syl150051 
1321256Syl150051 			if (first_time && index >= mempool->items_initial) {
1331256Syl150051 				break;
1341256Syl150051 			}
1351256Syl150051 
1361256Syl150051 			mempool->items_arr[index] =
1371256Syl150051 				((char *)the_memblock + j*mempool->item_size);
1381256Syl150051 
1391256Syl150051 			/* let caller to do more job on each item */
1401256Syl150051 			if (mempool->item_func_alloc != NULL) {
1411256Syl150051 				xge_hal_status_e status;
1421256Syl150051 
1431256Syl150051 				if ((status = mempool->item_func_alloc(
1441256Syl150051 					mempool,
1451256Syl150051 					the_memblock,
1461256Syl150051 					i,
1471256Syl150051 					dma_object,
1481256Syl150051 					mempool->items_arr[index],
1491256Syl150051 					index,
1501256Syl150051 					is_last,
1511256Syl150051 					mempool->userdata)) != XGE_HAL_OK) {
1521256Syl150051 
1531256Syl150051 					if (mempool->item_func_free != NULL) {
1541256Syl150051 						int k;
1551256Syl150051 
1561256Syl150051 						for (k=0; k<j; k++) {
1571256Syl150051 
1581256Syl150051 						    index =i*n_items + k;
1591256Syl150051 
1601256Syl150051 						  (void)mempool->item_func_free(
1611256Syl150051 						     mempool, the_memblock,
1621256Syl150051 						     i, dma_object,
1631256Syl150051 						     mempool->items_arr[index],
1641256Syl150051 						     index, is_last,
1651256Syl150051 						     mempool->userdata);
1661256Syl150051 						}
1671256Syl150051 					}
1681256Syl150051 
1691256Syl150051 					xge_os_free(mempool->pdev,
1701256Syl150051 					     mempool->memblocks_priv_arr[i],
1711256Syl150051 					     mempool->items_priv_size *
1721256Syl150051 					     n_items);
1731256Syl150051 					xge_os_dma_unmap(mempool->pdev,
1741256Syl150051 					     dma_object->handle,
1751256Syl150051 					     dma_object->addr,
1761256Syl150051 					     mempool->memblock_size,
1771256Syl150051 					     XGE_OS_DMA_DIR_BIDIRECTIONAL);
1781256Syl150051 					xge_os_dma_free(mempool->pdev,
1791256Syl150051 					     the_memblock,
1801256Syl150051 					     mempool->memblock_size,
1811256Syl150051 					     &dma_object->acc_handle,
1821256Syl150051 					     &dma_object->handle);
1831256Syl150051 					return status;
1841256Syl150051 				}
1851256Syl150051 			}
1861256Syl150051 
1871256Syl150051 			mempool->items_current = index + 1;
1881256Syl150051 		}
1891256Syl150051 
1901256Syl150051 		xge_debug_mm(XGE_TRACE,
191*3115Syl150051 			"memblock%d: allocated %dk, vaddr 0x"XGE_OS_LLXFMT", "
192*3115Syl150051 			"dma_addr 0x"XGE_OS_LLXFMT, i, mempool->memblock_size / 1024,
1931256Syl150051 			(unsigned long long)(ulong_t)mempool->memblocks_arr[i],
1941256Syl150051 			(unsigned long long)dma_object->addr);
1951256Syl150051 
1961256Syl150051 		(*num_allocated)++;
1971256Syl150051 
1981256Syl150051 		if (first_time && mempool->items_current ==
1991256Syl150051 						mempool->items_initial) {
2001256Syl150051 			break;
2011256Syl150051 		}
2021256Syl150051 	}
2031256Syl150051 
2041256Syl150051 	/* increment actual number of allocated memblocks */
2051256Syl150051 	mempool->memblocks_allocated += *num_allocated;
2061256Syl150051 
2071256Syl150051 	return XGE_HAL_OK;
2081256Syl150051 }
2091256Syl150051 
2101256Syl150051 /*
2111256Syl150051  * xge_hal_mempool_create
2121256Syl150051  * @memblock_size:
2131256Syl150051  * @items_initial:
2141256Syl150051  * @items_max:
2151256Syl150051  * @item_size:
2161256Syl150051  * @item_func:
2171256Syl150051  *
2181256Syl150051  * This function will create memory pool object. Pool may grow but will
2191256Syl150051  * never shrink. Pool consists of number of dynamically allocated blocks
2201256Syl150051  * with size enough to hold %items_initial number of items. Memory is
2211256Syl150051  * DMA-able but client must map/unmap before interoperating with the device.
2221256Syl150051  * See also: xge_os_dma_map(), xge_hal_dma_unmap(), xge_hal_status_e{}.
2231256Syl150051  */
2241256Syl150051 xge_hal_mempool_t*
__hal_mempool_create(pci_dev_h pdev,int memblock_size,int item_size,int items_priv_size,int items_initial,int items_max,xge_hal_mempool_item_f item_func_alloc,xge_hal_mempool_item_f item_func_free,void * userdata)2251256Syl150051 __hal_mempool_create(pci_dev_h pdev, int memblock_size, int item_size,
2261256Syl150051 		int items_priv_size, int items_initial, int items_max,
2271256Syl150051 		xge_hal_mempool_item_f item_func_alloc,
2281256Syl150051 		xge_hal_mempool_item_f item_func_free, void *userdata)
2291256Syl150051 {
2301256Syl150051 	xge_hal_status_e status;
2311256Syl150051 	int memblocks_to_allocate;
2321256Syl150051 	xge_hal_mempool_t *mempool;
2331256Syl150051 	int allocated;
2341256Syl150051 
2351256Syl150051 	if (memblock_size < item_size) {
2361256Syl150051 		xge_debug_mm(XGE_ERR,
2371256Syl150051 			"memblock_size %d < item_size %d: misconfiguration",
2381256Syl150051 			memblock_size, item_size);
2391256Syl150051 		return NULL;
2401256Syl150051 	}
2411256Syl150051 
242*3115Syl150051 	mempool = (xge_hal_mempool_t *) \
243*3115Syl150051 			xge_os_malloc(pdev, sizeof(xge_hal_mempool_t));
2441256Syl150051 	if (mempool == NULL) {
2451256Syl150051 		xge_debug_mm(XGE_ERR, "mempool allocation failure");
2461256Syl150051 		return NULL;
2471256Syl150051 	}
2481256Syl150051 	xge_os_memzero(mempool, sizeof(xge_hal_mempool_t));
2491256Syl150051 
2501256Syl150051 	mempool->pdev			= pdev;
2511256Syl150051 	mempool->memblock_size		= memblock_size;
2521256Syl150051 	mempool->items_max		= items_max;
2531256Syl150051 	mempool->items_initial		= items_initial;
2541256Syl150051 	mempool->item_size		= item_size;
2551256Syl150051 	mempool->items_priv_size	= items_priv_size;
2561256Syl150051 	mempool->item_func_alloc	= item_func_alloc;
2571256Syl150051 	mempool->item_func_free		= item_func_free;
2581256Syl150051 	mempool->userdata		= userdata;
2591256Syl150051 
2601256Syl150051 	mempool->memblocks_allocated = 0;
2611256Syl150051 
2621256Syl150051 	mempool->items_per_memblock = memblock_size / item_size;
2631256Syl150051 
2641256Syl150051 	mempool->memblocks_max = (items_max + mempool->items_per_memblock - 1) /
2651256Syl150051 					mempool->items_per_memblock;
2661256Syl150051 
2671256Syl150051 	/* allocate array of memblocks */
268*3115Syl150051 	mempool->memblocks_arr = (void ** ) xge_os_malloc(mempool->pdev,
2691256Syl150051 					sizeof(void*) * mempool->memblocks_max);
2701256Syl150051 	if (mempool->memblocks_arr == NULL) {
2711256Syl150051 		xge_debug_mm(XGE_ERR, "memblocks_arr allocation failure");
2721256Syl150051 		__hal_mempool_destroy(mempool);
2731256Syl150051 		return NULL;
2741256Syl150051 	}
2751256Syl150051 	xge_os_memzero(mempool->memblocks_arr,
2761256Syl150051 		    sizeof(void*) * mempool->memblocks_max);
2771256Syl150051 
2781256Syl150051 	/* allocate array of private parts of items per memblocks */
279*3115Syl150051 	mempool->memblocks_priv_arr = (void **) xge_os_malloc(mempool->pdev,
2801256Syl150051 					sizeof(void*) * mempool->memblocks_max);
2811256Syl150051 	if (mempool->memblocks_priv_arr == NULL) {
2821256Syl150051 		xge_debug_mm(XGE_ERR, "memblocks_priv_arr allocation failure");
2831256Syl150051 		__hal_mempool_destroy(mempool);
2841256Syl150051 		return NULL;
2851256Syl150051 	}
2861256Syl150051 	xge_os_memzero(mempool->memblocks_priv_arr,
2871256Syl150051 		    sizeof(void*) * mempool->memblocks_max);
2881256Syl150051 
2891256Syl150051 	/* allocate array of memblocks DMA objects */
290*3115Syl150051 	mempool->memblocks_dma_arr =
291*3115Syl150051 		(xge_hal_mempool_dma_t *) xge_os_malloc(mempool->pdev,
292*3115Syl150051 		sizeof(xge_hal_mempool_dma_t) * mempool->memblocks_max);
293*3115Syl150051 
2941256Syl150051 	if (mempool->memblocks_dma_arr == NULL) {
2951256Syl150051 		xge_debug_mm(XGE_ERR, "memblocks_dma_arr allocation failure");
2961256Syl150051 		__hal_mempool_destroy(mempool);
2971256Syl150051 		return NULL;
2981256Syl150051 	}
2991256Syl150051 	xge_os_memzero(mempool->memblocks_dma_arr,
3001256Syl150051 		     sizeof(xge_hal_mempool_dma_t) * mempool->memblocks_max);
3011256Syl150051 
3021256Syl150051 	/* allocate hash array of items */
303*3115Syl150051 	mempool->items_arr = (void **) xge_os_malloc(mempool->pdev,
3041256Syl150051 				 sizeof(void*) * mempool->items_max);
3051256Syl150051 	if (mempool->items_arr == NULL) {
3061256Syl150051 		xge_debug_mm(XGE_ERR, "items_arr allocation failure");
3071256Syl150051 		__hal_mempool_destroy(mempool);
3081256Syl150051 		return NULL;
3091256Syl150051 	}
3101256Syl150051 	xge_os_memzero(mempool->items_arr, sizeof(void *) * mempool->items_max);
3111256Syl150051 
312*3115Syl150051 	mempool->shadow_items_arr = (void **) xge_os_malloc(mempool->pdev,
313*3115Syl150051                                 sizeof(void*) *  mempool->items_max);
3141256Syl150051 	if (mempool->shadow_items_arr == NULL) {
3151256Syl150051 		xge_debug_mm(XGE_ERR, "shadow_items_arr allocation failure");
3161256Syl150051 		__hal_mempool_destroy(mempool);
3171256Syl150051 		return NULL;
3181256Syl150051 	}
3191256Syl150051 	xge_os_memzero(mempool->shadow_items_arr,
3201256Syl150051 		     sizeof(void *) * mempool->items_max);
3211256Syl150051 
3221256Syl150051 	/* calculate initial number of memblocks */
3231256Syl150051 	memblocks_to_allocate = (mempool->items_initial +
3241256Syl150051 				 mempool->items_per_memblock - 1) /
3251256Syl150051 						mempool->items_per_memblock;
3261256Syl150051 
3271256Syl150051 	xge_debug_mm(XGE_TRACE, "allocating %d memblocks, "
3281256Syl150051 			"%d items per memblock", memblocks_to_allocate,
3291256Syl150051 			mempool->items_per_memblock);
3301256Syl150051 
3311256Syl150051 	/* pre-allocate the mempool */
3321256Syl150051 	status = __hal_mempool_grow(mempool, memblocks_to_allocate, &allocated);
3331256Syl150051 	xge_os_memcpy(mempool->shadow_items_arr, mempool->items_arr,
3341256Syl150051 		    sizeof(void*) * mempool->items_max);
3351256Syl150051 	if (status != XGE_HAL_OK) {
3361256Syl150051 		xge_debug_mm(XGE_ERR, "mempool_grow failure");
3371256Syl150051 		__hal_mempool_destroy(mempool);
3381256Syl150051 		return NULL;
3391256Syl150051 	}
3401256Syl150051 
3411256Syl150051 	xge_debug_mm(XGE_TRACE,
3421256Syl150051 		"total: allocated %dk of DMA-capable memory",
3431256Syl150051 		mempool->memblock_size * allocated / 1024);
3441256Syl150051 
3451256Syl150051 	return mempool;
3461256Syl150051 }
3471256Syl150051 
3481256Syl150051 /*
3491256Syl150051  * xge_hal_mempool_destroy
3501256Syl150051  */
3511256Syl150051 void
__hal_mempool_destroy(xge_hal_mempool_t * mempool)3521256Syl150051 __hal_mempool_destroy(xge_hal_mempool_t *mempool)
3531256Syl150051 {
3541256Syl150051 	int i, j;
3551256Syl150051 
3561256Syl150051 	for (i=0; i<mempool->memblocks_allocated; i++) {
3571256Syl150051 		xge_hal_mempool_dma_t *dma_object;
3581256Syl150051 
3591256Syl150051 		xge_assert(mempool->memblocks_arr[i]);
3601256Syl150051 		xge_assert(mempool->memblocks_dma_arr + i);
3611256Syl150051 
3621256Syl150051 		dma_object = mempool->memblocks_dma_arr + i;
3631256Syl150051 
3641256Syl150051 		for (j=0; j<mempool->items_per_memblock; j++) {
3651256Syl150051 			int index = i*mempool->items_per_memblock + j;
3661256Syl150051 
3671256Syl150051 			/* to skip last partially filled(if any) memblock */
3681256Syl150051 			if (index >= mempool->items_current) {
3691256Syl150051 				break;
3701256Syl150051 			}
3711256Syl150051 
3721256Syl150051 			/* let caller to do more job on each item */
3731256Syl150051 			if (mempool->item_func_free != NULL) {
3741256Syl150051 
3751256Syl150051 				mempool->item_func_free(mempool,
3761256Syl150051 					mempool->memblocks_arr[i],
3771256Syl150051 					i, dma_object,
3781256Syl150051 					mempool->shadow_items_arr[index],
3791256Syl150051 					index, /* unused */ -1,
3801256Syl150051 					mempool->userdata);
3811256Syl150051 			}
3821256Syl150051 		}
3831256Syl150051 
3841256Syl150051 		xge_os_dma_unmap(mempool->pdev,
3851256Syl150051 	               dma_object->handle, dma_object->addr,
3861256Syl150051 		       mempool->memblock_size, XGE_OS_DMA_DIR_BIDIRECTIONAL);
3871256Syl150051 
3881256Syl150051 		xge_os_free(mempool->pdev, mempool->memblocks_priv_arr[i],
3891256Syl150051 			mempool->items_priv_size * mempool->items_per_memblock);
3901256Syl150051 
3911256Syl150051 		xge_os_dma_free(mempool->pdev, mempool->memblocks_arr[i],
3921256Syl150051 			      mempool->memblock_size, &dma_object->acc_handle,
3931256Syl150051 			      &dma_object->handle);
3941256Syl150051 	}
3951256Syl150051 
3961256Syl150051 	if (mempool->items_arr) {
3971256Syl150051 		xge_os_free(mempool->pdev, mempool->items_arr, sizeof(void*) *
3981256Syl150051 		          mempool->items_max);
3991256Syl150051 	}
4001256Syl150051 
4011256Syl150051 	if (mempool->shadow_items_arr) {
4021256Syl150051 		xge_os_free(mempool->pdev, mempool->shadow_items_arr,
4031256Syl150051 			  sizeof(void*) * mempool->items_max);
4041256Syl150051 	}
4051256Syl150051 
4061256Syl150051 	if (mempool->memblocks_dma_arr) {
4071256Syl150051 		xge_os_free(mempool->pdev, mempool->memblocks_dma_arr,
4081256Syl150051 		          sizeof(xge_hal_mempool_dma_t) *
4091256Syl150051 			     mempool->memblocks_max);
4101256Syl150051 	}
4111256Syl150051 
4121256Syl150051 	if (mempool->memblocks_priv_arr) {
4131256Syl150051 		xge_os_free(mempool->pdev, mempool->memblocks_priv_arr,
4141256Syl150051 		          sizeof(void*) * mempool->memblocks_max);
4151256Syl150051 	}
4161256Syl150051 
4171256Syl150051 	if (mempool->memblocks_arr) {
4181256Syl150051 		xge_os_free(mempool->pdev, mempool->memblocks_arr,
4191256Syl150051 		          sizeof(void*) * mempool->memblocks_max);
4201256Syl150051 	}
4211256Syl150051 
4221256Syl150051 	xge_os_free(mempool->pdev, mempool, sizeof(xge_hal_mempool_t));
4231256Syl150051 }
424