From 8284b1791ea99416db42075626d7098fa4f89598 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Mon, 20 Nov 2017 15:44:39 +0800 Subject: [PATCH] MdeModulePkg UhciPei: Support IoMmu 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 Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao --- MdeModulePkg/Bus/Pci/UhciPei/DmaMem.c | 251 ++++++++++++++ MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c | 398 +++++++++++++++++------ MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.h | 164 +++++++++- MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf | 5 +- 4 files changed, 719 insertions(+), 99 deletions(-) create mode 100644 MdeModulePkg/Bus/Pci/UhciPei/DmaMem.c diff --git a/MdeModulePkg/Bus/Pci/UhciPei/DmaMem.c b/MdeModulePkg/Bus/Pci/UhciPei/DmaMem.c new file mode 100644 index 0000000000..c92bee4298 --- /dev/null +++ b/MdeModulePkg/Bus/Pci/UhciPei/DmaMem.c @@ -0,0 +1,251 @@ +/** @file +The DMA memory help functions. + +Copyright (c) 2017, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions +of the BSD License which accompanies this distribution. The +full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UhcPeim.h" + +/** + Provides the controller-specific addresses required to access system memory from a + DMA bus master. + + @param IoMmu Pointer to IOMMU PPI. + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +EFI_STATUS +IoMmuMap ( + IN EDKII_IOMMU_PPI *IoMmu, + IN EDKII_IOMMU_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + UINT64 Attribute; + + if (IoMmu != NULL) { + Status = IoMmu->Map ( + IoMmu, + Operation, + HostAddress, + NumberOfBytes, + DeviceAddress, + Mapping + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + switch (Operation) { + case EdkiiIoMmuOperationBusMasterRead: + case EdkiiIoMmuOperationBusMasterRead64: + Attribute = EDKII_IOMMU_ACCESS_READ; + break; + case EdkiiIoMmuOperationBusMasterWrite: + case EdkiiIoMmuOperationBusMasterWrite64: + Attribute = EDKII_IOMMU_ACCESS_WRITE; + break; + case EdkiiIoMmuOperationBusMasterCommonBuffer: + case EdkiiIoMmuOperationBusMasterCommonBuffer64: + Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE; + break; + default: + ASSERT(FALSE); + return EFI_INVALID_PARAMETER; + } + Status = IoMmu->SetAttribute ( + IoMmu, + *Mapping, + Attribute + ); + if (EFI_ERROR (Status)) { + IoMmu->Unmap (IoMmu, Mapping); + *Mapping = NULL; + return Status; + } + } else { + *DeviceAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress; + *Mapping = NULL; + Status = EFI_SUCCESS; + } + return Status; +} + +/** + Completes the Map() operation and releases any corresponding resources. + + @param IoMmu Pointer to IOMMU PPI. + @param Mapping The mapping value returned from Map(). + +**/ +VOID +IoMmuUnmap ( + IN EDKII_IOMMU_PPI *IoMmu, + IN VOID *Mapping + ) +{ + if (IoMmu != NULL) { + IoMmu->SetAttribute (IoMmu, Mapping, 0); + IoMmu->Unmap (IoMmu, Mapping); + } +} + +/** + Allocates pages that are suitable for an OperationBusMasterCommonBuffer or + OperationBusMasterCommonBuffer64 mapping. + + @param IoMmu Pointer to IOMMU PPI. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +IoMmuAllocateBuffer ( + IN EDKII_IOMMU_PPI *IoMmu, + IN UINTN Pages, + OUT VOID **HostAddress, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + UINTN NumberOfBytes; + EFI_PHYSICAL_ADDRESS HostPhyAddress; + + *HostAddress = NULL; + *DeviceAddress = 0; + *Mapping = NULL; + + if (IoMmu != NULL) { + Status = IoMmu->AllocateBuffer ( + IoMmu, + EfiBootServicesData, + Pages, + HostAddress, + 0 + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + NumberOfBytes = EFI_PAGES_TO_SIZE (Pages); + Status = IoMmu->Map ( + IoMmu, + EdkiiIoMmuOperationBusMasterCommonBuffer, + *HostAddress, + &NumberOfBytes, + DeviceAddress, + Mapping + ); + if (EFI_ERROR (Status)) { + IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress); + *HostAddress = NULL; + return EFI_OUT_OF_RESOURCES; + } + Status = IoMmu->SetAttribute ( + IoMmu, + *Mapping, + EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE + ); + if (EFI_ERROR (Status)) { + IoMmu->Unmap (IoMmu, *Mapping); + IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress); + *Mapping = NULL; + *HostAddress = NULL; + return Status; + } + } else { + Status = PeiServicesAllocatePages ( + EfiBootServicesData, + Pages, + &HostPhyAddress + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + *HostAddress = (VOID *) (UINTN) HostPhyAddress; + *DeviceAddress = HostPhyAddress; + *Mapping = NULL; + } + return Status; +} + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param IoMmu Pointer to IOMMU PPI. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + @param Mapping The mapping value returned from Map(). + +**/ +VOID +IoMmuFreeBuffer ( + IN EDKII_IOMMU_PPI *IoMmu, + IN UINTN Pages, + IN VOID *HostAddress, + IN VOID *Mapping + ) +{ + if (IoMmu != NULL) { + IoMmu->SetAttribute (IoMmu, Mapping, 0); + IoMmu->Unmap (IoMmu, Mapping); + IoMmu->FreeBuffer (IoMmu, Pages, HostAddress); + } +} + +/** + Initialize IOMMU. + + @param IoMmu Pointer to pointer to IOMMU PPI. + +**/ +VOID +IoMmuInit ( + OUT EDKII_IOMMU_PPI **IoMmu + ) +{ + *IoMmu = NULL; + PeiServicesLocatePpi ( + &gEdkiiIoMmuPpiGuid, + 0, + NULL, + (VOID **) IoMmu + ); +} + diff --git a/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c b/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c index 37b2124c67..b7d60db0c9 100644 --- a/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c +++ b/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c @@ -2,7 +2,7 @@ PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid which is used to enable recovery function from USB Drivers. -Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions @@ -17,6 +17,78 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "UhcPeim.h" +/** + Stop the host controller. + + @param Uhc The UHCI device. + @param Timeout Max time allowed. + + @retval EFI_SUCCESS The host controller is stopped. + @retval EFI_TIMEOUT Failed to stop the host controller. + +**/ +EFI_STATUS +UhciStopHc ( + IN USB_UHC_DEV *Uhc, + IN UINTN Timeout + ) +{ + UINT16 CommandContent; + UINT16 UsbSts; + UINTN Index; + + CommandContent = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD); + CommandContent &= USBCMD_RS; + USBWritePortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD, CommandContent); + + // + // ensure the HC is in halt status after send the stop command + // Timeout is in us unit. + // + for (Index = 0; Index < (Timeout / 50) + 1; Index++) { + UsbSts = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBSTS); + + if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) { + return EFI_SUCCESS; + } + + MicroSecondDelay (50); + } + + return EFI_TIMEOUT; +} + +/** + One notified function to stop the Host Controller at the end of PEI + + @param[in] PeiServices Pointer to PEI Services Table. + @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that + caused this function to execute. + @param[in] Ppi Pointer to the PPI data associated with this function. + + @retval EFI_SUCCESS The function completes successfully + @retval others +**/ +EFI_STATUS +EFIAPI +UhcEndOfPei ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + USB_UHC_DEV *Uhc; + + Uhc = PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor); + + // + // Stop the Host Controller + // + UhciStopHc (Uhc, 1000 * 1000); + + return EFI_SUCCESS; +} + /** Initializes Usb Host Controller. @@ -98,6 +170,7 @@ UhcPeimEntry ( UhcDev = (USB_UHC_DEV *) ((UINTN) TempPtr); UhcDev->Signature = USB_UHC_DEV_SIGNATURE; + IoMmuInit (&UhcDev->IoMmu); UhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress; // @@ -133,6 +206,12 @@ UhcPeimEntry ( continue; } + UhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); + UhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid; + UhcDev->EndOfPeiNotifyList.Notify = UhcEndOfPei; + + PeiServicesNotifyPpi (&UhcDev->EndOfPeiNotifyList); + Index++; } @@ -190,9 +269,11 @@ UhcControlTransfer ( TD_STRUCT *PtrStatusTD; EFI_STATUS Status; UINT32 DataLen; - UINT8 *PtrDataSource; - UINT8 *Ptr; UINT8 DataToggle; + UINT8 *RequestPhy; + VOID *RequestMap; + UINT8 *DataPhy; + VOID *DataMap; UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This); @@ -216,6 +297,24 @@ UhcControlTransfer ( ClearStatusReg (UhcDev, StatusReg); + // + // Map the Request and data for bus master access, + // then create a list of TD for this transfer + // + Status = UhciMapUserRequest (UhcDev, Request, &RequestPhy, &RequestMap); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap); + + if (EFI_ERROR (Status)) { + if (RequestMap != NULL) { + IoMmuUnmap (UhcDev->IoMmu, RequestMap); + } + return Status; + } + // // generate Setup Stage TD // @@ -228,6 +327,7 @@ UhcControlTransfer ( 0, DeviceSpeed, (UINT8 *) Request, + RequestPhy, (UINT8) sizeof (EFI_USB_DEVICE_REQUEST), &PtrSetupTD ); @@ -242,38 +342,11 @@ UhcControlTransfer ( // // Data Stage of Control Transfer // - switch (TransferDirection) { - - case EfiUsbDataIn: - PktID = INPUT_PACKET_ID; - PtrDataSource = Data; - DataLen = (UINT32) *DataLength; - Ptr = PtrDataSource; - break; - - case EfiUsbDataOut: - PktID = OUTPUT_PACKET_ID; - PtrDataSource = Data; - DataLen = (UINT32) *DataLength; - Ptr = PtrDataSource; - break; - - // - // no data stage - // - case EfiUsbNoData: - if (*DataLength != 0) { - return EFI_INVALID_PARAMETER; - } - - PktID = OUTPUT_PACKET_ID; - PtrDataSource = NULL; - DataLen = 0; - Ptr = NULL; - break; - default: - return EFI_INVALID_PARAMETER; + if (TransferDirection == EfiUsbNoData) { + DataLen = 0; + } else { + DataLen = (UINT32) *DataLength; } DataToggle = 1; @@ -297,7 +370,8 @@ UhcControlTransfer ( UhcDev, DeviceAddress, 0, - Ptr, + Data, + DataPhy, PacketSize, PktID, DataToggle, @@ -312,7 +386,8 @@ UhcControlTransfer ( PtrPreTD = PtrTD; DataToggle ^= 1; - Ptr += PacketSize; + Data = (VOID *) ((UINT8 *) Data + PacketSize); + DataPhy += PacketSize; DataLen -= PacketSize; } @@ -365,14 +440,19 @@ UhcControlTransfer ( // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly. // if (!IsStatusOK (UhcDev, StatusReg)) { - - ClearStatusReg (UhcDev, StatusReg); *TransferResult |= EFI_USB_ERR_SYSTEM; - return EFI_DEVICE_ERROR; + Status = EFI_DEVICE_ERROR; } ClearStatusReg (UhcDev, StatusReg); + if (DataMap != NULL) { + IoMmuUnmap (UhcDev->IoMmu, DataMap); + } + if (RequestMap != NULL) { + IoMmuUnmap (UhcDev->IoMmu, RequestMap); + } + return Status; } @@ -431,8 +511,6 @@ UhcBulkTransfer ( TD_STRUCT *PtrPreTD; UINT8 PktID; - UINT8 *PtrDataSource; - UINT8 *Ptr; BOOLEAN IsFirstTD; @@ -444,6 +522,9 @@ UhcBulkTransfer ( UINT16 CommandContent; + UINT8 *DataPhy; + VOID *DataMap; + UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This); // @@ -467,7 +548,6 @@ UhcBulkTransfer ( PtrFirstTD = NULL; PtrPreTD = NULL; DataLen = 0; - Ptr = NULL; ShortPacketEnable = FALSE; @@ -495,33 +575,24 @@ UhcBulkTransfer ( ClearStatusReg (UhcDev, StatusReg); + // + // Map the source data buffer for bus master access, + // then create a list of TDs + // if ((EndPointAddress & 0x80) != 0) { TransferDirection = EfiUsbDataIn; } else { TransferDirection = EfiUsbDataOut; } - switch (TransferDirection) { + Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap); - case EfiUsbDataIn: - ShortPacketEnable = TRUE; - PktID = INPUT_PACKET_ID; - PtrDataSource = Data; - DataLen = (UINT32) *DataLength; - Ptr = PtrDataSource; - break; - - case EfiUsbDataOut: - PktID = OUTPUT_PACKET_ID; - PtrDataSource = Data; - DataLen = (UINT32) *DataLength; - Ptr = PtrDataSource; - break; - - default: - break; + if (EFI_ERROR (Status)) { + return Status; } + DataLen = (UINT32) *DataLength; + PtrQH = UhcDev->BulkQH; IsFirstTD = TRUE; @@ -540,7 +611,8 @@ UhcBulkTransfer ( UhcDev, DeviceAddress, EndPointAddress, - Ptr, + Data, + DataPhy, PacketSize, PktID, *DataToggle, @@ -570,7 +642,8 @@ UhcBulkTransfer ( PtrPreTD = PtrTD; *DataToggle ^= 1; - Ptr += PacketSize; + Data = (VOID *) ((UINT8 *) Data + PacketSize); + DataPhy += PacketSize; DataLen -= PacketSize; } // @@ -604,14 +677,16 @@ UhcBulkTransfer ( // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly. // if (!IsStatusOK (UhcDev, StatusReg)) { - - ClearStatusReg (UhcDev, StatusReg); *TransferResult |= EFI_USB_ERR_SYSTEM; - return EFI_DEVICE_ERROR; + Status = EFI_DEVICE_ERROR; } ClearStatusReg (UhcDev, StatusReg); + if (DataMap != NULL) { + IoMmuUnmap (UhcDev->IoMmu, DataMap); + } + return Status; } @@ -1492,7 +1567,8 @@ CreateTD ( @param DevAddr Device address. @param Endpoint Endpoint number. @param DeviceSpeed Device Speed. - @param DevRequest Device reuquest. + @param DevRequest CPU memory address of request structure buffer to transfer. + @param RequestPhy PCI memory address of request structure buffer to transfer. @param RequestLen Request length. @param PtrTD TD_STRUCT generated. @@ -1507,6 +1583,7 @@ GenSetupStageTD ( IN UINT8 Endpoint, IN UINT8 DeviceSpeed, IN UINT8 *DevRequest, + IN UINT8 *RequestPhy, IN UINT8 RequestLen, OUT TD_STRUCT **PtrTD ) @@ -1583,7 +1660,11 @@ GenSetupStageTD ( TdStruct->PtrTDBuffer = (UINT8 *) DevRequest; TdStruct->TDBufferLength = RequestLen; - SetTDDataBuffer (TdStruct); + // + // Set the beginning address of the buffer that will be used + // during the transaction. + // + TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) RequestPhy; *PtrTD = TdStruct; @@ -1596,7 +1677,8 @@ GenSetupStageTD ( @param UhcDev The UHCI device. @param DevAddr Device address. @param Endpoint Endpoint number. - @param PtrData Data buffer. + @param PtrData CPU memory address of user data buffer to transfer. + @param DataPhy PCI memory address of user data buffer to transfer. @param Len Data length. @param PktID PacketID. @param Toggle Data toggle value. @@ -1613,6 +1695,7 @@ GenDataTD ( IN UINT8 DevAddr, IN UINT8 Endpoint, IN UINT8 *PtrData, + IN UINT8 *DataPhy, IN UINT8 Len, IN UINT8 PktID, IN UINT8 Toggle, @@ -1700,7 +1783,11 @@ GenDataTD ( TdStruct->PtrTDBuffer = (UINT8 *) PtrData; TdStruct->TDBufferLength = Len; - SetTDDataBuffer (TdStruct); + // + // Set the beginning address of the buffer that will be used + // during the transaction. + // + TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) DataPhy; *PtrTD = TdStruct; @@ -1803,7 +1890,11 @@ CreateStatusTD ( PtrTDStruct->PtrTDBuffer = NULL; PtrTDStruct->TDBufferLength = 0; - SetTDDataBuffer (PtrTDStruct); + // + // Set the beginning address of the buffer that will be used + // during the transaction. + // + PtrTDStruct->TDData.TDBufferPtr = 0; *PtrTD = PtrTDStruct; @@ -2173,25 +2264,6 @@ SetTDTokenPacketID ( PtrTDStruct->TDData.TDTokenPID = PacketID; } -/** - Set the beginning address of the data buffer that will be used - during the transaction. - - @param PtrTDStruct Place to store TD_STRUCT pointer. - -**/ -VOID -SetTDDataBuffer ( - IN TD_STRUCT *PtrTDStruct - ) -{ - // - // Set the beginning address of the data buffer that will be used - // during the transaction. - // - PtrTDStruct->TDData.TDBufferPtr = (UINT32) (UINTN) (PtrTDStruct->PtrTDBuffer); -} - /** Detect whether the TD is active. @@ -2773,25 +2845,29 @@ CreateMemoryBlock ( ) { EFI_STATUS Status; - EFI_PHYSICAL_ADDRESS TempPtr; + UINT8 *TempPtr; UINTN MemPages; UINT8 *Ptr; + VOID *Mapping; + EFI_PHYSICAL_ADDRESS MappedAddr; // // Memory Block uses MemoryBlockSizeInPages pages, // memory management header and bit array use 1 page // MemPages = MemoryBlockSizeInPages + 1; - Status = PeiServicesAllocatePages ( - EfiBootServicesData, + Status = IoMmuAllocateBuffer ( + UhcDev->IoMmu, MemPages, - &TempPtr + (VOID **) &TempPtr, + &MappedAddr, + &Mapping ); if (EFI_ERROR (Status)) { return Status; } - Ptr = (UINT8 *) ((UINTN) TempPtr); + Ptr = TempPtr; ZeroMem (Ptr, MemPages * EFI_PAGE_SIZE); @@ -2810,7 +2886,7 @@ CreateMemoryBlock ( // // Memory block initial address // - Ptr = (UINT8 *) ((UINTN) TempPtr); + Ptr = TempPtr; Ptr += EFI_PAGE_SIZE; (*MemoryHeader)->MemoryBlockPtr = Ptr; // @@ -3217,3 +3293,135 @@ DelinkMemoryBlock ( } } } + +/** + Map address of request structure buffer. + + @param Uhc The UHCI device. + @param Request The user request buffer. + @param MappedAddr Mapped address of request. + @param Map Identificaion of this mapping to return. + + @return EFI_SUCCESS Success. + @return EFI_DEVICE_ERROR Fail to map the user request. + +**/ +EFI_STATUS +UhciMapUserRequest ( + IN USB_UHC_DEV *Uhc, + IN OUT VOID *Request, + OUT UINT8 **MappedAddr, + OUT VOID **Map + ) +{ + EFI_STATUS Status; + UINTN Len; + EFI_PHYSICAL_ADDRESS PhyAddr; + + Len = sizeof (EFI_USB_DEVICE_REQUEST); + Status = IoMmuMap ( + Uhc->IoMmu, + EdkiiIoMmuOperationBusMasterRead, + Request, + &Len, + &PhyAddr, + Map + ); + + if (!EFI_ERROR (Status)) { + *MappedAddr = (UINT8 *) (UINTN) PhyAddr; + } + + return Status; +} + +/** + Map address of user data buffer. + + @param Uhc The UHCI device. + @param Direction Direction of the data transfer. + @param Data The user data buffer. + @param Len Length of the user data. + @param PktId Packet identificaion. + @param MappedAddr Mapped address to return. + @param Map Identificaion of this mapping to return. + + @return EFI_SUCCESS Success. + @return EFI_DEVICE_ERROR Fail to map the user data. + +**/ +EFI_STATUS +UhciMapUserData ( + IN USB_UHC_DEV *Uhc, + IN EFI_USB_DATA_DIRECTION Direction, + IN VOID *Data, + IN OUT UINTN *Len, + OUT UINT8 *PktId, + OUT UINT8 **MappedAddr, + OUT VOID **Map + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhyAddr; + + Status = EFI_SUCCESS; + + switch (Direction) { + case EfiUsbDataIn: + // + // BusMasterWrite means cpu read + // + *PktId = INPUT_PACKET_ID; + Status = IoMmuMap ( + Uhc->IoMmu, + EdkiiIoMmuOperationBusMasterWrite, + Data, + Len, + &PhyAddr, + Map + ); + + if (EFI_ERROR (Status)) { + goto EXIT; + } + + *MappedAddr = (UINT8 *) (UINTN) PhyAddr; + break; + + case EfiUsbDataOut: + *PktId = OUTPUT_PACKET_ID; + Status = IoMmuMap ( + Uhc->IoMmu, + EdkiiIoMmuOperationBusMasterRead, + Data, + Len, + &PhyAddr, + Map + ); + + if (EFI_ERROR (Status)) { + goto EXIT; + } + + *MappedAddr = (UINT8 *) (UINTN) PhyAddr; + break; + + case EfiUsbNoData: + if ((Len != NULL) && (*Len != 0)) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + *PktId = OUTPUT_PACKET_ID; + *MappedAddr = NULL; + *Map = NULL; + break; + + default: + Status = EFI_INVALID_PARAMETER; + } + +EXIT: + return Status; +} + diff --git a/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.h b/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.h index 460db7eab9..9935f522cd 100644 --- a/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.h +++ b/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.h @@ -1,7 +1,7 @@ /** @file Private Header file for Usb Host Controller PEIM -Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions @@ -22,6 +22,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include +#include +#include #include #include @@ -177,7 +179,13 @@ struct _MEMORY_MANAGE_HEADER { typedef struct { UINTN Signature; PEI_USB_HOST_CONTROLLER_PPI UsbHostControllerPpi; + EDKII_IOMMU_PPI *IoMmu; EFI_PEI_PPI_DESCRIPTOR PpiDescriptor; + // + // EndOfPei callback is used to stop the UHC DMA operation + // after exit PEI phase. + // + EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList; UINT32 UsbHostControllerBaseAddress; FRAMELIST_ENTRY *FrameListEntry; @@ -191,6 +199,7 @@ typedef struct { } USB_UHC_DEV; #define PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS(a) CR (a, USB_UHC_DEV, UsbHostControllerPpi, USB_UHC_DEV_SIGNATURE) +#define PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY(a) CR (a, USB_UHC_DEV, EndOfPeiNotifyList, USB_UHC_DEV_SIGNATURE) /** Submits control transfer to a target USB device. @@ -654,7 +663,8 @@ CreateTD ( @param DevAddr Device address. @param Endpoint Endpoint number. @param DeviceSpeed Device Speed. - @param DevRequest Device reuquest. + @param DevRequest CPU memory address of request structure buffer to transfer. + @param RequestPhy PCI memory address of request structure buffer to transfer. @param RequestLen Request length. @param PtrTD TD_STRUCT generated. @@ -669,6 +679,7 @@ GenSetupStageTD ( IN UINT8 Endpoint, IN UINT8 DeviceSpeed, IN UINT8 *DevRequest, + IN UINT8 *RequestPhy, IN UINT8 RequestLen, OUT TD_STRUCT **PtrTD ); @@ -679,7 +690,8 @@ GenSetupStageTD ( @param UhcDev The UHCI device. @param DevAddr Device address. @param Endpoint Endpoint number. - @param PtrData Data buffer. + @param PtrData CPU memory address of user data buffer to transfer. + @param DataPhy PCI memory address of user data buffer to transfer. @param Len Data length. @param PktID PacketID. @param Toggle Data toggle value. @@ -696,6 +708,7 @@ GenDataTD ( IN UINT8 DevAddr, IN UINT8 Endpoint, IN UINT8 *PtrData, + IN UINT8 *DataPhy, IN UINT8 Len, IN UINT8 PktID, IN UINT8 Toggle, @@ -1330,4 +1343,149 @@ DelinkMemoryBlock ( IN MEMORY_MANAGE_HEADER *FreeMemoryHeader ); +/** + Map address of request structure buffer. + + @param Uhc The UHCI device. + @param Request The user request buffer. + @param MappedAddr Mapped address of request. + @param Map Identificaion of this mapping to return. + + @return EFI_SUCCESS Success. + @return EFI_DEVICE_ERROR Fail to map the user request. + +**/ +EFI_STATUS +UhciMapUserRequest ( + IN USB_UHC_DEV *Uhc, + IN OUT VOID *Request, + OUT UINT8 **MappedAddr, + OUT VOID **Map + ); + +/** + Map address of user data buffer. + + @param Uhc The UHCI device. + @param Direction Direction of the data transfer. + @param Data The user data buffer. + @param Len Length of the user data. + @param PktId Packet identificaion. + @param MappedAddr Mapped address to return. + @param Map Identificaion of this mapping to return. + + @return EFI_SUCCESS Success. + @return EFI_DEVICE_ERROR Fail to map the user data. + +**/ +EFI_STATUS +UhciMapUserData ( + IN USB_UHC_DEV *Uhc, + IN EFI_USB_DATA_DIRECTION Direction, + IN VOID *Data, + IN OUT UINTN *Len, + OUT UINT8 *PktId, + OUT UINT8 **MappedAddr, + OUT VOID **Map + ); + +/** + Provides the controller-specific addresses required to access system memory from a + DMA bus master. + + @param IoMmu Pointer to IOMMU PPI. + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +EFI_STATUS +IoMmuMap ( + IN EDKII_IOMMU_PPI *IoMmu, + IN EDKII_IOMMU_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Completes the Map() operation and releases any corresponding resources. + + @param IoMmu Pointer to IOMMU PPI. + @param Mapping The mapping value returned from Map(). + +**/ +VOID +IoMmuUnmap ( + IN EDKII_IOMMU_PPI *IoMmu, + IN VOID *Mapping + ); + +/** + Allocates pages that are suitable for an OperationBusMasterCommonBuffer or + OperationBusMasterCommonBuffer64 mapping. + + @param IoMmu Pointer to IOMMU PPI. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +IoMmuAllocateBuffer ( + IN EDKII_IOMMU_PPI *IoMmu, + IN UINTN Pages, + OUT VOID **HostAddress, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param IoMmu Pointer to IOMMU PPI. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + @param Mapping The mapping value returned from Map(). + +**/ +VOID +IoMmuFreeBuffer ( + IN EDKII_IOMMU_PPI *IoMmu, + IN UINTN Pages, + IN VOID *HostAddress, + IN VOID *Mapping + ); + +/** + Initialize IOMMU. + + @param IoMmu Pointer to pointer to IOMMU PPI. + +**/ +VOID +IoMmuInit ( + OUT EDKII_IOMMU_PPI **IoMmu + ); + #endif diff --git a/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf b/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf index 7baa07612d..95ddea2162 100644 --- a/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf +++ b/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf @@ -4,7 +4,7 @@ # It produces gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid which is used # to enable recovery function from USB Drivers. # -# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions @@ -36,6 +36,7 @@ [Sources] UhcPeim.c UhcPeim.h + DmaMem.c [Packages] @@ -55,6 +56,8 @@ [Ppis] gPeiUsbHostControllerPpiGuid ## PRODUCES gPeiUsbControllerPpiGuid ## CONSUMES + gEdkiiIoMmuPpiGuid ## CONSUMES + gEfiEndOfPeiSignalPpiGuid ## CONSUMES [Depex] -- 2.39.2