MdeModulePkg UhciPei: Support IoMmu
authorStar Zeng <star.zeng@intel.com>
Mon, 20 Nov 2017 07:44:39 +0000 (15:44 +0800)
committerStar Zeng <star.zeng@intel.com>
Wed, 22 Nov 2017 10:37:49 +0000 (18:37 +0800)
Update the UhciPei 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.

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

diff --git a/MdeModulePkg/Bus/Pci/UhciPei/DmaMem.c b/MdeModulePkg/Bus/Pci/UhciPei/DmaMem.c
new file mode 100644 (file)
index 0000000..c92bee4
--- /dev/null
@@ -0,0 +1,251 @@
+/** @file\r
+The DMA memory help functions.\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 "UhcPeim.h"\r
+\r
+/**\r
+  Provides the controller-specific addresses required to access system memory from a\r
+  DMA bus master.\r
+\r
+  @param IoMmu                  Pointer to IOMMU PPI.\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_PPI        *IoMmu,\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 (IoMmu != NULL) {\r
+    Status = IoMmu->Map (\r
+                      IoMmu,\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 = IoMmu->SetAttribute (\r
+                      IoMmu,\r
+                      *Mapping,\r
+                      Attribute\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      IoMmu->Unmap (IoMmu, Mapping);\r
+      *Mapping = NULL;\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 IoMmu              Pointer to IOMMU PPI.\r
+  @param Mapping            The mapping value returned from Map().\r
+\r
+**/\r
+VOID\r
+IoMmuUnmap (\r
+  IN EDKII_IOMMU_PPI        *IoMmu,\r
+  IN VOID                  *Mapping\r
+  )\r
+{\r
+  if (IoMmu != NULL) {\r
+    IoMmu->SetAttribute (IoMmu, Mapping, 0);\r
+    IoMmu->Unmap (IoMmu, Mapping);\r
+  }\r
+}\r
+\r
+/**\r
+  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+  OperationBusMasterCommonBuffer64 mapping.\r
+\r
+  @param IoMmu                  Pointer to IOMMU PPI.\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 EDKII_IOMMU_PPI        *IoMmu,\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
+  *Mapping = NULL;\r
+\r
+  if (IoMmu != NULL) {\r
+    Status = IoMmu->AllocateBuffer (\r
+                      IoMmu,\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 = IoMmu->Map (\r
+                      IoMmu,\r
+                      EdkiiIoMmuOperationBusMasterCommonBuffer,\r
+                      *HostAddress,\r
+                      &NumberOfBytes,\r
+                      DeviceAddress,\r
+                      Mapping\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);\r
+      *HostAddress = NULL;\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    Status = IoMmu->SetAttribute (\r
+                      IoMmu,\r
+                      *Mapping,\r
+                      EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      IoMmu->Unmap (IoMmu, *Mapping);\r
+      IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);\r
+      *Mapping = NULL;\r
+      *HostAddress = NULL;\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 IoMmu              Pointer to IOMMU PPI.\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
+**/\r
+VOID\r
+IoMmuFreeBuffer (\r
+  IN EDKII_IOMMU_PPI        *IoMmu,\r
+  IN UINTN                  Pages,\r
+  IN VOID                   *HostAddress,\r
+  IN VOID                   *Mapping\r
+  )\r
+{\r
+  if (IoMmu != NULL) {\r
+    IoMmu->SetAttribute (IoMmu, Mapping, 0);\r
+    IoMmu->Unmap (IoMmu, Mapping);\r
+    IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize IOMMU.\r
+\r
+  @param IoMmu              Pointer to pointer to IOMMU PPI.\r
+\r
+**/\r
+VOID\r
+IoMmuInit (\r
+  OUT EDKII_IOMMU_PPI       **IoMmu\r
+  )\r
+{\r
+  *IoMmu = NULL;\r
+  PeiServicesLocatePpi (\r
+    &gEdkiiIoMmuPpiGuid,\r
+    0,\r
+    NULL,\r
+    (VOID **) IoMmu\r
+    );\r
+}\r
+\r
index 37b2124c67ca8e27c8c449590c6569c2d40f1d2b..b7d60db0c94e090f70a7bd80352b41494257d96c 100644 (file)
@@ -2,7 +2,7 @@
 PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
 which is used to enable recovery function from USB Drivers.\r
 \r
-Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved. <BR>\r
+Copyright (c) 2006 - 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
@@ -17,6 +17,78 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include "UhcPeim.h"\r
 \r
+/**\r
+  Stop the host controller.\r
+\r
+  @param  Uhc           The UHCI device.\r
+  @param  Timeout       Max time allowed.\r
+\r
+  @retval EFI_SUCCESS   The host controller is stopped.\r
+  @retval EFI_TIMEOUT   Failed to stop the host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciStopHc (\r
+  IN USB_UHC_DEV        *Uhc,\r
+  IN UINTN              Timeout\r
+  )\r
+{\r
+  UINT16                CommandContent;\r
+  UINT16                UsbSts;\r
+  UINTN                 Index;\r
+\r
+  CommandContent = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD);\r
+  CommandContent &= USBCMD_RS;\r
+  USBWritePortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD, CommandContent);\r
+\r
+  //\r
+  // ensure the HC is in halt status after send the stop command\r
+  // Timeout is in us unit.\r
+  //\r
+  for (Index = 0; Index < (Timeout / 50) + 1; Index++) {\r
+    UsbSts = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBSTS);\r
+\r
+    if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    MicroSecondDelay (50);\r
+  }\r
+\r
+  return EFI_TIMEOUT;\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
+UhcEndOfPei (\r
+  IN EFI_PEI_SERVICES           **PeiServices,\r
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,\r
+  IN VOID                       *Ppi\r
+  )\r
+{\r
+  USB_UHC_DEV   *Uhc;\r
+\r
+  Uhc = PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor);\r
+\r
+  //\r
+  // Stop the Host Controller\r
+  //\r
+  UhciStopHc (Uhc, 1000 * 1000);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Initializes Usb Host Controller.\r
 \r
@@ -98,6 +170,7 @@ UhcPeimEntry (
 \r
     UhcDev = (USB_UHC_DEV *) ((UINTN) TempPtr);\r
     UhcDev->Signature   = USB_UHC_DEV_SIGNATURE;\r
+    IoMmuInit (&UhcDev->IoMmu);\r
     UhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;\r
 \r
     //\r
@@ -133,6 +206,12 @@ UhcPeimEntry (
       continue;\r
     }\r
 \r
+    UhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+    UhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;\r
+    UhcDev->EndOfPeiNotifyList.Notify = UhcEndOfPei;\r
+\r
+    PeiServicesNotifyPpi (&UhcDev->EndOfPeiNotifyList);\r
+\r
     Index++;\r
   }\r
 \r
@@ -190,9 +269,11 @@ UhcControlTransfer (
   TD_STRUCT   *PtrStatusTD;\r
   EFI_STATUS  Status;\r
   UINT32      DataLen;\r
-  UINT8       *PtrDataSource;\r
-  UINT8       *Ptr;\r
   UINT8       DataToggle;\r
+  UINT8       *RequestPhy;\r
+  VOID        *RequestMap;\r
+  UINT8       *DataPhy;\r
+  VOID        *DataMap;\r
 \r
   UhcDev      = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
 \r
@@ -216,6 +297,24 @@ UhcControlTransfer (
 \r
   ClearStatusReg (UhcDev, StatusReg);\r
 \r
+  //\r
+  // Map the Request and data for bus master access,\r
+  // then create a list of TD for this transfer\r
+  //\r
+  Status = UhciMapUserRequest (UhcDev, Request, &RequestPhy, &RequestMap);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    if (RequestMap != NULL) {\r
+      IoMmuUnmap (UhcDev->IoMmu, RequestMap);\r
+    }\r
+    return Status;\r
+  }\r
+\r
   //\r
   // generate Setup Stage TD\r
   //\r
@@ -228,6 +327,7 @@ UhcControlTransfer (
     0,\r
     DeviceSpeed,\r
     (UINT8 *) Request,\r
+    RequestPhy,\r
     (UINT8) sizeof (EFI_USB_DEVICE_REQUEST),\r
     &PtrSetupTD\r
     );\r
@@ -242,38 +342,11 @@ UhcControlTransfer (
   //\r
   //  Data Stage of Control Transfer\r
   //\r
-  switch (TransferDirection) {\r
-\r
-  case EfiUsbDataIn:\r
-    PktID         = INPUT_PACKET_ID;\r
-    PtrDataSource = Data;\r
-    DataLen       = (UINT32) *DataLength;\r
-    Ptr           = PtrDataSource;\r
-    break;\r
-\r
-  case EfiUsbDataOut:\r
-    PktID         = OUTPUT_PACKET_ID;\r
-    PtrDataSource = Data;\r
-    DataLen       = (UINT32) *DataLength;\r
-    Ptr           = PtrDataSource;\r
-    break;\r
-\r
-  //\r
-  // no data stage\r
-  //\r
-  case EfiUsbNoData:\r
-    if (*DataLength != 0) {\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-\r
-    PktID         = OUTPUT_PACKET_ID;\r
-    PtrDataSource = NULL;\r
-    DataLen       = 0;\r
-    Ptr           = NULL;\r
-    break;\r
 \r
-  default:\r
-    return EFI_INVALID_PARAMETER;\r
+  if (TransferDirection == EfiUsbNoData) {\r
+    DataLen = 0;\r
+  } else {\r
+    DataLen = (UINT32) *DataLength;\r
   }\r
 \r
   DataToggle  = 1;\r
@@ -297,7 +370,8 @@ UhcControlTransfer (
       UhcDev,\r
       DeviceAddress,\r
       0,\r
-      Ptr,\r
+      Data,\r
+      DataPhy,\r
       PacketSize,\r
       PktID,\r
       DataToggle,\r
@@ -312,7 +386,8 @@ UhcControlTransfer (
     PtrPreTD = PtrTD;\r
 \r
     DataToggle ^= 1;\r
-    Ptr += PacketSize;\r
+    Data = (VOID *) ((UINT8 *) Data + PacketSize);\r
+    DataPhy += PacketSize;\r
     DataLen -= PacketSize;\r
   }\r
 \r
@@ -365,14 +440,19 @@ UhcControlTransfer (
   // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.\r
   //\r
   if (!IsStatusOK (UhcDev, StatusReg)) {\r
-\r
-    ClearStatusReg (UhcDev, StatusReg);\r
     *TransferResult |= EFI_USB_ERR_SYSTEM;\r
-    return EFI_DEVICE_ERROR;\r
+    Status = EFI_DEVICE_ERROR;\r
   }\r
 \r
   ClearStatusReg (UhcDev, StatusReg);\r
 \r
+  if (DataMap != NULL) {\r
+    IoMmuUnmap (UhcDev->IoMmu, DataMap);\r
+  }\r
+  if (RequestMap != NULL) {\r
+    IoMmuUnmap (UhcDev->IoMmu, RequestMap);\r
+  }\r
+\r
   return Status;\r
 }\r
 \r
@@ -431,8 +511,6 @@ UhcBulkTransfer (
   TD_STRUCT               *PtrPreTD;\r
 \r
   UINT8                   PktID;\r
-  UINT8                   *PtrDataSource;\r
-  UINT8                   *Ptr;\r
 \r
   BOOLEAN                 IsFirstTD;\r
 \r
@@ -444,6 +522,9 @@ UhcBulkTransfer (
 \r
   UINT16                  CommandContent;\r
 \r
+  UINT8                   *DataPhy;\r
+  VOID                    *DataMap;\r
+\r
   UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
 \r
   //\r
@@ -467,7 +548,6 @@ UhcBulkTransfer (
   PtrFirstTD        = NULL;\r
   PtrPreTD          = NULL;\r
   DataLen           = 0;\r
-  Ptr               = NULL;\r
 \r
   ShortPacketEnable = FALSE;\r
 \r
@@ -495,33 +575,24 @@ UhcBulkTransfer (
 \r
   ClearStatusReg (UhcDev, StatusReg);\r
 \r
+  //\r
+  // Map the source data buffer for bus master access,\r
+  // then create a list of TDs\r
+  //\r
   if ((EndPointAddress & 0x80) != 0) {\r
     TransferDirection = EfiUsbDataIn;\r
   } else {\r
     TransferDirection = EfiUsbDataOut;\r
   }\r
 \r
-  switch (TransferDirection) {\r
+  Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap);\r
 \r
-  case EfiUsbDataIn:\r
-    ShortPacketEnable = TRUE;\r
-    PktID             = INPUT_PACKET_ID;\r
-    PtrDataSource     = Data;\r
-    DataLen           = (UINT32) *DataLength;\r
-    Ptr               = PtrDataSource;\r
-    break;\r
-\r
-  case EfiUsbDataOut:\r
-    PktID         = OUTPUT_PACKET_ID;\r
-    PtrDataSource = Data;\r
-    DataLen       = (UINT32) *DataLength;\r
-    Ptr           = PtrDataSource;\r
-    break;\r
-\r
-  default:\r
-    break;\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
 \r
+  DataLen = (UINT32) *DataLength;\r
+\r
   PtrQH = UhcDev->BulkQH;\r
 \r
   IsFirstTD = TRUE;\r
@@ -540,7 +611,8 @@ UhcBulkTransfer (
       UhcDev,\r
       DeviceAddress,\r
       EndPointAddress,\r
-      Ptr,\r
+      Data,\r
+      DataPhy,\r
       PacketSize,\r
       PktID,\r
       *DataToggle,\r
@@ -570,7 +642,8 @@ UhcBulkTransfer (
     PtrPreTD = PtrTD;\r
 \r
     *DataToggle ^= 1;\r
-    Ptr += PacketSize;\r
+    Data = (VOID *) ((UINT8 *) Data + PacketSize);\r
+    DataPhy += PacketSize;\r
     DataLen -= PacketSize;\r
   }\r
   //\r
@@ -604,14 +677,16 @@ UhcBulkTransfer (
   // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.\r
   //\r
   if (!IsStatusOK (UhcDev, StatusReg)) {\r
-\r
-    ClearStatusReg (UhcDev, StatusReg);\r
     *TransferResult |= EFI_USB_ERR_SYSTEM;\r
-    return EFI_DEVICE_ERROR;\r
+    Status = EFI_DEVICE_ERROR;\r
   }\r
 \r
   ClearStatusReg (UhcDev, StatusReg);\r
 \r
+  if (DataMap != NULL) {\r
+    IoMmuUnmap (UhcDev->IoMmu, DataMap);\r
+  }\r
+\r
   return Status;\r
 }\r
 \r
@@ -1492,7 +1567,8 @@ CreateTD (
   @param  DevAddr      Device address.\r
   @param  Endpoint     Endpoint number.\r
   @param  DeviceSpeed  Device Speed.\r
-  @param  DevRequest   Device reuquest.\r
+  @param  DevRequest   CPU memory address of request structure buffer to transfer.\r
+  @param  RequestPhy   PCI memory address of request structure buffer to transfer.\r
   @param  RequestLen   Request length.\r
   @param  PtrTD        TD_STRUCT generated.\r
 \r
@@ -1507,6 +1583,7 @@ GenSetupStageTD (
   IN  UINT8           Endpoint,\r
   IN  UINT8           DeviceSpeed,\r
   IN  UINT8           *DevRequest,\r
+  IN  UINT8           *RequestPhy,\r
   IN  UINT8           RequestLen,\r
   OUT TD_STRUCT       **PtrTD\r
   )\r
@@ -1583,7 +1660,11 @@ GenSetupStageTD (
 \r
   TdStruct->PtrTDBuffer      = (UINT8 *) DevRequest;\r
   TdStruct->TDBufferLength = RequestLen;\r
-  SetTDDataBuffer (TdStruct);\r
+  //\r
+  // Set the beginning address of the buffer that will be used\r
+  // during the transaction.\r
+  //\r
+  TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) RequestPhy;\r
 \r
   *PtrTD = TdStruct;\r
 \r
@@ -1596,7 +1677,8 @@ GenSetupStageTD (
   @param  UhcDev       The UHCI device.\r
   @param  DevAddr      Device address.\r
   @param  Endpoint     Endpoint number.\r
-  @param  PtrData      Data buffer.\r
+  @param  PtrData      CPU memory address of user data buffer to transfer.\r
+  @param  DataPhy      PCI memory address of user data buffer to transfer.\r
   @param  Len          Data length.\r
   @param  PktID        PacketID.\r
   @param  Toggle       Data toggle value.\r
@@ -1613,6 +1695,7 @@ GenDataTD (
   IN  UINT8           DevAddr,\r
   IN  UINT8           Endpoint,\r
   IN  UINT8           *PtrData,\r
+  IN  UINT8           *DataPhy,\r
   IN  UINT8           Len,\r
   IN  UINT8           PktID,\r
   IN  UINT8           Toggle,\r
@@ -1700,7 +1783,11 @@ GenDataTD (
 \r
   TdStruct->PtrTDBuffer      = (UINT8 *) PtrData;\r
   TdStruct->TDBufferLength = Len;\r
-  SetTDDataBuffer (TdStruct);\r
+  //\r
+  // Set the beginning address of the buffer that will be used\r
+  // during the transaction.\r
+  //\r
+  TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) DataPhy;\r
 \r
   *PtrTD = TdStruct;\r
 \r
@@ -1803,7 +1890,11 @@ CreateStatusTD (
 \r
   PtrTDStruct->PtrTDBuffer      = NULL;\r
   PtrTDStruct->TDBufferLength = 0;\r
-  SetTDDataBuffer (PtrTDStruct);\r
+  //\r
+  // Set the beginning address of the buffer that will be used\r
+  // during the transaction.\r
+  //\r
+  PtrTDStruct->TDData.TDBufferPtr = 0;\r
 \r
   *PtrTD = PtrTDStruct;\r
 \r
@@ -2173,25 +2264,6 @@ SetTDTokenPacketID (
   PtrTDStruct->TDData.TDTokenPID = PacketID;\r
 }\r
 \r
-/**\r
-  Set the beginning address of the data buffer that will be used\r
-  during the transaction.\r
-\r
-  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
-\r
-**/\r
-VOID\r
-SetTDDataBuffer (\r
-  IN  TD_STRUCT *PtrTDStruct\r
-  )\r
-{\r
-  //\r
-  // Set the beginning address of the data buffer that will be used\r
-  // during the transaction.\r
-  //\r
-  PtrTDStruct->TDData.TDBufferPtr = (UINT32) (UINTN) (PtrTDStruct->PtrTDBuffer);\r
-}\r
-\r
 /**\r
   Detect whether the TD is active.\r
 \r
@@ -2773,25 +2845,29 @@ CreateMemoryBlock (
   )\r
 {\r
   EFI_STATUS            Status;\r
-  EFI_PHYSICAL_ADDRESS  TempPtr;\r
+  UINT8                 *TempPtr;\r
   UINTN                 MemPages;\r
   UINT8                 *Ptr;\r
+  VOID                  *Mapping;\r
+  EFI_PHYSICAL_ADDRESS  MappedAddr;\r
 \r
   //\r
   // Memory Block uses MemoryBlockSizeInPages pages,\r
   // memory management header and bit array use 1 page\r
   //\r
   MemPages = MemoryBlockSizeInPages + 1;\r
-  Status = PeiServicesAllocatePages (\r
-             EfiBootServicesData,\r
+  Status = IoMmuAllocateBuffer (\r
+             UhcDev->IoMmu,\r
              MemPages,\r
-             &TempPtr\r
+             (VOID **) &TempPtr,\r
+             &MappedAddr,\r
+             &Mapping\r
              );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  Ptr = (UINT8 *) ((UINTN) TempPtr);\r
+  Ptr = TempPtr;\r
 \r
   ZeroMem (Ptr, MemPages * EFI_PAGE_SIZE);\r
 \r
@@ -2810,7 +2886,7 @@ CreateMemoryBlock (
   //\r
   // Memory block initial address\r
   //\r
-  Ptr = (UINT8 *) ((UINTN) TempPtr);\r
+  Ptr = TempPtr;\r
   Ptr += EFI_PAGE_SIZE;\r
   (*MemoryHeader)->MemoryBlockPtr = Ptr;\r
   //\r
@@ -3217,3 +3293,135 @@ DelinkMemoryBlock (
     }\r
   }\r
 }\r
+\r
+/**\r
+  Map address of request structure buffer.\r
+\r
+  @param  Uhc                The UHCI device.\r
+  @param  Request            The user request buffer.\r
+  @param  MappedAddr         Mapped address of request.\r
+  @param  Map                Identificaion of this mapping to return.\r
+\r
+  @return EFI_SUCCESS        Success.\r
+  @return EFI_DEVICE_ERROR   Fail to map the user request.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserRequest (\r
+  IN  USB_UHC_DEV         *Uhc,\r
+  IN  OUT VOID            *Request,\r
+  OUT UINT8               **MappedAddr,\r
+  OUT VOID                **Map\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINTN                 Len;\r
+  EFI_PHYSICAL_ADDRESS  PhyAddr;\r
+\r
+  Len    = sizeof (EFI_USB_DEVICE_REQUEST);\r
+  Status = IoMmuMap (\r
+             Uhc->IoMmu,\r
+             EdkiiIoMmuOperationBusMasterRead,\r
+             Request,\r
+             &Len,\r
+             &PhyAddr,\r
+             Map\r
+             );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Map address of user data buffer.\r
+\r
+  @param  Uhc                The UHCI device.\r
+  @param  Direction          Direction of the data transfer.\r
+  @param  Data               The user data buffer.\r
+  @param  Len                Length of the user data.\r
+  @param  PktId              Packet identificaion.\r
+  @param  MappedAddr         Mapped address to return.\r
+  @param  Map                Identificaion of this mapping to return.\r
+\r
+  @return EFI_SUCCESS        Success.\r
+  @return EFI_DEVICE_ERROR   Fail to map the user data.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserData (\r
+  IN  USB_UHC_DEV             *Uhc,\r
+  IN  EFI_USB_DATA_DIRECTION  Direction,\r
+  IN  VOID                    *Data,\r
+  IN  OUT UINTN               *Len,\r
+  OUT UINT8                   *PktId,\r
+  OUT UINT8                   **MappedAddr,\r
+  OUT VOID                    **Map\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  PhyAddr;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  switch (Direction) {\r
+  case EfiUsbDataIn:\r
+    //\r
+    // BusMasterWrite means cpu read\r
+    //\r
+    *PktId = INPUT_PACKET_ID;\r
+    Status = IoMmuMap (\r
+               Uhc->IoMmu,\r
+               EdkiiIoMmuOperationBusMasterWrite,\r
+               Data,\r
+               Len,\r
+               &PhyAddr,\r
+               Map\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto EXIT;\r
+    }\r
+\r
+    *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
+    break;\r
+\r
+  case EfiUsbDataOut:\r
+    *PktId = OUTPUT_PACKET_ID;\r
+    Status = IoMmuMap (\r
+               Uhc->IoMmu,\r
+               EdkiiIoMmuOperationBusMasterRead,\r
+               Data,\r
+               Len,\r
+               &PhyAddr,\r
+               Map\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto EXIT;\r
+    }\r
+\r
+    *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
+    break;\r
+\r
+  case EfiUsbNoData:\r
+    if ((Len != NULL) && (*Len != 0)) {\r
+      Status    = EFI_INVALID_PARAMETER;\r
+      goto EXIT;\r
+    }\r
+\r
+    *PktId      = OUTPUT_PACKET_ID;\r
+    *MappedAddr = NULL;\r
+    *Map        = NULL;\r
+    break;\r
+\r
+  default:\r
+    Status      = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+EXIT:\r
+  return Status;\r
+}\r
+\r
index 460db7eab9c6a121b74f7a84061cf24aa382fc92..9935f522cd0d37e65f2d1e292965786210070b34 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Private Header file for Usb Host Controller PEIM\r
 \r
-Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 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
@@ -22,6 +22,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include <Ppi/UsbController.h>\r
 #include <Ppi/UsbHostController.h>\r
+#include <Ppi/IoMmu.h>\r
+#include <Ppi/EndOfPeiPhase.h>\r
 \r
 #include <Library/DebugLib.h>\r
 #include <Library/PeimEntryPoint.h>\r
@@ -177,7 +179,13 @@ struct _MEMORY_MANAGE_HEADER {
 typedef struct {\r
   UINTN                       Signature;\r
   PEI_USB_HOST_CONTROLLER_PPI UsbHostControllerPpi;\r
+  EDKII_IOMMU_PPI             *IoMmu;\r
   EFI_PEI_PPI_DESCRIPTOR      PpiDescriptor;\r
+  //\r
+  // EndOfPei callback is used to stop the UHC DMA operation\r
+  // after exit PEI phase.\r
+  //\r
+  EFI_PEI_NOTIFY_DESCRIPTOR   EndOfPeiNotifyList;\r
 \r
   UINT32                      UsbHostControllerBaseAddress;\r
   FRAMELIST_ENTRY             *FrameListEntry;\r
@@ -191,6 +199,7 @@ typedef struct {
 } USB_UHC_DEV;\r
 \r
 #define PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS(a)  CR (a, USB_UHC_DEV, UsbHostControllerPpi, USB_UHC_DEV_SIGNATURE)\r
+#define PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY(a) CR (a, USB_UHC_DEV, EndOfPeiNotifyList, USB_UHC_DEV_SIGNATURE)\r
 \r
 /**\r
   Submits control transfer to a target USB device.\r
@@ -654,7 +663,8 @@ CreateTD (
   @param  DevAddr      Device address.\r
   @param  Endpoint     Endpoint number.\r
   @param  DeviceSpeed  Device Speed.\r
-  @param  DevRequest   Device reuquest.\r
+  @param  DevRequest   CPU memory address of request structure buffer to transfer.\r
+  @param  RequestPhy   PCI memory address of request structure buffer to transfer.\r
   @param  RequestLen   Request length.\r
   @param  PtrTD        TD_STRUCT generated.\r
 \r
@@ -669,6 +679,7 @@ GenSetupStageTD (
   IN  UINT8           Endpoint,\r
   IN  UINT8           DeviceSpeed,\r
   IN  UINT8           *DevRequest,\r
+  IN  UINT8           *RequestPhy,\r
   IN  UINT8           RequestLen,\r
   OUT TD_STRUCT       **PtrTD\r
   );\r
@@ -679,7 +690,8 @@ GenSetupStageTD (
   @param  UhcDev       The UHCI device.\r
   @param  DevAddr      Device address.\r
   @param  Endpoint     Endpoint number.\r
-  @param  PtrData      Data buffer.\r
+  @param  PtrData      CPU memory address of user data buffer to transfer.\r
+  @param  DataPhy      PCI memory address of user data buffer to transfer.\r
   @param  Len          Data length.\r
   @param  PktID        PacketID.\r
   @param  Toggle       Data toggle value.\r
@@ -696,6 +708,7 @@ GenDataTD (
   IN  UINT8           DevAddr,\r
   IN  UINT8           Endpoint,\r
   IN  UINT8           *PtrData,\r
+  IN  UINT8           *DataPhy,\r
   IN  UINT8           Len,\r
   IN  UINT8           PktID,\r
   IN  UINT8           Toggle,\r
@@ -1330,4 +1343,149 @@ DelinkMemoryBlock (
   IN MEMORY_MANAGE_HEADER    *FreeMemoryHeader\r
   );\r
 \r
+/**\r
+  Map address of request structure buffer.\r
+\r
+  @param  Uhc                The UHCI device.\r
+  @param  Request            The user request buffer.\r
+  @param  MappedAddr         Mapped address of request.\r
+  @param  Map                Identificaion of this mapping to return.\r
+\r
+  @return EFI_SUCCESS        Success.\r
+  @return EFI_DEVICE_ERROR   Fail to map the user request.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserRequest (\r
+  IN  USB_UHC_DEV         *Uhc,\r
+  IN  OUT VOID            *Request,\r
+  OUT UINT8               **MappedAddr,\r
+  OUT VOID                **Map\r
+  );\r
+\r
+/**\r
+  Map address of user data buffer.\r
+\r
+  @param  Uhc                The UHCI device.\r
+  @param  Direction          Direction of the data transfer.\r
+  @param  Data               The user data buffer.\r
+  @param  Len                Length of the user data.\r
+  @param  PktId              Packet identificaion.\r
+  @param  MappedAddr         Mapped address to return.\r
+  @param  Map                Identificaion of this mapping to return.\r
+\r
+  @return EFI_SUCCESS        Success.\r
+  @return EFI_DEVICE_ERROR   Fail to map the user data.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserData (\r
+  IN  USB_UHC_DEV             *Uhc,\r
+  IN  EFI_USB_DATA_DIRECTION  Direction,\r
+  IN  VOID                    *Data,\r
+  IN  OUT UINTN               *Len,\r
+  OUT UINT8                   *PktId,\r
+  OUT UINT8                   **MappedAddr,\r
+  OUT VOID                    **Map\r
+  );\r
+\r
+/**\r
+  Provides the controller-specific addresses required to access system memory from a\r
+  DMA bus master.\r
+\r
+  @param IoMmu                  Pointer to IOMMU PPI.\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_PPI        *IoMmu,\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 IoMmu              Pointer to IOMMU PPI.\r
+  @param Mapping            The mapping value returned from Map().\r
+\r
+**/\r
+VOID\r
+IoMmuUnmap (\r
+  IN EDKII_IOMMU_PPI        *IoMmu,\r
+  IN VOID                  *Mapping\r
+  );\r
+\r
+/**\r
+  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+  OperationBusMasterCommonBuffer64 mapping.\r
+\r
+  @param IoMmu                  Pointer to IOMMU PPI.\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 EDKII_IOMMU_PPI        *IoMmu,\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 IoMmu              Pointer to IOMMU PPI.\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
+**/\r
+VOID\r
+IoMmuFreeBuffer (\r
+  IN EDKII_IOMMU_PPI        *IoMmu,\r
+  IN UINTN                  Pages,\r
+  IN VOID                   *HostAddress,\r
+  IN VOID                   *Mapping\r
+  );\r
+\r
+/**\r
+  Initialize IOMMU.\r
+\r
+  @param IoMmu              Pointer to pointer to IOMMU PPI.\r
+\r
+**/\r
+VOID\r
+IoMmuInit (\r
+  OUT EDKII_IOMMU_PPI       **IoMmu\r
+  );\r
+\r
 #endif\r
index 7baa07612d01003eea2dccb4a98e911885d434f7..95ddea21626e5c81f7e3b31ba17b95abc5519ad5 100644 (file)
@@ -4,7 +4,7 @@
 # It produces gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid which is used\r
 # to enable recovery function from USB Drivers.\r
 #\r
-# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2006 - 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
@@ -36,6 +36,7 @@
 [Sources]\r
   UhcPeim.c\r
   UhcPeim.h\r
+  DmaMem.c\r
 \r
 \r
 [Packages]\r
@@ -55,6 +56,8 @@
 [Ppis]\r
   gPeiUsbHostControllerPpiGuid                  ## PRODUCES\r
   gPeiUsbControllerPpiGuid                      ## CONSUMES\r
+  gEdkiiIoMmuPpiGuid                            ## CONSUMES\r
+  gEfiEndOfPeiSignalPpiGuid                     ## CONSUMES\r
 \r
 \r
 [Depex]\r