]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/vxge/vxgehal/vxgehal-mm.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / vxge / vxgehal / vxgehal-mm.c
1 /*-
2  * Copyright(c) 2002-2011 Exar Corp.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification are permitted provided the following conditions are met:
7  *
8  *    1. Redistributions of source code must retain the above copyright notice,
9  *       this list of conditions and the following disclaimer.
10  *
11  *    2. Redistributions in binary form must reproduce the above copyright
12  *       notice, this list of conditions and the following disclaimer in the
13  *       documentation and/or other materials provided with the distribution.
14  *
15  *    3. Neither the name of the Exar Corporation nor the names of its
16  *       contributors may be used to endorse or promote products derived from
17  *       this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*$FreeBSD$*/
32
33 #include <dev/vxge/vxgehal/vxgehal.h>
34
35 /*
36  * __hal_mempool_grow
37  *
38  * Will resize mempool up to %num_allocate value.
39  */
40 static vxge_hal_status_e
41 __hal_mempool_grow(
42     vxge_hal_mempool_t *mempool,
43     u32 num_allocate,
44     u32 *num_allocated)
45 {
46         u32 i, j, k, item_index, is_last;
47         u32 first_time = mempool->memblocks_allocated == 0 ? 1 : 0;
48         u32 n_items = mempool->items_per_memblock;
49         u32 start_block_idx = mempool->memblocks_allocated;
50         u32 end_block_idx = mempool->memblocks_allocated + num_allocate;
51         __hal_device_t *hldev;
52
53         vxge_assert(mempool != NULL);
54
55         hldev = (__hal_device_t *) mempool->devh;
56
57         vxge_hal_trace_log_mm("==> %s:%s:%d",
58             __FILE__, __func__, __LINE__);
59
60         vxge_hal_trace_log_mm(
61             "mempool = 0x"VXGE_OS_STXFMT", num_allocate = %d, "
62             "num_allocated = 0x"VXGE_OS_STXFMT, (ptr_t) mempool,
63             num_allocate, (ptr_t) num_allocated);
64
65         *num_allocated = 0;
66
67         if (end_block_idx > mempool->memblocks_max) {
68                 vxge_hal_err_log_mm("%s",
69                     "__hal_mempool_grow: can grow anymore");
70                 vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
71                     __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
72                 return (VXGE_HAL_ERR_OUT_OF_MEMORY);
73         }
74
75         for (i = start_block_idx; i < end_block_idx; i++) {
76
77                 void *the_memblock;
78                 vxge_hal_mempool_dma_t *dma_object;
79
80                 is_last = ((end_block_idx - 1) == i);
81                 dma_object = mempool->memblocks_dma_arr + i;
82
83                 /*
84                  * allocate memblock's private part. Each DMA memblock
85                  * has a space allocated for item's private usage upon
86                  * mempool's user request. Each time mempool grows, it will
87                  * allocate new memblock and its private part at once.
88                  * This helps to minimize memory usage a lot.
89                  */
90                 mempool->memblocks_priv_arr[i] = vxge_os_malloc(
91                     ((__hal_device_t *) mempool->devh)->header.pdev,
92                     mempool->items_priv_size * n_items);
93                 if (mempool->memblocks_priv_arr[i] == NULL) {
94
95                         vxge_hal_err_log_mm("memblock_priv[%d]: \
96                             out of virtual memory, "
97                             "requested %d(%d:%d) bytes", i,
98                             mempool->items_priv_size * n_items,
99                             mempool->items_priv_size, n_items);
100                         vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
101                             __FILE__, __func__, __LINE__,
102                             VXGE_HAL_ERR_OUT_OF_MEMORY);
103                         return (VXGE_HAL_ERR_OUT_OF_MEMORY);
104
105                 }
106
107                 vxge_os_memzero(mempool->memblocks_priv_arr[i],
108                     mempool->items_priv_size * n_items);
109
110                 /* allocate DMA-capable memblock */
111                 mempool->memblocks_arr[i] =
112                     __hal_blockpool_malloc(mempool->devh,
113                     mempool->memblock_size,
114                     &dma_object->addr,
115                     &dma_object->handle,
116                     &dma_object->acc_handle);
117                 if (mempool->memblocks_arr[i] == NULL) {
118                         vxge_os_free(
119                             ((__hal_device_t *) mempool->devh)->header.pdev,
120                             mempool->memblocks_priv_arr[i],
121                             mempool->items_priv_size * n_items);
122                         vxge_hal_err_log_mm("memblock[%d]: \
123                             out of DMA memory", i);
124                         vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
125                             __FILE__, __func__, __LINE__,
126                             VXGE_HAL_ERR_OUT_OF_MEMORY);
127                         return (VXGE_HAL_ERR_OUT_OF_MEMORY);
128                 }
129
130                 (*num_allocated)++;
131                 mempool->memblocks_allocated++;
132
133                 vxge_os_memzero(mempool->memblocks_arr[i],
134                     mempool->memblock_size);
135
136                 the_memblock = mempool->memblocks_arr[i];
137
138                 /* fill the items hash array */
139                 for (j = 0; j < n_items; j++) {
140                         item_index = i * n_items + j;
141
142                         if (first_time && (item_index >= mempool->items_initial))
143                                 break;
144
145                         mempool->items_arr[item_index] =
146                             ((char *) the_memblock + j *mempool->item_size);
147
148                         /* let caller to do more job on each item */
149                         if (mempool->item_func_alloc != NULL) {
150                                 vxge_hal_status_e status;
151
152                                 if ((status = mempool->item_func_alloc(
153                                     mempool,
154                                     the_memblock,
155                                     i,
156                                     dma_object,
157                                     mempool->items_arr[item_index],
158                                     item_index,
159                                     is_last,
160                                     mempool->userdata)) != VXGE_HAL_OK) {
161
162                                         if (mempool->item_func_free != NULL) {
163
164                                                 for (k = 0; k < j; k++) {
165
166                                                         item_index = i * n_items + k;
167
168                                                         (void) mempool->item_func_free(
169                                                             mempool,
170                                                             the_memblock,
171                                                             i, dma_object,
172                                                             mempool->items_arr[item_index],
173                                                             item_index, is_last,
174                                                             mempool->userdata);
175                                                 }
176                                         }
177
178                                         vxge_os_free(((__hal_device_t *)
179                                             mempool->devh)->header.pdev,
180                                             mempool->memblocks_priv_arr[i],
181                                             mempool->items_priv_size *
182                                             n_items);
183
184                                         __hal_blockpool_free(mempool->devh,
185                                             the_memblock,
186                                             mempool->memblock_size,
187                                             &dma_object->addr,
188                                             &dma_object->handle,
189                                             &dma_object->acc_handle);
190
191                                         (*num_allocated)--;
192                                         mempool->memblocks_allocated--;
193                                         return (status);
194                                 }
195                         }
196
197                         mempool->items_current = item_index + 1;
198                 }
199
200                 vxge_hal_info_log_mm(
201                     "memblock%d: allocated %dk, vaddr 0x"VXGE_OS_STXFMT", "
202                     "dma_addr 0x"VXGE_OS_STXFMT,
203                     i, mempool->memblock_size / 1024,
204                     (ptr_t) mempool->memblocks_arr[i], dma_object->addr);
205
206                 if (first_time && mempool->items_current ==
207                     mempool->items_initial) {
208                         break;
209                 }
210         }
211
212         vxge_hal_trace_log_mm("<== %s:%s:%d  Result: 0",
213             __FILE__, __func__, __LINE__);
214
215         return (VXGE_HAL_OK);
216 }
217
218 /*
219  * vxge_hal_mempool_create
220  * @memblock_size:
221  * @items_initial:
222  * @items_max:
223  * @item_size:
224  * @item_func:
225  *
226  * This function will create memory pool object. Pool may grow but will
227  * never shrink. Pool consists of number of dynamically allocated blocks
228  * with size enough to hold %items_initial number of items. Memory is
229  * DMA-able but client must map/unmap before interoperating with the device.
230  * See also: vxge_os_dma_map(), vxge_hal_dma_unmap(), vxge_hal_status_e {}.
231  */
232 vxge_hal_mempool_t *
233 vxge_hal_mempool_create(
234     vxge_hal_device_h devh,
235     u32 memblock_size,
236     u32 item_size,
237     u32 items_priv_size,
238     u32 items_initial,
239     u32 items_max,
240     vxge_hal_mempool_item_f item_func_alloc,
241     vxge_hal_mempool_item_f item_func_free,
242     void *userdata)
243 {
244         vxge_hal_status_e status;
245         u32 memblocks_to_allocate;
246         vxge_hal_mempool_t *mempool;
247         __hal_device_t *hldev;
248         u32 allocated;
249
250         vxge_assert(devh != NULL);
251
252         hldev = (__hal_device_t *) devh;
253
254         vxge_hal_trace_log_mm("==> %s:%s:%d",
255             __FILE__, __func__, __LINE__);
256
257         vxge_hal_trace_log_mm(
258             "devh = 0x"VXGE_OS_STXFMT", memblock_size = %d, item_size = %d, "
259             "items_priv_size = %d, items_initial = %d, items_max = %d, "
260             "item_func_alloc = 0x"VXGE_OS_STXFMT", "
261             "item_func_free = 0x"VXGE_OS_STXFMT", "
262             "userdata = 0x"VXGE_OS_STXFMT, (ptr_t) devh,
263             memblock_size, item_size, items_priv_size,
264             items_initial, items_max, (ptr_t) item_func_alloc,
265             (ptr_t) item_func_free, (ptr_t) userdata);
266
267         if (memblock_size < item_size) {
268                 vxge_hal_err_log_mm(
269                     "memblock_size %d < item_size %d: misconfiguration",
270                     memblock_size, item_size);
271                 vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
272                     __FILE__, __func__, __LINE__, VXGE_HAL_FAIL);
273                 return (NULL);
274         }
275
276         mempool = (vxge_hal_mempool_t *) vxge_os_malloc(
277             ((__hal_device_t *) devh)->header.pdev, sizeof(vxge_hal_mempool_t));
278         if (mempool == NULL) {
279                 vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
280                     __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
281                 return (NULL);
282         }
283         vxge_os_memzero(mempool, sizeof(vxge_hal_mempool_t));
284
285         mempool->devh = devh;
286         mempool->memblock_size = memblock_size;
287         mempool->items_max = items_max;
288         mempool->items_initial = items_initial;
289         mempool->item_size = item_size;
290         mempool->items_priv_size = items_priv_size;
291         mempool->item_func_alloc = item_func_alloc;
292         mempool->item_func_free = item_func_free;
293         mempool->userdata = userdata;
294
295         mempool->memblocks_allocated = 0;
296
297         if (memblock_size != VXGE_OS_HOST_PAGE_SIZE)
298                 mempool->dma_flags = VXGE_OS_DMA_CACHELINE_ALIGNED;
299
300 #if defined(VXGE_HAL_DMA_CONSISTENT)
301         mempool->dma_flags |= VXGE_OS_DMA_CONSISTENT;
302 #else
303         mempool->dma_flags |= VXGE_OS_DMA_STREAMING;
304 #endif
305
306         mempool->items_per_memblock = memblock_size / item_size;
307
308         mempool->memblocks_max = (items_max + mempool->items_per_memblock - 1) /
309             mempool->items_per_memblock;
310
311         /* allocate array of memblocks */
312         mempool->memblocks_arr = (void **)vxge_os_malloc(
313             ((__hal_device_t *) mempool->devh)->header.pdev,
314             sizeof(void *) * mempool->memblocks_max);
315         if (mempool->memblocks_arr == NULL) {
316                 vxge_hal_mempool_destroy(mempool);
317                 vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
318                     __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
319                 return (NULL);
320         }
321         vxge_os_memzero(mempool->memblocks_arr,
322             sizeof(void *) * mempool->memblocks_max);
323
324         /* allocate array of private parts of items per memblocks */
325         mempool->memblocks_priv_arr = (void **)vxge_os_malloc(
326             ((__hal_device_t *) mempool->devh)->header.pdev,
327             sizeof(void *) * mempool->memblocks_max);
328         if (mempool->memblocks_priv_arr == NULL) {
329                 vxge_hal_mempool_destroy(mempool);
330                 vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
331                     __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
332                 return (NULL);
333         }
334         vxge_os_memzero(mempool->memblocks_priv_arr,
335             sizeof(void *) * mempool->memblocks_max);
336
337         /* allocate array of memblocks DMA objects */
338         mempool->memblocks_dma_arr =
339             (vxge_hal_mempool_dma_t *) vxge_os_malloc(
340             ((__hal_device_t *) mempool->devh)->header.pdev,
341             sizeof(vxge_hal_mempool_dma_t) * mempool->memblocks_max);
342
343         if (mempool->memblocks_dma_arr == NULL) {
344                 vxge_hal_mempool_destroy(mempool);
345                 vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
346                     __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
347                 return (NULL);
348         }
349         vxge_os_memzero(mempool->memblocks_dma_arr,
350             sizeof(vxge_hal_mempool_dma_t) * mempool->memblocks_max);
351
352         /* allocate hash array of items */
353         mempool->items_arr = (void **)vxge_os_malloc(
354             ((__hal_device_t *) mempool->devh)->header.pdev,
355             sizeof(void *) * mempool->items_max);
356         if (mempool->items_arr == NULL) {
357                 vxge_hal_mempool_destroy(mempool);
358                 vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
359                     __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
360                 return (NULL);
361         }
362         vxge_os_memzero(mempool->items_arr,
363             sizeof(void *) * mempool->items_max);
364
365         mempool->shadow_items_arr = (void **)vxge_os_malloc(
366             ((__hal_device_t *) mempool->devh)->header.pdev,
367             sizeof(void *) * mempool->items_max);
368         if (mempool->shadow_items_arr == NULL) {
369                 vxge_hal_mempool_destroy(mempool);
370                 vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
371                     __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
372                 return (NULL);
373         }
374         vxge_os_memzero(mempool->shadow_items_arr,
375             sizeof(void *) * mempool->items_max);
376
377         /* calculate initial number of memblocks */
378         memblocks_to_allocate = (mempool->items_initial +
379             mempool->items_per_memblock - 1) /
380             mempool->items_per_memblock;
381
382         vxge_hal_info_log_mm("allocating %d memblocks, "
383             "%d items per memblock", memblocks_to_allocate,
384             mempool->items_per_memblock);
385
386         /* pre-allocate the mempool */
387         status = __hal_mempool_grow(mempool, memblocks_to_allocate, &allocated);
388         vxge_os_memcpy(mempool->shadow_items_arr, mempool->items_arr,
389             sizeof(void *) * mempool->items_max);
390         if (status != VXGE_HAL_OK) {
391                 vxge_hal_mempool_destroy(mempool);
392                 vxge_hal_trace_log_mm("<== %s:%s:%d  Result: %d",
393                     __FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
394                 return (NULL);
395         }
396
397         vxge_hal_info_log_mm(
398             "total: allocated %dk of DMA-capable memory",
399             mempool->memblock_size * allocated / 1024);
400
401         vxge_hal_trace_log_mm("<== %s:%s:%d  Result: 0",
402             __FILE__, __func__, __LINE__);
403
404         return (mempool);
405 }
406
407 /*
408  * vxge_hal_mempool_destroy
409  */
410 void
411 vxge_hal_mempool_destroy(
412     vxge_hal_mempool_t *mempool)
413 {
414         u32 i, j, item_index;
415         __hal_device_t *hldev;
416
417         vxge_assert(mempool != NULL);
418
419         hldev = (__hal_device_t *) mempool->devh;
420
421         vxge_hal_trace_log_mm("==> %s:%s:%d",
422             __FILE__, __func__, __LINE__);
423
424         vxge_hal_trace_log_mm("mempool = 0x"VXGE_OS_STXFMT,
425             (ptr_t) mempool);
426
427         for (i = 0; i < mempool->memblocks_allocated; i++) {
428                 vxge_hal_mempool_dma_t *dma_object;
429
430                 vxge_assert(mempool->memblocks_arr[i]);
431                 vxge_assert(mempool->memblocks_dma_arr + i);
432
433                 dma_object = mempool->memblocks_dma_arr + i;
434
435                 for (j = 0; j < mempool->items_per_memblock; j++) {
436                         item_index = i * mempool->items_per_memblock + j;
437
438                         /* to skip last partially filled(if any) memblock */
439                         if (item_index >= mempool->items_current)
440                                 break;
441
442                         /* let caller to do more job on each item */
443                         if (mempool->item_func_free != NULL) {
444
445                                 mempool->item_func_free(mempool,
446                                     mempool->memblocks_arr[i],
447                                     i, dma_object,
448                                     mempool->shadow_items_arr[item_index],
449                                     item_index, /* unused */ -1,
450                                     mempool->userdata);
451                         }
452                 }
453
454                 vxge_os_free(hldev->header.pdev,
455                     mempool->memblocks_priv_arr[i],
456                     mempool->items_priv_size * mempool->items_per_memblock);
457
458                 __hal_blockpool_free(hldev,
459                     mempool->memblocks_arr[i],
460                     mempool->memblock_size,
461                     &dma_object->addr,
462                     &dma_object->handle,
463                     &dma_object->acc_handle);
464         }
465
466         if (mempool->items_arr) {
467                 vxge_os_free(hldev->header.pdev,
468                     mempool->items_arr, sizeof(void *) * mempool->items_max);
469         }
470
471         if (mempool->shadow_items_arr) {
472                 vxge_os_free(hldev->header.pdev,
473                     mempool->shadow_items_arr,
474                     sizeof(void *) * mempool->items_max);
475         }
476
477         if (mempool->memblocks_dma_arr) {
478                 vxge_os_free(hldev->header.pdev,
479                     mempool->memblocks_dma_arr,
480                     sizeof(vxge_hal_mempool_dma_t) *
481                     mempool->memblocks_max);
482         }
483
484         if (mempool->memblocks_priv_arr) {
485                 vxge_os_free(hldev->header.pdev,
486                     mempool->memblocks_priv_arr,
487                     sizeof(void *) * mempool->memblocks_max);
488         }
489
490         if (mempool->memblocks_arr) {
491                 vxge_os_free(hldev->header.pdev,
492                     mempool->memblocks_arr,
493                     sizeof(void *) * mempool->memblocks_max);
494         }
495
496         vxge_os_free(hldev->header.pdev,
497             mempool, sizeof(vxge_hal_mempool_t));
498
499         vxge_hal_trace_log_mm("<== %s:%s:%d  Result: 0",
500             __FILE__, __func__, __LINE__);
501 }
502
503 /*
504  * vxge_hal_check_alignment - Check buffer alignment    and     calculate the
505  * "misaligned" portion.
506  * @dma_pointer: DMA address of the     buffer.
507  * @size: Buffer size, in bytes.
508  * @alignment: Alignment "granularity" (see     below), in bytes.
509  * @copy_size: Maximum number of bytes to "extract"     from the buffer
510  * (in order to spost it as     a separate scatter-gather entry). See below.
511  *
512  * Check buffer alignment and calculate "misaligned" portion, if exists.
513  * The buffer is considered     aligned if its address is multiple of
514  * the specified @alignment. If this is the     case,
515  * vxge_hal_check_alignment() returns zero.
516  * Otherwise, vxge_hal_check_alignment()        uses the last argument,
517  * @copy_size,
518  * to calculate the     size to "extract" from the buffer. The @copy_size
519  * may or may not be equal @alignment. The difference between these     two
520  * arguments is that the @alignment is used to make the decision: aligned
521  * or not aligned. While the @copy_size is used to calculate the portion
522  * of the buffer to "extract", i.e.     to post as a separate entry in the
523  * transmit descriptor. For example, the combination
524  * @alignment = 8 and @copy_size = 64 will work okay on AMD Opteron boxes.
525  *
526  * Note: @copy_size should be a multiple of @alignment. In many practical
527  * cases @copy_size and @alignment will probably be equal.
528  *
529  * See also: vxge_hal_fifo_txdl_buffer_set_aligned().
530  */
531 u32
532 vxge_hal_check_alignment(
533     dma_addr_t dma_pointer,
534     u32 size,
535     u32 alignment,
536     u32 copy_size)
537 {
538         u32 misaligned_size;
539
540         misaligned_size = (int)(dma_pointer & (alignment - 1));
541         if (!misaligned_size) {
542                 return (0);
543         }
544
545         if (size > copy_size) {
546                 misaligned_size = (int)(dma_pointer & (copy_size - 1));
547                 misaligned_size = copy_size - misaligned_size;
548         } else {
549                 misaligned_size = size;
550         }
551
552         return (misaligned_size);
553 }