+++ /dev/null
-/** @file\r
-Routine procedures for memory allocate/free.\r
-\r
-Copyright (c) 2013-2015 Intel Corporation.\r
-\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-\r
-#include "Ohci.h"\r
-\r
-\r
-/**\r
- Allocate a block of memory to be used by the buffer pool.\r
-\r
- @param Pool The buffer pool to allocate memory for.\r
- @param Pages How many pages to allocate.\r
-\r
- @return The allocated memory block or NULL if failed.\r
-\r
-**/\r
-USBHC_MEM_BLOCK *\r
-UsbHcAllocMemBlock (\r
- IN USBHC_MEM_POOL *Pool,\r
- IN UINTN Pages\r
- )\r
-{\r
- USBHC_MEM_BLOCK *Block;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- VOID *BufHost;\r
- VOID *Mapping;\r
- EFI_PHYSICAL_ADDRESS MappedAddr;\r
- UINTN Bytes;\r
- EFI_STATUS Status;\r
-\r
- PciIo = Pool->PciIo;\r
-\r
- Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));\r
- if (Block == NULL) {\r
- return NULL;\r
- }\r
-\r
- //\r
- // each bit in the bit array represents USBHC_MEM_UNIT\r
- // bytes of memory in the memory block.\r
- //\r
- ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
-\r
- Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
- Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
- Block->Bits = AllocateZeroPool (Block->BitsLen);\r
-\r
- if (Block->Bits == NULL) {\r
- gBS->FreePool (Block);\r
- return NULL;\r
- }\r
-\r
- //\r
- // Allocate the number of Pages of memory, then map it for\r
- // bus master read and write.\r
- //\r
- Status = PciIo->AllocateBuffer (\r
- PciIo,\r
- AllocateAnyPages,\r
- EfiBootServicesData,\r
- Pages,\r
- &BufHost,\r
- 0\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto FREE_BITARRAY;\r
- }\r
-\r
- Bytes = EFI_PAGES_TO_SIZE (Pages);\r
- Status = PciIo->Map (\r
- PciIo,\r
- EfiPciIoOperationBusMasterCommonBuffer,\r
- BufHost,\r
- &Bytes,\r
- &MappedAddr,\r
- &Mapping\r
- );\r
-\r
- if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {\r
- goto FREE_BUFFER;\r
- }\r
-\r
- //\r
- // Check whether the data structure used by the host controller\r
- // should be restricted into the same 4G\r
- //\r
- if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {\r
- PciIo->Unmap (PciIo, Mapping);\r
- goto FREE_BUFFER;\r
- }\r
-\r
- Block->BufHost = BufHost;\r
- Block->Buf = (UINT8 *) ((UINTN) MappedAddr);\r
- Block->Mapping = Mapping;\r
-\r
- return Block;\r
-\r
-FREE_BUFFER:\r
- PciIo->FreeBuffer (PciIo, Pages, BufHost);\r
-\r
-FREE_BITARRAY:\r
- gBS->FreePool (Block->Bits);\r
- gBS->FreePool (Block);\r
- return NULL;\r
-}\r
-\r
-\r
-/**\r
- Free the memory block from the memory pool.\r
-\r
- @param Pool The memory pool to free the block from.\r
- @param Block The memory block to free.\r
-\r
-**/\r
-VOID\r
-UsbHcFreeMemBlock (\r
- IN USBHC_MEM_POOL *Pool,\r
- IN USBHC_MEM_BLOCK *Block\r
- )\r
-{\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
-\r
- ASSERT ((Pool != NULL) && (Block != NULL));\r
-\r
- PciIo = Pool->PciIo;\r
-\r
- //\r
- // Unmap the common buffer then free the structures\r
- //\r
- PciIo->Unmap (PciIo, Block->Mapping);\r
- PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);\r
-\r
- gBS->FreePool (Block->Bits);\r
- gBS->FreePool (Block);\r
-}\r
-\r
-\r
-/**\r
- Alloc some memory from the block.\r
-\r
- @param Block The memory block to allocate memory from.\r
- @param Units Number of memory units to allocate.\r
-\r
- @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
- the return value is NULL.\r
-\r
-**/\r
-VOID *\r
-UsbHcAllocMemFromBlock (\r
- IN USBHC_MEM_BLOCK *Block,\r
- IN UINTN Units\r
- )\r
-{\r
- UINTN Byte;\r
- UINT8 Bit;\r
- UINTN StartByte;\r
- UINT8 StartBit;\r
- UINTN Available;\r
- UINTN Count;\r
-\r
- ASSERT ((Block != 0) && (Units != 0));\r
-\r
- StartByte = 0;\r
- StartBit = 0;\r
- Available = 0;\r
-\r
- for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
- //\r
- // If current bit is zero, the corresponding memory unit is\r
- // available, otherwise we need to restart our searching.\r
- // Available counts the consective number of zero bit.\r
- //\r
- if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
- Available++;\r
-\r
- if (Available >= Units) {\r
- break;\r
- }\r
-\r
- NEXT_BIT (Byte, Bit);\r
-\r
- } else {\r
- NEXT_BIT (Byte, Bit);\r
-\r
- Available = 0;\r
- StartByte = Byte;\r
- StartBit = Bit;\r
- }\r
- }\r
-\r
- if (Available < Units) {\r
- return NULL;\r
- }\r
-\r
- //\r
- // Mark the memory as allocated\r
- //\r
- Byte = StartByte;\r
- Bit = StartBit;\r
-\r
- for (Count = 0; Count < Units; Count++) {\r
- ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
-\r
- Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | USB_HC_BIT (Bit));\r
- NEXT_BIT (Byte, Bit);\r
- }\r
-\r
- return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
-}\r
-\r
-/**\r
- Calculate the corresponding pci bus address according to the Mem parameter.\r
-\r
- @param Pool The memory pool of the host controller.\r
- @param Mem The pointer to host memory.\r
- @param Size The size of the memory region.\r
-\r
- @return the pci memory address\r
-**/\r
-EFI_PHYSICAL_ADDRESS\r
-UsbHcGetPciAddressForHostMem (\r
- IN USBHC_MEM_POOL *Pool,\r
- IN VOID *Mem,\r
- IN UINTN Size\r
- )\r
-{\r
- USBHC_MEM_BLOCK *Head;\r
- USBHC_MEM_BLOCK *Block;\r
- UINTN AllocSize;\r
- EFI_PHYSICAL_ADDRESS PhyAddr;\r
- UINTN Offset;\r
-\r
- Head = Pool->Head;\r
- AllocSize = USBHC_MEM_ROUND (Size);\r
-\r
- if (Mem == NULL) {\r
- return 0;\r
- }\r
-\r
- for (Block = Head; Block != NULL; Block = Block->Next) {\r
- //\r
- // scan the memory block list for the memory block that\r
- // completely contains the allocated memory.\r
- //\r
- if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
- break;\r
- }\r
- }\r
-\r
- ASSERT ((Block != NULL));\r
- //\r
- // calculate the pci memory address for host memory address.\r
- //\r
- Offset = (UINT8 *)Mem - Block->BufHost;\r
- PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset);\r
- return PhyAddr;\r
-}\r
-\r
-\r
-/**\r
- Insert the memory block to the pool's list of the blocks.\r
-\r
- @param Head The head of the memory pool's block list.\r
- @param Block The memory block to insert.\r
-\r
-**/\r
-VOID\r
-UsbHcInsertMemBlockToPool (\r
- IN USBHC_MEM_BLOCK *Head,\r
- IN USBHC_MEM_BLOCK *Block\r
- )\r
-{\r
- ASSERT ((Head != NULL) && (Block != NULL));\r
- Block->Next = Head->Next;\r
- Head->Next = Block;\r
-}\r
-\r
-\r
-/**\r
- Is the memory block empty?\r
-\r
- @param Block The memory block to check.\r
-\r
- @retval TRUE The memory block is empty.\r
- @retval FALSE The memory block isn't empty.\r
-\r
-**/\r
-BOOLEAN\r
-UsbHcIsMemBlockEmpty (\r
- IN USBHC_MEM_BLOCK *Block\r
- )\r
-{\r
- UINTN Index;\r
-\r
- for (Index = 0; Index < Block->BitsLen; Index++) {\r
- if (Block->Bits[Index] != 0) {\r
- return FALSE;\r
- }\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-\r
-/**\r
- Unlink the memory block from the pool's list.\r
-\r
- @param Head The block list head of the memory's pool.\r
- @param BlockToUnlink The memory block to unlink.\r
-\r
-**/\r
-VOID\r
-UsbHcUnlinkMemBlock (\r
- IN USBHC_MEM_BLOCK *Head,\r
- IN USBHC_MEM_BLOCK *BlockToUnlink\r
- )\r
-{\r
- USBHC_MEM_BLOCK *Block;\r
-\r
- ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
-\r
- for (Block = Head; Block != NULL; Block = Block->Next) {\r
- if (Block->Next == BlockToUnlink) {\r
- Block->Next = BlockToUnlink->Next;\r
- BlockToUnlink->Next = NULL;\r
- break;\r
- }\r
- }\r
-}\r
-\r
-\r
-/**\r
- Initialize the memory management pool for the host controller.\r
-\r
- @param PciIo The PciIo that can be used to access the host controller.\r
- @param Check4G Whether the host controller requires allocated memory\r
- from one 4G address space.\r
- @param Which4G The 4G memory area each memory allocated should be from.\r
-\r
- @retval EFI_SUCCESS The memory pool is initialized.\r
- @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
-\r
-**/\r
-USBHC_MEM_POOL *\r
-UsbHcInitMemPool (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN BOOLEAN Check4G,\r
- IN UINT32 Which4G\r
- )\r
-{\r
- USBHC_MEM_POOL *Pool;\r
-\r
- Pool = AllocatePool (sizeof (USBHC_MEM_POOL));\r
-\r
- if (Pool == NULL) {\r
- return Pool;\r
- }\r
-\r
- Pool->PciIo = PciIo;\r
- Pool->Check4G = Check4G;\r
- Pool->Which4G = Which4G;\r
- Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
-\r
- if (Pool->Head == NULL) {\r
- gBS->FreePool (Pool);\r
- Pool = NULL;\r
- }\r
-\r
- return Pool;\r
-}\r
-\r
-\r
-/**\r
- Release the memory management pool.\r
-\r
- @param Pool The USB memory pool to free.\r
-\r
- @retval EFI_SUCCESS The memory pool is freed.\r
- @retval EFI_DEVICE_ERROR Failed to free the memory pool.\r
-\r
-**/\r
-EFI_STATUS\r
-UsbHcFreeMemPool (\r
- IN USBHC_MEM_POOL *Pool\r
- )\r
-{\r
- USBHC_MEM_BLOCK *Block;\r
-\r
- ASSERT (Pool->Head != NULL);\r
-\r
- //\r
- // Unlink all the memory blocks from the pool, then free them.\r
- // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
- // first block.\r
- //\r
- for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
- UsbHcUnlinkMemBlock (Pool->Head, Block);\r
- UsbHcFreeMemBlock (Pool, Block);\r
- }\r
-\r
- UsbHcFreeMemBlock (Pool, Pool->Head);\r
- gBS->FreePool (Pool);\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Allocate some memory from the host controller's memory pool\r
- which can be used to communicate with host controller.\r
-\r
- @param Pool The host controller's memory pool.\r
- @param Size Size of the memory to allocate.\r
-\r
- @return The allocated memory or NULL.\r
-\r
-**/\r
-VOID *\r
-UsbHcAllocateMem (\r
- IN USBHC_MEM_POOL *Pool,\r
- IN UINTN Size\r
- )\r
-{\r
- USBHC_MEM_BLOCK *Head;\r
- USBHC_MEM_BLOCK *Block;\r
- USBHC_MEM_BLOCK *NewBlock;\r
- VOID *Mem;\r
- UINTN AllocSize;\r
- UINTN Pages;\r
-\r
- Mem = NULL;\r
- AllocSize = USBHC_MEM_ROUND (Size);\r
- Head = Pool->Head;\r
- ASSERT (Head != NULL);\r
-\r
- //\r
- // First check whether current memory blocks can satisfy the allocation.\r
- //\r
- for (Block = Head; Block != NULL; Block = Block->Next) {\r
- Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
-\r
- if (Mem != NULL) {\r
- ZeroMem (Mem, Size);\r
- break;\r
- }\r
- }\r
-\r
- if (Mem != NULL) {\r
- return Mem;\r
- }\r
-\r
- //\r
- // Create a new memory block if there is not enough memory\r
- // in the pool. If the allocation size is larger than the\r
- // default page number, just allocate a large enough memory\r
- // block. Otherwise allocate default pages.\r
- //\r
- if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
- Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
- } else {\r
- Pages = USBHC_MEM_DEFAULT_PAGES;\r
- }\r
-\r
- NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
-\r
- if (NewBlock == NULL) {\r
- DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));\r
- return NULL;\r
- }\r
-\r
- //\r
- // Add the new memory block to the pool, then allocate memory from it\r
- //\r
- UsbHcInsertMemBlockToPool (Head, NewBlock);\r
- Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
-\r
- if (Mem != NULL) {\r
- ZeroMem (Mem, Size);\r
- }\r
-\r
- return Mem;\r
-}\r
-\r
-\r
-/**\r
- Free the allocated memory back to the memory pool.\r
-\r
- @param Pool The memory pool of the host controller.\r
- @param Mem The memory to free.\r
- @param Size The size of the memory to free.\r
-\r
-**/\r
-VOID\r
-UsbHcFreeMem (\r
- IN USBHC_MEM_POOL *Pool,\r
- IN VOID *Mem,\r
- IN UINTN Size\r
- )\r
-{\r
- USBHC_MEM_BLOCK *Head;\r
- USBHC_MEM_BLOCK *Block;\r
- UINT8 *ToFree;\r
- UINTN AllocSize;\r
- UINTN Byte;\r
- UINTN Bit;\r
- UINTN Count;\r
-\r
- Head = Pool->Head;\r
- AllocSize = USBHC_MEM_ROUND (Size);\r
- ToFree = (UINT8 *) Mem;\r
-\r
- for (Block = Head; Block != NULL; Block = Block->Next) {\r
- //\r
- // scan the memory block list for the memory block that\r
- // completely contains the memory to free.\r
- //\r
- if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
- //\r
- // compute the start byte and bit in the bit array\r
- //\r
- Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;\r
- Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;\r
-\r
- //\r
- // reset associated bits in bit arry\r
- //\r
- for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
- ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
-\r
- Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
- NEXT_BIT (Byte, Bit);\r
- }\r
-\r
- break;\r
- }\r
- }\r
-\r
- //\r
- // If Block == NULL, it means that the current memory isn't\r
- // in the host controller's pool. This is critical because\r
- // the caller has passed in a wrong memory point\r
- //\r
- ASSERT (Block != NULL);\r
-\r
- //\r
- // Release the current memory block if it is empty and not the head\r
- //\r
- if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
- UsbHcUnlinkMemBlock (Head, Block);\r
- UsbHcFreeMemBlock (Pool, Block);\r
- }\r
-\r
- return ;\r
-}\r