--- /dev/null
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+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
+**/\r
+\r
+#include "XhcPeim.h"\r
+\r
+/**\r
+ Allocate a block of memory to be used by the buffer pool.\r
+\r
+ @param Pages How many pages to allocate.\r
+\r
+ @return Pointer to the allocated memory block or NULL if failed.\r
+\r
+**/\r
+USBHC_MEM_BLOCK *\r
+UsbHcAllocMemBlock (\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+ EFI_STATUS Status;\r
+ UINTN PageNumber;\r
+ EFI_PHYSICAL_ADDRESS TempPtr;\r
+\r
+ PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_BLOCK));\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ PageNumber,\r
+ &TempPtr\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));\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 = (USBHC_MEM_BLOCK *) (UINTN) TempPtr;\r
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
+ Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
+\r
+ PageNumber = EFI_SIZE_TO_PAGES (Block->BitsLen);\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ PageNumber,\r
+ &TempPtr\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));\r
+\r
+ Block->Bits = (UINT8 *) (UINTN) TempPtr;\r
+\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ Pages,\r
+ &TempPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (Pages));\r
+\r
+ Block->BufHost = (UINT8 *) (UINTN) TempPtr;;\r
+ Block->Buf = (UINT8 *) (UINTN) TempPtr;\r
+ Block->Next = NULL;\r
+\r
+ return Block;\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
+ ASSERT ((Pool != NULL) && (Block != NULL));\r
+ //\r
+ // No free memory in PEI.\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.\r
+ If couldn't allocate the needed memory, 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
+ } 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] | (UINT8) 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
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+UsbHcGetPciAddrForHostAddr (\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
+ Calculate the corresponding host address according to the pci address.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The pointer to pci memory.\r
+ @param Size The size of the memory region.\r
+\r
+ @return The host memory address\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+UsbHcGetHostAddrForPciAddr (\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 HostAddr;\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->Buf <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ ASSERT ((Block != NULL));\r
+ //\r
+ // calculate the host memory address for pci memory address.\r
+ //\r
+ Offset = (UINT8 *) Mem - Block->Buf;\r
+ HostAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) (Block->BufHost + Offset);\r
+ return HostAddr;\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
+ 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
+ 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
+ Initialize the memory management pool for the host controller.\r
+\r
+ @return Pointer to the allocated memory pool or NULL if failed.\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+ VOID\r
+ )\r
+{\r
+ USBHC_MEM_POOL *Pool;\r
+ UINTN PageNumber;\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS TempPtr;\r
+\r
+ PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_POOL));\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ PageNumber,\r
+ &TempPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));\r
+\r
+ Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr);\r
+ Pool->Head = UsbHcAllocMemBlock (USBHC_MEM_DEFAULT_PAGES);\r
+\r
+ if (Pool->Head == NULL) {\r
+ //\r
+ // No free memory in PEI.\r
+ //\r
+ Pool = NULL;\r
+ }\r
+\r
+ return Pool;\r
+}\r
+\r
+/**\r
+ Release the memory management pool.\r
+\r
+ @param Pool The USB memory pool to free.\r
+\r
+**/\r
+VOID\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
+}\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);\r
+ } else {\r
+ Pages = USBHC_MEM_DEFAULT_PAGES;\r
+ }\r
+ NewBlock = UsbHcAllocMemBlock (Pages);\r
+\r
+ if (NewBlock == NULL) {\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
+ 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 pointer\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
+\r
+/**\r
+ Allocates pages at a specified alignment.\r
+\r
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+\r
+ @param Pages The number of pages to allocate.\r
+ @param Alignment The requested alignment of the allocation. Must be a power of two.\r
+ @param HostAddress The system memory address to map to the PCI controller.\r
+ @param DeviceAddress The resulting map address for the bus master PCI controller to\r
+ use to access the hosts HostAddress.\r
+\r
+ @retval EFI_SUCCESS Success to allocate aligned pages.\r
+ @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.\r
+ @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcAllocateAlignedPages (\r
+ IN UINTN Pages,\r
+ IN UINTN Alignment,\r
+ OUT VOID **HostAddress,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS Memory;\r
+ UINTN AlignedMemory;\r
+ UINTN AlignmentMask;\r
+ UINTN RealPages;\r
+\r
+ //\r
+ // Alignment must be a power of two or zero.\r
+ //\r
+ ASSERT ((Alignment & (Alignment - 1)) == 0);\r
+\r
+ if ((Alignment & (Alignment - 1)) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Pages == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Alignment > EFI_PAGE_SIZE) {\r
+ //\r
+ // Caculate the total number of pages since alignment is larger than page size.\r
+ //\r
+ AlignmentMask = Alignment - 1;\r
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
+ //\r
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
+ //\r
+ ASSERT (RealPages > Pages);\r
+\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ Pages,\r
+ &Memory\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
+ } else {\r
+ //\r
+ // Do not over-allocate pages in this case.\r
+ //\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ Pages,\r
+ &Memory\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ AlignedMemory = (UINTN) Memory;\r
+ }\r
+\r
+ *HostAddress = (VOID *) AlignedMemory;\r
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS) AlignedMemory;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Frees memory that was allocated with UsbHcAllocateAlignedPages().\r
+\r
+ @param HostAddress The system memory address to map to the PCI controller.\r
+ @param Pages The number of pages to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeAlignedPages (\r
+ IN VOID *HostAddress,\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ ASSERT (Pages != 0);\r
+ //\r
+ // No free memory in PEI.\r
+ //\r
+}\r
+\r
--- /dev/null
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+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
+**/\r
+\r
+#ifndef _EFI_PEI_XHCI_MEM_H_\r
+#define _EFI_PEI_XHCI_MEM_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#define USBHC_MEM_DEFAULT_PAGES 16\r
+\r
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;\r
+\r
+struct _USBHC_MEM_BLOCK {\r
+ UINT8 *Bits; // Bit array to record which unit is allocated\r
+ UINTN BitsLen;\r
+ UINT8 *Buf;\r
+ UINT8 *BufHost;\r
+ UINTN BufLen; // Memory size in bytes\r
+ USBHC_MEM_BLOCK *Next;\r
+};\r
+\r
+//\r
+// Memory allocation unit, must be 2^n, n>4\r
+//\r
+#define USBHC_MEM_UNIT 64\r
+\r
+#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1)\r
+#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))\r
+\r
+#define USB_HC_BIT(a) ((UINTN)(1 << (a)))\r
+\r
+#define USB_HC_BIT_IS_SET(Data, Bit) \\r
+ ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define NEXT_BIT(Byte, Bit) \\r
+ do { \\r
+ (Bit)++; \\r
+ if ((Bit) > 7) { \\r
+ (Byte)++; \\r
+ (Bit) = 0; \\r
+ } \\r
+ } while (0)\r
+\r
+//\r
+// USBHC_MEM_POOL is used to manage the memory used by USB\r
+// host controller. XHCI requires the control memory and transfer\r
+// data to be on the same 4G memory.\r
+//\r
+typedef struct _USBHC_MEM_POOL {\r
+ BOOLEAN Check4G;\r
+ UINT32 Which4G;\r
+ USBHC_MEM_BLOCK *Head;\r
+} USBHC_MEM_POOL;\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
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+UsbHcGetPciAddrForHostAddr (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ );\r
+\r
+/**\r
+ Calculate the corresponding host address according to the pci address.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The pointer to pci memory.\r
+ @param Size The size of the memory region.\r
+\r
+ @return The host memory address\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+UsbHcGetHostAddrForPciAddr (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ );\r
+\r
+/**\r
+ Allocates pages at a specified alignment.\r
+\r
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+\r
+ @param Pages The number of pages to allocate.\r
+ @param Alignment The requested alignment of the allocation. Must be a power of two.\r
+ @param HostAddress The system memory address to map to the PCI controller.\r
+ @param DeviceAddress The resulting map address for the bus master PCI controller to\r
+ use to access the hosts HostAddress.\r
+\r
+ @retval EFI_SUCCESS Success to allocate aligned pages.\r
+ @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.\r
+ @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcAllocateAlignedPages (\r
+ IN UINTN Pages,\r
+ IN UINTN Alignment,\r
+ OUT VOID **HostAddress,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress\r
+ );\r
+\r
+/**\r
+ Frees memory that was allocated with UsbHcAllocateAlignedPages().\r
+\r
+ @param HostAddress The system memory address to map to the PCI controller.\r
+ @param Pages The number of pages to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeAlignedPages (\r
+ IN VOID *HostAddress,\r
+ IN UINTN Pages\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+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
+**/\r
+\r
+#include "XhcPeim.h"\r
+\r
+//\r
+// Two arrays used to translate the XHCI port state (change)\r
+// to the UEFI protocol's port state (change).\r
+//\r
+USB_PORT_STATE_MAP mUsbPortStateMap[] = {\r
+ {XHC_PORTSC_CCS, USB_PORT_STAT_CONNECTION},\r
+ {XHC_PORTSC_PED, USB_PORT_STAT_ENABLE},\r
+ {XHC_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},\r
+ {XHC_PORTSC_PP, USB_PORT_STAT_POWER},\r
+ {XHC_PORTSC_RESET, USB_PORT_STAT_RESET}\r
+};\r
+\r
+USB_PORT_STATE_MAP mUsbPortChangeMap[] = {\r
+ {XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},\r
+ {XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},\r
+ {XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},\r
+ {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}\r
+};\r
+\r
+USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {\r
+ {XHC_PORTSC_CSC, EfiUsbPortConnectChange},\r
+ {XHC_PORTSC_PEC, EfiUsbPortEnableChange},\r
+ {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},\r
+ {XHC_PORTSC_PRC, EfiUsbPortResetChange}\r
+};\r
+\r
+USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {\r
+ {XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION},\r
+ {XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE},\r
+ {XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},\r
+ {XHC_HUB_PORTSC_PP, USB_PORT_STAT_POWER},\r
+ {XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET}\r
+};\r
+\r
+USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {\r
+ {XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},\r
+ {XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},\r
+ {XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},\r
+ {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}\r
+};\r
+\r
+USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {\r
+ {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},\r
+ {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},\r
+ {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},\r
+ {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},\r
+ {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}\r
+};\r
+\r
+/**\r
+ Read XHCI Operation register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The operation register offset.\r
+\r
+ @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadOpReg (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ ASSERT (Xhc->CapLength != 0);\r
+\r
+ Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset);\r
+ return Data;\r
+}\r
+\r
+/**\r
+ Write the data to the XHCI operation register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The operation register offset.\r
+ @param Data The data to write.\r
+\r
+**/\r
+VOID\r
+XhcPeiWriteOpReg (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Data\r
+ )\r
+{\r
+ ASSERT (Xhc->CapLength != 0);\r
+\r
+ MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset, Data);\r
+}\r
+\r
+/**\r
+ Set one bit of the operational register while keeping other bits.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the operational register.\r
+ @param Bit The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcPeiSetOpRegBit (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = XhcPeiReadOpReg (Xhc, Offset);\r
+ Data |= Bit;\r
+ XhcPeiWriteOpReg (Xhc, Offset, Data);\r
+}\r
+\r
+/**\r
+ Clear one bit of the operational register while keeping other bits.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the operational register.\r
+ @param Bit The bit mask of the register to clear.\r
+\r
+**/\r
+VOID\r
+XhcPeiClearOpRegBit (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = XhcPeiReadOpReg (Xhc, Offset);\r
+ Data &= ~Bit;\r
+ XhcPeiWriteOpReg (Xhc, Offset, Data);\r
+}\r
+\r
+/**\r
+ Wait the operation register's bit as specified by Bit\r
+ to become set (or clear).\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the operational register.\r
+ @param Bit The bit mask of the register to wait for.\r
+ @param WaitToSet Wait the bit to set or clear.\r
+ @param Timeout The time to wait before abort (in microsecond, us).\r
+\r
+ @retval EFI_SUCCESS The bit successfully changed by host controller.\r
+ @retval EFI_TIMEOUT The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiWaitOpRegBit (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit,\r
+ IN BOOLEAN WaitToSet,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < Timeout / XHC_POLL_DELAY + 1; Index++) {\r
+ if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ MicroSecondDelay (XHC_POLL_DELAY);\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ Read XHCI capability register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset Capability register address.\r
+\r
+ @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadCapRegister (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Offset);\r
+\r
+ return Data;\r
+}\r
+\r
+/**\r
+ Read XHCI door bell register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the door bell register.\r
+\r
+ @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadDoorBellReg (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ ASSERT (Xhc->DBOff != 0);\r
+\r
+ Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset);\r
+\r
+ return Data;\r
+}\r
+\r
+/**\r
+ Write the data to the XHCI door bell register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the door bell register.\r
+ @param Data The data to write.\r
+\r
+**/\r
+VOID\r
+XhcPeiWriteDoorBellReg (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Data\r
+ )\r
+{\r
+ ASSERT (Xhc->DBOff != 0);\r
+\r
+ MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset, Data);\r
+}\r
+\r
+/**\r
+ Read XHCI runtime register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the runtime register.\r
+\r
+ @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadRuntimeReg (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ ASSERT (Xhc->RTSOff != 0);\r
+\r
+ Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset);\r
+\r
+ return Data;\r
+}\r
+\r
+/**\r
+ Write the data to the XHCI runtime register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the runtime register.\r
+ @param Data The data to write.\r
+\r
+**/\r
+VOID\r
+XhcPeiWriteRuntimeReg (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Data\r
+ )\r
+{\r
+ ASSERT (Xhc->RTSOff != 0);\r
+\r
+ MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset, Data);\r
+}\r
+\r
+/**\r
+ Set one bit of the runtime register while keeping other bits.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the runtime register.\r
+ @param Bit The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcPeiSetRuntimeRegBit (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = XhcPeiReadRuntimeReg (Xhc, Offset);\r
+ Data |= Bit;\r
+ XhcPeiWriteRuntimeReg (Xhc, Offset, Data);\r
+}\r
+\r
+/**\r
+ Clear one bit of the runtime register while keeping other bits.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the runtime register.\r
+ @param Bit The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcPeiClearRuntimeRegBit (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = XhcPeiReadRuntimeReg (Xhc, Offset);\r
+ Data &= ~Bit;\r
+ XhcPeiWriteRuntimeReg (Xhc, Offset, Data);\r
+}\r
+\r
+/**\r
+ Check whether Xhc is halted.\r
+\r
+ @param Xhc The XHCI device.\r
+\r
+ @retval TRUE The controller is halted.\r
+ @retval FALSE The controller isn't halted.\r
+\r
+**/\r
+BOOLEAN\r
+XhcPeiIsHalt (\r
+ IN PEI_XHC_DEV *Xhc\r
+ )\r
+{\r
+ return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);\r
+}\r
+\r
+/**\r
+ Check whether system error occurred.\r
+\r
+ @param Xhc The XHCI device.\r
+\r
+ @retval TRUE System error happened.\r
+ @retval FALSE No system error.\r
+\r
+**/\r
+BOOLEAN\r
+XhcPeiIsSysError (\r
+ IN PEI_XHC_DEV *Xhc\r
+ )\r
+{\r
+ return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);\r
+}\r
+\r
+/**\r
+ Reset the host controller.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Timeout Time to wait before abort (in microsecond, us).\r
+\r
+ @retval EFI_TIMEOUT The transfer failed due to time out.\r
+ @retval Others Failed to reset the host.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiResetHC (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Host can only be reset when it is halt. If not so, halt it\r
+ //\r
+ if (!XhcPeiIsHalt (Xhc)) {\r
+ Status = XhcPeiHaltHC (Xhc, Timeout);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+\r
+ XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);\r
+ Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);\r
+ON_EXIT:\r
+ DEBUG ((EFI_D_INFO, "XhcPeiResetHC: %r\n", Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Halt the host controller.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Timeout Time to wait before abort.\r
+\r
+ @retval EFI_TIMEOUT Failed to halt the controller before Timeout.\r
+ @retval EFI_SUCCESS The XHCI is halt.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiHaltHC (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);\r
+ Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);\r
+ DEBUG ((EFI_D_INFO, "XhcPeiHaltHC: %r\n", Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set the XHCI to run.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Timeout Time to wait before abort.\r
+\r
+ @retval EFI_SUCCESS The XHCI is running.\r
+ @retval Others Failed to set the XHCI to run.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiRunHC (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);\r
+ Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);\r
+ DEBUG ((EFI_D_INFO, "XhcPeiRunHC: %r\n", Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress The target device address.\r
+ @param DeviceSpeed Target device speed.\r
+ @param MaximumPacketLength Maximum packet size the default control transfer\r
+ endpoint is capable of sending or receiving.\r
+ @param Request USB device request to send.\r
+ @param TransferDirection Specifies the data direction for the data stage.\r
+ @param Data Data buffer to be transmitted or received from USB device.\r
+ @param DataLength The size (in bytes) of the data buffer.\r
+ @param TimeOut Indicates the maximum timeout, in millisecond.\r
+ If Timeout is 0, then the caller must wait for the function\r
+ to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.\r
+ @param Translator Transaction translator to be used by this device.\r
+ @param TransferResult Return the result of this control transfer.\r
+\r
+ @retval EFI_SUCCESS Transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT Transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiControlTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION TransferDirection,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN UINTN TimeOut,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ PEI_XHC_DEV *Xhc;\r
+ URB *Urb;\r
+ UINT8 Endpoint;\r
+ UINT8 Index;\r
+ UINT8 DescriptorType;\r
+ UINT8 SlotId;\r
+ UINT8 TTT;\r
+ UINT8 MTT;\r
+ UINT32 MaxPacket0;\r
+ EFI_USB_HUB_DESCRIPTOR *HubDesc;\r
+ EFI_STATUS Status;\r
+ EFI_STATUS RecoveryStatus;\r
+ UINTN MapSize;\r
+ EFI_USB_PORT_STATUS PortStatus;\r
+ UINT32 State;\r
+ EFI_USB_DEVICE_REQUEST ClearPortRequest;\r
+ UINTN Len;\r
+\r
+ //\r
+ // Validate parameters\r
+ //\r
+ if ((Request == NULL) || (TransferResult == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((TransferDirection != EfiUsbDataIn) &&\r
+ (TransferDirection != EfiUsbDataOut) &&\r
+ (TransferDirection != EfiUsbNoData)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((TransferDirection == EfiUsbNoData) &&\r
+ ((Data != NULL) || (*DataLength != 0))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((TransferDirection != EfiUsbNoData) &&\r
+ ((Data == NULL) || (*DataLength == 0))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&\r
+ (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&\r
+ (MaximumPacketLength != 512)\r
+ ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Len = 0;\r
+\r
+ if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: HC is halted or has system error\n"));\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Check if the device is still enabled before every transaction.\r
+ //\r
+ SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);\r
+ if (SlotId == 0) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Hook the Set_Address request from UsbBus.\r
+ // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.\r
+ //\r
+ if ((Request->Request == USB_REQ_SET_ADDRESS) &&\r
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {\r
+ //\r
+ // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.\r
+ // This way is used to clean the history to avoid using wrong device address afterwards.\r
+ //\r
+ for (Index = 0; Index < 255; Index++) {\r
+ if (!Xhc->UsbDevContext[Index + 1].Enabled &&\r
+ (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&\r
+ (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8) Request->Value)) {\r
+ Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;\r
+ }\r
+ }\r
+\r
+ if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // The actual device address has been assigned by XHCI during initializing the device slot.\r
+ // So we just need establish the mapping relationship between the device address requested from UsbBus\r
+ // and the actual device address assigned by XHCI. The following invocations through EFI_USB2_HC_PROTOCOL interface\r
+ // can find out the actual device address by it.\r
+ //\r
+ Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8) Request->Value;\r
+ Status = EFI_SUCCESS;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Create a new URB, insert it into the asynchronous\r
+ // schedule list, then poll the execution status.\r
+ // Note that we encode the direction in address although default control\r
+ // endpoint is bidirectional. XhcPeiCreateUrb expects this\r
+ // combination of Ep addr and its direction.\r
+ //\r
+ Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));\r
+ Urb = XhcPeiCreateUrb (\r
+ Xhc,\r
+ DeviceAddress,\r
+ Endpoint,\r
+ DeviceSpeed,\r
+ MaximumPacketLength,\r
+ XHC_CTRL_TRANSFER,\r
+ Request,\r
+ Data,\r
+ *DataLength,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ if (Urb == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: failed to create URB"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);\r
+\r
+ //\r
+ // Get the status from URB. The result is updated in XhcPeiCheckUrbResult\r
+ // which is called by XhcPeiExecTransfer\r
+ //\r
+ *TransferResult = Urb->Result;\r
+ *DataLength = Urb->Completed;\r
+\r
+ if (*TransferResult == EFI_USB_NOERROR) {\r
+ Status = EFI_SUCCESS;\r
+ } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
+ RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);\r
+ if (EFI_ERROR (RecoveryStatus)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
+ }\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto FREE_URB;\r
+ } else {\r
+ goto FREE_URB;\r
+ }\r
+\r
+ //\r
+ // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.\r
+ // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.\r
+ // Hook Set_Config request from UsbBus as we need configure device endpoint.\r
+ //\r
+ if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&\r
+ ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||\r
+ ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {\r
+ DescriptorType = (UINT8) (Request->Value >> 8);\r
+ if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {\r
+ ASSERT (Data != NULL);\r
+ //\r
+ // Store a copy of device scriptor as hub device need this info to configure endpoint.\r
+ //\r
+ CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);\r
+ if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB == 0x0300) {\r
+ //\r
+ // If it's a usb3.0 device, then its max packet size is a 2^n.\r
+ //\r
+ MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
+ } else {\r
+ MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
+ }\r
+ Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));\r
+ if (Xhc->UsbDevContext[SlotId].ConfDesc == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FREE_URB;\r
+ }\r
+ if (Xhc->HcCParams.Data.Csz == 0) {\r
+ Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);\r
+ } else {\r
+ Status = XhcPeiEvaluateContext64 (Xhc, SlotId, MaxPacket0);\r
+ }\r
+ } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {\r
+ ASSERT (Data != NULL);\r
+ if (*DataLength == ((UINT16 *) Data)[1]) {\r
+ //\r
+ // Get configuration value from request, store the configuration descriptor for Configure_Endpoint cmd.\r
+ //\r
+ Index = (UINT8) Request->Value;\r
+ ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);\r
+ Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);\r
+ if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FREE_URB;\r
+ }\r
+ CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);\r
+ }\r
+ } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||\r
+ (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {\r
+ ASSERT (Data != NULL);\r
+ HubDesc = (EFI_USB_HUB_DESCRIPTOR *) Data;\r
+ ASSERT (HubDesc->NumPorts <= 15);\r
+ //\r
+ // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.\r
+ //\r
+ TTT = (UINT8) ((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);\r
+ if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {\r
+ //\r
+ // Don't support multi-TT feature for super speed hub now.\r
+ //\r
+ MTT = 0;\r
+ DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));\r
+ } else {\r
+ MTT = 0;\r
+ }\r
+\r
+ if (Xhc->HcCParams.Data.Csz == 0) {\r
+ Status = XhcPeiConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
+ } else {\r
+ Status = XhcPeiConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
+ }\r
+ }\r
+ } else if ((Request->Request == USB_REQ_SET_CONFIG) &&\r
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {\r
+ //\r
+ // Hook Set_Config request from UsbBus as we need configure device endpoint.\r
+ //\r
+ for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
+ if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {\r
+ if (Xhc->HcCParams.Data.Csz == 0) {\r
+ Status = XhcPeiSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
+ } else {\r
+ Status = XhcPeiSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ } else if ((Request->Request == USB_REQ_GET_STATUS) &&\r
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {\r
+ ASSERT (Data != NULL);\r
+ //\r
+ // Hook Get_Status request from UsbBus to keep track of the port status change.\r
+ //\r
+ State = *(UINT32 *) Data;\r
+ PortStatus.PortStatus = 0;\r
+ PortStatus.PortChangeStatus = 0;\r
+\r
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+ //\r
+ // For super speed hub, its bit10~12 presents the attached device speed.\r
+ //\r
+ if ((State & XHC_PORTSC_PS) >> 10 == 0) {\r
+ PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
+ }\r
+ } else {\r
+ //\r
+ // For high or full/low speed hub, its bit9~10 presents the attached device speed.\r
+ //\r
+ if (XHC_BIT_IS_SET (State, BIT9)) {\r
+ PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+ } else if (XHC_BIT_IS_SET (State, BIT10)) {\r
+ PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Convert the XHCI port/port change state to UEFI status\r
+ //\r
+ MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
+ for (Index = 0; Index < MapSize; Index++) {\r
+ if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {\r
+ PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);\r
+ }\r
+ }\r
+\r
+ MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
+ for (Index = 0; Index < MapSize; Index++) {\r
+ if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {\r
+ PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);\r
+ }\r
+ }\r
+\r
+ MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
+\r
+ for (Index = 0; Index < MapSize; Index++) {\r
+ if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {\r
+ ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+ ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);\r
+ ClearPortRequest.Request = (UINT8) USB_REQ_CLEAR_FEATURE;\r
+ ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;\r
+ ClearPortRequest.Index = Request->Index;\r
+ ClearPortRequest.Length = 0;\r
+\r
+ XhcPeiControlTransfer (\r
+ PeiServices,\r
+ This,\r
+ DeviceAddress,\r
+ DeviceSpeed,\r
+ MaximumPacketLength,\r
+ &ClearPortRequest,\r
+ EfiUsbNoData,\r
+ NULL,\r
+ &Len,\r
+ TimeOut,\r
+ Translator,\r
+ TransferResult\r
+ );\r
+ }\r
+ }\r
+\r
+ XhcPeiPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);\r
+\r
+ *(UINT32 *) Data = *(UINT32 *) &PortStatus;\r
+ }\r
+\r
+FREE_URB:\r
+ XhcPeiFreeUrb (Xhc, Urb);\r
+\r
+ON_EXIT:\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress Target device address.\r
+ @param EndPointAddress Endpoint number and its direction in bit 7.\r
+ @param DeviceSpeed Device speed, Low speed device doesn't support\r
+ bulk transfer.\r
+ @param MaximumPacketLength Maximum packet size the endpoint is capable of\r
+ sending or receiving.\r
+ @param Data Array of pointers to the buffers of data to transmit\r
+ from or receive into.\r
+ @param DataLength The lenght of the data buffer.\r
+ @param DataToggle On input, the initial data toggle for the transfer;\r
+ On output, it is updated to to next data toggle to use of\r
+ the subsequent bulk transfer.\r
+ @param TimeOut Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+ If Timeout is 0, then the caller must wait for the function\r
+ to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.\r
+ @param Translator A pointr to the transaction translator data.\r
+ @param TransferResult A pointer to the detailed result information of the\r
+ bulk transfer.\r
+\r
+ @retval EFI_SUCCESS The transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+ @retval EFI_TIMEOUT The transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiBulkTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ PEI_XHC_DEV *Xhc;\r
+ URB *Urb;\r
+ UINT8 SlotId;\r
+ EFI_STATUS Status;\r
+ EFI_STATUS RecoveryStatus;\r
+\r
+ //\r
+ // Validate the parameters\r
+ //\r
+ if ((DataLength == NULL) || (*DataLength == 0) ||\r
+ (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((*DataToggle != 0) && (*DataToggle != 1)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
+ ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
+ ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 512)) ||\r
+ ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength > 1024))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
+\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_DEVICE_ERROR;\r
+\r
+ if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: HC is halted or has system error\n"));\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Check if the device is still enabled before every transaction.\r
+ //\r
+ SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);\r
+ if (SlotId == 0) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Create a new URB, insert it into the asynchronous\r
+ // schedule list, then poll the execution status.\r
+ //\r
+ Urb = XhcPeiCreateUrb (\r
+ Xhc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ DeviceSpeed,\r
+ MaximumPacketLength,\r
+ XHC_BULK_TRANSFER,\r
+ NULL,\r
+ Data[0],\r
+ *DataLength,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ if (Urb == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: failed to create URB\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);\r
+\r
+ *TransferResult = Urb->Result;\r
+ *DataLength = Urb->Completed;\r
+\r
+ if (*TransferResult == EFI_USB_NOERROR) {\r
+ Status = EFI_SUCCESS;\r
+ } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
+ RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);\r
+ if (EFI_ERROR (RecoveryStatus)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
+ }\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ XhcPeiFreeUrb (Xhc, Urb);\r
+\r
+ON_EXIT:\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Retrieves the number of root hub ports.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the\r
+ PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param[out] PortNumber The pointer to the number of the root hub ports.\r
+\r
+ @retval EFI_SUCCESS The port number was retrieved successfully.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiGetRootHubPortNumber (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ OUT UINT8 *PortNumber\r
+ )\r
+{\r
+ PEI_XHC_DEV *XhcDev;\r
+ XhcDev = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
+\r
+ if (PortNumber == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *PortNumber = XhcDev->HcSParams1.Data.MaxPorts;\r
+ DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortNumber: PortNumber = %x\n", *PortNumber));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Clears a feature for the specified root hub port.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param PortNumber Specifies the root hub port whose feature\r
+ is requested to be cleared.\r
+ @param PortFeature Indicates the feature selector associated with the\r
+ feature clear request.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared\r
+ for the USB root hub port specified by PortNumber.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiClearRootHubPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ PEI_XHC_DEV *Xhc;\r
+ UINT32 Offset;\r
+ UINT32 State;\r
+ EFI_STATUS Status;\r
+\r
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
+ State = XhcPeiReadOpReg (Xhc, Offset);\r
+ DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));\r
+\r
+ //\r
+ // Mask off the port status change bits, these bits are\r
+ // write clean bits\r
+ //\r
+ State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);\r
+\r
+ switch (PortFeature) {\r
+ case EfiUsbPortEnable:\r
+ //\r
+ // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.\r
+ // A port may be disabled by software writing a '1' to this flag.\r
+ //\r
+ State |= XHC_PORTSC_PED;\r
+ State &= ~XHC_PORTSC_RESET;\r
+ XhcPeiWriteOpReg (Xhc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortSuspend:\r
+ State |= XHC_PORTSC_LWS;\r
+ XhcPeiWriteOpReg (Xhc, Offset, State);\r
+ State &= ~XHC_PORTSC_PLS;\r
+ XhcPeiWriteOpReg (Xhc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ //\r
+ // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:\r
+ // Register bits indicate status when read, a clear bit may be set by\r
+ // writing a '1'. Writing a '0' to RW1S bits has no effect.\r
+ //\r
+ break;\r
+\r
+ case EfiUsbPortPower:\r
+ if (Xhc->HcCParams.Data.Ppc) {\r
+ //\r
+ // Port Power Control supported\r
+ //\r
+ State &= ~XHC_PORTSC_PP;\r
+ XhcPeiWriteOpReg (Xhc, Offset, State);\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortOwner:\r
+ //\r
+ // XHCI root hub port don't has the owner bit, ignore the operation\r
+ //\r
+ break;\r
+\r
+ case EfiUsbPortConnectChange:\r
+ //\r
+ // Clear connect status change\r
+ //\r
+ State |= XHC_PORTSC_CSC;\r
+ XhcPeiWriteOpReg (Xhc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortEnableChange:\r
+ //\r
+ // Clear enable status change\r
+ //\r
+ State |= XHC_PORTSC_PEC;\r
+ XhcPeiWriteOpReg (Xhc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortOverCurrentChange:\r
+ //\r
+ // Clear PortOverCurrent change\r
+ //\r
+ State |= XHC_PORTSC_OCC;\r
+ XhcPeiWriteOpReg (Xhc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortResetChange:\r
+ //\r
+ // Clear Port Reset change\r
+ //\r
+ State |= XHC_PORTSC_PRC;\r
+ XhcPeiWriteOpReg (Xhc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortSuspendChange:\r
+ //\r
+ // Not supported or not related operation\r
+ //\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ON_EXIT:\r
+ DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Sets a feature for the specified root hub port.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES\r
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI\r
+ @param PortNumber Root hub port to set.\r
+ @param PortFeature Feature to set.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+ @retval EFI_TIMEOUT The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiSetRootHubPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ PEI_XHC_DEV *Xhc;\r
+ UINT32 Offset;\r
+ UINT32 State;\r
+ EFI_STATUS Status;\r
+\r
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
+ State = XhcPeiReadOpReg (Xhc, Offset);\r
+ DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));\r
+\r
+ //\r
+ // Mask off the port status change bits, these bits are\r
+ // write clean bits\r
+ //\r
+ State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);\r
+\r
+ switch (PortFeature) {\r
+ case EfiUsbPortEnable:\r
+ //\r
+ // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.\r
+ // A port may be disabled by software writing a '1' to this flag.\r
+ //\r
+ break;\r
+\r
+ case EfiUsbPortSuspend:\r
+ State |= XHC_PORTSC_LWS;\r
+ XhcPeiWriteOpReg (Xhc, Offset, State);\r
+ State &= ~XHC_PORTSC_PLS;\r
+ State |= (3 << 5) ;\r
+ XhcPeiWriteOpReg (Xhc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ //\r
+ // Make sure Host Controller not halt before reset it\r
+ //\r
+ if (XhcPeiIsHalt (Xhc)) {\r
+ Status = XhcPeiRunHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // 4.3.1 Resetting a Root Hub Port\r
+ // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.\r
+ // 2) Wait for a successful Port Status Change Event for the port, where the Port Reset Change (PRC)\r
+ // bit in the PORTSC field is set to '1'.\r
+ //\r
+ State |= XHC_PORTSC_RESET;\r
+ XhcPeiWriteOpReg (Xhc, Offset, State);\r
+ XhcPeiWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);\r
+ break;\r
+\r
+ case EfiUsbPortPower:\r
+ if (Xhc->HcCParams.Data.Ppc) {\r
+ //\r
+ // Port Power Control supported\r
+ //\r
+ State |= XHC_PORTSC_PP;\r
+ XhcPeiWriteOpReg (Xhc, Offset, State);\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortOwner:\r
+ //\r
+ // XHCI root hub port don't has the owner bit, ignore the operation\r
+ //\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ON_EXIT:\r
+ DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Retrieves the current status of a USB root hub port.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param PortNumber The root hub port to retrieve the state from.\r
+ @param PortStatus Variable to receive the port state.\r
+\r
+ @retval EFI_SUCCESS The status of the USB root hub port specified.\r
+ by PortNumber was returned in PortStatus.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiGetRootHubPortStatus (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ )\r
+{\r
+ PEI_XHC_DEV *Xhc;\r
+ UINT32 Offset;\r
+ UINT32 State;\r
+ UINTN Index;\r
+ UINTN MapSize;\r
+ USB_DEV_ROUTE ParentRouteChart;\r
+\r
+ if (PortStatus == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
+\r
+ if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Clear port status.\r
+ //\r
+ PortStatus->PortStatus = 0;\r
+ PortStatus->PortChangeStatus = 0;\r
+\r
+ Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
+ State = XhcPeiReadOpReg (Xhc, Offset);\r
+ DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: Port: %x State: %x\n", PortNumber, State));\r
+\r
+ //\r
+ // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device.\r
+ //\r
+ switch ((State & XHC_PORTSC_PS) >> 10) {\r
+ case 2:\r
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+ break;\r
+\r
+ case 3:\r
+ PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
+ break;\r
+\r
+ case 4:\r
+ PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Convert the XHCI port/port change state to UEFI status\r
+ //\r
+ MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
+\r
+ for (Index = 0; Index < MapSize; Index++) {\r
+ if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {\r
+ PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);\r
+ }\r
+ }\r
+ //\r
+ // Bit5~8 reflects its current link state.\r
+ //\r
+ if ((State & XHC_PORTSC_PLS) >> 5 == 3) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
+ }\r
+\r
+ MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
+\r
+ for (Index = 0; Index < MapSize; Index++) {\r
+ if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {\r
+ PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
+ }\r
+ }\r
+\r
+ MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
+\r
+ for (Index = 0; Index < MapSize; Index++) {\r
+ if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {\r
+ XhcPeiClearRootHubPortFeature (PeiServices, This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.\r
+ // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.\r
+ //\r
+ ParentRouteChart.Dword = 0;\r
+ XhcPeiPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);\r
+\r
+ DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: PortChangeStatus: %x PortStatus: %x\n", PortStatus->PortChangeStatus, PortStatus->PortStatus));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCCESS PPI successfully installed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeimEntry (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ PEI_USB_CONTROLLER_PPI *UsbControllerPpi;\r
+ EFI_STATUS Status;\r
+ UINT8 Index;\r
+ UINTN ControllerType;\r
+ UINTN BaseAddress;\r
+ UINTN MemPages;\r
+ PEI_XHC_DEV *XhcDev;\r
+ EFI_PHYSICAL_ADDRESS TempPtr;\r
+ UINT32 PageSize;\r
+\r
+ //\r
+ // Shadow this PEIM to run from memory.\r
+ //\r
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = PeiServicesLocatePpi (\r
+ &gPeiUsbControllerPpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **) &UsbControllerPpi\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Index = 0;\r
+ while (TRUE) {\r
+ Status = UsbControllerPpi->GetUsbController (\r
+ (EFI_PEI_SERVICES **) PeiServices,\r
+ UsbControllerPpi,\r
+ Index,\r
+ &ControllerType,\r
+ &BaseAddress\r
+ );\r
+ //\r
+ // When status is error, it means no controller is found.\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // This PEIM is for XHC type controller.\r
+ //\r
+ if (ControllerType != PEI_XHCI_CONTROLLER) {\r
+ Index++;\r
+ continue;\r
+ }\r
+\r
+ MemPages = EFI_SIZE_TO_PAGES (sizeof (PEI_XHC_DEV));\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ MemPages,\r
+ &TempPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (MemPages));\r
+ XhcDev = (PEI_XHC_DEV *) ((UINTN) TempPtr);\r
+\r
+ XhcDev->Signature = USB_XHC_DEV_SIGNATURE;\r
+ XhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;\r
+ XhcDev->CapLength = XhcPeiReadCapRegister (XhcDev, XHC_CAPLENGTH_OFFSET) & 0x0FF;\r
+ XhcDev->HcSParams1.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS1_OFFSET);\r
+ XhcDev->HcSParams2.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS2_OFFSET);\r
+ XhcDev->HcCParams.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCCPARAMS_OFFSET);\r
+ XhcDev->DBOff = XhcPeiReadCapRegister (XhcDev, XHC_DBOFF_OFFSET);\r
+ XhcDev->RTSOff = XhcPeiReadCapRegister (XhcDev, XHC_RTSOFF_OFFSET);\r
+\r
+ //\r
+ // This PageSize field defines the page size supported by the xHC implementation.\r
+ // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,\r
+ // if bit 0 is Set, the xHC supports 4k byte page sizes.\r
+ //\r
+ PageSize = XhcPeiReadOpReg (XhcDev, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;\r
+ XhcDev->PageSize = 1 << (HighBitSet32 (PageSize) + 12);\r
+\r
+ DEBUG ((EFI_D_INFO, "XhciPei: UsbHostControllerBaseAddress: %x\n", XhcDev->UsbHostControllerBaseAddress));\r
+ DEBUG ((EFI_D_INFO, "XhciPei: CapLength: %x\n", XhcDev->CapLength));\r
+ DEBUG ((EFI_D_INFO, "XhciPei: HcSParams1: %x\n", XhcDev->HcSParams1.Dword));\r
+ DEBUG ((EFI_D_INFO, "XhciPei: HcSParams2: %x\n", XhcDev->HcSParams2.Dword));\r
+ DEBUG ((EFI_D_INFO, "XhciPei: HcCParams: %x\n", XhcDev->HcCParams.Dword));\r
+ DEBUG ((EFI_D_INFO, "XhciPei: DBOff: %x\n", XhcDev->DBOff));\r
+ DEBUG ((EFI_D_INFO, "XhciPei: RTSOff: %x\n", XhcDev->RTSOff));\r
+ DEBUG ((EFI_D_INFO, "XhciPei: PageSize: %x\n", XhcDev->PageSize));\r
+\r
+ XhcPeiResetHC (XhcDev, XHC_RESET_TIMEOUT);\r
+ ASSERT (XhcPeiIsHalt (XhcDev));\r
+\r
+ //\r
+ // Initialize the schedule\r
+ //\r
+ XhcPeiInitSched (XhcDev);\r
+\r
+ //\r
+ // Start the Host Controller\r
+ //\r
+ XhcPeiRunHC (XhcDev, XHC_GENERIC_TIMEOUT);\r
+\r
+ //\r
+ // Wait for root port state stable\r
+ //\r
+ MicroSecondDelay (XHC_ROOT_PORT_STATE_STABLE);\r
+\r
+ XhcDev->Usb2HostControllerPpi.ControlTransfer = XhcPeiControlTransfer;\r
+ XhcDev->Usb2HostControllerPpi.BulkTransfer = XhcPeiBulkTransfer;\r
+ XhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = XhcPeiGetRootHubPortNumber;\r
+ XhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = XhcPeiGetRootHubPortStatus;\r
+ XhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = XhcPeiSetRootHubPortFeature;\r
+ XhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = XhcPeiClearRootHubPortFeature;\r
+\r
+ XhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+ XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;\r
+ XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;\r
+\r
+ PeiServicesInstallPpi (&XhcDev->PpiDescriptor);\r
+\r
+ Index++;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+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
+**/\r
+\r
+#ifndef _RECOVERY_XHC_H_\r
+#define _RECOVERY_XHC_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbController.h>\r
+#include <Ppi/Usb2HostController.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+typedef struct _PEI_XHC_DEV PEI_XHC_DEV;\r
+typedef struct _USB_DEV_CONTEXT USB_DEV_CONTEXT;\r
+\r
+#include "UsbHcMem.h"\r
+#include "XhciReg.h"\r
+#include "XhciSched.h"\r
+\r
+#define CMD_RING_TRB_NUMBER 0x100\r
+#define TR_RING_TRB_NUMBER 0x100\r
+#define ERST_NUMBER 0x01\r
+#define EVENT_RING_TRB_NUMBER 0x200\r
+\r
+#define XHC_1_MICROSECOND 1\r
+#define XHC_1_MILLISECOND (1000 * XHC_1_MICROSECOND)\r
+#define XHC_1_SECOND (1000 * XHC_1_MILLISECOND)\r
+\r
+//\r
+// XHC reset timeout experience values.\r
+// The unit is microsecond, setting it as 1s.\r
+//\r
+#define XHC_RESET_TIMEOUT (1 * XHC_1_SECOND)\r
+//\r
+// XHC delay experience value for polling operation.\r
+// The unit is microsecond, set it as 1ms.\r
+//\r
+#define XHC_POLL_DELAY (1 * XHC_1_MILLISECOND)\r
+\r
+//\r
+// Wait for root port state stable.\r
+//\r
+#define XHC_ROOT_PORT_STATE_STABLE (200 * XHC_1_MILLISECOND)\r
+\r
+#define XHC_GENERIC_TIMEOUT (10 * XHC_1_MILLISECOND)\r
+\r
+#define XHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0XFFFFFFFF))\r
+#define XHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))\r
+#define XHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))\r
+\r
+#define XHC_REG_BIT_IS_SET(XHC, Offset, Bit) \\r
+ (XHC_BIT_IS_SET(XhcPeiReadOpReg ((XHC), (Offset)), (Bit)))\r
+\r
+#define USB_DESC_TYPE_HUB 0x29\r
+#define USB_DESC_TYPE_HUB_SUPER_SPEED 0x2a\r
+\r
+//\r
+// The RequestType in EFI_USB_DEVICE_REQUEST is composed of\r
+// three fields: One bit direction, 2 bit type, and 5 bit\r
+// target.\r
+//\r
+#define USB_REQUEST_TYPE(Dir, Type, Target) \\r
+ ((UINT8)((((Dir) == EfiUsbDataIn ? 0x01 : 0) << 7) | (Type) | (Target)))\r
+\r
+struct _USB_DEV_CONTEXT {\r
+ //\r
+ // Whether this entry in UsbDevContext array is used or not.\r
+ //\r
+ BOOLEAN Enabled;\r
+ //\r
+ // The slot id assigned to the new device through XHCI's Enable_Slot cmd.\r
+ //\r
+ UINT8 SlotId;\r
+ //\r
+ // The route string presented an attached usb device.\r
+ //\r
+ USB_DEV_ROUTE RouteString;\r
+ //\r
+ // The route string of parent device if it exists. Otherwise it's zero.\r
+ //\r
+ USB_DEV_ROUTE ParentRouteString;\r
+ //\r
+ // The actual device address assigned by XHCI through Address_Device command.\r
+ //\r
+ UINT8 XhciDevAddr;\r
+ //\r
+ // The requested device address from UsbBus driver through Set_Address standard usb request.\r
+ // As XHCI spec replaces this request with Address_Device command, we have to record the\r
+ // requested device address and establish a mapping relationship with the actual device address.\r
+ // Then UsbBus driver just need to be aware of the requested device address to access usb device\r
+ // through EFI_USB2_HC_PROTOCOL. Xhci driver would be responsible for translating it to actual\r
+ // device address and access the actual device.\r
+ //\r
+ UINT8 BusDevAddr;\r
+ //\r
+ // The pointer to the input device context.\r
+ //\r
+ VOID *InputContext;\r
+ //\r
+ // The pointer to the output device context.\r
+ //\r
+ VOID *OutputContext;\r
+ //\r
+ // The transfer queue for every endpoint.\r
+ //\r
+ VOID *EndpointTransferRing[31];\r
+ //\r
+ // The device descriptor which is stored to support XHCI's Evaluate_Context cmd.\r
+ //\r
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
+ //\r
+ // As a usb device may include multiple configuration descriptors, we dynamically allocate an array\r
+ // to store them.\r
+ // Note that every configuration descriptor stored here includes those lower level descriptors,\r
+ // such as Interface descriptor, Endpoint descriptor, and so on.\r
+ // These information is used to support XHCI's Config_Endpoint cmd.\r
+ //\r
+ EFI_USB_CONFIG_DESCRIPTOR **ConfDesc;\r
+};\r
+\r
+#define USB_XHC_DEV_SIGNATURE SIGNATURE_32 ('x', 'h', 'c', 'i')\r
+\r
+struct _PEI_XHC_DEV {\r
+ UINTN Signature;\r
+ PEI_USB2_HOST_CONTROLLER_PPI Usb2HostControllerPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;\r
+ UINT32 UsbHostControllerBaseAddress;\r
+ USBHC_MEM_POOL *MemPool;\r
+\r
+ //\r
+ // XHCI configuration data\r
+ //\r
+ UINT8 CapLength; ///< Capability Register Length\r
+ XHC_HCSPARAMS1 HcSParams1; ///< Structural Parameters 1\r
+ XHC_HCSPARAMS2 HcSParams2; ///< Structural Parameters 2\r
+ XHC_HCCPARAMS HcCParams; ///< Capability Parameters\r
+ UINT32 DBOff; ///< Doorbell Offset\r
+ UINT32 RTSOff; ///< Runtime Register Space Offset\r
+ UINT32 PageSize;\r
+ UINT32 MaxScratchpadBufs;\r
+ UINT64 *ScratchBuf;\r
+ UINT64 *ScratchEntry;\r
+ UINT64 *DCBAA;\r
+ UINT32 MaxSlotsEn;\r
+ //\r
+ // Cmd Transfer Ring\r
+ //\r
+ TRANSFER_RING CmdRing;\r
+ //\r
+ // EventRing\r
+ //\r
+ EVENT_RING EventRing;\r
+\r
+ //\r
+ // Store device contexts managed by XHCI device\r
+ // The array supports up to 255 devices, entry 0 is reserved and should not be used.\r
+ //\r
+ USB_DEV_CONTEXT UsbDevContext[256];\r
+};\r
+\r
+#define PEI_RECOVERY_USB_XHC_DEV_FROM_THIS(a) CR (a, PEI_XHC_DEV, Usb2HostControllerPpi, USB_XHC_DEV_SIGNATURE)\r
+\r
+/**\r
+ Initialize the memory management pool for the host controller.\r
+\r
+ @return Pointer to the allocated memory pool or NULL if failed.\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+ VOID\r
+ )\r
+;\r
+\r
+/**\r
+ Release the memory management pool.\r
+\r
+ @param Pool The USB memory pool to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMemPool (\r
+ IN USBHC_MEM_POOL *Pool\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
+\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
+\r
+#endif\r
--- /dev/null
+## @file\r
+# Component description file for XhcPeim PEIM to produce gPeiUsb2HostControllerPpiGuid\r
+# based on gPeiUsbControllerPpiGuid which is used to enable recovery function from USB Drivers.\r
+#\r
+# Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions\r
+# of the BSD License which accompanies this distribution. The\r
+# 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
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = XhciPei\r
+ FILE_GUID = 65E5746E-9C14-467d-B5B3-932A66D59F79\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = XhcPeimEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ XhcPeim.c\r
+ XhcPeim.h\r
+ XhciSched.c\r
+ UsbHcMem.c\r
+ XhciReg.h\r
+ XhciSched.h\r
+ UsbHcMem.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+ IoLib\r
+ TimerLib\r
+ BaseMemoryLib\r
+ PeimEntryPoint\r
+ PeiServicesLib\r
+ MemoryAllocationLib\r
+\r
+[Ppis]\r
+ gPeiUsb2HostControllerPpiGuid ## PRODUCES\r
+ gPeiUsbControllerPpiGuid ## CONSUMES\r
+\r
+[Depex]\r
+ gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
+\r
--- /dev/null
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+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
+**/\r
+\r
+#ifndef _EFI_PEI_XHCI_REG_H_\r
+#define _EFI_PEI_XHCI_REG_H_\r
+\r
+//\r
+// Capability registers offset\r
+//\r
+#define XHC_CAPLENGTH_OFFSET 0x00 // Capability register length offset\r
+#define XHC_HCIVERSION_OFFSET 0x02 // Interface Version Number 02-03h\r
+#define XHC_HCSPARAMS1_OFFSET 0x04 // Structural Parameters 1\r
+#define XHC_HCSPARAMS2_OFFSET 0x08 // Structural Parameters 2\r
+#define XHC_HCSPARAMS3_OFFSET 0x0c // Structural Parameters 3\r
+#define XHC_HCCPARAMS_OFFSET 0x10 // Capability Parameters\r
+#define XHC_DBOFF_OFFSET 0x14 // Doorbell Offset\r
+#define XHC_RTSOFF_OFFSET 0x18 // Runtime Register Space Offset\r
+\r
+//\r
+// Operational registers offset\r
+//\r
+#define XHC_USBCMD_OFFSET 0x0000 // USB Command Register Offset\r
+#define XHC_USBSTS_OFFSET 0x0004 // USB Status Register Offset\r
+#define XHC_PAGESIZE_OFFSET 0x0008 // USB Page Size Register Offset\r
+#define XHC_DNCTRL_OFFSET 0x0014 // Device Notification Control Register Offset\r
+#define XHC_CRCR_OFFSET 0x0018 // Command Ring Control Register Offset\r
+#define XHC_DCBAAP_OFFSET 0x0030 // Device Context Base Address Array Pointer Register Offset\r
+#define XHC_CONFIG_OFFSET 0x0038 // Configure Register Offset\r
+#define XHC_PORTSC_OFFSET 0x0400 // Port Status and Control Register Offset\r
+\r
+//\r
+// Runtime registers offset\r
+//\r
+#define XHC_MFINDEX_OFFSET 0x00 // Microframe Index Register Offset\r
+#define XHC_IMAN_OFFSET 0x20 // Interrupter X Management Register Offset\r
+#define XHC_IMOD_OFFSET 0x24 // Interrupter X Moderation Register Offset\r
+#define XHC_ERSTSZ_OFFSET 0x28 // Event Ring Segment Table Size Register Offset\r
+#define XHC_ERSTBA_OFFSET 0x30 // Event Ring Segment Table Base Address Register Offset\r
+#define XHC_ERDP_OFFSET 0x38 // Event Ring Dequeue Pointer Register Offset\r
+\r
+//\r
+// Register Bit Definition\r
+//\r
+#define XHC_USBCMD_RUN BIT0 // Run/Stop\r
+#define XHC_USBCMD_RESET BIT1 // Host Controller Reset\r
+#define XHC_USBCMD_INTE BIT2 // Interrupter Enable\r
+#define XHC_USBCMD_HSEE BIT3 // Host System Error Enable\r
+\r
+#define XHC_USBSTS_HALT BIT0 // Host Controller Halted\r
+#define XHC_USBSTS_HSE BIT2 // Host System Error\r
+#define XHC_USBSTS_EINT BIT3 // Event Interrupt\r
+#define XHC_USBSTS_PCD BIT4 // Port Change Detect\r
+#define XHC_USBSTS_SSS BIT8 // Save State Status\r
+#define XHC_USBSTS_RSS BIT9 // Restore State Status\r
+#define XHC_USBSTS_SRE BIT10 // Save/Restore Error\r
+#define XHC_USBSTS_CNR BIT11 // Host Controller Not Ready\r
+#define XHC_USBSTS_HCE BIT12 // Host Controller Error\r
+\r
+#define XHC_PAGESIZE_MASK 0xFFFF // Page Size\r
+\r
+#define XHC_CRCR_RCS BIT0 // Ring Cycle State\r
+#define XHC_CRCR_CS BIT1 // Command Stop\r
+#define XHC_CRCR_CA BIT2 // Command Abort\r
+#define XHC_CRCR_CRR BIT3 // Command Ring Running\r
+\r
+#define XHC_CONFIG_MASK 0xFF // Max Device Slots Enabled\r
+\r
+#define XHC_PORTSC_CCS BIT0 // Current Connect Status\r
+#define XHC_PORTSC_PED BIT1 // Port Enabled/Disabled\r
+#define XHC_PORTSC_OCA BIT3 // Over-current Active\r
+#define XHC_PORTSC_RESET BIT4 // Port Reset\r
+#define XHC_PORTSC_PLS (BIT5|BIT6|BIT7|BIT8) // Port Link State\r
+#define XHC_PORTSC_PP BIT9 // Port Power\r
+#define XHC_PORTSC_PS (BIT10|BIT11|BIT12) // Port Speed\r
+#define XHC_PORTSC_LWS BIT16 // Port Link State Write Strobe\r
+#define XHC_PORTSC_CSC BIT17 // Connect Status Change\r
+#define XHC_PORTSC_PEC BIT18 // Port Enabled/Disabled Change\r
+#define XHC_PORTSC_WRC BIT19 // Warm Port Reset Change\r
+#define XHC_PORTSC_OCC BIT20 // Over-Current Change\r
+#define XHC_PORTSC_PRC BIT21 // Port Reset Change\r
+#define XHC_PORTSC_PLC BIT22 // Port Link State Change\r
+#define XHC_PORTSC_CEC BIT23 // Port Config Error Change\r
+#define XHC_PORTSC_CAS BIT24 // Cold Attach Status\r
+\r
+#define XHC_HUB_PORTSC_CCS BIT0 // Hub's Current Connect Status\r
+#define XHC_HUB_PORTSC_PED BIT1 // Hub's Port Enabled/Disabled\r
+#define XHC_HUB_PORTSC_OCA BIT3 // Hub's Over-current Active\r
+#define XHC_HUB_PORTSC_RESET BIT4 // Hub's Port Reset\r
+#define XHC_HUB_PORTSC_PP BIT9 // Hub's Port Power\r
+#define XHC_HUB_PORTSC_CSC BIT16 // Hub's Connect Status Change\r
+#define XHC_HUB_PORTSC_PEC BIT17 // Hub's Port Enabled/Disabled Change\r
+#define XHC_HUB_PORTSC_OCC BIT19 // Hub's Over-Current Change\r
+#define XHC_HUB_PORTSC_PRC BIT20 // Hub's Port Reset Change\r
+#define XHC_HUB_PORTSC_BHRC BIT21 // Hub's Port Warm Reset Change\r
+\r
+#define XHC_IMAN_IP BIT0 // Interrupt Pending\r
+#define XHC_IMAN_IE BIT1 // Interrupt Enable\r
+\r
+#define XHC_IMODI_MASK 0x0000FFFF // Interrupt Moderation Interval\r
+#define XHC_IMODC_MASK 0xFFFF0000 // Interrupt Moderation Counter\r
+\r
+\r
+#pragma pack (1)\r
+typedef struct {\r
+ UINT8 MaxSlots; // Number of Device Slots\r
+ UINT16 MaxIntrs:11; // Number of Interrupters\r
+ UINT16 Rsvd:5;\r
+ UINT8 MaxPorts; // Number of Ports\r
+} HCSPARAMS1;\r
+\r
+//\r
+// Structural Parameters 1 Register Bitmap Definition\r
+//\r
+typedef union {\r
+ UINT32 Dword;\r
+ HCSPARAMS1 Data;\r
+} XHC_HCSPARAMS1;\r
+\r
+typedef struct {\r
+ UINT32 Ist:4; // Isochronous Scheduling Threshold\r
+ UINT32 Erst:4; // Event Ring Segment Table Max\r
+ UINT32 Rsvd:13;\r
+ UINT32 ScratchBufHi:5; // Max Scratchpad Buffers Hi\r
+ UINT32 Spr:1; // Scratchpad Restore\r
+ UINT32 ScratchBufLo:5; // Max Scratchpad Buffers Lo\r
+} HCSPARAMS2;\r
+\r
+//\r
+// Structural Parameters 2 Register Bitmap Definition\r
+//\r
+typedef union {\r
+ UINT32 Dword;\r
+ HCSPARAMS2 Data;\r
+} XHC_HCSPARAMS2;\r
+\r
+typedef struct {\r
+ UINT16 Ac64:1; // 64-bit Addressing Capability\r
+ UINT16 Bnc:1; // BW Negotiation Capability\r
+ UINT16 Csz:1; // Context Size\r
+ UINT16 Ppc:1; // Port Power Control\r
+ UINT16 Pind:1; // Port Indicators\r
+ UINT16 Lhrc:1; // Light HC Reset Capability\r
+ UINT16 Ltc:1; // Latency Tolerance Messaging Capability\r
+ UINT16 Nss:1; // No Secondary SID Support\r
+ UINT16 Pae:1; // Parse All Event Data\r
+ UINT16 Rsvd:3;\r
+ UINT16 MaxPsaSize:4; // Maximum Primary Stream Array Size\r
+ UINT16 ExtCapReg; // xHCI Extended Capabilities Pointer\r
+} HCCPARAMS;\r
+\r
+//\r
+// Capability Parameters Register Bitmap Definition\r
+//\r
+typedef union {\r
+ UINT32 Dword;\r
+ HCCPARAMS Data;\r
+} XHC_HCCPARAMS;\r
+\r
+#pragma pack ()\r
+\r
+//\r
+// XHCi Data and Ctrl Structures\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+ UINT8 Pi;\r
+ UINT8 SubClassCode;\r
+ UINT8 BaseCode;\r
+} USB_CLASSC;\r
+\r
+typedef struct {\r
+ UINT8 Length;\r
+ UINT8 DescType;\r
+ UINT8 NumPorts;\r
+ UINT16 HubCharacter;\r
+ UINT8 PwrOn2PwrGood;\r
+ UINT8 HubContrCurrent;\r
+ UINT8 Filler[16];\r
+} EFI_USB_HUB_DESCRIPTOR;\r
+#pragma pack()\r
+\r
+//\r
+// Hub Class Feature Selector for Clear Port Feature Request\r
+// It's the extension of hub class feature selector of USB 2.0 in USB 3.0 Spec.\r
+// For more details, Please refer to USB 3.0 Spec Table 10-7.\r
+//\r
+typedef enum {\r
+ Usb3PortBHPortReset = 28,\r
+ Usb3PortBHPortResetChange = 29\r
+} XHC_PORT_FEATURE;\r
+\r
+//\r
+// Structure to map the hardware port states to the\r
+// UEFI's port states.\r
+//\r
+typedef struct {\r
+ UINT32 HwState;\r
+ UINT16 UefiState;\r
+} USB_PORT_STATE_MAP;\r
+\r
+//\r
+// Structure to map the hardware port states to feature selector for clear port feature request.\r
+//\r
+typedef struct {\r
+ UINT32 HwState;\r
+ UINT16 Selector;\r
+} USB_CLEAR_PORT_MAP;\r
+\r
+/**\r
+ Read XHCI Operation register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The operation register offset.\r
+\r
+ @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadOpReg (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset\r
+ );\r
+\r
+/**\r
+ Write the data to the XHCI operation register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The operation register offset.\r
+ @param Data The data to write.\r
+\r
+**/\r
+VOID\r
+XhcPeiWriteOpReg (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Data\r
+ );\r
+\r
+/**\r
+ Set one bit of the operational register while keeping other bits.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the operational register.\r
+ @param Bit The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcPeiSetOpRegBit (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ );\r
+\r
+/**\r
+ Clear one bit of the operational register while keeping other bits.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the operational register.\r
+ @param Bit The bit mask of the register to clear.\r
+\r
+**/\r
+VOID\r
+XhcPeiClearOpRegBit (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ );\r
+\r
+/**\r
+ Wait the operation register's bit as specified by Bit\r
+ to be set (or clear).\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the operational register.\r
+ @param Bit The bit of the register to wait for.\r
+ @param WaitToSet Wait the bit to set or clear.\r
+ @param Timeout The time to wait before abort (in microsecond, us).\r
+\r
+ @retval EFI_SUCCESS The bit successfully changed by host controller.\r
+ @retval EFI_TIMEOUT The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiWaitOpRegBit (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit,\r
+ IN BOOLEAN WaitToSet,\r
+ IN UINT32 Timeout\r
+ );\r
+\r
+/**\r
+ Read XHCI door bell register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the door bell register.\r
+\r
+ @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadDoorBellReg (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset\r
+ );\r
+\r
+/**\r
+ Write the data to the XHCI door bell register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the door bell register.\r
+ @param Data The data to write.\r
+\r
+**/\r
+VOID\r
+XhcPeiWriteDoorBellReg (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Data\r
+ );\r
+\r
+/**\r
+ Read XHCI runtime register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the runtime register.\r
+\r
+ @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadRuntimeReg (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset\r
+ );\r
+\r
+/**\r
+ Write the data to the XHCI runtime register.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the runtime register.\r
+ @param Data The data to write.\r
+\r
+**/\r
+VOID\r
+XhcPeiWriteRuntimeReg (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Data\r
+ );\r
+\r
+/**\r
+ Set one bit of the runtime register while keeping other bits.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the runtime register.\r
+ @param Bit The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcPeiSetRuntimeRegBit (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ );\r
+\r
+/**\r
+ Clear one bit of the runtime register while keeping other bits.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Offset The offset of the runtime register.\r
+ @param Bit The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcPeiClearRuntimeRegBit (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ );\r
+\r
+/**\r
+ Check whether Xhc is halted.\r
+\r
+ @param Xhc The XHCI device.\r
+\r
+ @retval TRUE The controller is halted.\r
+ @retval FALSE The controller isn't halted.\r
+\r
+**/\r
+BOOLEAN\r
+XhcPeiIsHalt (\r
+ IN PEI_XHC_DEV *Xhc\r
+ );\r
+\r
+/**\r
+ Check whether system error occurred.\r
+\r
+ @param Xhc The XHCI device.\r
+\r
+ @retval TRUE System error happened.\r
+ @retval FALSE No system error.\r
+\r
+**/\r
+BOOLEAN\r
+XhcPeiIsSysError (\r
+ IN PEI_XHC_DEV *Xhc\r
+ );\r
+\r
+/**\r
+ Reset the host controller.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Timeout Time to wait before abort (in millisecond, ms).\r
+\r
+ @retval EFI_TIMEOUT The transfer failed due to time out.\r
+ @retval Others Failed to reset the host.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiResetHC (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Timeout\r
+ );\r
+\r
+/**\r
+ Halt the host controller.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Timeout Time to wait before abort.\r
+\r
+ @retval EFI_TIMEOUT Failed to halt the controller before Timeout.\r
+ @retval EFI_SUCCESS The XHCI is halt.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiHaltHC (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Timeout\r
+ );\r
+\r
+/**\r
+ Set the XHCI to run.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Timeout Time to wait before abort.\r
+\r
+ @retval EFI_SUCCESS The XHCI is running.\r
+ @retval Others Failed to set the XHCI to run.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiRunHC (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT32 Timeout\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+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
+**/\r
+\r
+#include "XhcPeim.h"\r
+\r
+/**\r
+ Create a command transfer TRB to support XHCI command interfaces.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param CmdTrb The cmd TRB to be executed.\r
+\r
+ @return Created URB or NULL.\r
+\r
+**/\r
+URB*\r
+XhcPeiCreateCmdTrb (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN TRB_TEMPLATE *CmdTrb\r
+ )\r
+{\r
+ URB *Urb;\r
+\r
+ Urb = AllocateZeroPool (sizeof (URB));\r
+ if (Urb == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Urb->Signature = XHC_URB_SIG;\r
+\r
+ Urb->Ring = &Xhc->CmdRing;\r
+ XhcPeiSyncTrsRing (Xhc, Urb->Ring);\r
+ Urb->TrbNum = 1;\r
+ Urb->TrbStart = Urb->Ring->RingEnqueue;\r
+ CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));\r
+ Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;\r
+ Urb->TrbEnd = Urb->TrbStart;\r
+\r
+ return Urb;\r
+}\r
+\r
+/**\r
+ Execute a XHCI cmd TRB pointed by CmdTrb.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param CmdTrb The cmd TRB to be executed.\r
+ @param Timeout Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+ @param EvtTrb The event TRB corresponding to the cmd TRB.\r
+\r
+ @retval EFI_SUCCESS The transfer was completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT The transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiCmdTransfer (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN TRB_TEMPLATE *CmdTrb,\r
+ IN UINTN Timeout,\r
+ OUT TRB_TEMPLATE **EvtTrb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ URB *Urb;\r
+\r
+ //\r
+ // Validate the parameters\r
+ //\r
+ if ((Xhc == NULL) || (CmdTrb == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+\r
+ if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiCmdTransfer: HC is halted or has system error\n"));\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Create a new URB, then poll the execution status.\r
+ //\r
+ Urb = XhcPeiCreateCmdTrb (Xhc, CmdTrb);\r
+ if (Urb == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiCmdTransfer: failed to create URB\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = XhcPeiExecTransfer (Xhc, TRUE, Urb, Timeout);\r
+ *EvtTrb = Urb->EvtTrb;\r
+\r
+ if (Urb->Result == EFI_USB_NOERROR) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ XhcPeiFreeUrb (Xhc, Urb);\r
+\r
+ON_EXIT:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Create a new URB for a new transaction.\r
+\r
+ @param Xhc The XHCI device\r
+ @param BusAddr The logical device address assigned by UsbBus driver\r
+ @param EpAddr Endpoint addrress\r
+ @param DevSpeed The device speed\r
+ @param MaxPacket The max packet length of the endpoint\r
+ @param Type The transaction type\r
+ @param Request The standard USB request for control transfer\r
+ @param Data The user data to transfer\r
+ @param DataLen The length of data buffer\r
+ @param Callback The function to call when data is transferred\r
+ @param Context The context to the callback\r
+\r
+ @return Created URB or NULL\r
+\r
+**/\r
+URB*\r
+XhcPeiCreateUrb (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 BusAddr,\r
+ IN UINT8 EpAddr,\r
+ IN UINT8 DevSpeed,\r
+ IN UINTN MaxPacket,\r
+ IN UINTN Type,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN VOID *Data,\r
+ IN UINTN DataLen,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ USB_ENDPOINT *Ep;\r
+ EFI_STATUS Status;\r
+ URB *Urb;\r
+\r
+ Urb = AllocateZeroPool (sizeof (URB));\r
+ if (Urb == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Urb->Signature = XHC_URB_SIG;\r
+\r
+ Ep = &Urb->Ep;\r
+ Ep->BusAddr = BusAddr;\r
+ Ep->EpAddr = (UINT8) (EpAddr & 0x0F);\r
+ Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
+ Ep->DevSpeed = DevSpeed;\r
+ Ep->MaxPacket = MaxPacket;\r
+ Ep->Type = Type;\r
+\r
+ Urb->Request = Request;\r
+ Urb->Data = Data;\r
+ Urb->DataLen = DataLen;\r
+ Urb->Callback = Callback;\r
+ Urb->Context = Context;\r
+\r
+ Status = XhcPeiCreateTransferTrb (Xhc, Urb);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiCreateUrb: XhcPeiCreateTransferTrb Failed, Status = %r\n", Status));\r
+ FreePool (Urb);\r
+ Urb = NULL;\r
+ }\r
+\r
+ return Urb;\r
+}\r
+\r
+/**\r
+ Free an allocated URB.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Urb The URB to free.\r
+\r
+**/\r
+VOID\r
+XhcPeiFreeUrb (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN URB *Urb\r
+ )\r
+{\r
+ if ((Xhc == NULL) || (Urb == NULL)) {\r
+ return;\r
+ }\r
+\r
+ FreePool (Urb);\r
+}\r
+\r
+/**\r
+ Create a transfer TRB.\r
+\r
+ @param Xhc The XHCI device\r
+ @param Urb The urb used to construct the transfer TRB.\r
+\r
+ @return Created TRB or NULL\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiCreateTransferTrb (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN URB *Urb\r
+ )\r
+{\r
+ VOID *OutputContext;\r
+ TRANSFER_RING *EPRing;\r
+ UINT8 EPType;\r
+ UINT8 SlotId;\r
+ UINT8 Dci;\r
+ TRB *TrbStart;\r
+ UINTN TotalLen;\r
+ UINTN Len;\r
+ UINTN TrbNum;\r
+\r
+ SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
+ if (SlotId == 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Urb->Finished = FALSE;\r
+ Urb->StartDone = FALSE;\r
+ Urb->EndDone = FALSE;\r
+ Urb->Completed = 0;\r
+ Urb->Result = EFI_USB_NOERROR;\r
+\r
+ Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
+ EPRing = (TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];\r
+ Urb->Ring = EPRing;\r
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
+ if (Xhc->HcCParams.Data.Csz == 0) {\r
+ EPType = (UINT8) ((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;\r
+ } else {\r
+ EPType = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;\r
+ }\r
+\r
+ Urb->DataPhy = Urb->Data;\r
+\r
+ //\r
+ // Construct the TRB\r
+ //\r
+ XhcPeiSyncTrsRing (Xhc, EPRing);\r
+ Urb->TrbStart = EPRing->RingEnqueue;\r
+ switch (EPType) {\r
+ case ED_CONTROL_BIDIR:\r
+ //\r
+ // For control transfer, create SETUP_STAGE_TRB first.\r
+ //\r
+ TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;\r
+ TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;\r
+ TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;\r
+ TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;\r
+ TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;\r
+ TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;\r
+ TrbStart->TrbCtrSetup.Length = 8;\r
+ TrbStart->TrbCtrSetup.IntTarget = 0;\r
+ TrbStart->TrbCtrSetup.IOC = 1;\r
+ TrbStart->TrbCtrSetup.IDT = 1;\r
+ TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;\r
+ if (Urb->Ep.Direction == EfiUsbDataIn) {\r
+ TrbStart->TrbCtrSetup.TRT = 3;\r
+ } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
+ TrbStart->TrbCtrSetup.TRT = 2;\r
+ } else {\r
+ TrbStart->TrbCtrSetup.TRT = 0;\r
+ }\r
+ //\r
+ // Update the cycle bit\r
+ //\r
+ TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;\r
+ Urb->TrbNum++;\r
+\r
+ //\r
+ // For control transfer, create DATA_STAGE_TRB.\r
+ //\r
+ if (Urb->DataLen > 0) {\r
+ XhcPeiSyncTrsRing (Xhc, EPRing);\r
+ TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;\r
+ TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT (Urb->DataPhy);\r
+ TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT (Urb->DataPhy);\r
+ TrbStart->TrbCtrData.Length = (UINT32) Urb->DataLen;\r
+ TrbStart->TrbCtrData.TDSize = 0;\r
+ TrbStart->TrbCtrData.IntTarget = 0;\r
+ TrbStart->TrbCtrData.ISP = 1;\r
+ TrbStart->TrbCtrData.IOC = 1;\r
+ TrbStart->TrbCtrData.IDT = 0;\r
+ TrbStart->TrbCtrData.CH = 0;\r
+ TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;\r
+ if (Urb->Ep.Direction == EfiUsbDataIn) {\r
+ TrbStart->TrbCtrData.DIR = 1;\r
+ } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
+ TrbStart->TrbCtrData.DIR = 0;\r
+ } else {\r
+ TrbStart->TrbCtrData.DIR = 0;\r
+ }\r
+ //\r
+ // Update the cycle bit\r
+ //\r
+ TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;\r
+ Urb->TrbNum++;\r
+ }\r
+ //\r
+ // For control transfer, create STATUS_STAGE_TRB.\r
+ // Get the pointer to next TRB for status stage use\r
+ //\r
+ XhcPeiSyncTrsRing (Xhc, EPRing);\r
+ TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;\r
+ TrbStart->TrbCtrStatus.IntTarget = 0;\r
+ TrbStart->TrbCtrStatus.IOC = 1;\r
+ TrbStart->TrbCtrStatus.CH = 0;\r
+ TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE;\r
+ if (Urb->Ep.Direction == EfiUsbDataIn) {\r
+ TrbStart->TrbCtrStatus.DIR = 0;\r
+ } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
+ TrbStart->TrbCtrStatus.DIR = 1;\r
+ } else {\r
+ TrbStart->TrbCtrStatus.DIR = 0;\r
+ }\r
+ //\r
+ // Update the cycle bit\r
+ //\r
+ TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;\r
+ //\r
+ // Update the enqueue pointer\r
+ //\r
+ XhcPeiSyncTrsRing (Xhc, EPRing);\r
+ Urb->TrbNum++;\r
+ Urb->TrbEnd = (TRB_TEMPLATE *) (UINTN) TrbStart;\r
+\r
+ break;\r
+\r
+ case ED_BULK_OUT:\r
+ case ED_BULK_IN:\r
+ TotalLen = 0;\r
+ Len = 0;\r
+ TrbNum = 0;\r
+ TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;\r
+ while (TotalLen < Urb->DataLen) {\r
+ if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
+ Len = Urb->DataLen - TotalLen;\r
+ } else {\r
+ Len = 0x10000;\r
+ }\r
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
+ TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
+ TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
+ TrbStart->TrbNormal.Length = (UINT32) Len;\r
+ TrbStart->TrbNormal.TDSize = 0;\r
+ TrbStart->TrbNormal.IntTarget = 0;\r
+ TrbStart->TrbNormal.ISP = 1;\r
+ TrbStart->TrbNormal.IOC = 1;\r
+ TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
+ //\r
+ // Update the cycle bit\r
+ //\r
+ TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
+\r
+ XhcPeiSyncTrsRing (Xhc, EPRing);\r
+ TrbNum++;\r
+ TotalLen += Len;\r
+ }\r
+\r
+ Urb->TrbNum = TrbNum;\r
+ Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
+ break;\r
+\r
+ case ED_INTERRUPT_OUT:\r
+ case ED_INTERRUPT_IN:\r
+ TotalLen = 0;\r
+ Len = 0;\r
+ TrbNum = 0;\r
+ TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;\r
+ while (TotalLen < Urb->DataLen) {\r
+ if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
+ Len = Urb->DataLen - TotalLen;\r
+ } else {\r
+ Len = 0x10000;\r
+ }\r
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
+ TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
+ TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
+ TrbStart->TrbNormal.Length = (UINT32) Len;\r
+ TrbStart->TrbNormal.TDSize = 0;\r
+ TrbStart->TrbNormal.IntTarget = 0;\r
+ TrbStart->TrbNormal.ISP = 1;\r
+ TrbStart->TrbNormal.IOC = 1;\r
+ TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
+ //\r
+ // Update the cycle bit\r
+ //\r
+ TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
+\r
+ XhcPeiSyncTrsRing (Xhc, EPRing);\r
+ TrbNum++;\r
+ TotalLen += Len;\r
+ }\r
+\r
+ Urb->TrbNum = TrbNum;\r
+ Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
+ break;\r
+\r
+ default:\r
+ DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
+ condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
+ Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
+ reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
+ Stopped to the Running state.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Urb The urb which makes the endpoint halted.\r
+\r
+ @retval EFI_SUCCESS The recovery is successful.\r
+ @retval Others Failed to recovery halted endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiRecoverHaltedEndpoint (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN URB *Urb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
+ CMD_TRB_RESET_ENDPOINT CmdTrbResetED;\r
+ CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;\r
+ UINT8 Dci;\r
+ UINT8 SlotId;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ Status = EFI_SUCCESS;\r
+ SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
+ if (SlotId == 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8) (Urb->Ep.Direction));\r
+\r
+ DEBUG ((EFI_D_INFO, "XhcPeiRecoverHaltedEndpoint: Recovery Halted Slot = %x, Dci = %x\n", SlotId, Dci));\r
+\r
+ //\r
+ // 1) Send Reset endpoint command to transit from halt to stop state\r
+ //\r
+ ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
+ CmdTrbResetED.CycleBit = 1;\r
+ CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;\r
+ CmdTrbResetED.EDID = Dci;\r
+ CmdTrbResetED.SlotId = SlotId;\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // 2) Set dequeue pointer\r
+ //\r
+ ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
+ CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
+ CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+ CmdSetTRDeq.CycleBit = 1;\r
+ CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;\r
+ CmdSetTRDeq.Endpoint = Dci;\r
+ CmdSetTRDeq.SlotId = SlotId;\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // 3) Ring the doorbell to transit from stop to active\r
+ //\r
+ XhcPeiRingDoorBell (Xhc, SlotId, Dci);\r
+\r
+Done:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check if the Trb is a transaction of the URB.\r
+\r
+ @param Trb The TRB to be checked\r
+ @param Urb The transfer ring to be checked.\r
+\r
+ @retval TRUE It is a transaction of the URB.\r
+ @retval FALSE It is not any transaction of the URB.\r
+\r
+**/\r
+BOOLEAN\r
+XhcPeiIsTransferRingTrb (\r
+ IN TRB_TEMPLATE *Trb,\r
+ IN URB *Urb\r
+ )\r
+{\r
+ TRB_TEMPLATE *CheckedTrb;\r
+ UINTN Index;\r
+\r
+ CheckedTrb = Urb->Ring->RingSeg0;\r
+\r
+ ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);\r
+\r
+ for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {\r
+ if (Trb == CheckedTrb) {\r
+ return TRUE;\r
+ }\r
+ CheckedTrb++;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Check the URB's execution result and update the URB's\r
+ result accordingly.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Urb The URB to check result.\r
+\r
+ @return Whether the result of URB transfer is finialized.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiCheckUrbResult (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN URB *Urb\r
+ )\r
+{\r
+ EVT_TRB_TRANSFER *EvtTrb;\r
+ TRB_TEMPLATE *TRBPtr;\r
+ UINTN Index;\r
+ UINT8 TRBType;\r
+ EFI_STATUS Status;\r
+ URB *CheckedUrb;\r
+ UINT64 XhcDequeue;\r
+ UINT32 High;\r
+ UINT32 Low;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ ASSERT ((Xhc != NULL) && (Urb != NULL));\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (Urb->Finished) {\r
+ goto EXIT;\r
+ }\r
+\r
+ EvtTrb = NULL;\r
+\r
+ if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
+ Urb->Result |= EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto EXIT;\r
+ }\r
+\r
+ //\r
+ // Traverse the event ring to find out all new events from the previous check.\r
+ //\r
+ XhcPeiSyncEventRing (Xhc, &Xhc->EventRing);\r
+ for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {\r
+ Status = XhcPeiCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **) &EvtTrb));\r
+ if (Status == EFI_NOT_READY) {\r
+ //\r
+ // All new events are handled, return directly.\r
+ //\r
+ goto EXIT;\r
+ }\r
+\r
+ //\r
+ // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.\r
+ //\r
+ if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Need convert pci device address to host address\r
+ //\r
+ PhyAddr = (EFI_PHYSICAL_ADDRESS) (EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));\r
+ TRBPtr = (TRB_TEMPLATE *) (UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *) (UINTN) PhyAddr, sizeof (TRB_TEMPLATE));\r
+\r
+ //\r
+ // Update the status of Urb according to the finished event regardless of whether\r
+ // the urb is current checked one or in the XHCI's async transfer list.\r
+ // This way is used to avoid that those completed async transfer events don't get\r
+ // handled in time and are flushed by newer coming events.\r
+ //\r
+ if (XhcPeiIsTransferRingTrb (TRBPtr, Urb)) {\r
+ CheckedUrb = Urb;\r
+ } else {\r
+ continue;\r
+ }\r
+\r
+ switch (EvtTrb->Completecode) {\r
+ case TRB_COMPLETION_STALL_ERROR:\r
+ CheckedUrb->Result |= EFI_USB_ERR_STALL;\r
+ CheckedUrb->Finished = TRUE;\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb->Completecode));\r
+ goto EXIT;\r
+\r
+ case TRB_COMPLETION_BABBLE_ERROR:\r
+ CheckedUrb->Result |= EFI_USB_ERR_BABBLE;\r
+ CheckedUrb->Finished = TRUE;\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb->Completecode));\r
+ goto EXIT;\r
+\r
+ case TRB_COMPLETION_DATA_BUFFER_ERROR:\r
+ CheckedUrb->Result |= EFI_USB_ERR_BUFFER;\r
+ CheckedUrb->Finished = TRUE;\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb->Completecode));\r
+ goto EXIT;\r
+\r
+ case TRB_COMPLETION_USB_TRANSACTION_ERROR:\r
+ CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
+ CheckedUrb->Finished = TRUE;\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb->Completecode));\r
+ goto EXIT;\r
+\r
+ case TRB_COMPLETION_SHORT_PACKET:\r
+ case TRB_COMPLETION_SUCCESS:\r
+ if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: short packet happens!\n"));\r
+ }\r
+\r
+ TRBType = (UINT8) (TRBPtr->Type);\r
+ if ((TRBType == TRB_TYPE_DATA_STAGE) ||\r
+ (TRBType == TRB_TYPE_NORMAL) ||\r
+ (TRBType == TRB_TYPE_ISOCH)) {\r
+ CheckedUrb->Completed += (CheckedUrb->DataLen - EvtTrb->Length);\r
+ }\r
+\r
+ break;\r
+\r
+ default:\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb->Completecode));\r
+ CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
+ CheckedUrb->Finished = TRUE;\r
+ goto EXIT;\r
+ }\r
+\r
+ //\r
+ // Only check first and end Trb event address\r
+ //\r
+ if (TRBPtr == CheckedUrb->TrbStart) {\r
+ CheckedUrb->StartDone = TRUE;\r
+ }\r
+\r
+ if (TRBPtr == CheckedUrb->TrbEnd) {\r
+ CheckedUrb->EndDone = TRUE;\r
+ }\r
+\r
+ if (CheckedUrb->StartDone && CheckedUrb->EndDone) {\r
+ CheckedUrb->Finished = TRUE;\r
+ CheckedUrb->EvtTrb = (TRB_TEMPLATE *) EvtTrb;\r
+ }\r
+ }\r
+\r
+EXIT:\r
+\r
+ //\r
+ // Advance event ring to last available entry\r
+ //\r
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+ // So divide it to two 32-bytes width register access.\r
+ //\r
+ Low = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);\r
+ High = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);\r
+ XhcDequeue = (UINT64) (LShiftU64((UINT64) High, 32) | Low);\r
+\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));\r
+\r
+ if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {\r
+ //\r
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+ // So divide it to two 32-bytes width register access.\r
+ //\r
+ XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);\r
+ XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Execute the transfer by polling the URB. This is a synchronous operation.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param CmdTransfer The executed URB is for cmd transfer or not.\r
+ @param Urb The URB to execute.\r
+ @param Timeout The time to wait before abort, in millisecond.\r
+\r
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
+ @return EFI_TIMEOUT The transfer failed due to time out.\r
+ @return EFI_SUCCESS The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiExecTransfer (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN BOOLEAN CmdTransfer,\r
+ IN URB *Urb,\r
+ IN UINTN Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN Loop;\r
+ UINT8 SlotId;\r
+ UINT8 Dci;\r
+\r
+ if (CmdTransfer) {\r
+ SlotId = 0;\r
+ Dci = 0;\r
+ } else {\r
+ SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
+ if (SlotId == 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ Loop = Timeout * XHC_1_MILLISECOND;\r
+ if (Timeout == 0) {\r
+ Loop = 0xFFFFFFFF;\r
+ }\r
+\r
+ XhcPeiRingDoorBell (Xhc, SlotId, Dci);\r
+\r
+ for (Index = 0; Index < Loop; Index++) {\r
+ Status = XhcPeiCheckUrbResult (Xhc, Urb);\r
+ if (Urb->Finished) {\r
+ break;\r
+ }\r
+ MicroSecondDelay (XHC_1_MICROSECOND);\r
+ }\r
+\r
+ if (Index == Loop) {\r
+ Urb->Result = EFI_USB_ERR_TIMEOUT;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param ParentRouteChart The route string pointed to the parent device if it exists.\r
+ @param Port The port to be polled.\r
+ @param PortState The port state.\r
+\r
+ @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.\r
+ @retval Others Should not appear.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiPollPortStatusChange (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN USB_DEV_ROUTE ParentRouteChart,\r
+ IN UINT8 Port,\r
+ IN EFI_USB_PORT_STATUS *PortState\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Speed;\r
+ UINT8 SlotId;\r
+ USB_DEV_ROUTE RouteChart;\r
+\r
+ DEBUG ((EFI_D_INFO, "XhcPeiPollPortStatusChange: PortChangeStatus: %x PortStatus: %x\n", PortState->PortChangeStatus, PortState->PortStatus));\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (ParentRouteChart.Dword == 0) {\r
+ RouteChart.Route.RouteString = 0;\r
+ RouteChart.Route.RootPortNum = Port + 1;\r
+ RouteChart.Route.TierNum = 1;\r
+ } else {\r
+ if(Port < 14) {\r
+ RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
+ } else {\r
+ RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
+ }\r
+ RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;\r
+ RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;\r
+ }\r
+\r
+ SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);\r
+ if (SlotId != 0) {\r
+ if (Xhc->HcCParams.Data.Csz == 0) {\r
+ Status = XhcPeiDisableSlotCmd (Xhc, SlotId);\r
+ } else {\r
+ Status = XhcPeiDisableSlotCmd64 (Xhc, SlotId);\r
+ }\r
+ }\r
+\r
+ if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&\r
+ ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {\r
+ //\r
+ // Has a device attached, Identify device speed after port is enabled.\r
+ //\r
+ Speed = EFI_USB_SPEED_FULL;\r
+ if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
+ Speed = EFI_USB_SPEED_LOW;\r
+ } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {\r
+ Speed = EFI_USB_SPEED_HIGH;\r
+ } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
+ Speed = EFI_USB_SPEED_SUPER;\r
+ }\r
+ //\r
+ // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.\r
+ //\r
+ SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);\r
+ if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {\r
+ if (Xhc->HcCParams.Data.Csz == 0) {\r
+ Status = XhcPeiInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
+ } else {\r
+ Status = XhcPeiInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
+ }\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Calculate the device context index by endpoint address and direction.\r
+\r
+ @param EpAddr The target endpoint number.\r
+ @param Direction The direction of the target endpoint.\r
+\r
+ @return The device context index of endpoint.\r
+\r
+**/\r
+UINT8\r
+XhcPeiEndpointToDci (\r
+ IN UINT8 EpAddr,\r
+ IN EFI_USB_DATA_DIRECTION Direction\r
+ )\r
+{\r
+ UINT8 Index;\r
+\r
+ ASSERT (EpAddr <= 15);\r
+\r
+ if (EpAddr == 0) {\r
+ return 1;\r
+ } else {\r
+ Index = (UINT8) (2 * EpAddr);\r
+ if (Direction == EfiUsbDataIn) {\r
+ Index += 1;\r
+ }\r
+ return Index;\r
+ }\r
+}\r
+\r
+/**\r
+ Find out the actual device address according to the requested device address from UsbBus.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param BusDevAddr The requested device address by UsbBus upper driver.\r
+\r
+ @return The actual device address assigned to the device.\r
+\r
+**/\r
+UINT8\r
+XhcPeiBusDevAddrToSlotId (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 BusDevAddr\r
+ )\r
+{\r
+ UINT8 Index;\r
+\r
+ for (Index = 0; Index < 255; Index++) {\r
+ if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
+ (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
+ (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index == 255) {\r
+ return 0;\r
+ }\r
+\r
+ return Xhc->UsbDevContext[Index + 1].SlotId;\r
+}\r
+\r
+/**\r
+ Find out the slot id according to the device's route string.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param RouteString The route string described the device location.\r
+\r
+ @return The slot id used by the device.\r
+\r
+**/\r
+UINT8\r
+XhcPeiRouteStringToSlotId (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN USB_DEV_ROUTE RouteString\r
+ )\r
+{\r
+ UINT8 Index;\r
+\r
+ for (Index = 0; Index < 255; Index++) {\r
+ if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
+ (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
+ (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index == 255) {\r
+ return 0;\r
+ }\r
+\r
+ return Xhc->UsbDevContext[Index + 1].SlotId;\r
+}\r
+\r
+/**\r
+ Ring the door bell to notify XHCI there is a transaction to be executed.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id of the target device.\r
+ @param Dci The device context index of the target slot or endpoint.\r
+\r
+**/\r
+VOID\r
+XhcPeiRingDoorBell (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT8 Dci\r
+ )\r
+{\r
+ if (SlotId == 0) {\r
+ XhcPeiWriteDoorBellReg (Xhc, 0, 0);\r
+ } else {\r
+ XhcPeiWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);\r
+ }\r
+}\r
+\r
+/**\r
+ Assign and initialize the device slot for a new device.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param ParentRouteChart The route string pointed to the parent device.\r
+ @param ParentPort The port at which the device is located.\r
+ @param RouteChart The route string pointed to the device.\r
+ @param DeviceSpeed The device speed.\r
+\r
+ @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
+ @retval Others Fail to initialize device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiInitializeDeviceSlot (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN USB_DEV_ROUTE ParentRouteChart,\r
+ IN UINT16 ParentPort,\r
+ IN USB_DEV_ROUTE RouteChart,\r
+ IN UINT8 DeviceSpeed\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
+ INPUT_CONTEXT *InputContext;\r
+ DEVICE_CONTEXT *OutputContext;\r
+ TRANSFER_RING *EndpointTransferRing;\r
+ CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
+ UINT8 DeviceAddress;\r
+ CMD_TRB_ENABLE_SLOT CmdTrb;\r
+ UINT8 SlotId;\r
+ UINT8 ParentSlotId;\r
+ DEVICE_CONTEXT *ParentDeviceContext;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
+ CmdTrb.CycleBit = 1;\r
+ CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
+\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+ ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
+ DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
+ SlotId = (UINT8) EvtTrb->SlotId;\r
+ ASSERT (SlotId != 0);\r
+\r
+ ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
+ Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
+ Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
+ Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
+ Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
+\r
+ //\r
+ // 4.3.3 Device Slot Initialization\r
+ // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
+ //\r
+ InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));\r
+ ASSERT (InputContext != NULL);\r
+ ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
+\r
+ Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
+\r
+ //\r
+ // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
+ // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
+ // Context are affected by the command.\r
+ //\r
+ InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
+\r
+ //\r
+ // 3) Initialize the Input Slot Context data structure\r
+ //\r
+ InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
+ InputContext->Slot.Speed = DeviceSpeed + 1;\r
+ InputContext->Slot.ContextEntries = 1;\r
+ InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
+\r
+ if (RouteChart.Route.RouteString != 0) {\r
+ //\r
+ // The device is behind of hub device.\r
+ //\r
+ ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);\r
+ ASSERT (ParentSlotId != 0);\r
+ //\r
+ // If the Full/Low device attached to a High Speed Hub, init the TTPortNum and TTHubSlotId field of slot context\r
+ //\r
+ ParentDeviceContext = (DEVICE_CONTEXT *) Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
+ if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
+ (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
+ if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
+ //\r
+ // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
+ // environment from Full/Low speed signaling environment for a device\r
+ //\r
+ InputContext->Slot.TTPortNum = ParentPort;\r
+ InputContext->Slot.TTHubSlotId = ParentSlotId;\r
+ }\r
+ } else {\r
+ //\r
+ // Inherit the TT parameters from parent device.\r
+ //\r
+ InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
+ InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
+ //\r
+ // If the device is a High speed device then down the speed to be the same as its parent Hub\r
+ //\r
+ if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+ InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
+ //\r
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
+ XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
+ //\r
+ // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
+ //\r
+ InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
+\r
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+ InputContext->EP[0].MaxPacketSize = 512;\r
+ } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+ InputContext->EP[0].MaxPacketSize = 64;\r
+ } else {\r
+ InputContext->EP[0].MaxPacketSize = 8;\r
+ }\r
+ //\r
+ // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
+ // 1KB, and Bulk and Isoch endpoints 3KB.\r
+ //\r
+ InputContext->EP[0].AverageTRBLength = 8;\r
+ InputContext->EP[0].MaxBurstSize = 0;\r
+ InputContext->EP[0].Interval = 0;\r
+ InputContext->EP[0].MaxPStreams = 0;\r
+ InputContext->EP[0].Mult = 0;\r
+ InputContext->EP[0].CErr = 3;\r
+\r
+ //\r
+ // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
+ //\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (\r
+ Xhc->MemPool,\r
+ ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
+ );\r
+ InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
+ InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+\r
+ //\r
+ // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
+ //\r
+ OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));\r
+ ASSERT (OutputContext != NULL);\r
+ ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
+ ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));\r
+\r
+ Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
+ //\r
+ // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
+ // a pointer to the Output Device Context data structure (6.2.1).\r
+ //\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));\r
+ //\r
+ // Fill DCBAA with PCI device address\r
+ //\r
+ Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;\r
+\r
+ //\r
+ // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
+ // Context data structure described above.\r
+ //\r
+ ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
+ CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+ CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+ CmdTrbAddr.CycleBit = 1;\r
+ CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
+ CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ DeviceAddress = (UINT8) OutputContext->Slot.DeviceAddress;\r
+ DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress));\r
+ Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Assign and initialize the device slot for a new device.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param ParentRouteChart The route string pointed to the parent device.\r
+ @param ParentPort The port at which the device is located.\r
+ @param RouteChart The route string pointed to the device.\r
+ @param DeviceSpeed The device speed.\r
+\r
+ @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
+ @retval Others Fail to initialize device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiInitializeDeviceSlot64 (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN USB_DEV_ROUTE ParentRouteChart,\r
+ IN UINT16 ParentPort,\r
+ IN USB_DEV_ROUTE RouteChart,\r
+ IN UINT8 DeviceSpeed\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
+ INPUT_CONTEXT_64 *InputContext;\r
+ DEVICE_CONTEXT_64 *OutputContext;\r
+ TRANSFER_RING *EndpointTransferRing;\r
+ CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
+ UINT8 DeviceAddress;\r
+ CMD_TRB_ENABLE_SLOT CmdTrb;\r
+ UINT8 SlotId;\r
+ UINT8 ParentSlotId;\r
+ DEVICE_CONTEXT_64 *ParentDeviceContext;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
+ CmdTrb.CycleBit = 1;\r
+ CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
+\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+ ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
+ DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
+ SlotId = (UINT8)EvtTrb->SlotId;\r
+ ASSERT (SlotId != 0);\r
+\r
+ ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
+ Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
+ Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
+ Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
+ Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
+\r
+ //\r
+ // 4.3.3 Device Slot Initialization\r
+ // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
+ //\r
+ InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));\r
+ ASSERT (InputContext != NULL);\r
+ ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
+\r
+ Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
+\r
+ //\r
+ // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
+ // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
+ // Context are affected by the command.\r
+ //\r
+ InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
+\r
+ //\r
+ // 3) Initialize the Input Slot Context data structure\r
+ //\r
+ InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
+ InputContext->Slot.Speed = DeviceSpeed + 1;\r
+ InputContext->Slot.ContextEntries = 1;\r
+ InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
+\r
+ if (RouteChart.Route.RouteString != 0) {\r
+ //\r
+ // The device is behind of hub device.\r
+ //\r
+ ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);\r
+ ASSERT (ParentSlotId != 0);\r
+ //\r
+ //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
+ //\r
+ ParentDeviceContext = (DEVICE_CONTEXT_64 *) Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
+ if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
+ (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
+ if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
+ //\r
+ // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
+ // environment from Full/Low speed signaling environment for a device\r
+ //\r
+ InputContext->Slot.TTPortNum = ParentPort;\r
+ InputContext->Slot.TTHubSlotId = ParentSlotId;\r
+ }\r
+ } else {\r
+ //\r
+ // Inherit the TT parameters from parent device.\r
+ //\r
+ InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
+ InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
+ //\r
+ // If the device is a High speed device then down the speed to be the same as its parent Hub\r
+ //\r
+ if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+ InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
+ //\r
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
+ XhcPeiCreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
+ //\r
+ // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
+ //\r
+ InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
+\r
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+ InputContext->EP[0].MaxPacketSize = 512;\r
+ } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+ InputContext->EP[0].MaxPacketSize = 64;\r
+ } else {\r
+ InputContext->EP[0].MaxPacketSize = 8;\r
+ }\r
+ //\r
+ // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
+ // 1KB, and Bulk and Isoch endpoints 3KB.\r
+ //\r
+ InputContext->EP[0].AverageTRBLength = 8;\r
+ InputContext->EP[0].MaxBurstSize = 0;\r
+ InputContext->EP[0].Interval = 0;\r
+ InputContext->EP[0].MaxPStreams = 0;\r
+ InputContext->EP[0].Mult = 0;\r
+ InputContext->EP[0].CErr = 3;\r
+\r
+ //\r
+ // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
+ //\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (\r
+ Xhc->MemPool,\r
+ ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
+ );\r
+ InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
+ InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+\r
+ //\r
+ // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
+ //\r
+ OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));\r
+ ASSERT (OutputContext != NULL);\r
+ ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
+ ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));\r
+\r
+ Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
+ //\r
+ // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
+ // a pointer to the Output Device Context data structure (6.2.1).\r
+ //\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));\r
+ //\r
+ // Fill DCBAA with PCI device address\r
+ //\r
+ Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;\r
+\r
+ //\r
+ // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
+ // Context data structure described above.\r
+ //\r
+ ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
+ CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+ CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+ CmdTrbAddr.CycleBit = 1;\r
+ CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
+ CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ DeviceAddress = (UINT8) OutputContext->Slot.DeviceAddress;\r
+ DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress));\r
+ Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status));\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Disable the specified device slot.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be disabled.\r
+\r
+ @retval EFI_SUCCESS Successfully disable the device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiDisableSlotCmd (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ TRB_TEMPLATE *EvtTrb;\r
+ CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
+ UINT8 Index;\r
+ VOID *RingSeg;\r
+\r
+ //\r
+ // Disable the device slots occupied by these devices on its downstream ports.\r
+ // Entry 0 is reserved.\r
+ //\r
+ for (Index = 0; Index < 255; Index++) {\r
+ if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
+ (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
+ (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
+ continue;\r
+ }\r
+\r
+ Status = XhcPeiDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));\r
+ Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Construct the disable slot command\r
+ //\r
+ DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId));\r
+\r
+ ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
+ CmdTrbDisSlot.CycleBit = 1;\r
+ CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
+ CmdTrbDisSlot.SlotId = SlotId;\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Free the slot's device context entry\r
+ //\r
+ Xhc->DCBAA[SlotId] = 0;\r
+\r
+ //\r
+ // Free the slot related data structure\r
+ //\r
+ for (Index = 0; Index < 31; Index++) {\r
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
+ RingSeg = ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
+ if (RingSeg != NULL) {\r
+ UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
+ }\r
+ FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
+ }\r
+ }\r
+\r
+ for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
+ if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
+ FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
+ }\r
+ }\r
+\r
+ if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
+ UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
+ }\r
+\r
+ if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
+ UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));\r
+ }\r
+ //\r
+ // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
+ // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
+ // remove urb from XHCI's asynchronous transfer list.\r
+ //\r
+ Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
+ Xhc->UsbDevContext[SlotId].SlotId = 0;\r
+\r
+ DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Disable the specified device slot.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be disabled.\r
+\r
+ @retval EFI_SUCCESS Successfully disable the device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiDisableSlotCmd64 (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ TRB_TEMPLATE *EvtTrb;\r
+ CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
+ UINT8 Index;\r
+ VOID *RingSeg;\r
+\r
+ //\r
+ // Disable the device slots occupied by these devices on its downstream ports.\r
+ // Entry 0 is reserved.\r
+ //\r
+ for (Index = 0; Index < 255; Index++) {\r
+ if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
+ (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
+ (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
+ continue;\r
+ }\r
+\r
+ Status = XhcPeiDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));\r
+ Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Construct the disable slot command\r
+ //\r
+ DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId));\r
+\r
+ ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
+ CmdTrbDisSlot.CycleBit = 1;\r
+ CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
+ CmdTrbDisSlot.SlotId = SlotId;\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Free the slot's device context entry\r
+ //\r
+ Xhc->DCBAA[SlotId] = 0;\r
+\r
+ //\r
+ // Free the slot related data structure\r
+ //\r
+ for (Index = 0; Index < 31; Index++) {\r
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
+ RingSeg = ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
+ if (RingSeg != NULL) {\r
+ UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
+ }\r
+ FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
+ }\r
+ }\r
+\r
+ for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
+ if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
+ FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
+ }\r
+ }\r
+\r
+ if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
+ UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
+ }\r
+\r
+ if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
+ UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));\r
+ }\r
+ //\r
+ // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
+ // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
+ // remove urb from XHCI's asynchronous transfer list.\r
+ //\r
+ Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
+ Xhc->UsbDevContext[SlotId].SlotId = 0;\r
+\r
+ DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be configured.\r
+ @param DeviceSpeed The device's speed.\r
+ @param ConfigDesc The pointer to the usb device configuration descriptor.\r
+\r
+ @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSetConfigCmd (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT8 DeviceSpeed,\r
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ USB_INTERFACE_DESCRIPTOR *IfDesc;\r
+ USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
+ UINT8 Index;\r
+ UINTN NumEp;\r
+ UINTN EpIndex;\r
+ UINT8 EpAddr;\r
+ EFI_USB_DATA_DIRECTION Direction;\r
+ UINT8 Dci;\r
+ UINT8 MaxDci;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+ UINT8 Interval;\r
+\r
+ TRANSFER_RING *EndpointTransferRing;\r
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
+ INPUT_CONTEXT *InputContext;\r
+ DEVICE_CONTEXT *OutputContext;\r
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
+ //\r
+ // 4.6.6 Configure Endpoint\r
+ //\r
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
+ CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
+\r
+ ASSERT (ConfigDesc != NULL);\r
+\r
+ MaxDci = 0;\r
+\r
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *) (ConfigDesc + 1);\r
+ for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
+ while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);\r
+ }\r
+\r
+ NumEp = IfDesc->NumEndpoints;\r
+\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDesc + 1);\r
+ for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
+ while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);\r
+ }\r
+\r
+ EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);\r
+ Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
+\r
+ Dci = XhcPeiEndpointToDci (EpAddr, Direction);\r
+ if (Dci > MaxDci) {\r
+ MaxDci = Dci;\r
+ }\r
+\r
+ InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
+ InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
+\r
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+ //\r
+ // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
+ //\r
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
+ } else {\r
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
+ }\r
+\r
+ switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
+ case USB_ENDPOINT_BULK:\r
+ if (Direction == EfiUsbDataIn) {\r
+ InputContext->EP[Dci-1].CErr = 3;\r
+ InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
+ } else {\r
+ InputContext->EP[Dci-1].CErr = 3;\r
+ InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
+ }\r
+\r
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
+ XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+ }\r
+\r
+ break;\r
+ case USB_ENDPOINT_ISO:\r
+ if (Direction == EfiUsbDataIn) {\r
+ InputContext->EP[Dci-1].CErr = 0;\r
+ InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
+ } else {\r
+ InputContext->EP[Dci-1].CErr = 0;\r
+ InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
+ }\r
+ break;\r
+ case USB_ENDPOINT_INTERRUPT:\r
+ if (Direction == EfiUsbDataIn) {\r
+ InputContext->EP[Dci-1].CErr = 3;\r
+ InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
+ } else {\r
+ InputContext->EP[Dci-1].CErr = 3;\r
+ InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
+ }\r
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
+ InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
+ //\r
+ // Get the bInterval from descriptor and init the interval field of endpoint context\r
+ //\r
+ if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
+ Interval = EpDesc->Interval;\r
+ //\r
+ // Calculate through the bInterval field of Endpoint descriptor.\r
+ //\r
+ ASSERT (Interval != 0);\r
+ InputContext->EP[Dci-1].Interval = (UINT32) HighBitSet32 ((UINT32) Interval) + 3;\r
+ } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
+ Interval = EpDesc->Interval;\r
+ ASSERT (Interval >= 1 && Interval <= 16);\r
+ //\r
+ // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
+ //\r
+ InputContext->EP[Dci-1].Interval = Interval - 1;\r
+ }\r
+\r
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
+ XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+ }\r
+ break;\r
+\r
+ case USB_ENDPOINT_CONTROL:\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (\r
+ Xhc->MemPool,\r
+ ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
+ );\r
+ PhyAddr &= ~(0x0F);\r
+ PhyAddr |= ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
+ InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+ InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);\r
+ }\r
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);\r
+ }\r
+\r
+ InputContext->InputControlContext.Dword2 |= BIT0;\r
+ InputContext->Slot.ContextEntries = MaxDci;\r
+ //\r
+ // configure endpoint\r
+ //\r
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+ CmdTrbCfgEP.CycleBit = 1;\r
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
+ DEBUG ((EFI_D_INFO, "XhcSetConfigCmd: Configure Endpoint\n"));\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be configured.\r
+ @param DeviceSpeed The device's speed.\r
+ @param ConfigDesc The pointer to the usb device configuration descriptor.\r
+\r
+ @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSetConfigCmd64 (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT8 DeviceSpeed,\r
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ USB_INTERFACE_DESCRIPTOR *IfDesc;\r
+ USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
+ UINT8 Index;\r
+ UINTN NumEp;\r
+ UINTN EpIndex;\r
+ UINT8 EpAddr;\r
+ EFI_USB_DATA_DIRECTION Direction;\r
+ UINT8 Dci;\r
+ UINT8 MaxDci;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+ UINT8 Interval;\r
+\r
+ TRANSFER_RING *EndpointTransferRing;\r
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
+ INPUT_CONTEXT_64 *InputContext;\r
+ DEVICE_CONTEXT_64 *OutputContext;\r
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
+ //\r
+ // 4.6.6 Configure Endpoint\r
+ //\r
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
+ CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));\r
+\r
+ ASSERT (ConfigDesc != NULL);\r
+\r
+ MaxDci = 0;\r
+\r
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *) (ConfigDesc + 1);\r
+ for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
+ while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);\r
+ }\r
+\r
+ NumEp = IfDesc->NumEndpoints;\r
+\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDesc + 1);\r
+ for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
+ while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);\r
+ }\r
+\r
+ EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);\r
+ Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
+\r
+ Dci = XhcPeiEndpointToDci (EpAddr, Direction);\r
+ ASSERT (Dci < 32);\r
+ if (Dci > MaxDci) {\r
+ MaxDci = Dci;\r
+ }\r
+\r
+ InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
+ InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
+\r
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+ //\r
+ // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
+ //\r
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
+ } else {\r
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
+ }\r
+\r
+ switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
+ case USB_ENDPOINT_BULK:\r
+ if (Direction == EfiUsbDataIn) {\r
+ InputContext->EP[Dci-1].CErr = 3;\r
+ InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
+ } else {\r
+ InputContext->EP[Dci-1].CErr = 3;\r
+ InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
+ }\r
+\r
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
+ XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+ }\r
+\r
+ break;\r
+ case USB_ENDPOINT_ISO:\r
+ if (Direction == EfiUsbDataIn) {\r
+ InputContext->EP[Dci-1].CErr = 0;\r
+ InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
+ } else {\r
+ InputContext->EP[Dci-1].CErr = 0;\r
+ InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
+ }\r
+ break;\r
+ case USB_ENDPOINT_INTERRUPT:\r
+ if (Direction == EfiUsbDataIn) {\r
+ InputContext->EP[Dci-1].CErr = 3;\r
+ InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
+ } else {\r
+ InputContext->EP[Dci-1].CErr = 3;\r
+ InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
+ }\r
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
+ InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
+ //\r
+ // Get the bInterval from descriptor and init the the interval field of endpoint context\r
+ //\r
+ if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
+ Interval = EpDesc->Interval;\r
+ //\r
+ // Calculate through the bInterval field of Endpoint descriptor.\r
+ //\r
+ ASSERT (Interval != 0);\r
+ InputContext->EP[Dci-1].Interval = (UINT32) HighBitSet32( (UINT32) Interval) + 3;\r
+ } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
+ Interval = EpDesc->Interval;\r
+ ASSERT (Interval >= 1 && Interval <= 16);\r
+ //\r
+ // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
+ //\r
+ InputContext->EP[Dci-1].Interval = Interval - 1;\r
+ }\r
+\r
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
+ XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+ }\r
+ break;\r
+\r
+ case USB_ENDPOINT_CONTROL:\r
+ default:\r
+ ASSERT (0);\r
+ break;\r
+ }\r
+\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (\r
+ Xhc->MemPool,\r
+ ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
+ );\r
+\r
+ PhyAddr &= ~(0x0F);\r
+ PhyAddr |= ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
+\r
+ InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+ InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN)EpDesc + EpDesc->Length);\r
+ }\r
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN)IfDesc + IfDesc->Length);\r
+ }\r
+\r
+ InputContext->InputControlContext.Dword2 |= BIT0;\r
+ InputContext->Slot.ContextEntries = MaxDci;\r
+ //\r
+ // configure endpoint\r
+ //\r
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+ CmdTrbCfgEP.CycleBit = 1;\r
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
+ DEBUG ((EFI_D_INFO, "XhcSetConfigCmd64: Configure Endpoint\n"));\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be evaluated.\r
+ @param MaxPacketSize The max packet size supported by the device control transfer.\r
+\r
+ @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiEvaluateContext (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT32 MaxPacketSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
+ INPUT_CONTEXT *InputContext;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
+\r
+ //\r
+ // 4.6.7 Evaluate Context\r
+ //\r
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
+\r
+ InputContext->InputControlContext.Dword2 |= BIT1;\r
+ InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
+\r
+ ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
+ CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+ CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+ CmdTrbEvalu.CycleBit = 1;\r
+ CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
+ CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
+ DEBUG ((EFI_D_INFO, "XhcEvaluateContext: Evaluate context\n"));\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be evaluated.\r
+ @param MaxPacketSize The max packet size supported by the device control transfer.\r
+\r
+ @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiEvaluateContext64 (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT32 MaxPacketSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
+ INPUT_CONTEXT_64 *InputContext;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
+\r
+ //\r
+ // 4.6.7 Evaluate Context\r
+ //\r
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
+\r
+ InputContext->InputControlContext.Dword2 |= BIT1;\r
+ InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
+\r
+ ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
+ CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+ CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+ CmdTrbEvalu.CycleBit = 1;\r
+ CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
+ CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
+ DEBUG ((EFI_D_INFO, "XhcEvaluateContext64: Evaluate context 64\n"));\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be configured.\r
+ @param PortNum The total number of downstream port supported by the hub.\r
+ @param TTT The TT think time of the hub device.\r
+ @param MTT The multi-TT of the hub device.\r
+\r
+ @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiConfigHubContext (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT8 PortNum,\r
+ IN UINT8 TTT,\r
+ IN UINT8 MTT\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
+ INPUT_CONTEXT *InputContext;\r
+ DEVICE_CONTEXT *OutputContext;\r
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
+\r
+ //\r
+ // 4.6.7 Evaluate Context\r
+ //\r
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
+\r
+ InputContext->InputControlContext.Dword2 |= BIT0;\r
+\r
+ //\r
+ // Copy the slot context from OutputContext to Input context\r
+ //\r
+ CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));\r
+ InputContext->Slot.Hub = 1;\r
+ InputContext->Slot.PortNum = PortNum;\r
+ InputContext->Slot.TTT = TTT;\r
+ InputContext->Slot.MTT = MTT;\r
+\r
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+ CmdTrbCfgEP.CycleBit = 1;\r
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
+ DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be configured.\r
+ @param PortNum The total number of downstream port supported by the hub.\r
+ @param TTT The TT think time of the hub device.\r
+ @param MTT The multi-TT of the hub device.\r
+\r
+ @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiConfigHubContext64 (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT8 PortNum,\r
+ IN UINT8 TTT,\r
+ IN UINT8 MTT\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
+ INPUT_CONTEXT_64 *InputContext;\r
+ DEVICE_CONTEXT_64 *OutputContext;\r
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
+\r
+ //\r
+ // 4.6.7 Evaluate Context\r
+ //\r
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
+\r
+ InputContext->InputControlContext.Dword2 |= BIT0;\r
+\r
+ //\r
+ // Copy the slot context from OutputContext to Input context\r
+ //\r
+ CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));\r
+ InputContext->Slot.Hub = 1;\r
+ InputContext->Slot.PortNum = PortNum;\r
+ InputContext->Slot.TTT = TTT;\r
+ InputContext->Slot.MTT = MTT;\r
+\r
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+ CmdTrbCfgEP.CycleBit = 1;\r
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
+ DEBUG ((EFI_D_INFO, "Configure Hub Slot Context 64\n"));\r
+ Status = XhcPeiCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check if there is a new generated event.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param EvtRing The event ring to check.\r
+ @param NewEvtTrb The new event TRB found.\r
+\r
+ @retval EFI_SUCCESS Found a new event TRB at the event ring.\r
+ @retval EFI_NOT_READY The event ring has no new event.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiCheckNewEvent (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN EVENT_RING *EvtRing,\r
+ OUT TRB_TEMPLATE **NewEvtTrb\r
+ )\r
+{\r
+ ASSERT (EvtRing != NULL);\r
+\r
+ *NewEvtTrb = EvtRing->EventRingDequeue;\r
+\r
+ if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ EvtRing->EventRingDequeue++;\r
+ //\r
+ // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.\r
+ //\r
+ if ((UINTN) EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
+ EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param EvtRing The event ring to sync.\r
+\r
+ @retval EFI_SUCCESS The event ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSyncEventRing (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN EVENT_RING *EvtRing\r
+ )\r
+{\r
+ UINTN Index;\r
+ TRB_TEMPLATE *EvtTrb;\r
+\r
+ ASSERT (EvtRing != NULL);\r
+\r
+ //\r
+ // Calculate the EventRingEnqueue and EventRingCCS.\r
+ // Note: only support single Segment\r
+ //\r
+ EvtTrb = EvtRing->EventRingDequeue;\r
+\r
+ for (Index = 0; Index < EvtRing->TrbNumber; Index++) {\r
+ if (EvtTrb->CycleBit != EvtRing->EventRingCCS) {\r
+ break;\r
+ }\r
+\r
+ EvtTrb++;\r
+\r
+ if ((UINTN) EvtTrb >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
+ EvtTrb = EvtRing->EventRingSeg0;\r
+ EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;\r
+ }\r
+ }\r
+\r
+ if (Index < EvtRing->TrbNumber) {\r
+ EvtRing->EventRingEnqueue = EvtTrb;\r
+ } else {\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Free XHCI event ring.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param EventRing The event ring to be freed.\r
+\r
+**/\r
+VOID\r
+XhcPeiFreeEventRing (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN EVENT_RING *EventRing\r
+ )\r
+{\r
+ if(EventRing->EventRingSeg0 == NULL) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Free EventRing Segment 0\r
+ //\r
+ UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
+\r
+ //\r
+ // Free ERST table\r
+ //\r
+ UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
+}\r
+\r
+/**\r
+ Create XHCI event ring.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param EventRing The created event ring.\r
+\r
+**/\r
+VOID\r
+XhcPeiCreateEventRing (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ OUT EVENT_RING *EventRing\r
+ )\r
+{\r
+ VOID *Buf;\r
+ EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;\r
+ UINTN Size;\r
+ EFI_PHYSICAL_ADDRESS ERSTPhy;\r
+ EFI_PHYSICAL_ADDRESS DequeuePhy;\r
+\r
+ ASSERT (EventRing != NULL);\r
+\r
+ Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;\r
+ Buf = UsbHcAllocateMem (Xhc->MemPool, Size);\r
+ ASSERT (Buf != NULL);\r
+ ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+ ZeroMem (Buf, Size);\r
+\r
+ DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);\r
+\r
+ EventRing->EventRingSeg0 = Buf;\r
+ EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;\r
+ EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
+ EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
+\r
+ //\r
+ // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
+ // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
+ //\r
+ EventRing->EventRingCCS = 1;\r
+\r
+ Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;\r
+ Buf = UsbHcAllocateMem (Xhc->MemPool, Size);\r
+ ASSERT (Buf != NULL);\r
+ ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+ ZeroMem (Buf, Size);\r
+\r
+ ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;\r
+ EventRing->ERSTBase = ERSTBase;\r
+ ERSTBase->PtrLo = XHC_LOW_32BIT (DequeuePhy);\r
+ ERSTBase->PtrHi = XHC_HIGH_32BIT (DequeuePhy);\r
+ ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
+\r
+ ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);\r
+\r
+ //\r
+ // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)\r
+ //\r
+ XhcPeiWriteRuntimeReg (\r
+ Xhc,\r
+ XHC_ERSTSZ_OFFSET,\r
+ ERST_NUMBER\r
+ );\r
+ //\r
+ // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)\r
+ //\r
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+ // So divide it to two 32-bytes width register access.\r
+ //\r
+ XhcPeiWriteRuntimeReg (\r
+ Xhc,\r
+ XHC_ERDP_OFFSET,\r
+ XHC_LOW_32BIT ((UINT64) (UINTN) DequeuePhy)\r
+ );\r
+ XhcPeiWriteRuntimeReg (\r
+ Xhc,\r
+ XHC_ERDP_OFFSET + 4,\r
+ XHC_HIGH_32BIT ((UINT64) (UINTN) DequeuePhy)\r
+ );\r
+ //\r
+ // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)\r
+ //\r
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+ // So divide it to two 32-bytes width register access.\r
+ //\r
+ XhcPeiWriteRuntimeReg (\r
+ Xhc,\r
+ XHC_ERSTBA_OFFSET,\r
+ XHC_LOW_32BIT ((UINT64) (UINTN) ERSTPhy)\r
+ );\r
+ XhcPeiWriteRuntimeReg (\r
+ Xhc,\r
+ XHC_ERSTBA_OFFSET + 4,\r
+ XHC_HIGH_32BIT ((UINT64) (UINTN) ERSTPhy)\r
+ );\r
+ //\r
+ // Need set IMAN IE bit to enable the ring interrupt\r
+ //\r
+ XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);\r
+}\r
+\r
+/**\r
+ Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param TrsRing The transfer ring to sync.\r
+\r
+ @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSyncTrsRing (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN TRANSFER_RING *TrsRing\r
+ )\r
+{\r
+ UINTN Index;\r
+ TRB_TEMPLATE *TrsTrb;\r
+\r
+ ASSERT (TrsRing != NULL);\r
+ //\r
+ // Calculate the latest RingEnqueue and RingPCS\r
+ //\r
+ TrsTrb = TrsRing->RingEnqueue;\r
+ ASSERT (TrsTrb != NULL);\r
+\r
+ for (Index = 0; Index < TrsRing->TrbNumber; Index++) {\r
+ if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {\r
+ break;\r
+ }\r
+ TrsTrb++;\r
+ if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {\r
+ ASSERT (((LINK_TRB *) TrsTrb)->TC != 0);\r
+ //\r
+ // set cycle bit in Link TRB as normal\r
+ //\r
+ ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;\r
+ //\r
+ // Toggle PCS maintained by software\r
+ //\r
+ TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;\r
+ TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0; // Use host address\r
+ }\r
+ }\r
+\r
+ ASSERT (Index != TrsRing->TrbNumber);\r
+\r
+ if (TrsTrb != TrsRing->RingEnqueue) {\r
+ TrsRing->RingEnqueue = TrsTrb;\r
+ }\r
+\r
+ //\r
+ // Clear the Trb context for enqueue, but reserve the PCS bit\r
+ //\r
+ TrsTrb->Parameter1 = 0;\r
+ TrsTrb->Parameter2 = 0;\r
+ TrsTrb->Status = 0;\r
+ TrsTrb->RsvdZ1 = 0;\r
+ TrsTrb->Type = 0;\r
+ TrsTrb->Control = 0;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Create XHCI transfer ring.\r
+\r
+ @param Xhc The XHCI Device.\r
+ @param TrbNum The number of TRB in the ring.\r
+ @param TransferRing The created transfer ring.\r
+\r
+**/\r
+VOID\r
+XhcPeiCreateTransferRing (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINTN TrbNum,\r
+ OUT TRANSFER_RING *TransferRing\r
+ )\r
+{\r
+ VOID *Buf;\r
+ LINK_TRB *EndTrb;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);\r
+ ASSERT (Buf != NULL);\r
+ ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+ ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
+\r
+ TransferRing->RingSeg0 = Buf;\r
+ TransferRing->TrbNumber = TrbNum;\r
+ TransferRing->RingEnqueue = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
+ TransferRing->RingDequeue = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
+ TransferRing->RingPCS = 1;\r
+ //\r
+ // 4.9.2 Transfer Ring Management\r
+ // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
+ // point to the first TRB in the ring.\r
+ //\r
+ EndTrb = (LINK_TRB *) ((UINTN) Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));\r
+ EndTrb->Type = TRB_TYPE_LINK;\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
+ EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+ EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+ //\r
+ // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
+ //\r
+ EndTrb->TC = 1;\r
+ //\r
+ // Set Cycle bit as other TRB PCS init value\r
+ //\r
+ EndTrb->CycleBit = 0;\r
+}\r
+\r
+/**\r
+ Initialize the XHCI host controller for schedule.\r
+\r
+ @param Xhc The XHCI device to be initialized.\r
+\r
+**/\r
+VOID\r
+XhcPeiInitSched (\r
+ IN PEI_XHC_DEV *Xhc\r
+ )\r
+{\r
+ VOID *Dcbaa;\r
+ EFI_PHYSICAL_ADDRESS DcbaaPhy;\r
+ UINTN Size;\r
+ EFI_PHYSICAL_ADDRESS CmdRingPhy;\r
+ UINT32 MaxScratchpadBufs;\r
+ UINT64 *ScratchBuf;\r
+ EFI_PHYSICAL_ADDRESS ScratchPhy;\r
+ UINT64 *ScratchEntry;\r
+ EFI_PHYSICAL_ADDRESS ScratchEntryPhy;\r
+ UINT32 Index;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Initialize memory management.\r
+ //\r
+ Xhc->MemPool = UsbHcInitMemPool ();\r
+ ASSERT (Xhc->MemPool != NULL);\r
+\r
+ //\r
+ // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)\r
+ // to enable the device slots that system software is going to use.\r
+ //\r
+ Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;\r
+ ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);\r
+ XhcPeiWriteOpReg (Xhc, XHC_CONFIG_OFFSET, (XhcPeiReadOpReg (Xhc, XHC_CONFIG_OFFSET) & ~XHC_CONFIG_MASK) | Xhc->MaxSlotsEn);\r
+\r
+ //\r
+ // The Device Context Base Address Array entry associated with each allocated Device Slot\r
+ // shall contain a 64-bit pointer to the base of the associated Device Context.\r
+ // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.\r
+ // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.\r
+ //\r
+ Size = (Xhc->MaxSlotsEn + 1) * sizeof (UINT64);\r
+ Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Size);\r
+ ASSERT (Dcbaa != NULL);\r
+\r
+ //\r
+ // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.\r
+ // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run\r
+ // mode (Run/Stop(R/S) ='1').\r
+ //\r
+ MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);\r
+ Xhc->MaxScratchpadBufs = MaxScratchpadBufs;\r
+ ASSERT (MaxScratchpadBufs <= 1023);\r
+ if (MaxScratchpadBufs != 0) {\r
+ //\r
+ // Allocate the buffer to record the host address for each entry\r
+ //\r
+ ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);\r
+ ASSERT (ScratchEntry != NULL);\r
+ Xhc->ScratchEntry = ScratchEntry;\r
+\r
+ Status = UsbHcAllocateAlignedPages (\r
+ EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),\r
+ Xhc->PageSize,\r
+ (VOID **) &ScratchBuf,\r
+ &ScratchPhy\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));\r
+ Xhc->ScratchBuf = ScratchBuf;\r
+\r
+ //\r
+ // Allocate each scratch buffer\r
+ //\r
+ for (Index = 0; Index < MaxScratchpadBufs; Index++) {\r
+ Status = UsbHcAllocateAlignedPages (\r
+ EFI_SIZE_TO_PAGES (Xhc->PageSize),\r
+ Xhc->PageSize,\r
+ (VOID **) &ScratchEntry[Index],\r
+ &ScratchEntryPhy\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ ZeroMem ((VOID *) (UINTN) ScratchEntry[Index], Xhc->PageSize);\r
+ //\r
+ // Fill with the PCI device address\r
+ //\r
+ *ScratchBuf++ = ScratchEntryPhy;\r
+ }\r
+ //\r
+ // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the\r
+ // Device Context Base Address Array points to the Scratchpad Buffer Array.\r
+ //\r
+ *(UINT64 *) Dcbaa = (UINT64) (UINTN) ScratchPhy;\r
+ }\r
+\r
+ //\r
+ // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with\r
+ // a 64-bit address pointing to where the Device Context Base Address Array is located.\r
+ //\r
+ Xhc->DCBAA = (UINT64 *) (UINTN) Dcbaa;\r
+ //\r
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+ // So divide it to two 32-bytes width register access.\r
+ //\r
+ DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Size);\r
+ XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT (DcbaaPhy));\r
+ XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));\r
+\r
+ DEBUG ((EFI_D_INFO, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc->DCBAA));\r
+\r
+ //\r
+ // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register\r
+ // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.\r
+ // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall\r
+ // always be '0'.\r
+ //\r
+ XhcPeiCreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);\r
+ //\r
+ // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a\r
+ // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.\r
+ // So we set RCS as inverted PCS init value to let Command Ring empty\r
+ //\r
+ CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
+ ASSERT ((CmdRingPhy & 0x3F) == 0);\r
+ CmdRingPhy |= XHC_CRCR_RCS;\r
+ //\r
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+ // So divide it to two 32-bytes width register access.\r
+ //\r
+ XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT (CmdRingPhy));\r
+ XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));\r
+\r
+ DEBUG ((EFI_D_INFO, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));\r
+\r
+ //\r
+ // Disable the 'interrupter enable' bit in USB_CMD\r
+ // and clear IE & IP bit in all Interrupter X Management Registers.\r
+ //\r
+ XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);\r
+ for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {\r
+ XhcPeiClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);\r
+ XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);\r
+ }\r
+\r
+ //\r
+ // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer\r
+ //\r
+ XhcPeiCreateEventRing (Xhc, &Xhc->EventRing);\r
+ DEBUG ((EFI_D_INFO, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));\r
+}\r
+\r
+/**\r
+ Free the resouce allocated at initializing schedule.\r
+\r
+ @param Xhc The XHCI device.\r
+\r
+**/\r
+VOID\r
+XhcPeiFreeSched (\r
+ IN PEI_XHC_DEV *Xhc\r
+ )\r
+{\r
+ UINT32 Index;\r
+ UINT64 *ScratchEntry;\r
+\r
+ if (Xhc->ScratchBuf != NULL) {\r
+ ScratchEntry = Xhc->ScratchEntry;\r
+ for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {\r
+ //\r
+ // Free Scratchpad Buffers\r
+ //\r
+ UsbHcFreeAlignedPages ((VOID*) (UINTN) ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize));\r
+ }\r
+ //\r
+ // Free Scratchpad Buffer Array\r
+ //\r
+ UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)));\r
+ FreePool (Xhc->ScratchEntry);\r
+ }\r
+\r
+ if (Xhc->CmdRing.RingSeg0 != NULL) {\r
+ UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
+ Xhc->CmdRing.RingSeg0 = NULL;\r
+ }\r
+\r
+ XhcPeiFreeEventRing (Xhc,&Xhc->EventRing);\r
+\r
+ if (Xhc->DCBAA != NULL) {\r
+ UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof (UINT64));\r
+ Xhc->DCBAA = NULL;\r
+ }\r
+\r
+ //\r
+ // Free memory pool at last\r
+ //\r
+ if (Xhc->MemPool != NULL) {\r
+ UsbHcFreeMemPool (Xhc->MemPool);\r
+ Xhc->MemPool = NULL;\r
+ }\r
+}\r
+\r
--- /dev/null
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+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
+**/\r
+\r
+#ifndef _EFI_PEI_XHCI_SCHED_H_\r
+#define _EFI_PEI_XHCI_SCHED_H_\r
+\r
+//\r
+// Transfer types, used in URB to identify the transfer type\r
+//\r
+#define XHC_CTRL_TRANSFER 0x01\r
+#define XHC_BULK_TRANSFER 0x02\r
+\r
+//\r
+// 6.4.6 TRB Types\r
+//\r
+#define TRB_TYPE_NORMAL 1\r
+#define TRB_TYPE_SETUP_STAGE 2\r
+#define TRB_TYPE_DATA_STAGE 3\r
+#define TRB_TYPE_STATUS_STAGE 4\r
+#define TRB_TYPE_ISOCH 5\r
+#define TRB_TYPE_LINK 6\r
+#define TRB_TYPE_EVENT_DATA 7\r
+#define TRB_TYPE_NO_OP 8\r
+#define TRB_TYPE_EN_SLOT 9\r
+#define TRB_TYPE_DIS_SLOT 10\r
+#define TRB_TYPE_ADDRESS_DEV 11\r
+#define TRB_TYPE_CON_ENDPOINT 12\r
+#define TRB_TYPE_EVALU_CONTXT 13\r
+#define TRB_TYPE_RESET_ENDPOINT 14\r
+#define TRB_TYPE_STOP_ENDPOINT 15\r
+#define TRB_TYPE_SET_TR_DEQUE 16\r
+#define TRB_TYPE_RESET_DEV 17\r
+#define TRB_TYPE_GET_PORT_BANW 21\r
+#define TRB_TYPE_FORCE_HEADER 22\r
+#define TRB_TYPE_NO_OP_COMMAND 23\r
+#define TRB_TYPE_TRANS_EVENT 32\r
+#define TRB_TYPE_COMMAND_COMPLT_EVENT 33\r
+#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT 34\r
+#define TRB_TYPE_HOST_CONTROLLER_EVENT 37\r
+#define TRB_TYPE_DEVICE_NOTIFI_EVENT 38\r
+#define TRB_TYPE_MFINDEX_WRAP_EVENT 39\r
+\r
+//\r
+// Endpoint Type (EP Type).\r
+//\r
+#define ED_NOT_VALID 0\r
+#define ED_ISOCH_OUT 1\r
+#define ED_BULK_OUT 2\r
+#define ED_INTERRUPT_OUT 3\r
+#define ED_CONTROL_BIDIR 4\r
+#define ED_ISOCH_IN 5\r
+#define ED_BULK_IN 6\r
+#define ED_INTERRUPT_IN 7\r
+\r
+//\r
+// 6.4.5 TRB Completion Codes\r
+//\r
+#define TRB_COMPLETION_INVALID 0\r
+#define TRB_COMPLETION_SUCCESS 1\r
+#define TRB_COMPLETION_DATA_BUFFER_ERROR 2\r
+#define TRB_COMPLETION_BABBLE_ERROR 3\r
+#define TRB_COMPLETION_USB_TRANSACTION_ERROR 4\r
+#define TRB_COMPLETION_TRB_ERROR 5\r
+#define TRB_COMPLETION_STALL_ERROR 6\r
+#define TRB_COMPLETION_SHORT_PACKET 13\r
+\r
+//\r
+// The topology string used to present usb device location\r
+//\r
+typedef struct _USB_DEV_TOPOLOGY {\r
+ //\r
+ // The tier concatenation of down stream port.\r
+ //\r
+ UINT32 RouteString:20;\r
+ //\r
+ // The root port number of the chain.\r
+ //\r
+ UINT32 RootPortNum:8;\r
+ //\r
+ // The Tier the device reside.\r
+ //\r
+ UINT32 TierNum:4;\r
+} USB_DEV_TOPOLOGY;\r
+\r
+//\r
+// USB Device's RouteChart\r
+//\r
+typedef union _USB_DEV_ROUTE {\r
+ UINT32 Dword;\r
+ USB_DEV_TOPOLOGY Route;\r
+} USB_DEV_ROUTE;\r
+\r
+//\r
+// Endpoint address and its capabilities\r
+//\r
+typedef struct _USB_ENDPOINT {\r
+ //\r
+ // Store logical device address assigned by UsbBus\r
+ // It's because some XHCI host controllers may assign the same physcial device\r
+ // address for those devices inserted at different root port.\r
+ //\r
+ UINT8 BusAddr;\r
+ UINT8 DevAddr;\r
+ UINT8 EpAddr;\r
+ EFI_USB_DATA_DIRECTION Direction;\r
+ UINT8 DevSpeed;\r
+ UINTN MaxPacket;\r
+ UINTN Type;\r
+} USB_ENDPOINT;\r
+\r
+//\r
+// TRB Template\r
+//\r
+typedef struct _TRB_TEMPLATE {\r
+ UINT32 Parameter1;\r
+\r
+ UINT32 Parameter2;\r
+\r
+ UINT32 Status;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ1:9;\r
+ UINT32 Type:6;\r
+ UINT32 Control:16;\r
+} TRB_TEMPLATE;\r
+\r
+typedef struct _TRANSFER_RING {\r
+ VOID *RingSeg0;\r
+ UINTN TrbNumber;\r
+ TRB_TEMPLATE *RingEnqueue;\r
+ TRB_TEMPLATE *RingDequeue;\r
+ UINT32 RingPCS;\r
+} TRANSFER_RING;\r
+\r
+typedef struct _EVENT_RING {\r
+ VOID *ERSTBase;\r
+ VOID *EventRingSeg0;\r
+ UINTN TrbNumber;\r
+ TRB_TEMPLATE *EventRingEnqueue;\r
+ TRB_TEMPLATE *EventRingDequeue;\r
+ UINT32 EventRingCCS;\r
+} EVENT_RING;\r
+\r
+#define XHC_URB_SIG SIGNATURE_32 ('U', 'S', 'B', 'R')\r
+\r
+//\r
+// URB (Usb Request Block) contains information for all kinds of\r
+// usb requests.\r
+//\r
+typedef struct _URB {\r
+ UINT32 Signature;\r
+ //\r
+ // Usb Device URB related information\r
+ //\r
+ USB_ENDPOINT Ep;\r
+ EFI_USB_DEVICE_REQUEST *Request;\r
+ VOID *Data;\r
+ UINTN DataLen;\r
+ VOID *DataPhy;\r
+ EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;\r
+ VOID *Context;\r
+ //\r
+ // Execute result\r
+ //\r
+ UINT32 Result;\r
+ //\r
+ // completed data length\r
+ //\r
+ UINTN Completed;\r
+ //\r
+ // Command/Tranfer Ring info\r
+ //\r
+ TRANSFER_RING *Ring;\r
+ TRB_TEMPLATE *TrbStart;\r
+ TRB_TEMPLATE *TrbEnd;\r
+ UINTN TrbNum;\r
+ BOOLEAN StartDone;\r
+ BOOLEAN EndDone;\r
+ BOOLEAN Finished;\r
+\r
+ TRB_TEMPLATE *EvtTrb;\r
+} URB;\r
+\r
+//\r
+// 6.5 Event Ring Segment Table\r
+// The Event Ring Segment Table is used to define multi-segment Event Rings and to enable runtime\r
+// expansion and shrinking of the Event Ring. The location of the Event Ring Segment Table is defined by the\r
+// Event Ring Segment Table Base Address Register (5.5.2.3.2). The size of the Event Ring Segment Table\r
+// is defined by the Event Ring Segment Table Base Size Register (5.5.2.3.1).\r
+//\r
+typedef struct _EVENT_RING_SEG_TABLE_ENTRY {\r
+ UINT32 PtrLo;\r
+ UINT32 PtrHi;\r
+ UINT32 RingTrbSize:16;\r
+ UINT32 RsvdZ1:16;\r
+ UINT32 RsvdZ2;\r
+} EVENT_RING_SEG_TABLE_ENTRY;\r
+\r
+//\r
+// 6.4.1.1 Normal TRB\r
+// A Normal TRB is used in several ways; exclusively on Bulk and Interrupt Transfer Rings for normal and\r
+// Scatter/Gather operations, to define additional data buffers for Scatter/Gather operations on Isoch Transfer\r
+// Rings, and to define the Data stage information for Control Transfer Rings.\r
+//\r
+typedef struct _TRANSFER_TRB_NORMAL {\r
+ UINT32 TRBPtrLo;\r
+\r
+ UINT32 TRBPtrHi;\r
+\r
+ UINT32 Length:17;\r
+ UINT32 TDSize:5;\r
+ UINT32 IntTarget:10;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 ENT:1;\r
+ UINT32 ISP:1;\r
+ UINT32 NS:1;\r
+ UINT32 CH:1;\r
+ UINT32 IOC:1;\r
+ UINT32 IDT:1;\r
+ UINT32 RsvdZ1:2;\r
+ UINT32 BEI:1;\r
+ UINT32 Type:6;\r
+ UINT32 RsvdZ2:16;\r
+} TRANSFER_TRB_NORMAL;\r
+\r
+//\r
+// 6.4.1.2.1 Setup Stage TRB\r
+// A Setup Stage TRB is created by system software to initiate a USB Setup packet on a control endpoint.\r
+//\r
+typedef struct _TRANSFER_TRB_CONTROL_SETUP {\r
+ UINT32 bmRequestType:8;\r
+ UINT32 bRequest:8;\r
+ UINT32 wValue:16;\r
+\r
+ UINT32 wIndex:16;\r
+ UINT32 wLength:16;\r
+\r
+ UINT32 Length:17;\r
+ UINT32 RsvdZ1:5;\r
+ UINT32 IntTarget:10;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ2:4;\r
+ UINT32 IOC:1;\r
+ UINT32 IDT:1;\r
+ UINT32 RsvdZ3:3;\r
+ UINT32 Type:6;\r
+ UINT32 TRT:2;\r
+ UINT32 RsvdZ4:14;\r
+} TRANSFER_TRB_CONTROL_SETUP;\r
+\r
+//\r
+// 6.4.1.2.2 Data Stage TRB\r
+// A Data Stage TRB is used generate the Data stage transaction of a USB Control transfer.\r
+//\r
+typedef struct _TRANSFER_TRB_CONTROL_DATA {\r
+ UINT32 TRBPtrLo;\r
+\r
+ UINT32 TRBPtrHi;\r
+\r
+ UINT32 Length:17;\r
+ UINT32 TDSize:5;\r
+ UINT32 IntTarget:10;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 ENT:1;\r
+ UINT32 ISP:1;\r
+ UINT32 NS:1;\r
+ UINT32 CH:1;\r
+ UINT32 IOC:1;\r
+ UINT32 IDT:1;\r
+ UINT32 RsvdZ1:3;\r
+ UINT32 Type:6;\r
+ UINT32 DIR:1;\r
+ UINT32 RsvdZ2:15;\r
+} TRANSFER_TRB_CONTROL_DATA;\r
+\r
+//\r
+// 6.4.1.2.2 Data Stage TRB\r
+// A Data Stage TRB is used generate the Data stage transaction of a USB Control transfer.\r
+//\r
+typedef struct _TRANSFER_TRB_CONTROL_STATUS {\r
+ UINT32 RsvdZ1;\r
+ UINT32 RsvdZ2;\r
+\r
+ UINT32 RsvdZ3:22;\r
+ UINT32 IntTarget:10;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 ENT:1;\r
+ UINT32 RsvdZ4:2;\r
+ UINT32 CH:1;\r
+ UINT32 IOC:1;\r
+ UINT32 RsvdZ5:4;\r
+ UINT32 Type:6;\r
+ UINT32 DIR:1;\r
+ UINT32 RsvdZ6:15;\r
+} TRANSFER_TRB_CONTROL_STATUS;\r
+\r
+//\r
+// 6.4.2.1 Transfer Event TRB\r
+// A Transfer Event provides the completion status associated with a Transfer TRB. Refer to section 4.11.3.1\r
+// for more information on the use and operation of Transfer Events.\r
+//\r
+typedef struct _EVT_TRB_TRANSFER {\r
+ UINT32 TRBPtrLo;\r
+\r
+ UINT32 TRBPtrHi;\r
+\r
+ UINT32 Length:24;\r
+ UINT32 Completecode:8;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ1:1;\r
+ UINT32 ED:1;\r
+ UINT32 RsvdZ2:7;\r
+ UINT32 Type:6;\r
+ UINT32 EndpointId:5;\r
+ UINT32 RsvdZ3:3;\r
+ UINT32 SlotId:8;\r
+} EVT_TRB_TRANSFER;\r
+\r
+//\r
+// 6.4.2.2 Command Completion Event TRB\r
+// A Command Completion Event TRB shall be generated by the xHC when a command completes on the\r
+// Command Ring. Refer to section 4.11.4 for more information on the use of Command Completion Events.\r
+//\r
+typedef struct _EVT_TRB_COMMAND_COMPLETION {\r
+ UINT32 TRBPtrLo;\r
+\r
+ UINT32 TRBPtrHi;\r
+\r
+ UINT32 RsvdZ2:24;\r
+ UINT32 Completecode:8;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ3:9;\r
+ UINT32 Type:6;\r
+ UINT32 VFID:8;\r
+ UINT32 SlotId:8;\r
+} EVT_TRB_COMMAND_COMPLETION;\r
+\r
+typedef union _TRB {\r
+ TRB_TEMPLATE TrbTemplate;\r
+ TRANSFER_TRB_NORMAL TrbNormal;\r
+ TRANSFER_TRB_CONTROL_SETUP TrbCtrSetup;\r
+ TRANSFER_TRB_CONTROL_DATA TrbCtrData;\r
+ TRANSFER_TRB_CONTROL_STATUS TrbCtrStatus;\r
+} TRB;\r
+\r
+//\r
+// 6.4.3.1 No Op Command TRB\r
+// The No Op Command TRB provides a simple means for verifying the operation of the Command Ring\r
+// mechanisms offered by the xHCI.\r
+//\r
+typedef struct _CMD_TRB_NO_OP {\r
+ UINT32 RsvdZ0;\r
+ UINT32 RsvdZ1;\r
+ UINT32 RsvdZ2;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ3:9;\r
+ UINT32 Type:6;\r
+ UINT32 RsvdZ4:16;\r
+} CMD_TRB_NO_OP;\r
+\r
+//\r
+// 6.4.3.2 Enable Slot Command TRB\r
+// The Enable Slot Command TRB causes the xHC to select an available Device Slot and return the ID of the\r
+// selected slot to the host in a Command Completion Event.\r
+//\r
+typedef struct _CMD_TRB_ENABLE_SLOT {\r
+ UINT32 RsvdZ0;\r
+ UINT32 RsvdZ1;\r
+ UINT32 RsvdZ2;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ3:9;\r
+ UINT32 Type:6;\r
+ UINT32 RsvdZ4:16;\r
+} CMD_TRB_ENABLE_SLOT;\r
+\r
+//\r
+// 6.4.3.3 Disable Slot Command TRB\r
+// The Disable Slot Command TRB releases any bandwidth assigned to the disabled slot and frees any\r
+// internal xHC resources assigned to the slot.\r
+//\r
+typedef struct _CMD_TRB_DISABLE_SLOT {\r
+ UINT32 RsvdZ0;\r
+ UINT32 RsvdZ1;\r
+ UINT32 RsvdZ2;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ3:9;\r
+ UINT32 Type:6;\r
+ UINT32 RsvdZ4:8;\r
+ UINT32 SlotId:8;\r
+} CMD_TRB_DISABLE_SLOT;\r
+\r
+//\r
+// 6.4.3.4 Address Device Command TRB\r
+// The Address Device Command TRB transitions the selected Device Context from the Default to the\r
+// Addressed state and causes the xHC to select an address for the USB device in the Default State and\r
+// issue a SET_ADDRESS request to the USB device.\r
+//\r
+typedef struct _CMD_TRB_ADDRESS_DEVICE {\r
+ UINT32 PtrLo;\r
+\r
+ UINT32 PtrHi;\r
+\r
+ UINT32 RsvdZ1;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ2:8;\r
+ UINT32 BSR:1;\r
+ UINT32 Type:6;\r
+ UINT32 RsvdZ3:8;\r
+ UINT32 SlotId:8;\r
+} CMD_TRB_ADDRESS_DEVICE;\r
+\r
+//\r
+// 6.4.3.5 Configure Endpoint Command TRB\r
+// The Configure Endpoint Command TRB evaluates the bandwidth and resource requirements of the\r
+// endpoints selected by the command.\r
+//\r
+typedef struct _CMD_TRB_CONFIG_ENDPOINT {\r
+ UINT32 PtrLo;\r
+\r
+ UINT32 PtrHi;\r
+\r
+ UINT32 RsvdZ1;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ2:8;\r
+ UINT32 DC:1;\r
+ UINT32 Type:6;\r
+ UINT32 RsvdZ3:8;\r
+ UINT32 SlotId:8;\r
+} CMD_TRB_CONFIG_ENDPOINT;\r
+\r
+//\r
+// 6.4.3.6 Evaluate Context Command TRB\r
+// The Evaluate Context Command TRB is used by system software to inform the xHC that the selected\r
+// Context data structures in the Device Context have been modified by system software and that the xHC\r
+// shall evaluate any changes\r
+//\r
+typedef struct _CMD_TRB_EVALUATE_CONTEXT {\r
+ UINT32 PtrLo;\r
+\r
+ UINT32 PtrHi;\r
+\r
+ UINT32 RsvdZ1;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ2:9;\r
+ UINT32 Type:6;\r
+ UINT32 RsvdZ3:8;\r
+ UINT32 SlotId:8;\r
+} CMD_TRB_EVALUATE_CONTEXT;\r
+\r
+//\r
+// 6.4.3.7 Reset Endpoint Command TRB\r
+// The Reset Endpoint Command TRB is used by system software to reset a specified Transfer Ring\r
+//\r
+typedef struct _CMD_TRB_RESET_ENDPOINT {\r
+ UINT32 RsvdZ0;\r
+ UINT32 RsvdZ1;\r
+ UINT32 RsvdZ2;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ3:8;\r
+ UINT32 TSP:1;\r
+ UINT32 Type:6;\r
+ UINT32 EDID:5;\r
+ UINT32 RsvdZ4:3;\r
+ UINT32 SlotId:8;\r
+} CMD_TRB_RESET_ENDPOINT;\r
+\r
+//\r
+// 6.4.3.8 Stop Endpoint Command TRB\r
+// The Stop Endpoint Command TRB command allows software to stop the xHC execution of the TDs on a\r
+// Transfer Ring and temporarily take ownership of TDs that had previously been passed to the xHC.\r
+//\r
+typedef struct _CMD_TRB_STOP_ENDPOINT {\r
+ UINT32 RsvdZ0;\r
+ UINT32 RsvdZ1;\r
+ UINT32 RsvdZ2;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ3:9;\r
+ UINT32 Type:6;\r
+ UINT32 EDID:5;\r
+ UINT32 RsvdZ4:2;\r
+ UINT32 SP:1;\r
+ UINT32 SlotId:8;\r
+} CMD_TRB_STOP_ENDPOINT;\r
+\r
+//\r
+// 6.4.3.9 Set TR Dequeue Pointer Command TRB\r
+// The Set TR Dequeue Pointer Command TRB is used by system software to modify the TR Dequeue\r
+// Pointer and DCS fields of an Endpoint or Stream Context.\r
+//\r
+typedef struct _CMD_SET_TR_DEQ_POINTER {\r
+ UINT32 PtrLo;\r
+\r
+ UINT32 PtrHi;\r
+\r
+ UINT32 RsvdZ1:16;\r
+ UINT32 StreamID:16;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 RsvdZ2:9;\r
+ UINT32 Type:6;\r
+ UINT32 Endpoint:5;\r
+ UINT32 RsvdZ3:3;\r
+ UINT32 SlotId:8;\r
+} CMD_SET_TR_DEQ_POINTER;\r
+\r
+//\r
+// 6.4.4.1 Link TRB\r
+// A Link TRB provides support for non-contiguous TRB Rings.\r
+//\r
+typedef struct _LINK_TRB {\r
+ UINT32 PtrLo;\r
+\r
+ UINT32 PtrHi;\r
+\r
+ UINT32 RsvdZ1:22;\r
+ UINT32 InterTarget:10;\r
+\r
+ UINT32 CycleBit:1;\r
+ UINT32 TC:1;\r
+ UINT32 RsvdZ2:2;\r
+ UINT32 CH:1;\r
+ UINT32 IOC:1;\r
+ UINT32 RsvdZ3:4;\r
+ UINT32 Type:6;\r
+ UINT32 RsvdZ4:16;\r
+} LINK_TRB;\r
+\r
+//\r
+// 6.2.2 Slot Context\r
+//\r
+typedef struct _SLOT_CONTEXT {\r
+ UINT32 RouteString:20;\r
+ UINT32 Speed:4;\r
+ UINT32 RsvdZ1:1;\r
+ UINT32 MTT:1;\r
+ UINT32 Hub:1;\r
+ UINT32 ContextEntries:5;\r
+\r
+ UINT32 MaxExitLatency:16;\r
+ UINT32 RootHubPortNum:8;\r
+ UINT32 PortNum:8;\r
+\r
+ UINT32 TTHubSlotId:8;\r
+ UINT32 TTPortNum:8;\r
+ UINT32 TTT:2;\r
+ UINT32 RsvdZ2:4;\r
+ UINT32 InterTarget:10;\r
+\r
+ UINT32 DeviceAddress:8;\r
+ UINT32 RsvdZ3:19;\r
+ UINT32 SlotState:5;\r
+\r
+ UINT32 RsvdZ4;\r
+ UINT32 RsvdZ5;\r
+ UINT32 RsvdZ6;\r
+ UINT32 RsvdZ7;\r
+} SLOT_CONTEXT;\r
+\r
+typedef struct _SLOT_CONTEXT_64 {\r
+ UINT32 RouteString:20;\r
+ UINT32 Speed:4;\r
+ UINT32 RsvdZ1:1;\r
+ UINT32 MTT:1;\r
+ UINT32 Hub:1;\r
+ UINT32 ContextEntries:5;\r
+\r
+ UINT32 MaxExitLatency:16;\r
+ UINT32 RootHubPortNum:8;\r
+ UINT32 PortNum:8;\r
+\r
+ UINT32 TTHubSlotId:8;\r
+ UINT32 TTPortNum:8;\r
+ UINT32 TTT:2;\r
+ UINT32 RsvdZ2:4;\r
+ UINT32 InterTarget:10;\r
+\r
+ UINT32 DeviceAddress:8;\r
+ UINT32 RsvdZ3:19;\r
+ UINT32 SlotState:5;\r
+\r
+ UINT32 RsvdZ4;\r
+ UINT32 RsvdZ5;\r
+ UINT32 RsvdZ6;\r
+ UINT32 RsvdZ7;\r
+\r
+ UINT32 RsvdZ8;\r
+ UINT32 RsvdZ9;\r
+ UINT32 RsvdZ10;\r
+ UINT32 RsvdZ11;\r
+\r
+ UINT32 RsvdZ12;\r
+ UINT32 RsvdZ13;\r
+ UINT32 RsvdZ14;\r
+ UINT32 RsvdZ15;\r
+\r
+} SLOT_CONTEXT_64;\r
+\r
+\r
+//\r
+// 6.2.3 Endpoint Context\r
+//\r
+typedef struct _ENDPOINT_CONTEXT {\r
+ UINT32 EPState:3;\r
+ UINT32 RsvdZ1:5;\r
+ UINT32 Mult:2;\r
+ UINT32 MaxPStreams:5;\r
+ UINT32 LSA:1;\r
+ UINT32 Interval:8;\r
+ UINT32 RsvdZ2:8;\r
+\r
+ UINT32 RsvdZ3:1;\r
+ UINT32 CErr:2;\r
+ UINT32 EPType:3;\r
+ UINT32 RsvdZ4:1;\r
+ UINT32 HID:1;\r
+ UINT32 MaxBurstSize:8;\r
+ UINT32 MaxPacketSize:16;\r
+\r
+ UINT32 PtrLo;\r
+\r
+ UINT32 PtrHi;\r
+\r
+ UINT32 AverageTRBLength:16;\r
+ UINT32 MaxESITPayload:16;\r
+\r
+ UINT32 RsvdZ5;\r
+ UINT32 RsvdZ6;\r
+ UINT32 RsvdZ7;\r
+} ENDPOINT_CONTEXT;\r
+\r
+typedef struct _ENDPOINT_CONTEXT_64 {\r
+ UINT32 EPState:3;\r
+ UINT32 RsvdZ1:5;\r
+ UINT32 Mult:2;\r
+ UINT32 MaxPStreams:5;\r
+ UINT32 LSA:1;\r
+ UINT32 Interval:8;\r
+ UINT32 RsvdZ2:8;\r
+\r
+ UINT32 RsvdZ3:1;\r
+ UINT32 CErr:2;\r
+ UINT32 EPType:3;\r
+ UINT32 RsvdZ4:1;\r
+ UINT32 HID:1;\r
+ UINT32 MaxBurstSize:8;\r
+ UINT32 MaxPacketSize:16;\r
+\r
+ UINT32 PtrLo;\r
+\r
+ UINT32 PtrHi;\r
+\r
+ UINT32 AverageTRBLength:16;\r
+ UINT32 MaxESITPayload:16;\r
+\r
+ UINT32 RsvdZ5;\r
+ UINT32 RsvdZ6;\r
+ UINT32 RsvdZ7;\r
+\r
+ UINT32 RsvdZ8;\r
+ UINT32 RsvdZ9;\r
+ UINT32 RsvdZ10;\r
+ UINT32 RsvdZ11;\r
+\r
+ UINT32 RsvdZ12;\r
+ UINT32 RsvdZ13;\r
+ UINT32 RsvdZ14;\r
+ UINT32 RsvdZ15;\r
+\r
+} ENDPOINT_CONTEXT_64;\r
+\r
+\r
+//\r
+// 6.2.5.1 Input Control Context\r
+//\r
+typedef struct _INPUT_CONTRL_CONTEXT {\r
+ UINT32 Dword1;\r
+ UINT32 Dword2;\r
+ UINT32 RsvdZ1;\r
+ UINT32 RsvdZ2;\r
+ UINT32 RsvdZ3;\r
+ UINT32 RsvdZ4;\r
+ UINT32 RsvdZ5;\r
+ UINT32 RsvdZ6;\r
+} INPUT_CONTRL_CONTEXT;\r
+\r
+typedef struct _INPUT_CONTRL_CONTEXT_64 {\r
+ UINT32 Dword1;\r
+ UINT32 Dword2;\r
+ UINT32 RsvdZ1;\r
+ UINT32 RsvdZ2;\r
+ UINT32 RsvdZ3;\r
+ UINT32 RsvdZ4;\r
+ UINT32 RsvdZ5;\r
+ UINT32 RsvdZ6;\r
+ UINT32 RsvdZ7;\r
+ UINT32 RsvdZ8;\r
+ UINT32 RsvdZ9;\r
+ UINT32 RsvdZ10;\r
+ UINT32 RsvdZ11;\r
+ UINT32 RsvdZ12;\r
+ UINT32 RsvdZ13;\r
+ UINT32 RsvdZ14;\r
+} INPUT_CONTRL_CONTEXT_64;\r
+\r
+//\r
+// 6.2.1 Device Context\r
+//\r
+typedef struct _DEVICE_CONTEXT {\r
+ SLOT_CONTEXT Slot;\r
+ ENDPOINT_CONTEXT EP[31];\r
+} DEVICE_CONTEXT;\r
+\r
+typedef struct _DEVICE_CONTEXT_64 {\r
+ SLOT_CONTEXT_64 Slot;\r
+ ENDPOINT_CONTEXT_64 EP[31];\r
+} DEVICE_CONTEXT_64;\r
+\r
+//\r
+// 6.2.5 Input Context\r
+//\r
+typedef struct _INPUT_CONTEXT {\r
+ INPUT_CONTRL_CONTEXT InputControlContext;\r
+ SLOT_CONTEXT Slot;\r
+ ENDPOINT_CONTEXT EP[31];\r
+} INPUT_CONTEXT;\r
+\r
+typedef struct _INPUT_CONTEXT_64 {\r
+ INPUT_CONTRL_CONTEXT_64 InputControlContext;\r
+ SLOT_CONTEXT_64 Slot;\r
+ ENDPOINT_CONTEXT_64 EP[31];\r
+} INPUT_CONTEXT_64;\r
+\r
+/**\r
+ Execute the transfer by polling the URB. This is a synchronous operation.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param CmdTransfer The executed URB is for cmd transfer or not.\r
+ @param Urb The URB to execute.\r
+ @param Timeout The time to wait before abort, in millisecond.\r
+\r
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
+ @return EFI_TIMEOUT The transfer failed due to time out.\r
+ @return EFI_SUCCESS The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiExecTransfer (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN BOOLEAN CmdTransfer,\r
+ IN URB *Urb,\r
+ IN UINTN Timeout\r
+ );\r
+\r
+/**\r
+ Find out the actual device address according to the requested device address from UsbBus.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param BusDevAddr The requested device address by UsbBus upper driver.\r
+\r
+ @return The actual device address assigned to the device.\r
+\r
+**/\r
+UINT8\r
+XhcPeiBusDevAddrToSlotId (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 BusDevAddr\r
+ );\r
+\r
+/**\r
+ Find out the slot id according to the device's route string.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param RouteString The route string described the device location.\r
+\r
+ @return The slot id used by the device.\r
+\r
+**/\r
+UINT8\r
+XhcPeiRouteStringToSlotId (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN USB_DEV_ROUTE RouteString\r
+ );\r
+\r
+/**\r
+ Calculate the device context index by endpoint address and direction.\r
+\r
+ @param EpAddr The target endpoint number.\r
+ @param Direction The direction of the target endpoint.\r
+\r
+ @return The device context index of endpoint.\r
+\r
+**/\r
+UINT8\r
+XhcPeiEndpointToDci (\r
+ IN UINT8 EpAddr,\r
+ IN EFI_USB_DATA_DIRECTION Direction\r
+ );\r
+\r
+/**\r
+ Ring the door bell to notify XHCI there is a transaction to be executed.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id of the target device.\r
+ @param Dci The device context index of the target slot or endpoint.\r
+\r
+**/\r
+VOID\r
+XhcPeiRingDoorBell (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT8 Dci\r
+ );\r
+\r
+/**\r
+ Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param ParentRouteChart The route string pointed to the parent device if it exists.\r
+ @param Port The port to be polled.\r
+ @param PortState The port state.\r
+\r
+ @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.\r
+ @retval Others Should not appear.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiPollPortStatusChange (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN USB_DEV_ROUTE ParentRouteChart,\r
+ IN UINT8 Port,\r
+ IN EFI_USB_PORT_STATUS *PortState\r
+ );\r
+\r
+/**\r
+ Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be configured.\r
+ @param PortNum The total number of downstream port supported by the hub.\r
+ @param TTT The TT think time of the hub device.\r
+ @param MTT The multi-TT of the hub device.\r
+\r
+ @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiConfigHubContext (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT8 PortNum,\r
+ IN UINT8 TTT,\r
+ IN UINT8 MTT\r
+ );\r
+\r
+/**\r
+ Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be configured.\r
+ @param PortNum The total number of downstream port supported by the hub.\r
+ @param TTT The TT think time of the hub device.\r
+ @param MTT The multi-TT of the hub device.\r
+\r
+ @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiConfigHubContext64 (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT8 PortNum,\r
+ IN UINT8 TTT,\r
+ IN UINT8 MTT\r
+ );\r
+\r
+/**\r
+ Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be configured.\r
+ @param DeviceSpeed The device's speed.\r
+ @param ConfigDesc The pointer to the usb device configuration descriptor.\r
+\r
+ @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSetConfigCmd (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT8 DeviceSpeed,\r
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
+ );\r
+\r
+/**\r
+ Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be configured.\r
+ @param DeviceSpeed The device's speed.\r
+ @param ConfigDesc The pointer to the usb device configuration descriptor.\r
+\r
+ @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSetConfigCmd64 (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT8 DeviceSpeed,\r
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
+ );\r
+\r
+/**\r
+ Assign and initialize the device slot for a new device.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param ParentRouteChart The route string pointed to the parent device.\r
+ @param ParentPort The port at which the device is located.\r
+ @param RouteChart The route string pointed to the device.\r
+ @param DeviceSpeed The device speed.\r
+\r
+ @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
+ @retval Others Fail to initialize device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiInitializeDeviceSlot (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN USB_DEV_ROUTE ParentRouteChart,\r
+ IN UINT16 ParentPort,\r
+ IN USB_DEV_ROUTE RouteChart,\r
+ IN UINT8 DeviceSpeed\r
+ );\r
+\r
+/**\r
+ Assign and initialize the device slot for a new device.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param ParentRouteChart The route string pointed to the parent device.\r
+ @param ParentPort The port at which the device is located.\r
+ @param RouteChart The route string pointed to the device.\r
+ @param DeviceSpeed The device speed.\r
+\r
+ @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
+ @retval Others Fail to initialize device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiInitializeDeviceSlot64 (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN USB_DEV_ROUTE ParentRouteChart,\r
+ IN UINT16 ParentPort,\r
+ IN USB_DEV_ROUTE RouteChart,\r
+ IN UINT8 DeviceSpeed\r
+ );\r
+\r
+/**\r
+ Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be evaluated.\r
+ @param MaxPacketSize The max packet size supported by the device control transfer.\r
+\r
+ @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiEvaluateContext (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT32 MaxPacketSize\r
+ );\r
+\r
+/**\r
+ Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be evaluated.\r
+ @param MaxPacketSize The max packet size supported by the device control transfer.\r
+\r
+ @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiEvaluateContext64 (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT32 MaxPacketSize\r
+ );\r
+\r
+/**\r
+ Disable the specified device slot.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be disabled.\r
+\r
+ @retval EFI_SUCCESS Successfully disable the device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiDisableSlotCmd (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId\r
+ );\r
+\r
+/**\r
+ Disable the specified device slot.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param SlotId The slot id to be disabled.\r
+\r
+ @retval EFI_SUCCESS Successfully disable the device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiDisableSlotCmd64 (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 SlotId\r
+ );\r
+\r
+/**\r
+ System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
+ condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
+ Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
+ reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
+ Stopped to the Running state.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Urb The urb which makes the endpoint halted.\r
+\r
+ @retval EFI_SUCCESS The recovery is successful.\r
+ @retval Others Failed to recovery halted endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiRecoverHaltedEndpoint (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN URB *Urb\r
+ );\r
+\r
+/**\r
+ Create a new URB for a new transaction.\r
+\r
+ @param Xhc The XHCI device\r
+ @param DevAddr The device address\r
+ @param EpAddr Endpoint addrress\r
+ @param DevSpeed The device speed\r
+ @param MaxPacket The max packet length of the endpoint\r
+ @param Type The transaction type\r
+ @param Request The standard USB request for control transfer\r
+ @param Data The user data to transfer\r
+ @param DataLen The length of data buffer\r
+ @param Callback The function to call when data is transferred\r
+ @param Context The context to the callback\r
+\r
+ @return Created URB or NULL\r
+\r
+**/\r
+URB*\r
+XhcPeiCreateUrb (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 EpAddr,\r
+ IN UINT8 DevSpeed,\r
+ IN UINTN MaxPacket,\r
+ IN UINTN Type,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN VOID *Data,\r
+ IN UINTN DataLen,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
+ IN VOID *Context\r
+ );\r
+\r
+/**\r
+ Free an allocated URB.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param Urb The URB to free.\r
+\r
+**/\r
+VOID\r
+XhcPeiFreeUrb (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN URB *Urb\r
+ );\r
+\r
+/**\r
+ Create a transfer TRB.\r
+\r
+ @param Xhc The XHCI device\r
+ @param Urb The urb used to construct the transfer TRB.\r
+\r
+ @return Created TRB or NULL\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiCreateTransferTrb (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN URB *Urb\r
+ );\r
+\r
+/**\r
+ Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param TrsRing The transfer ring to sync.\r
+\r
+ @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSyncTrsRing (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN TRANSFER_RING *TrsRing\r
+ );\r
+\r
+/**\r
+ Create XHCI transfer ring.\r
+\r
+ @param Xhc The XHCI Device.\r
+ @param TrbNum The number of TRB in the ring.\r
+ @param TransferRing The created transfer ring.\r
+\r
+**/\r
+VOID\r
+XhcPeiCreateTransferRing (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN UINTN TrbNum,\r
+ OUT TRANSFER_RING *TransferRing\r
+ );\r
+\r
+/**\r
+ Check if there is a new generated event.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param EvtRing The event ring to check.\r
+ @param NewEvtTrb The new event TRB found.\r
+\r
+ @retval EFI_SUCCESS Found a new event TRB at the event ring.\r
+ @retval EFI_NOT_READY The event ring has no new event.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiCheckNewEvent (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN EVENT_RING *EvtRing,\r
+ OUT TRB_TEMPLATE **NewEvtTrb\r
+ );\r
+\r
+/**\r
+ Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param EvtRing The event ring to sync.\r
+\r
+ @retval EFI_SUCCESS The event ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSyncEventRing (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ IN EVENT_RING *EvtRing\r
+ );\r
+\r
+/**\r
+ Create XHCI event ring.\r
+\r
+ @param Xhc The XHCI device.\r
+ @param EventRing The created event ring.\r
+\r
+**/\r
+VOID\r
+XhcPeiCreateEventRing (\r
+ IN PEI_XHC_DEV *Xhc,\r
+ OUT EVENT_RING *EventRing\r
+ );\r
+\r
+/**\r
+ Initialize the XHCI host controller for schedule.\r
+\r
+ @param Xhc The XHCI device to be initialized.\r
+\r
+**/\r
+VOID\r
+XhcPeiInitSched (\r
+ IN PEI_XHC_DEV *Xhc\r
+ );\r
+\r
+/**\r
+ Free the resouce allocated at initializing schedule.\r
+\r
+ @param Xhc The XHCI device.\r
+\r
+**/\r
+VOID\r
+XhcPeiFreeSched (\r
+ IN PEI_XHC_DEV *Xhc\r
+ );\r
+\r
+#endif\r
/** @file\r
Usb Hub Request Support In PEI Phase\r
\r
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions\r
);\r
}\r
\r
+/**\r
+ Get a given SuperSpeed hub descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param HubDescriptor Caller allocated buffer to store the hub descriptor if\r
+ successfully returned.\r
+\r
+ @retval EFI_SUCCESS Hub descriptor is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiGetSuperSpeedHubDesc (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DevReq.RequestType = USB_RT_HUB | 0x80;\r
+ DevReq.Request = USB_HUB_GET_DESCRIPTOR;\r
+ DevReq.Value = USB_DT_SUPERSPEED_HUB << 8;\r
+ DevReq.Length = 12;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbDataIn,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ HubDescriptor,\r
+ 12\r
+ );\r
+}\r
+\r
+/**\r
+ Read the whole usb hub descriptor. It is necessary\r
+ to do it in two steps because hub descriptor is of\r
+ variable length.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param PeiUsbDevice Indicates the hub controller device.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param HubDescriptor Caller allocated buffer to store the hub descriptor if\r
+ successfully returned.\r
+\r
+ @retval EFI_SUCCESS Hub descriptor is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbHubReadDesc (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+ //\r
+ // Get the super speed hub descriptor\r
+ //\r
+ Status = PeiGetSuperSpeedHubDesc (PeiServices, UsbIoPpi, HubDescriptor);\r
+ } else {\r
+\r
+ //\r
+ // First get the hub descriptor length\r
+ //\r
+ Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, 2, HubDescriptor);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get the whole hub descriptor\r
+ //\r
+ Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, HubDescriptor->Length, HubDescriptor);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ USB hub control transfer to set the hub depth.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param PeiUsbDevice Indicates the hub controller device.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+\r
+ @retval EFI_SUCCESS Depth of the hub is set.\r
+ @retval Others Failed to set the depth.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbHubCtrlSetHubDepth (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DevReq.RequestType = USB_RT_HUB;\r
+ DevReq.Request = USB_HUB_REQ_SET_DEPTH;\r
+ DevReq.Value = PeiUsbDevice->Tier;\r
+ DevReq.Length = 0;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
/**\r
Configure a given hub.\r
\r
EFI_STATUS Status;\r
EFI_USB_HUB_STATUS HubStatus;\r
UINTN Index;\r
- UINT32 PortStatus;\r
PEI_USB_IO_PPI *UsbIoPpi;\r
\r
ZeroMem (&HubDescriptor, sizeof (HubDescriptor));\r
UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
\r
//\r
- // First get the hub descriptor length\r
- //\r
- Status = PeiGetHubDescriptor (\r
- PeiServices,\r
- UsbIoPpi,\r
- 2,\r
- &HubDescriptor\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
- //\r
- // First get the whole descriptor, then\r
- // get the number of hub ports\r
+ // Get the hub descriptor \r
//\r
- Status = PeiGetHubDescriptor (\r
+ Status = PeiUsbHubReadDesc (\r
PeiServices,\r
+ PeiUsbDevice,\r
UsbIoPpi,\r
- HubDescriptor.Length,\r
&HubDescriptor\r
);\r
if (EFI_ERROR (Status)) {\r
\r
PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts;\r
\r
- Status = PeiHubGetHubStatus (\r
- PeiServices,\r
- UsbIoPpi,\r
- (UINT32 *) &HubStatus\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
- //\r
- // Get all hub ports status\r
- //\r
- for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
-\r
- Status = PeiHubGetPortStatus (\r
- PeiServices,\r
- UsbIoPpi,\r
- (UINT8) (Index + 1),\r
- &PortStatus\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
- }\r
- //\r
- // Power all the hub ports\r
- //\r
- for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
- Status = PeiHubSetPortFeature (\r
- PeiServices,\r
- UsbIoPpi,\r
- (UINT8) (Index + 1),\r
- EfiUsbPortPower\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
- }\r
- //\r
- // Clear Hub Status Change\r
- //\r
- Status = PeiHubGetHubStatus (\r
- PeiServices,\r
- UsbIoPpi,\r
- (UINT32 *) &HubStatus\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
+ if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+ DEBUG ((EFI_D_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier));\r
+ PeiUsbHubCtrlSetHubDepth (\r
+ PeiServices,\r
+ PeiUsbDevice,\r
+ UsbIoPpi\r
+ );\r
} else {\r
//\r
- // Hub power supply change happens\r
+ // Power all the hub ports\r
//\r
- if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {\r
- PeiHubClearHubFeature (\r
- PeiServices,\r
- UsbIoPpi,\r
- C_HUB_LOCAL_POWER\r
- );\r
+ for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
+ Status = PeiHubSetPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ EfiUsbPortPower\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG (( EFI_D_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index));\r
+ continue;\r
+ }\r
}\r
+\r
+ DEBUG (( EFI_D_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor.PwrOn2PwrGood));\r
+ if (HubDescriptor.PwrOn2PwrGood > 0) {\r
+ MicroSecondDelay (HubDescriptor.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);\r
+ }\r
+\r
//\r
- // Hub change overcurrent happens\r
+ // Clear Hub Status Change\r
//\r
- if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {\r
- PeiHubClearHubFeature (\r
- PeiServices,\r
- UsbIoPpi,\r
- C_HUB_OVER_CURRENT\r
- );\r
+ Status = PeiHubGetHubStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT32 *) &HubStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ } else {\r
+ //\r
+ // Hub power supply change happens\r
+ //\r
+ if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {\r
+ PeiHubClearHubFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ C_HUB_LOCAL_POWER\r
+ );\r
+ }\r
+ //\r
+ // Hub change overcurrent happens\r
+ //\r
+ if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {\r
+ PeiHubClearHubFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ C_HUB_OVER_CURRENT\r
+ );\r
+ }\r
}\r
}\r
\r
IN UINT8 PortNum\r
)\r
{\r
- UINT8 Try;\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
EFI_USB_PORT_STATUS HubPortStatus;\r
\r
-\r
MicroSecondDelay (100 * 1000);\r
\r
//\r
EfiUsbPortReset\r
);\r
\r
- Try = 10;\r
- do {\r
- PeiHubGetPortStatus (\r
- PeiServices,\r
- UsbIoPpi,\r
- PortNum,\r
- (UINT32 *) &HubPortStatus\r
- );\r
+ //\r
+ // Drive the reset signal for worst 20ms. Check USB 2.0 Spec\r
+ // section 7.1.7.5 for timing requirements.\r
+ //\r
+ MicroSecondDelay (USB_SET_PORT_RESET_STALL);\r
\r
- MicroSecondDelay (2 * 1000);\r
- Try -= 1;\r
- } while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Try > 0);\r
+ //\r
+ // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.\r
+ //\r
+ ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS));\r
+\r
+ for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
+ Status = PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ (UINT32 *) &HubPortStatus\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) {\r
+ break;\r
+ }\r
+\r
+ MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);\r
+ }\r
+\r
+ if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {\r
+ DEBUG ((EFI_D_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum));\r
+ return;\r
+ }\r
\r
//\r
- // clear reset root port\r
+ // clear reset change root port\r
//\r
PeiHubClearPortFeature (\r
PeiServices,\r
UsbIoPpi,\r
PortNum,\r
- EfiUsbPortReset\r
+ EfiUsbPortResetChange\r
);\r
\r
MicroSecondDelay (1 * 1000);\r
/** @file\r
Constants definitions for Usb Hub Peim\r
\r
-Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions\r
#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE)\r
#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)\r
\r
+#define USB_HUB_REQ_SET_DEPTH 12\r
+\r
#define MAXBYTES 8\r
#pragma pack(1)\r
//\r
}\r
\r
/**\r
- Judge if the port is connected with a low-speed usb device or not.\r
+ Get device speed according to port status.\r
\r
- @param PortStatus The usb port status gotten.\r
+ @param PortStatus The usb port status gotten.\r
\r
- @retval TRUE A low-speed usb device is connected with the port.\r
- @retval FALSE No low-speed usb device is connected with the port.\r
+ @return Device speed value.\r
\r
**/\r
UINTN\r
-IsPortLowSpeedDeviceAttached (\r
- IN UINT16 PortStatus\r
+PeiUsbGetDeviceSpeed (\r
+ IN UINT16 PortStatus\r
)\r
{\r
- //\r
- // return the bit 9 value of PortStatus\r
- //\r
if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
return EFI_USB_SPEED_LOW;\r
} else if ((PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0){\r
return EFI_USB_SPEED_HIGH;\r
+ } else if ((PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
+ return EFI_USB_SPEED_SUPER;\r
} else {\r
return EFI_USB_SPEED_FULL;\r
}\r
#define USB_DT_INTERFACE 0x04\r
#define USB_DT_ENDPOINT 0x05\r
#define USB_DT_HUB 0x29\r
+#define USB_DT_SUPERSPEED_HUB 0x2A\r
#define USB_DT_HID 0x21\r
\r
//\r
);\r
\r
/**\r
- Judge if the port is connected with a low-speed usb device or not.\r
+ Get device speed according to port status.\r
\r
- @param PortStatus The usb port status gotten.\r
+ @param PortStatus The usb port status gotten.\r
\r
- @retval TRUE A low-speed usb device is connected with the port.\r
- @retval FALSE No low-speed usb device is connected with the port.\r
+ @return Device speed value.\r
\r
**/\r
UINTN\r
-IsPortLowSpeedDeviceAttached (\r
- IN UINT16 PortStatus\r
+PeiUsbGetDeviceSpeed (\r
+ IN UINT16 PortStatus\r
);\r
\r
/**\r
PeiUsbDev->UsbHcPpi,\r
PeiUsbDev->DeviceAddress,\r
PeiUsbDev->DeviceSpeed,\r
- PeiUsbDev->MaxPacketSize0,\r
+ (UINT8) PeiUsbDev->MaxPacketSize0,\r
Request,\r
Direction,\r
Data,\r
}\r
}\r
\r
+ DEBUG ((EFI_D_INFO, "PeiUsbControlTransfer: %r\n", Status));\r
return Status;\r
}\r
\r
PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));\r
}\r
\r
+ DEBUG ((EFI_D_INFO, "PeiUsbBulkTransfer: %r\n", Status));\r
return Status;\r
}\r
\r
\r
UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
\r
+ DEBUG ((EFI_D_INFO, "PeiHubEnumeration: DownStreamPortNo: %x\n", PeiUsbDevice->DownStreamPortNo));\r
+\r
for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
\r
Status = PeiHubGetPortStatus (\r
continue;\r
}\r
\r
- if (IsPortConnectChange (PortStatus.PortChangeStatus)) {\r
- PeiHubClearPortFeature (\r
- PeiServices,\r
- UsbIoPpi,\r
- (UINT8) (Index + 1),\r
- EfiUsbPortConnectChange\r
- );\r
-\r
- MicroSecondDelay (100 * 1000);\r
-\r
+ DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));\r
+ //\r
+ // Only handle connection/enable/overcurrent/reset change.\r
+ //\r
+ if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
+ continue;\r
+ } else {\r
if (IsPortConnect (PortStatus.PortStatus)) {\r
-\r
- PeiHubGetPortStatus (\r
- PeiServices,\r
- UsbIoPpi,\r
- (UINT8) (Index + 1),\r
- (UINT32 *) &PortStatus\r
- );\r
-\r
//\r
// Begin to deal with the new device\r
//\r
NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;\r
NewPeiUsbDevice->UsbHcPpi = PeiUsbDevice->UsbHcPpi;\r
NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi;\r
+ NewPeiUsbDevice->Tier = (UINT8) (PeiUsbDevice->Tier + 1);\r
NewPeiUsbDevice->IsHub = 0x0;\r
NewPeiUsbDevice->DownStreamPortNo = 0x0;\r
\r
- PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));\r
+ if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) || \r
+ ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) {\r
+ //\r
+ // If the port already has reset change flag and is connected and enabled, skip the port reset logic. \r
+ //\r
+ PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));\r
+ \r
+ PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ (UINT32 *) &PortStatus\r
+ );\r
+ } else {\r
+ PeiHubClearPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ EfiUsbPortResetChange\r
+ );\r
+ }\r
\r
- PeiHubGetPortStatus (\r
- PeiServices,\r
- UsbIoPpi,\r
- (UINT8) (Index + 1),\r
- (UINT32 *) &PortStatus\r
- );\r
+ NewPeiUsbDevice->DeviceSpeed = (UINT8) PeiUsbGetDeviceSpeed (PortStatus.PortStatus);\r
+ DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));\r
\r
- NewPeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);\r
+ if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)){\r
+ NewPeiUsbDevice->MaxPacketSize0 = 512;\r
+ } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {\r
+ NewPeiUsbDevice->MaxPacketSize0 = 64;\r
+ } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {\r
+ NewPeiUsbDevice->MaxPacketSize0 = 8;\r
+ } else {\r
+ NewPeiUsbDevice->MaxPacketSize0 = 8;\r
+ }\r
\r
if(NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) {\r
if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
if (EFI_ERROR (Status)) {\r
continue;\r
}\r
+ DEBUG ((EFI_D_INFO, "PeiHubEnumeration: PeiConfigureUsbDevice Success\n"));\r
\r
Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);\r
\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: NumOfRootPort: %x\n", NumOfRootPort));\r
+\r
for (Index = 0; Index < NumOfRootPort; Index++) {\r
//\r
// First get root port status to detect changes happen\r
&PortStatus\r
);\r
}\r
- DEBUG ((EFI_D_INFO, "USB Status --- ConnectChange[%04x] Status[%04x]\n", PortStatus.PortChangeStatus, PortStatus.PortStatus));\r
- if (IsPortConnectChange (PortStatus.PortChangeStatus)) {\r
- //\r
- // Changes happen, first clear this change status\r
- //\r
- if (Usb2HcPpi != NULL) {\r
- Usb2HcPpi->ClearRootHubPortFeature (\r
- PeiServices,\r
- Usb2HcPpi,\r
- (UINT8) Index,\r
- EfiUsbPortConnectChange\r
- ); \r
- } else {\r
- UsbHcPpi->ClearRootHubPortFeature (\r
- PeiServices,\r
- UsbHcPpi,\r
- (UINT8) Index,\r
- EfiUsbPortConnectChange\r
- );\r
- }\r
- MicroSecondDelay (100 * 1000);\r
-\r
+ DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));\r
+ //\r
+ // Only handle connection/enable/overcurrent/reset change.\r
+ //\r
+ if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
+ continue;\r
+ } else {\r
if (IsPortConnect (PortStatus.PortStatus)) {\r
- if (Usb2HcPpi != NULL) {\r
- Usb2HcPpi->GetRootHubPortStatus (\r
- PeiServices,\r
- Usb2HcPpi,\r
- (UINT8) Index,\r
- &PortStatus\r
- );\r
- } else {\r
- UsbHcPpi->GetRootHubPortStatus (\r
- PeiServices,\r
- UsbHcPpi,\r
- (UINT8) Index,\r
- &PortStatus\r
- );\r
- }\r
-\r
- //\r
- // Connect change happen\r
- //\r
MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;\r
Status = PeiServicesAllocatePages (\r
EfiBootServicesCode,\r
PeiUsbDevice->IsHub = 0x0;\r
PeiUsbDevice->DownStreamPortNo = 0x0;\r
\r
- ResetRootPort (\r
- PeiServices,\r
- PeiUsbDevice->UsbHcPpi,\r
- PeiUsbDevice->Usb2HcPpi,\r
- Index,\r
- 0\r
- );\r
+ if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) || \r
+ ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) {\r
+ //\r
+ // If the port already has reset change flag and is connected and enabled, skip the port reset logic. \r
+ //\r
+ ResetRootPort (\r
+ PeiServices,\r
+ PeiUsbDevice->UsbHcPpi,\r
+ PeiUsbDevice->Usb2HcPpi,\r
+ Index,\r
+ 0\r
+ );\r
\r
- if (Usb2HcPpi != NULL) {\r
- Usb2HcPpi->GetRootHubPortStatus (\r
- PeiServices,\r
- Usb2HcPpi,\r
- (UINT8) Index,\r
- &PortStatus\r
- );\r
+ if (Usb2HcPpi != NULL) {\r
+ Usb2HcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ );\r
+ } else {\r
+ UsbHcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ );\r
+ }\r
} else {\r
- UsbHcPpi->GetRootHubPortStatus (\r
- PeiServices,\r
- UsbHcPpi,\r
- (UINT8) Index,\r
- &PortStatus\r
- );\r
+ if (Usb2HcPpi != NULL) {\r
+ Usb2HcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ (UINT8) Index,\r
+ EfiUsbPortResetChange\r
+ ); \r
+ } else {\r
+ UsbHcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ (UINT8) Index,\r
+ EfiUsbPortResetChange\r
+ );\r
+ }\r
}\r
\r
- PeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);\r
+ PeiUsbDevice->DeviceSpeed = (UINT8) PeiUsbGetDeviceSpeed (PortStatus.PortStatus);\r
DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));\r
\r
+ if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)){\r
+ PeiUsbDevice->MaxPacketSize0 = 512;\r
+ } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {\r
+ PeiUsbDevice->MaxPacketSize0 = 64;\r
+ } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {\r
+ PeiUsbDevice->MaxPacketSize0 = 8;\r
+ } else {\r
+ PeiUsbDevice->MaxPacketSize0 = 8;\r
+ }\r
+\r
//\r
// Configure that Usb Device\r
//\r
if (EFI_ERROR (Status)) {\r
continue;\r
}\r
- DEBUG ((EFI_D_INFO, "PeiConfigureUsbDevice Success\n"));\r
+ DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n"));\r
\r
Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);\r
\r
//\r
\r
for (Retry = 0; Retry < 3; Retry ++) {\r
-\r
- PeiUsbDevice->MaxPacketSize0 = 8;\r
-\r
Status = PeiUsbGetDescriptor (\r
PeiServices,\r
UsbIoPpi,\r
);\r
\r
if (!EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Sucess\n", Retry));\r
+ DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Success\n", Retry));\r
break;\r
}\r
}\r
\r
if (Retry == 3) {\r
- DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail\n", Retry));\r
+ DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail: %x %r\n", Retry, Status));\r
return Status;\r
}\r
\r
- PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;\r
+ if ((DeviceDescriptor.BcdUSB == 0x0300) && (DeviceDescriptor.MaxPacketSize0 == 9)) {\r
+ PeiUsbDevice->MaxPacketSize0 = 1 << 9;\r
+ } else {\r
+ PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;\r
+ }\r
\r
(*DeviceAddress) ++;\r
\r
);\r
\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed\n"));\r
+ DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed: %r\n", Status));\r
return Status;\r
}\r
\r
)\r
{\r
EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_USB_PORT_STATUS PortStatus;\r
\r
\r
if (Usb2HcPpi != NULL) {\r
return;\r
}\r
\r
- MicroSecondDelay (200 * 1000);\r
- \r
+ //\r
+ // Drive the reset signal for at least 50ms. Check USB 2.0 Spec\r
+ // section 7.1.7.5 for timing requirements.\r
+ //\r
+ MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);\r
+\r
//\r
// clear reset root port\r
//\r
DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));\r
return;\r
}\r
- \r
- MicroSecondDelay (1 * 1000);\r
- \r
+\r
+ MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);\r
+\r
+ //\r
+ // USB host controller won't clear the RESET bit until\r
+ // reset is actually finished.\r
+ //\r
+ ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));\r
+\r
+ for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
+ Status = Usb2HcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ PortNum,\r
+ &PortStatus\r
+ ); \r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {\r
+ break;\r
+ }\r
+\r
+ MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);\r
+ }\r
+\r
+ if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {\r
+ DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));\r
+ return;\r
+ }\r
+\r
+ Usb2HcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ PortNum,\r
+ EfiUsbPortResetChange\r
+ );\r
+\r
Usb2HcPpi->ClearRootHubPortFeature (\r
PeiServices,\r
Usb2HcPpi,\r
return;\r
}\r
\r
- MicroSecondDelay (200 * 1000);\r
+ //\r
+ // Drive the reset signal for at least 50ms. Check USB 2.0 Spec\r
+ // section 7.1.7.5 for timing requirements.\r
+ //\r
+ MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);\r
\r
//\r
// clear reset root port\r
return;\r
}\r
\r
- MicroSecondDelay (1 * 1000);\r
- \r
+ MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);\r
+\r
+ //\r
+ // USB host controller won't clear the RESET bit until\r
+ // reset is actually finished.\r
+ //\r
+ ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));\r
+\r
+ for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
+ Status = UsbHcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ PortNum,\r
+ &PortStatus\r
+ ); \r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {\r
+ break;\r
+ }\r
+\r
+ MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);\r
+ }\r
+\r
+ if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {\r
+ DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));\r
+ return;\r
+ }\r
+\r
+ UsbHcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ PortNum,\r
+ EfiUsbPortResetChange\r
+ );\r
+\r
UsbHcPpi->ClearRootHubPortFeature (\r
PeiServices,\r
UsbHcPpi,\r
\r
#include <IndustryStandard/Usb.h>\r
\r
-#define MAX_ROOT_PORT 2\r
#define MAX_INTERFACE 8\r
#define MAX_ENDPOINT 16\r
\r
-#define USB_SLOW_SPEED_DEVICE 0x01\r
-#define USB_FULL_SPEED_DEVICE 0x02\r
-\r
#define PEI_USB_DEVICE_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'D')\r
typedef struct {\r
UINTN Signature;\r
PEI_USB_IO_PPI UsbIoPpi;\r
EFI_PEI_PPI_DESCRIPTOR UsbIoPpiList;\r
+ UINT16 MaxPacketSize0;\r
+ UINT16 DataToggle;\r
UINT8 DeviceAddress;\r
- UINT8 MaxPacketSize0;\r
UINT8 DeviceSpeed;\r
UINT8 IsHub;\r
- UINT16 DataToggle;\r
UINT8 DownStreamPortNo;\r
- UINT8 Reserved; // Padding for IPF\r
UINTN AllocateAddress;\r
PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi;\r
PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi;\r
EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescList[MAX_INTERFACE];\r
EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc[MAX_ENDPOINT];\r
EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescList[MAX_INTERFACE][MAX_ENDPOINT];\r
- EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator; \r
+ EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator;\r
+ UINT8 Tier;\r
} PEI_USB_DEVICE;\r
\r
#define PEI_USB_DEVICE_FROM_THIS(a) CR (a, PEI_USB_DEVICE, UsbIoPpi, PEI_USB_DEVICE_SIGNATURE)\r
\r
+#define USB_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))\r
+\r
+#define USB_BUS_1_MILLISECOND 1000\r
+\r
+//\r
+// Wait for port reset, refers to specification\r
+// [USB20-7.1.7.5, it says 10ms for hub and 50ms for\r
+// root hub]\r
+//\r
+// According to USB2.0, Chapter 11.5.1.5 Resetting,\r
+// the worst case for TDRST is 20ms\r
+//\r
+#define USB_SET_PORT_RESET_STALL (20 * USB_BUS_1_MILLISECOND)\r
+#define USB_SET_ROOT_PORT_RESET_STALL (50 * USB_BUS_1_MILLISECOND)\r
+\r
+//\r
+// Wait for clear roothub port reset, set by experience\r
+//\r
+#define USB_CLR_ROOT_PORT_RESET_STALL (20 * USB_BUS_1_MILLISECOND)\r
+\r
+//\r
+// Wait for port statue reg change, set by experience\r
+//\r
+#define USB_WAIT_PORT_STS_CHANGE_STALL (100)\r
+\r
+//\r
+// Host software return timeout if port status doesn't change \r
+// after 500ms(LOOP * STALL = 5000 * 0.1ms), set by experience\r
+//\r
+#define USB_WAIT_PORT_STS_CHANGE_LOOP 5000\r
+\r
+//\r
+// Wait for hub port power-on, refers to specification\r
+// [USB20-11.23.2]\r
+//\r
+#define USB_SET_PORT_POWER_STALL (2 * USB_BUS_1_MILLISECOND)\r
\r
/**\r
Submits control transfer to a target USB device.\r
Define APIs to retrieve USB Host Controller Info such as controller type and \r
I/O Port Base Address.\r
\r
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions\r
///\r
#define PEI_EHCI_CONTROLLER 0x03\r
\r
+///\r
+/// This bit is used in the ControllerType return parameter of GetUsbController()\r
+/// to identify the USB Host Controller type as XHCI\r
+///\r
+#define PEI_XHCI_CONTROLLER 0x04\r
+\r
/**\r
Retrieve USB Host Controller Info such as controller type and I/O Base Address.\r
\r
MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf\r
MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf\r
MdeModulePkg/Bus/Pci/EhciPei/EhciPei.inf\r
+ MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf\r
MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPei.inf\r
MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf\r
MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf\r