]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.c
Remove some useless EDK_RELEASE_VERSION, EFI_SPECIFICATION_VERSION ,and review VALID_...
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / UhciDxe / UsbHcMem.c
CommitLineData
913cb9dc 1/** @file\r
2\r
ab6495ea 3 The routine procedure for uhci memory allocate/free.\r
4\r
913cb9dc 5Copyright (c) 2007, Intel Corporation\r
6All rights reserved. This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
913cb9dc 14**/\r
15\r
16#include "Uhci.h"\r
17\r
18\r
913cb9dc 19/**\r
ab6495ea 20 Allocate a block of memory to be used by the buffer pool.\r
913cb9dc 21\r
ab6495ea 22 @param Pool The buffer pool to allocate memory for.\r
23 @param Pages How many pages to allocate.\r
913cb9dc 24\r
ab6495ea 25 @return The allocated memory block or NULL if failed.\r
913cb9dc 26\r
27**/\r
913cb9dc 28USBHC_MEM_BLOCK *\r
29UsbHcAllocMemBlock (\r
30 IN USBHC_MEM_POOL *Pool,\r
31 IN UINTN Pages\r
32 )\r
33{\r
34 USBHC_MEM_BLOCK *Block;\r
35 EFI_PCI_IO_PROTOCOL *PciIo;\r
36 VOID *BufHost;\r
37 VOID *Mapping;\r
38 EFI_PHYSICAL_ADDRESS MappedAddr;\r
39 UINTN Bytes;\r
40 EFI_STATUS Status;\r
41\r
42 PciIo = Pool->PciIo;\r
43\r
44 Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));\r
45 if (Block == NULL) {\r
46 return NULL;\r
47 }\r
48\r
49 //\r
50 // each bit in the bit array represents USBHC_MEM_UNIT\r
51 // bytes of memory in the memory block.\r
52 //\r
53 ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
54\r
55 Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
56 Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
57 Block->Bits = AllocateZeroPool (Block->BitsLen);\r
58\r
59 if (Block->Bits == NULL) {\r
60 gBS->FreePool (Block);\r
61 return NULL;\r
62 }\r
63\r
64 //\r
65 // Allocate the number of Pages of memory, then map it for\r
66 // bus master read and write.\r
67 //\r
68 Status = PciIo->AllocateBuffer (\r
69 PciIo,\r
70 AllocateAnyPages,\r
71 EfiBootServicesData,\r
72 Pages,\r
73 &BufHost,\r
74 0\r
75 );\r
76\r
77 if (EFI_ERROR (Status)) {\r
78 goto FREE_BITARRAY;\r
79 }\r
80\r
81 Bytes = EFI_PAGES_TO_SIZE (Pages);\r
82 Status = PciIo->Map (\r
83 PciIo,\r
84 EfiPciIoOperationBusMasterCommonBuffer,\r
85 BufHost,\r
86 &Bytes,\r
87 &MappedAddr,\r
88 &Mapping\r
89 );\r
90\r
91 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {\r
92 goto FREE_BUFFER;\r
93 }\r
94\r
95 //\r
96 // Check whether the data structure used by the host controller\r
97 // should be restricted into the same 4G\r
98 //\r
99 if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {\r
100 PciIo->Unmap (PciIo, Mapping);\r
101 goto FREE_BUFFER;\r
102 }\r
103\r
104 Block->BufHost = BufHost;\r
105 Block->Buf = (UINT8 *) ((UINTN) MappedAddr);\r
106 Block->Mapping = Mapping;\r
107\r
913cb9dc 108 return Block;\r
109\r
110FREE_BUFFER:\r
111 PciIo->FreeBuffer (PciIo, Pages, BufHost);\r
112\r
113FREE_BITARRAY:\r
114 gBS->FreePool (Block->Bits);\r
115 gBS->FreePool (Block);\r
116 return NULL;\r
117}\r
118\r
119\r
120/**\r
ab6495ea 121 Free the memory block from the memory pool.\r
913cb9dc 122\r
ab6495ea 123 @param Pool The memory pool to free the block from.\r
124 @param Block The memory block to free.\r
913cb9dc 125\r
ab6495ea 126 @return None.\r
913cb9dc 127\r
128**/\r
913cb9dc 129VOID\r
130UsbHcFreeMemBlock (\r
131 IN USBHC_MEM_POOL *Pool,\r
132 IN USBHC_MEM_BLOCK *Block\r
133 )\r
134{\r
135 EFI_PCI_IO_PROTOCOL *PciIo;\r
136\r
137 ASSERT ((Pool != NULL) && (Block != NULL));\r
138\r
139 PciIo = Pool->PciIo;\r
140\r
141 //\r
142 // Unmap the common buffer then free the structures\r
143 //\r
144 PciIo->Unmap (PciIo, Block->Mapping);\r
145 PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);\r
146\r
147 gBS->FreePool (Block->Bits);\r
148 gBS->FreePool (Block);\r
149}\r
150\r
151\r
152/**\r
ab6495ea 153 Alloc some memory from the block.\r
913cb9dc 154\r
ab6495ea 155 @param Block The memory block to allocate memory from.\r
156 @param Units Number of memory units to allocate.\r
913cb9dc 157\r
ab6495ea 158 @return EFI_SUCCESS The needed memory is allocated.\r
159 @return EFI_NOT_FOUND Can't find the free memory.\r
913cb9dc 160\r
161**/\r
913cb9dc 162VOID *\r
163UsbHcAllocMemFromBlock (\r
164 IN USBHC_MEM_BLOCK *Block,\r
165 IN UINTN Units\r
166 )\r
167{\r
168 UINTN Byte;\r
169 UINT8 Bit;\r
170 UINTN StartByte;\r
171 UINT8 StartBit;\r
172 UINTN Available;\r
173 UINTN Count;\r
174\r
175 ASSERT ((Block != 0) && (Units != 0));\r
176\r
177 StartByte = 0;\r
178 StartBit = 0;\r
179 Available = 0;\r
180\r
181 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
182 //\r
183 // If current bit is zero, the corresponding memory unit is\r
184 // available, otherwise we need to restart our searching.\r
185 // Available counts the consective number of zero bit.\r
186 //\r
187 if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
188 Available++;\r
189\r
190 if (Available >= Units) {\r
191 break;\r
192 }\r
193\r
194 NEXT_BIT (Byte, Bit);\r
195\r
196 } else {\r
197 NEXT_BIT (Byte, Bit);\r
198\r
199 Available = 0;\r
200 StartByte = Byte;\r
201 StartBit = Bit;\r
202 }\r
203 }\r
204\r
205 if (Available < Units) {\r
206 return NULL;\r
207 }\r
208\r
209 //\r
210 // Mark the memory as allocated\r
211 //\r
212 Byte = StartByte;\r
213 Bit = StartBit;\r
214\r
215 for (Count = 0; Count < Units; Count++) {\r
216 ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
217\r
d074a8e1 218 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));\r
913cb9dc 219 NEXT_BIT (Byte, Bit);\r
220 }\r
221\r
222 return Block->Buf + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
223}\r
224\r
225\r
226/**\r
ab6495ea 227 Insert the memory block to the pool's list of the blocks.\r
913cb9dc 228\r
ab6495ea 229 @param Head The head of the memory pool's block list.\r
230 @param Block The memory block to insert.\r
913cb9dc 231\r
ab6495ea 232 @return None.\r
913cb9dc 233\r
234**/\r
913cb9dc 235VOID\r
236UsbHcInsertMemBlockToPool (\r
237 IN USBHC_MEM_BLOCK *Head,\r
238 IN USBHC_MEM_BLOCK *Block\r
239 )\r
240{\r
241 ASSERT ((Head != NULL) && (Block != NULL));\r
242 Block->Next = Head->Next;\r
243 Head->Next = Block;\r
244}\r
245\r
246\r
247/**\r
248 Is the memory block empty?\r
249\r
ab6495ea 250 @param Block The memory block to check.\r
913cb9dc 251\r
ab6495ea 252 @return TRUE The memory block is empty.\r
253 @return FALSE The memory block isn't empty.\r
913cb9dc 254\r
255**/\r
913cb9dc 256BOOLEAN\r
257UsbHcIsMemBlockEmpty (\r
258 IN USBHC_MEM_BLOCK *Block\r
259 )\r
260{\r
261 UINTN Index;\r
262\r
263 for (Index = 0; Index < Block->BitsLen; Index++) {\r
264 if (Block->Bits[Index] != 0) {\r
265 return FALSE;\r
266 }\r
267 }\r
268\r
269 return TRUE;\r
270}\r
271\r
272\r
273/**\r
ab6495ea 274 Unlink the memory block from the pool's list.\r
913cb9dc 275\r
ab6495ea 276 @param Head The block list head of the memory's pool.\r
913cb9dc 277 @param BlockToUnlink The memory block to unlink.\r
278\r
ab6495ea 279 @return None.\r
913cb9dc 280\r
281**/\r
913cb9dc 282VOID\r
283UsbHcUnlinkMemBlock (\r
284 IN USBHC_MEM_BLOCK *Head,\r
285 IN USBHC_MEM_BLOCK *BlockToUnlink\r
286 )\r
287{\r
288 USBHC_MEM_BLOCK *Block;\r
289\r
290 ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
291\r
292 for (Block = Head; Block != NULL; Block = Block->Next) {\r
293 if (Block->Next == BlockToUnlink) {\r
294 Block->Next = BlockToUnlink->Next;\r
295 BlockToUnlink->Next = NULL;\r
296 break;\r
297 }\r
298 }\r
299}\r
300\r
301\r
302/**\r
ab6495ea 303 Initialize the memory management pool for the host controller.\r
913cb9dc 304\r
ab6495ea 305 @param PciIo The PciIo that can be used to access the host controller.\r
306 @param Check4G Whether the host controller requires allocated memory\r
307 from one 4G address space.\r
308 @param Which4G The 4G memory area each memory allocated should be from.\r
913cb9dc 309\r
ab6495ea 310 @return EFI_SUCCESS The memory pool is initialized.\r
311 @return EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
913cb9dc 312\r
313**/\r
314USBHC_MEM_POOL *\r
315UsbHcInitMemPool (\r
316 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
317 IN BOOLEAN Check4G,\r
318 IN UINT32 Which4G\r
319 )\r
320{\r
321 USBHC_MEM_POOL *Pool;\r
322\r
323 Pool = AllocatePool (sizeof (USBHC_MEM_POOL));\r
324\r
325 if (Pool == NULL) {\r
326 return Pool;\r
327 }\r
328\r
329 Pool->PciIo = PciIo;\r
330 Pool->Check4G = Check4G;\r
331 Pool->Which4G = Which4G;\r
332 Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
333\r
334 if (Pool->Head == NULL) {\r
335 gBS->FreePool (Pool);\r
336 Pool = NULL;\r
337 }\r
338\r
339 return Pool;\r
340}\r
341\r
342\r
343/**\r
ab6495ea 344 Release the memory management pool.\r
913cb9dc 345\r
ab6495ea 346 @param Pool The USB memory pool to free.\r
913cb9dc 347\r
ab6495ea 348 @return EFI_SUCCESS The memory pool is freed.\r
349 @return EFI_DEVICE_ERROR Failed to free the memory pool.\r
913cb9dc 350\r
351**/\r
352EFI_STATUS\r
353UsbHcFreeMemPool (\r
354 IN USBHC_MEM_POOL *Pool\r
355 )\r
356{\r
357 USBHC_MEM_BLOCK *Block;\r
358\r
359 ASSERT (Pool->Head != NULL);\r
360\r
361 //\r
362 // Unlink all the memory blocks from the pool, then free them.\r
363 // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
364 // first block.\r
365 //\r
366 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
367 UsbHcUnlinkMemBlock (Pool->Head, Block);\r
368 UsbHcFreeMemBlock (Pool, Block);\r
369 }\r
370\r
371 UsbHcFreeMemBlock (Pool, Pool->Head);\r
372 gBS->FreePool (Pool);\r
373 return EFI_SUCCESS;\r
374}\r
375\r
376\r
377/**\r
378 Allocate some memory from the host controller's memory pool\r
379 which can be used to communicate with host controller.\r
380\r
ab6495ea 381 @param Pool The host controller's memory pool.\r
382 @param Size Size of the memory to allocate.\r
913cb9dc 383\r
ab6495ea 384 @return The allocated memory or NULL.\r
913cb9dc 385\r
386**/\r
387VOID *\r
388UsbHcAllocateMem (\r
389 IN USBHC_MEM_POOL *Pool,\r
390 IN UINTN Size\r
391 )\r
392{\r
393 USBHC_MEM_BLOCK *Head;\r
394 USBHC_MEM_BLOCK *Block;\r
395 USBHC_MEM_BLOCK *NewBlock;\r
396 VOID *Mem;\r
397 UINTN AllocSize;\r
398 UINTN Pages;\r
399\r
400 Mem = NULL;\r
401 AllocSize = USBHC_MEM_ROUND (Size);\r
402 Head = Pool->Head;\r
403 ASSERT (Head != NULL);\r
404\r
405 //\r
406 // First check whether current memory blocks can satisfy the allocation.\r
407 //\r
408 for (Block = Head; Block != NULL; Block = Block->Next) {\r
409 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
410\r
411 if (Mem != NULL) {\r
412 ZeroMem (Mem, Size);\r
413 break;\r
414 }\r
415 }\r
416\r
417 if (Mem != NULL) {\r
418 return Mem;\r
419 }\r
420\r
421 //\r
422 // Create a new memory block if there is not enough memory\r
423 // in the pool. If the allocation size is larger than the\r
424 // default page number, just allocate a large enough memory\r
425 // block. Otherwise allocate default pages.\r
426 //\r
427 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
428 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
429 } else {\r
430 Pages = USBHC_MEM_DEFAULT_PAGES;\r
431 }\r
432\r
433 NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
434\r
435 if (NewBlock == NULL) {\r
1c619535 436 DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));\r
913cb9dc 437 return NULL;\r
438 }\r
439\r
440 //\r
441 // Add the new memory block to the pool, then allocate memory from it\r
442 //\r
443 UsbHcInsertMemBlockToPool (Head, NewBlock);\r
444 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
445\r
446 if (Mem != NULL) {\r
447 ZeroMem (Mem, Size);\r
448 }\r
449\r
450 return Mem;\r
451}\r
452\r
453\r
454/**\r
ab6495ea 455 Free the allocated memory back to the memory pool.\r
913cb9dc 456\r
ab6495ea 457 @param Pool The memory pool of the host controller.\r
458 @param Mem The memory to free.\r
459 @param Size The size of the memory to free.\r
913cb9dc 460\r
ab6495ea 461 @return None.\r
913cb9dc 462\r
463**/\r
464VOID\r
465UsbHcFreeMem (\r
466 IN USBHC_MEM_POOL *Pool,\r
467 IN VOID *Mem,\r
468 IN UINTN Size\r
469 )\r
470{\r
471 USBHC_MEM_BLOCK *Head;\r
472 USBHC_MEM_BLOCK *Block;\r
473 UINT8 *ToFree;\r
474 UINTN AllocSize;\r
475 UINTN Byte;\r
476 UINTN Bit;\r
477 UINTN Count;\r
478\r
479 Head = Pool->Head;\r
480 AllocSize = USBHC_MEM_ROUND (Size);\r
481 ToFree = (UINT8 *) Mem;\r
482\r
483 for (Block = Head; Block != NULL; Block = Block->Next) {\r
484 //\r
485 // scan the memory block list for the memory block that\r
486 // completely contains the memory to free.\r
487 //\r
488 if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
489 //\r
490 // compute the start byte and bit in the bit array\r
491 //\r
492 Byte = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8;\r
493 Bit = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8;\r
494\r
495 //\r
496 // reset associated bits in bit arry\r
497 //\r
498 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
499 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
500\r
c52fa98c 501 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
913cb9dc 502 NEXT_BIT (Byte, Bit);\r
503 }\r
504\r
505 break;\r
506 }\r
507 }\r
508\r
509 //\r
510 // If Block == NULL, it means that the current memory isn't\r
511 // in the host controller's pool. This is critical because\r
512 // the caller has passed in a wrong memory point\r
513 //\r
514 ASSERT (Block != NULL);\r
515\r
516 //\r
517 // Release the current memory block if it is empty and not the head\r
518 //\r
519 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
913cb9dc 520 UsbHcUnlinkMemBlock (Head, Block);\r
521 UsbHcFreeMemBlock (Pool, Block);\r
522 }\r
523\r
524 return ;\r
525}\r