* Sync up to trunk r55544.
[reactos.git] / drivers / network / ndis / ndis / memory.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS library
4 * FILE: ndis/memory.c
5 * PURPOSE: Memory management routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Vizzini (vizzini@plasmic.com)
8 * REVISIONS:
9 * CSH 01/08-2000 Created
10 * 15 Aug 2003 Vizzini - DMA support
11 * 3 Oct 2003 Vizzini - formatting and minor bugfixing
12 */
13
14 #include "ndissys.h"
15
16 \f
17 /*
18 * @implemented
19 */
20 NDIS_STATUS
21 EXPORT
22 NdisAllocateMemoryWithTag(
23 OUT PVOID *VirtualAddress,
24 IN UINT Length,
25 IN ULONG Tag)
26 /*
27 * FUNCTION: Allocates a block of memory, with a 32-bit tag
28 * ARGUMENTS:
29 * VirtualAddress = a pointer to the returned memory block
30 * Length = the number of requested bytes
31 * Tag = 32-bit pool tag
32 * RETURNS:
33 * NDIS_STATUS_SUCCESS on success
34 * NDIS_STATUS_FAILURE on failure
35 */
36 {
37 PVOID Block;
38
39 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
40
41 Block = ExAllocatePoolWithTag(NonPagedPool, Length, Tag);
42 *VirtualAddress = Block;
43
44 if (!Block) {
45 NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate memory (%lx)\n", Length));
46 return NDIS_STATUS_FAILURE;
47 }
48
49 return NDIS_STATUS_SUCCESS;
50 }
51
52
53 \f
54 /*
55 * @implemented
56 */
57 NDIS_STATUS
58 EXPORT
59 NdisAllocateMemory(
60 OUT PVOID *VirtualAddress,
61 IN UINT Length,
62 IN UINT MemoryFlags,
63 IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress)
64 /*
65 * FUNCTION: Allocates a block of memory
66 * ARGUMENTS:
67 * VirtualAddress = Address of buffer to place virtual
68 * address of the allocated memory
69 * Length = Size of the memory block to allocate
70 * MemoryFlags = Flags to specify special restrictions
71 * HighestAcceptableAddress = Specifies -1
72 * RETURNS:
73 * NDIS_STATUS_SUCCESS on success
74 * NDIS_STATUS_FAILURE on failure
75 */
76 {
77 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
78
79 if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS)
80 {
81 /* Allocate contiguous memory (possibly noncached) */
82 *VirtualAddress = MmAllocateContiguousMemorySpecifyCache(Length,
83 RtlConvertUlongToLargeInteger(0),
84 HighestAcceptableAddress,
85 RtlConvertUlongToLargeInteger(0),
86 (MemoryFlags & NDIS_MEMORY_NONCACHED) ? MmNonCached : MmCached);
87 }
88 else if (MemoryFlags & NDIS_MEMORY_NONCACHED)
89 {
90 /* Allocate noncached noncontiguous memory */
91 *VirtualAddress = MmAllocateNonCachedMemory(Length);
92 }
93 else
94 {
95 /* Allocate plain nonpaged memory */
96 *VirtualAddress = ExAllocatePool(NonPagedPool, Length);
97 }
98
99 if (!*VirtualAddress) {
100 NDIS_DbgPrint(MIN_TRACE, ("Allocation failed (%lx, %lx)\n", MemoryFlags, Length));
101 return NDIS_STATUS_FAILURE;
102 }
103
104 return NDIS_STATUS_SUCCESS;
105 }
106
107 \f
108 /*
109 * @implemented
110 */
111 VOID
112 EXPORT
113 NdisFreeMemory(
114 IN PVOID VirtualAddress,
115 IN UINT Length,
116 IN UINT MemoryFlags)
117 /*
118 * FUNCTION: Frees a memory block allocated with NdisAllocateMemory
119 * ARGUMENTS:
120 * VirtualAddress = Pointer to the base virtual address of the allocated memory
121 * Length = Size of the allocated memory block as passed to NdisAllocateMemory
122 * MemoryFlags = Memory flags passed to NdisAllocateMemory
123 */
124 {
125 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
126
127 if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS)
128 {
129 /* Free contiguous memory (possibly noncached) */
130 MmFreeContiguousMemorySpecifyCache(VirtualAddress,
131 Length,
132 (MemoryFlags & NDIS_MEMORY_NONCACHED) ? MmNonCached : MmCached);
133 }
134 else if (MemoryFlags & NDIS_MEMORY_NONCACHED)
135 {
136 /* Free noncached noncontiguous memory */
137 MmFreeNonCachedMemory(VirtualAddress, Length);
138 }
139 else
140 {
141 /* Free nonpaged pool */
142 ExFreePool(VirtualAddress);
143 }
144 }
145
146 \f
147 /*
148 * @implemented
149 */
150 VOID
151 EXPORT
152 NdisMAllocateSharedMemory(
153 IN NDIS_HANDLE MiniportAdapterHandle,
154 IN ULONG Length,
155 IN BOOLEAN Cached,
156 OUT PVOID *VirtualAddress,
157 OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress)
158 /*
159 * FUNCTION: Allocate a common buffer for DMA
160 * ARGUMENTS:
161 * MiniportAdapterHandle: Handle passed into MiniportInitialize
162 * Length: Number of bytes to allocate
163 * Cached: Whether or not the memory can be cached
164 * VirtualAddress: Pointer to memory is returned here
165 * PhysicalAddress: Physical address corresponding to virtual address
166 * NOTES:
167 * - Cached is ignored; we always allocate non-cached
168 */
169 {
170 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
171
172 NDIS_DbgPrint(MAX_TRACE,("Called.\n"));
173
174 if (KeGetCurrentIrql() != PASSIVE_LEVEL)
175 {
176 KeBugCheckEx(BUGCODE_ID_DRIVER,
177 (ULONG_PTR)MiniportAdapterHandle,
178 Length,
179 0,
180 1);
181 }
182
183 *VirtualAddress = Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->AllocateCommonBuffer(
184 Adapter->NdisMiniportBlock.SystemAdapterObject, Length, PhysicalAddress, Cached);
185 }
186
187 \f
188 VOID
189 NTAPI
190 NdisMFreeSharedMemoryPassive(
191 PDEVICE_OBJECT DeviceObject,
192 PVOID Context)
193 /*
194 * FUNCTION: Free a common buffer
195 * ARGUMENTS:
196 * Context: Pointer to a miniport shared memory context
197 * NOTES:
198 * - Called by NdisMFreeSharedMemory to do the actual work
199 */
200 {
201 PMINIPORT_SHARED_MEMORY Memory = (PMINIPORT_SHARED_MEMORY)Context;
202
203 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
204
205 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
206
207 Memory->AdapterObject->DmaOperations->FreeCommonBuffer(
208 Memory->AdapterObject, Memory->Length, Memory->PhysicalAddress,
209 Memory->VirtualAddress, Memory->Cached);
210
211 IoFreeWorkItem(Memory->WorkItem);
212 ExFreePool(Memory);
213 }
214
215 \f
216 /*
217 * @implemented
218 */
219 VOID
220 EXPORT
221 NdisMFreeSharedMemory(
222 IN NDIS_HANDLE MiniportAdapterHandle,
223 IN ULONG Length,
224 IN BOOLEAN Cached,
225 IN PVOID VirtualAddress,
226 IN NDIS_PHYSICAL_ADDRESS PhysicalAddress)
227 /*
228 * FUNCTION: Free a shared memory block
229 * ARGUMENTS:
230 * MiniportAdapterHandle: Handle passed into MiniportInitialize
231 * Length: Number of bytes in the block to free
232 * Cached: Whether or not the memory was cached
233 * VirtualAddress: Address to free
234 * PhysicalAddress: corresponding physical addres
235 * NOTES:
236 * - This function can be called at dispatch_level or passive_level.
237 * Therefore we have to do this in a worker thread.
238 */
239 {
240 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
241 PMINIPORT_SHARED_MEMORY Memory;
242 PDMA_ADAPTER DmaAdapter = Adapter->NdisMiniportBlock.SystemAdapterObject;
243
244 NDIS_DbgPrint(MAX_TRACE,("Called.\n"));
245
246 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
247
248 /* Call FreeCommonBuffer synchronously if we are at PASSIVE_LEVEL */
249 if (KeGetCurrentIrql() == PASSIVE_LEVEL)
250 {
251 /* We need this case because we free shared memory asynchronously
252 * and the miniport (and DMA adapter object) could be freed before
253 * our work item executes. Lucky for us, the scenarios where the
254 * freeing needs to be synchronous (failed init, MiniportHalt,
255 * and driver unload) are all at PASSIVE_LEVEL so we can just
256 * call FreeCommonBuffer synchronously and not have to worry
257 * about the miniport falling out from under us */
258
259 NDIS_DbgPrint(MID_TRACE,("Freeing shared memory synchronously\n"));
260
261 DmaAdapter->DmaOperations->FreeCommonBuffer(DmaAdapter,
262 Length,
263 PhysicalAddress,
264 VirtualAddress,
265 Cached);
266 return;
267 }
268
269 /* Must be NonpagedPool because by definition we're at DISPATCH_LEVEL */
270 Memory = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_SHARED_MEMORY));
271
272 if(!Memory)
273 {
274 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
275 return;
276 }
277
278 Memory->AdapterObject = Adapter->NdisMiniportBlock.SystemAdapterObject;
279 Memory->Length = Length;
280 Memory->PhysicalAddress = PhysicalAddress;
281 Memory->VirtualAddress = VirtualAddress;
282 Memory->Cached = Cached;
283 Memory->Adapter = &Adapter->NdisMiniportBlock;
284
285 Memory->WorkItem = IoAllocateWorkItem(Adapter->NdisMiniportBlock.DeviceObject);
286 if (!Memory->WorkItem)
287 {
288 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
289 ExFreePool(Memory);
290 return;
291 }
292
293 IoQueueWorkItem(Memory->WorkItem,
294 NdisMFreeSharedMemoryPassive,
295 CriticalWorkQueue,
296 Memory);
297 }
298
299 VOID
300 NTAPI
301 NdisMAllocateSharedMemoryPassive(
302 PDEVICE_OBJECT DeviceObject,
303 PVOID Context)
304 /*
305 * FUNCTION: Allocate a common buffer
306 * ARGUMENTS:
307 * Context: Pointer to a miniport shared memory context
308 * NOTES:
309 * - Called by NdisMAllocateSharedMemoryAsync to do the actual work
310 */
311 {
312 PMINIPORT_SHARED_MEMORY Memory = (PMINIPORT_SHARED_MEMORY)Context;
313
314 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
315
316 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
317
318 Memory->VirtualAddress = Memory->AdapterObject->DmaOperations->AllocateCommonBuffer(
319 Memory->AdapterObject, Memory->Length, &Memory->PhysicalAddress, Memory->Cached);
320
321 if (Memory->Adapter->DriverHandle->MiniportCharacteristics.AllocateCompleteHandler)
322 Memory->Adapter->DriverHandle->MiniportCharacteristics.AllocateCompleteHandler(
323 Memory->Adapter->MiniportAdapterContext, Memory->VirtualAddress,
324 &Memory->PhysicalAddress, Memory->Length, Memory->Context);
325
326 IoFreeWorkItem(Memory->WorkItem);
327 ExFreePool(Memory);
328 }
329
330
331 /*
332 * @implemented
333 */
334 NDIS_STATUS
335 EXPORT
336 NdisMAllocateSharedMemoryAsync(
337 IN NDIS_HANDLE MiniportAdapterHandle,
338 IN ULONG Length,
339 IN BOOLEAN Cached,
340 IN PVOID Context)
341 {
342 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
343 PMINIPORT_SHARED_MEMORY Memory;
344
345 NDIS_DbgPrint(MAX_TRACE,("Called.\n"));
346
347 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
348
349 /* Must be NonpagedPool because by definition we're at DISPATCH_LEVEL */
350 Memory = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_SHARED_MEMORY));
351
352 if(!Memory)
353 {
354 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
355 return NDIS_STATUS_FAILURE;
356 }
357
358 Memory->AdapterObject = Adapter->NdisMiniportBlock.SystemAdapterObject;
359 Memory->Length = Length;
360 Memory->Cached = Cached;
361 Memory->Adapter = &Adapter->NdisMiniportBlock;
362 Memory->Context = Context;
363
364 Memory->WorkItem = IoAllocateWorkItem(Adapter->NdisMiniportBlock.DeviceObject);
365 if (!Memory->WorkItem)
366 {
367 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
368 ExFreePool(Memory);
369 return NDIS_STATUS_FAILURE;
370 }
371
372 IoQueueWorkItem(Memory->WorkItem,
373 NdisMAllocateSharedMemoryPassive,
374 DelayedWorkQueue,
375 Memory);
376
377 return NDIS_STATUS_PENDING;
378 }
379
380 /*
381 * @implemented
382 */
383 VOID
384 EXPORT
385 NdisAllocateSharedMemory(
386 IN NDIS_HANDLE NdisAdapterHandle,
387 IN ULONG Length,
388 IN BOOLEAN Cached,
389 OUT PVOID *VirtualAddress,
390 OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress)
391 {
392 NdisMAllocateSharedMemory(NdisAdapterHandle,
393 Length,
394 Cached,
395 VirtualAddress,
396 PhysicalAddress);
397 }
398
399
400 /*
401 * @implemented
402 */
403 VOID
404 EXPORT
405 NdisFreeSharedMemory(
406 IN NDIS_HANDLE NdisAdapterHandle,
407 IN ULONG Length,
408 IN BOOLEAN Cached,
409 IN PVOID VirtualAddress,
410 IN NDIS_PHYSICAL_ADDRESS PhysicalAddress)
411 /*
412 * FUNCTION:
413 * ARGUMENTS:
414 * NOTES:
415 * NDIS 4.0
416 */
417 {
418 NdisMFreeSharedMemory(NdisAdapterHandle,
419 Length,
420 Cached,
421 VirtualAddress,
422 PhysicalAddress);
423 }
424
425
426 /* EOF */
427