Section 7.8.2 of the PCI Express specification (r4.0 v0.3), entitled "PCI Express Capabilities Register (Offset 02h)", describes the conditions when a PCIe port should be considered "supporting hotplug": - it should be a root complex port or a switch downstream port, and - it should have the "Slot Implemented" bit set.
This logic is already implemented in at least two open source projects I could find: - in SeaBIOS by Marcel Apfelbaum: "hw/pci: reserve IO and mem for pci express downstream ports with no devices attached" <https://code.coreboot.org/p/seabios/source/commit/3aa31d7d6375>, - in edk2 itself, in the implementation of the "PCI" UEFI Shell command: see the "PcieExplainTypeSlot" case label in function PciExplainPciExpress(), file "ShellPkg/Library/UefiShellDebug1CommandsLib/Pci.c". PciBusDxe recognizes such PCIe ports as bridges, but it doesn't realize they support hotplug. In turn PciBusDxe omits getting any resource padding information from the platform's EFI_PCI_HOT_PLUG_INIT_PROTOCOL for these bridges: GatherPpbInfo() [PciEnumeratorSupport.c] GetResourcePaddingPpb() [PciResourceSupport.c] GetResourcePaddingForHpb() [PciHotPlugSupport.c] IsPciHotPlugBus() [PciHotPlugSupport.c] // // returns FALSE // // // the following is not reached: // gPciHotPlugInit->GetResourcePadding() Implement a function called SupportsPcieHotplug() for identifying such ports, and call it from IsPciHotPlugBus() (after the call to IsSHPC()). Cc: "Johnson, Brian J." <[email protected]> Cc: Alex Williamson <[email protected]> Cc: Andrew Fish <[email protected]> Cc: Feng Tian <[email protected]> Cc: Jordan Justen <[email protected]> Cc: Marcel Apfelbaum <[email protected]> Cc: Ruiyu Ni <[email protected]> Cc: Star Zeng <[email protected]> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <[email protected]> --- MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h | 19 ++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c | 71 ++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h index 1fb9ba972091..6e02b8b98bf0 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h @@ -177,6 +177,25 @@ IsSHPC ( ); /** + Check whether PciIoDevice supports PCIe hotplug. + + This is equivalent to the following condition: + - the device is either a PCIe switch downstream port or a root port, + - and the device has the SlotImplemented bit set in its PCIe capability + register. + + @param[in] PciIoDevice The device being checked. + + @retval TRUE PciIoDevice is a PCIe port that accepts a hotplugged device. + @retval FALSE Otherwise. + +**/ +BOOLEAN +SupportsPcieHotplug ( + IN PCI_IO_DEVICE *PciIoDevice + ); + +/** Get resource padding if the specified PCI bridge is a hot plug bus. @param PciIoDevice PCI bridge instance. diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c index ca8766869ae7..19dd97a4528d 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c @@ -317,6 +317,69 @@ IsSHPC ( } /** + Check whether PciIoDevice supports PCIe hotplug. + + This is equivalent to the following condition: + - the device is either a PCIe switch downstream port or a root port, + - and the device has the SlotImplemented bit set in its PCIe capability + register. + + @param[in] PciIoDevice The device being checked. + + @retval TRUE PciIoDevice is a PCIe port that accepts a hotplugged device. + @retval FALSE Otherwise. + +**/ +BOOLEAN +SupportsPcieHotplug ( + IN PCI_IO_DEVICE *PciIoDevice + ) +{ + UINT32 Offset; + EFI_STATUS Status; + PCI_REG_PCIE_CAPABILITY Capability; + + if (PciIoDevice == NULL) { + return FALSE; + } + + // + // Read the PCI Express Capabilities Register + // + if (!PciIoDevice->IsPciExp) { + return FALSE; + } + Offset = PciIoDevice->PciExpressCapabilityOffset + + OFFSET_OF (PCI_CAPABILITY_PCIEXP, Capability); + + Status = PciIoDevice->PciIo.Pci.Read ( + &PciIoDevice->PciIo, + EfiPciIoWidthUint16, + Offset, + 1, + &Capability + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + // + // Check the contents of the register + // + switch (Capability.Bits.DevicePortType) { + case PCIE_DEVICE_PORT_TYPE_ROOT_PORT: + case PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT: + break; + default: + return FALSE; + } + if (Capability.Bits.SlotImplemented) { + return TRUE; + } + return FALSE; +} + +/** Get resource padding if the specified PCI bridge is a hot plug bus. @param PciIoDevice PCI bridge instance. @@ -382,6 +445,14 @@ IsPciHotPlugBus ( return TRUE; } + if (SupportsPcieHotplug (PciIoDevice)) { + // + // If the PPB is a PCIe root complex port or a switch downstream port, and + // implements a slot, then also return TRUE. + // + return TRUE; + } + // // Otherwise, see if it is a Root HPC // -- 1.8.3.1 _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

