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