From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by mx.groups.io with SMTP id smtpd.web09.10520.1581105960932621955 for ; Fri, 07 Feb 2020 12:06:01 -0800 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 192.55.52.115, mailfrom: ashraf.javeed@intel.com) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 12:06:00 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="225644120" Received: from unknown (HELO PIDSBABIOS005.gar.corp.intel.com) ([10.223.9.183]) by fmsmga007.fm.intel.com with ESMTP; 07 Feb 2020 12:05:56 -0800 From: "Javeed, Ashraf" To: devel@edk2.groups.io Cc: Jian J Wang , Hao A Wu , Ray Ni Subject: [edk2-staging/UEFI_PCI_ENHANCE-2 PATCH 01/12] MdeModulePkg/PciBusDxe: Setup for PCI Express features Date: Sat, 8 Feb 2020 01:34:36 +0530 Message-Id: <20200207200447.10536-2-ashraf.javeed@intel.com> X-Mailer: git-send-email 2.21.0.windows.1 In-Reply-To: <20200207200447.10536-1-ashraf.javeed@intel.com> References: <20200207200447.10536-1-ashraf.javeed@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit References:- https://bugzilla.tianocore.org/show_bug.cgi?id=1954 https://bugzilla.tianocore.org/show_bug.cgi?id=2194 https://bugzilla.tianocore.org/show_bug.cgi?id=2313 https://bugzilla.tianocore.org/show_bug.cgi?id=2499 https://bugzilla.tianocore.org/show_bug.cgi?id=2500 This code change represents the preparation of common code setup for the new PCI Express features initialization, utilizing the new PCI Express Platform / Override Protocol. The new set of source files are as follows:- new file: /PciFeatureSupport.c new file: /PciFeatureSupport.h new file: /PciPlatformSupport.c new file: /PciPlatformSupport.h Signed-off-by: Ashraf Javeed Cc: Jian J Wang Cc: Hao A Wu Cc: Ray Ni --- MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c | 6 +++++- MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h | 12 ++++++++++-- MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf | 9 ++++++++- MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c | 12 +++++++++++- MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c | 891 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c | 302 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 1540 insertions(+), 5 deletions(-) diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c index b020ce5..714101c 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c @@ -8,7 +8,7 @@ PCI Root Bridges. So it means platform needs install PCI Root Bridge IO protocol for each PCI Root Bus and install PCI Host Bridge Resource Allocation Protocol. -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -284,6 +284,10 @@ PciBusDriverBindingStart ( (VOID **) &gPciOverrideProtocol ); } + // + // get the PCI Express Protocol or the PCI Express Override Protocol + // + GetPciExpressProtocol (); if (mIoMmuProtocol == NULL) { gBS->LocateProtocol ( diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h index 504a1b1..225229d 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h @@ -1,7 +1,7 @@ /** @file Header files and data structures needed by PCI Bus module. -Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -42,6 +42,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include +#include typedef struct _PCI_IO_DEVICE PCI_IO_DEVICE; typedef struct _PCI_BAR PCI_BAR; @@ -79,6 +81,8 @@ typedef enum { #include "PciPowerManagement.h" #include "PciHotPlugSupport.h" #include "PciLib.h" +#include "PciPlatformSupport.h" +#include "PciFeatureSupport.h" #define VGABASE1 0x3B0 #define VGALIMIT1 0x3BB @@ -263,9 +267,13 @@ struct _PCI_IO_DEVICE { BOOLEAN IsPciExp; // - // For SR-IOV + // For PCI Express Capability List Structure // UINT8 PciExpressCapabilityOffset; + PCI_CAPABILITY_PCIEXP PciExpressCapabilityStructure; + // + // For SR-IOV + // UINT32 AriCapabilityOffset; UINT32 SrIovCapabilityOffset; UINT32 MrIovCapabilityOffset; diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf index 05c2202..f06b411 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf @@ -2,7 +2,7 @@ # The PCI bus driver will probe all PCI devices and allocate MMIO and IO space for these devices. # Please use PCD feature flag PcdPciBusHotplugDeviceSupport to enable hot plug supporting. # -# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -57,6 +57,10 @@ PciCommand.h PciIo.h PciBus.h + PciFeatureSupport.c + PciFeatureSupport.h + PciPlatformSupport.c + PciPlatformSupport.h [Packages] MdePkg/MdePkg.dec @@ -91,6 +95,9 @@ gEfiLoadFile2ProtocolGuid ## SOMETIMES_PRODUCES gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES gEfiLoadedImageDevicePathProtocolGuid ## CONSUMES + gEfiPciExpressPlatformProtocolGuid ## SOMETIMES_CONSUMES + gEfiPciExpressOverrideProtocolGuid ## SOMETIMES_CONSUMES + [FeaturePcd] gEfiMdeModulePkgTokenSpaceGuid.PcdPciBusHotplugDeviceSupport ## CONSUMES diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c index c7eafff..c9e52ea 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c @@ -1,7 +1,7 @@ /** @file PCI emumeration support functions implementation for PCI Bus module. -Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
(C) Copyright 2015 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -2154,6 +2154,16 @@ CreatePciIoDevice ( ); if (!EFI_ERROR (Status)) { PciIoDevice->IsPciExp = TRUE; + // + // read the PCI device's entire PCI Express Capability structure + // + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PciIoDevice->PciExpressCapabilityOffset, + sizeof (PCI_CAPABILITY_PCIEXP) / sizeof (UINT8), + &PciIoDevice->PciExpressCapabilityStructure + ); } if (PcdGetBool (PcdAriSupport)) { diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c new file mode 100644 index 0000000..3980a8e --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c @@ -0,0 +1,891 @@ +/** @file + PCI standard feature support functions implementation for PCI Bus module.. + +Copyright (c) 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PciBus.h" +#include "PciFeatureSupport.h" + +/** + Hold the current instance of Root Bridge IO protocol Handle +**/ +EFI_HANDLE mRootBridgeHandle; + +/** + A gobal pointer to BRIDGE_DEVICE_NODE buffer to track all the primary physical + PCI Root Ports (PCI Controllers) for a given PCI Root Bridge instance while + enumerating to configure the PCI features +**/ +LIST_ENTRY mRootBridgeDeviceList; + +/** + global list to indicate the supported PCI Express features of this driver, it + is expected to be overridden based on the platform request +**/ +EFI_PCI_EXPRESS_PLATFORM_POLICY mPciExpressPlatformPolicy = { + // + // support for PCI Express feature - Max. Payload Size + // + FALSE, + // + // support for PCI Express feature - Max. Read Request Size + // + FALSE, + // + // support for PCI Express feature - Extended Tag + // + FALSE, + // + // support for PCI Express feature - Relax Order + // + FALSE, + // + // support for PCI Express feature - No-Snoop + // + FALSE, + // + // support for PCI Express feature - ASPM state + // + FALSE, + // + // support for PCI Express feature - Common Clock Configuration + // + FALSE, + // + // support for PCI Express feature - Extended Sync + // + FALSE, + // + // support for PCI Express feature - Atomic Op + // + FALSE, + // + // support for PCI Express feature - LTR + // + FALSE, + // + // support for PCI Express feature - PTM + // + FALSE, + // + // support for PCI Express feature - Completion Timeout + // + FALSE, + // + // support for PCI Express feature - Clock Power Management + // + FALSE, + // + // support for PCI Express feature - L1 PM Substates + // + FALSE +}; + +// +// indicates the driver has completed query to platform on the list of supported +// PCI features to be configured +// +BOOLEAN mPciExpressGetPlatformPolicyComplete = FALSE; + +// +// PCI Express feature initialization phase handle routines +// +PCI_EXPRESS_FEATURE_INITIALIZATION_POINT mPciExpressFeatureInitializationList[] = { + // + // vacant entry, shall be replaced with actual entry when the PCI Express + // feature are added. + // + { 0, 0, NULL} +}; + +/** + Routine to serially dispatch the designated the PCI Express feature specific + functions defined for each of the configuration phase. The order for each phase + would be based entirely on the table mPciExpressFeatureInitializationList. + + @param PciDevice pointer to PCI_IO_DEVICE to identify device + @param PciExFeatureConfigPhase input configuration phase + @param PciExpressFeatureConfiguration used pointer to void to accomodate any PCI + Express feature specific data type + @retval EFI_STATUS output only from feature specific function + defined in the table mPciExpressFeatureInitializationList +**/ +EFI_STATUS +DispatchPciExpressInitializationFunctions ( + IN PCI_IO_DEVICE *PciDevice, + IN PCI_EXPRESS_FEATURE_CONFIGURATION_PHASE PciExFeatureConfigPhase, + IN VOID *PciExpressFeatureConfiguration + ) +{ + UINTN idx; + EFI_STATUS Status; + UINT8 *PciExpressPolicy; + + for ( + idx = 0, PciExpressPolicy = (UINT8*)&mPciExpressPlatformPolicy + ; idx < sizeof (mPciExpressFeatureInitializationList) / sizeof (PCI_EXPRESS_FEATURE_INITIALIZATION_POINT) + ; idx++ + ){ + if ( + // + // match the configuration phase + // + mPciExpressFeatureInitializationList[idx].PciExpressFeatureConfigurationPhase == PciExFeatureConfigPhase + // + // check whether the PCI Express features is enabled + // + && PciExpressPolicy[mPciExpressFeatureInitializationList[idx].PciExpressFeatureId] == TRUE + ) { + Status = mPciExpressFeatureInitializationList[idx].PciExpressFeatureConfigurationRoutine ( + PciDevice, + PciExpressFeatureConfiguration + ); + } + } + return Status; +} + +/** + Main routine to indicate platform selection of any of the other PCI features + to be configured by this driver + + @retval TRUE platform has selected the other PCI features to be configured + FALSE platform has not selected any of the other PCI features +**/ +BOOLEAN +CheckPciExpressFeatureList ( + ) +{ + UINTN length; + UINT8 *list; + + for ( + length = 0, list = (UINT8*)&mPciExpressPlatformPolicy + ; length < sizeof (EFI_PCI_EXPRESS_PLATFORM_POLICY) + ; length++ + ) { + if (list[length]) { + return TRUE; + } + } + return FALSE; +} + +/** + helper routine to wipe out the global PCI Express feature list +**/ +VOID +NegatePciExpressFeatureList ( + ) +{ + UINTN length; + UINT8 *list; + + for ( + length = 0, list = (UINT8*)&mPciExpressPlatformPolicy + ; length < sizeof (EFI_PCI_EXPRESS_PLATFORM_POLICY) + ; length++ + ) { + if (list[length]) { + list[length] = FALSE; + } + } +} + +/** + Main routine to indicate whether the PCI Express feature initialization is + required or not + + @retval TRUE PCI Express feature initialization required + FALSE PCI Express feature not required +**/ +BOOLEAN +IsPciExpressFeatureConfigurationRequired ( + ) +{ + EFI_STATUS Status; + + if (mPciExpressGetPlatformPolicyComplete) { + return CheckPciExpressFeatureList (); + } + // + // initialize the PCI Express feature data members + // + InitializeListHead (&mRootBridgeDeviceList); + // + // check the platform to configure the PCI Express features + // + mPciExpressGetPlatformPolicyComplete = TRUE; + + Status = PciExpressPlatformGetPolicy (); + if (EFI_ERROR (Status)) { + // + // fail to obtain the PCI Express feature configuration from platform, + // negate the list to avoid any unwanted configuration + // + NegatePciExpressFeatureList (); + return FALSE; + } + // + // PCI Express feature configuration list is ready from platform + // + return TRUE; +} + + +/** + Indicates whether the set of PCI Express features selected by platform requires + extended setup, that has additional resources that would be allocated to align + all the devices in the PCI tree, and free the resources later. + + @retval TRUE PCI Express feature requires extended setup + FALSE PCI Express feature does not require extended setup +**/ +BOOLEAN +IsPciExpressFeatureExtendedSetupRequired ( + ) +{ + UINTN idx; + UINT8 *PciExpressPolicy; + // + // return TRUE only for those features which are required to be aligned with + // common values among all the devices in the PCI tree + // + for ( + idx = 0, PciExpressPolicy = (UINT8*)&mPciExpressPlatformPolicy + ; idx < sizeof (mPciExpressFeatureInitializationList) / sizeof (PCI_EXPRESS_FEATURE_INITIALIZATION_POINT) + ; idx++ + ){ + if ( + // + // match the configuration phase to extended setup phase + // + mPciExpressFeatureInitializationList[idx].PciExpressFeatureConfigurationPhase == PciExpressFeatureEntendedSetupPhase + // + // check whether the PCI Express features is enabled + // + && PciExpressPolicy[mPciExpressFeatureInitializationList[idx].PciExpressFeatureId] == TRUE + ) { + return TRUE; + } + } + + return FALSE; +} + +/** + Helper routine to determine the existence of previously enumerated PCI device + + @retval TRUE PCI device exist + FALSE does not exist +**/ +BOOLEAN +DeviceExist ( + PCI_IO_DEVICE *PciDevice + ) +{ + EFI_PCI_IO_PROTOCOL *PciIoProtocol = &PciDevice->PciIo; + UINT16 VendorId = 0xFFFF; + + PciIoProtocol->Pci.Read ( + PciIoProtocol, + EfiPciIoWidthUint16, + PCI_VENDOR_ID_OFFSET, + 1, + &VendorId + ); + if (VendorId == 0 || VendorId == 0xFFFF) { + return FALSE; + } else { + return TRUE; + } +} + +/** + Free up memory alloted for the primary physical PCI Root ports of the PCI Root + Bridge instance. Free up all the nodes of type BRIDGE_DEVICE_NODE. +**/ +VOID +DestroyRootBridgeDeviceNodes () +{ + LIST_ENTRY *Link; + BRIDGE_DEVICE_NODE *Temp; + + Link = mRootBridgeDeviceList.ForwardLink; + while (Link != NULL && Link != &mRootBridgeDeviceList) { + Temp = ROOT_BRIDGE_DEVICE_NODE_FROM_LINK (Link); + Link = RemoveEntryList (Link); + FreePool (Temp->PciExFeaturesConfigurationTable); + FreePool (Temp); + } +} + +/** + Main routine to determine the child PCI devices of a PCI bridge device + and group them under a common internal PCI features Configuration table. + + @param PciDevice A pointer to the PCI_IO_DEVICE. + @param PciFeaturesConfigTable A pointer to a pointer to the + PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE. + Returns NULL in case of RCiEP or the PCI + device does match with any of the physical + Root ports, or it does not belong to any + Root port's PCI bus range (not a child) + + @retval EFI_SUCCESS able to determine the PCI feature + configuration table. For RCiEP since + since it is not prepared. + EFI_DEVICE_ERROR the PCI device has invalid EFI device + path +**/ +EFI_STATUS +GetPciExpressFeaturesConfigurationTable ( + IN PCI_IO_DEVICE *PciDevice, + OUT PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE **PciFeaturesConfigTable + ) +{ + LIST_ENTRY *Link; + BRIDGE_DEVICE_NODE *Temp; + BOOLEAN NodeMatch; + EFI_DEVICE_PATH_PROTOCOL *RootPortPath; + EFI_DEVICE_PATH_PROTOCOL *PciDevicePath; + + if (IsListEmpty (&mRootBridgeDeviceList)) { + // + // no populated PCI primary root ports to parse and match the PCI features + // configuration table + // + *PciFeaturesConfigTable = NULL; + return EFI_SUCCESS; + } + + // + // The PCI features configuration table is not built for RCiEP, return NULL + // + if (PciDevice->PciExpressCapabilityStructure.Capability.Bits.DevicePortType == \ + PCIE_DEVICE_PORT_TYPE_ROOT_COMPLEX_INTEGRATED_ENDPOINT) { + *PciFeaturesConfigTable = NULL; + return EFI_SUCCESS; + } + + if (IsDevicePathEnd (PciDevice->DevicePath)){ + // + // the given PCI device does not have a valid device path + // + *PciFeaturesConfigTable = NULL; + return EFI_DEVICE_ERROR; + } + + + Link = mRootBridgeDeviceList.ForwardLink; + do { + Temp = ROOT_BRIDGE_DEVICE_NODE_FROM_LINK (Link); + RootPortPath = Temp->RootBridgeDevicePath; + PciDevicePath = PciDevice->DevicePath; + NodeMatch = FALSE; + // + // match the device path from the list of primary Root Ports with the given + // device; the initial nodes matching in sequence indicate that the given PCI + // device belongs to that PCI tree from the root port + // + if (IsDevicePathEnd (RootPortPath)) { + // + // critical error as no device path available in root + // + *PciFeaturesConfigTable = NULL; + return EFI_DEVICE_ERROR; + } + + if (EfiCompareDevicePath (RootPortPath, PciDevicePath)) { + // + // the given PCI device is the primary root port itself + // + *PciFeaturesConfigTable = Temp->PciExFeaturesConfigurationTable; + return EFI_SUCCESS; + } + // + // check this PCI device belongs to the primary root port of the root bridge + // any child PCI device will have the same initial device path nodes as + // its parent root port + // + while (!IsDevicePathEnd (RootPortPath)){ + + if (DevicePathNodeLength (RootPortPath) != DevicePathNodeLength (PciDevicePath)) { + // + // break to check the next primary root port nodes as does not match + // + NodeMatch = FALSE; + break; + } + if (CompareMem (RootPortPath, PciDevicePath, DevicePathNodeLength (RootPortPath)) != 0) { + // + // node does not match, break to check next node + // + NodeMatch = FALSE; + break; + } + NodeMatch = TRUE; + // + // advance to next node + // + RootPortPath = NextDevicePathNode (RootPortPath); + PciDevicePath = NextDevicePathNode (PciDevicePath); + } + + if (NodeMatch == TRUE) { + // + // device belongs to primary root port, return its PCI feature configuration + // table + // + *PciFeaturesConfigTable = Temp->PciExFeaturesConfigurationTable; + return EFI_SUCCESS; + } + + // + // advance to next Root port node + // + Link = Link->ForwardLink; + } while (Link != &mRootBridgeDeviceList && Link != NULL); + // + // the PCI device must be RCiEP, does not belong to any primary root port + // + *PciFeaturesConfigTable = NULL; + return EFI_SUCCESS; +} + +/** + helper routine to dump the PCIe Device Port Type +**/ +VOID +DumpDevicePortType ( + IN UINT8 DevicePortType + ) +{ + switch (DevicePortType){ + case PCIE_DEVICE_PORT_TYPE_PCIE_ENDPOINT: + DEBUG (( DEBUG_INFO, "PCIe endpoint found\n")); + break; + case PCIE_DEVICE_PORT_TYPE_LEGACY_PCIE_ENDPOINT: + DEBUG (( DEBUG_INFO, "legacy PCI endpoint found\n")); + break; + case PCIE_DEVICE_PORT_TYPE_ROOT_PORT: + DEBUG (( DEBUG_INFO, "PCIe Root Port found\n")); + break; + case PCIE_DEVICE_PORT_TYPE_UPSTREAM_PORT: + DEBUG (( DEBUG_INFO, "PCI switch upstream port found\n")); + break; + case PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT: + DEBUG (( DEBUG_INFO, "PCI switch downstream port found\n")); + break; + case PCIE_DEVICE_PORT_TYPE_PCIE_TO_PCI_BRIDGE: + DEBUG (( DEBUG_INFO, "PCIe-PCI bridge found\n")); + break; + case PCIE_DEVICE_PORT_TYPE_PCI_TO_PCIE_BRIDGE: + DEBUG (( DEBUG_INFO, "PCI-PCIe bridge found\n")); + break; + case PCIE_DEVICE_PORT_TYPE_ROOT_COMPLEX_INTEGRATED_ENDPOINT: + DEBUG (( DEBUG_INFO, "RCiEP found\n")); + break; + case PCIE_DEVICE_PORT_TYPE_ROOT_COMPLEX_EVENT_COLLECTOR: + DEBUG (( DEBUG_INFO, "RC Event Collector found\n")); + break; + } +} + +/** + Setup each PCI device as per the pltaform's device-specific policy, in accordance + with PCI Express Base specification. + + @param RootBridge A pointer to the PCI_IO_DEVICE. + + @retval EFI_SUCCESS processing each PCI feature as per policy defined + was successful. + **/ +EFI_STATUS +SetupDevicePciExpressFeatures ( + IN PCI_IO_DEVICE *PciDevice, + IN PCI_EXPRESS_FEATURE_CONFIGURATION_PHASE PciConfigPhase + ) +{ + EFI_STATUS Status; + PCI_REG_PCIE_CAPABILITY PcieCap; + PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE *PciExpressFeaturesConfigTable; + + PciExpressFeaturesConfigTable = NULL; + Status = GetPciExpressFeaturesConfigurationTable (PciDevice, &PciExpressFeaturesConfigTable); + + if (PciConfigPhase == PciExpressFeatureSetupPhase) { + DEBUG_CODE ( + if (EFI_ERROR( Status)) { + DEBUG (( + DEBUG_WARN, + "[Cfg group: 0 {error in dev path}]" + )); + } else if (PciExpressFeaturesConfigTable == NULL) { + DEBUG (( + DEBUG_INFO, + "[Cfg group: 0]" + )); + } else { + DEBUG (( + DEBUG_INFO, + "[Cfg group: %d]", + PciExpressFeaturesConfigTable->ID + )); + } + PcieCap.Uint16 = PciDevice->PciExpressCapabilityStructure.Capability.Uint16; + DumpDevicePortType ((UINT8)PcieCap.Bits.DevicePortType); + ); + + // + // get the device-specific platform policy for the PCI Express features + // + Status = PciExpressPlatformGetDevicePolicy (PciDevice); + if (EFI_ERROR(Status)) { + DEBUG (( + DEBUG_ERROR, + "Error in obtaining PCI device policy!!!\n" + )); + } + } + + DEBUG ((DEBUG_INFO, "[")); + + Status = DispatchPciExpressInitializationFunctions ( + PciDevice, + PciConfigPhase, + PciExpressFeaturesConfigTable + ); + + DEBUG ((DEBUG_INFO, "]\n")); + return Status; +} + +/** + Create and append a node of type BRIDGE_DEVICE_NODE in the list for the primary + Root Port so that all its child PCI devices can be identified against the PCI + features configuration table group ID, of type PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE. + + @param BridgePort A pointer to the PCI_IO_DEVICE + @param PortNumber A UINTN value to identify the PCI feature configuration + table group + + @retval EFI_SUCCESS success in adding a node of BRIDGE_DEVICE_NODE + to the list + EFI_OUT_OF_RESOURCES unable to get memory for creating the node +**/ +EFI_STATUS +CreatePciRootBridgeDeviceNode ( + IN PCI_IO_DEVICE *BridgePort, + IN UINTN PortNumber + ) +{ + BRIDGE_DEVICE_NODE *RootBridgeNode = NULL; + PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE *PciConfigTable = NULL; + + RootBridgeNode = AllocateZeroPool (sizeof (BRIDGE_DEVICE_NODE)); + if (RootBridgeNode == NULL) { + return EFI_OUT_OF_RESOURCES; + } + RootBridgeNode->Signature = PCI_ROOT_BRIDGE_DEVICE_SIGNATURE; + RootBridgeNode->RootBridgeDevicePath = BridgePort->DevicePath; + PciConfigTable = AllocateZeroPool ( + sizeof (PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE) + ); + if (PciConfigTable) { + PciConfigTable->ID = PortNumber; + } + + RootBridgeNode->PciExFeaturesConfigurationTable = PciConfigTable; + + InsertTailList (&mRootBridgeDeviceList, &RootBridgeNode->NextRootBridgeDevice); + + if (PciConfigTable == NULL) { + return EFI_OUT_OF_RESOURCES; + } + return EFI_SUCCESS; +} + +/** + Scan all the nodes of the RootBridge to identify and create a separate list + of all primary physical PCI root ports and link each with its own instance of + the PCI Feature Configuration Table. + + @param RootBridge A pointer to the PCI_IO_DEVICE of the PCI Root Bridge + + @retval EFI_OUT_OF_RESOURCES unable to allocate buffer to store PCI feature + configuration table for all the physical PCI root + ports given + EFI_NOT_FOUND No PCI Bridge device found + EFI_SUCCESS PCI Feature COnfiguration table created for all + the PCI Rooot ports found + EFI_INVALID_PARAMETER invalid parameter passed to the routine which + creates the PCI controller node for the primary + Root post list +**/ +EFI_STATUS +CreatePciRootBridgeDeviceList ( + IN PCI_IO_DEVICE *RootBridge + ) +{ + EFI_STATUS Status = EFI_NOT_FOUND; + LIST_ENTRY *Link; + PCI_IO_DEVICE *Device; + UINTN BridgeDeviceCount; + + BridgeDeviceCount = 0; + for ( Link = RootBridge->ChildList.ForwardLink + ; Link != &RootBridge->ChildList + ; Link = Link->ForwardLink + ) { + Device = PCI_IO_DEVICE_FROM_LINK (Link); + if (!DeviceExist (Device)) { + continue; + } + if (IS_PCI_BRIDGE (&Device->Pci)) { + BridgeDeviceCount++; + DEBUG (( + DEBUG_INFO, + "#%d ::Bridge [%02x|%02x|%02x]", + BridgeDeviceCount, Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber + )); + // + // create a list of bridge devices if that is connected to any other device + // + if (!IsListEmpty (&Device->ChildList)) { + DEBUG (( + DEBUG_INFO, + "- has downstream device!\n" + )); + Status = CreatePciRootBridgeDeviceNode (Device, BridgeDeviceCount); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "PCI configuration table allocation failure for #%d ::Bridge [%02x|%02x|%02x]\n", + BridgeDeviceCount, Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber + )); + } + } else { + DEBUG (( + DEBUG_INFO, + "- no downstream device!\n" + )); + } + } + } + + return Status; +} + +/** + Initialize the device's PCI Express features, in a staged manner + @param PciDevice A pointer to the PCI_IO_DEVICE. + + @retval EFI_SUCCESS initializing all the nodes of the root bridge + instances were successfull. +**/ +EFI_STATUS +InitializeDevicePciExpressFeatures ( + IN PCI_IO_DEVICE *PciDevice, + IN PCI_EXPRESS_FEATURE_CONFIGURATION_PHASE PciConfigPhase + ) +{ + EFI_STATUS Status; + + switch (PciConfigPhase) { + case PciExpressFeatureSetupPhase: + case PciExpressFeatureEntendedSetupPhase: + case PciExpressFeatureProgramPhase: + Status = SetupDevicePciExpressFeatures (PciDevice, PciConfigPhase); + break; + case PciExpressFeatureEndPhase: + Status = PciExpressPlatformNotifyDeviceState (PciDevice); + break; + } + return Status; +} + +/** + Traverse all the nodes from the root bridge or PCI-PCI bridge instance, to + configure the PCI Express features as per the PCI Express Base Secification + by considering its device-specific platform policy, and its device capability, + as applicable. + + @param RootBridge A pointer to the PCI_IO_DEVICE. + + @retval EFI_SUCCESS Traversing all the nodes of the root bridge + instances were successfull. +**/ +EFI_STATUS +InitializePciExpressFeatures ( + IN PCI_IO_DEVICE *RootBridge, + IN PCI_EXPRESS_FEATURE_CONFIGURATION_PHASE PciConfigPhase + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + PCI_IO_DEVICE *Device; + + for ( Link = RootBridge->ChildList.ForwardLink + ; Link != &RootBridge->ChildList + ; Link = Link->ForwardLink + ) { + Device = PCI_IO_DEVICE_FROM_LINK (Link); + if (!DeviceExist (Device)) { + DEBUG (( + DEBUG_ERROR, + "::Device [%02x|%02x|%02x] - does not exist!!!\n", + Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber + )); + continue; + } + if (IS_PCI_BRIDGE (&Device->Pci)) { + DEBUG (( + DEBUG_INFO, + "::Bridge [%02x|%02x|%02x] -", + Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber + )); + if (Device->IsPciExp) { + Status = InitializeDevicePciExpressFeatures ( + Device, + PciConfigPhase + ); + } else { + DEBUG (( + DEBUG_INFO, + "Not a PCIe capable device!\n" + )); + // + // PCI Bridge which does not have PCI Express Capability structure + // cannot process this kind of PCI Bridge device + // + } + + InitializePciExpressFeatures (Device, PciConfigPhase); + } else { + DEBUG (( + DEBUG_INFO, + "::Device [%02x|%02x|%02x] -", + Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber + )); + if (Device->IsPciExp) { + Status = InitializeDevicePciExpressFeatures ( + Device, + PciConfigPhase + ); + } else { + DEBUG (( + DEBUG_INFO, + "Not a PCIe capable device!\n" + )); + // + // PCI Device which does not have PCI Express Capability structure + // cannot process this kind of PCI device + // + } + } + } + + return EFI_SUCCESS; +} + +/** + Enumerate all the nodes of the specified root bridge or PCI-PCI Bridge, to + configure the other PCI features. + + @param RootBridge A pointer to the PCI_IO_DEVICE. + + @retval EFI_SUCCESS The other PCI features configuration during enumeration + of all the nodes of the PCI root bridge instance were + programmed in PCI-compliance pattern along with the + device-specific policy, as applicable. + @retval EFI_UNSUPPORTED One of the override operation maong the nodes of + the PCI hierarchy resulted in a incompatible address + range. + @retval EFI_INVALID_PARAMETER The override operation is performed with invalid input + parameters. +**/ +EFI_STATUS +EnumeratePciExpressFeatures ( + IN EFI_HANDLE Controller, + IN PCI_IO_DEVICE *RootBridge + ) +{ + EFI_STATUS Status; + UINTN PciExpressFeatureConfigPhase; + + if (!IsPciExpressFeatureConfigurationRequired ()) { + // + // exit as agreement is not reached with platform to configure the PCI + // Express features + // + return EFI_SUCCESS; + } + mRootBridgeHandle = Controller; + + DEBUG_CODE ( + CHAR16 *Str; + Str = ConvertDevicePathToText ( + DevicePathFromHandle (RootBridge->Handle), + FALSE, + FALSE + ); + DEBUG (( + DEBUG_INFO, + "Enumerating PCI features for Root Bridge %s\n", + Str != NULL ? Str : L"" + )); + + if (Str != NULL) { + FreePool (Str); + } + ); + + for ( PciExpressFeatureConfigPhase = PciExpressFeaturePreProcessPhase + ; PciExpressFeatureConfigPhase <= PciExpressFeatureEndPhase + ; PciExpressFeatureConfigPhase++ + ) { + DEBUG (( + DEBUG_INFO, + "<<********** Phase [%d]**********>>\n", + PciExpressFeatureConfigPhase + )); + if (PciExpressFeatureConfigPhase == PciExpressFeaturePreProcessPhase) { + // + // create a list of root bridge devices (root ports) of the root complex + // if extra setup phase required + // + if (IsPciExpressFeatureExtendedSetupRequired ()) { + CreatePciRootBridgeDeviceList (RootBridge); + } + continue; + } + if (PciExpressFeatureConfigPhase == PciExpressFeatureEntendedSetupPhase) { + if (!IsPciExpressFeatureExtendedSetupRequired ()) { + // + // since the PCI Express features require no extra initialization steps + // skip this phase + // + continue; + } + } + // + // setup the PCI Express features + // + Status = InitializePciExpressFeatures (RootBridge, PciExpressFeatureConfigPhase); + + if (PciExpressFeatureConfigPhase == PciExpressFeatureEndPhase) { + // + // clean up the temporary resource nodes created for this root bridge + // + if (IsPciExpressFeatureExtendedSetupRequired ()) { + DestroyRootBridgeDeviceNodes (); + } + } + } + + return Status; +} diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h new file mode 100644 index 0000000..2eff8aa --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h @@ -0,0 +1,226 @@ +/** @file + PCI standard feature support functions implementation for PCI Bus module.. + +Copyright (c) 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_PCI_FEATURES_SUPPORT_H_ +#define _EFI_PCI_FEATURES_SUPPORT_H_ + +extern EFI_HANDLE mRootBridgeHandle; +extern EFI_PCI_EXPRESS_PLATFORM_POLICY mPciExpressPlatformPolicy; +// +// defines the data structure to hold the details of the PCI Root port devices +// +typedef struct _BRIDGE_DEVICE_NODE BRIDGE_DEVICE_NODE; + +// +// defines the data structure to hold the configuration data for the other PCI +// features +// +typedef struct _PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE; + +// +// define the data type for the PCI feature policy support +// +typedef struct _PCI_FEATURE_POLICY PCI_FEATURE_POLICY; + +// +// Signature value for the PCI Root Port node +// +#define PCI_ROOT_BRIDGE_DEVICE_SIGNATURE SIGNATURE_32 ('p', 'c', 'i', 'p') + +// +// Definitions of the PCI Root Port data structure members +// +struct _BRIDGE_DEVICE_NODE { + // + // Signature header + // + UINT32 Signature; + // + // linked list pointers to next node + // + LIST_ENTRY NextRootBridgeDevice; + // + // pointer to PCI_IO_DEVICE of the primary PCI Controller device + // + EFI_DEVICE_PATH_PROTOCOL *RootBridgeDevicePath; + // + // pointer to the corresponding PCI Express feature configuration Table node + // all the child PCI devices of the controller are aligned based on this table + // + PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE *PciExFeaturesConfigurationTable; +}; + +#define ROOT_BRIDGE_DEVICE_NODE_FROM_LINK(a) \ + CR (a, BRIDGE_DEVICE_NODE, NextRootBridgeDevice, PCI_ROOT_BRIDGE_DEVICE_SIGNATURE) + +// +// Definition of the PCI Feature configuration Table members +// +struct _PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE { + // + // Configuration Table ID + // + UINTN ID; +}; + +// +// Declaration of the internal sub-phases during enumeration to configure the PCI +// Express features +// +typedef enum { + // + // preprocessing applicable only to few PCI Express features to bind all devices + // under the common root bridge device (root port), that would be useful to align + // all devices with a common value. This would be optional phase based on the + // type of the PCI Express feature to be programmed based on platform policy + // + PciExpressFeaturePreProcessPhase, + + // + // mandatory phase to setup the PCI Express feature to its applicable attribute, + // based on its device-specific platform policies, matching with its device capabilities + // + PciExpressFeatureSetupPhase, + + // + // optional phase primarily to align all devices, specially required when PCI + // switch is present in the hierarchy, applicable to certain few PCI Express + // features only + // + PciExpressFeatureEntendedSetupPhase, + + // + // mandatory programming phase to complete the configuration of the PCI Express + // features + // + PciExpressFeatureProgramPhase, + + // + // optional phase to clean up temporary buffers, like those that were prepared + // during the preprocessing phase above + // + PciExpressFeatureEndPhase + +}PCI_EXPRESS_FEATURE_CONFIGURATION_PHASE; + +// +// declaration for the data type to harbor the PCI feature policies +// +struct _PCI_FEATURE_POLICY { + // + // if set, it indicates the feature should be enabled + // if clear, it indicates the feature should be disabled + // + UINT8 Act : 1; + // + // this field will be specific to feature, it can be implementation specific + // or it can be reserved and remain unused + // + UINT8 Support : 6; + // + // if set indicates override the feature policy defined by the members above + // if clear it indicates that this feature policy should be ignored completely + // this means the above two members should not be used + // + UINT8 Override : 1; +}; + +// +// Declaration of the PCI Express features unique Id +// +typedef enum { + // + // support for PCI Express feature - Max. Payload Size + // + PciExpressMps, + // + // support for PCI Express feature - Max. Read Request Size + // + PciExpressMrrs, + // + // support for PCI Express feature - Extended Tag + // + PciExpressExtTag, + // + // support for PCI Express feature - Relax Order + // + PciExpressRelaxOrder, + // + // support for PCI Express feature - No-Snoop + // + PciExpressNoSnoop, + // + // support for PCI Express feature - ASPM state + // + PciExpressAspm, + // + // support for PCI Express feature - Common Clock Configuration + // + PciExpressCcc, + // + // support for PCI Express feature - Extended Sync + // + PciExpressExtSync, + // + // support for PCI Express feature - Atomic Op + // + PciExpressAtomicOp, + // + // support for PCI Express feature - LTR + // + PciExpressLtr, + // + // support for PCI Express feature - PTM + // + PciExpressPtm, + // + // support for PCI Express feature - Completion Timeout + // + PciExpressCto, + // + // support for PCI Express feature - Clock Power Management + // + PciExpressCpm, + // + // support for PCI Express feature - L1 PM Substates + // + PciExpressL1PmSubstates + +} PCI_EXPRESS_FEATURE_ID; + +// +// PCI Express feature configuration routine during initialization phases +// +typedef +EFI_STATUS +(*PCI_EXPRESS_FEATURE_CONFIGURATION_ROUTINE) ( + IN PCI_IO_DEVICE *PciDevice, + IN VOID *PciExpressFeatureConfiguration + ); + +// +// data type for the PCI Express feature initialization phases +// +typedef struct { + // + // Pci Express feature configuration phase + // + PCI_EXPRESS_FEATURE_CONFIGURATION_PHASE PciExpressFeatureConfigurationPhase; + // + // PCI Express feature Id + // + PCI_EXPRESS_FEATURE_ID PciExpressFeatureId; + // + // PCI Express feature configuration routine + // + PCI_EXPRESS_FEATURE_CONFIGURATION_ROUTINE PciExpressFeatureConfigurationRoutine; + +}PCI_EXPRESS_FEATURE_INITIALIZATION_POINT; + + +#endif diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c new file mode 100644 index 0000000..31c675d --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c @@ -0,0 +1,302 @@ +/** @file + This file encapsulate the usage of PCI Platform Protocol + + This file define the necessary hooks used to obtain the platform + level data and policies which could be used in the PCI Enumeration phases + +Copyright (c) 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PciBus.h" + + +EFI_PCI_EXPRESS_PLATFORM_PROTOCOL *mPciExPlatformProtocol; +EFI_PCI_EXPRESS_OVERRIDE_PROTOCOL *mPciExOverrideProtocol; + + +/** + This function retrieves the PCI Express Platform Protocols published by platform + @retval EFI_STATUS direct return status from the LocateProtocol () + boot service for the PCI Express Override Protocol + EFI_SUCCESS The PCI Express Platform Protocol is found +**/ +EFI_STATUS +GetPciExpressProtocol ( + ) +{ + EFI_STATUS Status; + + if (mPciExPlatformProtocol) { + // + // the PCI Express Platform Protocol is already initialized + // + return EFI_SUCCESS; + } + if (mPciExOverrideProtocol) { + // + // the PCI Express Override Protocol is already initialized + // + return EFI_SUCCESS; + } + // + // locate the PCI Express Platform Protocol + // + Status = gBS->LocateProtocol ( + &gEfiPciExpressPlatformProtocolGuid, + NULL, + (VOID **) &mPciExPlatformProtocol + ); + if (!EFI_ERROR (Status)) { + return Status; + } + // + // If PCI Express Platform protocol doesn't exist, try to get the Pci Express + // Override Protocol. + // + return gBS->LocateProtocol ( + &gEfiPciExpressOverrideProtocolGuid, + NULL, + (VOID **) &mPciExOverrideProtocol + ); +} + +/** + This function indicates that the platform has published the PCI Express Platform + Protocol (or PCI Express Override Protocol) to indicate that this driver can + initialize the PCI Express features. + @retval TRUE or FALSE +**/ +BOOLEAN +IsPciExpressProtocolPresent ( + ) +{ + if ( + mPciExPlatformProtocol == NULL + && mPciExOverrideProtocol == NULL + ) { + return FALSE; + } + return TRUE; +} + + +/** + Generic routine to setup the PCI features as per its predetermined defaults. +**/ +VOID +SetupDefaultPciExpressDevicePolicy ( + IN PCI_IO_DEVICE *PciDevice + ) +{ + +} + +/** + initialize the device policy data members +**/ +VOID +InitializeDevicePolicyData ( + IN EFI_PCI_EXPRESS_DEVICE_POLICY *PciExpressDevicePolicy + ) +{ + UINTN length; + UINT8 *PciExpressPolicy; + UINT8 *PciExDevicePolicy; + + + ZeroMem (PciExpressDevicePolicy, sizeof (EFI_PCI_EXPRESS_DEVICE_POLICY)); + + for ( + length = 0 + , PciExpressPolicy = (UINT8*)&mPciExpressPlatformPolicy + , PciExDevicePolicy = (UINT8*)PciExpressDevicePolicy + ; length < sizeof (EFI_PCI_EXPRESS_PLATFORM_POLICY) + ; length++ + ) { + if (!PciExpressPolicy[length]) { + PciExDevicePolicy[length] = EFI_PCI_EXPRESS_NOT_APPLICABLE; + } + } +} + +/** + Intermediate routine to either get the PCI device specific platform policies + through the PCI Platform Protocol, or its alias the PCI Override Protocol. + + @param PciDevice A pointer to PCI_IO_DEVICE + @param PciPlatformProtocol A pointer to EFI_PCI_EXPRESS_PLATFORM_PROTOCOL + + @retval EFI_STATUS The direct status from the PCI Platform Protocol + @retval EFI_SUCCESS if on returning predetermined PCI features defaults, + for the case when protocol returns as EFI_UNSUPPORTED + to indicate PCI device exist and it has no platform + policy defined. +**/ +EFI_STATUS +GetPciExpressDevicePolicy ( + IN PCI_IO_DEVICE *PciDevice, + IN EFI_PCI_EXPRESS_PLATFORM_PROTOCOL *PciPlatformProtocol + ) +{ + EFI_PCI_EXPRESS_DEVICE_POLICY PciExpressDevicePolicy; + EFI_STATUS Status; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress; + + PciAddress.Bus = PciDevice->BusNumber; + PciAddress.Device = PciDevice->DeviceNumber; + PciAddress.Function = PciDevice->FunctionNumber; + PciAddress.Register = 0; + PciAddress.ExtendedRegister = 0; + + InitializeDevicePolicyData (&PciExpressDevicePolicy); + Status = PciPlatformProtocol->GetDevicePolicy ( + PciPlatformProtocol, + mRootBridgeHandle, + PciAddress, + sizeof (EFI_PCI_EXPRESS_DEVICE_POLICY), + &PciExpressDevicePolicy + ); + if (!EFI_ERROR(Status)) { + // + // platform chipset policies are returned for this PCI device + // + + + DEBUG (( + DEBUG_INFO, + "[device policy: platform]" + )); + return Status; + } else if (Status == EFI_UNSUPPORTED) { + // + // platform chipset policies are not provided for this PCI device + // let the enumeration happen as per the PCI standard way + // + SetupDefaultPciExpressDevicePolicy (PciDevice); + DEBUG (( + DEBUG_INFO, + "[device policy: default]" + )); + return EFI_SUCCESS; + } + DEBUG (( + DEBUG_ERROR, + "[device policy: none (error)]" + )); + return Status; +} + +/** + Gets the PCI device-specific platform policy from the PCI Express Platform Protocol. + If no PCI Platform protocol is published than setup the PCI feature to predetermined + defaults, in order to align all the PCI devices in the PCI hierarchy, as applicable. + + @param PciDevice A pointer to PCI_IO_DEVICE + + @retval EFI_STATUS The direct status from the PCI Platform Protocol + @retval EFI_SUCCESS On return of predetermined PCI features defaults, for + the case when protocol returns as EFI_UNSUPPORTED to + indicate PCI device exist and it has no platform policy + defined. Also, on returns when no PCI Platform Protocol + exist. +**/ +EFI_STATUS +PciExpressPlatformGetDevicePolicy ( + IN PCI_IO_DEVICE *PciDevice + ) +{ + if (mPciExPlatformProtocol != NULL) { + return GetPciExpressDevicePolicy (PciDevice, mPciExPlatformProtocol); + } else if (mPciExOverrideProtocol != NULL) { + return GetPciExpressDevicePolicy (PciDevice, mPciExOverrideProtocol); + } else { + // + // no protocol found, platform does not require the PCI Express initialization + // + return EFI_UNSUPPORTED; + } +} + +/** + This function gets the platform requirement to initialize the list of PCI Express + features from the protocol definition supported. + This function should be called after the LocatePciPlatformProtocol. + @retval EFI_SUCCESS return by platform to acknowledge the list of + PCI Express feature to be configured + (in mPciExpressPlatformPolicy) + EFI_INVALID_PARAMETER platform does not support the protocol arguements + passed + EFI_UNSUPPORTED platform did not published the protocol +**/ +EFI_STATUS +PciExpressPlatformGetPolicy ( + ) +{ + EFI_STATUS Status; + + if (mPciExPlatformProtocol) { + Status = mPciExPlatformProtocol->GetPolicy ( + mPciExPlatformProtocol, + sizeof (EFI_PCI_EXPRESS_PLATFORM_POLICY), + &mPciExpressPlatformPolicy + ); + } else if (mPciExOverrideProtocol) { + Status = mPciExOverrideProtocol->GetPolicy ( + mPciExOverrideProtocol, + sizeof (EFI_PCI_EXPRESS_PLATFORM_POLICY), + &mPciExpressPlatformPolicy + ); + } else { + // + // no protocol found, platform does not require the PCI Express initialization + // + return EFI_UNSUPPORTED; + } + return Status; +} + + +/** + Notifies the platform about the current PCI Express state of the device. + + @param PciDevice A pointer to PCI_IO_DEVICE + @param PciExDeviceConfiguration Pointer to EFI_PCI_EXPRESS_DEVICE_CONFIGURATION. + Used to pass the current state of device to + platform. + + @retval EFI_STATUS The direct status from the PCI Express Platform Protocol + @retval EFI_UNSUPPORTED returns when the PCI Express Platform Protocol or its + alias PCI Express OVerride Protocol is not present. +**/ +EFI_STATUS +PciExpressPlatformNotifyDeviceState ( + IN PCI_IO_DEVICE *PciDevice + ) +{ + EFI_PCI_EXPRESS_DEVICE_CONFIGURATION PciExDeviceConfiguration; + + + if (mPciExPlatformProtocol != NULL) { + return mPciExPlatformProtocol->NotifyDeviceState ( + mPciExPlatformProtocol, + PciDevice->Handle, + sizeof (EFI_PCI_EXPRESS_DEVICE_CONFIGURATION), + &PciExDeviceConfiguration + ); + } else if (mPciExOverrideProtocol != NULL) { + return mPciExOverrideProtocol->NotifyDeviceState ( + mPciExOverrideProtocol, + PciDevice->Handle, + sizeof (EFI_PCI_EXPRESS_DEVICE_CONFIGURATION), + &PciExDeviceConfiguration + ); + } else { + // + // unexpected error + // + return EFI_UNSUPPORTED; + } +} + diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h new file mode 100644 index 0000000..4283b81 --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h @@ -0,0 +1,87 @@ +/** @file + This file encapsulate the usage of PCI Platform Protocol + + This file define the necessary hooks used to obtain the platform + level data and policies which could be used in the PCI Enumeration phases + +Copyright (c) 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _EFI_PCI_PLATFORM_SUPPORT_H_ +#define _EFI_PCI_PLATFORM_SUPPORT_H_ + + +/** + This function retrieves the PCI Express Platform Protocols published by platform + @retval EFI_STATUS direct return status from the LocateProtocol () + boot service for the PCI Express Override Protocol + EFI_SUCCESS The PCI Express Platform Protocol is found +**/ +EFI_STATUS +GetPciExpressProtocol ( + ); + +/** + This function indicates that the platform has published the PCI Express Platform + Protocol (or PCI Express Override Protocol) to indicate that this driver can + initialize the PCI Express features. + @retval TRUE or FALSE +**/ +BOOLEAN +IsPciExpressProtocolPresent ( + ); + +/** + This function gets the platform requirement to initialize the list of PCI Express + features from the protocol definition supported. + This function should be called after the LocatePciPlatformProtocol. + @retval EFI_SUCCESS return by platform to acknowledge the list of + PCI Express feature to be configured + (in mPciExpressPlatformPolicy) + EFI_INVALID_PARAMETER platform does not support the protocol arguements + passed + EFI_UNSUPPORTED platform did not published the protocol +**/ +EFI_STATUS +PciExpressPlatformGetPolicy ( + ); + +/** + Gets the PCI device-specific platform policy from the PCI Platform Protocol. + If no PCI Platform protocol is published than setup the PCI feature to predetermined + defaults, in order to align all the PCI devices in the PCI hierarchy, as applicable. + + @param PciDevice A pointer to PCI_IO_DEVICE + + @retval EFI_STATUS The direct status from the PCI Platform Protocol + @retval EFI_SUCCESS On return of predetermined PCI features defaults, for + the case when protocol returns as EFI_UNSUPPORTED to + indicate PCI device exist and it has no platform policy + defined. Also, on returns when no PCI Platform Protocol + exist. +**/ +EFI_STATUS +PciExpressPlatformGetDevicePolicy ( + IN PCI_IO_DEVICE *PciDevice + ); + +/** + Notifies the platform about the current PCI Express state of the device. + + @param PciDevice A pointer to PCI_IO_DEVICE + @param PciExDeviceConfiguration Pointer to EFI_PCI_EXPRESS_DEVICE_CONFIGURATION. + Used to pass the current state of device to + platform. + + @retval EFI_STATUS The direct status from the PCI Express Platform Protocol + @retval EFI_UNSUPPORTED returns when the PCI Express Platform Protocol or its + alias PCI Express OVerride Protocol is not present. +**/ +EFI_STATUS +PciExpressPlatformNotifyDeviceState ( + IN PCI_IO_DEVICE *PciDevice + ); +#endif -- 2.21.0.windows.1