]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c
MdeModulePkg UhciPei: Support IoMmu
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / UhciPei / UhcPeim.c
index 368b75d75304b817b7981eb41115b144b4567d9f..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 - 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
@@ -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
@@ -3120,7 +3196,7 @@ UhcFreePool (
       StartBitPos   = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) % 8);\r
 \r
       //\r
-      // reset associated bits in bit arry\r
+      // reset associated bits in bit array\r
       //\r
       for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {\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