From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) (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 CC05321BC6A7F for ; Sun, 26 Mar 2017 22:31:35 -0700 (PDT) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga105.jf.intel.com with ESMTP; 26 Mar 2017 22:31:35 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.36,229,1486454400"; d="scan'208";a="1147288951" Received: from fmsmsx107.amr.corp.intel.com ([10.18.124.205]) by fmsmga002.fm.intel.com with ESMTP; 26 Mar 2017 22:31:35 -0700 Received: from fmsmsx122.amr.corp.intel.com (10.18.125.37) by fmsmsx107.amr.corp.intel.com (10.18.124.205) with Microsoft SMTP Server (TLS) id 14.3.319.2; Sun, 26 Mar 2017 22:31:34 -0700 Received: from shsmsx151.ccr.corp.intel.com (10.239.6.50) by fmsmsx122.amr.corp.intel.com (10.18.125.37) with Microsoft SMTP Server (TLS) id 14.3.319.2; Sun, 26 Mar 2017 22:31:34 -0700 Received: from shsmsx104.ccr.corp.intel.com ([169.254.5.42]) by SHSMSX151.ccr.corp.intel.com ([169.254.3.82]) with mapi id 14.03.0248.002; Mon, 27 Mar 2017 13:31:30 +0800 From: "Ni, Ruiyu" To: "Yao, Jiewen" , "edk2-devel@lists.01.org" CC: Leo Duran , Brijesh Singh Thread-Topic: [RFC] [PATCH 2/3] MdeModulePkg/PciHostBridge: Add IOMMU support. Thread-Index: AQHSpUo5Bwnazdcy4ESkdN1jNXJaVKGoBqOg Date: Mon, 27 Mar 2017 05:31:30 +0000 Message-ID: <734D49CCEBEEF84792F5B80ED585239D5B8EC254@SHSMSX104.ccr.corp.intel.com> References: <1490434122-16200-1-git-send-email-jiewen.yao@intel.com> <1490434122-16200-3-git-send-email-jiewen.yao@intel.com> In-Reply-To: <1490434122-16200-3-git-send-email-jiewen.yao@intel.com> Accept-Language: en-US, zh-CN X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [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: , X-List-Received-Date: Mon, 27 Mar 2017 05:31:36 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Jiewen, #1. In RootBridgeIoMap(), NeedMap is TRUE when: 1). Host or device doesn't support above 4GB DMA access Or 2). The memory size is not multiple of IO MMU page size For case 2), we only need to call BS.AllocatePages with AllocateAnyAddress = allocation type, but I saw you still use AllocateMaxAddress allocation type. Can we guarantee that (AllocateMaxAddress plus MaxAddress =3D MAX_UINT64) e= quals to (AllocateAnyAddress)? I thought the first combination requires to allocate = from very top physical memory, but the second (AllocateAnyAddress) doesn't have such requ= irement. #2. In InternalAllocateAlignedPagesWithAllocateType (): #a). AlignedMemory =3D ((UINTN) Memory + AlignmentMask) & ~Alignment= Mask; Can we use ALIGNED_POINTER() macro? #b). I think we do not need to free last unaligned pages. Because we = only over-allocate several pages in the beginning. Please correct me if I am wrong. #c). The function name is too long. Can we rename it to IAllocatePage= s()? The parameter Type and Alignment indicate the allocation honors Type and Alignment. Thanks/Ray > -----Original Message----- > From: Yao, Jiewen > Sent: Saturday, March 25, 2017 5:29 PM > To: edk2-devel@lists.01.org > Cc: Ni, Ruiyu ; Leo Duran ; > Brijesh Singh > Subject: [RFC] [PATCH 2/3] MdeModulePkg/PciHostBridge: Add IOMMU > support. >=20 > 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. >=20 > PciHostBridge does not set IOMMU attribute because it does not know > which device request the DMA. This work is done by PciBus driver. >=20 > 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(-) >=20 > diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c > b/MdeModulePkg/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 apertur= e. >=20 > diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf > b/MdeModulePkg/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/MdeModulePkg/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/MdeModulePkg/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 specifie= d > 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 > + satisfy the request, then NULL is returned. > + If Alignment is not a power of two and Alignment is not zero, then > ASSERT(). > + 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 allocatio= n. > Must be a power of two. > + If Alignment is zero, then byte alignmen= t 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 tha= n 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 > overflow. > + // > + ASSERT (RealPages > Pages); > + > + Memory =3D *Address; > + Status =3D gBS->AllocatePages (Type, MemoryType, RealPages, > &Memory); > + 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_TO_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 || DeviceAddr= ess =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 abo= ve > @@ -1113,15 +1258,18 @@ RootBridgeIoMap ( > MapInfo->NumberOfBytes =3D *NumberOfBytes; > MapInfo->NumberOfPages =3D EFI_SIZE_TO_PAGES (MapInfo- > >NumberOfBytes); > 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->MappedNumberOfBytes); >=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 > -- > 2.7.4.windows.1