]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.c
NumberOfCpus and SmmStartupThisAp field in Framework SMST should be updated per PI...
[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
913cb9dc 126**/\r
913cb9dc 127VOID\r
128UsbHcFreeMemBlock (\r
129 IN USBHC_MEM_POOL *Pool,\r
130 IN USBHC_MEM_BLOCK *Block\r
131 )\r
132{\r
133 EFI_PCI_IO_PROTOCOL *PciIo;\r
134\r
135 ASSERT ((Pool != NULL) && (Block != NULL));\r
136\r
137 PciIo = Pool->PciIo;\r
138\r
139 //\r
140 // Unmap the common buffer then free the structures\r
141 //\r
142 PciIo->Unmap (PciIo, Block->Mapping);\r
143 PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);\r
144\r
145 gBS->FreePool (Block->Bits);\r
146 gBS->FreePool (Block);\r
147}\r
148\r
149\r
150/**\r
ab6495ea 151 Alloc some memory from the block.\r
913cb9dc 152\r
ab6495ea 153 @param Block The memory block to allocate memory from.\r
154 @param Units Number of memory units to allocate.\r
913cb9dc 155\r
ab6495ea 156 @return EFI_SUCCESS The needed memory is allocated.\r
157 @return EFI_NOT_FOUND Can't find the free memory.\r
913cb9dc 158\r
159**/\r
913cb9dc 160VOID *\r
161UsbHcAllocMemFromBlock (\r
162 IN USBHC_MEM_BLOCK *Block,\r
163 IN UINTN Units\r
164 )\r
165{\r
166 UINTN Byte;\r
167 UINT8 Bit;\r
168 UINTN StartByte;\r
169 UINT8 StartBit;\r
170 UINTN Available;\r
171 UINTN Count;\r
172\r
173 ASSERT ((Block != 0) && (Units != 0));\r
174\r
175 StartByte = 0;\r
176 StartBit = 0;\r
177 Available = 0;\r
178\r
179 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
180 //\r
181 // If current bit is zero, the corresponding memory unit is\r
182 // available, otherwise we need to restart our searching.\r
183 // Available counts the consective number of zero bit.\r
184 //\r
185 if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
186 Available++;\r
187\r
188 if (Available >= Units) {\r
189 break;\r
190 }\r
191\r
192 NEXT_BIT (Byte, Bit);\r
193\r
194 } else {\r
195 NEXT_BIT (Byte, Bit);\r
196\r
197 Available = 0;\r
198 StartByte = Byte;\r
199 StartBit = Bit;\r
200 }\r
201 }\r
202\r
203 if (Available < Units) {\r
204 return NULL;\r
205 }\r
206\r
207 //\r
208 // Mark the memory as allocated\r
209 //\r
210 Byte = StartByte;\r
211 Bit = StartBit;\r
212\r
213 for (Count = 0; Count < Units; Count++) {\r
214 ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
215\r
d074a8e1 216 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));\r
913cb9dc 217 NEXT_BIT (Byte, Bit);\r
218 }\r
219\r
220 return Block->Buf + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
221}\r
222\r
223\r
224/**\r
ab6495ea 225 Insert the memory block to the pool's list of the blocks.\r
913cb9dc 226\r
ab6495ea 227 @param Head The head of the memory pool's block list.\r
228 @param Block The memory block to insert.\r
913cb9dc 229\r
913cb9dc 230**/\r
913cb9dc 231VOID\r
232UsbHcInsertMemBlockToPool (\r
233 IN USBHC_MEM_BLOCK *Head,\r
234 IN USBHC_MEM_BLOCK *Block\r
235 )\r
236{\r
237 ASSERT ((Head != NULL) && (Block != NULL));\r
238 Block->Next = Head->Next;\r
239 Head->Next = Block;\r
240}\r
241\r
242\r
243/**\r
244 Is the memory block empty?\r
245\r
ab6495ea 246 @param Block The memory block to check.\r
913cb9dc 247\r
ab6495ea 248 @return TRUE The memory block is empty.\r
249 @return FALSE The memory block isn't empty.\r
913cb9dc 250\r
251**/\r
913cb9dc 252BOOLEAN\r
253UsbHcIsMemBlockEmpty (\r
254 IN USBHC_MEM_BLOCK *Block\r
255 )\r
256{\r
257 UINTN Index;\r
258\r
259 for (Index = 0; Index < Block->BitsLen; Index++) {\r
260 if (Block->Bits[Index] != 0) {\r
261 return FALSE;\r
262 }\r
263 }\r
264\r
265 return TRUE;\r
266}\r
267\r
268\r
269/**\r
ab6495ea 270 Unlink the memory block from the pool's list.\r
913cb9dc 271\r
ab6495ea 272 @param Head The block list head of the memory's pool.\r
913cb9dc 273 @param BlockToUnlink The memory block to unlink.\r
274\r
913cb9dc 275**/\r
913cb9dc 276VOID\r
277UsbHcUnlinkMemBlock (\r
278 IN USBHC_MEM_BLOCK *Head,\r
279 IN USBHC_MEM_BLOCK *BlockToUnlink\r
280 )\r
281{\r
282 USBHC_MEM_BLOCK *Block;\r
283\r
284 ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
285\r
286 for (Block = Head; Block != NULL; Block = Block->Next) {\r
287 if (Block->Next == BlockToUnlink) {\r
288 Block->Next = BlockToUnlink->Next;\r
289 BlockToUnlink->Next = NULL;\r
290 break;\r
291 }\r
292 }\r
293}\r
294\r
295\r
296/**\r
ab6495ea 297 Initialize the memory management pool for the host controller.\r
913cb9dc 298\r
ab6495ea 299 @param PciIo The PciIo that can be used to access the host controller.\r
300 @param Check4G Whether the host controller requires allocated memory\r
301 from one 4G address space.\r
302 @param Which4G The 4G memory area each memory allocated should be from.\r
913cb9dc 303\r
ab6495ea 304 @return EFI_SUCCESS The memory pool is initialized.\r
305 @return EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
913cb9dc 306\r
307**/\r
308USBHC_MEM_POOL *\r
309UsbHcInitMemPool (\r
310 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
311 IN BOOLEAN Check4G,\r
312 IN UINT32 Which4G\r
313 )\r
314{\r
315 USBHC_MEM_POOL *Pool;\r
316\r
317 Pool = AllocatePool (sizeof (USBHC_MEM_POOL));\r
318\r
319 if (Pool == NULL) {\r
320 return Pool;\r
321 }\r
322\r
323 Pool->PciIo = PciIo;\r
324 Pool->Check4G = Check4G;\r
325 Pool->Which4G = Which4G;\r
326 Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
327\r
328 if (Pool->Head == NULL) {\r
329 gBS->FreePool (Pool);\r
330 Pool = NULL;\r
331 }\r
332\r
333 return Pool;\r
334}\r
335\r
336\r
337/**\r
ab6495ea 338 Release the memory management pool.\r
913cb9dc 339\r
ab6495ea 340 @param Pool The USB memory pool to free.\r
913cb9dc 341\r
ab6495ea 342 @return EFI_SUCCESS The memory pool is freed.\r
343 @return EFI_DEVICE_ERROR Failed to free the memory pool.\r
913cb9dc 344\r
345**/\r
346EFI_STATUS\r
347UsbHcFreeMemPool (\r
348 IN USBHC_MEM_POOL *Pool\r
349 )\r
350{\r
351 USBHC_MEM_BLOCK *Block;\r
352\r
353 ASSERT (Pool->Head != NULL);\r
354\r
355 //\r
356 // Unlink all the memory blocks from the pool, then free them.\r
357 // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
358 // first block.\r
359 //\r
360 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
361 UsbHcUnlinkMemBlock (Pool->Head, Block);\r
362 UsbHcFreeMemBlock (Pool, Block);\r
363 }\r
364\r
365 UsbHcFreeMemBlock (Pool, Pool->Head);\r
366 gBS->FreePool (Pool);\r
367 return EFI_SUCCESS;\r
368}\r
369\r
370\r
371/**\r
372 Allocate some memory from the host controller's memory pool\r
373 which can be used to communicate with host controller.\r
374\r
ab6495ea 375 @param Pool The host controller's memory pool.\r
376 @param Size Size of the memory to allocate.\r
913cb9dc 377\r
ab6495ea 378 @return The allocated memory or NULL.\r
913cb9dc 379\r
380**/\r
381VOID *\r
382UsbHcAllocateMem (\r
383 IN USBHC_MEM_POOL *Pool,\r
384 IN UINTN Size\r
385 )\r
386{\r
387 USBHC_MEM_BLOCK *Head;\r
388 USBHC_MEM_BLOCK *Block;\r
389 USBHC_MEM_BLOCK *NewBlock;\r
390 VOID *Mem;\r
391 UINTN AllocSize;\r
392 UINTN Pages;\r
393\r
394 Mem = NULL;\r
395 AllocSize = USBHC_MEM_ROUND (Size);\r
396 Head = Pool->Head;\r
397 ASSERT (Head != NULL);\r
398\r
399 //\r
400 // First check whether current memory blocks can satisfy the allocation.\r
401 //\r
402 for (Block = Head; Block != NULL; Block = Block->Next) {\r
403 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
404\r
405 if (Mem != NULL) {\r
406 ZeroMem (Mem, Size);\r
407 break;\r
408 }\r
409 }\r
410\r
411 if (Mem != NULL) {\r
412 return Mem;\r
413 }\r
414\r
415 //\r
416 // Create a new memory block if there is not enough memory\r
417 // in the pool. If the allocation size is larger than the\r
418 // default page number, just allocate a large enough memory\r
419 // block. Otherwise allocate default pages.\r
420 //\r
421 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
422 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
423 } else {\r
424 Pages = USBHC_MEM_DEFAULT_PAGES;\r
425 }\r
426\r
427 NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
428\r
429 if (NewBlock == NULL) {\r
1c619535 430 DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));\r
913cb9dc 431 return NULL;\r
432 }\r
433\r
434 //\r
435 // Add the new memory block to the pool, then allocate memory from it\r
436 //\r
437 UsbHcInsertMemBlockToPool (Head, NewBlock);\r
438 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
439\r
440 if (Mem != NULL) {\r
441 ZeroMem (Mem, Size);\r
442 }\r
443\r
444 return Mem;\r
445}\r
446\r
447\r
448/**\r
ab6495ea 449 Free the allocated memory back to the memory pool.\r
913cb9dc 450\r
ab6495ea 451 @param Pool The memory pool of the host controller.\r
452 @param Mem The memory to free.\r
453 @param Size The size of the memory to free.\r
913cb9dc 454\r
913cb9dc 455**/\r
456VOID\r
457UsbHcFreeMem (\r
458 IN USBHC_MEM_POOL *Pool,\r
459 IN VOID *Mem,\r
460 IN UINTN Size\r
461 )\r
462{\r
463 USBHC_MEM_BLOCK *Head;\r
464 USBHC_MEM_BLOCK *Block;\r
465 UINT8 *ToFree;\r
466 UINTN AllocSize;\r
467 UINTN Byte;\r
468 UINTN Bit;\r
469 UINTN Count;\r
470\r
471 Head = Pool->Head;\r
472 AllocSize = USBHC_MEM_ROUND (Size);\r
473 ToFree = (UINT8 *) Mem;\r
474\r
475 for (Block = Head; Block != NULL; Block = Block->Next) {\r
476 //\r
477 // scan the memory block list for the memory block that\r
478 // completely contains the memory to free.\r
479 //\r
480 if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
481 //\r
482 // compute the start byte and bit in the bit array\r
483 //\r
484 Byte = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8;\r
485 Bit = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8;\r
486\r
487 //\r
488 // reset associated bits in bit arry\r
489 //\r
490 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
491 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
492\r
c52fa98c 493 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
913cb9dc 494 NEXT_BIT (Byte, Bit);\r
495 }\r
496\r
497 break;\r
498 }\r
499 }\r
500\r
501 //\r
502 // If Block == NULL, it means that the current memory isn't\r
503 // in the host controller's pool. This is critical because\r
504 // the caller has passed in a wrong memory point\r
505 //\r
506 ASSERT (Block != NULL);\r
507\r
508 //\r
509 // Release the current memory block if it is empty and not the head\r
510 //\r
511 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
913cb9dc 512 UsbHcUnlinkMemBlock (Head, Block);\r
513 UsbHcFreeMemBlock (Pool, Block);\r
514 }\r
515\r
516 return ;\r
517}\r