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

Reply via email to