xref: /reactos/drivers/network/ndis/ndis/memory.c (revision 34593d93)
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
NdisAllocateMemoryWithTag(OUT PVOID * VirtualAddress,IN UINT Length,IN ULONG Tag)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
NdisAllocateMemory(OUT PVOID * VirtualAddress,IN UINT Length,IN UINT MemoryFlags,IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress)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
NdisFreeMemory(IN PVOID VirtualAddress,IN UINT Length,IN UINT MemoryFlags)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
NdisMAllocateSharedMemory(IN NDIS_HANDLE MiniportAdapterHandle,IN ULONG Length,IN BOOLEAN Cached,OUT PVOID * VirtualAddress,OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress)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
NdisMFreeSharedMemoryPassive(PDEVICE_OBJECT DeviceObject,PVOID Context)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
NdisMFreeSharedMemory(IN NDIS_HANDLE MiniportAdapterHandle,IN ULONG Length,IN BOOLEAN Cached,IN PVOID VirtualAddress,IN NDIS_PHYSICAL_ADDRESS PhysicalAddress)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
NdisMAllocateSharedMemoryPassive(PDEVICE_OBJECT DeviceObject,PVOID Context)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
NdisMAllocateSharedMemoryAsync(IN NDIS_HANDLE MiniportAdapterHandle,IN ULONG Length,IN BOOLEAN Cached,IN PVOID Context)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
NdisAllocateSharedMemory(IN NDIS_HANDLE NdisAdapterHandle,IN ULONG Length,IN BOOLEAN Cached,OUT PVOID * VirtualAddress,OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress)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
NdisFreeSharedMemory(IN NDIS_HANDLE NdisAdapterHandle,IN ULONG Length,IN BOOLEAN Cached,IN PVOID VirtualAddress,IN NDIS_PHYSICAL_ADDRESS PhysicalAddress)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