1221167Sgnn/*-
2221167Sgnn * Copyright(c) 2002-2011 Exar Corp.
3221167Sgnn * All rights reserved.
4221167Sgnn *
5221167Sgnn * Redistribution and use in source and binary forms, with or without
6221167Sgnn * modification are permitted provided the following conditions are met:
7221167Sgnn *
8221167Sgnn *    1. Redistributions of source code must retain the above copyright notice,
9221167Sgnn *       this list of conditions and the following disclaimer.
10221167Sgnn *
11221167Sgnn *    2. Redistributions in binary form must reproduce the above copyright
12221167Sgnn *       notice, this list of conditions and the following disclaimer in the
13221167Sgnn *       documentation and/or other materials provided with the distribution.
14221167Sgnn *
15221167Sgnn *    3. Neither the name of the Exar Corporation nor the names of its
16221167Sgnn *       contributors may be used to endorse or promote products derived from
17221167Sgnn *       this software without specific prior written permission.
18221167Sgnn *
19221167Sgnn * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20221167Sgnn * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21221167Sgnn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22221167Sgnn * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23221167Sgnn * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24221167Sgnn * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25221167Sgnn * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26221167Sgnn * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27221167Sgnn * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28221167Sgnn * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29221167Sgnn * POSSIBILITY OF SUCH DAMAGE.
30221167Sgnn */
31221167Sgnn/*$FreeBSD$*/
32221167Sgnn
33221167Sgnn#include <dev/vxge/vxgehal/vxgehal.h>
34221167Sgnn
35221167Sgnn/*
36221167Sgnn * __hal_mempool_grow
37221167Sgnn *
38221167Sgnn * Will resize mempool up to %num_allocate value.
39221167Sgnn */
40221167Sgnnstatic vxge_hal_status_e
41221167Sgnn__hal_mempool_grow(
42221167Sgnn    vxge_hal_mempool_t *mempool,
43221167Sgnn    u32 num_allocate,
44221167Sgnn    u32 *num_allocated)
45221167Sgnn{
46221167Sgnn	u32 i, j, k, item_index, is_last;
47221167Sgnn	u32 first_time = mempool->memblocks_allocated == 0 ? 1 : 0;
48221167Sgnn	u32 n_items = mempool->items_per_memblock;
49221167Sgnn	u32 start_block_idx = mempool->memblocks_allocated;
50221167Sgnn	u32 end_block_idx = mempool->memblocks_allocated + num_allocate;
51221167Sgnn	__hal_device_t *hldev;
52221167Sgnn
53221167Sgnn	vxge_assert(mempool != NULL);
54221167Sgnn
55221167Sgnn	hldev = (__hal_device_t *) mempool->devh;
56221167Sgnn
57221167Sgnn	vxge_hal_trace_log_mm("==> %s:%s:%d",
58221167Sgnn	    __FILE__, __func__, __LINE__);
59221167Sgnn
60221167Sgnn	vxge_hal_trace_log_mm(
61221167Sgnn	    "mempool = 0x"VXGE_OS_STXFMT", num_allocate = %d, "
62221167Sgnn	    "num_allocated = 0x"VXGE_OS_STXFMT, (ptr_t) mempool,
63221167Sgnn	    num_allocate, (ptr_t) num_allocated);
64221167Sgnn
65221167Sgnn	*num_allocated = 0;
66221167Sgnn
67221167Sgnn	if (end_block_idx > mempool->memblocks_max) {
68221167Sgnn		vxge_hal_err_log_mm("%s",
69221167Sgnn		    "__hal_mempool_grow: can grow anymore");
70221167Sgnn		vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
71221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
72221167Sgnn		return (VXGE_HAL_ERR_OUT_OF_MEMORY);
73221167Sgnn	}
74221167Sgnn
75221167Sgnn	for (i = start_block_idx; i < end_block_idx; i++) {
76221167Sgnn
77221167Sgnn		void *the_memblock;
78221167Sgnn		vxge_hal_mempool_dma_t *dma_object;
79221167Sgnn
80221167Sgnn		is_last = ((end_block_idx - 1) == i);
81221167Sgnn		dma_object = mempool->memblocks_dma_arr + i;
82221167Sgnn
83221167Sgnn		/*
84221167Sgnn		 * allocate memblock's private part. Each DMA memblock
85221167Sgnn		 * has a space allocated for item's private usage upon
86221167Sgnn		 * mempool's user request. Each time mempool grows, it will
87221167Sgnn		 * allocate new memblock and its private part at once.
88221167Sgnn		 * This helps to minimize memory usage a lot.
89221167Sgnn		 */
90221167Sgnn		mempool->memblocks_priv_arr[i] = vxge_os_malloc(
91221167Sgnn		    ((__hal_device_t *) mempool->devh)->header.pdev,
92221167Sgnn		    mempool->items_priv_size * n_items);
93221167Sgnn		if (mempool->memblocks_priv_arr[i] == NULL) {
94221167Sgnn
95221167Sgnn			vxge_hal_err_log_mm("memblock_priv[%d]: \
96221167Sgnn			    out of virtual memory, "
97221167Sgnn			    "requested %d(%d:%d) bytes", i,
98221167Sgnn			    mempool->items_priv_size * n_items,
99221167Sgnn			    mempool->items_priv_size, n_items);
100221167Sgnn			vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
101221167Sgnn			    __FILE__, __func__, __LINE__,
102221167Sgnn			    VXGE_HAL_ERR_OUT_OF_MEMORY);
103221167Sgnn			return (VXGE_HAL_ERR_OUT_OF_MEMORY);
104221167Sgnn
105221167Sgnn		}
106221167Sgnn
107221167Sgnn		vxge_os_memzero(mempool->memblocks_priv_arr[i],
108221167Sgnn		    mempool->items_priv_size * n_items);
109221167Sgnn
110221167Sgnn		/* allocate DMA-capable memblock */
111221167Sgnn		mempool->memblocks_arr[i] =
112221167Sgnn		    __hal_blockpool_malloc(mempool->devh,
113221167Sgnn		    mempool->memblock_size,
114221167Sgnn		    &dma_object->addr,
115221167Sgnn		    &dma_object->handle,
116221167Sgnn		    &dma_object->acc_handle);
117221167Sgnn		if (mempool->memblocks_arr[i] == NULL) {
118221167Sgnn			vxge_os_free(
119221167Sgnn			    ((__hal_device_t *) mempool->devh)->header.pdev,
120221167Sgnn			    mempool->memblocks_priv_arr[i],
121221167Sgnn			    mempool->items_priv_size * n_items);
122221167Sgnn			vxge_hal_err_log_mm("memblock[%d]: \
123221167Sgnn			    out of DMA memory", i);
124221167Sgnn			vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
125221167Sgnn			    __FILE__, __func__, __LINE__,
126221167Sgnn			    VXGE_HAL_ERR_OUT_OF_MEMORY);
127221167Sgnn			return (VXGE_HAL_ERR_OUT_OF_MEMORY);
128221167Sgnn		}
129221167Sgnn
130221167Sgnn		(*num_allocated)++;
131221167Sgnn		mempool->memblocks_allocated++;
132221167Sgnn
133221167Sgnn		vxge_os_memzero(mempool->memblocks_arr[i],
134221167Sgnn		    mempool->memblock_size);
135221167Sgnn
136221167Sgnn		the_memblock = mempool->memblocks_arr[i];
137221167Sgnn
138221167Sgnn		/* fill the items hash array */
139221167Sgnn		for (j = 0; j < n_items; j++) {
140221167Sgnn			item_index = i * n_items + j;
141221167Sgnn
142221167Sgnn			if (first_time && (item_index >= mempool->items_initial))
143221167Sgnn				break;
144221167Sgnn
145221167Sgnn			mempool->items_arr[item_index] =
146221167Sgnn			    ((char *) the_memblock + j *mempool->item_size);
147221167Sgnn
148221167Sgnn			/* let caller to do more job on each item */
149221167Sgnn			if (mempool->item_func_alloc != NULL) {
150221167Sgnn				vxge_hal_status_e status;
151221167Sgnn
152221167Sgnn				if ((status = mempool->item_func_alloc(
153221167Sgnn				    mempool,
154221167Sgnn				    the_memblock,
155221167Sgnn				    i,
156221167Sgnn				    dma_object,
157221167Sgnn				    mempool->items_arr[item_index],
158221167Sgnn				    item_index,
159221167Sgnn				    is_last,
160221167Sgnn				    mempool->userdata)) != VXGE_HAL_OK) {
161221167Sgnn
162221167Sgnn					if (mempool->item_func_free != NULL) {
163221167Sgnn
164221167Sgnn						for (k = 0; k < j; k++) {
165221167Sgnn
166221167Sgnn							item_index = i * n_items + k;
167221167Sgnn
168221167Sgnn							(void) mempool->item_func_free(
169221167Sgnn							    mempool,
170221167Sgnn							    the_memblock,
171221167Sgnn							    i, dma_object,
172221167Sgnn							    mempool->items_arr[item_index],
173221167Sgnn							    item_index, is_last,
174221167Sgnn							    mempool->userdata);
175221167Sgnn						}
176221167Sgnn					}
177221167Sgnn
178221167Sgnn					vxge_os_free(((__hal_device_t *)
179221167Sgnn					    mempool->devh)->header.pdev,
180221167Sgnn					    mempool->memblocks_priv_arr[i],
181221167Sgnn					    mempool->items_priv_size *
182221167Sgnn					    n_items);
183221167Sgnn
184221167Sgnn					__hal_blockpool_free(mempool->devh,
185221167Sgnn					    the_memblock,
186221167Sgnn					    mempool->memblock_size,
187221167Sgnn					    &dma_object->addr,
188221167Sgnn					    &dma_object->handle,
189221167Sgnn					    &dma_object->acc_handle);
190221167Sgnn
191221167Sgnn					(*num_allocated)--;
192221167Sgnn					mempool->memblocks_allocated--;
193221167Sgnn					return (status);
194221167Sgnn				}
195221167Sgnn			}
196221167Sgnn
197221167Sgnn			mempool->items_current = item_index + 1;
198221167Sgnn		}
199221167Sgnn
200221167Sgnn		vxge_hal_info_log_mm(
201221167Sgnn		    "memblock%d: allocated %dk, vaddr 0x"VXGE_OS_STXFMT", "
202221167Sgnn		    "dma_addr 0x"VXGE_OS_STXFMT,
203221167Sgnn		    i, mempool->memblock_size / 1024,
204221167Sgnn		    (ptr_t) mempool->memblocks_arr[i], dma_object->addr);
205221167Sgnn
206221167Sgnn		if (first_time && mempool->items_current ==
207221167Sgnn		    mempool->items_initial) {
208221167Sgnn			break;
209221167Sgnn		}
210221167Sgnn	}
211221167Sgnn
212221167Sgnn	vxge_hal_trace_log_mm("<== %s:%s:%d  Result: 0",
213221167Sgnn	    __FILE__, __func__, __LINE__);
214221167Sgnn
215221167Sgnn	return (VXGE_HAL_OK);
216221167Sgnn}
217221167Sgnn
218221167Sgnn/*
219221167Sgnn * vxge_hal_mempool_create
220221167Sgnn * @memblock_size:
221221167Sgnn * @items_initial:
222221167Sgnn * @items_max:
223221167Sgnn * @item_size:
224221167Sgnn * @item_func:
225221167Sgnn *
226221167Sgnn * This function will create memory pool object. Pool may grow but will
227221167Sgnn * never shrink. Pool consists of number of dynamically allocated blocks
228221167Sgnn * with size enough to hold %items_initial number of items. Memory is
229221167Sgnn * DMA-able but client must map/unmap before interoperating with the device.
230221167Sgnn * See also: vxge_os_dma_map(), vxge_hal_dma_unmap(), vxge_hal_status_e {}.
231221167Sgnn */
232221167Sgnnvxge_hal_mempool_t *
233221167Sgnnvxge_hal_mempool_create(
234221167Sgnn    vxge_hal_device_h devh,
235221167Sgnn    u32 memblock_size,
236221167Sgnn    u32 item_size,
237221167Sgnn    u32 items_priv_size,
238221167Sgnn    u32 items_initial,
239221167Sgnn    u32 items_max,
240221167Sgnn    vxge_hal_mempool_item_f item_func_alloc,
241221167Sgnn    vxge_hal_mempool_item_f item_func_free,
242221167Sgnn    void *userdata)
243221167Sgnn{
244221167Sgnn	vxge_hal_status_e status;
245221167Sgnn	u32 memblocks_to_allocate;
246221167Sgnn	vxge_hal_mempool_t *mempool;
247221167Sgnn	__hal_device_t *hldev;
248221167Sgnn	u32 allocated;
249221167Sgnn
250221167Sgnn	vxge_assert(devh != NULL);
251221167Sgnn
252221167Sgnn	hldev = (__hal_device_t *) devh;
253221167Sgnn
254221167Sgnn	vxge_hal_trace_log_mm("==> %s:%s:%d",
255221167Sgnn	    __FILE__, __func__, __LINE__);
256221167Sgnn
257221167Sgnn	vxge_hal_trace_log_mm(
258221167Sgnn	    "devh = 0x"VXGE_OS_STXFMT", memblock_size = %d, item_size = %d, "
259221167Sgnn	    "items_priv_size = %d, items_initial = %d, items_max = %d, "
260221167Sgnn	    "item_func_alloc = 0x"VXGE_OS_STXFMT", "
261221167Sgnn	    "item_func_free = 0x"VXGE_OS_STXFMT", "
262221167Sgnn	    "userdata = 0x"VXGE_OS_STXFMT, (ptr_t) devh,
263221167Sgnn	    memblock_size, item_size, items_priv_size,
264221167Sgnn	    items_initial, items_max, (ptr_t) item_func_alloc,
265221167Sgnn	    (ptr_t) item_func_free, (ptr_t) userdata);
266221167Sgnn
267221167Sgnn	if (memblock_size < item_size) {
268221167Sgnn		vxge_hal_err_log_mm(
269221167Sgnn		    "memblock_size %d < item_size %d: misconfiguration",
270221167Sgnn		    memblock_size, item_size);
271221167Sgnn		vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
272221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_HAL_FAIL);
273221167Sgnn		return (NULL);
274221167Sgnn	}
275221167Sgnn
276221167Sgnn	mempool = (vxge_hal_mempool_t *) vxge_os_malloc(
277221167Sgnn	    ((__hal_device_t *) devh)->header.pdev, sizeof(vxge_hal_mempool_t));
278221167Sgnn	if (mempool == NULL) {
279221167Sgnn		vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
280221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
281221167Sgnn		return (NULL);
282221167Sgnn	}
283221167Sgnn	vxge_os_memzero(mempool, sizeof(vxge_hal_mempool_t));
284221167Sgnn
285221167Sgnn	mempool->devh = devh;
286221167Sgnn	mempool->memblock_size = memblock_size;
287221167Sgnn	mempool->items_max = items_max;
288221167Sgnn	mempool->items_initial = items_initial;
289221167Sgnn	mempool->item_size = item_size;
290221167Sgnn	mempool->items_priv_size = items_priv_size;
291221167Sgnn	mempool->item_func_alloc = item_func_alloc;
292221167Sgnn	mempool->item_func_free = item_func_free;
293221167Sgnn	mempool->userdata = userdata;
294221167Sgnn
295221167Sgnn	mempool->memblocks_allocated = 0;
296221167Sgnn
297221167Sgnn	if (memblock_size != VXGE_OS_HOST_PAGE_SIZE)
298221167Sgnn		mempool->dma_flags = VXGE_OS_DMA_CACHELINE_ALIGNED;
299221167Sgnn
300221167Sgnn#if defined(VXGE_HAL_DMA_CONSISTENT)
301221167Sgnn	mempool->dma_flags |= VXGE_OS_DMA_CONSISTENT;
302221167Sgnn#else
303221167Sgnn	mempool->dma_flags |= VXGE_OS_DMA_STREAMING;
304221167Sgnn#endif
305221167Sgnn
306221167Sgnn	mempool->items_per_memblock = memblock_size / item_size;
307221167Sgnn
308221167Sgnn	mempool->memblocks_max = (items_max + mempool->items_per_memblock - 1) /
309221167Sgnn	    mempool->items_per_memblock;
310221167Sgnn
311221167Sgnn	/* allocate array of memblocks */
312221167Sgnn	mempool->memblocks_arr = (void **)vxge_os_malloc(
313221167Sgnn	    ((__hal_device_t *) mempool->devh)->header.pdev,
314221167Sgnn	    sizeof(void *) * mempool->memblocks_max);
315221167Sgnn	if (mempool->memblocks_arr == NULL) {
316221167Sgnn		vxge_hal_mempool_destroy(mempool);
317221167Sgnn		vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
318221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
319221167Sgnn		return (NULL);
320221167Sgnn	}
321221167Sgnn	vxge_os_memzero(mempool->memblocks_arr,
322221167Sgnn	    sizeof(void *) * mempool->memblocks_max);
323221167Sgnn
324221167Sgnn	/* allocate array of private parts of items per memblocks */
325221167Sgnn	mempool->memblocks_priv_arr = (void **)vxge_os_malloc(
326221167Sgnn	    ((__hal_device_t *) mempool->devh)->header.pdev,
327221167Sgnn	    sizeof(void *) * mempool->memblocks_max);
328221167Sgnn	if (mempool->memblocks_priv_arr == NULL) {
329221167Sgnn		vxge_hal_mempool_destroy(mempool);
330221167Sgnn		vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
331221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
332221167Sgnn		return (NULL);
333221167Sgnn	}
334221167Sgnn	vxge_os_memzero(mempool->memblocks_priv_arr,
335221167Sgnn	    sizeof(void *) * mempool->memblocks_max);
336221167Sgnn
337221167Sgnn	/* allocate array of memblocks DMA objects */
338221167Sgnn	mempool->memblocks_dma_arr =
339221167Sgnn	    (vxge_hal_mempool_dma_t *) vxge_os_malloc(
340221167Sgnn	    ((__hal_device_t *) mempool->devh)->header.pdev,
341221167Sgnn	    sizeof(vxge_hal_mempool_dma_t) * mempool->memblocks_max);
342221167Sgnn
343221167Sgnn	if (mempool->memblocks_dma_arr == NULL) {
344221167Sgnn		vxge_hal_mempool_destroy(mempool);
345221167Sgnn		vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
346221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
347221167Sgnn		return (NULL);
348221167Sgnn	}
349221167Sgnn	vxge_os_memzero(mempool->memblocks_dma_arr,
350221167Sgnn	    sizeof(vxge_hal_mempool_dma_t) * mempool->memblocks_max);
351221167Sgnn
352221167Sgnn	/* allocate hash array of items */
353221167Sgnn	mempool->items_arr = (void **)vxge_os_malloc(
354221167Sgnn	    ((__hal_device_t *) mempool->devh)->header.pdev,
355221167Sgnn	    sizeof(void *) * mempool->items_max);
356221167Sgnn	if (mempool->items_arr == NULL) {
357221167Sgnn		vxge_hal_mempool_destroy(mempool);
358221167Sgnn		vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
359221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
360221167Sgnn		return (NULL);
361221167Sgnn	}
362221167Sgnn	vxge_os_memzero(mempool->items_arr,
363221167Sgnn	    sizeof(void *) * mempool->items_max);
364221167Sgnn
365221167Sgnn	mempool->shadow_items_arr = (void **)vxge_os_malloc(
366221167Sgnn	    ((__hal_device_t *) mempool->devh)->header.pdev,
367221167Sgnn	    sizeof(void *) * mempool->items_max);
368221167Sgnn	if (mempool->shadow_items_arr == NULL) {
369221167Sgnn		vxge_hal_mempool_destroy(mempool);
370221167Sgnn		vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
371221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
372221167Sgnn		return (NULL);
373221167Sgnn	}
374221167Sgnn	vxge_os_memzero(mempool->shadow_items_arr,
375221167Sgnn	    sizeof(void *) * mempool->items_max);
376221167Sgnn
377221167Sgnn	/* calculate initial number of memblocks */
378221167Sgnn	memblocks_to_allocate = (mempool->items_initial +
379221167Sgnn	    mempool->items_per_memblock - 1) /
380221167Sgnn	    mempool->items_per_memblock;
381221167Sgnn
382221167Sgnn	vxge_hal_info_log_mm("allocating %d memblocks, "
383221167Sgnn	    "%d items per memblock", memblocks_to_allocate,
384221167Sgnn	    mempool->items_per_memblock);
385221167Sgnn
386221167Sgnn	/* pre-allocate the mempool */
387221167Sgnn	status = __hal_mempool_grow(mempool, memblocks_to_allocate, &allocated);
388221167Sgnn	vxge_os_memcpy(mempool->shadow_items_arr, mempool->items_arr,
389221167Sgnn	    sizeof(void *) * mempool->items_max);
390221167Sgnn	if (status != VXGE_HAL_OK) {
391221167Sgnn		vxge_hal_mempool_destroy(mempool);
392221167Sgnn		vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
393221167Sgnn		    __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
394221167Sgnn		return (NULL);
395221167Sgnn	}
396221167Sgnn
397221167Sgnn	vxge_hal_info_log_mm(
398221167Sgnn	    "total: allocated %dk of DMA-capable memory",
399221167Sgnn	    mempool->memblock_size * allocated / 1024);
400221167Sgnn
401221167Sgnn	vxge_hal_trace_log_mm("<== %s:%s:%d  Result: 0",
402221167Sgnn	    __FILE__, __func__, __LINE__);
403221167Sgnn
404221167Sgnn	return (mempool);
405221167Sgnn}
406221167Sgnn
407221167Sgnn/*
408221167Sgnn * vxge_hal_mempool_destroy
409221167Sgnn */
410221167Sgnnvoid
411221167Sgnnvxge_hal_mempool_destroy(
412221167Sgnn    vxge_hal_mempool_t *mempool)
413221167Sgnn{
414221167Sgnn	u32 i, j, item_index;
415221167Sgnn	__hal_device_t *hldev;
416221167Sgnn
417221167Sgnn	vxge_assert(mempool != NULL);
418221167Sgnn
419221167Sgnn	hldev = (__hal_device_t *) mempool->devh;
420221167Sgnn
421221167Sgnn	vxge_hal_trace_log_mm("==> %s:%s:%d",
422221167Sgnn	    __FILE__, __func__, __LINE__);
423221167Sgnn
424221167Sgnn	vxge_hal_trace_log_mm("mempool = 0x"VXGE_OS_STXFMT,
425221167Sgnn	    (ptr_t) mempool);
426221167Sgnn
427221167Sgnn	for (i = 0; i < mempool->memblocks_allocated; i++) {
428221167Sgnn		vxge_hal_mempool_dma_t *dma_object;
429221167Sgnn
430221167Sgnn		vxge_assert(mempool->memblocks_arr[i]);
431221167Sgnn		vxge_assert(mempool->memblocks_dma_arr + i);
432221167Sgnn
433221167Sgnn		dma_object = mempool->memblocks_dma_arr + i;
434221167Sgnn
435221167Sgnn		for (j = 0; j < mempool->items_per_memblock; j++) {
436221167Sgnn			item_index = i * mempool->items_per_memblock + j;
437221167Sgnn
438221167Sgnn			/* to skip last partially filled(if any) memblock */
439221167Sgnn			if (item_index >= mempool->items_current)
440221167Sgnn				break;
441221167Sgnn
442221167Sgnn			/* let caller to do more job on each item */
443221167Sgnn			if (mempool->item_func_free != NULL) {
444221167Sgnn
445221167Sgnn				mempool->item_func_free(mempool,
446221167Sgnn				    mempool->memblocks_arr[i],
447221167Sgnn				    i, dma_object,
448221167Sgnn				    mempool->shadow_items_arr[item_index],
449221167Sgnn				    item_index, /* unused */ -1,
450221167Sgnn				    mempool->userdata);
451221167Sgnn			}
452221167Sgnn		}
453221167Sgnn
454221167Sgnn		vxge_os_free(hldev->header.pdev,
455221167Sgnn		    mempool->memblocks_priv_arr[i],
456221167Sgnn		    mempool->items_priv_size * mempool->items_per_memblock);
457221167Sgnn
458221167Sgnn		__hal_blockpool_free(hldev,
459221167Sgnn		    mempool->memblocks_arr[i],
460221167Sgnn		    mempool->memblock_size,
461221167Sgnn		    &dma_object->addr,
462221167Sgnn		    &dma_object->handle,
463221167Sgnn		    &dma_object->acc_handle);
464221167Sgnn	}
465221167Sgnn
466221167Sgnn	if (mempool->items_arr) {
467221167Sgnn		vxge_os_free(hldev->header.pdev,
468221167Sgnn		    mempool->items_arr, sizeof(void *) * mempool->items_max);
469221167Sgnn	}
470221167Sgnn
471221167Sgnn	if (mempool->shadow_items_arr) {
472221167Sgnn		vxge_os_free(hldev->header.pdev,
473221167Sgnn		    mempool->shadow_items_arr,
474221167Sgnn		    sizeof(void *) * mempool->items_max);
475221167Sgnn	}
476221167Sgnn
477221167Sgnn	if (mempool->memblocks_dma_arr) {
478221167Sgnn		vxge_os_free(hldev->header.pdev,
479221167Sgnn		    mempool->memblocks_dma_arr,
480221167Sgnn		    sizeof(vxge_hal_mempool_dma_t) *
481221167Sgnn		    mempool->memblocks_max);
482221167Sgnn	}
483221167Sgnn
484221167Sgnn	if (mempool->memblocks_priv_arr) {
485221167Sgnn		vxge_os_free(hldev->header.pdev,
486221167Sgnn		    mempool->memblocks_priv_arr,
487221167Sgnn		    sizeof(void *) * mempool->memblocks_max);
488221167Sgnn	}
489221167Sgnn
490221167Sgnn	if (mempool->memblocks_arr) {
491221167Sgnn		vxge_os_free(hldev->header.pdev,
492221167Sgnn		    mempool->memblocks_arr,
493221167Sgnn		    sizeof(void *) * mempool->memblocks_max);
494221167Sgnn	}
495221167Sgnn
496221167Sgnn	vxge_os_free(hldev->header.pdev,
497221167Sgnn	    mempool, sizeof(vxge_hal_mempool_t));
498221167Sgnn
499221167Sgnn	vxge_hal_trace_log_mm("<== %s:%s:%d  Result: 0",
500221167Sgnn	    __FILE__, __func__, __LINE__);
501221167Sgnn}
502221167Sgnn
503221167Sgnn/*
504221167Sgnn * vxge_hal_check_alignment - Check buffer alignment	and	calculate the
505221167Sgnn * "misaligned"	portion.
506221167Sgnn * @dma_pointer: DMA address of	the	buffer.
507221167Sgnn * @size: Buffer size, in bytes.
508221167Sgnn * @alignment: Alignment "granularity" (see	below),	in bytes.
509221167Sgnn * @copy_size: Maximum number of bytes to "extract"	from the buffer
510221167Sgnn * (in order to	spost it as	a separate scatter-gather entry). See below.
511221167Sgnn *
512221167Sgnn * Check buffer	alignment and calculate	"misaligned" portion, if exists.
513221167Sgnn * The buffer is considered	aligned	if its address is multiple of
514221167Sgnn * the specified @alignment. If	this is	the	case,
515221167Sgnn * vxge_hal_check_alignment() returns zero.
516221167Sgnn * Otherwise, vxge_hal_check_alignment()	uses the last argument,
517221167Sgnn * @copy_size,
518221167Sgnn * to calculate	the	size to	"extract" from the buffer. The @copy_size
519221167Sgnn * may or may not be equal @alignment. The difference between these	two
520221167Sgnn * arguments is	that the @alignment is used to make the decision: aligned
521221167Sgnn * or not aligned. While the @copy_size	is used	to calculate the portion
522221167Sgnn * of the buffer to "extract", i.e.	to post	as a separate entry in the
523221167Sgnn * transmit descriptor.	For example, the combination
524221167Sgnn * @alignment = 8 and @copy_size = 64 will work	okay on	AMD Opteron boxes.
525221167Sgnn *
526221167Sgnn * Note: @copy_size should be a	multiple of @alignment.	In many	practical
527221167Sgnn * cases @copy_size and	@alignment will	probably be equal.
528221167Sgnn *
529221167Sgnn * See also: vxge_hal_fifo_txdl_buffer_set_aligned().
530221167Sgnn */
531221167Sgnnu32
532221167Sgnnvxge_hal_check_alignment(
533221167Sgnn    dma_addr_t dma_pointer,
534221167Sgnn    u32 size,
535221167Sgnn    u32 alignment,
536221167Sgnn    u32 copy_size)
537221167Sgnn{
538221167Sgnn	u32 misaligned_size;
539221167Sgnn
540221167Sgnn	misaligned_size = (int)(dma_pointer & (alignment - 1));
541221167Sgnn	if (!misaligned_size) {
542221167Sgnn		return (0);
543221167Sgnn	}
544221167Sgnn
545221167Sgnn	if (size > copy_size) {
546221167Sgnn		misaligned_size = (int)(dma_pointer & (copy_size - 1));
547221167Sgnn		misaligned_size = copy_size - misaligned_size;
548221167Sgnn	} else {
549221167Sgnn		misaligned_size = size;
550221167Sgnn	}
551221167Sgnn
552221167Sgnn	return (misaligned_size);
553221167Sgnn}
554