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