]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciDxe/UsbHcMem.c
MdeModulePkg: Fixed extra 1 SR-IOV reserved bus
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / UsbHcMem.c
CommitLineData
1847ed0b
EL
1/** @file\r
2\r
3 Routine procedures for memory allocate/free.\r
4\r
d1102dba 5Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
1847ed0b
EL
7\r
8**/\r
9\r
1847ed0b
EL
10#include "Xhci.h"\r
11\r
1847ed0b
EL
12/**\r
13 Allocate a block of memory to be used by the buffer pool.\r
14\r
15 @param Pool The buffer pool to allocate memory for.\r
16 @param Pages How many pages to allocate.\r
17\r
18 @return The allocated memory block or NULL if failed.\r
19\r
20**/\r
21USBHC_MEM_BLOCK *\r
22UsbHcAllocMemBlock (\r
1436aea4
MK
23 IN USBHC_MEM_POOL *Pool,\r
24 IN UINTN Pages\r
1847ed0b
EL
25 )\r
26{\r
1436aea4
MK
27 USBHC_MEM_BLOCK *Block;\r
28 EFI_PCI_IO_PROTOCOL *PciIo;\r
29 VOID *BufHost;\r
30 VOID *Mapping;\r
31 EFI_PHYSICAL_ADDRESS MappedAddr;\r
32 UINTN Bytes;\r
33 EFI_STATUS Status;\r
1847ed0b
EL
34\r
35 PciIo = Pool->PciIo;\r
36\r
37 Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));\r
38 if (Block == NULL) {\r
39 return NULL;\r
40 }\r
41\r
42 //\r
43 // each bit in the bit array represents USBHC_MEM_UNIT\r
44 // bytes of memory in the memory block.\r
45 //\r
46 ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
47\r
1436aea4
MK
48 Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
49 Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
50 Block->Bits = AllocateZeroPool (Block->BitsLen);\r
1847ed0b
EL
51\r
52 if (Block->Bits == NULL) {\r
53 gBS->FreePool (Block);\r
54 return NULL;\r
55 }\r
56\r
57 //\r
58 // Allocate the number of Pages of memory, then map it for\r
59 // bus master read and write.\r
60 //\r
61 Status = PciIo->AllocateBuffer (\r
62 PciIo,\r
63 AllocateAnyPages,\r
64 EfiBootServicesData,\r
65 Pages,\r
66 &BufHost,\r
67 0\r
68 );\r
69\r
70 if (EFI_ERROR (Status)) {\r
71 goto FREE_BITARRAY;\r
72 }\r
73\r
1436aea4 74 Bytes = EFI_PAGES_TO_SIZE (Pages);\r
1847ed0b
EL
75 Status = PciIo->Map (\r
76 PciIo,\r
77 EfiPciIoOperationBusMasterCommonBuffer,\r
78 BufHost,\r
79 &Bytes,\r
80 &MappedAddr,\r
81 &Mapping\r
82 );\r
83\r
84 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {\r
85 goto FREE_BUFFER;\r
86 }\r
87\r
1436aea4
MK
88 Block->BufHost = BufHost;\r
89 Block->Buf = (UINT8 *)((UINTN)MappedAddr);\r
90 Block->Mapping = Mapping;\r
1847ed0b
EL
91\r
92 return Block;\r
93\r
94FREE_BUFFER:\r
95 PciIo->FreeBuffer (PciIo, Pages, BufHost);\r
96\r
97FREE_BITARRAY:\r
98 gBS->FreePool (Block->Bits);\r
99 gBS->FreePool (Block);\r
100 return NULL;\r
101}\r
102\r
1847ed0b
EL
103/**\r
104 Free the memory block from the memory pool.\r
105\r
106 @param Pool The memory pool to free the block from.\r
107 @param Block The memory block to free.\r
108\r
109**/\r
110VOID\r
111UsbHcFreeMemBlock (\r
1436aea4
MK
112 IN USBHC_MEM_POOL *Pool,\r
113 IN USBHC_MEM_BLOCK *Block\r
1847ed0b
EL
114 )\r
115{\r
1436aea4 116 EFI_PCI_IO_PROTOCOL *PciIo;\r
1847ed0b
EL
117\r
118 ASSERT ((Pool != NULL) && (Block != NULL));\r
119\r
120 PciIo = Pool->PciIo;\r
121\r
122 //\r
123 // Unmap the common buffer then free the structures\r
124 //\r
125 PciIo->Unmap (PciIo, Block->Mapping);\r
126 PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);\r
127\r
128 gBS->FreePool (Block->Bits);\r
129 gBS->FreePool (Block);\r
130}\r
131\r
1847ed0b
EL
132/**\r
133 Alloc some memory from the block.\r
134\r
135 @param Block The memory block to allocate memory from.\r
136 @param Units Number of memory units to allocate.\r
137\r
138 @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
139 the return value is NULL.\r
140\r
141**/\r
142VOID *\r
143UsbHcAllocMemFromBlock (\r
1436aea4
MK
144 IN USBHC_MEM_BLOCK *Block,\r
145 IN UINTN Units\r
1847ed0b
EL
146 )\r
147{\r
1436aea4
MK
148 UINTN Byte;\r
149 UINT8 Bit;\r
150 UINTN StartByte;\r
151 UINT8 StartBit;\r
152 UINTN Available;\r
153 UINTN Count;\r
1847ed0b
EL
154\r
155 ASSERT ((Block != 0) && (Units != 0));\r
156\r
1436aea4
MK
157 StartByte = 0;\r
158 StartBit = 0;\r
159 Available = 0;\r
1847ed0b
EL
160\r
161 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
162 //\r
163 // If current bit is zero, the corresponding memory unit is\r
164 // available, otherwise we need to restart our searching.\r
165 // Available counts the consective number of zero bit.\r
166 //\r
167 if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
168 Available++;\r
169\r
170 if (Available >= Units) {\r
171 break;\r
172 }\r
173\r
174 NEXT_BIT (Byte, Bit);\r
1847ed0b
EL
175 } else {\r
176 NEXT_BIT (Byte, Bit);\r
177\r
1436aea4
MK
178 Available = 0;\r
179 StartByte = Byte;\r
180 StartBit = Bit;\r
1847ed0b
EL
181 }\r
182 }\r
183\r
184 if (Available < Units) {\r
185 return NULL;\r
186 }\r
187\r
188 //\r
189 // Mark the memory as allocated\r
190 //\r
1436aea4
MK
191 Byte = StartByte;\r
192 Bit = StartBit;\r
1847ed0b
EL
193\r
194 for (Count = 0; Count < Units; Count++) {\r
195 ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
196\r
1436aea4 197 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] | USB_HC_BIT (Bit));\r
1847ed0b
EL
198 NEXT_BIT (Byte, Bit);\r
199 }\r
200\r
201 return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
202}\r
203\r
204/**\r
205 Calculate the corresponding pci bus address according to the Mem parameter.\r
206\r
207 @param Pool The memory pool of the host controller.\r
208 @param Mem The pointer to host memory.\r
209 @param Size The size of the memory region.\r
210\r
211 @return The pci memory address\r
212\r
213**/\r
214EFI_PHYSICAL_ADDRESS\r
215UsbHcGetPciAddrForHostAddr (\r
1436aea4
MK
216 IN USBHC_MEM_POOL *Pool,\r
217 IN VOID *Mem,\r
218 IN UINTN Size\r
1847ed0b
EL
219 )\r
220{\r
1436aea4
MK
221 USBHC_MEM_BLOCK *Head;\r
222 USBHC_MEM_BLOCK *Block;\r
223 UINTN AllocSize;\r
224 EFI_PHYSICAL_ADDRESS PhyAddr;\r
225 UINTN Offset;\r
1847ed0b
EL
226\r
227 Head = Pool->Head;\r
228 AllocSize = USBHC_MEM_ROUND (Size);\r
229\r
230 if (Mem == NULL) {\r
231 return 0;\r
232 }\r
233\r
234 for (Block = Head; Block != NULL; Block = Block->Next) {\r
235 //\r
236 // scan the memory block list for the memory block that\r
237 // completely contains the allocated memory.\r
238 //\r
1436aea4 239 if ((Block->BufHost <= (UINT8 *)Mem) && (((UINT8 *)Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
1847ed0b
EL
240 break;\r
241 }\r
242 }\r
243\r
244 ASSERT ((Block != NULL));\r
245 //\r
246 // calculate the pci memory address for host memory address.\r
247 //\r
1436aea4
MK
248 Offset = (UINT8 *)Mem - Block->BufHost;\r
249 PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)(Block->Buf + Offset);\r
1847ed0b
EL
250 return PhyAddr;\r
251}\r
252\r
253/**\r
254 Calculate the corresponding host address according to the pci address.\r
255\r
256 @param Pool The memory pool of the host controller.\r
257 @param Mem The pointer to pci memory.\r
258 @param Size The size of the memory region.\r
259\r
260 @return The host memory address\r
261\r
262**/\r
263EFI_PHYSICAL_ADDRESS\r
264UsbHcGetHostAddrForPciAddr (\r
1436aea4
MK
265 IN USBHC_MEM_POOL *Pool,\r
266 IN VOID *Mem,\r
267 IN UINTN Size\r
1847ed0b
EL
268 )\r
269{\r
1436aea4
MK
270 USBHC_MEM_BLOCK *Head;\r
271 USBHC_MEM_BLOCK *Block;\r
272 UINTN AllocSize;\r
273 EFI_PHYSICAL_ADDRESS HostAddr;\r
274 UINTN Offset;\r
1847ed0b
EL
275\r
276 Head = Pool->Head;\r
277 AllocSize = USBHC_MEM_ROUND (Size);\r
278\r
279 if (Mem == NULL) {\r
280 return 0;\r
281 }\r
282\r
283 for (Block = Head; Block != NULL; Block = Block->Next) {\r
284 //\r
285 // scan the memory block list for the memory block that\r
286 // completely contains the allocated memory.\r
287 //\r
1436aea4 288 if ((Block->Buf <= (UINT8 *)Mem) && (((UINT8 *)Mem + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
1847ed0b
EL
289 break;\r
290 }\r
291 }\r
292\r
293 ASSERT ((Block != NULL));\r
294 //\r
295 // calculate the pci memory address for host memory address.\r
296 //\r
1436aea4
MK
297 Offset = (UINT8 *)Mem - Block->Buf;\r
298 HostAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)(Block->BufHost + Offset);\r
1847ed0b
EL
299 return HostAddr;\r
300}\r
301\r
302/**\r
303 Insert the memory block to the pool's list of the blocks.\r
304\r
305 @param Head The head of the memory pool's block list.\r
306 @param Block The memory block to insert.\r
307\r
308**/\r
309VOID\r
310UsbHcInsertMemBlockToPool (\r
1436aea4
MK
311 IN USBHC_MEM_BLOCK *Head,\r
312 IN USBHC_MEM_BLOCK *Block\r
1847ed0b
EL
313 )\r
314{\r
315 ASSERT ((Head != NULL) && (Block != NULL));\r
316 Block->Next = Head->Next;\r
317 Head->Next = Block;\r
318}\r
319\r
1847ed0b
EL
320/**\r
321 Is the memory block empty?\r
322\r
323 @param Block The memory block to check.\r
324\r
325 @retval TRUE The memory block is empty.\r
326 @retval FALSE The memory block isn't empty.\r
327\r
328**/\r
329BOOLEAN\r
330UsbHcIsMemBlockEmpty (\r
1436aea4 331 IN USBHC_MEM_BLOCK *Block\r
1847ed0b
EL
332 )\r
333{\r
1436aea4 334 UINTN Index;\r
1847ed0b
EL
335\r
336 for (Index = 0; Index < Block->BitsLen; Index++) {\r
337 if (Block->Bits[Index] != 0) {\r
338 return FALSE;\r
339 }\r
340 }\r
341\r
342 return TRUE;\r
343}\r
344\r
1847ed0b
EL
345/**\r
346 Unlink the memory block from the pool's list.\r
347\r
348 @param Head The block list head of the memory's pool.\r
349 @param BlockToUnlink The memory block to unlink.\r
350\r
351**/\r
352VOID\r
353UsbHcUnlinkMemBlock (\r
1436aea4
MK
354 IN USBHC_MEM_BLOCK *Head,\r
355 IN USBHC_MEM_BLOCK *BlockToUnlink\r
1847ed0b
EL
356 )\r
357{\r
1436aea4 358 USBHC_MEM_BLOCK *Block;\r
1847ed0b
EL
359\r
360 ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
361\r
362 for (Block = Head; Block != NULL; Block = Block->Next) {\r
363 if (Block->Next == BlockToUnlink) {\r
364 Block->Next = BlockToUnlink->Next;\r
365 BlockToUnlink->Next = NULL;\r
366 break;\r
367 }\r
368 }\r
369}\r
370\r
1847ed0b
EL
371/**\r
372 Initialize the memory management pool for the host controller.\r
373\r
374 @param PciIo The PciIo that can be used to access the host controller.\r
375\r
376 @retval EFI_SUCCESS The memory pool is initialized.\r
377 @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
378\r
379**/\r
380USBHC_MEM_POOL *\r
381UsbHcInitMemPool (\r
382 IN EFI_PCI_IO_PROTOCOL *PciIo\r
383 )\r
384{\r
1436aea4 385 USBHC_MEM_POOL *Pool;\r
1847ed0b
EL
386\r
387 Pool = AllocatePool (sizeof (USBHC_MEM_POOL));\r
388\r
389 if (Pool == NULL) {\r
390 return Pool;\r
391 }\r
392\r
1436aea4
MK
393 Pool->PciIo = PciIo;\r
394 Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
1847ed0b
EL
395\r
396 if (Pool->Head == NULL) {\r
397 gBS->FreePool (Pool);\r
398 Pool = NULL;\r
399 }\r
400\r
401 return Pool;\r
402}\r
403\r
1847ed0b
EL
404/**\r
405 Release the memory management pool.\r
406\r
407 @param Pool The USB memory pool to free.\r
408\r
409 @retval EFI_SUCCESS The memory pool is freed.\r
410 @retval EFI_DEVICE_ERROR Failed to free the memory pool.\r
411\r
412**/\r
413EFI_STATUS\r
414UsbHcFreeMemPool (\r
1436aea4 415 IN USBHC_MEM_POOL *Pool\r
1847ed0b
EL
416 )\r
417{\r
1436aea4 418 USBHC_MEM_BLOCK *Block;\r
1847ed0b
EL
419\r
420 ASSERT (Pool->Head != NULL);\r
421\r
422 //\r
423 // Unlink all the memory blocks from the pool, then free them.\r
424 // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
425 // first block.\r
426 //\r
427 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
428 UsbHcUnlinkMemBlock (Pool->Head, Block);\r
429 UsbHcFreeMemBlock (Pool, Block);\r
430 }\r
431\r
432 UsbHcFreeMemBlock (Pool, Pool->Head);\r
433 gBS->FreePool (Pool);\r
434 return EFI_SUCCESS;\r
435}\r
436\r
1847ed0b
EL
437/**\r
438 Allocate some memory from the host controller's memory pool\r
439 which can be used to communicate with host controller.\r
440\r
441 @param Pool The host controller's memory pool.\r
442 @param Size Size of the memory to allocate.\r
443\r
444 @return The allocated memory or NULL.\r
445\r
446**/\r
447VOID *\r
448UsbHcAllocateMem (\r
1436aea4
MK
449 IN USBHC_MEM_POOL *Pool,\r
450 IN UINTN Size\r
1847ed0b
EL
451 )\r
452{\r
1436aea4
MK
453 USBHC_MEM_BLOCK *Head;\r
454 USBHC_MEM_BLOCK *Block;\r
455 USBHC_MEM_BLOCK *NewBlock;\r
456 VOID *Mem;\r
457 UINTN AllocSize;\r
458 UINTN Pages;\r
1847ed0b
EL
459\r
460 Mem = NULL;\r
461 AllocSize = USBHC_MEM_ROUND (Size);\r
462 Head = Pool->Head;\r
463 ASSERT (Head != NULL);\r
464\r
465 //\r
466 // First check whether current memory blocks can satisfy the allocation.\r
467 //\r
468 for (Block = Head; Block != NULL; Block = Block->Next) {\r
469 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
470\r
471 if (Mem != NULL) {\r
472 ZeroMem (Mem, Size);\r
473 break;\r
474 }\r
475 }\r
476\r
477 if (Mem != NULL) {\r
478 return Mem;\r
479 }\r
480\r
481 //\r
482 // Create a new memory block if there is not enough memory\r
483 // in the pool. If the allocation size is larger than the\r
484 // default page number, just allocate a large enough memory\r
485 // block. Otherwise allocate default pages.\r
486 //\r
487 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
488 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
489 } else {\r
490 Pages = USBHC_MEM_DEFAULT_PAGES;\r
491 }\r
492\r
493 NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
494\r
495 if (NewBlock == NULL) {\r
87000d77 496 DEBUG ((DEBUG_ERROR, "UsbHcAllocateMem: failed to allocate block\n"));\r
1847ed0b
EL
497 return NULL;\r
498 }\r
499\r
500 //\r
501 // Add the new memory block to the pool, then allocate memory from it\r
502 //\r
503 UsbHcInsertMemBlockToPool (Head, NewBlock);\r
504 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
505\r
506 if (Mem != NULL) {\r
507 ZeroMem (Mem, Size);\r
508 }\r
509\r
510 return Mem;\r
511}\r
512\r
1847ed0b
EL
513/**\r
514 Free the allocated memory back to the memory pool.\r
515\r
516 @param Pool The memory pool of the host controller.\r
517 @param Mem The memory to free.\r
518 @param Size The size of the memory to free.\r
519\r
520**/\r
521VOID\r
522UsbHcFreeMem (\r
1436aea4
MK
523 IN USBHC_MEM_POOL *Pool,\r
524 IN VOID *Mem,\r
525 IN UINTN Size\r
1847ed0b
EL
526 )\r
527{\r
1436aea4
MK
528 USBHC_MEM_BLOCK *Head;\r
529 USBHC_MEM_BLOCK *Block;\r
530 UINT8 *ToFree;\r
531 UINTN AllocSize;\r
532 UINTN Byte;\r
533 UINTN Bit;\r
534 UINTN Count;\r
1847ed0b
EL
535\r
536 Head = Pool->Head;\r
537 AllocSize = USBHC_MEM_ROUND (Size);\r
1436aea4 538 ToFree = (UINT8 *)Mem;\r
1847ed0b
EL
539\r
540 for (Block = Head; Block != NULL; Block = Block->Next) {\r
541 //\r
542 // scan the memory block list for the memory block that\r
543 // completely contains the memory to free.\r
544 //\r
545 if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
546 //\r
547 // compute the start byte and bit in the bit array\r
548 //\r
1436aea4
MK
549 Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;\r
550 Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;\r
1847ed0b
EL
551\r
552 //\r
2048c585 553 // reset associated bits in bit array\r
1847ed0b
EL
554 //\r
555 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
556 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
557\r
1436aea4 558 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
1847ed0b
EL
559 NEXT_BIT (Byte, Bit);\r
560 }\r
561\r
562 break;\r
563 }\r
564 }\r
565\r
566 //\r
567 // If Block == NULL, it means that the current memory isn't\r
568 // in the host controller's pool. This is critical because\r
569 // the caller has passed in a wrong memory point\r
570 //\r
571 ASSERT (Block != NULL);\r
572\r
573 //\r
574 // Release the current memory block if it is empty and not the head\r
575 //\r
576 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
577 UsbHcUnlinkMemBlock (Head, Block);\r
578 UsbHcFreeMemBlock (Pool, Block);\r
579 }\r
580\r
1436aea4 581 return;\r
1847ed0b
EL
582}\r
583\r
d1102dba 584/**\r
1847ed0b 585 Allocates pages at a specified alignment that are suitable for an EfiPciIoOperationBusMasterCommonBuffer mapping.\r
d1102dba 586\r
1847ed0b
EL
587 If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
588\r
589 @param PciIo The PciIo that can be used to access the host controller.\r
590 @param Pages The number of pages to allocate.\r
591 @param Alignment The requested alignment of the allocation. Must be a power of two.\r
592 @param HostAddress The system memory address to map to the PCI controller.\r
d1102dba 593 @param DeviceAddress The resulting map address for the bus master PCI controller to\r
1847ed0b
EL
594 use to access the hosts HostAddress.\r
595 @param Mapping A resulting value to pass to Unmap().\r
596\r
597 @retval EFI_SUCCESS Success to allocate aligned pages.\r
598 @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.\r
599 @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.\r
d1102dba 600\r
1847ed0b
EL
601\r
602**/\r
603EFI_STATUS\r
604UsbHcAllocateAlignedPages (\r
605 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
606 IN UINTN Pages,\r
607 IN UINTN Alignment,\r
608 OUT VOID **HostAddress,\r
609 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
610 OUT VOID **Mapping\r
611 )\r
612{\r
1436aea4
MK
613 EFI_STATUS Status;\r
614 VOID *Memory;\r
615 UINTN AlignedMemory;\r
616 UINTN AlignmentMask;\r
617 UINTN UnalignedPages;\r
618 UINTN RealPages;\r
619 UINTN Bytes;\r
1847ed0b
EL
620\r
621 //\r
622 // Alignment must be a power of two or zero.\r
623 //\r
624 ASSERT ((Alignment & (Alignment - 1)) == 0);\r
d1102dba 625\r
1847ed0b
EL
626 if ((Alignment & (Alignment - 1)) != 0) {\r
627 return EFI_INVALID_PARAMETER;\r
628 }\r
d1102dba 629\r
1847ed0b
EL
630 if (Pages == 0) {\r
631 return EFI_INVALID_PARAMETER;\r
632 }\r
1436aea4 633\r
1847ed0b
EL
634 if (Alignment > EFI_PAGE_SIZE) {\r
635 //\r
e50a226b 636 // Calculate the total number of pages since alignment is larger than page size.\r
1847ed0b 637 //\r
1436aea4
MK
638 AlignmentMask = Alignment - 1;\r
639 RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
1847ed0b
EL
640 //\r
641 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
642 //\r
643 ASSERT (RealPages > Pages);\r
d1102dba 644\r
1847ed0b
EL
645 Status = PciIo->AllocateBuffer (\r
646 PciIo,\r
647 AllocateAnyPages,\r
648 EfiBootServicesData,\r
3b889f6f 649 RealPages,\r
1847ed0b
EL
650 &Memory,\r
651 0\r
d1102dba 652 );\r
1847ed0b
EL
653 if (EFI_ERROR (Status)) {\r
654 return EFI_OUT_OF_RESOURCES;\r
655 }\r
1436aea4
MK
656\r
657 AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask;\r
658 UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory);\r
1847ed0b
EL
659 if (UnalignedPages > 0) {\r
660 //\r
661 // Free first unaligned page(s).\r
662 //\r
663 Status = PciIo->FreeBuffer (PciIo, UnalignedPages, Memory);\r
664 ASSERT_EFI_ERROR (Status);\r
665 }\r
1436aea4 666\r
1847ed0b
EL
667 Memory = (VOID *)(UINTN)(AlignedMemory + EFI_PAGES_TO_SIZE (Pages));\r
668 UnalignedPages = RealPages - Pages - UnalignedPages;\r
669 if (UnalignedPages > 0) {\r
670 //\r
671 // Free last unaligned page(s).\r
672 //\r
673 Status = PciIo->FreeBuffer (PciIo, UnalignedPages, Memory);\r
674 ASSERT_EFI_ERROR (Status);\r
675 }\r
676 } else {\r
677 //\r
678 // Do not over-allocate pages in this case.\r
679 //\r
680 Status = PciIo->AllocateBuffer (\r
681 PciIo,\r
682 AllocateAnyPages,\r
683 EfiBootServicesData,\r
684 Pages,\r
685 &Memory,\r
686 0\r
687 );\r
688 if (EFI_ERROR (Status)) {\r
689 return EFI_OUT_OF_RESOURCES;\r
690 }\r
1436aea4
MK
691\r
692 AlignedMemory = (UINTN)Memory;\r
1847ed0b
EL
693 }\r
694\r
1436aea4 695 Bytes = EFI_PAGES_TO_SIZE (Pages);\r
1847ed0b
EL
696 Status = PciIo->Map (\r
697 PciIo,\r
698 EfiPciIoOperationBusMasterCommonBuffer,\r
1436aea4 699 (VOID *)AlignedMemory,\r
1847ed0b
EL
700 &Bytes,\r
701 DeviceAddress,\r
702 Mapping\r
703 );\r
704\r
705 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {\r
1436aea4 706 Status = PciIo->FreeBuffer (PciIo, Pages, (VOID *)AlignedMemory);\r
1847ed0b
EL
707 return EFI_OUT_OF_RESOURCES;\r
708 }\r
d1102dba 709\r
1436aea4 710 *HostAddress = (VOID *)AlignedMemory;\r
1847ed0b
EL
711\r
712 return EFI_SUCCESS;\r
713}\r
714\r
715/**\r
716 Frees memory that was allocated with UsbHcAllocateAlignedPages().\r
d1102dba 717\r
1847ed0b
EL
718 @param PciIo The PciIo that can be used to access the host controller.\r
719 @param HostAddress The system memory address to map to the PCI controller.\r
720 @param Pages The number of 4 KB pages to free.\r
721 @param Mapping The mapping value returned from Map().\r
722\r
723**/\r
724VOID\r
725UsbHcFreeAlignedPages (\r
1436aea4
MK
726 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
727 IN VOID *HostAddress,\r
728 IN UINTN Pages,\r
729 VOID *Mapping\r
1847ed0b
EL
730 )\r
731{\r
1436aea4 732 EFI_STATUS Status;\r
d1102dba 733\r
1847ed0b 734 ASSERT (Pages != 0);\r
d1102dba 735\r
1847ed0b
EL
736 Status = PciIo->Unmap (PciIo, Mapping);\r
737 ASSERT_EFI_ERROR (Status);\r
738\r
739 Status = PciIo->FreeBuffer (\r
740 PciIo,\r
741 Pages,\r
742 HostAddress\r
d1102dba 743 );\r
1847ed0b
EL
744 ASSERT_EFI_ERROR (Status);\r
745}\r