2 * Copyright (C) 2001-2003 by NBMK Encryption Technologies.
5 * NBMK Encryption Technologies provides no support of any kind for
6 * this software. Questions or concerns about it may be addressed to
7 * the members of the relevant open-source community at
8 * <tech-crypto@netbsd.org>.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above
18 * copyright notice, this list of conditions and the following
19 * disclaimer in the documentation and/or other materials provided
20 * with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 /*****************************************************************************
36 * @(#) n8_memory.c 1.1@(#)
37 *****************************************************************************/
39 /*****************************************************************************/
40 /** @file n8_manage_memory.c *
41 * @brief Memory Services - Cross-Platform *
43 * This file implements the portions of the memory allocation and management *
44 * service for the NSP2000 devices which are available from both user and *
45 * kernel space. The most important of these are *
48 * Replicates standard malloc() functionality with a similar interface. *
49 * Allocates a block of memory from a pool that is safe to perform DMA *
50 * operations to/from since is has been allocated and locked down by *
51 * the device driver. *
53 * Replicates standard free() functionality with the same interface. It *
54 * free the block of memory allocated by n8_pmalloc. *
56 *****************************************************************************/
58 /*****************************************************************************
60 * 05/07/03 brr Moved n8_calculateSize & n8_setupAllocateMemory into the
61 * kernel. Updated comments.
62 * 04/21/03 brr Added support for multiple memory banks.
63 * 10/25/02 brr Clean up function prototypes & include files.
64 * 07/29/02 jpw n8_pmalloc - SearchCount must be changed before searchIndex
65 * when scanning for free blocks - prevents false pmalloc failures
66 * 07/11/02 brr Round memBankPtr up to next granularity.
67 * 07/01/02 brr Ensure all operations on curAllocated are atomic.
68 * 06/27/02 brr Removed bank parameter from call to N8_PhysToVirt.
69 * 06/25/02 brr Moved n8_displayMemory to n8_memory.c.
70 * 06/14/02 hml Release semaphore at the bottom of n8_pmalloc.
71 * 06/12/02 hml Calls to N8_PhysToVirt now take the bank parameter.
72 * 06/11/02 hml Use the processSem ops instead of the *ATOMIC* ops.
73 * 06/10/02 hml Updated comments.
74 * 06/10/02 hml New file with functionality taken from n8_memory.c.
75 ****************************************************************************/
76 /** @defgroup NSP2000Driver Memory Allocation Services - Cross-Platform.
80 #include "n8_OS_intf.h"
81 #if (defined __KERNEL__) || (defined KERNEL)
84 #include "n8_malloc_common.h"
85 #include "n8_semaphore.h"
87 /* LOCAL GLOBAL THAT INDICATES WHETHER DEBUGGING MESSAGES ARE ENABLED */
88 static int DebugFlag_g
= 0;
90 /* The memory bank controller for the request pool */
91 extern MemBankCtl_t
*requestPoolCtl_gp
;
92 extern MemBankCtl_t
*memBankCtl_gp
[];
95 /* MACROS FOR READABILITY */
96 #define PRINTK if (DebugFlag_g) N8_PRINT
98 /*****************************************************************************
100 *****************************************************************************/
101 /** @ingroup NSP2000Driver
102 * @brief API - Allocates a portion of the large space.
104 * This routine allocates a portion of the large space, from within the
105 * specified bank, and returns a pointer to the physical address of
106 * the portion. This routine is meant to be equivalent to a standard
107 * malloc() sort of system call.
109 * @param bank RW: Specifies the bank from which to allocate. The
110 * allocation map inside the bank is updated.
111 * @param bytesReq RO: Specifies the number of bytes to be allocated
112 * @param sessionID RO: The sessionID doing the allocation.
116 * Debug_g RO: Switch to enable/disable debug messages. <BR>
119 * NULL pointer if there's insufficient free space in the big alloc.
120 * non-NULL void virtual pointer to the base virtual address of the
121 * desired chunk of the big allocation.
124 * See return section for error information.
125 *****************************************************************************/
128 n8_pmalloc(int bank
, int bytesReq
, unsigned long sessionID
)
132 MemCtlList_t
* memCtlPtr
;
136 unsigned long physAddr
;
137 #if (defined __KERNEL__) || (defined KERNEL) || (defined VX_BUILD)
138 MemBankCtl_t
*memCtl_p
= memBankCtl_gp
[bank
];
140 MemBankCtl_t
*memCtl_p
= requestPoolCtl_gp
;
143 if (memCtl_p
== NULL
)
147 PRINTK("n8_pmalloc: bytes requested = %d, sessionID = %lx \n",
148 bytesReq
, sessionID
);
149 blocksReq
= bytesReq
/ memCtl_p
->granularity
;
150 if (bytesReq
% memCtl_p
->granularity
)
155 /* ENSURE VALID SIZE AND BANK PARAMETERS AND A NON-NULL ALLOCATION LIST */
160 PRINTK("n8_pmalloc: Invalid allocation size: %d\n",blocksReq
);
165 /* LOCK ALLOCATION LIST */
166 N8_acquireProcessSem(&memCtl_p
->allocationMapLock
);
168 /* LOCATE THE BEGINNING OF THIS BANK */
169 memCtlPtr
= &memCtl_p
->memCtlList
[0];
170 searchIndex
= memCtl_p
->nextIndex
;
173 /* Memory blocks are free if the numBlocks field is zero, The */
174 /* nextIndex is our best guess at the next freeBlock but is */
175 /* not guarenteed. */
176 while (searchCount
< memCtl_p
->maxEntries
)
179 if (memCtlPtr
[searchIndex
].numBlocks
== 0)
182 /* Handle the simple case of a single block first in order to */
183 /* optimize the majority of the requests. */
186 memCtlPtr
[searchIndex
].sessionID
= sessionID
;
187 memCtlPtr
[searchIndex
].numBlocks
= blocksReq
;
188 memCtlPtr
[searchIndex
].reqSize
= bytesReq
;
190 /* Update the next search index with our best guess */
191 memCtl_p
->nextIndex
= (searchIndex
+ 1) % memCtl_p
->maxEntries
;
192 n8_atomic_add(memCtl_p
->curAllocated
, 1);
194 /* Check high water mark to see if it needs updated. */
195 if (n8_atomic_read(memCtl_p
->curAllocated
) > memCtl_p
->maxAllocated
)
197 memCtl_p
->maxAllocated
= n8_atomic_read(memCtl_p
->curAllocated
);
200 N8_releaseProcessSem(&memCtl_p
->allocationMapLock
);
201 physAddr
= (unsigned long)(memCtl_p
->memBankPtr
+
202 (searchIndex
* memCtl_p
->granularity
));
206 /* We have a free block, check for enough continuous blocks to honor */
210 while (((searchIndex
+ freeBlocks
) < memCtl_p
->maxEntries
) &&
211 (!memCtlPtr
[searchIndex
+ freeBlocks
].numBlocks
))
215 /* We have found a sufficient number of free blocks, return them */
216 if (blocksReq
== freeBlocks
)
218 /* Mark the first block with the sessionID & requested bytes */
219 memCtlPtr
[searchIndex
].sessionID
= sessionID
;
220 memCtlPtr
[searchIndex
].reqSize
= bytesReq
;
222 /* Mark the each block with allocated blocks */
223 for (indx
= 0; indx
< blocksReq
; indx
++)
225 memCtlPtr
[searchIndex
+ indx
].numBlocks
= blocksReq
;
228 /* Update the next search index with our best guess */
229 memCtl_p
->nextIndex
= (searchIndex
+ blocksReq
) % memCtl_p
->maxEntries
;
231 /* Check high water mark to see if it needs updated. */
232 n8_atomic_add(memCtl_p
->curAllocated
, blocksReq
);
233 if (n8_atomic_read(memCtl_p
->curAllocated
) > memCtl_p
->maxAllocated
)
235 memCtl_p
->maxAllocated
= n8_atomic_read(memCtl_p
->curAllocated
);
237 N8_releaseProcessSem(&memCtl_p
->allocationMapLock
);
238 physAddr
= (unsigned long)(memCtl_p
->memBankPtr
+
239 (searchIndex
* memCtl_p
->granularity
));
243 searchIndex
= (searchIndex
+ freeBlocks
) % memCtl_p
->maxEntries
;
244 searchCount
+= freeBlocks
;
248 /* Note - SearchCount must be changed BEFORE searchIndex is changed */
249 searchCount
+= memCtlPtr
[searchIndex
].numBlocks
;
250 searchIndex
= (searchIndex
+ memCtlPtr
[searchIndex
].numBlocks
) % memCtl_p
->maxEntries
;
253 N8_releaseProcessSem(&memCtl_p
->allocationMapLock
);
255 /* Only log failure message on the first occurance */
256 if (!memCtl_p
->failedAllocs
)
258 N8_PRINT(KERN_CRIT
"NSP2000: kmalloc FAILURE unable to allocate %d blocks.\n",
261 memCtl_p
->failedAllocs
++;
268 /*****************************************************************************
270 *****************************************************************************/
271 /** @ingroup NSP2000Driver
272 * @brief API - Releases a suballocation of the large allocated space.
274 * This routine returns the memory allocated by the physical address to the
275 * memory pool. The length is calculated so only the bank need be specified.
278 * @param bank RO: Specifies the bank from which the memory was allocated
280 * @param ptr RO: Void pointer to the physical base address of the chunk to
281 * be returned to the memory bank.
284 * Debug_g RO: Global flag that indicates whether debugging<BR>
285 * messages are enabled. <BR>
291 * See return section for error information.
293 * NOTE: THIS FUNCTION MAY BE CALLED FROM INTERRUPT CONTEXT and cannot take
294 * semaphores or print.
295 *****************************************************************************/
297 void n8_pfree(int bank
, void *ptr
)
300 MemCtlList_t
* memCtlPtr
;
304 #if (defined __KERNEL__) || (defined KERNEL) || (defined VX_BUILD)
305 MemBankCtl_t
*memCtl_p
= memBankCtl_gp
[bank
];
307 MemBankCtl_t
*memCtl_p
= requestPoolCtl_gp
;
311 if (memCtl_p
== NULL
)
316 memCtlPtr
= &memCtl_p
->memCtlList
[0];
317 index
= ((unsigned long)ptr
- (int)memCtl_p
->memBankPtr
)/memCtl_p
->granularity
;
319 /* Verify pointer is within the address range of our preallocated pool */
320 if (((char *)ptr
>= memCtl_p
->memBankPtr
) && (index
< memCtl_p
->maxEntries
))
322 numBlocks
= memCtlPtr
[index
].numBlocks
;
323 for (count
= 0; count
<numBlocks
; count
++)
325 memCtlPtr
[index
+count
].sessionID
= 0;
326 memCtlPtr
[index
+count
].numBlocks
= 0;
328 #if (defined __KERNEL__) || (defined KERNEL)
329 n8_atomic_sub(memCtl_p
->curAllocated
, numBlocks
);
331 /* In user space there is no atomic operation available, so it */
332 /* is necessary to take the semaphore to ensure the operation */
333 /* is atomic. The n8_atomic_sub is an abstraction that merely */
334 /* equates to integer subtraction in user space. */
335 N8_acquireProcessSem(&memCtl_p
->allocationMapLock
);
336 n8_atomic_sub(memCtl_p
->curAllocated
, numBlocks
);
337 N8_releaseProcessSem(&memCtl_p
->allocationMapLock
);