MdeModulePkg/XhciPei: Support IoMmu.
authorJiewen Yao <jiewen.yao@intel.com>
Thu, 7 Sep 2017 08:06:27 +0000 (16:06 +0800)
committerJiewen Yao <jiewen.yao@intel.com>
Sat, 16 Sep 2017 01:18:16 +0000 (09:18 +0800)
Update XHCI driver to consume IOMMU_PPI to allocate DMA buffer.

If no IOMMU_PPI exists, this driver still calls PEI service
to allocate DMA buffer, with assumption that DRAM==DMA.

This is a compatible change.

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c
MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h
MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h
MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf
MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c
MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h

diff --git a/MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c b/MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c
new file mode 100644 (file)
index 0000000..6e2c1b5
--- /dev/null
@@ -0,0 +1,249 @@
+/** @file\r
+The DMA memory help function.\r
+\r
+Copyright (c) 2017, 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
+EDKII_IOMMU_PPI  *mIoMmu;\r
+\r
+/**\r
+  Provides the controller-specific addresses required to access system memory from a\r
+  DMA bus master.\r
+\r
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.\r
+  @param  HostAddress           The system memory address to map to the PCI controller.\r
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes\r
+                                that were mapped.\r
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to\r
+                                access the hosts HostAddress.\r
+  @param  Mapping               A resulting value to pass to Unmap().\r
+\r
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.\r
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.\r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuMap (\r
+  IN  EDKII_IOMMU_OPERATION Operation,\r
+  IN VOID                   *HostAddress,\r
+  IN  OUT UINTN             *NumberOfBytes,\r
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,\r
+  OUT VOID                  **Mapping\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT64      Attribute;\r
+\r
+  if (mIoMmu != NULL) {\r
+    Status = mIoMmu->Map (\r
+                       mIoMmu,\r
+                       Operation,\r
+                       HostAddress,\r
+                       NumberOfBytes,\r
+                       DeviceAddress,\r
+                       Mapping\r
+                       );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    switch (Operation) {\r
+    case EdkiiIoMmuOperationBusMasterRead:\r
+    case EdkiiIoMmuOperationBusMasterRead64:\r
+      Attribute = EDKII_IOMMU_ACCESS_READ;\r
+      break;\r
+    case EdkiiIoMmuOperationBusMasterWrite:\r
+    case EdkiiIoMmuOperationBusMasterWrite64:\r
+      Attribute = EDKII_IOMMU_ACCESS_WRITE;\r
+      break;\r
+    case EdkiiIoMmuOperationBusMasterCommonBuffer:\r
+    case EdkiiIoMmuOperationBusMasterCommonBuffer64:\r
+      Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;\r
+      break;\r
+    default:\r
+      ASSERT(FALSE);\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    Status = mIoMmu->SetAttribute (\r
+                       mIoMmu,\r
+                       *Mapping,\r
+                       Attribute\r
+                       );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
+    *Mapping = NULL;\r
+    Status = EFI_SUCCESS;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Completes the Map() operation and releases any corresponding resources.\r
+\r
+  @param  Mapping               The mapping value returned from Map().\r
+\r
+  @retval EFI_SUCCESS           The range was unmapped.\r
+  @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.\r
+**/\r
+EFI_STATUS\r
+IoMmuUnmap (\r
+  IN VOID                  *Mapping\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if (mIoMmu != NULL) {\r
+    Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);\r
+    Status = mIoMmu->Unmap (mIoMmu, Mapping);\r
+  } else {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+  OperationBusMasterCommonBuffer64 mapping.\r
+\r
+  @param  Pages                 The number of pages to allocate.\r
+  @param  HostAddress           A pointer to store the base system memory address of the\r
+                                allocated range.\r
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to\r
+                                access the hosts HostAddress.\r
+  @param  Mapping               A resulting value to pass to Unmap().\r
+\r
+  @retval EFI_SUCCESS           The requested memory pages were allocated.\r
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are\r
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuAllocateBuffer (\r
+  IN UINTN                  Pages,\r
+  OUT VOID                  **HostAddress,\r
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,\r
+  OUT VOID                  **Mapping\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINTN                 NumberOfBytes;\r
+  EFI_PHYSICAL_ADDRESS  HostPhyAddress;\r
+\r
+  *HostAddress = NULL;\r
+  *DeviceAddress = 0;\r
+\r
+  if (mIoMmu != NULL) {\r
+    Status = mIoMmu->AllocateBuffer (\r
+                       mIoMmu,\r
+                       EfiBootServicesData,\r
+                       Pages,\r
+                       HostAddress,\r
+                       0\r
+                       );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);\r
+    Status = mIoMmu->Map (\r
+                       mIoMmu,\r
+                       EdkiiIoMmuOperationBusMasterCommonBuffer,\r
+                       *HostAddress,\r
+                       &NumberOfBytes,\r
+                       DeviceAddress,\r
+                       Mapping\r
+                       );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    Status = mIoMmu->SetAttribute (\r
+                       mIoMmu,\r
+                       *Mapping,\r
+                       EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
+                       );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    Status = PeiServicesAllocatePages (\r
+               EfiBootServicesData,\r
+               Pages,\r
+               &HostPhyAddress\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    *HostAddress = (VOID *)(UINTN)HostPhyAddress;\r
+    *DeviceAddress = HostPhyAddress;\r
+    *Mapping = NULL;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Frees memory that was allocated with AllocateBuffer().\r
+\r
+  @param  Pages                 The number of pages to free.\r
+  @param  HostAddress           The base system memory address of the allocated range.\r
+  @param  Mapping               The mapping value returned from Map().\r
+\r
+  @retval EFI_SUCCESS           The requested memory pages were freed.\r
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
+                                was not allocated with AllocateBuffer().\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuFreeBuffer (\r
+  IN UINTN                  Pages,\r
+  IN VOID                   *HostAddress,\r
+  IN VOID                   *Mapping\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if (mIoMmu != NULL) {\r
+    Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);\r
+    Status = mIoMmu->Unmap (mIoMmu, Mapping);\r
+    Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress);\r
+  } else {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Initialize IOMMU.\r
+**/\r
+VOID\r
+IoMmuInit (\r
+  VOID\r
+  )\r
+{\r
+  PeiServicesLocatePpi (\r
+    &gEdkiiIoMmuPpiGuid,\r
+    0,\r
+    NULL,\r
+    (VOID **)&mIoMmu\r
+    );\r
+}\r
+\r
index 6a3f3a5..5d0232c 100644 (file)
@@ -31,6 +31,9 @@ UsbHcAllocMemBlock (
   )\r
 {\r
   USBHC_MEM_BLOCK       *Block;\r
+  VOID                  *BufHost;\r
+  VOID                  *Mapping;\r
+  EFI_PHYSICAL_ADDRESS  MappedAddr;\r
   EFI_STATUS            Status;\r
   UINTN                 PageNumber;\r
   EFI_PHYSICAL_ADDRESS  TempPtr;\r
@@ -71,18 +74,20 @@ UsbHcAllocMemBlock (
 \r
   Block->Bits = (UINT8 *) (UINTN) TempPtr;\r
 \r
-  Status = PeiServicesAllocatePages (\r
-             EfiBootServicesData,\r
+  Status = IoMmuAllocateBuffer (\r
              Pages,\r
-             &TempPtr\r
+             &BufHost,\r
+             &MappedAddr,\r
+             &Mapping\r
              );\r
   if (EFI_ERROR (Status)) {\r
     return NULL;\r
   }\r
-  ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (Pages));\r
+  ZeroMem ((VOID *) (UINTN) BufHost, EFI_PAGES_TO_SIZE (Pages));\r
 \r
-  Block->BufHost = (UINT8 *) (UINTN) TempPtr;;\r
-  Block->Buf = (UINT8 *) (UINTN) TempPtr;\r
+  Block->BufHost = (UINT8 *) (UINTN) BufHost;\r
+  Block->Buf = (UINT8 *) (UINTN) MappedAddr;\r
+  Block->Mapping  = Mapping;\r
   Block->Next = NULL;\r
 \r
   return Block;\r
@@ -102,6 +107,9 @@ UsbHcFreeMemBlock (
   )\r
 {\r
   ASSERT ((Pool != NULL) && (Block != NULL));\r
+\r
+  IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);\r
+\r
   //\r
   // No free memory in PEI.\r
   //\r
@@ -567,6 +575,7 @@ UsbHcFreeMem (
   @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
+  @param  Mapping               A resulting value to pass to Unmap().\r
 \r
   @retval EFI_SUCCESS           Success to allocate aligned pages.\r
   @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.\r
@@ -578,13 +587,16 @@ UsbHcAllocateAlignedPages (
   IN UINTN                      Pages,\r
   IN UINTN                      Alignment,\r
   OUT VOID                      **HostAddress,\r
-  OUT EFI_PHYSICAL_ADDRESS      *DeviceAddress\r
+  OUT EFI_PHYSICAL_ADDRESS      *DeviceAddress,\r
+  OUT VOID                      **Mapping\r
   )\r
 {\r
   EFI_STATUS            Status;\r
-  EFI_PHYSICAL_ADDRESS  Memory;\r
+  VOID                  *Memory;\r
   UINTN                 AlignedMemory;\r
   UINTN                 AlignmentMask;\r
+  EFI_PHYSICAL_ADDRESS  DeviceMemory;\r
+  UINTN                 AlignedDeviceMemory;\r
   UINTN                 RealPages;\r
 \r
   //\r
@@ -611,32 +623,36 @@ UsbHcAllocateAlignedPages (
     //\r
     ASSERT (RealPages > Pages);\r
 \r
-    Status = PeiServicesAllocatePages (\r
-               EfiBootServicesData,\r
+    Status = IoMmuAllocateBuffer (\r
                Pages,\r
-               &Memory\r
+               &Memory,\r
+               &DeviceMemory,\r
+               Mapping\r
                );\r
     if (EFI_ERROR (Status)) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
     AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
+    AlignedDeviceMemory = ((UINTN) DeviceMemory + AlignmentMask) & ~AlignmentMask;\r
   } else {\r
     //\r
     // Do not over-allocate pages in this case.\r
     //\r
-    Status = PeiServicesAllocatePages (\r
-               EfiBootServicesData,\r
+    Status = IoMmuAllocateBuffer (\r
                Pages,\r
-               &Memory\r
+               &Memory,\r
+               &DeviceMemory,\r
+               Mapping\r
                );\r
     if (EFI_ERROR (Status)) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
     AlignedMemory = (UINTN) Memory;\r
+    AlignedDeviceMemory = (UINTN) DeviceMemory;\r
   }\r
 \r
   *HostAddress = (VOID *) AlignedMemory;\r
-  *DeviceAddress = (EFI_PHYSICAL_ADDRESS) AlignedMemory;\r
+  *DeviceAddress = (EFI_PHYSICAL_ADDRESS) AlignedDeviceMemory;\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -646,17 +662,18 @@ UsbHcAllocateAlignedPages (
 \r
   @param  HostAddress           The system memory address to map to the PCI controller.\r
   @param  Pages                 The number of pages to free.\r
+  @param  Mapping               The mapping value returned from Map().\r
 \r
 **/\r
 VOID\r
 UsbHcFreeAlignedPages (\r
   IN VOID               *HostAddress,\r
-  IN UINTN              Pages\r
+  IN UINTN              Pages,\r
+  IN VOID               *Mapping\r
   )\r
 {\r
   ASSERT (Pages != 0);\r
-  //\r
-  // No free memory in PEI.\r
-  //\r
+\r
+  IoMmuFreeBuffer (Pages, HostAddress, Mapping);\r
 }\r
 \r
index c314e92..c315e6e 100644 (file)
@@ -29,6 +29,7 @@ struct _USBHC_MEM_BLOCK {
   UINT8                 *Buf;\r
   UINT8                 *BufHost;\r
   UINTN                 BufLen; // Memory size in bytes\r
+  VOID                  *Mapping;\r
   USBHC_MEM_BLOCK       *Next;\r
 };\r
 \r
@@ -112,6 +113,7 @@ UsbHcGetHostAddrForPciAddr (
   @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
+  @param  Mapping               A resulting value to pass to Unmap().\r
 \r
   @retval EFI_SUCCESS           Success to allocate aligned pages.\r
   @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.\r
@@ -123,7 +125,8 @@ UsbHcAllocateAlignedPages (
   IN UINTN                      Pages,\r
   IN UINTN                      Alignment,\r
   OUT VOID                      **HostAddress,\r
-  OUT EFI_PHYSICAL_ADDRESS      *DeviceAddress\r
+  OUT EFI_PHYSICAL_ADDRESS      *DeviceAddress,\r
+  OUT VOID                      **Mapping\r
   );\r
 \r
 /**\r
@@ -131,12 +134,14 @@ UsbHcAllocateAlignedPages (
 \r
   @param  HostAddress           The system memory address to map to the PCI controller.\r
   @param  Pages                 The number of pages to free.\r
+  @param  Mapping               The mapping value returned from Map().\r
 \r
 **/\r
 VOID\r
 UsbHcFreeAlignedPages (\r
   IN VOID               *HostAddress,\r
-  IN UINTN              Pages\r
+  IN UINTN              Pages,\r
+  IN VOID               *Mapping\r
   );\r
 \r
 #endif\r
index 38f0d21..99f69f7 100644 (file)
@@ -662,7 +662,8 @@ XhcPeiControlTransfer (
     if (EFI_ERROR(RecoveryStatus)) {\r
       DEBUG((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));\r
     }\r
-    goto FREE_URB;\r
+    XhcPeiFreeUrb (Xhc, Urb);\r
+    goto ON_EXIT;\r
   } else {\r
     if (*TransferResult == EFI_USB_NOERROR) {\r
       Status = EFI_SUCCESS;\r
@@ -672,11 +673,17 @@ XhcPeiControlTransfer (
         DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
       }\r
       Status = EFI_DEVICE_ERROR;\r
-      goto FREE_URB;\r
+      XhcPeiFreeUrb (Xhc, Urb);\r
+      goto ON_EXIT;\r
     } else {\r
-      goto FREE_URB;\r
+      XhcPeiFreeUrb (Xhc, Urb);\r
+      goto ON_EXIT;\r
     }\r
   }\r
+  //\r
+  // Unmap data before consume.\r
+  //\r
+  XhcPeiFreeUrb (Xhc, Urb);\r
 \r
   //\r
   // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.\r
@@ -704,7 +711,7 @@ XhcPeiControlTransfer (
       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
+        goto ON_EXIT;\r
       }\r
       if (Xhc->HcCParams.Data.Csz == 0) {\r
         Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);\r
@@ -722,7 +729,7 @@ XhcPeiControlTransfer (
         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
+          goto ON_EXIT;\r
         }\r
         CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);\r
       }\r
@@ -844,9 +851,6 @@ XhcPeiControlTransfer (
     *(UINT32 *) Data = *(UINT32 *) &PortStatus;\r
   }\r
 \r
-FREE_URB:\r
-  XhcPeiFreeUrb (Xhc, Urb);\r
-\r
 ON_EXIT:\r
 \r
   if (EFI_ERROR (Status)) {\r
@@ -1398,6 +1402,34 @@ XhcPeiGetRootHubPortStatus (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  One notified function to stop the Host Controller at the end of PEI\r
+\r
+  @param[in]  PeiServices        Pointer to PEI Services Table.\r
+  @param[in]  NotifyDescriptor   Pointer to the descriptor for the Notification event that\r
+                                 caused this function to execute.\r
+  @param[in]  Ppi                Pointer to the PPI data associated with this function.\r
+\r
+  @retval     EFI_SUCCESS  The function completes successfully\r
+  @retval     others\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcEndOfPei (\r
+  IN EFI_PEI_SERVICES           **PeiServices,\r
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,\r
+  IN VOID                       *Ppi\r
+  )\r
+{\r
+  PEI_XHC_DEV    *Xhc;\r
+\r
+  Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS_NOTIFY(NotifyDescriptor);\r
+\r
+  XhcPeiHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+\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
@@ -1429,6 +1461,8 @@ XhcPeimEntry (
     return EFI_SUCCESS;\r
   }\r
 \r
+  IoMmuInit ();\r
+\r
   Status = PeiServicesLocatePpi (\r
              &gPeiUsbControllerPpiGuid,\r
              0,\r
@@ -1530,7 +1564,12 @@ XhcPeimEntry (
     XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;\r
     XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;\r
 \r
+    XhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+    XhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;\r
+    XhcDev->EndOfPeiNotifyList.Notify = XhcEndOfPei;\r
+\r
     PeiServicesInstallPpi (&XhcDev->PpiDescriptor);\r
+    PeiServicesNotifyPpi (&XhcDev->EndOfPeiNotifyList);\r
 \r
     Index++;\r
   }\r
index 99f0396..e7a100f 100644 (file)
@@ -21,6 +21,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include <Ppi/UsbController.h>\r
 #include <Ppi/Usb2HostController.h>\r
+#include <Ppi/IoMmu.h>\r
+#include <Ppi/EndOfPeiPhase.h>\r
 \r
 #include <Library/DebugLib.h>\r
 #include <Library/PeimEntryPoint.h>\r
@@ -152,6 +154,12 @@ struct _PEI_XHC_DEV {
   UINT32                            UsbHostControllerBaseAddress;\r
   USBHC_MEM_POOL                    *MemPool;\r
 \r
+  //\r
+  // EndOfPei callback is used to stop the XHC DMA operation\r
+  // after exit PEI phase.\r
+  //\r
+  EFI_PEI_NOTIFY_DESCRIPTOR         EndOfPeiNotifyList;\r
+\r
   //\r
   // XHCI configuration data\r
   //\r
@@ -164,7 +172,9 @@ struct _PEI_XHC_DEV {
   UINT32                            PageSize;\r
   UINT32                            MaxScratchpadBufs;\r
   UINT64                            *ScratchBuf;\r
+  VOID                              *ScratchMap;\r
   UINT64                            *ScratchEntry;\r
+  UINTN                             *ScratchEntryMap;\r
   UINT64                            *DCBAA;\r
   UINT32                            MaxSlotsEn;\r
   //\r
@@ -184,6 +194,7 @@ struct _PEI_XHC_DEV {
 };\r
 \r
 #define PEI_RECOVERY_USB_XHC_DEV_FROM_THIS(a) CR (a, PEI_XHC_DEV, Usb2HostControllerPpi, USB_XHC_DEV_SIGNATURE)\r
+#define PEI_RECOVERY_USB_XHC_DEV_FROM_THIS_NOTIFY(a) CR (a, PEI_XHC_DEV, EndOfPeiNotifyList, USB_XHC_DEV_SIGNATURE)\r
 \r
 /**\r
   Initialize the memory management pool for the host controller.\r
@@ -242,4 +253,100 @@ UsbHcFreeMem (
   )\r
 ;\r
 \r
+\r
+/**\r
+  Initialize IOMMU.\r
+**/\r
+VOID\r
+IoMmuInit (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Provides the controller-specific addresses required to access system memory from a\r
+  DMA bus master.\r
+\r
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.\r
+  @param  HostAddress           The system memory address to map to the PCI controller.\r
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes\r
+                                that were mapped.\r
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to\r
+                                access the hosts HostAddress.\r
+  @param  Mapping               A resulting value to pass to Unmap().\r
+\r
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.\r
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.\r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuMap (\r
+  IN  EDKII_IOMMU_OPERATION Operation,\r
+  IN  VOID                  *HostAddress,\r
+  IN  OUT UINTN             *NumberOfBytes,\r
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,\r
+  OUT VOID                  **Mapping\r
+  );\r
+\r
+/**\r
+  Completes the Map() operation and releases any corresponding resources.\r
+\r
+  @param  Mapping               The mapping value returned from Map().\r
+\r
+  @retval EFI_SUCCESS           The range was unmapped.\r
+  @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.\r
+**/\r
+EFI_STATUS\r
+IoMmuUnmap (\r
+  IN VOID                  *Mapping\r
+  );\r
+\r
+/**\r
+  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+  OperationBusMasterCommonBuffer64 mapping.\r
+\r
+  @param  Pages                 The number of pages to allocate.\r
+  @param  HostAddress           A pointer to store the base system memory address of the\r
+                                allocated range.\r
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to\r
+                                access the hosts HostAddress.\r
+  @param  Mapping               A resulting value to pass to Unmap().\r
+\r
+  @retval EFI_SUCCESS           The requested memory pages were allocated.\r
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are\r
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuAllocateBuffer (\r
+  IN UINTN                  Pages,\r
+  OUT VOID                  **HostAddress,\r
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,\r
+  OUT VOID                  **Mapping\r
+  );\r
+\r
+/**\r
+  Frees memory that was allocated with AllocateBuffer().\r
+\r
+  @param  Pages                 The number of pages to free.\r
+  @param  HostAddress           The base system memory address of the allocated range.\r
+  @param  Mapping               The mapping value returned from Map().\r
+\r
+  @retval EFI_SUCCESS           The requested memory pages were freed.\r
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
+                                was not allocated with AllocateBuffer().\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuFreeBuffer (\r
+  IN UINTN                  Pages,\r
+  IN VOID                   *HostAddress,\r
+  IN VOID                   *Mapping\r
+  );\r
+\r
 #endif\r
index dc65f28..f307ea7 100644 (file)
@@ -37,6 +37,7 @@
   XhcPeim.h\r
   XhciSched.c\r
   UsbHcMem.c\r
+  DmaMem.c\r
   XhciReg.h\r
   XhciSched.h\r
   UsbHcMem.h\r
@@ -56,6 +57,8 @@
 [Ppis]\r
   gPeiUsb2HostControllerPpiGuid                 ## PRODUCES\r
   gPeiUsbControllerPpiGuid                      ## CONSUMES\r
+  gEdkiiIoMmuPpiGuid                            ## CONSUMES\r
+  gEfiEndOfPeiSignalPpiGuid                     ## CONSUMES\r
 \r
 [Depex]\r
   gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
index 3dd2b89..e5aee49 100644 (file)
@@ -200,6 +200,8 @@ XhcPeiFreeUrb (
     return;\r
   }\r
 \r
+  IoMmuUnmap (Urb->DataMap);\r
+\r
   FreePool (Urb);\r
 }\r
 \r
@@ -227,6 +229,10 @@ XhcPeiCreateTransferTrb (
   UINTN                         TotalLen;\r
   UINTN                         Len;\r
   UINTN                         TrbNum;\r
+  EDKII_IOMMU_OPERATION         MapOp;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+  VOID                          *Map;\r
+  EFI_STATUS                    Status;\r
 \r
   SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
   if (SlotId == 0) {\r
@@ -249,7 +255,27 @@ XhcPeiCreateTransferTrb (
     EPType  = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;\r
   }\r
 \r
-  Urb->DataPhy = Urb->Data;\r
+  //\r
+  // No need to remap.\r
+  //\r
+  if ((Urb->Data != NULL) && (Urb->DataMap == NULL)) {\r
+    if (((UINT8) (Urb->Ep.Direction)) == EfiUsbDataIn) {\r
+      MapOp = EdkiiIoMmuOperationBusMasterWrite;\r
+    } else {\r
+      MapOp = EdkiiIoMmuOperationBusMasterRead;\r
+    }\r
+\r
+    Len = Urb->DataLen;\r
+    Status = IoMmuMap (MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
+\r
+    if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
+      DEBUG ((DEBUG_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Urb->DataPhy  = (VOID *) ((UINTN) PhyAddr);\r
+    Urb->DataMap  = Map;\r
+  }\r
 \r
   //\r
   // Construct the TRB\r
@@ -2812,6 +2838,7 @@ XhcPeiInitSched (
   UINT64                *ScratchEntry;\r
   EFI_PHYSICAL_ADDRESS  ScratchEntryPhy;\r
   UINT32                Index;\r
+  UINTN                 *ScratchEntryMap;\r
   EFI_STATUS            Status;\r
 \r
   //\r
@@ -2847,6 +2874,13 @@ XhcPeiInitSched (
   Xhc->MaxScratchpadBufs = MaxScratchpadBufs;\r
   ASSERT (MaxScratchpadBufs <= 1023);\r
   if (MaxScratchpadBufs != 0) {\r
+    //\r
+    // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them\r
+    //\r
+    ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);\r
+    ASSERT (ScratchEntryMap != NULL);\r
+    Xhc->ScratchEntryMap = ScratchEntryMap;\r
+\r
     //\r
     // Allocate the buffer to record the host address for each entry\r
     //\r
@@ -2859,7 +2893,8 @@ XhcPeiInitSched (
                EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),\r
                Xhc->PageSize,\r
                (VOID **) &ScratchBuf,\r
-               &ScratchPhy\r
+               &ScratchPhy,\r
+               &Xhc->ScratchMap\r
                );\r
     ASSERT_EFI_ERROR (Status);\r
 \r
@@ -2875,7 +2910,8 @@ XhcPeiInitSched (
                  EFI_SIZE_TO_PAGES (Xhc->PageSize),\r
                  Xhc->PageSize,\r
                  (VOID **) &ScratchEntry[Index],\r
-                 &ScratchEntryPhy\r
+                 &ScratchEntryPhy,\r
+                 (VOID **) &ScratchEntryMap[Index]\r
                  );\r
       ASSERT_EFI_ERROR (Status);\r
       ZeroMem ((VOID *) (UINTN) ScratchEntry[Index], Xhc->PageSize);\r
@@ -2967,12 +3003,13 @@ XhcPeiFreeSched (
       //\r
       // Free Scratchpad Buffers\r
       //\r
-      UsbHcFreeAlignedPages ((VOID*) (UINTN) ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize));\r
+      UsbHcFreeAlignedPages ((VOID*) (UINTN) ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *) Xhc->ScratchEntryMap[Index]);\r
     }\r
     //\r
     // Free Scratchpad Buffer Array\r
     //\r
-    UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)));\r
+    UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);\r
+    FreePool (Xhc->ScratchEntryMap);\r
     FreePool (Xhc->ScratchEntry);\r
   }\r
 \r
index b3d4c45..faf2e63 100644 (file)
@@ -170,6 +170,7 @@ typedef struct _URB {
   VOID                              *Data;\r
   UINTN                             DataLen;\r
   VOID                              *DataPhy;\r
+  VOID                              *DataMap;\r
   EFI_ASYNC_USB_TRANSFER_CALLBACK   Callback;\r
   VOID                              *Context;\r
   //\r