Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / pci / n8 / memory / n8_manage_memory.c
blob0a2779d2dc6fea8a453103065f784f03a46a5570
1 /*-
2 * Copyright (C) 2001-2003 by NBMK Encryption Technologies.
3 * All rights reserved.
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>.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are
12 * met:
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 *
42 * *
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 *
46 * *
47 * n8_pmalloc - *
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. *
52 * n8_pfree - *
53 * Replicates standard free() functionality with the same interface. It *
54 * free the block of memory allocated by n8_pmalloc. *
55 * *
56 *****************************************************************************/
58 /*****************************************************************************
59 * Revision history:
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)
82 #include "helper.h"
83 #endif
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 /*****************************************************************************
99 * n8_pmalloc
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.
115 * @par Externals:
116 * Debug_g RO: Switch to enable/disable debug messages. <BR>
118 * @return
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.
123 * @par Errors:
124 * See return section for error information.
125 *****************************************************************************/
127 unsigned long
128 n8_pmalloc(int bank, int bytesReq, unsigned long sessionID)
130 int searchIndex;
131 int searchCount;
132 MemCtlList_t* memCtlPtr;
133 int freeBlocks;
134 int indx;
135 int blocksReq;
136 unsigned long physAddr;
137 #if (defined __KERNEL__) || (defined KERNEL) || (defined VX_BUILD)
138 MemBankCtl_t *memCtl_p = memBankCtl_gp[bank];
139 #else
140 MemBankCtl_t *memCtl_p = requestPoolCtl_gp;
141 #endif
143 if (memCtl_p == NULL)
145 return 0;
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)
152 blocksReq++;
155 /* ENSURE VALID SIZE AND BANK PARAMETERS AND A NON-NULL ALLOCATION LIST */
156 if (!blocksReq)
158 if (!blocksReq)
160 PRINTK("n8_pmalloc: Invalid allocation size: %d\n",blocksReq);
162 return 0;
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;
171 searchCount = 0;
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. */
184 if (blocksReq == 1)
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));
203 return (physAddr);
206 /* We have a free block, check for enough continuous blocks to honor */
207 /* this request. */
208 freeBlocks = 1;
210 while (((searchIndex + freeBlocks) < memCtl_p->maxEntries) &&
211 (!memCtlPtr[searchIndex + freeBlocks].numBlocks))
213 freeBlocks++;
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));
240 return (physAddr);
243 searchIndex = (searchIndex + freeBlocks) % memCtl_p->maxEntries;
244 searchCount += freeBlocks;
246 else
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",
259 blocksReq);
261 memCtl_p->failedAllocs++;
262 return 0;
268 /*****************************************************************************
269 * n8_pfree
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
279 * from.
280 * @param ptr RO: Void pointer to the physical base address of the chunk to
281 * be returned to the memory bank.
283 * @par Externals:
284 * Debug_g RO: Global flag that indicates whether debugging<BR>
285 * messages are enabled. <BR>
287 * @return
288 * N/A
290 * @par Errors:
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;
301 int index;
302 int count;
303 int numBlocks;
304 #if (defined __KERNEL__) || (defined KERNEL) || (defined VX_BUILD)
305 MemBankCtl_t *memCtl_p = memBankCtl_gp[bank];
306 #else
307 MemBankCtl_t *memCtl_p = requestPoolCtl_gp;
308 #endif
311 if (memCtl_p == NULL)
313 return;
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);
330 #else
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);
338 #endif
341 return;