From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga03.intel.com (mga03.intel.com []) by mx.groups.io with SMTP id smtpd.web09.10525.1581105967427505892 for ; Fri, 07 Feb 2020 12:06:12 -0800 Authentication-Results: mx.groups.io; dkim=missing; spf=fail (domain: intel.com, ip: , mailfrom: ashraf.javeed@intel.com) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 12:06:11 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="225644214" Received: from unknown (HELO PIDSBABIOS005.gar.corp.intel.com) ([10.223.9.183]) by fmsmga007.fm.intel.com with ESMTP; 07 Feb 2020 12:06:09 -0800 From: "Javeed, Ashraf" To: devel@edk2.groups.io Cc: Jian J Wang , Hao A Wu , Ray Ni Subject: [edk2-staging/UEFI_PCI_ENHANCE-2 PATCH 03/12] PciBusDxe: New PCI Express feature Max_Payload_Size Date: Sat, 8 Feb 2020 01:34:38 +0530 Message-Id: <20200207200447.10536-4-ashraf.javeed@intel.com> X-Mailer: git-send-email 2.21.0.windows.1 In-Reply-To: <20200207200447.10536-1-ashraf.javeed@intel.com> References: <20200207200447.10536-1-ashraf.javeed@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2194 The code changes are made to enable the configuration of new PCI Express feature Max_Payload_Size (MPS), which defines the data packet size for the PCI transactions, as per the PCI Base Specification 4 Revision 1. The code changes are made to calibrate highest common value that is appl- icable to all the child nodes originating from the primary root bridge device instance. This programming of MPS is based on each PCI device's capability, and also its device-specific platform policy obtained using the new PCI Express Platform Protocol interface, defined in the below feature request:- https://bugzilla.tianocore.org/show_bug.cgi?id=1954 Signed-off-by: Ashraf Javeed Cc: Jian J Wang Cc: Hao A Wu Cc: Ray Ni --- MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h | 1 + MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf | 2 ++ MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.h | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c | 22 ++++++++++++++++------ MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h | 5 +++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h | 17 +++++++++++++++++ 8 files changed, 369 insertions(+), 6 deletions(-) diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h index 225229d..5dc5f61 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h @@ -287,6 +287,7 @@ struct _PCI_IO_DEVICE { // This field is used to support this case. // UINT16 BridgeIoAlignment; + UINT8 SetupMPS; }; #define PCI_IO_DEVICE_FROM_PCI_IO_THIS(a) \ diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf index f06b411..e3ad105 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf @@ -61,6 +61,8 @@ PciFeatureSupport.h PciPlatformSupport.c PciPlatformSupport.h + PciExpressFeatures.c + PciExpressFeatures.h [Packages] MdePkg/MdePkg.dec diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.c new file mode 100644 index 0000000..6084446 --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.c @@ -0,0 +1,193 @@ +/** @file + PCI standard feature support functions implementation for PCI Bus module.. + +Copyright (c) 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PciBus.h" +#include "PciFeatureSupport.h" + +VOID +ReportPciWriteError ( + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 Function, + IN UINT32 Offset + ) +{ + DEBUG (( + DEBUG_ERROR, + "Unexpected PCI register (%d,%d,%d,0x%x) write error!", + Bus, + Device, + Function, + Offset + )); +} + +/** + Compare and Swap the payload value - between the global variable to maaintain + common value among all the devices in the PCIe heirarchy from the root bridge + device and all its child devices; with the device-sepcific setup value. + + @param PciDevice A pointer to the PCI_IO_DEVICE. + @param PciExpressConfigurationTable pointer to PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE + + @retval EFI_SUCCESS processing of PCI feature Max_Payload_Size + is successful. +**/ +EFI_STATUS +CasMaxPayloadSize ( + IN PCI_IO_DEVICE *PciDevice, + IN PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE *PciExpressConfigurationTable + ) +{ + UINT8 MpsValue; + + // + // align the MPS of the tree to the HCF with this device + // + if (PciExpressConfigurationTable) { + MpsValue = PciExpressConfigurationTable->Max_Payload_Size; + + MpsValue = MIN (PciDevice->SetupMPS, MpsValue); + PciDevice->SetupMPS = MIN (PciDevice->SetupMPS, MpsValue); + + if (MpsValue != PciExpressConfigurationTable->Max_Payload_Size) { + PciExpressConfigurationTable->Max_Payload_Size = MpsValue; + } + } + + DEBUG (( + DEBUG_INFO, + "MPS: %d [DevCap:%d],", + PciDevice->SetupMPS, PciDevice->PciExpressCapabilityStructure.DeviceCapability.Bits.MaxPayloadSize + )); + + return EFI_SUCCESS; +} + +/** + The main routine which process the PCI feature Max_Payload_Size as per the + device-specific platform policy, as well as in complaince with the PCI Base + specification Revision 4, that aligns the value for the entire PCI heirarchy + starting from its physical PCI Root port / Bridge device. + + @param PciDevice A pointer to the PCI_IO_DEVICE. + @param PciExpressConfigurationTable pointer to PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE + + @retval EFI_SUCCESS processing of PCI feature Max_Payload_Size + is successful. +**/ +EFI_STATUS +SetupMaxPayloadSize ( + IN PCI_IO_DEVICE *PciDevice, + IN PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE *PciExpressConfigurationTable + ) +{ + PCI_REG_PCIE_DEVICE_CAPABILITY PciDeviceCap; + UINT8 MpsValue; + + + PciDeviceCap.Uint32 = PciDevice->PciExpressCapabilityStructure.DeviceCapability.Uint32; + + if (PciDevice->SetupMPS == EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_AUTO) { + // + // configure this feature as per its PCIe device capabilities + // + MpsValue = (UINT8)PciDeviceCap.Bits.MaxPayloadSize; + // + // no change to PCI Root ports without any endpoint device + // + if (IS_PCI_BRIDGE (&PciDevice->Pci) && PciDeviceCap.Bits.MaxPayloadSize) { + if (IsListEmpty (&PciDevice->ChildList)) { + // + // No device on root bridge + // + MpsValue = PCIE_MAX_PAYLOAD_SIZE_128B; + } + } + } else { + MpsValue = SetDevicePolicyPciExpressMps (PciDevice->SetupMPS); + } + // + // discard device policy override request if greater than PCI device capability + // + PciDevice->SetupMPS = MIN ((UINT8)PciDeviceCap.Bits.MaxPayloadSize, MpsValue); + + return CasMaxPayloadSize ( + PciDevice, + PciExpressConfigurationTable + ); +} + +/** + 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 PCI device. + @retval EFI_UNSUPPORTED The address range specified by Offset, Width, 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 +ProgramMaxPayloadSize ( + IN PCI_IO_DEVICE *PciDevice, + IN VOID *PciExFeatureConfiguration + ) +{ + PCI_REG_PCIE_DEVICE_CONTROL PcieDev; + UINT32 Offset; + EFI_STATUS Status; + EFI_TPL OldTpl; + + PcieDev.Uint16 = 0; + Offset = PciDevice->PciExpressCapabilityOffset + + OFFSET_OF (PCI_CAPABILITY_PCIEXP, DeviceControl); + Status = PciDevice->PciIo.Pci.Read ( + &PciDevice->PciIo, + EfiPciIoWidthUint16, + Offset, + 1, + &PcieDev.Uint16 + ); + ASSERT (Status == EFI_SUCCESS); + + if (PcieDev.Bits.MaxPayloadSize != PciDevice->SetupMPS) { + PcieDev.Bits.MaxPayloadSize = PciDevice->SetupMPS; + DEBUG (( DEBUG_INFO, "MPS=%d,", PciDevice->SetupMPS)); + + // + // Raise TPL to high level to disable timer interrupt while the write operation completes + // + OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + + Status = PciDevice->PciIo.Pci.Write ( + &PciDevice->PciIo, + EfiPciIoWidthUint16, + Offset, + 1, + &PcieDev.Uint16 + ); + // + // Restore TPL to its original level + // + gBS->RestoreTPL (OldTpl); + + if (!EFI_ERROR(Status)) { + PciDevice->PciExpressCapabilityStructure.DeviceControl.Uint16 = PcieDev.Uint16; + } else { + ReportPciWriteError (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, Offset); + } + } else { + DEBUG (( DEBUG_INFO, "No MPS=%d,", PciDevice->SetupMPS)); + } + + return Status; +} + diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.h new file mode 100644 index 0000000..460437b --- /dev/null +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.h @@ -0,0 +1,55 @@ +/** @file + PCI standard feature support functions implementation for PCI Bus module.. + +Copyright (c) 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_PCI_EXPRESS_FEATURES_H_ +#define _EFI_PCI_EXPRESS_FEATURES_H_ + + +/** + The main routine which process the PCI feature Max_Payload_Size as per the + device-specific platform policy, as well as in complaince with the PCI Base + specification Revision 4, that aligns the value for the entire PCI heirarchy + starting from its physical PCI Root port / Bridge device. + + @param PciDevice A pointer to the PCI_IO_DEVICE. + @param PciFeaturesConfigurationTable pointer to PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE + + @retval EFI_SUCCESS processing of PCI feature Max_Payload_Size + is successful. +**/ +EFI_STATUS +SetupMaxPayloadSize ( + IN PCI_IO_DEVICE *PciDevice, + IN PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE *PciFeaturesConfigurationTable + ); + +EFI_STATUS +CasMaxPayloadSize ( + IN PCI_IO_DEVICE *PciDevice, + IN PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE *PciFeaturesConfigurationTable + ); + +/** + Overrides the PCI Device Control register Max_Read_Req_Size 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 PCI controller. + @retval EFI_UNSUPPORTED The address range specified by Offset, Width, 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 +ProgramMaxPayloadSize ( + IN PCI_IO_DEVICE *PciDevice, + IN VOID *PciExFeatureConfiguration + ); + +#endif diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c index 3980a8e..aae6139 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c @@ -8,6 +8,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include "PciBus.h" #include "PciFeatureSupport.h" +#include "PciExpressFeatures.h" /** Hold the current instance of Root Bridge IO protocol Handle @@ -29,7 +30,7 @@ EFI_PCI_EXPRESS_PLATFORM_POLICY mPciExpressPlatformPolicy = { // // support for PCI Express feature - Max. Payload Size // - FALSE, + TRUE, // // support for PCI Express feature - Max. Read Request Size // @@ -94,11 +95,16 @@ BOOLEAN mPciExpressGetPlatformPolicyComplete = FALSE; // PCI Express feature initialization phase handle routines // PCI_EXPRESS_FEATURE_INITIALIZATION_POINT mPciExpressFeatureInitializationList[] = { - // - // vacant entry, shall be replaced with actual entry when the PCI Express - // feature are added. - // - { 0, 0, NULL} + + { + PciExpressFeatureSetupPhase, PciExpressMps, SetupMaxPayloadSize + }, + { + PciExpressFeatureEntendedSetupPhase, PciExpressMps, CasMaxPayloadSize + }, + { + PciExpressFeatureProgramPhase, PciExpressMps, ProgramMaxPayloadSize + } }; /** @@ -597,6 +603,10 @@ CreatePciRootBridgeDeviceNode ( ); if (PciConfigTable) { PciConfigTable->ID = PortNumber; + // + // start by assuming 4096B as the default value for the Max. Payload Size + // + PciConfigTable->Max_Payload_Size = PCIE_MAX_PAYLOAD_SIZE_4096B; } RootBridgeNode->PciExFeaturesConfigurationTable = PciConfigTable; diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h index 9b7e51f..4ecbefc 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.h @@ -66,6 +66,11 @@ struct _PCI_EXPRESS_FEATURES_CONFIGURATION_TABLE { // Configuration Table ID // UINTN ID; + // + // to configure the PCI feature Maximum payload size to maintain the data packet + // size among all the PCI devices in the PCI hierarchy + // + UINT8 Max_Payload_Size; }; // diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c index 31c675d..3e9d4c5 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c @@ -81,6 +81,39 @@ IsPciExpressProtocolPresent ( return TRUE; } +/** + Routine to translate the given device-specific platform policy from type + EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE to HW-specific value, as per PCI Base Specification + Revision 4.0; for the PCI feature Max_Payload_Size. + + @param MPS Input device-specific policy should be in terms of type + EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE + + @retval Range values for the Max_Payload_Size as defined in the PCI + Base Specification 4.0 +**/ +UINT8 +SetDevicePolicyPciExpressMps ( + IN UINT8 MPS +) +{ + switch (MPS) { + case EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_128B: + return PCIE_MAX_PAYLOAD_SIZE_128B; + case EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_256B: + return PCIE_MAX_PAYLOAD_SIZE_256B; + case EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_512B: + return PCIE_MAX_PAYLOAD_SIZE_512B; + case EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_1024B: + return PCIE_MAX_PAYLOAD_SIZE_1024B; + case EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_2048B: + return PCIE_MAX_PAYLOAD_SIZE_2048B; + case EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_4096B: + return PCIE_MAX_PAYLOAD_SIZE_4096B; + default: + return PCIE_MAX_PAYLOAD_SIZE_128B; + } +} /** Generic routine to setup the PCI features as per its predetermined defaults. @@ -91,6 +124,12 @@ SetupDefaultPciExpressDevicePolicy ( ) { + if (mPciExpressPlatformPolicy.Mps) { + PciDevice->SetupMPS = EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_AUTO; + } else { + PciDevice->SetupMPS = EFI_PCI_EXPRESS_NOT_APPLICABLE; + } + } /** @@ -163,6 +202,15 @@ GetPciExpressDevicePolicy ( // platform chipset policies are returned for this PCI device // + // + // set device specific policy for the Max_Payload_Size + // + if (mPciExpressPlatformPolicy.Mps) { + PciDevice->SetupMPS = PciExpressDevicePolicy.DeviceCtlMPS; + } else { + PciDevice->SetupMPS = EFI_PCI_EXPRESS_NOT_APPLICABLE; + } + DEBUG (( DEBUG_INFO, @@ -257,6 +305,28 @@ PciExpressPlatformGetPolicy ( return Status; } +EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE +GetPciExpressMps ( + IN UINT8 Mps + ) +{ + switch (Mps) { + case PCIE_MAX_PAYLOAD_SIZE_128B: + return EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_128B; + case PCIE_MAX_PAYLOAD_SIZE_256B: + return EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_256B; + case PCIE_MAX_PAYLOAD_SIZE_512B: + return EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_512B; + case PCIE_MAX_PAYLOAD_SIZE_1024B: + return EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_1024B; + case PCIE_MAX_PAYLOAD_SIZE_2048B: + return EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_2048B; + case PCIE_MAX_PAYLOAD_SIZE_4096B: + return EFI_PCI_EXPRESS_MAX_PAYLOAD_SIZE_4096B; + } + return EFI_PCI_EXPRESS_NOT_APPLICABLE; +} + /** Notifies the platform about the current PCI Express state of the device. @@ -277,6 +347,16 @@ PciExpressPlatformNotifyDeviceState ( { EFI_PCI_EXPRESS_DEVICE_CONFIGURATION PciExDeviceConfiguration; + // + // get the device-specific state for the PCIe Max_Payload_Size feature + // + if (mPciExpressPlatformPolicy.Mps) { + PciExDeviceConfiguration.DeviceCtlMPS = GetPciExpressMps ( + (UINT8)PciDevice->PciExpressCapabilityStructure.DeviceControl.Bits.MaxPayloadSize + ); + } else { + PciExDeviceConfiguration.DeviceCtlMPS = EFI_PCI_EXPRESS_NOT_APPLICABLE; + } if (mPciExPlatformProtocol != NULL) { return mPciExPlatformProtocol->NotifyDeviceState ( diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h index 4283b81..5ae6386 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.h @@ -84,4 +84,21 @@ EFI_STATUS PciExpressPlatformNotifyDeviceState ( IN PCI_IO_DEVICE *PciDevice ); + +/** + 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 Specification + 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 +SetDevicePolicyPciExpressMps ( + IN UINT8 MPS +); + #endif -- 2.21.0.windows.1