From nobody Sat Nov 2 12:27:19 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zoho.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1490434138318297.44068916392894; Sat, 25 Mar 2017 02:28:58 -0700 (PDT) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 4239F21DFA916; Sat, 25 Mar 2017 02:28:55 -0700 (PDT) Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 31BC321DFA7B4 for ; Sat, 25 Mar 2017 02:28:53 -0700 (PDT) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga104.jf.intel.com with ESMTP; 25 Mar 2017 02:28:53 -0700 Received: from jyao1-mobl.ccr.corp.intel.com ([10.254.213.212]) by orsmga003.jf.intel.com with ESMTP; 25 Mar 2017 02:28:51 -0700 X-Original-To: edk2-devel@lists.01.org X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.36,219,1486454400"; d="scan'208";a="948072138" From: Jiewen Yao To: edk2-devel@lists.01.org Date: Sat, 25 Mar 2017 17:28:41 +0800 Message-Id: <1490434122-16200-3-git-send-email-jiewen.yao@intel.com> X-Mailer: git-send-email 2.7.4.windows.1 In-Reply-To: <1490434122-16200-1-git-send-email-jiewen.yao@intel.com> References: <1490434122-16200-1-git-send-email-jiewen.yao@intel.com> Subject: [edk2] [RFC] [PATCH 2/3] MdeModulePkg/PciHostBridge: Add IOMMU support. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Ruiyu Ni , Brijesh Singh , Leo Duran MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The responsibility of PciHostBridge is to allocate IOMMU page aligned memory for Map and AllocateBuffer, because PciHostBridge driver already handles Map() request to allocate another buffer for DMA read/write. PciHostBridge does not set IOMMU attribute because it does not know which device request the DMA. This work is done by PciBus driver. Cc: Ruiyu Ni Cc: Leo Duran Cc: Brijesh Singh Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao --- MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c | 3 + MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf | 1 + MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h | 7 + MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c | 172 +++++++++= ++++++++++- 4 files changed, 178 insertions(+), 5 deletions(-) diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c b/MdeMod= ulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c index 9005dee..35233a7 100644 --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c @@ -28,6 +28,9 @@ GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mPciResourceTypeStr= [] =3D { L"I/O", L"Mem", L"PMem", L"Mem64", L"PMem64", L"Bus" }; =20 +EDKII_IOMMU_PROTOCOL *gIoMmuProtocol; +UINTN mIoMmuPageSize =3D 1; + /** Ensure the compatibility of an IO space descriptor with the IO aperture. =20 diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf b/M= deModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf index d8b0439..2d3c8c9 100644 --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf @@ -49,6 +49,7 @@ gEfiDevicePathProtocolGuid ## BY_START gEfiPciRootBridgeIoProtocolGuid ## BY_START gEfiPciHostBridgeResourceAllocationProtocolGuid ## BY_START + gEdkiiIoMmuProtocolGuid ## CONSUMES =20 [Depex] gEfiCpuIo2ProtocolGuid AND diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h b/MdeMod= ulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h index 13185b4..4d21d10 100644 --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h @@ -27,6 +27,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER= EXPRESS OR IMPLIED. #include #include #include +#include #include #include #include @@ -50,6 +51,8 @@ typedef struct { EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation; UINTN NumberOfBytes; UINTN NumberOfPages; + UINTN MappedNumberOfBytes; + UINTN MappedNumberOfPages; EFI_PHYSICAL_ADDRESS HostAddress; EFI_PHYSICAL_ADDRESS MappedHostAddress; } MAP_INFO; @@ -575,4 +578,8 @@ RootBridgeIoConfiguration ( =20 extern EFI_METRONOME_ARCH_PROTOCOL *mMetronome; extern EFI_CPU_IO2_PROTOCOL *mCpuIo; + +extern EDKII_IOMMU_PROTOCOL *gIoMmuProtocol; +extern UINTN mIoMmuPageSize; + #endif diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c b/MdeM= odulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c index 8af131b..47ea697 100644 --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c @@ -1022,6 +1022,121 @@ RootBridgeIoPciWrite ( } =20 /** + Allocates one or more 4KB pages of a certain memory type at a specified = alignment. + + Allocates the number of 4KB pages specified by Pages of a certain memory= type with an alignment + specified by Alignment. The allocated buffer is returned. If Pages is = 0, then NULL is returned. + If there is not enough memory at the specified alignment remaining to sa= tisfy the request, then + NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSER= T(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Type The type of allocation to perform. + @param MemoryType The type of memory to allocate. + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation.= Must be a power of two. + If Alignment is zero, then byte alignment = is used. + @param Address Pointer to a physical address. + + @return Memory Allocation Status. + +**/ +EFI_STATUS +InternalAllocateAlignedPagesWithAllocateType ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment, + IN OUT EFI_PHYSICAL_ADDRESS *Address + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Memory; + UINTN AlignedMemory; + UINTN AlignmentMask; + UINTN UnalignedPages; + UINTN RealPages; + + // + // Alignment must be a power of two or zero. + // + ASSERT ((Alignment & (Alignment - 1)) =3D=3D 0); + + if (Pages =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + if (Alignment > EFI_PAGE_SIZE) { + // + // Calculate the total number of pages since alignment is larger than = page size. + // + AlignmentMask =3D Alignment - 1; + RealPages =3D Pages + EFI_SIZE_TO_PAGES (Alignment); + // + // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not ov= erflow. + // + ASSERT (RealPages > Pages); + + Memory =3D *Address; + Status =3D gBS->AllocatePages (Type, MemoryType, RealPages, &M= emory); + if (EFI_ERROR (Status)) { + return Status; + } + AlignedMemory =3D ((UINTN) Memory + AlignmentMask) & ~AlignmentMask; + UnalignedPages =3D EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory); + if (UnalignedPages > 0) { + // + // Free first unaligned page(s). + // + Status =3D gBS->FreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + Memory =3D (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_T= O_SIZE (Pages)); + UnalignedPages =3D RealPages - Pages - UnalignedPages; + if (UnalignedPages > 0) { + // + // Free last unaligned page(s). + // + Status =3D gBS->FreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + } else { + // + // Do not over-allocate pages in this case. + // + Memory =3D *Address; + Status =3D gBS->AllocatePages (Type, MemoryType, Pages, &Memory); + if (EFI_ERROR (Status)) { + return Status; + } + AlignedMemory =3D (UINTN) Memory; + } + *Address =3D AlignedMemory; + return EFI_SUCCESS; +} + +/** + Return if a value is aligned. + + @param Value the value to be checked + @param Alignment the alignment to be checked with. + + @retval TRUE The value is aligned + @retval FALSE The value is not aligned. +**/ +BOOLEAN +InternalIsAlgined ( + IN UINTN Value, + IN UINTN Alignment + ) +{ + if (Value !=3D ALIGN_VALUE(Value, Alignment)) { + return FALSE; + } else { + return FALSE; + } +} + +/** Provides the PCI controller-specific address needed to access system memory for DMA. =20 @@ -1057,6 +1172,8 @@ RootBridgeIoMap ( PCI_ROOT_BRIDGE_INSTANCE *RootBridge; EFI_PHYSICAL_ADDRESS PhysicalAddress; MAP_INFO *MapInfo; + BOOLEAN NeedMap; + EFI_PHYSICAL_ADDRESS MaxAddress; =20 if (HostAddress =3D=3D NULL || NumberOfBytes =3D=3D NULL || DeviceAddres= s =3D=3D NULL || Mapping =3D=3D NULL) { @@ -1072,12 +1189,40 @@ RootBridgeIoMap ( =20 RootBridge =3D ROOT_BRIDGE_FROM_THIS (This); =20 + if (gIoMmuProtocol =3D=3D NULL) { + gBS->LocateProtocol ( + &gEdkiiIoMmuProtocolGuid, + NULL, + (VOID **) &gIoMmuProtocol + ); + if (gIoMmuProtocol !=3D NULL) { + gIoMmuProtocol->GetPageSize (gIoMmuProtocol, &mIoMmuPageSize); + ASSERT ((mIoMmuPageSize & (mIoMmuPageSize - 1)) =3D=3D 0); + } + } + PhysicalAddress =3D (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress; + + NeedMap =3D FALSE; + MaxAddress =3D (UINT64)-1; + if ((!RootBridge->DmaAbove4G || (Operation !=3D EfiPciOperationBusMasterRead64 && Operation !=3D EfiPciOperationBusMasterWrite64 && Operation !=3D EfiPciOperationBusMasterCommonBuffer64)) && ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) { + NeedMap =3D TRUE; + MaxAddress =3D SIZE_4GB - 1; + } + + if (gIoMmuProtocol !=3D NULL) { + if ((!InternalIsAlgined (*NumberOfBytes, mIoMmuPageSize)) || + (!InternalIsAlgined ((UINTN)HostAddress, mIoMmuPageSize))) { + NeedMap =3D TRUE; + } + } + + if (NeedMap) { =20 // // If the root bridge or the device cannot handle performing DMA above @@ -1113,15 +1258,18 @@ RootBridgeIoMap ( MapInfo->NumberOfBytes =3D *NumberOfBytes; MapInfo->NumberOfPages =3D EFI_SIZE_TO_PAGES (MapInfo->NumberOfByt= es); MapInfo->HostAddress =3D PhysicalAddress; - MapInfo->MappedHostAddress =3D SIZE_4GB - 1; + MapInfo->MappedHostAddress =3D MaxAddress; + MapInfo->MappedNumberOfBytes =3D ALIGN_VALUE (MapInfo->NumberOfBytes, = mIoMmuPageSize); + MapInfo->MappedNumberOfPages =3D EFI_SIZE_TO_PAGES (MapInfo->MappedNum= berOfBytes); =20 // // Allocate a buffer below 4GB to map the transfer to. // - Status =3D gBS->AllocatePages ( + Status =3D InternalAllocateAlignedPagesWithAllocateType ( AllocateMaxAddress, EfiBootServicesData, - MapInfo->NumberOfPages, + MapInfo->MappedNumberOfPages, + mIoMmuPageSize, &MapInfo->MappedHostAddress ); if (EFI_ERROR (Status)) { @@ -1240,7 +1388,7 @@ RootBridgeIoUnmap ( // // Free the mapped buffer and the MAP_INFO structure. // - gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->NumberOfPages); + gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->MappedNumberOfPages= ); FreePool (Mapping); return EFI_SUCCESS; } @@ -1286,6 +1434,7 @@ RootBridgeIoAllocateBuffer ( EFI_PHYSICAL_ADDRESS PhysicalAddress; PCI_ROOT_BRIDGE_INSTANCE *RootBridge; EFI_ALLOCATE_TYPE AllocateType; + UINTN Size; =20 // // Validate Attributes @@ -1321,10 +1470,16 @@ RootBridgeIoAllocateBuffer ( AllocateType =3D AllocateMaxAddress; PhysicalAddress =3D (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1); } - Status =3D gBS->AllocatePages ( + if (gIoMmuProtocol !=3D NULL) { + Size =3D EFI_PAGES_TO_SIZE(Pages); + Size =3D ALIGN_VALUE(EFI_PAGES_TO_SIZE(Pages), mIoMmuPageSize); + Pages =3D EFI_SIZE_TO_PAGES (Size); + } + Status =3D InternalAllocateAlignedPagesWithAllocateType ( AllocateType, MemoryType, Pages, + mIoMmuPageSize, &PhysicalAddress ); if (!EFI_ERROR (Status)) { @@ -1356,6 +1511,13 @@ RootBridgeIoFreeBuffer ( OUT VOID *HostAddress ) { + UINTN Size; + + if (gIoMmuProtocol !=3D NULL) { + Size =3D EFI_PAGES_TO_SIZE(Pages); + Size =3D ALIGN_VALUE(EFI_PAGES_TO_SIZE(Pages), mIoMmuPageSize); + Pages =3D EFI_SIZE_TO_PAGES (Size); + } return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages= ); } =20 --=20 2.7.4.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel