2 Routine procedures for memory allocate/free.
4 Copyright (c) 2013-2015 Intel Corporation.
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 Allocate a block of memory to be used by the buffer pool.
23 Use Redirect memory services to allocate memmory so that USB DMA transfers do
24 not cause IMR violations on Quark.
26 @param Pool The buffer pool to allocate memory for.
27 @param Pages How many pages to allocate.
29 @return The allocated memory block or NULL if failed.
34 IN USBHC_MEM_POOL
*Pool
,
38 USBHC_MEM_BLOCK
*Block
;
41 EFI_PHYSICAL_ADDRESS MappedAddr
;
44 EFI_PHYSICAL_ADDRESS TempPtr
;
47 PageNumber
= sizeof(USBHC_MEM_BLOCK
)/PAGESIZE
+1;
48 Status
= PeiServicesAllocatePages (
54 if (EFI_ERROR (Status
)) {
57 ZeroMem ((VOID
*)(UINTN
)TempPtr
, PageNumber
*EFI_PAGE_SIZE
);
60 // each bit in the bit array represents USBHC_MEM_UNIT
61 // bytes of memory in the memory block.
63 ASSERT (USBHC_MEM_UNIT
* 8 <= EFI_PAGE_SIZE
);
65 Block
= (USBHC_MEM_BLOCK
*)(UINTN
)TempPtr
;
66 Block
->BufLen
= EFI_PAGES_TO_SIZE (Pages
);
67 Block
->BitsLen
= Block
->BufLen
/ (USBHC_MEM_UNIT
* 8);
69 PageNumber
= (Block
->BitsLen
)/PAGESIZE
+1;
70 Status
= PeiServicesAllocatePages (
75 if (EFI_ERROR (Status
)) {
78 ZeroMem ((VOID
*)(UINTN
)TempPtr
, PageNumber
*EFI_PAGE_SIZE
);
80 Block
->Bits
= (UINT8
*)(UINTN
)TempPtr
;
82 Status
= PeiServicesAllocatePages (
87 ZeroMem ((VOID
*)(UINTN
)TempPtr
, Pages
*EFI_PAGE_SIZE
);
89 BufHost
= (VOID
*)(UINTN
)TempPtr
;
90 MappedAddr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) BufHost
;
92 // Check whether the data structure used by the host controller
93 // should be restricted into the same 4G
95 if (Pool
->Check4G
&& (Pool
->Which4G
!= USB_HC_HIGH_32BIT (MappedAddr
))) {
99 Block
->BufHost
= BufHost
;
100 Block
->Buf
= (UINT8
*) ((UINTN
) MappedAddr
);
101 Block
->Mapping
= Mapping
;
110 Free the memory block from the memory pool.
112 @param Pool The memory pool to free the block from.
113 @param Block The memory block to free.
118 IN USBHC_MEM_POOL
*Pool
,
119 IN USBHC_MEM_BLOCK
*Block
123 ASSERT ((Pool
!= NULL
) && (Block
!= NULL
));
128 Alloc some memory from the block.
130 @param Block The memory block to allocate memory from.
131 @param Units Number of memory units to allocate.
133 @return The pointer to the allocated memory. If couldn't allocate the needed memory,
134 the return value is NULL.
138 UsbHcAllocMemFromBlock (
139 IN USBHC_MEM_BLOCK
*Block
,
150 ASSERT ((Block
!= 0) && (Units
!= 0));
156 for (Byte
= 0, Bit
= 0; Byte
< Block
->BitsLen
;) {
158 // If current bit is zero, the corresponding memory unit is
159 // available, otherwise we need to restart our searching.
160 // Available counts the consective number of zero bit.
162 if (!USB_HC_BIT_IS_SET (Block
->Bits
[Byte
], Bit
)) {
165 if (Available
>= Units
) {
169 NEXT_BIT (Byte
, Bit
);
172 NEXT_BIT (Byte
, Bit
);
180 if (Available
< Units
) {
185 // Mark the memory as allocated
190 for (Count
= 0; Count
< Units
; Count
++) {
191 ASSERT (!USB_HC_BIT_IS_SET (Block
->Bits
[Byte
], Bit
));
193 Block
->Bits
[Byte
] = (UINT8
) (Block
->Bits
[Byte
] | (UINT8
) USB_HC_BIT (Bit
));
194 NEXT_BIT (Byte
, Bit
);
197 return Block
->BufHost
+ (StartByte
* 8 + StartBit
) * USBHC_MEM_UNIT
;
201 Insert the memory block to the pool's list of the blocks.
203 @param Head The head of the memory pool's block list.
204 @param Block The memory block to insert.
208 UsbHcInsertMemBlockToPool (
209 IN USBHC_MEM_BLOCK
*Head
,
210 IN USBHC_MEM_BLOCK
*Block
213 ASSERT ((Head
!= NULL
) && (Block
!= NULL
));
214 Block
->Next
= Head
->Next
;
220 Is the memory block empty?
222 @param Block The memory block to check.
224 @retval TRUE The memory block is empty.
225 @retval FALSE The memory block isn't empty.
229 UsbHcIsMemBlockEmpty (
230 IN USBHC_MEM_BLOCK
*Block
235 for (Index
= 0; Index
< Block
->BitsLen
; Index
++) {
236 if (Block
->Bits
[Index
] != 0) {
246 Unlink the memory block from the pool's list.
248 @param Head The block list head of the memory's pool.
249 @param BlockToUnlink The memory block to unlink.
253 UsbHcUnlinkMemBlock (
254 IN USBHC_MEM_BLOCK
*Head
,
255 IN USBHC_MEM_BLOCK
*BlockToUnlink
258 USBHC_MEM_BLOCK
*Block
;
260 ASSERT ((Head
!= NULL
) && (BlockToUnlink
!= NULL
));
262 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
263 if (Block
->Next
== BlockToUnlink
) {
264 Block
->Next
= BlockToUnlink
->Next
;
265 BlockToUnlink
->Next
= NULL
;
273 Initialize the memory management pool for the host controller.
275 @param PciIo The PciIo that can be used to access the host controller.
276 @param Check4G Whether the host controller requires allocated memory
277 from one 4G address space.
278 @param Which4G The 4G memory area each memory allocated should be from.
280 @retval EFI_SUCCESS The memory pool is initialized.
281 @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
290 USBHC_MEM_POOL
*Pool
;
293 EFI_PHYSICAL_ADDRESS TempPtr
;
295 PageNumber
= sizeof(USBHC_MEM_POOL
)/PAGESIZE
+1;
296 Status
= PeiServicesAllocatePages (
301 if (EFI_ERROR (Status
)) {
304 ZeroMem ((VOID
*)(UINTN
)TempPtr
, PageNumber
*EFI_PAGE_SIZE
);
306 Pool
= (USBHC_MEM_POOL
*) ((UINTN
) TempPtr
);
307 Pool
->Check4G
= Check4G
;
308 Pool
->Which4G
= Which4G
;
309 Pool
->Head
= UsbHcAllocMemBlock (Pool
, USBHC_MEM_DEFAULT_PAGES
);
311 if (Pool
->Head
== NULL
) {
320 Release the memory management pool.
322 @param Pool The USB memory pool to free.
324 @retval EFI_SUCCESS The memory pool is freed.
325 @retval EFI_DEVICE_ERROR Failed to free the memory pool.
330 IN USBHC_MEM_POOL
*Pool
333 USBHC_MEM_BLOCK
*Block
;
335 ASSERT (Pool
->Head
!= NULL
);
338 // Unlink all the memory blocks from the pool, then free them.
339 // UsbHcUnlinkMemBlock can't be used to unlink and free the
342 for (Block
= Pool
->Head
->Next
; Block
!= NULL
; Block
= Pool
->Head
->Next
) {
343 UsbHcFreeMemBlock (Pool
, Block
);
346 UsbHcFreeMemBlock (Pool
, Pool
->Head
);
353 Allocate some memory from the host controller's memory pool
354 which can be used to communicate with host controller.
356 @param Pool The host controller's memory pool.
357 @param Size Size of the memory to allocate.
359 @return The allocated memory or NULL.
364 IN USBHC_MEM_POOL
*Pool
,
368 USBHC_MEM_BLOCK
*Head
;
369 USBHC_MEM_BLOCK
*Block
;
370 USBHC_MEM_BLOCK
*NewBlock
;
376 AllocSize
= USBHC_MEM_ROUND (Size
);
378 ASSERT (Head
!= NULL
);
381 // First check whether current memory blocks can satisfy the allocation.
383 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
384 Mem
= UsbHcAllocMemFromBlock (Block
, AllocSize
/ USBHC_MEM_UNIT
);
397 // Create a new memory block if there is not enough memory
398 // in the pool. If the allocation size is larger than the
399 // default page number, just allocate a large enough memory
400 // block. Otherwise allocate default pages.
402 if (AllocSize
> EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES
)) {
403 Pages
= EFI_SIZE_TO_PAGES (AllocSize
) + 1;
405 Pages
= USBHC_MEM_DEFAULT_PAGES
;
408 NewBlock
= UsbHcAllocMemBlock (Pool
, Pages
);
410 if (NewBlock
== NULL
) {
411 DEBUG ((EFI_D_INFO
, "UsbHcAllocateMem: failed to allocate block\n"));
416 // Add the new memory block to the pool, then allocate memory from it
418 UsbHcInsertMemBlockToPool (Head
, NewBlock
);
419 Mem
= UsbHcAllocMemFromBlock (NewBlock
, AllocSize
/ USBHC_MEM_UNIT
);
430 Free the allocated memory back to the memory pool.
432 @param Pool The memory pool of the host controller.
433 @param Mem The memory to free.
434 @param Size The size of the memory to free.
439 IN USBHC_MEM_POOL
*Pool
,
444 USBHC_MEM_BLOCK
*Head
;
445 USBHC_MEM_BLOCK
*Block
;
453 AllocSize
= USBHC_MEM_ROUND (Size
);
454 ToFree
= (UINT8
*) Mem
;
456 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
458 // scan the memory block list for the memory block that
459 // completely contains the memory to free.
461 if ((Block
->BufHost
<= ToFree
) && ((ToFree
+ AllocSize
) <= (Block
->BufHost
+ Block
->BufLen
))) {
463 // compute the start byte and bit in the bit array
465 Byte
= ((ToFree
- Block
->BufHost
) / USBHC_MEM_UNIT
) / 8;
466 Bit
= ((ToFree
- Block
->BufHost
) / USBHC_MEM_UNIT
) % 8;
469 // reset associated bits in bit arry
471 for (Count
= 0; Count
< (AllocSize
/ USBHC_MEM_UNIT
); Count
++) {
472 ASSERT (USB_HC_BIT_IS_SET (Block
->Bits
[Byte
], Bit
));
474 Block
->Bits
[Byte
] = (UINT8
) (Block
->Bits
[Byte
] ^ USB_HC_BIT (Bit
));
475 NEXT_BIT (Byte
, Bit
);
483 // If Block == NULL, it means that the current memory isn't
484 // in the host controller's pool. This is critical because
485 // the caller has passed in a wrong memory point
487 ASSERT (Block
!= NULL
);
490 // Release the current memory block if it is empty and not the head
492 if ((Block
!= Head
) && UsbHcIsMemBlockEmpty (Block
)) {
493 UsbHcFreeMemBlock (Pool
, Block
);