Message ID | 1519282474-94811-2-git-send-email-heyi.guo@linaro.org |
---|---|
State | New |
Headers | show |
Series | Add translation support to generic PCIHostBridge | expand |
On 2/22/2018 2:54 PM, Heyi Guo wrote: > This is the draft patch for the discussion posted in edk2-devel > mailing list: > https://lists.01.org/pipermail/edk2-devel/2017-December/019289.html > > As discussed in the mailing list, we'd like to add support for PCI > address translation which is necessary for some non-x86 platforms. I > also want to minimize the changes to the generic host bridge driver > and platform PciHostBridgeLib implemetations, so additional two > interfaces are added to expose translation information of the > platform. To be generic, I add translation for each type of IO or > memory resources. > > The patch is still a RFC, so I only passed the build for qemu64 and > the function has not been tested yet. > > Please let me know your comments about it. > > Thanks. > > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Heyi Guo <heyi.guo@linaro.org> > Cc: Ruiyu Ni <ruiyu.ni@intel.com> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> > Cc: Star Zeng <star.zeng@intel.com> > Cc: Eric Dong <eric.dong@intel.com> > Cc: Laszlo Ersek <lersek@redhat.com> > Cc: Michael D Kinney <michael.d.kinney@intel.com> > --- > .../Bus/Pci/PciHostBridgeDxe/PciHostBridge.c | 57 ++++++++---- > .../Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c | 101 ++++++++++++++++++--- > MdeModulePkg/Include/Library/PciHostBridgeLib.h | 1 + > 3 files changed, 131 insertions(+), 28 deletions(-) > > diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c > index 1494848..fa22d8d 100644 > --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c > +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c > @@ -32,6 +32,29 @@ EDKII_IOMMU_PROTOCOL *mIoMmuProtocol; > EFI_EVENT mIoMmuEvent; > VOID *mIoMmuRegistration; > > +STATIC > +UINT64 > +GetTranslationByResourceType ( > + IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge, > + IN PCI_RESOURCE_TYPE ResourceType > + ) > +{ > + switch (ResourceType) { > + case TypeIo: > + return RootBridge->Io.Translation; > + case TypeMem32: > + return RootBridge->Mem.Translation; > + case TypePMem32: > + return RootBridge->PMem.Translation; > + case TypeMem64: > + return RootBridge->MemAbove4G.Translation; > + case TypePMem64: > + return RootBridge->PMemAbove4G.Translation; > + default: > + return 0; > + } > +} > + > /** > Ensure the compatibility of an IO space descriptor with the IO aperture. > > @@ -412,7 +435,7 @@ InitializePciHostBridge ( > > if (RootBridges[Index].Io.Base <= RootBridges[Index].Io.Limit) { > Status = AddIoSpace ( > - RootBridges[Index].Io.Base, > + RootBridges[Index].Io.Base + RootBridges[Index].Io.Translation, > RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1 > ); > ASSERT_EFI_ERROR (Status); > @@ -422,7 +445,7 @@ InitializePciHostBridge ( > EfiGcdIoTypeIo, > 0, > RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1, > - &RootBridges[Index].Io.Base, > + &RootBridges[Index].Io.Base + RootBridges[Index].Io.Translation, > gImageHandle, > NULL > ); > @@ -444,13 +467,13 @@ InitializePciHostBridge ( > for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) { > if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) { > Status = AddMemoryMappedIoSpace ( > - MemApertures[MemApertureIndex]->Base, > + MemApertures[MemApertureIndex]->Base + MemApertures[MemApertureIndex]->Translation, > MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1, > EFI_MEMORY_UC > ); > ASSERT_EFI_ERROR (Status); > Status = gDS->SetMemorySpaceAttributes ( > - MemApertures[MemApertureIndex]->Base, > + MemApertures[MemApertureIndex]->Base + MemApertures[MemApertureIndex]->Translation, > MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1, > EFI_MEMORY_UC > ); > @@ -463,7 +486,7 @@ InitializePciHostBridge ( > EfiGcdMemoryTypeMemoryMappedIo, > 0, > MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1, > - &MemApertures[MemApertureIndex]->Base, > + &MemApertures[MemApertureIndex]->Base + MemApertures[MemApertureIndex]->Translation, > gImageHandle, > NULL > ); > @@ -828,8 +851,8 @@ NotifyPhase ( > FALSE, > RootBridge->ResAllocNode[Index].Length, > MIN (15, BitsOfAlignment), > - ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1), > - RootBridge->Io.Limit > + ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1) + RootBridge->Io.Translation, > + RootBridge->Io.Limit + RootBridge->Io.Translation > ); > break; > > @@ -838,8 +861,8 @@ NotifyPhase ( > TRUE, > RootBridge->ResAllocNode[Index].Length, > MIN (63, BitsOfAlignment), > - ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1), > - RootBridge->MemAbove4G.Limit > + ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1) + RootBridge->MemAbove4G.Translation, > + RootBridge->MemAbove4G.Limit + RootBridge->MemAbove4G.Translation > ); > if (BaseAddress != MAX_UINT64) { > break; > @@ -853,8 +876,8 @@ NotifyPhase ( > TRUE, > RootBridge->ResAllocNode[Index].Length, > MIN (31, BitsOfAlignment), > - ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1), > - RootBridge->Mem.Limit > + ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1) + RootBridge->Mem.Translation, > + RootBridge->Mem.Limit + RootBridge->Mem.Translation > ); > break; > > @@ -863,8 +886,8 @@ NotifyPhase ( > TRUE, > RootBridge->ResAllocNode[Index].Length, > MIN (63, BitsOfAlignment), > - ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1), > - RootBridge->PMemAbove4G.Limit > + ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1) + RootBridge->PMemAbove4G.Translation, > + RootBridge->PMemAbove4G.Limit + RootBridge->PMemAbove4G.Translation > ); > if (BaseAddress != MAX_UINT64) { > break; > @@ -877,8 +900,8 @@ NotifyPhase ( > TRUE, > RootBridge->ResAllocNode[Index].Length, > MIN (31, BitsOfAlignment), > - ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1), > - RootBridge->PMem.Limit > + ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1) + RootBridge->PMem.Translation, > + RootBridge->PMem.Limit + RootBridge->PMem.Translation > ); > break; > > @@ -1152,6 +1175,7 @@ StartBusEnumeration ( > Descriptor->AddrSpaceGranularity = 0; > Descriptor->AddrRangeMin = RootBridge->Bus.Base; > Descriptor->AddrRangeMax = 0; > + // Ignore translation offset for bus > Descriptor->AddrTranslationOffset = 0; > Descriptor->AddrLen = RootBridge->Bus.Limit - RootBridge->Bus.Base + 1; > > @@ -1421,7 +1445,8 @@ GetProposedResources ( > Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; > Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;; > Descriptor->GenFlag = 0; > - Descriptor->AddrRangeMin = RootBridge->ResAllocNode[Index].Base; > + Descriptor->AddrRangeMin = RootBridge->ResAllocNode[Index].Base - > + GetTranslationByResourceType (RootBridge, Index); > Descriptor->AddrRangeMax = 0; > Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS; > Descriptor->AddrLen = RootBridge->ResAllocNode[Index].Length; > diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c > index dc06c16..bd3394a 100644 > --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c > +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c > @@ -86,12 +86,23 @@ CreateRootBridge ( > (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0 ? L"CombineMemPMem " : L"", > (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0 ? L"Mem64Decode" : L"" > )); > + // We don't see any scenario for bus translation, so translation for bus is just ignored. > DEBUG ((EFI_D_INFO, " Bus: %lx - %lx\n", Bridge->Bus.Base, Bridge->Bus.Limit)); > - DEBUG ((EFI_D_INFO, " Io: %lx - %lx\n", Bridge->Io.Base, Bridge->Io.Limit)); > - DEBUG ((EFI_D_INFO, " Mem: %lx - %lx\n", Bridge->Mem.Base, Bridge->Mem.Limit)); > - DEBUG ((EFI_D_INFO, " MemAbove4G: %lx - %lx\n", Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit)); > - DEBUG ((EFI_D_INFO, " PMem: %lx - %lx\n", Bridge->PMem.Base, Bridge->PMem.Limit)); > - DEBUG ((EFI_D_INFO, " PMemAbove4G: %lx - %lx\n", Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit)); > + DEBUG ((DEBUG_INFO, " Io: %lx - %lx translation=%lx\n", > + Bridge->Io.Base, Bridge->Io.Limit, Bridge->Io.Translation > + )); > + DEBUG ((DEBUG_INFO, " Mem: %lx - %lx translation=%lx\n", > + Bridge->Mem.Base, Bridge->Mem.Limit, Bridge->Mem.Translation > + )); > + DEBUG ((DEBUG_INFO, " MemAbove4G: %lx - %lx translation=%lx\n", > + Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit, Bridge->MemAbove4G.Translation > + )); > + DEBUG ((DEBUG_INFO, " PMem: %lx - %lx translation=%lx\n", > + Bridge->PMem.Base, Bridge->PMem.Limit, Bridge->PMem.Translation > + )); > + DEBUG ((DEBUG_INFO, " PMemAbove4G: %lx - %lx translation=%lx\n", > + Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit, Bridge->PMemAbove4G.Translation > + )); > > // > // Make sure Mem and MemAbove4G apertures are valid > @@ -403,6 +414,28 @@ RootBridgeIoCheckParameter ( > return EFI_SUCCESS; > } > > +EFI_STATUS > +RootBridgeIoGetMemTranslationByAddress ( > + IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge, > + IN UINT64 Address, > + IN OUT UINT64 *Translation > + ) > +{ > + if (Address >= RootBridge->Mem.Base && Address <= RootBridge->Mem.Limit) { > + *Translation = RootBridge->Mem.Translation; > + } else if (Address >= RootBridge->PMem.Base && Address <= RootBridge->PMem.Limit) { > + *Translation = RootBridge->PMem.Translation; > + } else if (Address >= RootBridge->MemAbove4G.Base && Address <= RootBridge->MemAbove4G.Limit) { > + *Translation = RootBridge->MemAbove4G.Translation; > + } else if (Address >= RootBridge->PMemAbove4G.Base && Address <= RootBridge->PMemAbove4G.Limit) { > + *Translation = RootBridge->PMemAbove4G.Translation; > + } else { > + return EFI_INVALID_PARAMETER; > + } > + > + return EFI_SUCCESS; > +} > + > /** > Polls an address in memory mapped I/O space until an exit condition is met, > or a timeout occurs. > @@ -658,13 +691,22 @@ RootBridgeIoMemRead ( > ) > { > EFI_STATUS Status; > + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; > + UINT64 Translation; > > Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address, > Count, Buffer); > if (EFI_ERROR (Status)) { > return Status; > } > - return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); > + > + RootBridge = ROOT_BRIDGE_FROM_THIS (This); > + Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address + Translation, Count, Buffer); > } > > /** > @@ -705,13 +747,22 @@ RootBridgeIoMemWrite ( > ) > { > EFI_STATUS Status; > + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; > + UINT64 Translation; > > Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address, > Count, Buffer); > if (EFI_ERROR (Status)) { > return Status; > } > - return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); > + > + RootBridge = ROOT_BRIDGE_FROM_THIS (This); > + Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address + Translation, Count, Buffer); > } > > /** > @@ -746,6 +797,8 @@ RootBridgeIoIoRead ( > ) > { > EFI_STATUS Status; > + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; > + > Status = RootBridgeIoCheckParameter ( > This, IoOperation, Width, > Address, Count, Buffer > @@ -753,7 +806,10 @@ RootBridgeIoIoRead ( > if (EFI_ERROR (Status)) { > return Status; > } > - return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); > + > + RootBridge = ROOT_BRIDGE_FROM_THIS (This); > + > + return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address + RootBridge->Io.Translation, Count, Buffer); > } > > /** > @@ -788,6 +844,8 @@ RootBridgeIoIoWrite ( > ) > { > EFI_STATUS Status; > + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; > + > Status = RootBridgeIoCheckParameter ( > This, IoOperation, Width, > Address, Count, Buffer > @@ -795,7 +853,10 @@ RootBridgeIoIoWrite ( > if (EFI_ERROR (Status)) { > return Status; > } > - return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); > + > + RootBridge = ROOT_BRIDGE_FROM_THIS (This); > + > + return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address + RootBridge->Io.Translation, Count, Buffer); > } > > /** > @@ -1615,25 +1676,41 @@ RootBridgeIoConfiguration ( > > Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; > Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3; > + // According to UEFI 2.7, RootBridgeIo::Configuration should return address > + // range in CPU view, and TranslationOffset = PCI view - CPU view. > Descriptor->AddrRangeMin = ResAllocNode->Base; > Descriptor->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1; > Descriptor->AddrLen = ResAllocNode->Length; > switch (ResAllocNode->Type) { > > case TypeIo: > - Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO; > + Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO; > + // According to UEFI 2.7, translation = PCI address - CPU address, > + // so we change the sign here to make it consistent with UEFI spec. > + // The other translations will be treated as the same. > + Descriptor->AddrTranslationOffset = -RootBridge->Io.Translation; > break; > > case TypePMem32: > - Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE; > + Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE; > + Descriptor->AddrTranslationOffset = -RootBridge->PMem.Translation; > + Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; > + Descriptor->AddrSpaceGranularity = 32; > + break; > + > case TypeMem32: > + Descriptor->AddrTranslationOffset = -RootBridge->Mem.Translation; > Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; > Descriptor->AddrSpaceGranularity = 32; > break; > > case TypePMem64: > - Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE; > + Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE; > + Descriptor->AddrTranslationOffset = -RootBridge->PMemAbove4G.Translation; > + Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; > + Descriptor->AddrSpaceGranularity = 64; > case TypeMem64: > + Descriptor->AddrTranslationOffset = -RootBridge->MemAbove4G.Translation; > Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; > Descriptor->AddrSpaceGranularity = 64; > break; > diff --git a/MdeModulePkg/Include/Library/PciHostBridgeLib.h b/MdeModulePkg/Include/Library/PciHostBridgeLib.h > index d42e9ec..b9e8c0f 100644 > --- a/MdeModulePkg/Include/Library/PciHostBridgeLib.h > +++ b/MdeModulePkg/Include/Library/PciHostBridgeLib.h > @@ -22,6 +22,7 @@ > typedef struct { > UINT64 Base; > UINT64 Limit; > + UINT64 Translation; > } PCI_ROOT_BRIDGE_APERTURE; > > typedef struct { > Heyi, The address stored in GCD database should only be in CPU-view. I think you might improperly add the CPU-view address range to GCD. Thanks, Ray -- Thanks, Ray _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
On 2/22/2018 2:54 PM, Heyi Guo wrote: > This is the draft patch for the discussion posted in edk2-devel > mailing list: > https://lists.01.org/pipermail/edk2-devel/2017-December/019289.html > > As discussed in the mailing list, we'd like to add support for PCI > address translation which is necessary for some non-x86 platforms. I > also want to minimize the changes to the generic host bridge driver > and platform PciHostBridgeLib implemetations, so additional two > interfaces are added to expose translation information of the > platform. To be generic, I add translation for each type of IO or > memory resources. > > The patch is still a RFC, so I only passed the build for qemu64 and > the function has not been tested yet. > > Please let me know your comments about it. > > Thanks. > > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Heyi Guo <heyi.guo@linaro.org> > Cc: Ruiyu Ni <ruiyu.ni@intel.com> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> > Cc: Star Zeng <star.zeng@intel.com> > Cc: Eric Dong <eric.dong@intel.com> > Cc: Laszlo Ersek <lersek@redhat.com> > Cc: Michael D Kinney <michael.d.kinney@intel.com> > --- > .../Bus/Pci/PciHostBridgeDxe/PciHostBridge.c | 57 ++++++++---- > .../Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c | 101 ++++++++++++++++++--- > MdeModulePkg/Include/Library/PciHostBridgeLib.h | 1 + > 3 files changed, 131 insertions(+), 28 deletions(-) > > diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c > index 1494848..fa22d8d 100644 > --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c > +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c > @@ -32,6 +32,29 @@ EDKII_IOMMU_PROTOCOL *mIoMmuProtocol; > EFI_EVENT mIoMmuEvent; > VOID *mIoMmuRegistration; > > +STATIC > +UINT64 > +GetTranslationByResourceType ( > + IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge, > + IN PCI_RESOURCE_TYPE ResourceType > + ) > +{ > + switch (ResourceType) { > + case TypeIo: > + return RootBridge->Io.Translation; > + case TypeMem32: > + return RootBridge->Mem.Translation; > + case TypePMem32: > + return RootBridge->PMem.Translation; > + case TypeMem64: > + return RootBridge->MemAbove4G.Translation; > + case TypePMem64: > + return RootBridge->PMemAbove4G.Translation; > + default: > + return 0; > + } > +} > + > /** > Ensure the compatibility of an IO space descriptor with the IO aperture. > > @@ -412,7 +435,7 @@ InitializePciHostBridge ( > > if (RootBridges[Index].Io.Base <= RootBridges[Index].Io.Limit) { > Status = AddIoSpace ( > - RootBridges[Index].Io.Base, > + RootBridges[Index].Io.Base + RootBridges[Index].Io.Translation, > RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1 > ); > ASSERT_EFI_ERROR (Status); > @@ -422,7 +445,7 @@ InitializePciHostBridge ( > EfiGcdIoTypeIo, > 0, > RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1, > - &RootBridges[Index].Io.Base, > + &RootBridges[Index].Io.Base + RootBridges[Index].Io.Translation, > gImageHandle, > NULL > ); > @@ -444,13 +467,13 @@ InitializePciHostBridge ( > for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) { > if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) { > Status = AddMemoryMappedIoSpace ( > - MemApertures[MemApertureIndex]->Base, > + MemApertures[MemApertureIndex]->Base + MemApertures[MemApertureIndex]->Translation, > MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1, > EFI_MEMORY_UC > ); > ASSERT_EFI_ERROR (Status); > Status = gDS->SetMemorySpaceAttributes ( > - MemApertures[MemApertureIndex]->Base, > + MemApertures[MemApertureIndex]->Base + MemApertures[MemApertureIndex]->Translation, > MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1, > EFI_MEMORY_UC > ); > @@ -463,7 +486,7 @@ InitializePciHostBridge ( > EfiGcdMemoryTypeMemoryMappedIo, > 0, > MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1, > - &MemApertures[MemApertureIndex]->Base, > + &MemApertures[MemApertureIndex]->Base + MemApertures[MemApertureIndex]->Translation, > gImageHandle, > NULL > ); > @@ -828,8 +851,8 @@ NotifyPhase ( > FALSE, > RootBridge->ResAllocNode[Index].Length, > MIN (15, BitsOfAlignment), > - ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1), > - RootBridge->Io.Limit > + ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1) + RootBridge->Io.Translation, > + RootBridge->Io.Limit + RootBridge->Io.Translation > ); > break; > > @@ -838,8 +861,8 @@ NotifyPhase ( > TRUE, > RootBridge->ResAllocNode[Index].Length, > MIN (63, BitsOfAlignment), > - ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1), > - RootBridge->MemAbove4G.Limit > + ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1) + RootBridge->MemAbove4G.Translation, > + RootBridge->MemAbove4G.Limit + RootBridge->MemAbove4G.Translation > ); > if (BaseAddress != MAX_UINT64) { > break; > @@ -853,8 +876,8 @@ NotifyPhase ( > TRUE, > RootBridge->ResAllocNode[Index].Length, > MIN (31, BitsOfAlignment), > - ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1), > - RootBridge->Mem.Limit > + ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1) + RootBridge->Mem.Translation, > + RootBridge->Mem.Limit + RootBridge->Mem.Translation > ); > break; > > @@ -863,8 +886,8 @@ NotifyPhase ( > TRUE, > RootBridge->ResAllocNode[Index].Length, > MIN (63, BitsOfAlignment), > - ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1), > - RootBridge->PMemAbove4G.Limit > + ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1) + RootBridge->PMemAbove4G.Translation, > + RootBridge->PMemAbove4G.Limit + RootBridge->PMemAbove4G.Translation > ); > if (BaseAddress != MAX_UINT64) { > break; > @@ -877,8 +900,8 @@ NotifyPhase ( > TRUE, > RootBridge->ResAllocNode[Index].Length, > MIN (31, BitsOfAlignment), > - ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1), > - RootBridge->PMem.Limit > + ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1) + RootBridge->PMem.Translation, > + RootBridge->PMem.Limit + RootBridge->PMem.Translation > ); > break; > > @@ -1152,6 +1175,7 @@ StartBusEnumeration ( > Descriptor->AddrSpaceGranularity = 0; > Descriptor->AddrRangeMin = RootBridge->Bus.Base; > Descriptor->AddrRangeMax = 0; > + // Ignore translation offset for bus > Descriptor->AddrTranslationOffset = 0; > Descriptor->AddrLen = RootBridge->Bus.Limit - RootBridge->Bus.Base + 1; > > @@ -1421,7 +1445,8 @@ GetProposedResources ( > Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; > Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;; > Descriptor->GenFlag = 0; > - Descriptor->AddrRangeMin = RootBridge->ResAllocNode[Index].Base; > + Descriptor->AddrRangeMin = RootBridge->ResAllocNode[Index].Base - > + GetTranslationByResourceType (RootBridge, Index); > Descriptor->AddrRangeMax = 0; > Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS; > Descriptor->AddrLen = RootBridge->ResAllocNode[Index].Length; > diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c > index dc06c16..bd3394a 100644 > --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c > +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c > @@ -86,12 +86,23 @@ CreateRootBridge ( > (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0 ? L"CombineMemPMem " : L"", > (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0 ? L"Mem64Decode" : L"" > )); > + // We don't see any scenario for bus translation, so translation for bus is just ignored. > DEBUG ((EFI_D_INFO, " Bus: %lx - %lx\n", Bridge->Bus.Base, Bridge->Bus.Limit)); > - DEBUG ((EFI_D_INFO, " Io: %lx - %lx\n", Bridge->Io.Base, Bridge->Io.Limit)); > - DEBUG ((EFI_D_INFO, " Mem: %lx - %lx\n", Bridge->Mem.Base, Bridge->Mem.Limit)); > - DEBUG ((EFI_D_INFO, " MemAbove4G: %lx - %lx\n", Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit)); > - DEBUG ((EFI_D_INFO, " PMem: %lx - %lx\n", Bridge->PMem.Base, Bridge->PMem.Limit)); > - DEBUG ((EFI_D_INFO, " PMemAbove4G: %lx - %lx\n", Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit)); > + DEBUG ((DEBUG_INFO, " Io: %lx - %lx translation=%lx\n", > + Bridge->Io.Base, Bridge->Io.Limit, Bridge->Io.Translation > + )); > + DEBUG ((DEBUG_INFO, " Mem: %lx - %lx translation=%lx\n", > + Bridge->Mem.Base, Bridge->Mem.Limit, Bridge->Mem.Translation > + )); > + DEBUG ((DEBUG_INFO, " MemAbove4G: %lx - %lx translation=%lx\n", > + Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit, Bridge->MemAbove4G.Translation > + )); > + DEBUG ((DEBUG_INFO, " PMem: %lx - %lx translation=%lx\n", > + Bridge->PMem.Base, Bridge->PMem.Limit, Bridge->PMem.Translation > + )); > + DEBUG ((DEBUG_INFO, " PMemAbove4G: %lx - %lx translation=%lx\n", > + Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit, Bridge->PMemAbove4G.Translation > + )); > > // > // Make sure Mem and MemAbove4G apertures are valid > @@ -403,6 +414,28 @@ RootBridgeIoCheckParameter ( > return EFI_SUCCESS; > } > > +EFI_STATUS > +RootBridgeIoGetMemTranslationByAddress ( > + IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge, > + IN UINT64 Address, > + IN OUT UINT64 *Translation > + ) > +{ > + if (Address >= RootBridge->Mem.Base && Address <= RootBridge->Mem.Limit) { > + *Translation = RootBridge->Mem.Translation; > + } else if (Address >= RootBridge->PMem.Base && Address <= RootBridge->PMem.Limit) { > + *Translation = RootBridge->PMem.Translation; > + } else if (Address >= RootBridge->MemAbove4G.Base && Address <= RootBridge->MemAbove4G.Limit) { > + *Translation = RootBridge->MemAbove4G.Translation; > + } else if (Address >= RootBridge->PMemAbove4G.Base && Address <= RootBridge->PMemAbove4G.Limit) { > + *Translation = RootBridge->PMemAbove4G.Translation; > + } else { > + return EFI_INVALID_PARAMETER; > + } > + > + return EFI_SUCCESS; > +} > + > /** > Polls an address in memory mapped I/O space until an exit condition is met, > or a timeout occurs. > @@ -658,13 +691,22 @@ RootBridgeIoMemRead ( > ) > { > EFI_STATUS Status; > + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; > + UINT64 Translation; > > Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address, > Count, Buffer); > if (EFI_ERROR (Status)) { > return Status; > } > - return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); > + > + RootBridge = ROOT_BRIDGE_FROM_THIS (This); > + Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address + Translation, Count, Buffer); > } > > /** > @@ -705,13 +747,22 @@ RootBridgeIoMemWrite ( > ) > { > EFI_STATUS Status; > + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; > + UINT64 Translation; > > Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address, > Count, Buffer); > if (EFI_ERROR (Status)) { > return Status; > } > - return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); > + > + RootBridge = ROOT_BRIDGE_FROM_THIS (This); > + Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address + Translation, Count, Buffer); > } > > /** > @@ -746,6 +797,8 @@ RootBridgeIoIoRead ( > ) > { > EFI_STATUS Status; > + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; > + > Status = RootBridgeIoCheckParameter ( > This, IoOperation, Width, > Address, Count, Buffer > @@ -753,7 +806,10 @@ RootBridgeIoIoRead ( > if (EFI_ERROR (Status)) { > return Status; > } > - return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); > + > + RootBridge = ROOT_BRIDGE_FROM_THIS (This); > + > + return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address + RootBridge->Io.Translation, Count, Buffer); > } > > /** > @@ -788,6 +844,8 @@ RootBridgeIoIoWrite ( > ) > { > EFI_STATUS Status; > + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; > + > Status = RootBridgeIoCheckParameter ( > This, IoOperation, Width, > Address, Count, Buffer > @@ -795,7 +853,10 @@ RootBridgeIoIoWrite ( > if (EFI_ERROR (Status)) { > return Status; > } > - return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); > + > + RootBridge = ROOT_BRIDGE_FROM_THIS (This); > + > + return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address + RootBridge->Io.Translation, Count, Buffer); > } > > /** > @@ -1615,25 +1676,41 @@ RootBridgeIoConfiguration ( > > Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; > Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3; > + // According to UEFI 2.7, RootBridgeIo::Configuration should return address > + // range in CPU view, and TranslationOffset = PCI view - CPU view. > Descriptor->AddrRangeMin = ResAllocNode->Base; > Descriptor->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1; > Descriptor->AddrLen = ResAllocNode->Length; > switch (ResAllocNode->Type) { > > case TypeIo: > - Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO; > + Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO; > + // According to UEFI 2.7, translation = PCI address - CPU address, > + // so we change the sign here to make it consistent with UEFI spec. > + // The other translations will be treated as the same. > + Descriptor->AddrTranslationOffset = -RootBridge->Io.Translation; > break; > > case TypePMem32: > - Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE; > + Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE; > + Descriptor->AddrTranslationOffset = -RootBridge->PMem.Translation; > + Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; > + Descriptor->AddrSpaceGranularity = 32; > + break; > + > case TypeMem32: > + Descriptor->AddrTranslationOffset = -RootBridge->Mem.Translation; > Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; > Descriptor->AddrSpaceGranularity = 32; > break; > > case TypePMem64: > - Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE; > + Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE; > + Descriptor->AddrTranslationOffset = -RootBridge->PMemAbove4G.Translation; > + Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; > + Descriptor->AddrSpaceGranularity = 64; > case TypeMem64: > + Descriptor->AddrTranslationOffset = -RootBridge->MemAbove4G.Translation; > Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; > Descriptor->AddrSpaceGranularity = 64; > break; > diff --git a/MdeModulePkg/Include/Library/PciHostBridgeLib.h b/MdeModulePkg/Include/Library/PciHostBridgeLib.h > index d42e9ec..b9e8c0f 100644 > --- a/MdeModulePkg/Include/Library/PciHostBridgeLib.h > +++ b/MdeModulePkg/Include/Library/PciHostBridgeLib.h > @@ -22,6 +22,7 @@ > typedef struct { > UINT64 Base; > UINT64 Limit; > + UINT64 Translation; > } PCI_ROOT_BRIDGE_APERTURE; > > typedef struct { > And I think you'd better to add comments in code to clarify whether it's a PCI-view address or CPU-view address. -- Thanks, Ray _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hello Heyi, On 02/22/18 07:54, Heyi Guo wrote: > This is the draft patch for the discussion posted in edk2-devel > mailing list: > https://lists.01.org/pipermail/edk2-devel/2017-December/019289.html > > As discussed in the mailing list, we'd like to add support for PCI > address translation which is necessary for some non-x86 platforms. I > also want to minimize the changes to the generic host bridge driver > and platform PciHostBridgeLib implemetations, so additional two > interfaces are added to expose translation information of the > platform. To be generic, I add translation for each type of IO or > memory resources. > > The patch is still a RFC, so I only passed the build for qemu64 and > the function has not been tested yet. > > Please let me know your comments about it. > > Thanks. I have two requests here: (1) In the commit message -- and, as requested by Ray, near the PCI_ROOT_BRIDGE_APERTURE typedef too --, please document the *exact* mathematical formula that defines how the translation is supposed to work: DeviceAddress = HostAddress + AddressTranslationOffset versus HostAddress = DeviceAddress + AddressTranslationOffset We've have a whole lot of discussion around that, both on this list and on the PIWG and/or USWG lists, and it's still unclear to me. The last discussion I recall (that I was involved in) starts here: [edk2] [PATCH] MdeModulePkg/PciBusDxe: GetBarAttributes() returns Host address https://lists.01.org/pipermail/edk2-devel/2017-September/014425.html Due to our (apparently!) collective confusion in that thread, Ray decided back then not to change the code at all. So, have we cleared up the confusion? Do we have an agreement on what formula to use? Is the formula consistent with the UEFI spec? Reviewing the (more recent, December 2017) thread that you link in the commit message (which I apparently didn't participate in, apologies), I find the following message from Ray: https://lists.01.org/pipermail/edk2-devel/2017-December/019335.html > And further more, there was a discussion in the mailing list > regarding how to utilize the Offset. There was 2 points > about the meaning of Offset and we cannot agree with each > other. Spec is not quite clear. > 1. Offset = Host - Device > 2. Offset = Device - Host Based on your followup to that, <https://lists.01.org/pipermail/edk2-devel/2017-December/019341.html>, it looks like you picked #1, or in other words, HostAddress = DeviceAddress + AddressTranslationOffset To quote Ray again from the September 2017 thread, 'Your understanding to "apply to" is "add", my understanding is "minus"'. So, if we go with this approach, please quote the EFI_PCI_IO_PROTOCOL.GetBarAttributes() language from the UEFI 2.7 spec in the code, and explicitly define "apply" as *subtract*: "Translation Offset. Offset to apply to the Starting address of a BAR to convert it to a PCI address" with "apply" defined as "subtract"; in other words DeviceAddress = HostAddress - AddressTranslationOffset > diff --git a/MdeModulePkg/Include/Library/PciHostBridgeLib.h b/MdeModulePkg/Include/Library/PciHostBridgeLib.h > index d42e9ec..b9e8c0f 100644 > --- a/MdeModulePkg/Include/Library/PciHostBridgeLib.h > +++ b/MdeModulePkg/Include/Library/PciHostBridgeLib.h > @@ -22,6 +22,7 @@ > typedef struct { > UINT64 Base; > UINT64 Limit; > + UINT64 Translation; > } PCI_ROOT_BRIDGE_APERTURE; > > typedef struct { > (2) My second request is that you please audit all uses of PCI_ROOT_BRIDGE_APERTURE and PCI_ROOT_BRIDGE in the edk2 tree. For example: (2a) "ArmVirtPkg/Library/FdtPciHostBridgeLib/FdtPciHostBridgeLib.c" is fine, it needs no updates. It uses STATIC PCI_ROOT_BRIDGE mRootBridge; so the new Translation field will be zero, in all the aperture fields. OK. (2b) However, under "OvmfPkg/Library/PciHostBridgeLib", several updates are needed. This library instance behaves differently on Xen vs. QEMU, and both branches need fixes. The InitRootBridge() function needs no change, because it calls ZeroMem(), in order to "Be safe if other fields are added to PCI_ROOT_BRIDGE later". OK. There's also a global variable called "mNonExistAperture" where the Translation field will be initialized to zero, implicitly. So that's OK too. However, both the QEMU and the Xen code use *local variables* of type PCI_ROOT_BRIDGE_APERTURE: - in PciHostBridgeGetRootBridges(): Io, Mem, MemAbove4G - in ScanForRootBridges(): Io, Mem, MemAbove4G, PMem, PMemAbove4G The Translation field in all of these local structs would be indeterminate, and then that would be copied into the PCI_ROOT_BRIDGE object(s) exposed by PciHostBridgeGetRootBridges(). So, please zero out all of these local structs (with ZeroMem()) in their respective functions, before they are populated member-wise. (Note that in ScanForRootBridges(), the zeroing should occur at the top of the loop body, replacing the manual zeroing of the .Limit fields.) Thanks Laszlo _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c index 1494848..fa22d8d 100644 --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c @@ -32,6 +32,29 @@ EDKII_IOMMU_PROTOCOL *mIoMmuProtocol; EFI_EVENT mIoMmuEvent; VOID *mIoMmuRegistration; +STATIC +UINT64 +GetTranslationByResourceType ( + IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge, + IN PCI_RESOURCE_TYPE ResourceType + ) +{ + switch (ResourceType) { + case TypeIo: + return RootBridge->Io.Translation; + case TypeMem32: + return RootBridge->Mem.Translation; + case TypePMem32: + return RootBridge->PMem.Translation; + case TypeMem64: + return RootBridge->MemAbove4G.Translation; + case TypePMem64: + return RootBridge->PMemAbove4G.Translation; + default: + return 0; + } +} + /** Ensure the compatibility of an IO space descriptor with the IO aperture. @@ -412,7 +435,7 @@ InitializePciHostBridge ( if (RootBridges[Index].Io.Base <= RootBridges[Index].Io.Limit) { Status = AddIoSpace ( - RootBridges[Index].Io.Base, + RootBridges[Index].Io.Base + RootBridges[Index].Io.Translation, RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1 ); ASSERT_EFI_ERROR (Status); @@ -422,7 +445,7 @@ InitializePciHostBridge ( EfiGcdIoTypeIo, 0, RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1, - &RootBridges[Index].Io.Base, + &RootBridges[Index].Io.Base + RootBridges[Index].Io.Translation, gImageHandle, NULL ); @@ -444,13 +467,13 @@ InitializePciHostBridge ( for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) { if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) { Status = AddMemoryMappedIoSpace ( - MemApertures[MemApertureIndex]->Base, + MemApertures[MemApertureIndex]->Base + MemApertures[MemApertureIndex]->Translation, MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1, EFI_MEMORY_UC ); ASSERT_EFI_ERROR (Status); Status = gDS->SetMemorySpaceAttributes ( - MemApertures[MemApertureIndex]->Base, + MemApertures[MemApertureIndex]->Base + MemApertures[MemApertureIndex]->Translation, MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1, EFI_MEMORY_UC ); @@ -463,7 +486,7 @@ InitializePciHostBridge ( EfiGcdMemoryTypeMemoryMappedIo, 0, MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1, - &MemApertures[MemApertureIndex]->Base, + &MemApertures[MemApertureIndex]->Base + MemApertures[MemApertureIndex]->Translation, gImageHandle, NULL ); @@ -828,8 +851,8 @@ NotifyPhase ( FALSE, RootBridge->ResAllocNode[Index].Length, MIN (15, BitsOfAlignment), - ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1), - RootBridge->Io.Limit + ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1) + RootBridge->Io.Translation, + RootBridge->Io.Limit + RootBridge->Io.Translation ); break; @@ -838,8 +861,8 @@ NotifyPhase ( TRUE, RootBridge->ResAllocNode[Index].Length, MIN (63, BitsOfAlignment), - ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1), - RootBridge->MemAbove4G.Limit + ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1) + RootBridge->MemAbove4G.Translation, + RootBridge->MemAbove4G.Limit + RootBridge->MemAbove4G.Translation ); if (BaseAddress != MAX_UINT64) { break; @@ -853,8 +876,8 @@ NotifyPhase ( TRUE, RootBridge->ResAllocNode[Index].Length, MIN (31, BitsOfAlignment), - ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1), - RootBridge->Mem.Limit + ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1) + RootBridge->Mem.Translation, + RootBridge->Mem.Limit + RootBridge->Mem.Translation ); break; @@ -863,8 +886,8 @@ NotifyPhase ( TRUE, RootBridge->ResAllocNode[Index].Length, MIN (63, BitsOfAlignment), - ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1), - RootBridge->PMemAbove4G.Limit + ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1) + RootBridge->PMemAbove4G.Translation, + RootBridge->PMemAbove4G.Limit + RootBridge->PMemAbove4G.Translation ); if (BaseAddress != MAX_UINT64) { break; @@ -877,8 +900,8 @@ NotifyPhase ( TRUE, RootBridge->ResAllocNode[Index].Length, MIN (31, BitsOfAlignment), - ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1), - RootBridge->PMem.Limit + ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1) + RootBridge->PMem.Translation, + RootBridge->PMem.Limit + RootBridge->PMem.Translation ); break; @@ -1152,6 +1175,7 @@ StartBusEnumeration ( Descriptor->AddrSpaceGranularity = 0; Descriptor->AddrRangeMin = RootBridge->Bus.Base; Descriptor->AddrRangeMax = 0; + // Ignore translation offset for bus Descriptor->AddrTranslationOffset = 0; Descriptor->AddrLen = RootBridge->Bus.Limit - RootBridge->Bus.Base + 1; @@ -1421,7 +1445,8 @@ GetProposedResources ( Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;; Descriptor->GenFlag = 0; - Descriptor->AddrRangeMin = RootBridge->ResAllocNode[Index].Base; + Descriptor->AddrRangeMin = RootBridge->ResAllocNode[Index].Base - + GetTranslationByResourceType (RootBridge, Index); Descriptor->AddrRangeMax = 0; Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS; Descriptor->AddrLen = RootBridge->ResAllocNode[Index].Length; diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c index dc06c16..bd3394a 100644 --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c @@ -86,12 +86,23 @@ CreateRootBridge ( (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0 ? L"CombineMemPMem " : L"", (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0 ? L"Mem64Decode" : L"" )); + // We don't see any scenario for bus translation, so translation for bus is just ignored. DEBUG ((EFI_D_INFO, " Bus: %lx - %lx\n", Bridge->Bus.Base, Bridge->Bus.Limit)); - DEBUG ((EFI_D_INFO, " Io: %lx - %lx\n", Bridge->Io.Base, Bridge->Io.Limit)); - DEBUG ((EFI_D_INFO, " Mem: %lx - %lx\n", Bridge->Mem.Base, Bridge->Mem.Limit)); - DEBUG ((EFI_D_INFO, " MemAbove4G: %lx - %lx\n", Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit)); - DEBUG ((EFI_D_INFO, " PMem: %lx - %lx\n", Bridge->PMem.Base, Bridge->PMem.Limit)); - DEBUG ((EFI_D_INFO, " PMemAbove4G: %lx - %lx\n", Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit)); + DEBUG ((DEBUG_INFO, " Io: %lx - %lx translation=%lx\n", + Bridge->Io.Base, Bridge->Io.Limit, Bridge->Io.Translation + )); + DEBUG ((DEBUG_INFO, " Mem: %lx - %lx translation=%lx\n", + Bridge->Mem.Base, Bridge->Mem.Limit, Bridge->Mem.Translation + )); + DEBUG ((DEBUG_INFO, " MemAbove4G: %lx - %lx translation=%lx\n", + Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit, Bridge->MemAbove4G.Translation + )); + DEBUG ((DEBUG_INFO, " PMem: %lx - %lx translation=%lx\n", + Bridge->PMem.Base, Bridge->PMem.Limit, Bridge->PMem.Translation + )); + DEBUG ((DEBUG_INFO, " PMemAbove4G: %lx - %lx translation=%lx\n", + Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit, Bridge->PMemAbove4G.Translation + )); // // Make sure Mem and MemAbove4G apertures are valid @@ -403,6 +414,28 @@ RootBridgeIoCheckParameter ( return EFI_SUCCESS; } +EFI_STATUS +RootBridgeIoGetMemTranslationByAddress ( + IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge, + IN UINT64 Address, + IN OUT UINT64 *Translation + ) +{ + if (Address >= RootBridge->Mem.Base && Address <= RootBridge->Mem.Limit) { + *Translation = RootBridge->Mem.Translation; + } else if (Address >= RootBridge->PMem.Base && Address <= RootBridge->PMem.Limit) { + *Translation = RootBridge->PMem.Translation; + } else if (Address >= RootBridge->MemAbove4G.Base && Address <= RootBridge->MemAbove4G.Limit) { + *Translation = RootBridge->MemAbove4G.Translation; + } else if (Address >= RootBridge->PMemAbove4G.Base && Address <= RootBridge->PMemAbove4G.Limit) { + *Translation = RootBridge->PMemAbove4G.Translation; + } else { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + /** Polls an address in memory mapped I/O space until an exit condition is met, or a timeout occurs. @@ -658,13 +691,22 @@ RootBridgeIoMemRead ( ) { EFI_STATUS Status; + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; + UINT64 Translation; Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address, Count, Buffer); if (EFI_ERROR (Status)) { return Status; } - return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); + + RootBridge = ROOT_BRIDGE_FROM_THIS (This); + Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation); + if (EFI_ERROR (Status)) { + return Status; + } + + return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address + Translation, Count, Buffer); } /** @@ -705,13 +747,22 @@ RootBridgeIoMemWrite ( ) { EFI_STATUS Status; + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; + UINT64 Translation; Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address, Count, Buffer); if (EFI_ERROR (Status)) { return Status; } - return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); + + RootBridge = ROOT_BRIDGE_FROM_THIS (This); + Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation); + if (EFI_ERROR (Status)) { + return Status; + } + + return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address + Translation, Count, Buffer); } /** @@ -746,6 +797,8 @@ RootBridgeIoIoRead ( ) { EFI_STATUS Status; + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; + Status = RootBridgeIoCheckParameter ( This, IoOperation, Width, Address, Count, Buffer @@ -753,7 +806,10 @@ RootBridgeIoIoRead ( if (EFI_ERROR (Status)) { return Status; } - return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); + + RootBridge = ROOT_BRIDGE_FROM_THIS (This); + + return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address + RootBridge->Io.Translation, Count, Buffer); } /** @@ -788,6 +844,8 @@ RootBridgeIoIoWrite ( ) { EFI_STATUS Status; + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; + Status = RootBridgeIoCheckParameter ( This, IoOperation, Width, Address, Count, Buffer @@ -795,7 +853,10 @@ RootBridgeIoIoWrite ( if (EFI_ERROR (Status)) { return Status; } - return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); + + RootBridge = ROOT_BRIDGE_FROM_THIS (This); + + return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address + RootBridge->Io.Translation, Count, Buffer); } /** @@ -1615,25 +1676,41 @@ RootBridgeIoConfiguration ( Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3; + // According to UEFI 2.7, RootBridgeIo::Configuration should return address + // range in CPU view, and TranslationOffset = PCI view - CPU view. Descriptor->AddrRangeMin = ResAllocNode->Base; Descriptor->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1; Descriptor->AddrLen = ResAllocNode->Length; switch (ResAllocNode->Type) { case TypeIo: - Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO; + Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO; + // According to UEFI 2.7, translation = PCI address - CPU address, + // so we change the sign here to make it consistent with UEFI spec. + // The other translations will be treated as the same. + Descriptor->AddrTranslationOffset = -RootBridge->Io.Translation; break; case TypePMem32: - Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE; + Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE; + Descriptor->AddrTranslationOffset = -RootBridge->PMem.Translation; + Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + Descriptor->AddrSpaceGranularity = 32; + break; + case TypeMem32: + Descriptor->AddrTranslationOffset = -RootBridge->Mem.Translation; Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; Descriptor->AddrSpaceGranularity = 32; break; case TypePMem64: - Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE; + Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE; + Descriptor->AddrTranslationOffset = -RootBridge->PMemAbove4G.Translation; + Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + Descriptor->AddrSpaceGranularity = 64; case TypeMem64: + Descriptor->AddrTranslationOffset = -RootBridge->MemAbove4G.Translation; Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; Descriptor->AddrSpaceGranularity = 64; break; diff --git a/MdeModulePkg/Include/Library/PciHostBridgeLib.h b/MdeModulePkg/Include/Library/PciHostBridgeLib.h index d42e9ec..b9e8c0f 100644 --- a/MdeModulePkg/Include/Library/PciHostBridgeLib.h +++ b/MdeModulePkg/Include/Library/PciHostBridgeLib.h @@ -22,6 +22,7 @@ typedef struct { UINT64 Base; UINT64 Limit; + UINT64 Translation; } PCI_ROOT_BRIDGE_APERTURE; typedef struct {
This is the draft patch for the discussion posted in edk2-devel mailing list: https://lists.01.org/pipermail/edk2-devel/2017-December/019289.html As discussed in the mailing list, we'd like to add support for PCI address translation which is necessary for some non-x86 platforms. I also want to minimize the changes to the generic host bridge driver and platform PciHostBridgeLib implemetations, so additional two interfaces are added to expose translation information of the platform. To be generic, I add translation for each type of IO or memory resources. The patch is still a RFC, so I only passed the build for qemu64 and the function has not been tested yet. Please let me know your comments about it. Thanks. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Heyi Guo <heyi.guo@linaro.org> Cc: Ruiyu Ni <ruiyu.ni@intel.com> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Star Zeng <star.zeng@intel.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> --- .../Bus/Pci/PciHostBridgeDxe/PciHostBridge.c | 57 ++++++++---- .../Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c | 101 ++++++++++++++++++--- MdeModulePkg/Include/Library/PciHostBridgeLib.h | 1 + 3 files changed, 131 insertions(+), 28 deletions(-) -- 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel