2 Routine procedures for memory allocate/free.
4 Copyright (c) 2013-2015 Intel Corporation.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
15 Allocate a block of memory to be used by the buffer pool.
17 Use Redirect memory services to allocate memmory so that USB DMA transfers do
18 not cause IMR violations on Quark.
20 @param Pool The buffer pool to allocate memory for.
21 @param Pages How many pages to allocate.
23 @return The allocated memory block or NULL if failed.
28 IN USBHC_MEM_POOL
*Pool
,
32 USBHC_MEM_BLOCK
*Block
;
35 EFI_PHYSICAL_ADDRESS MappedAddr
;
38 EFI_PHYSICAL_ADDRESS TempPtr
;
41 PageNumber
= sizeof(USBHC_MEM_BLOCK
)/PAGESIZE
+1;
42 Status
= PeiServicesAllocatePages (
48 if (EFI_ERROR (Status
)) {
51 ZeroMem ((VOID
*)(UINTN
)TempPtr
, PageNumber
*EFI_PAGE_SIZE
);
54 // each bit in the bit array represents USBHC_MEM_UNIT
55 // bytes of memory in the memory block.
57 ASSERT (USBHC_MEM_UNIT
* 8 <= EFI_PAGE_SIZE
);
59 Block
= (USBHC_MEM_BLOCK
*)(UINTN
)TempPtr
;
60 Block
->BufLen
= EFI_PAGES_TO_SIZE (Pages
);
61 Block
->BitsLen
= Block
->BufLen
/ (USBHC_MEM_UNIT
* 8);
63 PageNumber
= (Block
->BitsLen
)/PAGESIZE
+1;
64 Status
= PeiServicesAllocatePages (
69 if (EFI_ERROR (Status
)) {
72 ZeroMem ((VOID
*)(UINTN
)TempPtr
, PageNumber
*EFI_PAGE_SIZE
);
74 Block
->Bits
= (UINT8
*)(UINTN
)TempPtr
;
76 Status
= PeiServicesAllocatePages (
81 ZeroMem ((VOID
*)(UINTN
)TempPtr
, Pages
*EFI_PAGE_SIZE
);
83 BufHost
= (VOID
*)(UINTN
)TempPtr
;
84 MappedAddr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) BufHost
;
86 // Check whether the data structure used by the host controller
87 // should be restricted into the same 4G
89 if (Pool
->Check4G
&& (Pool
->Which4G
!= USB_HC_HIGH_32BIT (MappedAddr
))) {
93 Block
->BufHost
= BufHost
;
94 Block
->Buf
= (UINT8
*) ((UINTN
) MappedAddr
);
95 Block
->Mapping
= Mapping
;
104 Free the memory block from the memory pool.
106 @param Pool The memory pool to free the block from.
107 @param Block The memory block to free.
112 IN USBHC_MEM_POOL
*Pool
,
113 IN USBHC_MEM_BLOCK
*Block
117 ASSERT ((Pool
!= NULL
) && (Block
!= NULL
));
122 Alloc some memory from the block.
124 @param Block The memory block to allocate memory from.
125 @param Units Number of memory units to allocate.
127 @return The pointer to the allocated memory. If couldn't allocate the needed memory,
128 the return value is NULL.
132 UsbHcAllocMemFromBlock (
133 IN USBHC_MEM_BLOCK
*Block
,
144 ASSERT ((Block
!= 0) && (Units
!= 0));
150 for (Byte
= 0, Bit
= 0; Byte
< Block
->BitsLen
;) {
152 // If current bit is zero, the corresponding memory unit is
153 // available, otherwise we need to restart our searching.
154 // Available counts the consective number of zero bit.
156 if (!USB_HC_BIT_IS_SET (Block
->Bits
[Byte
], Bit
)) {
159 if (Available
>= Units
) {
163 NEXT_BIT (Byte
, Bit
);
166 NEXT_BIT (Byte
, Bit
);
174 if (Available
< Units
) {
179 // Mark the memory as allocated
184 for (Count
= 0; Count
< Units
; Count
++) {
185 ASSERT (!USB_HC_BIT_IS_SET (Block
->Bits
[Byte
], Bit
));
187 Block
->Bits
[Byte
] = (UINT8
) (Block
->Bits
[Byte
] | (UINT8
) USB_HC_BIT (Bit
));
188 NEXT_BIT (Byte
, Bit
);
191 return Block
->BufHost
+ (StartByte
* 8 + StartBit
) * USBHC_MEM_UNIT
;
195 Insert the memory block to the pool's list of the blocks.
197 @param Head The head of the memory pool's block list.
198 @param Block The memory block to insert.
202 UsbHcInsertMemBlockToPool (
203 IN USBHC_MEM_BLOCK
*Head
,
204 IN USBHC_MEM_BLOCK
*Block
207 ASSERT ((Head
!= NULL
) && (Block
!= NULL
));
208 Block
->Next
= Head
->Next
;
214 Is the memory block empty?
216 @param Block The memory block to check.
218 @retval TRUE The memory block is empty.
219 @retval FALSE The memory block isn't empty.
223 UsbHcIsMemBlockEmpty (
224 IN USBHC_MEM_BLOCK
*Block
229 for (Index
= 0; Index
< Block
->BitsLen
; Index
++) {
230 if (Block
->Bits
[Index
] != 0) {
240 Unlink the memory block from the pool's list.
242 @param Head The block list head of the memory's pool.
243 @param BlockToUnlink The memory block to unlink.
247 UsbHcUnlinkMemBlock (
248 IN USBHC_MEM_BLOCK
*Head
,
249 IN USBHC_MEM_BLOCK
*BlockToUnlink
252 USBHC_MEM_BLOCK
*Block
;
254 ASSERT ((Head
!= NULL
) && (BlockToUnlink
!= NULL
));
256 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
257 if (Block
->Next
== BlockToUnlink
) {
258 Block
->Next
= BlockToUnlink
->Next
;
259 BlockToUnlink
->Next
= NULL
;
267 Initialize the memory management pool for the host controller.
269 @param PciIo The PciIo that can be used to access the host controller.
270 @param Check4G Whether the host controller requires allocated memory
271 from one 4G address space.
272 @param Which4G The 4G memory area each memory allocated should be from.
274 @retval EFI_SUCCESS The memory pool is initialized.
275 @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
284 USBHC_MEM_POOL
*Pool
;
287 EFI_PHYSICAL_ADDRESS TempPtr
;
289 PageNumber
= sizeof(USBHC_MEM_POOL
)/PAGESIZE
+1;
290 Status
= PeiServicesAllocatePages (
295 if (EFI_ERROR (Status
)) {
298 ZeroMem ((VOID
*)(UINTN
)TempPtr
, PageNumber
*EFI_PAGE_SIZE
);
300 Pool
= (USBHC_MEM_POOL
*) ((UINTN
) TempPtr
);
301 Pool
->Check4G
= Check4G
;
302 Pool
->Which4G
= Which4G
;
303 Pool
->Head
= UsbHcAllocMemBlock (Pool
, USBHC_MEM_DEFAULT_PAGES
);
305 if (Pool
->Head
== NULL
) {
314 Release the memory management pool.
316 @param Pool The USB memory pool to free.
318 @retval EFI_SUCCESS The memory pool is freed.
319 @retval EFI_DEVICE_ERROR Failed to free the memory pool.
324 IN USBHC_MEM_POOL
*Pool
327 USBHC_MEM_BLOCK
*Block
;
329 ASSERT (Pool
->Head
!= NULL
);
332 // Unlink all the memory blocks from the pool, then free them.
333 // UsbHcUnlinkMemBlock can't be used to unlink and free the
336 for (Block
= Pool
->Head
->Next
; Block
!= NULL
; Block
= Pool
->Head
->Next
) {
337 UsbHcFreeMemBlock (Pool
, Block
);
340 UsbHcFreeMemBlock (Pool
, Pool
->Head
);
347 Allocate some memory from the host controller's memory pool
348 which can be used to communicate with host controller.
350 @param Pool The host controller's memory pool.
351 @param Size Size of the memory to allocate.
353 @return The allocated memory or NULL.
358 IN USBHC_MEM_POOL
*Pool
,
362 USBHC_MEM_BLOCK
*Head
;
363 USBHC_MEM_BLOCK
*Block
;
364 USBHC_MEM_BLOCK
*NewBlock
;
370 AllocSize
= USBHC_MEM_ROUND (Size
);
372 ASSERT (Head
!= NULL
);
375 // First check whether current memory blocks can satisfy the allocation.
377 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
378 Mem
= UsbHcAllocMemFromBlock (Block
, AllocSize
/ USBHC_MEM_UNIT
);
391 // Create a new memory block if there is not enough memory
392 // in the pool. If the allocation size is larger than the
393 // default page number, just allocate a large enough memory
394 // block. Otherwise allocate default pages.
396 if (AllocSize
> EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES
)) {
397 Pages
= EFI_SIZE_TO_PAGES (AllocSize
) + 1;
399 Pages
= USBHC_MEM_DEFAULT_PAGES
;
402 NewBlock
= UsbHcAllocMemBlock (Pool
, Pages
);
404 if (NewBlock
== NULL
) {
405 DEBUG ((EFI_D_INFO
, "UsbHcAllocateMem: failed to allocate block\n"));
410 // Add the new memory block to the pool, then allocate memory from it
412 UsbHcInsertMemBlockToPool (Head
, NewBlock
);
413 Mem
= UsbHcAllocMemFromBlock (NewBlock
, AllocSize
/ USBHC_MEM_UNIT
);
424 Free the allocated memory back to the memory pool.
426 @param Pool The memory pool of the host controller.
427 @param Mem The memory to free.
428 @param Size The size of the memory to free.
433 IN USBHC_MEM_POOL
*Pool
,
438 USBHC_MEM_BLOCK
*Head
;
439 USBHC_MEM_BLOCK
*Block
;
447 AllocSize
= USBHC_MEM_ROUND (Size
);
448 ToFree
= (UINT8
*) Mem
;
450 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
452 // scan the memory block list for the memory block that
453 // completely contains the memory to free.
455 if ((Block
->BufHost
<= ToFree
) && ((ToFree
+ AllocSize
) <= (Block
->BufHost
+ Block
->BufLen
))) {
457 // compute the start byte and bit in the bit array
459 Byte
= ((ToFree
- Block
->BufHost
) / USBHC_MEM_UNIT
) / 8;
460 Bit
= ((ToFree
- Block
->BufHost
) / USBHC_MEM_UNIT
) % 8;
463 // reset associated bits in bit arry
465 for (Count
= 0; Count
< (AllocSize
/ USBHC_MEM_UNIT
); Count
++) {
466 ASSERT (USB_HC_BIT_IS_SET (Block
->Bits
[Byte
], Bit
));
468 Block
->Bits
[Byte
] = (UINT8
) (Block
->Bits
[Byte
] ^ USB_HC_BIT (Bit
));
469 NEXT_BIT (Byte
, Bit
);
477 // If Block == NULL, it means that the current memory isn't
478 // in the host controller's pool. This is critical because
479 // the caller has passed in a wrong memory point
481 ASSERT (Block
!= NULL
);
484 // Release the current memory block if it is empty and not the head
486 if ((Block
!= Head
) && UsbHcIsMemBlockEmpty (Block
)) {
487 UsbHcFreeMemBlock (Pool
, Block
);