--- /dev/null
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation \r
+All rights reserved. This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php \r
+ \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+Module Name:\r
+\r
+ EhciMem.c\r
+ \r
+Abstract: \r
+ \r
+\r
+Revision History\r
+--*/\r
+\r
+#include "Ehci.h"\r
+\r
+\r
+EFI_STATUS\r
+CreateMemoryBlock (\r
+ IN USB2_HC_DEV *HcDev,\r
+ OUT MEMORY_MANAGE_HEADER **MemoryHeader,\r
+ IN UINTN MemoryBlockSizeInPages\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Use PciIo->AllocateBuffer to allocate common buffer for the memory block,\r
+ and use PciIo->Map to map the common buffer for Bus Master Read/Write.\r
+\r
+Arguments:\r
+\r
+ HcDev - USB2_HC_DEV\r
+ MemoryHeader - MEMORY_MANAGE_HEADER to output\r
+ MemoryBlockSizeInPages - MemoryBlockSizeInPages\r
+ \r
+Returns:\r
+\r
+ EFI_SUCCESS Success\r
+ EFI_OUT_OF_RESOURCES Fail for no resources\r
+ EFI_UNSUPPORTED Unsupported currently\r
+ \r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *CommonBuffer;\r
+ EFI_PHYSICAL_ADDRESS MappedAddress;\r
+ UINTN MemoryBlockSizeInBytes;\r
+ VOID *Mapping;\r
+\r
+ //\r
+ // Allocate memory for MemoryHeader\r
+ //\r
+ *MemoryHeader = AllocateZeroPool (sizeof (MEMORY_MANAGE_HEADER));\r
+ if (*MemoryHeader == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ (*MemoryHeader)->Next = NULL;\r
+\r
+ //\r
+ // set Memory block size\r
+ //\r
+ (*MemoryHeader)->MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);\r
+\r
+ //\r
+ // each bit in Bit Array will manage 32 bytes memory in memory block\r
+ //\r
+ (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;\r
+\r
+ //\r
+ // Allocate memory for BitArray\r
+ //\r
+ (*MemoryHeader)->BitArrayPtr = AllocateZeroPool ((*MemoryHeader)->BitArraySizeInBytes);\r
+ if ((*MemoryHeader)->BitArrayPtr == NULL) {\r
+ gBS->FreePool (*MemoryHeader);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ \r
+ //\r
+ // Memory Block uses MemoryBlockSizeInPages pages,\r
+ // and it is allocated as common buffer use.\r
+ //\r
+ Status = HcDev->PciIo->AllocateBuffer (\r
+ HcDev->PciIo,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ MemoryBlockSizeInPages,\r
+ &CommonBuffer,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool ((*MemoryHeader)->BitArrayPtr);\r
+ gBS->FreePool (*MemoryHeader);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);\r
+ Status = HcDev->PciIo->Map (\r
+ HcDev->PciIo,\r
+ EfiPciIoOperationBusMasterCommonBuffer,\r
+ CommonBuffer,\r
+ &MemoryBlockSizeInBytes,\r
+ &MappedAddress,\r
+ &Mapping\r
+ );\r
+ //\r
+ // If returned Mapped size is less than the size \r
+ // we request,do not support.\r
+ //\r
+ if (EFI_ERROR (Status) || (MemoryBlockSizeInBytes != EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages))) {\r
+ HcDev->PciIo->FreeBuffer (HcDev->PciIo, MemoryBlockSizeInPages, CommonBuffer);\r
+ gBS->FreePool ((*MemoryHeader)->BitArrayPtr);\r
+ gBS->FreePool (*MemoryHeader);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ \r
+ //\r
+ // Data structure involved by host controller \r
+ // should be restricted into the same 4G\r
+ //\r
+ if (HcDev->Is64BitCapable != 0) {\r
+ if (HcDev->High32BitAddr != GET_32B_TO_63B (MappedAddress)) {\r
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);\r
+ HcDev->PciIo->FreeBuffer (HcDev->PciIo, MemoryBlockSizeInPages, CommonBuffer);\r
+ gBS->FreePool ((*MemoryHeader)->BitArrayPtr);\r
+ gBS->FreePool (*MemoryHeader);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Set Memory block initial address\r
+ //\r
+ (*MemoryHeader)->MemoryBlockPtr = (UINT8 *) ((UINTN) MappedAddress);\r
+ (*MemoryHeader)->Mapping = Mapping;\r
+\r
+ ZeroMem (\r
+ (*MemoryHeader)->MemoryBlockPtr,\r
+ EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages)\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FreeMemoryHeader (\r
+ IN USB2_HC_DEV *HcDev,\r
+ IN MEMORY_MANAGE_HEADER *MemoryHeader\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Free Memory Header\r
+\r
+Arguments:\r
+\r
+ HcDev - USB2_HC_DEV\r
+ MemoryHeader - MemoryHeader to be freed\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Success\r
+ EFI_INVALID_PARAMETER Parameter is error\r
+\r
+--*/\r
+{\r
+ if ((MemoryHeader == NULL) || (HcDev == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // unmap the common buffer used by the memory block\r
+ //\r
+ HcDev->PciIo->Unmap (HcDev->PciIo, MemoryHeader->Mapping);\r
+\r
+ //\r
+ // free common buffer\r
+ //\r
+ HcDev->PciIo->FreeBuffer (\r
+ HcDev->PciIo,\r
+ EFI_SIZE_TO_PAGES (MemoryHeader->MemoryBlockSizeInBytes),\r
+ MemoryHeader->MemoryBlockPtr\r
+ );\r
+ //\r
+ // free bit array\r
+ //\r
+ gBS->FreePool (MemoryHeader->BitArrayPtr);\r
+ //\r
+ // free memory header\r
+ //\r
+ gBS->FreePool (MemoryHeader);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EhciAllocatePool (\r
+ IN USB2_HC_DEV *HcDev,\r
+ OUT UINT8 **Pool,\r
+ IN UINTN AllocSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Ehci Allocate Pool\r
+\r
+Arguments:\r
+\r
+ HcDev - USB2_HC_DEV\r
+ Pool - Place to store pointer to the memory buffer\r
+ AllocSize - Alloc Size\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Success\r
+ EFI_DEVICE_ERROR Fail\r
+\r
+--*/\r
+{\r
+ MEMORY_MANAGE_HEADER *MemoryHeader;\r
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
+ MEMORY_MANAGE_HEADER *NewMemoryHeader;\r
+ UINTN RealAllocSize;\r
+ UINTN MemoryBlockSizeInPages;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+\r
+ *Pool = NULL;\r
+\r
+ MemoryHeader = HcDev->MemoryHeader;\r
+ ASSERT (MemoryHeader != NULL);\r
+\r
+ OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY + 1);\r
+ \r
+ //\r
+ // allocate unit is 32 bytes (align on 32 byte)\r
+ //\r
+ if (AllocSize & 0x1F) {\r
+ RealAllocSize = (AllocSize / 32 + 1) * 32;\r
+ } else {\r
+ RealAllocSize = AllocSize;\r
+ }\r
+ \r
+ //\r
+ // There may be linked MemoryHeaders.\r
+ // To allocate a free pool in Memory blocks,\r
+ // must search in the MemoryHeader link list\r
+ // until enough free pool is found.\r
+ //\r
+ Status = EFI_NOT_FOUND;\r
+ for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {\r
+\r
+ Status = AllocMemInMemoryBlock (\r
+ TempHeaderPtr,\r
+ Pool,\r
+ RealAllocSize / 32\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ ZeroMem (*Pool, AllocSize);\r
+ gBS->RestoreTPL (OldTpl);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+ \r
+ //\r
+ // There is no enough memory,\r
+ // Create a new Memory Block\r
+ //\r
+ \r
+ //\r
+ // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,\r
+ // just allocate a large enough memory block.\r
+ //\r
+ if (RealAllocSize > EFI_PAGES_TO_SIZE (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES)) {\r
+ MemoryBlockSizeInPages = EFI_SIZE_TO_PAGES (RealAllocSize) + 1;\r
+ } else {\r
+ MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;\r
+ }\r
+\r
+ Status = CreateMemoryBlock (HcDev, &NewMemoryHeader, MemoryBlockSizeInPages);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY + 1);\r\r
+ \r
+ //\r
+ // Link the new Memory Block to the Memory Header list\r
+ //\r
+ InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);\r
+\r
+ Status = AllocMemInMemoryBlock (\r
+ NewMemoryHeader,\r
+ Pool,\r
+ RealAllocSize / 32\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ ZeroMem (*Pool, AllocSize);\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+VOID\r
+EhciFreePool (\r
+ IN USB2_HC_DEV *HcDev,\r
+ IN UINT8 *Pool,\r
+ IN UINTN AllocSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Uhci Free Pool\r
+\r
+Arguments:\r
+\r
+ HcDev - USB_HC_DEV\r
+ Pool - Pool to free\r
+ AllocSize - Pool size\r
+\r
+Returns:\r
+\r
+ VOID\r
+\r
+--*/\r
+{\r
+ MEMORY_MANAGE_HEADER *MemoryHeader;\r
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
+ UINTN StartBytePos;\r
+ UINTN Index;\r
+ UINT8 StartBitPos;\r
+ UINT8 Index2;\r
+ UINTN Count;\r
+ UINTN RealAllocSize;\r
+ EFI_TPL OldTpl;\r
+\r
+ OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY + 1);\r
+\r
+ MemoryHeader = HcDev->MemoryHeader;\r
+\r
+ //\r
+ // allocate unit is 32 byte (align on 32 byte)\r
+ //\r
+ if (AllocSize & 0x1F) {\r
+ RealAllocSize = (AllocSize / 32 + 1) * 32;\r
+ } else {\r
+ RealAllocSize = AllocSize;\r
+ }\r
+ \r
+ //\r
+ // scan the memory header linked list for\r
+ // the asigned memory to free.\r
+ //\r
+ for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {\r
+\r
+ if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&\r
+ ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr + TempHeaderPtr->MemoryBlockSizeInBytes))\r
+ ) {\r
+ //\r
+ // Pool is in the Memory Block area,\r
+ // find the start byte and bit in the bit array\r
+ //\r
+ StartBytePos = ((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) / 8;\r
+ StartBitPos = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) & 0x7);\r
+\r
+ //\r
+ // reset associated bits in bit arry\r
+ //\r
+ for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {\r
+ TempHeaderPtr->BitArrayPtr[Index] ^= (UINT8) (bit (Index2));\r
+ Index2++;\r
+ if (Index2 == 8) {\r
+ Index += 1;\r
+ Index2 = 0;\r
+ }\r
+ }\r
+ //\r
+ // break the loop\r
+ //\r
+ break;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Release emptied memory blocks (only if the memory block is not\r
+ // the first one in the memory header list\r
+ //\r
+ for (TempHeaderPtr = MemoryHeader->Next; TempHeaderPtr != NULL;) {\r
+\r
+ ASSERT (MemoryHeader->Next != NULL);\r
+\r
+ if (IsMemoryBlockEmptied (TempHeaderPtr)) {\r
+\r
+ DelinkMemoryBlock (MemoryHeader, TempHeaderPtr);\r
+ //\r
+ // when the TempHeaderPtr is freed in FreeMemoryHeader(),\r
+ // the TempHeaderPtr is pointing to nonsense content.\r
+ //\r
+ gBS->RestoreTPL (OldTpl);\r
+ FreeMemoryHeader (HcDev, TempHeaderPtr);\r
+ OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY + 1);\r
+ //\r
+ // reset the TempHeaderPtr, continue search for\r
+ // another empty memory block.\r
+ //\r
+ TempHeaderPtr = MemoryHeader->Next;\r
+ continue;\r
+ }\r
+\r
+ TempHeaderPtr = TempHeaderPtr->Next;\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+}\r
+\r
+VOID\r
+InsertMemoryHeaderToList (\r
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,\r
+ IN MEMORY_MANAGE_HEADER *NewMemoryHeader\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Insert Memory Header To List\r
+\r
+Arguments:\r
+\r
+ MemoryHeader - MEMORY_MANAGE_HEADER\r
+ NewMemoryHeader - MEMORY_MANAGE_HEADER\r
+\r
+Returns:\r
+\r
+ VOID\r
+\r
+--*/\r
+{\r
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
+\r
+ for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {\r
+ if (TempHeaderPtr->Next == NULL) {\r
+ TempHeaderPtr->Next = NewMemoryHeader;\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+EFI_STATUS\r
+AllocMemInMemoryBlock (\r
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,\r
+ OUT VOID **Pool,\r
+ IN UINTN NumberOfMemoryUnit\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Alloc Memory In MemoryBlock\r
+\r
+Arguments:\r
+\r
+ MemoryHeader - MEMORY_MANAGE_HEADER\r
+ Pool - Place to store pointer to memory\r
+ NumberOfMemoryUnit - Number Of Memory Unit\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Success\r
+ EFI_NOT_FOUND Can't find the free memory \r
+\r
+--*/\r
+{\r
+ UINTN TempBytePos;\r
+ UINTN FoundBytePos;\r
+ UINT8 Index;\r
+ UINT8 FoundBitPos;\r
+ UINT8 ByteValue;\r
+ UINT8 BitValue;\r
+ UINTN NumberOfZeros;\r
+ UINTN Count;\r
+\r
+ FoundBytePos = 0;\r
+ FoundBitPos = 0;\r
+ ByteValue = MemoryHeader->BitArrayPtr[0];\r
+ NumberOfZeros = 0;\r
+ Index = 0;\r
+\r
+ for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes;) {\r
+ \r
+ //\r
+ // Pop out BitValue from a byte in TempBytePos.\r
+ //\r
+ BitValue = (UINT8) (ByteValue & 0x1);\r
+ \r
+ //\r
+ // right shift the byte\r
+ //\r
+ ByteValue /= 2;\r
+\r
+ if (BitValue == 0) {\r
+ //\r
+ // Found a free bit, the NumberOfZeros only record the number\r
+ // of those consecutive zeros\r
+ //\r
+ NumberOfZeros++;\r
+ //\r
+ // Found enough consecutive free space, break the loop\r
+ //\r
+ if (NumberOfZeros >= NumberOfMemoryUnit) {\r
+ break;\r
+ }\r
+ } else {\r
+ //\r
+ // Encountering a '1', meant the bit is ocupied.\r
+ //\r
+ if (NumberOfZeros >= NumberOfMemoryUnit) {\r
+ //\r
+ // Found enough consecutive free space,break the loop\r
+ //\r
+ break;\r
+ } else {\r
+ //\r
+ // the NumberOfZeros only record the number of those consecutive zeros,\r
+ // so reset the NumberOfZeros to 0 when encountering '1' before finding\r
+ // enough consecutive '0's\r
+ //\r
+ NumberOfZeros = 0;\r
+ //\r
+ // reset the (FoundBytePos,FoundBitPos) to the position of '1'\r
+ //\r
+ FoundBytePos = TempBytePos;\r
+ FoundBitPos = Index;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // step forward a bit\r
+ //\r
+ Index++;\r
+ if (Index == 8) {\r
+ //\r
+ // step forward a byte, getting the byte value,\r
+ // and reset the bit pos.\r
+ //\r
+ TempBytePos += 1;\r
+ ByteValue = MemoryHeader->BitArrayPtr[TempBytePos];\r
+ Index = 0;\r
+ }\r
+ }\r
+\r
+ if (NumberOfZeros < NumberOfMemoryUnit) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ \r
+ //\r
+ // Found enough free space.\r
+ //\r
+ \r
+ //\r
+ // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:\r
+ // 1)(FoundBytePos,FoundBitPos) record the position\r
+ // of the last '1' before the consecutive '0's, it must\r
+ // be adjusted to the start position of the consecutive '0's.\r
+ // 2)the start address of the consecutive '0's is just the start of\r
+ // the bitarray. so no need to adjust the values of\r
+ // (FoundBytePos,FoundBitPos).\r
+ //\r
+ if ((MemoryHeader->BitArrayPtr[FoundBytePos] & bit (FoundBitPos)) != 0) {\r
+ FoundBitPos += 1;\r
+ }\r
+ \r
+ //\r
+ // Have the (FoundBytePos,FoundBitPos) make sense.\r
+ //\r
+ if (FoundBitPos > 7) {\r
+ FoundBytePos += 1;\r
+ FoundBitPos -= 8;\r
+ }\r
+ \r
+ //\r
+ // Set the memory as allocated\r
+ //\r
+ for (TempBytePos = FoundBytePos, Index = FoundBitPos, Count = 0; Count < NumberOfMemoryUnit; Count++) {\r
+\r
+ MemoryHeader->BitArrayPtr[TempBytePos] |= bit (Index);\r
+ Index++;\r
+ if (Index == 8) {\r
+ TempBytePos += 1;\r
+ Index = 0;\r
+ }\r
+ }\r
+\r
+ *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+IsMemoryBlockEmptied (\r
+ IN MEMORY_MANAGE_HEADER *MemoryHeaderPtr\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Is Memory Block Emptied\r
+\r
+Arguments:\r
+\r
+ MemoryHeaderPtr - MEMORY_MANAGE_HEADER\r
+\r
+Returns:\r
+\r
+ TRUE Empty\r
+ FALSE Not Empty \r
+\r
+--*/\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < MemoryHeaderPtr->BitArraySizeInBytes; Index++) {\r
+ if (MemoryHeaderPtr->BitArrayPtr[Index] != 0) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+VOID\r
+DelinkMemoryBlock (\r
+ IN MEMORY_MANAGE_HEADER *FirstMemoryHeader,\r
+ IN MEMORY_MANAGE_HEADER *NeedFreeMemoryHeader\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Delink Memory Block\r
+\r
+Arguments:\r
+\r
+ FirstMemoryHeader - MEMORY_MANAGE_HEADER\r
+ NeedFreeMemoryHeader - MEMORY_MANAGE_HEADER\r
+\r
+Returns:\r
+\r
+ VOID\r
+\r
+--*/\r
+{\r
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
+\r
+ if ((FirstMemoryHeader == NULL) || (NeedFreeMemoryHeader == NULL)) {\r
+ return ;\r
+ }\r
+\r
+ for (TempHeaderPtr = FirstMemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {\r
+\r
+ if (TempHeaderPtr->Next == NeedFreeMemoryHeader) {\r
+ //\r
+ // Link the before and after\r
+ //\r
+ TempHeaderPtr->Next = NeedFreeMemoryHeader->Next;\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+EFI_STATUS\r
+InitialMemoryManagement (\r
+ IN USB2_HC_DEV *HcDev\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initialize Memory Management\r
+\r
+Arguments:\r
+\r
+ HcDev - USB2_HC_DEV\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Success\r
+ EFI_DEVICE_ERROR Fail\r
+ \r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ MEMORY_MANAGE_HEADER *MemoryHeader;\r
+ UINTN MemPages;\r
+\r
+ MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;\r
+ Status = CreateMemoryBlock (HcDev, &MemoryHeader, MemPages);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto exit;\r
+ }\r
+\r
+ HcDev->MemoryHeader = MemoryHeader;\r
+\r
+exit:\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+DeinitialMemoryManagement (\r
+ IN USB2_HC_DEV *HcDev\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Deinitialize Memory Management\r
+\r
+Arguments:\r
+\r
+ HcDev - USB2_HC_DEV\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Success\r
+ EFI_DEVICE_ERROR Fail\r
+ \r
+--*/\r
+{\r
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
+\r
+ for (TempHeaderPtr = HcDev->MemoryHeader->Next; TempHeaderPtr != NULL;) {\r
+\r
+ DelinkMemoryBlock (HcDev->MemoryHeader, TempHeaderPtr);\r
+ //\r
+ // when the TempHeaderPtr is freed in FreeMemoryHeader(),\r
+ // the TempHeaderPtr is pointing to nonsense content.\r
+ //\r
+ FreeMemoryHeader (HcDev, TempHeaderPtr);\r
+ //\r
+ // reset the TempHeaderPtr,continue free another memory block.\r
+ //\r
+ TempHeaderPtr = HcDev->MemoryHeader->Next;\r
+ }\r
+\r
+ FreeMemoryHeader (HcDev, HcDev->MemoryHeader);\r
+\r
+ return EFI_SUCCESS;\r
+}\r