From nobody Sun Apr 28 14:31:57 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+47851+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+47851+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1569248500; cv=none; d=zoho.com; s=zohoarc; b=X1UyfVhYtTRyiS+PvCO6+TvbIjKUw1PsKZKrKnwYwkBQFSqQrT2fLIGpe2OFoTEIw4zRw9qG6PnByZf2z99D+u09hKZaFq7Tg4zBjvByjGZlqQ5c2AiACcaPFkZxO7wVE318BZvGmCaN6fNn4sOwIuHoZemhBba2kfcFu5ak6sA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1569248500; h=Content-Transfer-Encoding:Cc:Date:From:List-Id:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Sender:Subject:To:ARC-Authentication-Results; bh=GY6rqpjRgj5kZKCNqteVRHTdIL1dkVTjx/nqhCvltes=; b=Harkyje2l2anyheevS/NAstSyYyVZnqwnclAZmslEhZix17l5ZRow5Wgg1MOTbMZ2QBGQcDe+IzIchf8O52jyU4WrbofW6yLg9yJOSbQg+ZEnWnfZtppozecVlmNX/aiLxPdKBviF7mlexwlE+b+g3jQYv+sY1UNnjdlAyqCh8E= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+47851+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1569248500734817.7420392897942; Mon, 23 Sep 2019 07:21:40 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id aaaaYY1788612xaaaaaaaaaa; Mon, 23 Sep 2019 07:21:40 -0700 X-Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by groups.io with SMTP; Mon, 23 Sep 2019 07:21:39 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 23 Sep 2019 07:21:39 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,540,1559545200"; d="scan'208";a="213343654" X-Received: from pidsbabios005.gar.corp.intel.com ([10.66.128.253]) by fmsmga004.fm.intel.com with ESMTP; 23 Sep 2019 07:21:34 -0700 From: "Javeed, Ashraf" To: devel@edk2.groups.io Cc: Jian J Wang , Hao A Wu , Ray Ni Subject: [edk2-devel] [edk2-staging/UEFI_PCI_ENHANCE-2 PATCH] PciBusDxe: New PCI features Max_Payload_Size, Max_Read_Req_Size Date: Mon, 23 Sep 2019 19:50:51 +0530 Message-Id: <20190923142051.10832-1-ashraf.javeed@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,ashraf.javeed@intel.com X-Gm-Message-State: aaaaaaaaaaaaaaaaaaaaaaaax1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1569248500; bh=Z2xZs2t2eARVPyBtTden0TqVGjVFcstzITR+7UhVE7Y=; h=Cc:Date:From:Reply-To:Subject:To; b=aQ9P0HPxIoDuPKkOna0RhEnCKUMjbqWHTYPvoI5/5co5SZaxdxC4DIOWvpnnVvrISKb LtchPyU1dnzxwDALpTjOFBywG3ep6sX0g+RAZgJ5zA6eFlWbk8JFyc07WsD444Ut+fyIk XeY6akchlPPLF5ZODOqH37I4MIfm6bqVRzc= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D2194 The EDK2 Kernel PciBusDxe driver is enhanced to enable the configuration of PCI features like Max_Payload_Size and Max_Read_Req_Size. Max_Payload_Size:- The PCI Device Control register provides this feature register field which controls the maximum data packet (TLP) size that a PCI device should maintain as a requester. The PCI Bus driver is required to maintain a highest common value supported by all the PCI devices in a PCIe hierarchy, especially in case of isochronous applications. Max_Read_Req_Size:- The PCI Device Control register provides this feature register field which controls the maximum memory read request size that a PCI device should maintain as a requester. The PCI Bus driver is required to maintain a common value, same as Max_Payload_Size, in case of isochronous applications only; or else, it should maintain the user requested value uniformly in a PCIe hierarchy (PCI root port and its downstream devices). The PCI Base Specification 4 Revision 1 contains detailed information about these features. The EDK2 PCI Bus driver needs to enable the configuration of these features as per the PCI Base specification. The EDK2 PCI Bus driver also needs to take the PCI device-specific platform policy into the consideration while programming these features; thus the code changes to support these, is explicitly dependent on the new PCI Platform Protocol interface definition defined in the below record:- https://bugzilla.tianocore.org/show_bug.cgi?id=3D1954 Signed-off-by: Ashraf Javeed Cc: Jian J Wang Cc: Hao A Wu Cc: Ray Ni --- MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c | 23 ++------------ MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h | 14 ++++++++- MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf | 9 +++++- MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c | 229 +++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--= ---------------------------------------------- MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c | 139 +++++++++++++= +++++++-------------------------------------------------------------- MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c | 34 ++++++++++++-= ------- MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c | 1601 +++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h | 201 +++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c | 565 +++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h | 193 +++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c | 15 +-------- MdeModulePkg/MdeModulePkg.dec | 10 ++++++ 12 files changed, 2797 insertions(+), 236 deletions(-) diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c b/MdeModulePkg/Bus/Pci= /PciBusDxe/PciBus.c index b020ce50ce..2503b298f4 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. =20 -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent =20 **/ @@ -34,8 +34,6 @@ BOOLEAN gFullEnumer= ation =3D TRUE; UINT64 gAllOne =3D 0xF= FFFFFFFFFFFFFFFULL; UINT64 gAllZero =3D 0; =20 -EFI_PCI_PLATFORM_PROTOCOL *gPciPlatformProtocol; -EFI_PCI_OVERRIDE_PROTOCOL *gPciOverrideProtocol; EDKII_IOMMU_PROTOCOL *mIoMmuProtocol; =20 =20 @@ -266,24 +264,7 @@ PciBusDriverBindingStart ( // If PCI Platform protocol is available, get it now. // If the platform implements this, it must be installed before BDS phase // - gPciPlatformProtocol =3D NULL; - gBS->LocateProtocol ( - &gEfiPciPlatformProtocolGuid, - NULL, - (VOID **) &gPciPlatformProtocol - ); - - // - // If PCI Platform protocol doesn't exist, try to Pci Override Protocol. - // - if (gPciPlatformProtocol =3D=3D NULL) { - gPciOverrideProtocol =3D NULL; - gBS->LocateProtocol ( - &gEfiPciOverrideProtocolGuid, - NULL, - (VOID **) &gPciOverrideProtocol - ); - } + GetPciPlatformProtocol (); =20 if (mIoMmuProtocol =3D=3D NULL) { gBS->LocateProtocol ( diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h b/MdeModulePkg/Bus/Pci= /PciBusDxe/PciBus.h index 504a1b1c12..7955bf8a26 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h @@ -27,6 +27,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include +#include =20 #include #include @@ -79,6 +81,7 @@ typedef enum { #include "PciPowerManagement.h" #include "PciHotPlugSupport.h" #include "PciLib.h" +#include "PciFeatureSupport.h" =20 #define VGABASE1 0x3B0 #define VGALIMIT1 0x3BB @@ -263,9 +266,13 @@ struct _PCI_IO_DEVICE { =20 BOOLEAN IsPciExp; // - // For SR-IOV + // For PCI Express Capability List Structure // UINT8 PciExpressCapabilityOffset; + PCI_CAPABILITY_PCIEXP PciExpStruct; + // + // For SR-IOV + // UINT32 AriCapabilityOffset; UINT32 SrIovCapabilityOffset; UINT32 MrIovCapabilityOffset; @@ -279,6 +286,11 @@ struct _PCI_IO_DEVICE { // This field is used to support this case. // UINT16 BridgeIoAlignment; + // + // Other PCI features setup flags + // + UINT8 SetupMPS; + UINT8 SetupMRRS; }; =20 #define PCI_IO_DEVICE_FROM_PCI_IO_THIS(a) \ diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf b/MdeModulePkg/Bu= s/Pci/PciBusDxe/PciBusDxe.inf index 05c22025b8..13768d7ded 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 - 2019, 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 =20 [Packages] MdePkg/MdePkg.dec @@ -91,6 +95,8 @@ gEfiLoadFile2ProtocolGuid ## SOMETIMES_PRODUCES gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES gEfiLoadedImageDevicePathProtocolGuid ## CONSUMES + gEfiPciPlatformProtocol2Guid ## SOMETIMES_CONSUMES + gEfiPciOverrideProtocol2Guid ## SOMETIMES_CONSUMES =20 [FeaturePcd] gEfiMdeModulePkgTokenSpaceGuid.PcdPciBusHotplugDeviceSupport ## CON= SUMES @@ -104,6 +110,7 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdAriSupport ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdMrIovSupport ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration ## SOMETIM= ES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdOtherPciFeatures ##= CONSUMES =20 [UserExtensions.TianoCore."ExtraFiles"] PciBusDxeExtra.uni diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c b/MdeModuleP= kg/Bus/Pci/PciBusDxe/PciDeviceSupport.c index b7832c6970..0f76ab1cd5 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c @@ -170,6 +170,8 @@ DestroyRootBridgeByHandle ( =20 if (Temp->Handle =3D=3D Controller) { =20 + DestroyRootBridgePciFeaturesConfigCompletionList ( Temp); + RemoveEntryList (CurrentLink); =20 DestroyPciDeviceTree (Temp); @@ -208,8 +210,6 @@ RegisterPciDevice ( ) { EFI_STATUS Status; - VOID *PlatformOpRomBuffer; - UINTN PlatformOpRomSize; EFI_PCI_IO_PROTOCOL *PciIo; UINT8 Data8; BOOLEAN HasEfiImage; @@ -244,49 +244,13 @@ RegisterPciDevice ( // // Get the OpRom provided by platform // - if (gPciPlatformProtocol !=3D NULL) { - Status =3D gPciPlatformProtocol->GetPciRom ( - gPciPlatformProtocol, - PciIoDevice->Handle, - &PlatformOpRomBuffer, - &PlatformOpRomSize - ); - if (!EFI_ERROR (Status)) { - PciIoDevice->EmbeddedRom =3D FALSE; - PciIoDevice->RomSize =3D (UINT32) PlatformOpRomSize; - PciIoDevice->PciIo.RomSize =3D PlatformOpRomSize; - PciIoDevice->PciIo.RomImage =3D PlatformOpRomBuffer; - // - // For OpROM read from gPciPlatformProtocol: - // Add the Rom Image to internal database for later PCI light enum= eration - // - PciRomAddImageMapping ( - NULL, - PciIoDevice->PciRootBridgeIo->SegmentNumber, - PciIoDevice->BusNumber, - PciIoDevice->DeviceNumber, - PciIoDevice->FunctionNumber, - PciIoDevice->PciIo.RomImage, - PciIoDevice->PciIo.RomSize - ); - } - } else if (gPciOverrideProtocol !=3D NULL) { - Status =3D gPciOverrideProtocol->GetPciRom ( - gPciOverrideProtocol, - PciIoDevice->Handle, - &PlatformOpRomBuffer, - &PlatformOpRomSize - ); - if (!EFI_ERROR (Status)) { - PciIoDevice->EmbeddedRom =3D FALSE; - PciIoDevice->RomSize =3D (UINT32) PlatformOpRomSize; - PciIoDevice->PciIo.RomSize =3D PlatformOpRomSize; - PciIoDevice->PciIo.RomImage =3D PlatformOpRomBuffer; - // - // For OpROM read from gPciOverrideProtocol: - // Add the Rom Image to internal database for later PCI light enum= eration - // - PciRomAddImageMapping ( + Status =3D GetPlatformPciOptionRom ( Controller, PciIoDevice); + if (!EFI_ERROR (Status)) { + // + // For OpROM read from the PCI Platform Protocol: + // Add the Rom Image to internal database for later PCI light enumer= ation + // + PciRomAddImageMapping ( NULL, PciIoDevice->PciRootBridgeIo->SegmentNumber, PciIoDevice->BusNumber, @@ -294,8 +258,7 @@ RegisterPciDevice ( PciIoDevice->FunctionNumber, PciIoDevice->PciIo.RomImage, PciIoDevice->PciIo.RomSize - ); - } + ); } } =20 @@ -597,7 +560,7 @@ DeRegisterPciDevice ( } =20 /** - Start to manage the PCI device on the specified root bridge or PCI-PCI B= ridge. + Start the PCI root Ports or PCI-PCI Bridge only. =20 @param Controller The root bridge handle. @param RootBridge A pointer to the PCI_IO_DEVICE. @@ -612,7 +575,82 @@ DeRegisterPciDevice ( =20 **/ EFI_STATUS -StartPciDevicesOnBridge ( +StartPciRootPortsOnBridge ( + IN EFI_HANDLE Controller, + IN PCI_IO_DEVICE *RootBridge + ) + +{ + PCI_IO_DEVICE *PciIoDevice; + EFI_STATUS Status; + LIST_ENTRY *CurrentLink; + UINT64 Supports; + + PciIoDevice =3D NULL; + CurrentLink =3D RootBridge->ChildList.ForwardLink; + + while (CurrentLink !=3D NULL && CurrentLink !=3D &RootBridge->ChildList)= { + + PciIoDevice =3D PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + // + // check if the device has been assigned with required resource + // and registered + // + if (!PciIoDevice->Registered && !PciIoDevice->Allocated) { + return EFI_NOT_READY; + } + + if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { + Status =3D StartPciRootPortsOnBridge ( + Controller, + PciIoDevice + ); + + PciIoDevice->PciIo.Attributes ( + &(PciIoDevice->PciIo), + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + Supports &=3D (UINT64)EFI_PCI_DEVICE_ENABLE; + PciIoDevice->PciIo.Attributes ( + &(PciIoDevice->PciIo), + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); + + } + + CurrentLink =3D CurrentLink->ForwardLink; + } + + if (PciIoDevice =3D=3D NULL) { + return EFI_NOT_FOUND; + } else { + return EFI_SUCCESS; + } +} + + +/** + Register to manage the PCI device on the specified root bridge or PCI-PC= I Bridge. + + @param Controller The root bridge handle. + @param RootBridge A pointer to the PCI_IO_DEVICE. + @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL. + @param NumberOfChildren Children number. + @param ChildHandleBuffer A pointer to the child handle buffer. + + @retval EFI_NOT_READY Device is not allocated. + @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge. + @retval EFI_NOT_FOUND Can not find the specific device. + @retval EFI_SUCCESS Success to start Pci devices on bridge. + +**/ +EFI_STATUS +RegisterPciDevicesOnBridge ( IN EFI_HANDLE Controller, IN PCI_IO_DEVICE *RootBridge, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, @@ -626,7 +664,6 @@ StartPciDevicesOnBridge ( EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath; EFI_STATUS Status; LIST_ENTRY *CurrentLink; - UINT64 Supports; =20 PciIoDevice =3D NULL; CurrentLink =3D RootBridge->ChildList.ForwardLink; @@ -681,7 +718,7 @@ StartPciDevicesOnBridge ( // If it is a PPB // if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { - Status =3D StartPciDevicesOnBridge ( + Status =3D RegisterPciDevicesOnBridge ( Controller, PciIoDevice, CurrentDevicePath, @@ -689,20 +726,6 @@ StartPciDevicesOnBridge ( ChildHandleBuffer ); =20 - PciIoDevice->PciIo.Attributes ( - &(PciIoDevice->PciIo), - EfiPciIoAttributeOperationSupported, - 0, - &Supports - ); - Supports &=3D (UINT64)EFI_PCI_DEVICE_ENABLE; - PciIoDevice->PciIo.Attributes ( - &(PciIoDevice->PciIo), - EfiPciIoAttributeOperationEnable, - Supports, - NULL - ); - return Status; } else { =20 @@ -733,28 +756,13 @@ StartPciDevicesOnBridge ( } =20 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { - Status =3D StartPciDevicesOnBridge ( + Status =3D RegisterPciDevicesOnBridge ( Controller, PciIoDevice, RemainingDevicePath, NumberOfChildren, ChildHandleBuffer ); - - PciIoDevice->PciIo.Attributes ( - &(PciIoDevice->PciIo), - EfiPciIoAttributeOperationSupported, - 0, - &Supports - ); - Supports &=3D (UINT64)EFI_PCI_DEVICE_ENABLE; - PciIoDevice->PciIo.Attributes ( - &(PciIoDevice->PciIo), - EfiPciIoAttributeOperationEnable, - Supports, - NULL - ); - } =20 CurrentLink =3D CurrentLink->ForwardLink; @@ -768,6 +776,65 @@ StartPciDevicesOnBridge ( } } =20 +/** + Start to manage the PCI device on the specified root bridge or PCI-PCI B= ridge. + + @param Controller The root bridge handle. + @param RootBridge A pointer to the PCI_IO_DEVICE. + @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL. + @param NumberOfChildren Children number. + @param ChildHandleBuffer A pointer to the child handle buffer. + + @retval EFI_NOT_READY Device is not allocated. + @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge. + @retval EFI_NOT_FOUND Can not find the specific device. + @retval EFI_SUCCESS Success to start Pci devices on bridge. + +**/ +EFI_STATUS +StartPciDevicesOnBridge ( + IN EFI_HANDLE Controller, + IN PCI_IO_DEVICE *RootBridge, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, + IN OUT UINT8 *NumberOfChildren, + IN OUT EFI_HANDLE *ChildHandleBuffer + ) + +{ + EFI_STATUS Status; + + // + // first register all the PCI devices + // + Status =3D RegisterPciDevicesOnBridge ( + Controller, + RootBridge, + RemainingDevicePath, + NumberOfChildren, + ChildHandleBuffer + ); + + if (EFI_ERROR (Status) =3D=3D EFI_NOT_FOUND) { + return Status; + } else { + if ( CheckOtherPciFeaturesPcd ()) { + // + // the late configuration of PCI features + // + Status =3D EnumerateOtherPciFeatures ( + RootBridge + ); + } + // + // finally start those PCI bridge port devices only + // + return StartPciRootPortsOnBridge ( + Controller, + RootBridge + ); + } +} + /** Start to manage all the PCI devices it found previously under the entire host bridge. diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c b/MdeModulePkg/= Bus/Pci/PciBusDxe/PciEnumerator.c index 8db1ebf8ec..0a56668380 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c @@ -1003,7 +1003,7 @@ PciHostBridgeAdjustAllocation ( Status =3D RejectPciDevice (PciResNode->PciDev); if (Status =3D=3D EFI_SUCCESS) { DEBUG (( - EFI_D_ERROR, + DEBUG_ERROR, "PciBus: [%02x|%02x|%02x] was rejected due to resource confliction= .\n", PciResNode->PciDev->BusNumber, PciResNode->PciDev->DeviceNumber, P= ciResNode->PciDev->FunctionNumber )); @@ -1746,7 +1746,7 @@ NotifyPhase ( =20 HostBridgeHandle =3D NULL; RootBridgeHandle =3D NULL; - if (gPciPlatformProtocol !=3D NULL) { + if ( CheckPciPlatformProtocolInstall()) { // // Get Host Bridge Handle. // @@ -1770,42 +1770,11 @@ NotifyPhase ( // // Call PlatformPci::PlatformNotify() if the protocol is present. // - gPciPlatformProtocol->PlatformNotify ( - gPciPlatformProtocol, - HostBridgeHandle, - Phase, - ChipsetEntry - ); - } else if (gPciOverrideProtocol !=3D NULL){ - // - // Get Host Bridge Handle. - // - PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle); - - // - // Get the rootbridge Io protocol to find the host bridge handle - // - Status =3D gBS->HandleProtocol ( - RootBridgeHandle, - &gEfiPciRootBridgeIoProtocolGuid, - (VOID **) &PciRootBridgeIo - ); - - if (EFI_ERROR (Status)) { - return EFI_NOT_FOUND; - } - - HostBridgeHandle =3D PciRootBridgeIo->ParentHandle; - - // - // Call PlatformPci::PhaseNotify() if the protocol is present. - // - gPciOverrideProtocol->PlatformNotify ( - gPciOverrideProtocol, - HostBridgeHandle, - Phase, - ChipsetEntry - ); + PciPlatformNotifyPhase ( + HostBridgeHandle, + Phase, + ChipsetEntry + ); } =20 Status =3D PciResAlloc->NotifyPhase ( @@ -1813,27 +1782,15 @@ NotifyPhase ( Phase ); =20 - if (gPciPlatformProtocol !=3D NULL) { + if ( CheckPciPlatformProtocolInstall()) { // // Call PlatformPci::PlatformNotify() if the protocol is present. // - gPciPlatformProtocol->PlatformNotify ( - gPciPlatformProtocol, - HostBridgeHandle, - Phase, - ChipsetExit - ); - - } else if (gPciOverrideProtocol !=3D NULL) { - // - // Call PlatformPci::PhaseNotify() if the protocol is present. - // - gPciOverrideProtocol->PlatformNotify ( - gPciOverrideProtocol, - HostBridgeHandle, - Phase, - ChipsetExit - ); + PciPlatformNotifyPhase ( + HostBridgeHandle, + Phase, + ChipsetExit + ); } =20 return Status; @@ -1914,31 +1871,16 @@ PreprocessController ( RootBridgePciAddress.Bus =3D Bus; RootBridgePciAddress.ExtendedRegister =3D 0; =20 - if (gPciPlatformProtocol !=3D NULL) { - // - // Call PlatformPci::PrepController() if the protocol is present. - // - gPciPlatformProtocol->PlatformPrepController ( - gPciPlatformProtocol, - HostBridgeHandle, - RootBridgeHandle, - RootBridgePciAddress, - Phase, - ChipsetEntry - ); - } else if (gPciOverrideProtocol !=3D NULL) { - // - // Call PlatformPci::PrepController() if the protocol is present. - // - gPciOverrideProtocol->PlatformPrepController ( - gPciOverrideProtocol, - HostBridgeHandle, - RootBridgeHandle, - RootBridgePciAddress, - Phase, - ChipsetEntry - ); - } + // + // Call PlatformPci::PrepController() if the protocol is present. + // + PciPlatformPreprocessController ( + HostBridgeHandle, + RootBridgeHandle, + RootBridgePciAddress, + Phase, + ChipsetEntry + ); =20 Status =3D PciResAlloc->PreprocessController ( PciResAlloc, @@ -1947,31 +1889,16 @@ PreprocessController ( Phase ); =20 - if (gPciPlatformProtocol !=3D NULL) { - // - // Call PlatformPci::PrepController() if the protocol is present. - // - gPciPlatformProtocol->PlatformPrepController ( - gPciPlatformProtocol, - HostBridgeHandle, - RootBridgeHandle, - RootBridgePciAddress, - Phase, - ChipsetExit - ); - } else if (gPciOverrideProtocol !=3D NULL) { - // - // Call PlatformPci::PrepController() if the protocol is present. - // - gPciOverrideProtocol->PlatformPrepController ( - gPciOverrideProtocol, - HostBridgeHandle, - RootBridgeHandle, - RootBridgePciAddress, - Phase, - ChipsetExit - ); - } + // + // Call PlatformPci::PrepController() if the protocol is present. + // + PciPlatformPreprocessController ( + HostBridgeHandle, + RootBridgeHandle, + RootBridgePciAddress, + Phase, + ChipsetExit + ); =20 return EFI_SUCCESS; } diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c b/MdeMod= ulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c index c7eafff593..2343702154 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c @@ -230,7 +230,7 @@ PciSearchDevice ( PciIoDevice =3D NULL; =20 DEBUG (( - EFI_D_INFO, + DEBUG_INFO, "PciBus: Discovered %s @ [%02x|%02x|%02x]\n", IS_PCI_BRIDGE (Pci) ? L"PPB" : IS_CARDBUS_BRIDGE (Pci) ? L"P2C" : @@ -397,7 +397,7 @@ DumpPpbPaddingResource ( =20 if ((Type !=3D PciBarTypeUnknown) && ((ResourceType =3D=3D PciBarTypeU= nknown) || (ResourceType =3D=3D Type))) { DEBUG (( - EFI_D_INFO, + DEBUG_INFO, " Padding: Type =3D %s; Alignment =3D 0x%lx;\tLength =3D 0x%lx\n= ", mBarTypeStr[Type], Descriptor->AddrRangeMax, Descriptor->AddrLen )); @@ -424,7 +424,7 @@ DumpPciBars ( } =20 DEBUG (( - EFI_D_INFO, + DEBUG_INFO, " BAR[%d]: Type =3D %s; Alignment =3D 0x%lx;\tLength =3D 0x%lx;\tO= ffset =3D 0x%02x\n", Index, mBarTypeStr[MIN (PciIoDevice->PciBar[Index].BarType, PciBarTy= peMaxType)], PciIoDevice->PciBar[Index].Alignment, PciIoDevice->PciBar[Index].Len= gth, PciIoDevice->PciBar[Index].Offset @@ -437,13 +437,13 @@ DumpPciBars ( } =20 DEBUG (( - EFI_D_INFO, + DEBUG_INFO, " VFBAR[%d]: Type =3D %s; Alignment =3D 0x%lx;\tLength =3D 0x%lx;\tO= ffset =3D 0x%02x\n", Index, mBarTypeStr[MIN (PciIoDevice->VfPciBar[Index].BarType, PciBar= TypeMaxType)], PciIoDevice->VfPciBar[Index].Alignment, PciIoDevice->VfPciBar[Index]= .Length, PciIoDevice->VfPciBar[Index].Offset )); } - DEBUG ((EFI_D_INFO, "\n")); + DEBUG ((DEBUG_INFO, "\n")); } =20 /** @@ -1903,7 +1903,7 @@ PciParseBar ( // Fix the length to support some special 64 bit BAR // if (Value =3D=3D 0) { - DEBUG ((EFI_D_INFO, "[PciBus]BAR probing for upper 32bit of MEM64 = BAR returns 0, change to 0xFFFFFFFF.\n")); + DEBUG ((DEBUG_INFO, "[PciBus]BAR probing for upper 32bit of MEM64 = BAR returns 0, change to 0xFFFFFFFF.\n")); Value =3D (UINT32) -1; } else { Value |=3D ((UINT32)(-1) << HighBitSet32 (Value)); @@ -2153,7 +2153,17 @@ CreatePciIoDevice ( NULL ); if (!EFI_ERROR (Status)) { - PciIoDevice->IsPciExp =3D TRUE; + PciIoDevice->IsPciExp =3D 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->PciExpStruct + ); } =20 if (PcdGetBool (PcdAriSupport)) { @@ -2206,7 +2216,7 @@ CreatePciIoDevice ( &Data32 ); DEBUG (( - EFI_D_INFO, + DEBUG_INFO, " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n", Bridge->BusNumber, Bridge->DeviceNumber, @@ -2215,7 +2225,7 @@ CreatePciIoDevice ( } } =20 - DEBUG ((EFI_D_INFO, " ARI: CapOffset =3D 0x%x\n", PciIoDevice->AriCa= pabilityOffset)); + DEBUG ((DEBUG_INFO, " ARI: CapOffset =3D 0x%x\n", PciIoDevice->AriCa= pabilityOffset)); } } =20 @@ -2325,12 +2335,12 @@ CreatePciIoDevice ( PciIoDevice->ReservedBusNum =3D (UINT16)(EFI_PCI_BUS_OF_RID (LastVF)= - Bus + 1); =20 DEBUG (( - EFI_D_INFO, + DEBUG_INFO, " SR-IOV: SupportedPageSize =3D 0x%x; SystemPageSize =3D 0x%x; Fir= stVFOffset =3D 0x%x;\n", SupportedPageSize, PciIoDevice->SystemPageSize >> 12, FirstVFOffset )); DEBUG (( - EFI_D_INFO, + DEBUG_INFO, " InitialVFs =3D 0x%x; ReservedBusNum =3D 0x%x; CapOffset = =3D 0x%x\n", PciIoDevice->InitialVFs, PciIoDevice->ReservedBusNum, PciIoDevice-= >SrIovCapabilityOffset )); @@ -2345,7 +2355,7 @@ CreatePciIoDevice ( NULL ); if (!EFI_ERROR (Status)) { - DEBUG ((EFI_D_INFO, " MR-IOV: CapOffset =3D 0x%x\n", PciIoDevice->Mr= IovCapabilityOffset)); + DEBUG ((DEBUG_INFO, " MR-IOV: CapOffset =3D 0x%x\n", PciIoDevice->Mr= IovCapabilityOffset)); } } =20 diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c b/MdeModule= Pkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c new file mode 100644 index 0000000000..0819da6536 --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c @@ -0,0 +1,1601 @@ +/** @file + PCI standard feature support functions implementation for PCI Bus module= .. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PciFeatureSupport.h" + +/** + A gobal pointer to PRIMARY_ROOT_PORT_NODE buffer to track all the primar= y physical + PCI Root Ports (PCI Controllers) for a given PCI Root Bridge instance wh= ile + enumerating to configure the PCI features +**/ +PRIMARY_ROOT_PORT_NODE *mPrimaryRootPortList; + +/** + A gobal pointer to OTHER_PCI_FEATURES_CONFIGURATION_TABLE buffer all the= PCI + Feature configuration Table nodes to pair against each of the PRIMARY_RO= OT_PORT_NODE + buffer nodes. Each node of these is used to align all the PCI devices or= iginating + from the PCI Root Port devices of a PCI Root Bridge instance +**/ +OTHER_PCI_FEATURES_CONFIGURATION_TABLE *mPciFeaturesConfigurationTabl= eInstances; + +/** + A global pointer to PCI_FEATURE_CONFIGURATION_COMPLETION_LIST, which sto= res all + the PCI Root Bridge instances that are enumerated for the other PCI feat= ures, + like MaxPayloadSize & MaxReadReqSize; during the the Start() interface o= f the + driver binding protocol. The records pointed by this pointer would be de= stroyed + when the DXE core invokes the Stop() interface. +**/ +PCI_FEATURE_CONFIGURATION_COMPLETION_LIST *mPciFeaturesConfigurationComp= letionList =3D NULL; + +/** + Main routine to indicate platform selection of any of the other PCI feat= ures + to be configured by this driver + + @retval TRUE platform has selected the other PCI features to be confi= gured + FALSE platform has not selected any of the other PCI features +**/ +BOOLEAN +CheckOtherPciFeaturesPcd ( + ) +{ + return PcdGet32 ( PcdOtherPciFeatures) ? TRUE : FALSE; +} + +/** + Main routine to indicate whether the platform has selected the Max_Paylo= ad_Size + PCI feature to be configured by this driver + + @retval TRUE platform has selected the Max_Payload_Size to be configu= red + FALSE platform has not selected this feature +**/ +BOOLEAN +SetupMaxPayloadSize ( + ) +{ + return (PcdGet32 ( PcdOtherPciFeatures) & PCI_FEATURE_SUPPORT_FLAG_MPS) = ? TRUE : FALSE; +} + +/** + Main routine to indicate whether the platform has selected the Max_Read_= Req_Size + PCI feature to be configured by this driver + + @retval TRUE platform has selected the Max_Read_Req_Size to be config= ured + FALSE platform has not selected this feature +**/ +BOOLEAN +SetupMaxReadReqSize ( + ) +{ + return (PcdGet32 ( PcdOtherPciFeatures) & PCI_FEATURE_SUPPORT_FLAG_MRRS)= ? TRUE : FALSE; +} + +/** + Helper routine which determines whether the given PCI Root Bridge instan= ce + record already exist. This routine shall help avoid duplicate record cre= ation + in case of re-enumeration of PCI configuation features. + + @param RootBridge A pointer to the PCI_IO_DEVICE for the R= oot Bridge + @param PciFeatureConfigRecord A pointer to a pointer for type + PCI_FEATURE_CONFIGURATION_COMPLETION_LIST + record, Use to return the specific recor= d. + + @retval TRUE Record already exist + FALSE Record does not exist for the given PCI = Root Bridge +**/ +BOOLEAN +CheckPciFeatureConfigurationRecordExist ( + IN PCI_IO_DEVICE *RootBridge, + OUT PCI_FEATURE_CONFIGURATION_COMPLETION_LIST **PciFeatureConfigRecord + ) +{ + LIST_ENTRY *Link; + PCI_FEATURE_CONFIGURATION_COMPLETION_LIST *Temp; + + if ( mPciFeaturesConfigurationCompletionList) { + Link =3D &mPciFeaturesConfigurationCompletionList->RootBridgeLink; + + do { + Temp =3D PCI_FEATURE_CONFIGURATION_COMPLETION_LIST_FROM_LINK (Link); + if ( Temp->RootBridgeHandle =3D=3D RootBridge->Handle) { + *PciFeatureConfigRecord =3D Temp; + return TRUE; + } + Link =3D Link->ForwardLink; + } while (Link !=3D &mPciFeaturesConfigurationCompletionList->RootBridg= eLink); + } + // + // not found on the PCI feature configuration completion list + // + *PciFeatureConfigRecord =3D NULL; + return FALSE; +} + +/** + This routine is primarily to avoid multiple configuration of PCI features + to the same PCI Root Bridge due to EDK2 core's ConnectController calls on + all the EFI handles. This routine also provide re-enumeration of the PCI + features on the same PCI Root Bridge based on the policy of ReEnumerateP= ciFeatureConfiguration + of the PCI_FEATURE_CONFIGURATION_COMPLETION_LIST. + + @param RootBridge A pointer to the PCI_IO_DEVICE for the R= oot Bridge + + @retval TRUE PCI Feature configuration required for t= he PCI + Root Bridge + FALSE PCI Feature configuration is not require= d to be + re-enumerated for the PCI Root Bridge +**/ +BOOLEAN +CheckPciFeaturesConfigurationRequired ( + IN PCI_IO_DEVICE *RootBridge + ) +{ + LIST_ENTRY *Link; + PCI_FEATURE_CONFIGURATION_COMPLETION_LIST *Temp; + + if ( mPciFeaturesConfigurationCompletionList) { + Link =3D &mPciFeaturesConfigurationCompletionList->RootBridgeLink; + + do { + Temp =3D PCI_FEATURE_CONFIGURATION_COMPLETION_LIST_FROM_LINK (Link); + if ( Temp->RootBridgeHandle =3D=3D RootBridge->Handle) { + return Temp->ReEnumeratePciFeatureConfiguration; + } + Link =3D Link->ForwardLink; + } while (Link !=3D &mPciFeaturesConfigurationCompletionList->RootBridg= eLink); + } + // + // not found on the PCI feature configuration completion list, return as= required + // + return TRUE; +} + +/** + This routine finds the duplicate record if exist and assigns the re-enum= eration + requirement flag, as passed as input. It creates new record for the PCI = Root + Bridge and appends the list after updating its re-enumeration flag. + + @param RootBridge A pointer to PCI_IO_DEVICE of the Root Bri= dge + @param ReEnumerationRequired A BOOLEAN for recording the re-enumeration= requirement + + @retval EFI_SUCCESS new record inserted into the list or updat= ed the + existing record + EFI_INVALID_PARAMETER Unexpected error as CheckPciFeatureConfigu= rationRecordExist + reports as record exist but does not retur= n its pointer + EFI_OUT_OF_RESOURCES Not able to create PCI features configurat= in complete + record for the RootBridge +**/ +EFI_STATUS +AddRootBridgeInPciFeaturesConfigCompletionList ( + IN PCI_IO_DEVICE *RootBridge, + IN BOOLEAN ReEnumerationRequired + ) +{ + PCI_FEATURE_CONFIGURATION_COMPLETION_LIST *Temp; + + if ( CheckPciFeatureConfigurationRecordExist ( RootBridge, &Temp)) { + // + // this PCI Root Bridge record already exist; it may have been re-enum= erated + // hence just update its enumeration required flag again to exit + // + if ( Temp) { + Temp->ReEnumeratePciFeatureConfiguration =3D ReEnumerationRequired; + return EFI_SUCCESS; + } else { + // + // PCI feature configuration complete record reported as exist and no + // record pointer returned + // + return EFI_INVALID_PARAMETER; + } + + } else { + + Temp =3D AllocateZeroPool ( sizeof ( PCI_FEATURE_CONFIGURATION_COMPLET= ION_LIST)); + if ( !Temp) { + return EFI_OUT_OF_RESOURCES; + } + Temp->Signature =3D PCI_FEATURE_CONFIGURATIO= N_SIGNATURE; + Temp->RootBridgeHandle =3D RootBridge->Handle; + Temp->ReEnumeratePciFeatureConfiguration =3D ReEnumerationRequired; + if ( mPciFeaturesConfigurationCompletionList) { + InsertTailList ( &mPciFeaturesConfigurationCompletionList->RootBridg= eLink, + &Temp->RootBridgeLink); + } else { + // + // init the very first node of the Root Bridge + // + mPciFeaturesConfigurationCompletionList =3D Temp; + InitializeListHead ( &mPciFeaturesConfigurationCompletionList->RootB= ridgeLink); + } + } + return EFI_SUCCESS; +} + +/** + Free up memory alloted for the primary physical PCI Root ports of the PC= I Root + Bridge instance. Free up all the nodes of type PRIMARY_ROOT_PORT_NODE. +**/ +VOID +DestroyPrimaryRootPortNodes () +{ + LIST_ENTRY *Link; + PRIMARY_ROOT_PORT_NODE *Temp; + + if ( mPrimaryRootPortList) { + Link =3D &mPrimaryRootPortList->NeighborRootPort; + + if ( IsListEmpty ( Link)) { + FreePool ( mPrimaryRootPortList); + } else { + do { + if ( Link->ForwardLink !=3D &mPrimaryRootPortList->NeighborRootPor= t) { + Link =3D Link->ForwardLink; + } + Temp =3D PRIMARY_ROOT_PORT_NODE_FROM_LINK ( Link); + Link =3D RemoveEntryList ( Link); + FreePool ( Temp); + } while ( !IsListEmpty ( Link)); + FreePool ( mPrimaryRootPortList); + } + mPrimaryRootPortList =3D NULL; + } +} + +/** + Free up the memory allocated for temporarily maintaining the PCI feature + configuration table for all the nodes of the primary PCI Root port. + Free up memory alloted for OTHER_PCI_FEATURES_CONFIGURATION_TABLE. +**/ +VOID +ErasePciFeaturesConfigurationTable ( + ) +{ + if ( mPciFeaturesConfigurationTableInstances) { + FreePool ( mPciFeaturesConfigurationTableInstances); + } + mPciFeaturesConfigurationTableInstances =3D NULL; +} + +/** + Routine meant for initializing any global variables used. It primarily c= leans + up the internal data structure memory allocated for the previous PCI Roo= t Bridge + instance. This should be the first routine to call for any virtual PCI R= oot + Bridge instance. +**/ +VOID +SetupPciFeaturesConfigurationDefaults () +{ + // + // delete the primary root port list + // + if (mPrimaryRootPortList) { + DestroyPrimaryRootPortNodes (); + } + + if ( mPciFeaturesConfigurationTableInstances) { + ErasePciFeaturesConfigurationTable (); + } +} + +/** + Helper routine to determine whether the PCI device is a physical root po= rt + recorded in the list. + + @param PciDevice A pointer to the PCI_IO_DEVICE. + + @retval TRUE The PCI device instance is a pri= mary + primary physical PCI Root Port + FALSE Not a primary physical PCI Root = port +**/ +BOOLEAN +CheckRootBridgePrimaryPort ( + IN PCI_IO_DEVICE *PciDevice + ) +{ + LIST_ENTRY *Link; + PRIMARY_ROOT_PORT_NODE *Temp; + + if ( !mPrimaryRootPortList) { + return FALSE; + } + Link =3D &mPrimaryRootPortList->NeighborRootPort; + do { + Temp =3D PRIMARY_ROOT_PORT_NODE_FROM_LINK ( Link); + if ( Temp->RootBridgeHandle =3D=3D PciDevice->Parent->Handle + && Temp->RootPortHandle =3D=3D PciDevice->Handle) { + // + // the given PCI device is the primary root port of the Root Bridge = controller + // + return TRUE; + } + Link =3D Link->ForwardLink; + } while ( Link !=3D &mPrimaryRootPortList->NeighborRootPort); + // + // the given PCI device is not the primary root port of the Bridge contr= oller + // + return FALSE; +} + +/** + Main routine to determine the child PCI devices of a physical 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 + OTHER_PCI_FEATURES_CONFIGURATION= _TABLE. + Returns NULL in case of RCiEP or= the PCI + device does match with any of th= e physical + Root ports, or it does not belon= g to any + Root port's PCU bus range (not a= child) + + @retval EFI_SUCCESS able to determine the PCI feature + configuration table. For RCiEP s= ince + since it is not prepared. + EFI_NOT_FOUND the PCI feature configuration ta= ble does + not exist as the PCI physical Br= idge device + is not found for this device's p= arent + Root Bridge instance +**/ +EFI_STATUS +GetPciFeaturesConfigurationTable ( + IN PCI_IO_DEVICE *PciDevice, + OUT OTHER_PCI_FEATURES_CONFIGURATION_TABLE **PciFeaturesConfigTable + ) +{ + LIST_ENTRY *Link; + PRIMARY_ROOT_PORT_NODE *Temp; + + if ( !mPrimaryRootPortList) { + *PciFeaturesConfigTable =3D NULL; + return EFI_NOT_FOUND; + } + + // + // The PCI features configuration table is not built for RCiEP, return N= ULL + // + if ( PciDevice->PciExpStruct.Capability.Bits.DevicePortType =3D=3D \ + PCIE_DEVICE_PORT_TYPE_ROOT_COMPLEX_INTEGRATED_ENDPOINT) { + *PciFeaturesConfigTable =3D NULL; + return EFI_SUCCESS; + } + + Link =3D &mPrimaryRootPortList->NeighborRootPort; + do { + Temp =3D PRIMARY_ROOT_PORT_NODE_FROM_LINK ( Link); + if ( Temp->RootBridgeHandle =3D=3D PciDevice->Parent->Handle + && Temp->RootPortHandle =3D=3D PciDevice->Handle) { + // + // the given PCI device is the primary root port of the Root Bridge = controller + // + *PciFeaturesConfigTable =3D Temp->OtherPciFeaturesConfigurationTable; + return EFI_SUCCESS; + } else { + // + // check this PCI device belongs to the primary root port of the roo= t bridge + // + if ( PciDevice->BusNumber >=3D Temp->SecondaryBusStart + && PciDevice->BusNumber <=3D Temp->SecondaryBusEnd) { + *PciFeaturesConfigTable =3D Temp->OtherPciFeaturesConfigurationTab= le; + return EFI_SUCCESS; + } + } + Link =3D Link->ForwardLink; + } while ( Link !=3D &mPrimaryRootPortList->NeighborRootPort); + // + // the PCI device must be RCiEP, does not belong to any primary root port + // + *PciFeaturesConfigTable =3D NULL; + return EFI_SUCCESS; +} + +/** + The helper routine to retrieve the PCI bus numbers from the PCI Bridge o= r Root + port device. Assumes the input PCI device has the PCI Type 1 configurati= on header. + + @param PciDevice A pointer to the PCI_IO_DEVICE. + @param PrimaryBusNumber A pointer to return the PCI Pria= mry + Bus number. + @param SecondaryBusNumber A pointer to return the PCI Seco= ndary + Bus number. + @param SubordinateBusNumber A pointer to return the PCI Subo= rdinate + Bus number. + + @retval EFI_SUCCESS The data was read from the PCI device. + @retval EFI_UNSUPPORTED The address range specified by Offset, Wid= th, and Count is not + valid for the PCI configuration header of = the PCI device. + @retval EFI_INVALID_PARAMETER input parameters provided to the read oper= ation were invalid. +**/ +EFI_STATUS +GetPciRootPortBusAssigned ( + IN PCI_IO_DEVICE *PciDevice, + OUT UINT8 *PrimaryBusNumber, + OUT UINT8 *SecondaryBusNumber, + OUT UINT8 *SubordinateBusNumber + ) +{ + EFI_STATUS Status; + UINT32 RootPortBusAssigned; + + Status =3D PciDevice->PciIo.Pci.Read ( + &PciDevice->PciIo, + EfiPciIoWidthUint32, + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, + 1, + &RootPortBusAssigned + ); + if ( !EFI_ERROR(Status)) { + if ( PrimaryBusNumber) { + *PrimaryBusNumber =3D (UINT8) (0xFF & RootPortBusAssigned); + } + if ( SecondaryBusNumber) { + *SecondaryBusNumber =3D (UINT8)(0xFF & (RootPortBusAssigned >> 8)); + } + if ( SubordinateBusNumber) { + *SubordinateBusNumber =3D (UINT8)(0xFF & (RootPortBusAssigned >> 16)= ); + } + } + return Status; +} + +/** + This routine determines the existance of the child PCI device for the gi= ven + PCI Root / Bridge Port device. Always assumes the input PCI device is th= e bridge + or PCI-PCI Bridge device. This routine should not be used with PCI endpo= int device. + + @param PciDevice A pointer to the PCI_IO_DEVICE. + + @retval TRUE child device exist + FALSE no child device +**/ +BOOLEAN +IsPciRootPortEmpty ( + IN PCI_IO_DEVICE *PciDevice + ) +{ + UINT8 SecBus, + SubBus; + EFI_STATUS Status; + LIST_ENTRY *Link; + PCI_IO_DEVICE *NextPciDevice; + + // + // check secondary & suboridinate bus numbers for its endpoint device + // existance + // + Status =3D GetPciRootPortBusAssigned ( PciDevice, NULL, &SecBus, &SubBus= ); + if ( !EFI_ERROR( Status)) { + Link =3D PciDevice->ChildList.ForwardLink; + if ( IsListEmpty ( Link)) { + // + // return as PCI Root port empty + // + DEBUG (( DEBUG_INFO, "RP empty,")); + return TRUE; + } + do { + NextPciDevice =3D PCI_IO_DEVICE_FROM_LINK ( Link); + DEBUG (( DEBUG_INFO, "dev@%x", NextPciDevice->BusNumber)); + + if ( NextPciDevice->BusNumber >=3D SecBus + && NextPciDevice->BusNumber <=3D SubBus) { + + return FALSE; + } + + Link =3D Link->ForwardLink; + } while ( Link !=3D &PciDevice->ChildList); + } else { + SecBus =3D SubBus =3D 0; + DEBUG (( DEBUG_ERROR, "unable to retrieve root port's bus range assign= ed!!!")); + } + + // + // return as PCI Root port empty + // + return TRUE; +} + +/** + The main routine which process the PCI feature Max_Payload_Size as per t= he + device-specific platform policy, as well as in complaince with the PCI B= ase + specification Revision 4, that aligns the value for the entire PCI heira= rchy + starting from its physical PCI Root port / Bridge device. + + @param PciDevice A pointer to the PCI_IO_DEVICE. + @param PciConfigPhase for the PCI feature configuration = phases: + PciFeatureGetDevicePolicy & PciFea= tureSetupPhase + @param PciFeaturesConfigurationTable pointer to OTHER_PCI_FEATURES_CONF= IGURATION_TABLE + + @retval EFI_SUCCESS processing of PCI feature Max_Payl= oad_Size + is successful. +**/ +EFI_STATUS +ProcessMaxPayloadSize ( + IN PCI_IO_DEVICE *PciDevice, + IN PCI_FEATURE_CONFIGURATION_PHASE PciConfigPhase, + IN OTHER_PCI_FEATURES_CONFIGURATION_TABLE *PciFeaturesConfigurationTab= le + ) +{ + PCI_REG_PCIE_DEVICE_CAPABILITY PciDeviceCap; + UINT8 MpsValue; + + + PciDeviceCap.Uint32 =3D PciDevice->PciExpStruct.DeviceCapability.Uint32; + + if ( PciConfigPhase =3D=3D PciFeatureGetDevicePolicy) { + if ( SetupMpsAsPerDeviceCapability ( PciDevice->SetupMPS)) + { + MpsValue =3D (UINT8)PciDeviceCap.Bits.MaxPayloadSize; + // + // no change to PCI Root ports without any endpoint device + // + if ( IS_PCI_BRIDGE ( &PciDevice->Pci) && PciDeviceCap.Bits.MaxPayloa= dSize) { + if ( IsPciRootPortEmpty ( PciDevice)) { + MpsValue =3D PCIE_MAX_PAYLOAD_SIZE_128B; + DEBUG (( DEBUG_INFO, "(reset RP MPS to min.)")); + } + } + } else { + MpsValue =3D TranslateMpsSetupValueToPci ( PciDevice->SetupMPS); + } + // + // discard device policy override request if greater than PCI device c= apability + // + PciDevice->SetupMPS =3D MIN( (UINT8)PciDeviceCap.Bits.MaxPayloadSize, = MpsValue); + } + + // + // align the MPS of the tree to the HCF with this device + // + if ( PciFeaturesConfigurationTable) { + MpsValue =3D PciFeaturesConfigurationTable->Max_Payload_Size; + + MpsValue =3D MIN ( PciDevice->SetupMPS, MpsValue); + PciDevice->SetupMPS =3D MIN ( PciDevice->SetupMPS, MpsValue); + + if ( MpsValue !=3D PciFeaturesConfigurationTable->Max_Payload_Size) { + DEBUG (( DEBUG_INFO, "reset MPS of the tree to %d,", MpsValue)); + PciFeaturesConfigurationTable->Max_Payload_Size =3D MpsValue; + } + } + + DEBUG (( DEBUG_INFO, + "Max_Payload_Size: %d [DevCap:%d],", + PciDevice->SetupMPS, PciDeviceCap.Bits.MaxPayloadSize + )); + return EFI_SUCCESS; +} + +/** + The main routine which process the PCI feature Max_Read_Req_Size as per = the + device-specific platform policy, as well as in complaince with the PCI B= ase + specification Revision 4, that aligns the value for the entire PCI heira= rchy + starting from its physical PCI Root port / Bridge device. + + @param PciDevice A pointer to the PCI_IO_DEVICE. + @param PciConfigPhase for the PCI feature configuration = phases: + PciFeatureGetDevicePolicy & PciFea= tureSetupPhase + @param PciFeaturesConfigurationTable pointer to OTHER_PCI_FEATURES_CONF= IGURATION_TABLE + + @retval EFI_SUCCESS processing of PCI feature Max_Read= _Req_Size + is successful. +**/ +EFI_STATUS +ProcessMaxReadReqSize ( + IN PCI_IO_DEVICE *PciDevice, + IN PCI_FEATURE_CONFIGURATION_PHASE PciConfigPhase, + IN OTHER_PCI_FEATURES_CONFIGURATION_TABLE *PciFeaturesConfigurationTab= le + ) +{ + PCI_REG_PCIE_DEVICE_CAPABILITY PciDeviceCap; + UINT8 MrrsValue; + + PciDeviceCap.Uint32 =3D PciDevice->PciExpStruct.DeviceCapability.Uint32; + + if ( PciConfigPhase =3D=3D PciFeatureGetDevicePolicy) { + if ( SetupMrrsAsPerDeviceCapability ( PciDevice->SetupMRRS)) + { + // + // The maximum read request size is not the data packet size of the = TLP, + // but the memory read request size, and set to the function as a re= questor + // to not exceed this limit. + // However, for the PCI device capable of isochronous traffic; this = memory read + // request size should not extend beyond the Max_Payload_Size. Thus,= in case if + // device policy return by platform indicates to set as per device c= apability + // than set as per Max_Payload_Size configuration value + // + if ( SetupMaxPayloadSize()) { + MrrsValue =3D PciDevice->SetupMPS; + } else { + // + // in case this driver is not required to configure the Max_Payloa= d_Size + // than consider programming HCF of the device capability's Max_Pa= yload_Size + // in this PCI hierarchy; thus making this an implementation speci= fic feature + // which the platform should avoid. For better results, the platfo= rm should + // make both the Max_Payload_Size & Max_Read_Request_Size to be co= nfigured + // by this driver + // + MrrsValue =3D (UINT8)PciDeviceCap.Bits.MaxPayloadSize; + } + } else { + // + // override as per platform based device policy + // + MrrsValue =3D TranslateMrrsSetupValueToPci ( PciDevice->SetupMRRS); + // + // align this device's Max_Read_Request_Size value to the entire PCI= tree + // + if ( PciFeaturesConfigurationTable) { + if ( !PciFeaturesConfigurationTable->Lock_Max_Read_Request_Size) { + PciFeaturesConfigurationTable->Lock_Max_Read_Request_Size =3D TR= UE; + PciFeaturesConfigurationTable->Max_Read_Request_Size =3D MrrsVal= ue; + } else { + // + // in case of another user enforced value of MRRS within the sam= e tree, + // pick the smallest between the locked value and this value; to= set + // across entire PCI tree nodes + // + MrrsValue =3D MIN ( + MrrsValue, + PciFeaturesConfigurationTable->Max_Read_Request_Si= ze + ); + PciFeaturesConfigurationTable->Max_Read_Request_Size =3D MrrsVal= ue; + } + } + } + // + // align this device's Max_Read_Request_Size to derived configuration = value + // + PciDevice->SetupMRRS =3D MrrsValue; + + } + + // + // align the Max_Read_Request_Size of the PCI tree based on 3 conditions: + // first, if user defines MRRS for any one PCI device in the tree than a= lign + // all the devices in the PCI tree. + // second, if user override is not define for this PCI tree than setup t= he MRRS + // based on MPS value of the tree to meet the criteria for the isochrono= us + // traffic. + // third, if no user override, or platform firmware policy has not selec= ted + // this PCI bus driver to configure the MPS; than configure the MRRS to a + // highest common value of PCI device capability for the MPS found among= all + // the PCI devices in this tree + // + if ( PciFeaturesConfigurationTable) { + if ( PciFeaturesConfigurationTable->Lock_Max_Read_Request_Size) { + PciDevice->SetupMRRS =3D PciFeaturesConfigurationTable->Max_Read_Req= uest_Size; + } else { + if ( SetupMaxPayloadSize()) { + PciDevice->SetupMRRS =3D PciDevice->SetupMPS; + } else { + PciDevice->SetupMRRS =3D MIN ( + PciDevice->SetupMRRS, + PciFeaturesConfigurationTable->Max_Read_Re= quest_Size + ); + } + PciFeaturesConfigurationTable->Max_Read_Request_Size =3D PciDevice->= SetupMRRS; + } + } + DEBUG (( DEBUG_INFO, "Max_Read_Request_Size: %d\n", PciDevice->SetupMRRS= )); + + return EFI_SUCCESS; +} + +/** + Overrides the PCI Device Control register MaxPayloadSize register field;= if + the hardware value is different than the intended value. + + @param PciDevice A pointer to the PCI_IO_DEVICE instance. + + @retval EFI_SUCCESS The data was read from or written to the P= CI device. + @retval EFI_UNSUPPORTED The address range specified by Offset, Wid= th, and Count is not + valid for the PCI configuration header of = the PCI controller. + @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid. + +**/ +EFI_STATUS +OverrideMaxPayloadSize ( + IN PCI_IO_DEVICE *PciDevice + ) +{ + PCI_REG_PCIE_DEVICE_CONTROL PcieDev; + UINT32 Offset; + EFI_STATUS Status; + + PcieDev.Uint16 =3D 0; + Offset =3D PciDevice->PciExpressCapabilityOffset + + OFFSET_OF (PCI_CAPABILITY_PCIEXP, DeviceControl); + Status =3D PciDevice->PciIo.Pci.Read ( + &PciDevice->PciIo, + EfiPciIoWidthUint16, + Offset, + 1, + &PcieDev.Uint16 + ); + if ( EFI_ERROR(Status)){ + DEBUG (( DEBUG_ERROR, "Unexpected DeviceControl register (0x%x) read e= rror!", + Offset + )); + return Status; + } + if ( PcieDev.Bits.MaxPayloadSize !=3D PciDevice->SetupMPS) { + PcieDev.Bits.MaxPayloadSize =3D PciDevice->SetupMPS; + DEBUG (( DEBUG_INFO, "Max_Payload_Size=3D%d,", PciDevice->SetupMPS)); + + Status =3D PciDevice->PciIo.Pci.Write ( + &PciDevice->PciIo, + EfiPciIoWidthUint16, + Offset, + 1, + &PcieDev.Uint16 + ); + if ( !EFI_ERROR(Status)) { + PciDevice->PciExpStruct.DeviceControl.Uint16 =3D PcieDev.Uint16; + } else { + DEBUG (( DEBUG_ERROR, "Unexpected DeviceControl register (0x%x) writ= e error!", + Offset + )); + } + } else { + DEBUG (( DEBUG_INFO, "No write of Max_Payload_Size=3D%d,", PciDevice->= SetupMPS)); + } + + return Status; +} + +/** + Overrides the PCI Device Control register MaxPayloadSize register field;= if + the hardware value is different than the intended value. + + @param PciDevice A pointer to the PCI_IO_DEVICE instance. + + @retval EFI_SUCCESS The data was read from or written to the P= CI controller. + @retval EFI_UNSUPPORTED The address range specified by Offset, Wid= th, and Count is not + valid for the PCI configuration header of = the PCI controller. + @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid. + +**/ +EFI_STATUS +OverrideMaxReadReqSize ( + IN PCI_IO_DEVICE *PciDevice + ) +{ + PCI_REG_PCIE_DEVICE_CONTROL PcieDev; + UINT32 Offset; + EFI_STATUS Status; + + PcieDev.Uint16 =3D 0; + Offset =3D PciDevice->PciExpressCapabilityOffset + + OFFSET_OF (PCI_CAPABILITY_PCIEXP, DeviceControl); + Status =3D PciDevice->PciIo.Pci.Read ( + &PciDevice->PciIo, + EfiPciIoWidthUint16, + Offset, + 1, + &PcieDev.Uint16 + ); + if ( EFI_ERROR(Status)){ + DEBUG (( DEBUG_ERROR, "Unexpected DeviceControl register (0x%x) read e= rror!", + Offset + )); + return Status; + } + if ( PcieDev.Bits.MaxReadRequestSize !=3D PciDevice->SetupMRRS) { + PcieDev.Bits.MaxReadRequestSize =3D PciDevice->SetupMRRS; + DEBUG (( DEBUG_INFO, "Max_Read_Request_Size: %d\n", PciDevice->SetupMR= RS)); + + Status =3D PciDevice->PciIo.Pci.Write ( + &PciDevice->PciIo, + EfiPciIoWidthUint16, + Offset, + 1, + &PcieDev.Uint16 + ); + if ( !EFI_ERROR(Status)) { + PciDevice->PciExpStruct.DeviceControl.Uint16 =3D PcieDev.Uint16; + } else { + DEBUG (( DEBUG_ERROR, "Unexpected DeviceControl register (0x%x) writ= e error!", + Offset + )); + } + } else { + DEBUG (( DEBUG_INFO, "No write of Max_Read_Request_Size=3D%d\n", PciDe= vice->SetupMRRS)); + } + + return Status; +} + +/** + 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; + } +} + +/** + Process each PCI device as per the pltaform and device-specific policy. + + @param RootBridge A pointer to the PCI_IO_DEVICE. + + @retval EFI_SUCCESS processing each PCI feature as per policy = defined + was successful. + **/ +EFI_STATUS +SetupDevicePciFeatures ( + IN PCI_IO_DEVICE *PciDevice, + IN PCI_FEATURE_CONFIGURATION_PHASE PciConfigPhase + ) +{ + EFI_STATUS Status; + PCI_REG_PCIE_CAPABILITY PcieCap; + OTHER_PCI_FEATURES_CONFIGURATION_TABLE *OtherPciFeaturesConfigTable; + + PcieCap.Uint16 =3D PciDevice->PciExpStruct.Capability.Uint16; + DumpDevicePortType ( (UINT8)PcieCap.Bits.DevicePortType); + + OtherPciFeaturesConfigTable =3D NULL; + Status =3D GetPciFeaturesConfigurationTable ( PciDevice, &OtherPciFeatur= esConfigTable); + if ( EFI_ERROR( Status)) { + DEBUG (( + EFI_D_WARN, "No primary root port found in these root bridge nodes= !\n" + )); + } else if ( !OtherPciFeaturesConfigTable) { + DEBUG (( + DEBUG_INFO, "No PCI features config. table for this device!\n" + )); + } else { + DEBUG (( + DEBUG_INFO, "using PCI features config. table ID: %d\n", + OtherPciFeaturesConfigTable->ID + )); + } + + if ( PciConfigPhase =3D=3D PciFeatureGetDevicePolicy) { + Status =3D GetPciDevicePlatformPolicy ( PciDevice); + if ( EFI_ERROR(Status)) { + DEBUG (( + DEBUG_ERROR, "Error in obtaining PCI device policy!!!\n" + )); + } + } + + if ( SetupMaxPayloadSize ()) { + Status =3D ProcessMaxPayloadSize ( + PciDevice, + PciConfigPhase, + OtherPciFeaturesConfigTable + ); + } + // + // implementation specific rule:- the MRRS of any PCI device should be p= rocessed + // only after the MPS is processed for that device + // + if ( SetupMaxReadReqSize ()) { + Status =3D ProcessMaxReadReqSize ( + PciDevice, + PciConfigPhase, + OtherPciFeaturesConfigTable + ); + } + return Status; +} + +/** + Traverse all the nodes from the root bridge or PCI-PCI bridge instance, = to + configure the PCI features as per the device-specific platform policy, a= nd + as per the 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 +SetupPciFeatures ( + IN PCI_IO_DEVICE *RootBridge, + IN PCI_FEATURE_CONFIGURATION_PHASE PciConfigPhase + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + PCI_IO_DEVICE *Device; + + for ( Link =3D RootBridge->ChildList.ForwardLink + ; Link !=3D &RootBridge->ChildList + ; Link =3D Link->ForwardLink + ) { + Device =3D PCI_IO_DEVICE_FROM_LINK (Link); + if (IS_PCI_BRIDGE (&Device->Pci)) { + DEBUG (( + DEBUG_INFO, "::Bridge [%02x|%02x|%02x] -", + Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber + )); + if (Device->IsPciExp) { + Status =3D SetupDevicePciFeatures ( 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 + // + + } + + SetupPciFeatures ( Device, PciConfigPhase); + } else { + DEBUG (( + DEBUG_INFO, "::Device [%02x|%02x|%02x] -", + Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber + )); + if (Device->IsPciExp) { + + Status =3D SetupDevicePciFeatures ( 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; +} + +/** + Program the PCI device, to override the PCI features as per the policy, + resolved from previous traverse. + + @param RootBridge A pointer to the PCI_IO_DEVICE. + + @retval EFI_SUCCESS The other PCI features configuration durin= g enumeration + of all the nodes of the PCI root bridge in= stance were + programmed in PCI-compliance pattern along= with the + device-specific policy, as applicable. + @retval EFI_UNSUPPORTED One of the override operation maong the no= des of + the PCI hierarchy resulted in a incompatib= le address + range. + @retval EFI_INVALID_PARAMETER The override operation is performed with i= nvalid input + parameters. +**/ +EFI_STATUS +ProgramDevicePciFeatures ( + IN PCI_IO_DEVICE *PciDevice + ) +{ + EFI_STATUS Status; + + if ( SetupMaxPayloadSize ()) { + Status =3D OverrideMaxPayloadSize (PciDevice); + } + if ( SetupMaxReadReqSize ()) { + Status =3D OverrideMaxReadReqSize (PciDevice); + } + return Status; +} + +/** + Program all the nodes of the specified root bridge or PCI-PCI Bridge, to + override the PCI features. + + @param RootBridge A pointer to the PCI_IO_DEVICE. + + @retval EFI_SUCCESS The other PCI features configuration durin= g enumeration + of all the nodes of the PCI root bridge in= stance were + programmed in PCI-compliance pattern along= with the + device-specific policy, as applicable. + @retval EFI_UNSUPPORTED One of the override operation maong the no= des of + the PCI hierarchy resulted in a incompatib= le address + range. + @retval EFI_INVALID_PARAMETER The override operation is performed with i= nvalid input + parameters. +**/ +EFI_STATUS +ProgramPciFeatures ( + IN PCI_IO_DEVICE *RootBridge + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + PCI_IO_DEVICE *Device; + + for ( Link =3D RootBridge->ChildList.ForwardLink + ; Link !=3D &RootBridge->ChildList + ; Link =3D Link->ForwardLink + ) { + Device =3D PCI_IO_DEVICE_FROM_LINK (Link); + if (IS_PCI_BRIDGE (&Device->Pci)) { + DEBUG (( + DEBUG_INFO, "::Bridge [%02x|%02x|%02x] -", + Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber + )); + if (Device->IsPciExp) { + DEBUG (( DEBUG_INFO, "ready to override!\n")); + + Status =3D ProgramDevicePciFeatures ( Device); + } else { + DEBUG (( DEBUG_INFO, "skipped!\n")); + // + // PCI Bridge which does not have PCI Express Capability structure + // cannot process this kind of PCI Bridge device + // + + } + + Status =3D ProgramPciFeatures ( Device); + } else { + DEBUG (( + DEBUG_INFO, "::Device [%02x|%02x|%02x] -", + Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber + )); + if (Device->IsPciExp) { + DEBUG (( DEBUG_INFO, "ready to override!\n")); + + Status =3D ProgramDevicePciFeatures ( Device); + } else { + DEBUG (( DEBUG_INFO, "skipped!\n")); + // + // PCI Device which does not have PCI Express Capability structure + // cannot process this kind of PCI device + // + } + } + } + + return Status; +} + +/** + Create a node of type PRIMARY_ROOT_PORT_NODE for the given PCI device, a= nd + assigns EFI handles of its Root Bridge and its own, along with its PCI B= us + range for the secondary and subordinate bus range. + + @param RootBridge A pointer to the PCI_IO_DEVICE for its PCI R= oot Bridge + @param Device A pointer to the PCI_IO_DEVICE for the PCI c= ontroller + @param RootPortSecBus PCI controller's Secondary Bus number + @param RootPortSubBus PCI controller's Subordinate Bus number + @param PrimaryRootPortNode A pointer to the PRIMARY_ROOT_PORT_NODE to r= eturn + the newly created node for the PCI controlle= r. In + case of error nothing is return in this. + + @retval EFI_SUCCESS new node of PRIMARY_ROOT_PORT_NODE is retu= rned for + the PCI controller + EFI_OUT_OF_RESOURCES unable to create the node for the PCI cont= roller + EFI_INVALID_PARAMETER unable to store the node as the input buff= er is + not empty (*PrimaryRootPortNode) +**/ +EFI_STATUS +CreatePrimaryPciRootPortNode ( + IN PCI_IO_DEVICE *RootBridge, + IN PCI_IO_DEVICE *Device, + IN UINT8 RootPortSecBus, + IN UINT8 RootPortSubBus, + OUT PRIMARY_ROOT_PORT_NODE **PrimaryRootPortNode + ) +{ + PRIMARY_ROOT_PORT_NODE *RootPortNode =3D NULL; + + if ( !*PrimaryRootPortNode) { + RootPortNode =3D AllocateZeroPool ( sizeof (PRIMARY= _ROOT_PORT_NODE)); + if ( RootPortNode =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + RootPortNode->Signature =3D PCI_ROOT_PORT_SIGNATURE; + RootPortNode->RootBridgeHandle =3D RootBridge->Handle; + RootPortNode->RootPortHandle =3D Device->Handle; + RootPortNode->SecondaryBusStart =3D RootPortSecBus; + RootPortNode->SecondaryBusEnd =3D RootPortSubBus; + InitializeListHead ( &RootPortNode->NeighborRootPort); + *PrimaryRootPortNode =3D RootPortNode; + return EFI_SUCCESS; + } else { + return EFI_INVALID_PARAMETER; + } +} + +/** + Checks to report whether the input PCI controller's secondary / subordin= ate + bus numbers are within the recorded list of other PCI controllers (root = ports). + + @param RootPortNode A pointer to the first node of PRIMARY_ROOT_PO= RT_NODE + @param RootPortSecBus PCI secondary bus number of the PCI controller= found + @param RootPortSubBus PCI subordinate bus number of the PCI Root Por= t found + + @retval TRUE A child PCI Root port found + FALSE A new PCI controller found +**/ +BOOLEAN +CheckChildRootPort ( + IN PRIMARY_ROOT_PORT_NODE *RootPortNode, + IN UINT8 RootPortSecBus, + IN UINT8 RootPortSubBus +) +{ + LIST_ENTRY *Link; + PRIMARY_ROOT_PORT_NODE *Temp; + + if ( !RootPortNode) { + return FALSE; + } + Link =3D &RootPortNode->NeighborRootPort; + do { + Temp =3D PRIMARY_ROOT_PORT_NODE_FROM_LINK ( Link); + if ( RootPortSecBus >=3D Temp->SecondaryBusStart + && RootPortSubBus <=3D Temp->SecondaryBusEnd) { + // + // given root port's secondary & subordinate within its primary ports + // hence return as child port + // + return TRUE; + } + Link =3D Link->ForwardLink; + } while (Link !=3D &RootPortNode->NeighborRootPort); + // + // the given root port's secondary / subordinate bus numbers do not belo= ng to + // any existing primary root port's bus range hence consider another pri= mary + // root port of the root bridge controller + // + return FALSE; +} + +/** + Create the vector of PCI Feature configuration table as per the number of + the PCI Root Ports given, assigns default value to the PCI features supp= orted + and assign its address to the global variable "mPciFeaturesConfiguration= TableInstances". + + @param NumberOfRootPorts An input arguement of UINTN to indicate numb= er of + primary PCI physical Root Bridge devices fou= nd + + @retval EFI_OUT_OF_RESOURCES unable to allocate buffer to store PCI fea= ture + configuration table for all the physical P= CI root + ports given + EFI_SUCCESS PCI Feature COnfiguration table created fo= r all + the PCI Rooot ports reported + */ +EFI_STATUS +CreatePciFeaturesConfigurationTableInstances ( + IN UINTN NumberOfRootPorts + ) +{ + OTHER_PCI_FEATURES_CONFIGURATION_TABLE *PciRootBridgePortFeatures =3D = NULL; + UINTN Instances; + + PciRootBridgePortFeatures =3D AllocateZeroPool ( + sizeof ( OTHER_PCI_FEATURES_CONFIGURATION_= TABLE) * NumberOfRootPorts + ); + if ( !PciRootBridgePortFeatures) { + return EFI_OUT_OF_RESOURCES; + } + + for ( Instances =3D 0; Instances < NumberOfRootPorts; Instances++) { + PciRootBridgePortFeatures [Instances].ID =3D Instan= ces + 1; + PciRootBridgePortFeatures [Instances].Max_Payload_Size =3D PCIE_M= AX_PAYLOAD_SIZE_4096B; + PciRootBridgePortFeatures [Instances].Max_Read_Request_Size =3D PCIE_M= AX_READ_REQ_SIZE_4096B; + PciRootBridgePortFeatures [Instances].Lock_Max_Read_Request_Size =3D F= ALSE; + } + mPciFeaturesConfigurationTableInstances =3D PciRootBridgePortFeatures; + return EFI_SUCCESS; +} + +/** + This routine pairs the each PCI Root Port node with one of the PCI Featu= re + Configuration Table node. Each physical PCI Root Port has its own PCI fe= ature + configuration table which will used for aligning all its downstream comp= onents. + + @param NumberOfRootPorts inputs the number of physical PCI root por= ts + found on the Root bridge instance + + @retval EFI_INVALID_PARAMETER if the primary PCI root ports list is vaca= nt when + there is one or more PCI Root port indicat= ed as per + input parameter + EFI_UNSUPPORTED The PCI Root Port nodes not paired equally= with + the PCI Configuration Table nodes + EFI_SUCCESS each PCI feature configuration node is pai= red equally + with each PCI Root port in the list +**/ +EFI_STATUS +AssignPciFeaturesConfigurationTable ( + IN UINTN NumberOfRootPorts + ) +{ + UINTN Instances; + LIST_ENTRY *Link; + PRIMARY_ROOT_PORT_NODE *Temp; + + if ( !mPrimaryRootPortList + && NumberOfRootPorts) { + DEBUG (( + DEBUG_ERROR, + "Critical error! no internal table setup for %d PCI Root ports \n", + NumberOfRootPorts + )); + return EFI_INVALID_PARAMETER; + } + + if ( NumberOfRootPorts) { + Link =3D &mPrimaryRootPortList->NeighborRootPort; + for ( Instances =3D 0 + ; (Instances < NumberOfRootPorts) + ; Instances++ + ) { + Temp =3D PRIMARY_ROOT_PORT_NODE_FROM_LINK ( Link); + Temp->OtherPciFeaturesConfigurationTable =3D &mPciFeaturesConfigurat= ionTableInstances [Instances]; + DEBUG (( + DEBUG_INFO, + "Assigned to %dth primary root port\n", + Instances + )); + + Link =3D Link->ForwardLink; + } + if ( Link !=3D &mPrimaryRootPortList->NeighborRootPort) { + DEBUG (( + DEBUG_ERROR, + "Error!! PCI Root Port list is not properly matched with Config.= , Table list \n" + )); + return EFI_UNSUPPORTED; + } + } + return EFI_SUCCESS; +} + +/** + Prepare each PCI Controller (Root Port) with its own PCI Feature configu= ration + table node that can be used for tracking to align all PCI nodes in its h= ierarchy. + + @param PrimaryRootPorts A pointer to PRIMARY_ROOT_PORT_NODE + @param NumberOfRootPorts Total number of pysical primary PCI Root p= orts + + @retval EFI_OUT_OF_RESOURCES unable to allocate buffer to store PCI fea= ture + configuration table for all the physical P= CI root + ports given + EFI_INVALID_PARAMETER if the primary PCI root ports list is vaca= nt when + there is one or more PCI Root port indicat= ed as per + input parameter + EFI_UNSUPPORTED The PCI Root Port nodes not paired equally= with + the PCI Configuration Table nodes + EFI_SUCCESS each PCI feature configuration node is pai= red equally + with each PCI Root port in the list +**/ +EFI_STATUS +PreparePciControllerConfigurationTable ( + IN PRIMARY_ROOT_PORT_NODE *PrimaryRootPorts, + IN UINTN NumberOfRootPorts + ) +{ + EFI_STATUS Status; + + mPrimaryRootPortList =3D PrimaryRootPorts; + DEBUG (( + DEBUG_INFO, "Number of primary Root Ports found on this bridge =3D %= d\n", + NumberOfRootPorts + )); + + Status =3D CreatePciFeaturesConfigurationTableInstances ( NumberOfRootPo= rts); + if ( EFI_ERROR(Status)) { + DEBUG (( + DEBUG_ERROR, "Unexpected memory node creation error for PCI featur= es!\n" + )); + } else { + // + // align the primary root port nodes list with the PCI Feature configu= ration + // table. Note that the PCI Feature configuration table is not maintai= n for + // the RCiEP devices + // + Status =3D AssignPciFeaturesConfigurationTable ( NumberOfRootPorts); + } + return Status; +} + +/** + Scan all the nodes of the RootBridge to identify and create a separate l= ist + of all primary physical PCI root ports and link each with its own instan= ce of + the PCI Feature Configuration Table. + + @param RootBridge A pointer to the PCI_IO_DEVICE of the PCI Root Bri= dge + + @retval EFI_OUT_OF_RESOURCES unable to allocate buffer to store PCI fea= ture + configuration table for all the physical P= CI root + ports given + EFI_NOT_FOUND No PCI Bridge device found + EFI_SUCCESS PCI Feature COnfiguration table created fo= r all + the PCI Rooot ports found + EFI_INVALID_PARAMETER invalid parameter passed to the routine wh= ich + creates the PCI controller node for the pr= imary + Root post list +**/ +EFI_STATUS +RecordPciRootPortBridges ( + IN PCI_IO_DEVICE *RootBridge + ) +{ + EFI_STATUS Status =3D EFI_NOT_FOUND; + LIST_ENTRY *Link; + PCI_IO_DEVICE *Device; + UINTN NumberOfRootPorts; + PRIMARY_ROOT_PORT_NODE *PrimaryRootPorts, + *TempNode; + UINT8 RootPortSecBus, + RootPortSubBus; + + DEBUG (( + DEBUG_INFO, "<<********** RecordPciRootPortBridges -start **********= ***>>\n" + )); + NumberOfRootPorts =3D 0; + PrimaryRootPorts =3D NULL; + for ( Link =3D RootBridge->ChildList.ForwardLink + ; Link !=3D &RootBridge->ChildList + ; Link =3D Link->ForwardLink + ) { + Device =3D PCI_IO_DEVICE_FROM_LINK (Link); + if (IS_PCI_BRIDGE (&Device->Pci)) { + Status =3D GetPciRootPortBusAssigned ( + Device, + NULL, + &RootPortSecBus, + &RootPortSubBus + ); + if ( !EFI_ERROR(Status)) { + DEBUG (( + DEBUG_INFO, "::Device [%02x|%02x|%02x] - SecBus=3D0x%x, SubBus= =3D0x%x\n", + Device->BusNumber, Device->DeviceNumber, Device->FunctionNumbe= r, + RootPortSecBus, RootPortSubBus + )); + } else { + DEBUG (( + DEBUG_ERROR, "Unexpected read error [0x%lx]::Device [%02x|%02x= |%02x]\n", + Status, Device->BusNumber, Device->DeviceNumber, Device->Funct= ionNumber + )); + RootPortSecBus =3D RootPortSubBus =3D 0; + continue; + } + + if ( !PrimaryRootPorts) { + NumberOfRootPorts++; + Status =3D CreatePrimaryPciRootPortNode ( + RootBridge, + Device, + RootPortSecBus, + RootPortSubBus, + &PrimaryRootPorts + ); + if ( EFI_ERROR(Status)) { + // + // abort mission to scan for all primary roots ports of a bridge + // controller if error encountered for very first PCI primary ro= ot port + // + DEBUG (( + DEBUG_ERROR, "Unexpected node creation error [0x%lx]::Device= [%02x|%02x|%02x]\n", + Status, Device->BusNumber, Device->DeviceNumber, Device->Fun= ctionNumber + )); + return Status; + } + DEBUG (( + DEBUG_INFO, "first primary root port found::Device [%02x|%02x|= %02x]\n", + Device->BusNumber, Device->DeviceNumber, Device->FunctionNumber + )); + } else { + if ( !CheckChildRootPort ( PrimaryRootPorts, RootPortSecBus, RootP= ortSubBus)) { + NumberOfRootPorts++; + TempNode =3D NULL; + Status =3D CreatePrimaryPciRootPortNode ( + RootBridge, + Device, + RootPortSecBus, + RootPortSubBus, + &TempNode + ); + if ( !EFI_ERROR(Status)) { + // + // another primary root port found on the same bridge controll= er + // insert in the node list + // + InsertTailList ( &PrimaryRootPorts->NeighborRootPort, &TempNod= e->NeighborRootPort); + DEBUG (( + DEBUG_INFO, "next primary root port found::Device [%02x|%0= 2x|%02x]\n", + Device->BusNumber, Device->DeviceNumber, Device->FunctionN= umber + )); + } else { + DEBUG (( + DEBUG_ERROR, "Unexpected node creation error [0x%lx]::Devi= ce [%02x|%02x|%02x]\n", + Status, Device->BusNumber, Device->DeviceNumber, Device->F= unctionNumber + )); + } + } + } + } + } + // + // prepare the PCI root port and its feature configuration table list + // + if ( NumberOfRootPorts) { + Status =3D PreparePciControllerConfigurationTable ( + PrimaryRootPorts, + NumberOfRootPorts + ); + + } else { + DEBUG (( + DEBUG_INFO, "No PCI Root port found on this bridge!\n" + )); + } + + DEBUG (( + DEBUG_INFO, "<<********** RecordPciRootPortBridges - end **********>= >\n" + )); + return Status; +} + +/** + 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 durin= g enumeration + of all the nodes of the PCI root bridge in= stance were + programmed in PCI-compliance pattern along= with the + device-specific policy, as applicable. + @retval EFI_UNSUPPORTED One of the override operation maong the no= des of + the PCI hierarchy resulted in a incompatib= le address + range. + @retval EFI_INVALID_PARAMETER The override operation is performed with i= nvalid input + parameters. +**/ +EFI_STATUS +EnumerateOtherPciFeatures ( + IN PCI_IO_DEVICE *RootBridge + ) +{ + EFI_STATUS Status; + CHAR16 *Str; + UINTN OtherPciFeatureConfigPhase; + + // + // check on PCI features configuration is complete and re-enumeration is= required + // + if ( !CheckPciFeaturesConfigurationRequired ( RootBridge)) { + return EFI_ALREADY_STARTED; + } + + Str =3D ConvertDevicePathToText ( + DevicePathFromHandle (RootBridge->Handle), + FALSE, + FALSE + ); + DEBUG ((DEBUG_INFO, "Enumerating PCI features for Root Bridge %s\n", Str= !=3D NULL ? Str : L"")); + + for ( OtherPciFeatureConfigPhase =3D PciFeatureRootBridgeScan + ; OtherPciFeatureConfigPhase <=3D PciFeatureConfigurationComplete + ; OtherPciFeatureConfigPhase++ + ) { + switch ( OtherPciFeatureConfigPhase){ + case PciFeatureRootBridgeScan: + SetupPciFeaturesConfigurationDefaults (); + // + //first scan the entire root bridge heirarchy for the primary PCI = root ports + // + RecordPciRootPortBridges ( RootBridge); + break; + + case PciFeatureGetDevicePolicy: + case PciFeatureSetupPhase: + DEBUG (( + DEBUG_INFO, "<<********** SetupPciFeatures - start **********>= >\n" + )); + // + // enumerate the other PCI features + // + Status =3D SetupPciFeatures ( RootBridge, OtherPciFeatureConfigPha= se); + + DEBUG (( + DEBUG_INFO, "<<********** SetupPciFeatures - end **********>>\= n" + )); + break; + + case PciFeatureConfigurationPhase: + // + // override the PCI features as per enumeration phase + // + DEBUG ((DEBUG_INFO, "PCI features override for Root Bridge %s\n", = Str !=3D NULL ? Str : L"")); + DEBUG (( + DEBUG_INFO, "<<********** ProgramPciFeatures - start *********= *>>\n" + )); + Status =3D ProgramPciFeatures ( RootBridge); + DEBUG (( + DEBUG_INFO, "<<********** ProgramPciFeatures - end **********>= >\n" + )); + break; + + case PciFeatureConfigurationComplete: + // + // clean up the temporary resource nodes created for this root bri= dge + // + DestroyPrimaryRootPortNodes (); + + ErasePciFeaturesConfigurationTable (); + } + } + + if (Str !=3D NULL) { + FreePool (Str); + } + // + // mark this root bridge as PCI features configuration complete, and no = new + // enumeration is required + // + AddRootBridgeInPciFeaturesConfigCompletionList ( RootBridge, FALSE); + return Status; +} + +/** + This routine is invoked from the Stop () interface for the EFI handle of= the + RootBridge. Free up its node of type PCI_FEATURE_CONFIGURATION_COMPLETIO= N_LIST. + + @param RootBridge A pointer to the PCI_IO_DEVICE +**/ +VOID +DestroyRootBridgePciFeaturesConfigCompletionList ( + IN PCI_IO_DEVICE *RootBridge + ) +{ + LIST_ENTRY *Link; + PCI_FEATURE_CONFIGURATION_COMPLETION_LIST *Temp; + + if ( mPciFeaturesConfigurationCompletionList) { + Link =3D &mPciFeaturesConfigurationCompletionList->RootBridgeLink; + + do { + Temp =3D PCI_FEATURE_CONFIGURATION_COMPLETION_LIST_FROM_LINK (Link); + if ( Temp->RootBridgeHandle =3D=3D RootBridge->Handle) { + RemoveEntryList ( Link); + FreePool ( Temp); + return; + } + Link =3D Link->ForwardLink; + } while (Link !=3D &mPciFeaturesConfigurationCompletionList->RootBridg= eLink); + } + // + // not found on the PCI feature configuration completion list, return + // + return; +} diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h b/MdeModule= Pkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h new file mode 100644 index 0000000000..9f225fa993 --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h @@ -0,0 +1,201 @@ +/** @file + PCI standard feature support functions implementation for PCI Bus module= .. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_PCI_FEATURES_SUPPORT_H_ +#define _EFI_PCI_FEATURES_SUPPORT_H_ + +#include "PciBus.h" +#include "PciPlatformSupport.h" + +// +// Macro definitions for the PCI Features support PCD +// +#define PCI_FEATURE_SUPPORT_FLAG_MPS BIT0 +#define PCI_FEATURE_SUPPORT_FLAG_MRRS BIT1 + +// +// defines the data structure to hold the details of the PCI Root port dev= ices +// +typedef struct _PRIMARY_ROOT_PORT_NODE PRIMARY_ROOT_PORT_NODE; + +// +// defines the data structure to hold the configuration data for the other= PCI +// features +// +typedef struct _OTHER_PCI_FEATURES_CONFIGURATION_TABLE OTHER_PCI_FEATURES= _CONFIGURATION_TABLE; + +// +// Defines for the PCI features configuration completion and re-enumeratio= n list +// +typedef struct _PCI_FEATURE_CONFIGURATION_COMPLETION_LIST PCI_FEATURE_CON= FIGURATION_COMPLETION_LIST; + +// +// Signature value for the PCI Root Port node +// +#define PCI_ROOT_PORT_SIGNATURE SIGNATURE_32 ('p', 'c', 'i',= 'p') + +// +// Definitions of the PCI Root Port data structure members +// +struct _PRIMARY_ROOT_PORT_NODE { + // + // Signature header + // + UINT32 Signature; + // + // linked list pointers to next node + // + LIST_ENTRY NeighborRootPort; + // + // EFI handle of the parent Root Bridge instance + // + EFI_HANDLE RootBridgeHandle; + // + // EFI handle of the PCI controller + // + EFI_HANDLE RootPortHandle; + // + // PCI Secondary bus value of the PCI controller + // + UINT8 SecondaryBusStart; + // + // PCI Subordinate bus value of the PCI controller + // + UINT8 SecondaryBusEnd; + // + // pointer to the corresponding PCI feature configuration Table node + // + OTHER_PCI_FEATURES_CONFIGURATION_TABLE *OtherPciFeaturesConfiguration= Table; +}; + +#define PRIMARY_ROOT_PORT_NODE_FROM_LINK(a) \ + CR (a, PRIMARY_ROOT_PORT_NODE, NeighborRootPort, PCI_ROOT_PORT_SIGNATURE) + +// +// Definition of the PCI Feature configuration Table members +// +struct _OTHER_PCI_FEATURES_CONFIGURATION_TABLE { + // + // Configuration Table ID + // + UINTN ID; + // + // to configure the PCI feature Maximum payload size to maintain the dat= a packet + // size among all the PCI devices in the PCI hierarchy + // + UINT8 Max_Payload_Size; + // + // to configure the PCI feature maximum read request size to maintain th= e memory + // requester size among all the PCI devices in the PCI hierarchy + // + UINT8 Max_Read_Request_Size; + // + // lock the Max_Read_Request_Size for the entire PCI tree of a root port + // + BOOLEAN Lock_Max_Read_Request_Size; +}; + + +// +// PCI feature configuration node signature value +// +#define PCI_FEATURE_CONFIGURATION_SIGNATURE SIGNATURE_32 ('p= ', 'c', 'i', 'f') + +struct _PCI_FEATURE_CONFIGURATION_COMPLETION_LIST { + // + // Signature header + // + UINT32 Signature; + // + // link to next Root Bridge whose PCI Feature configuration is complete + // + LIST_ENTRY RootBridgeLink; + // + // EFI handle of the Root Bridge whose PCI feature configuration is comp= lete + // + EFI_HANDLE RootBridgeHandle; + // + // indication for complete re-enumeration of the PCI feature configurati= on + // + BOOLEAN ReEnumeratePciFeatureConfigura= tion; +}; + +#define PCI_FEATURE_CONFIGURATION_COMPLETION_LIST_FROM_LINK(a) \ + CR (a, PCI_FEATURE_CONFIGURATION_COMPLETION_LIST, RootBridgeLink, PCI_FE= ATURE_CONFIGURATION_SIGNATURE) + +// +// Declaration of the internal sub-phases within the PCI Feature enumerati= on +// +typedef enum { + // + // initial phase in configuring the other PCI features to record the pri= mary + // root ports + // + PciFeatureRootBridgeScan, + // + // get the PCI device-specific platform policies and align with device c= apabilities + // + PciFeatureGetDevicePolicy, + // + // align all PCI nodes in the PCI heirarchical tree + // + PciFeatureSetupPhase, + // + // finally override to complete configuration of the PCI feature + // + PciFeatureConfigurationPhase, + // + // PCI feature configuration complete + // + PciFeatureConfigurationComplete + +}PCI_FEATURE_CONFIGURATION_PHASE; + +/** + Main routine to indicate platform selection of any of the other PCI feat= ures + to be configured by this driver + + @retval TRUE platform has selected the other PCI features to be confi= gured + FALSE platform has not selected any of the other PCI features +**/ +BOOLEAN +CheckOtherPciFeaturesPcd ( + ); + +/** + 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 durin= g enumeration + of all the nodes of the PCI root bridge in= stance were + programmed in PCI-compliance pattern along= with the + device-specific policy, as applicable. + @retval EFI_UNSUPPORTED One of the override operation maong the no= des of + the PCI hierarchy resulted in a incompatib= le address + range. + @retval EFI_INVALID_PARAMETER The override operation is performed with i= nvalid input + parameters. +**/ +EFI_STATUS +EnumerateOtherPciFeatures ( + IN PCI_IO_DEVICE *RootBridge + ); + +/** + This routine is invoked from the Stop () interface for the EFI handle of= the + RootBridge. Free up its node of type PCI_FEATURE_CONFIGURATION_COMPLETIO= N_LIST. + + @param RootBridge A pointer to the PCI_IO_DEVICE +**/ +VOID +DestroyRootBridgePciFeaturesConfigCompletionList ( + IN PCI_IO_DEVICE *RootBridge + ); +#endif diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c b/MdeModul= ePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c new file mode 100644 index 0000000000..d94037d69a --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c @@ -0,0 +1,565 @@ +/** @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) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PciPlatformSupport.h" + +EFI_PCI_PLATFORM_PROTOCOL *mPciPlatformProtocol; +EFI_PCI_OVERRIDE_PROTOCOL *mPciOverrideProtocol; + +EFI_PCI_PLATFORM_PROTOCOL2 *mPciPlatformProtocol2; +EFI_PCI_OVERRIDE_PROTOCOL2 *mPciOverrideProtocol2; + + +/** + This function retrieves the PCI Platform Protocol published by platform = driver + +**/ +VOID +GetPciPlatformProtocol ( + ) +{ + mPciPlatformProtocol2 =3D NULL; + gBS->LocateProtocol ( + &gEfiPciPlatformProtocol2Guid, + NULL, + (VOID **) &mPciPlatformProtocol2 + ); + + // + // If PCI Platform protocol doesn't exist, try to get Pci Override Proto= col. + // + if (mPciPlatformProtocol2 =3D=3D NULL) { + mPciOverrideProtocol2 =3D NULL; + gBS->LocateProtocol ( + &gEfiPciOverrideProtocol2Guid, + NULL, + (VOID **) &mPciOverrideProtocol2 + ); + } + // + // fetch the old PCI Platform Protocols if new are not installed + // + if (mPciOverrideProtocol2 =3D=3D NULL) { + + mPciPlatformProtocol =3D NULL; + gBS->LocateProtocol ( + &gEfiPciPlatformProtocolGuid, + NULL, + (VOID **) &mPciPlatformProtocol + ); + + // + // If PCI Platform protocol doesn't exist, try to get Pci Override Pr= otocol. + // + if (mPciPlatformProtocol =3D=3D NULL) { + mPciOverrideProtocol =3D NULL; + gBS->LocateProtocol ( + &gEfiPciOverrideProtocolGuid, + NULL, + (VOID **) &mPciOverrideProtocol + ); + } + } +} + +/** + This function indicates the presence of PCI Platform driver + @retval TRUE or FALSE +**/ +BOOLEAN +CheckPciPlatformProtocolInstall ( + ) +{ + if (mPciPlatformProtocol2 !=3D NULL) { + return TRUE; + } else if (mPciOverrideProtocol2 !=3D NULL) { + return TRUE; + } else { + if (mPciPlatformProtocol !=3D NULL) { + return TRUE; + } else if (mPciOverrideProtocol !=3D NULL){ + return TRUE; + } + } + return FALSE; +} + +/** + Provides the hooks from the PCI bus driver to every PCI controller (devi= ce/function) at various + stages of the PCI enumeration process that allow the host bridge driver = to preinitialize individual + PCI controllers before enumeration. + + This function is called during the PCI enumeration process. No specific = action is expected from this + member function. It allows the host bridge driver to preinitialize indiv= idual PCI controllers before + enumeration. + + @param[in] HostBridgeHandle The associated PCI host bridge handle. + @param[in] RootBridgeHandle The associated PCI root bridge handle. + @param[in] RootBridgePciAddress The address of the PCI device on the PCI= bus. + @param[in] Phase The phase of the PCI controller enumeration. + @param[in] ExecPhase Defines the execution phase of the PCI chipset= driver. + + @retval Status returns the status from the PCI Platform proto= col as is + +**/ +EFI_STATUS +PciPlatformPreprocessController ( + IN EFI_HANDLE HostBridgeHandle, + IN EFI_HANDLE RootBridgeHandle, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS RootBridgePciAddress, + IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase, + IN EFI_PCI_EXECUTION_PHASE ExecPhase + ) +{ + EFI_STATUS Status; + + if (mPciPlatformProtocol2 !=3D NULL) { + // + // Call PlatformPci::PrepController() if the protocol is present. + // + Status =3D mPciPlatformProtocol2->PlatformPrepController ( + (EFI_PCI_PLATFORM_PROTOCOL*)mPciPlat= formProtocol2, + HostBridgeHandle, + RootBridgeHandle, + RootBridgePciAddress, + Phase, + ExecPhase + ); + } else if (mPciOverrideProtocol2 !=3D NULL) { + // + // Call PlatformPci::PrepController() if the protocol is present. + // + Status =3D mPciOverrideProtocol2->PlatformPrepController ( + (EFI_PCI_PLATFORM_PROTOCOL*)mPciOver= rideProtocol2, + HostBridgeHandle, + RootBridgeHandle, + RootBridgePciAddress, + Phase, + ExecPhase + ); + } else { + if (mPciPlatformProtocol !=3D NULL) { + // + // Call PlatformPci::PrepController() if the protocol is present. + // + Status =3D mPciPlatformProtocol->PlatformPrepController ( + mPciPlatformProtocol, + HostBridgeHandle, + RootBridgeHandle, + RootBridgePciAddress, + Phase, + ExecPhase + ); + } else if (mPciOverrideProtocol !=3D NULL) { + // + // Call PlatformPci::PrepController() if the protocol is present. + // + Status =3D mPciOverrideProtocol->PlatformPrepController ( + mPciOverrideProtocol, + HostBridgeHandle, + RootBridgeHandle, + RootBridgePciAddress, + Phase, + ExecPhase + ); + } else { + // + // return PCI Platform Protocol not found + // + return EFI_NOT_FOUND; + } + } + return Status; +} + +/** + This function notifies the PCI Platform driver about the PCI host bridge= resource + allocation phase and PCI execution phase. + + @param[in] HostBridge The handle of the host bridge controller. + @param[in] Phase The phase of the PCI bus enumeration. + @param[in] ExecPhase Defines the execution phase of the PCI chipse= t driver. + @retval Status returns the status from the PCI Platform pro= tocol as is + +**/ +EFI_STATUS +PciPlatformNotifyPhase ( + IN EFI_HANDLE HostBridgeHandle, + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase, + IN EFI_PCI_EXECUTION_PHASE ExecPhase + ) +{ + EFI_STATUS Status; + + if ( mPciPlatformProtocol2 !=3D NULL) { + Status =3D mPciPlatformProtocol2->PlatformNotify ( + (EFI_PCI_PLATFORM_PROTOCOL*)mPciPlat= formProtocol2, + HostBridgeHandle, + Phase, + ExecPhase + ); + } else if ( mPciOverrideProtocol2 !=3D NULL) { + Status =3D mPciOverrideProtocol2->PlatformNotify ( + (EFI_PCI_PLATFORM_PROTOCOL*)mPciOver= rideProtocol2, + HostBridgeHandle, + Phase, + ExecPhase + ); + } else { + + if ( mPciPlatformProtocol !=3D NULL) { + Status =3D mPciPlatformProtocol->PlatformNotify ( + mPciPlatformProtocol, + HostBridgeHandle, + Phase, + ExecPhase + ); + } else if ( mPciOverrideProtocol !=3D NULL){ + Status =3D mPciOverrideProtocol->PlatformNotify ( + mPciOverrideProtocol, + HostBridgeHandle, + Phase, + ExecPhase + ); + } else { + // + // return PCI Platform Protocol not found + // + return EFI_NOT_FOUND; + } + } + return Status; +} + +/** + This function retrieves the PCI platform policy. + + @param PciPolicy pointer to the legacy EFI_PCI_PLATFORM_POLICY + @retval Status returns the status from the PCI Platform protocol = as is + +**/ +EFI_STATUS +PciGetPlatformPolicy ( + OUT EFI_PCI_PLATFORM_POLICY *PciPolicy + ) +{ + EFI_STATUS Status; + + if ( mPciPlatformProtocol2 !=3D NULL) { + Status =3D mPciPlatformProtocol2->GetPlatformPolicy ( + (EFI_PCI_PLATFORM_PROTOCOL*)mPciPl= atformProtocol2, + PciPolicy + ); + } else if ( mPciOverrideProtocol2 !=3D NULL) { + Status =3D mPciOverrideProtocol2->GetPlatformPolicy ( + (EFI_PCI_PLATFORM_PROTOCOL*)mPciOv= errideProtocol2, + PciPolicy + ); + } else { + if ( mPciPlatformProtocol !=3D NULL) { + Status =3D mPciPlatformProtocol->GetPlatformPolicy ( + mPciPlatformProtocol, + PciPolicy + ); + } + + if ( mPciOverrideProtocol !=3D NULL) { + Status =3D mPciOverrideProtocol->GetPlatformPolicy ( + mPciOverrideProtocol, + PciPolicy + ); + } else { + // + // return PCI Platform Protocol not found + // + return EFI_NOT_FOUND; + } + } + return Status; +} + +/** + This function retrieves the Option ROM image and size from the Platform. + + It uses the PCI_IO_DEVICE internal fields are used to store OpROM image/= size + + @param Controller An EFI handle for the PCI bus controller. + @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be= registered. + + @retval EFI_SUCCESS The option ROM was available for this dev= ice and loaded into memory. + @retval EFI_NOT_FOUND No option ROM was available for this devi= ce. + @retval EFI_OUT_OF_RESOURCES No memory was available to load the optio= n ROM. + @retval EFI_DEVICE_ERROR An error occurred in obtaining the option= ROM. + +**/ +EFI_STATUS +GetPlatformPciOptionRom ( + IN EFI_HANDLE Controller, + IN PCI_IO_DEVICE *PciIoDevice + ) +{ + EFI_STATUS Status; + VOID *PlatformOpRomBuffer; + UINTN PlatformOpRomSize; + + if (mPciPlatformProtocol2 !=3D NULL) { + Status =3D mPciPlatformProtocol2->GetPciRom ( + (EFI_PCI_PLATFORM_PROTOCOL*)mPciPlat= formProtocol2, + PciIoDevice->Handle, + &PlatformOpRomBuffer, + &PlatformOpRomSize + ); + } else if (mPciOverrideProtocol2 !=3D NULL) { + Status =3D mPciOverrideProtocol2->GetPciRom ( + (EFI_PCI_PLATFORM_PROTOCOL*)mPciOver= rideProtocol2, + PciIoDevice->Handle, + &PlatformOpRomBuffer, + &PlatformOpRomSize + ); + } else { + if (mPciPlatformProtocol !=3D NULL) { + Status =3D mPciPlatformProtocol->GetPciRom ( + mPciPlatformProtocol, + PciIoDevice->Handle, + &PlatformOpRomBuffer, + &PlatformOpRomSize + ); + } else if (mPciOverrideProtocol !=3D NULL) { + Status =3D mPciOverrideProtocol->GetPciRom ( + mPciOverrideProtocol, + PciIoDevice->Handle, + &PlatformOpRomBuffer, + &PlatformOpRomSize + ); + } else { + // + // return PCI Platform Protocol not found + // + return EFI_NOT_FOUND; + } + } + + if (!EFI_ERROR (Status)) { + PciIoDevice->EmbeddedRom =3D FALSE; + PciIoDevice->RomSize =3D (UINT32)PlatformOpRomSize; + PciIoDevice->PciIo.RomSize =3D PlatformOpRomSize; + PciIoDevice->PciIo.RomImage =3D PlatformOpRomBuffer; + } + return Status; +} + +/** + Helper routine to indicate whether the given PCI device specific policy = value + dictates to override the Max_Payload_Size to a particular value, or set = as per + device capability. + + @param MPS Input device-specific policy should be in terms of type + EFI_PCI_CONF_MAX_PAYLOAD_SIZE + + @retval TRUE Setup Max_Payload_Size as per device capability + FALSE override as per device-specific platform policy +**/ +BOOLEAN +SetupMpsAsPerDeviceCapability ( + IN UINT8 MPS +) +{ + if ( MPS =3D=3D EFI_PCI_CONF_MAX_PAYLOAD_SIZE_AUTO) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Helper routine to indicate whether the given PCI device specific policy = value + dictates to override the Max_Read_Req_Size to a particular value, or set= as per + device capability. + + @param MRRS Input device-specific policy should be in terms of type + EFI_PCI_CONF_MAX_READ_REQ_SIZE + + @retval TRUE Setup Max_Read_Req_Size as per device capability + FALSE override as per device-specific platform policy +**/ +BOOLEAN +SetupMrrsAsPerDeviceCapability ( + IN UINT8 MRRS +) +{ + if ( MRRS =3D=3D EFI_PCI_CONF_MAX_READ_REQ_SIZE_AUTO) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Routine to translate the given device-specific platform policy from type + EFI_PCI_CONF_MAX_PAYLOAD_SIZE to HW-specific value, as per PCI Base Spec= ification + Revision 4.0; for the PCI feature Max_Payload_Size. + + @param MPS Input device-specific policy should be in terms of type + EFI_PCI_CONF_MAX_PAYLOAD_SIZE + + @retval Range values for the Max_Payload_Size as defined in the = PCI + Base Specification 4.0 +**/ +UINT8 +TranslateMpsSetupValueToPci ( + IN UINT8 MPS +) +{ + switch (MPS) { + case EFI_PCI_CONF_MAX_PAYLOAD_SIZE_128B: + return PCIE_MAX_PAYLOAD_SIZE_128B; + case EFI_PCI_CONF_MAX_PAYLOAD_SIZE_256B: + return PCIE_MAX_PAYLOAD_SIZE_256B; + case EFI_PCI_CONF_MAX_PAYLOAD_SIZE_512B: + return PCIE_MAX_PAYLOAD_SIZE_512B; + case EFI_PCI_CONF_MAX_PAYLOAD_SIZE_1024B: + return PCIE_MAX_PAYLOAD_SIZE_1024B; + case EFI_PCI_CONF_MAX_PAYLOAD_SIZE_2048B: + return PCIE_MAX_PAYLOAD_SIZE_2048B; + case EFI_PCI_CONF_MAX_PAYLOAD_SIZE_4096B: + return PCIE_MAX_PAYLOAD_SIZE_4096B; + default: + return PCIE_MAX_PAYLOAD_SIZE_128B; + } +} + +/** + Routine to translate the given device-specific platform policy from type + EFI_PCI_CONF_MAX_READ_REQ_SIZE to HW-specific value, as per PCI Base Spe= cification + Revision 4.0; for the PCI feature Max_Read_Req_Size. + + @param MRRS Input device-specific policy should be in terms of type + EFI_PCI_CONF_MAX_READ_REQ_SIZE + + @retval Range values for the Max_Read_Req_Size as defined in the= PCI + Base Specification 4.0 +**/ +UINT8 +TranslateMrrsSetupValueToPci ( + IN UINT8 MRRS +) +{ + switch (MRRS) { + case EFI_PCI_CONF_MAX_READ_REQ_SIZE_128B: + return PCIE_MAX_READ_REQ_SIZE_128B; + case EFI_PCI_CONF_MAX_READ_REQ_SIZE_256B: + return PCIE_MAX_READ_REQ_SIZE_256B; + case EFI_PCI_CONF_MAX_READ_REQ_SIZE_512B: + return PCIE_MAX_READ_REQ_SIZE_512B; + case EFI_PCI_CONF_MAX_READ_REQ_SIZE_1024B: + return PCIE_MAX_READ_REQ_SIZE_1024B; + case EFI_PCI_CONF_MAX_READ_REQ_SIZE_2048B: + return PCIE_MAX_READ_REQ_SIZE_2048B; + case EFI_PCI_CONF_MAX_READ_REQ_SIZE_4096B: + return PCIE_MAX_READ_REQ_SIZE_4096B; + default: + return PCIE_MAX_READ_REQ_SIZE_128B; + } +} + +/** + Generic routine to setup the PCI features as per its predetermined defau= lts. +**/ +VOID +SetupDefaultsDevicePlatformPolicy ( + IN PCI_IO_DEVICE *PciDevice + ) +{ + PciDevice->SetupMPS =3D EFI_PCI_CONF_MAX_PAYLOAD_SIZE_AUTO; + PciDevice->SetupMRRS =3D EFI_PCI_CONF_MAX_READ_REQ_SIZE_AUTO; +} + +/** + Intermediate routine to either get the PCI device specific platform poli= cies + through the PCI Platform Protocol, or its alias the PCI Override Protoco= l. + + @param PciIoDevice A pointer to PCI_IO_DEVICE + @param PciPlatformProtocol A pointer to EFI_PCI_PLATFORM_PROTOCOL2 + + @retval EFI_STATUS The direct status from the PCI Platform Prot= ocol + @retval EFI_SUCCESS if on returning predetermined PCI features d= efaults, + for the case when protocol returns as EFI_UN= SUPPORTED + to indicate PCI device exist and it has no p= latform + policy defined. +**/ +EFI_STATUS +GetPciDevicePlatformPolicyEx ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_PCI_PLATFORM_PROTOCOL2 *PciPlatformProtocol + ) +{ + EFI_PCI_PLATFORM_EXTENDED_POLICY PciPlatformExtendedPolicy; + EFI_STATUS Status; + + ZeroMem ( &PciPlatformExtendedPolicy, sizeof (EFI_PCI_PLATFORM_EXTENDED_= POLICY)); + Status =3D PciPlatformProtocol->GetDevicePolicy ( + PciPlatformProtocol, + PciIoDevice->Handle, + &PciPlatformExtendedPolicy + ); + // + // platform chipset policies are returned for this PCI device + // + if (!EFI_ERROR(Status)) { + PciIoDevice->SetupMPS =3D PciPlatformExtendedPolicy.DeviceCtlMPS; + PciIoDevice->SetupMRRS =3D PciPlatformExtendedPolicy.DeviceCtlMRRS; + } + // + // platform chipset policies are not provided for this PCI device + // + if (EFI_ERROR(Status) =3D=3D EFI_UNSUPPORTED) { + // + // let the enumeration happen as per the PCI standard way + // + SetupDefaultsDevicePlatformPolicy ( PciIoDevice); + return EFI_SUCCESS; + } + + return Status; +} + +/** + Gets the PCI device-specific platform policy from the PCI Platform Proto= col. + If no PCI Platform protocol is published than setup the PCI feature to p= redetermined + 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 p= olicy + defined. Also, on returns when no PCI Platform Pro= tocol + exist. +**/ +EFI_STATUS +GetPciDevicePlatformPolicy ( + IN PCI_IO_DEVICE *PciDevice + ) +{ + if ( mPciPlatformProtocol2 !=3D NULL) { + return GetPciDevicePlatformPolicyEx ( PciDevice, mPciPlatformProtocol2= ); + } else if (mPciOverrideProtocol2 !=3D NULL) { + return GetPciDevicePlatformPolicyEx ( PciDevice, mPciOverrideProtocol2= ); + } else { + // + // new PCI Platform Protocol 2 is not installed; let the enumeration h= appen + // as per PCI standard way + // + SetupDefaultsDevicePlatformPolicy ( PciDevice); + return EFI_SUCCESS; + } +} diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h b/MdeModul= ePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h new file mode 100644 index 0000000000..d54e46b950 --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h @@ -0,0 +1,193 @@ +/** @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) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _EFI_PCI_PLATFORM_SUPPORT_H_ +#define _EFI_PCI_PLATFORM_SUPPORT_H_ + +#include "PciBus.h" + +/** + This function retrieves the PCI Platform Protocol published by platform = driver + +**/ +VOID +GetPciPlatformProtocol ( + ); + +/** + This function indicates the presence of PCI Platform driver + @retval TRUE or FALSE +**/ +BOOLEAN +CheckPciPlatformProtocolInstall ( + ); + + +/** + Provides the hooks from the PCI bus driver to every PCI controller (devi= ce/function) at various + stages of the PCI enumeration process that allow the host bridge driver = to preinitialize individual + PCI controllers before enumeration. + + This function is called during the PCI enumeration process. No specific = action is expected from this + member function. It allows the host bridge driver to preinitialize indiv= idual PCI controllers before + enumeration. + + @param[in] HostBridgeHandle The associated PCI host bridge handle. + @param[in] RootBridgeHandle The associated PCI root bridge handle. + @param[in] RootBridgePciAddress The address of the PCI device on the PCI= bus. + @param[in] Phase The phase of the PCI controller enumeration. + @param[in] ExecPhase Defines the execution phase of the PCI chipset= driver. + + @retval Status returns the status from the PCI Platform proto= col as is + +**/ +EFI_STATUS +PciPlatformPreprocessController ( + IN EFI_HANDLE HostBridgeHandle, + IN EFI_HANDLE RootBridgeHandle, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS RootBridgePciAddress, + IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase, + IN EFI_PCI_EXECUTION_PHASE ExecPhase + ); + +/** + This function notifies the PCI Platform driver about the PCI host bridge= resource + allocation phase and PCI execution phase. + + @param[in] HostBridge The handle of the host bridge controller. + @param[in] Phase The phase of the PCI bus enumeration. + @param[in] ExecPhase Defines the execution phase of the PCI chipse= t driver. + @retval Status returns the status from the PCI Platform pro= tocol as is + +**/ +EFI_STATUS +PciPlatformNotifyPhase ( + IN EFI_HANDLE HostBridgeHandle, + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase, + IN EFI_PCI_EXECUTION_PHASE ExecPhase + ); + +/** + This function retrieves the PCI platform policy. + + @param PciPolicy pointer to the legacy EFI_PCI_PLATFORM_POLICY + @retval Status returns the status from the PCI Platform protocol = as is + +**/ +EFI_STATUS +PciGetPlatformPolicy ( + OUT EFI_PCI_PLATFORM_POLICY *PciPolicy + ); + +/** + This function retrieves the Option ROM image and size from the Platform. + + It uses the PCI_IO_DEVICE internal fields are used to store OpROM image/= size + + @param Controller An EFI handle for the PCI bus controller. + @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be= registered. + + @retval EFI_SUCCESS The option ROM was available for this dev= ice and loaded into memory. + @retval EFI_NOT_FOUND No option ROM was available for this devi= ce. + @retval EFI_OUT_OF_RESOURCES No memory was available to load the optio= n ROM. + @retval EFI_DEVICE_ERROR An error occurred in obtaining the option= ROM. + +**/ +EFI_STATUS +GetPlatformPciOptionRom ( + IN EFI_HANDLE Controller, + IN PCI_IO_DEVICE *PciIoDevice + ); + +/** + Gets the PCI device-specific platform policy from the PCI Platform Proto= col. + If no PCI Platform protocol is published than setup the PCI feature to p= redetermined + 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 p= olicy + defined. Also, on returns when no PCI Platform Pro= tocol + exist. +**/ +EFI_STATUS +GetPciDevicePlatformPolicy ( + IN PCI_IO_DEVICE *PciDevice + ); + +/** + Helper routine to indicate whether the given PCI device specific policy = value + dictates to override the Max_Payload_Size to a particular value, or set = as per + device capability. + + @param MPS Input device-specific policy should be in terms of type + EFI_PCI_CONF_MAX_PAYLOAD_SIZE + + @retval TRUE Setup Max_Payload_Size as per device capability + FALSE override as per device-specific platform policy +**/ +BOOLEAN +SetupMpsAsPerDeviceCapability ( + IN UINT8 MPS +); + +/** + Helper routine to indicate whether the given PCI device specific policy = value + dictates to override the Max_Read_Req_Size to a particular value, or set= as per + device capability. + + @param MRRS Input device-specific policy should be in terms of type + EFI_PCI_CONF_MAX_READ_REQ_SIZE + + @retval TRUE Setup Max_Read_Req_Size as per device capability + FALSE override as per device-specific platform policy +**/ +BOOLEAN +SetupMrrsAsPerDeviceCapability ( + IN UINT8 MRRS +); + +/** + Routine to translate the given device-specific platform policy from type + EFI_PCI_CONF_MAX_PAYLOAD_SIZE to HW-specific value, as per PCI Base Spec= ification + Revision 4.0; for the PCI feature Max_Payload_Size. + + @param MPS Input device-specific policy should be in terms of type + EFI_PCI_CONF_MAX_PAYLOAD_SIZE + + @retval Range values for the Max_Payload_Size as defined in the = PCI + Base Specification 4.0 +**/ +UINT8 +TranslateMpsSetupValueToPci ( + IN UINT8 MPS +); + +/** + Routine to translate the given device-specific platform policy from type + EFI_PCI_CONF_MAX_READ_REQ_SIZE to HW-specific value, as per PCI Base Spe= cification + Revision 4.0; for the PCI feature Max_Read_Req_Size. + + @param MRRS Input device-specific policy should be in terms of type + EFI_PCI_CONF_MAX_READ_REQ_SIZE + + @retval Range values for the Max_Read_Req_Size as defined in the= PCI + Base Specification 4.0 +**/ +UINT8 +TranslateMrrsSetupValueToPci ( + IN UINT8 MRRS +); +#endif diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c b/MdeModul= ePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c index 4969ee0f64..755423f77b 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c @@ -198,20 +198,7 @@ CalculateApertureIo16 ( // Status =3D EFI_NOT_FOUND; PciPolicy =3D 0; - if (gPciPlatformProtocol !=3D NULL) { - Status =3D gPciPlatformProtocol->GetPlatformPolicy ( - gPciPlatformProtocol, - &PciPolicy - ); - } - - if (EFI_ERROR (Status) && gPciOverrideProtocol !=3D NULL) { - Status =3D gPciOverrideProtocol->GetPlatformPolicy ( - gPciOverrideProtocol, - &PciPolicy - ); - } - + Status =3D PciGetPlatformPolicy ( &PciPolicy); if (!EFI_ERROR (Status)) { if ((PciPolicy & EFI_RESERVE_ISA_IO_ALIAS) !=3D 0) { mReserveIsaAliases =3D TRUE; diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 17beb45235..7bcbe5a3ea 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -1026,6 +1026,16 @@ # @Prompt Enable UEFI Stack Guard. gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard|FALSE|BOOLEAN|0x30001055 =20 + ## This PCD is to indicate the PCI Bus driver to setup other new PCI fea= tures. + # Each PCI feature is represented by its mask bit position and it confi= gures + # if that bit is set. + # + # Bit 0 - if set, the PCI Bus driver programs the device's Max_Payload= _Size.
+ # Bit 1 - if set, the PCI Bus driver programs the device's Max_Read_Re= q_Size.
+ # Bit 2 to 31 - Reserved for future use by the PCI Bus driver.
+ # @Prompt The UEFI PCU Bus driver enables the new set of other PCI Featu= res. + gEfiMdeModulePkgTokenSpaceGuid.PcdOtherPciFeatures|0x00000003|UINT32|0x3= 0001056 + [PcdsFixedAtBuild, PcdsPatchableInModule] ## Dynamic type PCD can be registered callback function for Pcd setting = action. # PcdMaxPeiPcdCallBackNumberPerPcdEntry indicates the maximum number of= callback function --=20 2.21.0.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#47851): https://edk2.groups.io/g/devel/message/47851 Mute This Topic: https://groups.io/mt/34264504/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-