On 03/06/16 11:54, Marcel Apfelbaum wrote:
> On 03/04/2016 04:46 PM, Laszlo Ersek wrote:
>> The comments in the code should speak for themselves; here we note only
>> two facts:
>>
>> - The PCI config space writes (to the PCIEXBAR register) are performed
>>    using the 0xCF8 / 0xCFC IO ports, by virtue of PciLib being
>> resolved to
>>    BasePciLibCf8. (This library resolution will permanently remain in
>> place
>>    for the PEI phase.)
>>
>> - Since PCIEXBAR counts as a chipset register, it is the
>> responsibility of
>>    the firmware to reprogram it at S3 resume. Therefore
>>    PciExBarInitialization() is called regardless of the boot path.
>> (Marcel
>>    recently posted patches for SeaBIOS that implement this.)
>>
>> This patch suffices to enable PCIEXBAR (and the dependent ACPI table
>> generation in QEMU), for the sake of "PCIeHotplug" in the Linux guest:
>>
>>    ACPI: MCFG 0x000000007E193000 00003C
>>          (v01 BOCHS  BXPCMCFG 00000001 BXPC 00000001)
>>    PCI: MMCONFIG for domain 0000 [bus 00-ff] at [mem
>> 0xb0000000-0xbfffffff]
>>         (base 0xb0000000)
>>    PCI: MMCONFIG at [mem 0xb0000000-0xbfffffff] reserved in E820
>>    acpi PNP0A08:00: _OSC: OS supports
>>                     [ExtendedConfig ASPM ClockPM Segments MSI]
>>    acpi PNP0A08:00: _OSC: OS now controls
>>                     [PCIeHotplug PME AER PCIeCapability]
>>
>> In the following patches, we'll equip the core PCI host bridge / root
>> bridge driver and the rest of DXE as well to utilize ECAM on Q35.
>>
>> Cc: Gabriel Somlo <so...@cmu.edu>
>> Cc: Jordan Justen <jordan.l.jus...@intel.com>
>> Cc: Marcel Apfelbaum <mar...@redhat.com>
>> Cc: Michał Zegan <webczat_...@poczta.onet.pl>
>> Ref: https://github.com/tianocore/edk2/issues/32
>> Ref: http://thread.gmane.org/gmane.comp.bios.coreboot.seabios/10548
>> Suggested-by: Marcel Apfelbaum <mar...@redhat.com>
>> Reported-by: Michał Zegan <webczat_...@poczta.onet.pl>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Laszlo Ersek <ler...@redhat.com>
>> ---
>>   OvmfPkg/OvmfPkgIa32.dsc             |  8 ++
>>   OvmfPkg/OvmfPkgIa32X64.dsc          |  8 ++
>>   OvmfPkg/OvmfPkgX64.dsc              |  8 ++
>>   OvmfPkg/PlatformPei/PlatformPei.inf |  3 +
>>   OvmfPkg/PlatformPei/Platform.c      | 81 ++++++++++++++++++++
>>   5 files changed, 108 insertions(+)
>>
>> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
>> index 2b928506e481..d1f91172044e 100644
>> --- a/OvmfPkg/OvmfPkgIa32.dsc
>> +++ b/OvmfPkg/OvmfPkgIa32.dsc
>> @@ -395,6 +395,14 @@ [PcdsFixedAtBuild]
>>     gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F
>>   !endif
>>
>> +  # This PCD is used to set the base address of the PCI express
>> hierarchy. It
>> +  # is only consulted when OVMF runs on Q35. In that case it is
>> programmed into
>> +  # the PCIEXBAR register.
>> +  #
>> +  # The value we set below matches both the QEMU default, and the
>> value that
>> +  # SeaBIOS hard-codes.
>> +  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0xB0000000
>> +
>>   !ifdef $(SOURCE_DEBUG_ENABLE)
>>     gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod|0x2
>>   !endif
>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
>> index 8d6271824f89..c9eeace4a134 100644
>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
>> @@ -400,6 +400,14 @@ [PcdsFixedAtBuild]
>>     gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F
>>   !endif
>>
>> +  # This PCD is used to set the base address of the PCI express
>> hierarchy. It
>> +  # is only consulted when OVMF runs on Q35. In that case it is
>> programmed into
>> +  # the PCIEXBAR register.
>> +  #
>> +  # The value we set below matches both the QEMU default, and the
>> value that
>> +  # SeaBIOS hard-codes.
>> +  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0xB0000000
>> +
>>   !ifdef $(SOURCE_DEBUG_ENABLE)
>>     gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod|0x2
>>   !endif
>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
>> index e3f97f16f28b..b6f4b252ff03 100644
>> --- a/OvmfPkg/OvmfPkgX64.dsc
>> +++ b/OvmfPkg/OvmfPkgX64.dsc
>> @@ -400,6 +400,14 @@ [PcdsFixedAtBuild]
>>     gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F
>>   !endif
>>
>> +  # This PCD is used to set the base address of the PCI express
>> hierarchy. It
>> +  # is only consulted when OVMF runs on Q35. In that case it is
>> programmed into
>> +  # the PCIEXBAR register.
>> +  #
>> +  # The value we set below matches both the QEMU default, and the
>> value that
>> +  # SeaBIOS hard-codes.
>> +  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0xB0000000
>> +
>>   !ifdef $(SOURCE_DEBUG_ENABLE)
>>     gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod|0x2
>>   !endif
>> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf
>> b/OvmfPkg/PlatformPei/PlatformPei.inf
>> index 8480839efc8e..6dc5ff079f53 100644
>> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
>> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
>> @@ -94,6 +94,9 @@ [Pcd]
>>     gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable
>>     gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
>>
>> +[FixedPcd]
>> +  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
>> +
>>   [FeaturePcd]
>>     gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
>>
>> diff --git a/OvmfPkg/PlatformPei/Platform.c
>> b/OvmfPkg/PlatformPei/Platform.c
>> index 7d0941209f25..f0a488bcfc2b 100644
>> --- a/OvmfPkg/PlatformPei/Platform.c
>> +++ b/OvmfPkg/PlatformPei/Platform.c
>> @@ -214,6 +214,7 @@ MemMapInitialization (
>>       UINT32  TopOfLowRam;
>>       UINT32  PciBase;
>>       UINT32  PciSize;
>> +    UINT64  PciExBarBase;
>>
>>       TopOfLowRam = GetSystemMemorySizeBelow4gb ();
>>       if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
>> @@ -224,6 +225,16 @@ MemMapInitialization (
>>         //
>>         PciBase = BASE_2GB + BASE_1GB;
>>         ASSERT (TopOfLowRam <= PciBase);
>> +
>> +      //
>> +      // The (exclusive) end of the MMCONFIG area should be
>> expressible as a
>> +      // UINT64. Additionally, the MMCONFIG area is expected to fall
>> between
>> +      // the top of low RAM and the base of the 32-bit PCI host
>> aperture.
>> +      //
>> +      PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);
>> +      ASSERT (PciExBarBase <= MAX_UINT64 - SIZE_256MB);
>> +      ASSERT (TopOfLowRam <= PciExBarBase);
>> +      ASSERT (PciExBarBase + SIZE_256MB <= PciBase);
>>       } else {
>>         PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam;
>>       }
>> @@ -249,6 +260,30 @@ MemMapInitialization (
>>       AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
>>       if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
>>         AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
>> +      //
>> +      // Note: there should be an
>> +      //
>> +      //   AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
>> +      //
>> +      // call below, just like the one above for RCBA. However, Linux
>> insists
>> +      // that the MMCONFIG area be marked in the E820 or UEFI memory
>> map as
>> +      // "reserved memory" -- Linux does not content itself with a
>> simple gap
>> +      // in the memory map wherever the MCFG ACPI table points to.
>> +      //
>> +      // This appears to be a safety measure. The PCI Firmware
>> Specification
>> +      // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The
>> resources can
>> +      // *optionally* be returned in [...] EFIGetMemoryMap as
>> reserved memory
>> +      // [...]". (Emphasis added here.)
>> +      //
>> +      // Normally we add memory resource descriptor HOBs in
>> +      // QemuInitializeRam(), and pre-allocate from those with memory
>> +      // allocation HOBs in InitializeRamRegions(). However, the
>> MMCONFIG area
>> +      // is most definitely not RAM; so, as an exception, cover it with
>> +      // uncacheable reserved memory right here.
>> +      //
>> +      AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
>> +      BuildMemoryAllocationHob (PciExBarBase, SIZE_256MB,
>> +        EfiReservedMemoryType);
>>       }
>>       AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress),
>> SIZE_1MB);
>>     }
>> @@ -318,6 +353,47 @@ NoexecDxeInitialization (
>>   }
>>
>>   VOID
>> +PciExBarInitialization (
>> +  VOID
>> +  )
>> +{
>> +  union {
>> +    UINT64 Uint64;
>> +    UINT32 Uint32[2];
>> +  } PciExBarBase;
>> +
>> +  //
>> +  // We only support the 256MB size for the MMCONFIG area:
>> +  // 256 buses * 32 devices * 8 functions * 4096 bytes config space.
>> +  //
>> +  // The masks used below enforce the Q35 requirements that the
>> MMCONFIG area
>> +  // be (a) correctly aligned -- here at 256 MB --, (b) located under
>> 64 GB.
>> +  //
>> +  // Note that (b) also ensures that the minimum address width we have
>> +  // determined in AddressWidthInitialization(), i.e., 36 bits, will
>> suffice
>> +  // for DXE's page tables to cover the MMCONFIG area.
>> +  //
>> +  PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);
>> +  ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);
>> +  ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);
>> +
>> +  //
>> +  // Clear the PCIEXBAREN bit first, before programming the high
>> register.
>> +  //
>> +  PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);
>> +
>> +  //
>> +  // Program the high register. Then program the low register,
>> setting the
>> +  // MMCONFIG area size and enabling decoding at once.
>> +  //
>> +  PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH),
>> PciExBarBase.Uint32[1]);
>> +  PciWrite32 (
>> +    DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),
>> +    PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN
>> +    );
>> +}
>> +
>> +VOID
>>   MiscInitialization (
>>     VOID
>>     )
>> @@ -394,6 +470,11 @@ MiscInitialization (
>>         POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
>>         ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
>>         );
>> +
>> +    //
>> +    // Set PCI Express Register Range Base Address
>> +    //
>> +    PciExBarInitialization ();
>>     }
>>   }
>>
>>
> 
> Hi,
> 
> The PCI config accesses to PCIEXBAR are correct.
> 
> Reviewed-by: Marcel Apfelbaum <mar...@redhat.com>
> 
> Thanks,
> Marcel

Thanks, Marcel!
Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to