From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga18.intel.com (mga18.intel.com []) by mx.groups.io with SMTP id smtpd.web09.10529.1581105978095314348 for ; Fri, 07 Feb 2020 12:06:24 -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 orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 12:06:24 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="225644272" 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:21 -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 07/12] PciBusDxe: New PCI Express feature Completion Timeout Date: Sat, 8 Feb 2020 01:34:42 +0530 Message-Id: <20200207200447.10536-8-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=2313 The code changes are made; as per the PCI Express Base Specification 4 Revision 1; to enable the configuration of PCI Express feature Completion Timeout (CTO), that enables the PCI function to wait on programmed dura- tion for its transactions before timeout, or disable its detection mecha- nism. The code changes are made to configure only those PCI devices which are requested by platform for override through the new PCI Express Platform protocol interface for device-specific policies. The changes are made to also comply with the device-specific capability attributes. The code follows the below implementation specific rules in case the req- uested platform policy does not match with the device-specific capability attributes:- (1) if device is capable of Range A only and if platform ask for any of ranges B, C, D; than this implementation will only program the default range value for the duration of 50us to 50ms (2) if device is capable of Range B, or range B & C, or Ranges B, C & D only and if the platform ask for the Range A; than this implementation will only program the default range value for the duration of 50us to 50ms (3) if the device is capable of Range B only, or the ranges A & B; and if the platform ask for Range C, or Range D values, than this implement- ation will only program the Range B value for the duration of 65ms to 210ms (4) if the device is capable of Ranges B & C, or Ranges A, B, and C; and if the platform ask for Range D values; than this implementation will only program the Range C for the duration of 1s to 3.5s 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/PciExpressFeatures.c | 387 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.h | 35 +++++++++++++++++++++++++++++++++++ MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c | 8 +++++++- MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 561 insertions(+), 1 deletion(-) diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h index e610b52..9b03c12 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h @@ -294,6 +294,7 @@ struct _PCI_IO_DEVICE { UINT8 SetupMRRS; PCI_FEATURE_POLICY SetupRO; PCI_FEATURE_POLICY SetupNS; + PCI_FEATURE_POLICY SetupCTO; }; #define PCI_IO_DEVICE_FROM_PCI_IO_THIS(a) \ diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.c index df85366..f3f4d39 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.c @@ -521,3 +521,390 @@ ProgramNoSnoop ( return Status; } +/** + To determine the CTO Range A values + + @param CtoValue input CTO range value from 0 to 14 + @retval TRUE the given CTO value belongs to Range A + FALSE the given value does not belong to Range A +**/ +BOOLEAN +IsCtoRangeA ( + IN UINT8 CtoValue + ) +{ + switch (CtoValue) { + case PCIE_COMPLETION_TIMEOUT_50US_100US: + case PCIE_COMPLETION_TIMEOUT_1MS_10MS: + return TRUE; + } + return FALSE; +} + +/** + To determine the CTO Range B values + + @param CtoValue input CTO range value from 0 to 14 + @retval TRUE the given CTO value belongs to Range B + FALSE the given value does not belong to Range B +**/ +BOOLEAN +IsCtoRangeB ( + IN UINT8 CtoValue + ) +{ + switch (CtoValue) { + case PCIE_COMPLETION_TIMEOUT_16MS_55MS: + case PCIE_COMPLETION_TIMEOUT_65MS_210MS: + return TRUE; + } + return FALSE; +} + +/** + To determine the CTO Range C values + + @param CtoValue input CTO range value from 0 to 14 + @retval TRUE the given CTO value belongs to Range C + FALSE the given value does not belong to Range C +**/ +BOOLEAN +IsCtoRangeC ( + IN UINT8 CtoValue + ) +{ + switch (CtoValue) { + case PCIE_COMPLETION_TIMEOUT_260MS_900MS: + case PCIE_COMPLETION_TIMEOUT_1S_3_5S: + return TRUE; + } + return FALSE; +} + +/** + To determine the CTO Range D values + + @param CtoValue input CTO range value from 0 to 14 + @retval TRUE the given CTO value belongs to Range D + FALSE the given value does not belong to Range D +**/ +BOOLEAN +IsCtoRangeD ( + IN UINT8 CtoValue + ) +{ + switch (CtoValue) { + case PCIE_COMPLETION_TIMEOUT_4S_13S: + case PCIE_COMPLETION_TIMEOUT_17S_64S: + return TRUE; + } + return FALSE; +} + +/** + The main routine which setup the PCI feature Completion Timeout as per the + device-specific platform policy, as well as in complaince with the PCI Base + specification Revision 4. + + @param PciDevice A pointer to the PCI_IO_DEVICE. + + @retval EFI_SUCCESS processing of PCI feature CTO is successful. +**/ +EFI_STATUS +SetupCompletionTimeout ( + IN PCI_IO_DEVICE *PciDevice, + IN VOID *PciExFeatureConfiguration + ) +{ + PCI_REG_PCIE_DEVICE_CAPABILITY2 DeviceCap2; + UINT8 CtoRangeValue; + + if (!PciDevice->SetupCTO.Override) { + // + // No override of CTO is required for this device + // + return EFI_SUCCESS; + } + + // + // determine the CTO range values as per its device capability register + // + DeviceCap2.Uint32 = PciDevice->PciExpressCapabilityStructure.DeviceCapability2.Uint32; + if (!DeviceCap2.Bits.CompletionTimeoutRanges + && !DeviceCap2.Bits.CompletionTimeoutDisable + ) { + // + // device does not support the CTO mechanism, hence no override is applicable + // + return EFI_SUCCESS; + } + + // + // override the device CTO values if applicable + // + if (PciDevice->SetupCTO.Act) { + // + // program the CTO range values + // + if (DeviceCap2.Bits.CompletionTimeoutRanges) { + CtoRangeValue = PCIE_COMPLETION_TIMEOUT_50US_50MS; + // + // in case if the supported CTO range and the requirement from platform + // policy does not match, than the CTO range setting would be based on + // this driver's implementation specific, and its rules are as follows:- + // + // if device is capable of Range A only and if platform ask for any of + // ranges B, C, D; than this implementation will only program the default + // range value for the duration of 50us to 50ms. + // + // if device is capable of Range B, or range B & C, or Ranges B, C & D only + // and if the platform ask for the Range A; than this implementation will + // only program the default range value for the duration of 50us to 50ms. + // + // if the device is capable of Range B only, or the ranges A & B; and the + // platform ask for Range C, or Range D values, than this implementation + // will only program the Range B value for the duration of 65ms to 210ms. + // + // if the device is capable of Ranges B & C, or Ranges A, B, and C; and + // if the platform ask for Range D values; than this implementation will + // only program the Range C for the duration of 1s to 3.5s. + // + + switch (DeviceCap2.Bits.CompletionTimeoutRanges) { + case PCIE_COMPLETION_TIMEOUT_RANGE_A_SUPPORTED: + if (IsCtoRangeA (PciDevice->SetupCTO.Support)) { + CtoRangeValue = PciDevice->SetupCTO.Support; + } + // + // if device is capable of Range A only and if platform ask for any of + // ranges B, C, D; than this implementation will only program the default + // range value for the duration of 50us to 50ms. + // + if (IsCtoRangeB (PciDevice->SetupCTO.Support) + || IsCtoRangeC (PciDevice->SetupCTO.Support) + || IsCtoRangeD (PciDevice->SetupCTO.Support) + ) { + CtoRangeValue = PCIE_COMPLETION_TIMEOUT_50US_50MS; + } + break; + + case PCIE_COMPLETION_TIMEOUT_RANGE_B_SUPPORTED: + // + // if device is capable of Range B, or range B & C, or Ranges B, C & D only + // and if the platform ask for the Range A; than this implementation will + // only program the default range value for the duration of 50us to 50ms. + // + if (IsCtoRangeA (PciDevice->SetupCTO.Support)) { + CtoRangeValue = PCIE_COMPLETION_TIMEOUT_50US_50MS; + } + + if (IsCtoRangeB (PciDevice->SetupCTO.Support)) { + CtoRangeValue = PciDevice->SetupCTO.Support; + } + // + // if the device is capable of Range B only, or the ranges A & B; and the + // platform ask for Range C, or Range D values, than this implementation + // will only program the Range B value for the duration of 65ms to 210ms. + // + if (IsCtoRangeC (PciDevice->SetupCTO.Support) + || IsCtoRangeD (PciDevice->SetupCTO.Support) + ) { + CtoRangeValue = PCIE_COMPLETION_TIMEOUT_65MS_210MS; + } + break; + + case PCIE_COMPLETION_TIMEOUT_RANGE_B_C_SUPPORTED: + if (IsCtoRangeA (PciDevice->SetupCTO.Support)) { + CtoRangeValue = PCIE_COMPLETION_TIMEOUT_50US_50MS; + } + + if (IsCtoRangeB (PciDevice->SetupCTO.Support) + || IsCtoRangeC (PciDevice->SetupCTO.Support) + ) { + CtoRangeValue = PciDevice->SetupCTO.Support; + } + // + // if the device is capable of Ranges B & C, or Ranges A, B, and C; and + // if the platform ask for Range D values; than this implementation will + // only program the Range C for the duration of 1s to 3.5s. + // + if (IsCtoRangeD (PciDevice->SetupCTO.Support)) { + CtoRangeValue = PCIE_COMPLETION_TIMEOUT_1S_3_5S; + } + break; + + case PCIE_COMPLETION_TIMEOUT_RANGE_B_C_D_SUPPORTED: + if (IsCtoRangeA (PciDevice->SetupCTO.Support)) { + CtoRangeValue = PCIE_COMPLETION_TIMEOUT_50US_50MS; + } + if (IsCtoRangeB (PciDevice->SetupCTO.Support) + || IsCtoRangeC (PciDevice->SetupCTO.Support) + || IsCtoRangeD (PciDevice->SetupCTO.Support) + ) { + CtoRangeValue = PciDevice->SetupCTO.Support; + } + break; + + case PCIE_COMPLETION_TIMEOUT_RANGE_A_B_SUPPORTED: + if (IsCtoRangeA (PciDevice->SetupCTO.Support) + || IsCtoRangeB (PciDevice->SetupCTO.Support) + ) { + CtoRangeValue = PciDevice->SetupCTO.Support; + } + if (IsCtoRangeC (PciDevice->SetupCTO.Support) + || IsCtoRangeD (PciDevice->SetupCTO.Support) + ) { + CtoRangeValue = PCIE_COMPLETION_TIMEOUT_65MS_210MS; + } + break; + + case PCIE_COMPLETION_TIMEOUT_RANGE_A_B_C_SUPPORTED: + if (IsCtoRangeA (PciDevice->SetupCTO.Support) + || IsCtoRangeB (PciDevice->SetupCTO.Support) + || IsCtoRangeC (PciDevice->SetupCTO.Support) + ) { + CtoRangeValue = PciDevice->SetupCTO.Support; + } + if (IsCtoRangeD (PciDevice->SetupCTO.Support)) { + CtoRangeValue = PCIE_COMPLETION_TIMEOUT_1S_3_5S; + } + break; + + case PCIE_COMPLETION_TIMEOUT_RANGE_A_B_C_D_SUPPORTED: + if (IsCtoRangeA (PciDevice->SetupCTO.Support) + || IsCtoRangeB (PciDevice->SetupCTO.Support) + || IsCtoRangeC (PciDevice->SetupCTO.Support) + || IsCtoRangeD (PciDevice->SetupCTO.Support) + ) { + CtoRangeValue = PciDevice->SetupCTO.Support; + } + break; + + default: + DEBUG (( + DEBUG_ERROR, + "Invalid CTO range: %d\n", + DeviceCap2.Bits.CompletionTimeoutRanges + )); + return EFI_INVALID_PARAMETER; + } + + if (PciDevice->SetupCTO.Support != CtoRangeValue) { + PciDevice->SetupCTO.Support = CtoRangeValue; + } + } + DEBUG (( DEBUG_INFO, "CTO enable: %d, CTO range: 0x%x,", + PciDevice->SetupCTO.Act, + PciDevice->SetupCTO.Support + )); + } + return EFI_SUCCESS; +} + +/** + Overrides the PCI Device Control2 register Completion Timeout range; 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 +ProgramCompletionTimeout ( + IN PCI_IO_DEVICE *PciDevice, + IN VOID *PciExFeatureConfiguration + ) +{ + PCI_REG_PCIE_DEVICE_CONTROL2 DeviceCtl2; + PCI_REG_PCIE_DEVICE_CAPABILITY2 DeviceCap2; + UINT32 Offset; + EFI_STATUS Status; + EFI_TPL OldTpl; + + if (!PciDevice->SetupCTO.Override) { + // + // No override of CTO is required for this device + // + DEBUG (( DEBUG_INFO, "CTO skipped,")); + return EFI_SUCCESS; + } + + // + // to program the CTO range values, determine in its device capability register + // + DeviceCap2.Uint32 = PciDevice->PciExpressCapabilityStructure.DeviceCapability2.Uint32; + if (DeviceCap2.Bits.CompletionTimeoutRanges + || DeviceCap2.Bits.CompletionTimeoutDisable) { + // + // device supports the CTO mechanism + // + DeviceCtl2.Uint16 = 0; + Offset = PciDevice->PciExpressCapabilityOffset + + OFFSET_OF (PCI_CAPABILITY_PCIEXP, DeviceControl2); + Status = PciDevice->PciIo.Pci.Read ( + &PciDevice->PciIo, + EfiPciIoWidthUint16, + Offset, + 1, + &DeviceCtl2.Uint16 + ); + ASSERT (Status == EFI_SUCCESS); + } else { + // + // device does not support the CTO mechanism, hence no override performed + // + DEBUG (( DEBUG_INFO, "CTO n/a,")); + return EFI_SUCCESS; + } + + // + // override the device CTO values if applicable + // + if (PciDevice->SetupCTO.Act) { + // + // program the CTO range values + // + if (PciDevice->SetupCTO.Support != DeviceCtl2.Bits.CompletionTimeoutValue) { + DeviceCtl2.Bits.CompletionTimeoutValue = PciDevice->SetupCTO.Support; + } + } else { + // + // disable the CTO mechanism in device + // + DeviceCtl2.Bits.CompletionTimeoutValue = 0; + DeviceCtl2.Bits.CompletionTimeoutDisable = 1; + } + DEBUG (( DEBUG_INFO, "CTO disable: %d, CTO range: 0x%x,", + DeviceCtl2.Bits.CompletionTimeoutDisable, + DeviceCtl2.Bits.CompletionTimeoutValue + )); + + // + // 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, + &DeviceCtl2.Uint16 + ); + // + // Restore TPL to its original level + // + gBS->RestoreTPL (OldTpl); + + if (!EFI_ERROR(Status)) { + PciDevice->PciExpressCapabilityStructure.DeviceControl2.Uint16 = DeviceCtl2.Uint16; + } else { + ReportPciWriteError (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, Offset); + } + return Status; +} + diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.h index ee636ce..2ee7d4d 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.h @@ -133,4 +133,39 @@ ProgramNoSnoop ( IN VOID *PciExFeatureConfiguration ); +/** + The main routine which process the PCI feature Completion Timeout as per the + device-specific platform policy, as well as in complaince with the PCI Base + specification Revision 4. + + @param PciDevice A pointer to the PCI_IO_DEVICE. + @param PciConfigPhase for the PCI feature configuration phases: + PciExpressFeatureSetupPhase & PciExpressFeatureEntendedSetupPhase + + @retval EFI_SUCCESS processing of PCI feature CTO is successful. +**/ +EFI_STATUS +SetupCompletionTimeout ( + IN PCI_IO_DEVICE *PciDevice, + IN VOID *PciExFeatureConfiguration + ); + +/** + Overrides the PCI Device Control2 register Completion Timeout range; 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 +ProgramCompletionTimeout ( + 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 d264d13..d4459f3 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c @@ -74,7 +74,7 @@ EFI_PCI_EXPRESS_PLATFORM_POLICY mPciExpressPlatformPolicy = { // // support for PCI Express feature - Completion Timeout // - FALSE, + TRUE, // // support for PCI Express feature - Clock Power Management // @@ -119,6 +119,12 @@ PCI_EXPRESS_FEATURE_INITIALIZATION_POINT mPciExpressFeatureInitializationList[] }, { PciExpressFeatureProgramPhase, PciExpressNoSnoop, ProgramNoSnoop + }, + { + PciExpressFeatureSetupPhase, PciExpressCto, SetupCompletionTimeout + }, + { + PciExpressFeatureProgramPhase, PciExpressCto, ProgramCompletionTimeout } }; diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c index 954ce16..1afea19 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c @@ -228,6 +228,85 @@ SetDevicePolicyPciExpressNs ( } } +/** + Routine to set the device-specific policy for the PCI feature CTO value range + or disable + + @param CtoSupport value corresponding to data type EFI_PCI_EXPRESS_CTO_SUPPORT + @param PciDevice A pointer to PCI_IO_DEVICE +**/ +VOID +SetDevicePolicyPciExpressCto ( + IN EFI_PCI_EXPRESS_CTO_SUPPORT CtoSupport, + OUT PCI_IO_DEVICE *PciDevice +) +{ + // + // implementation specific rules for the usage of PCI_FEATURE_POLICY members + // exclusively for the PCI Feature CTO + // + // .Override = 0 to skip this PCI feature CTO for the PCI device + // .Override = 1 to program this CTO PCI feature + // .Act = 1 to program the CTO range as per given device policy in .Support + // .Act = 0 to disable the CTO mechanism in the PCI device, CTO set to default range + // + switch (CtoSupport) { + case EFI_PCI_EXPRESS_CTO_AUTO: + PciDevice->SetupCTO.Override = 0; + break; + case EFI_PCI_EXPRESS_CTO_DEFAULT: + PciDevice->SetupCTO.Override = 1; + PciDevice->SetupCTO.Act = 1; + PciDevice->SetupCTO.Support = PCIE_COMPLETION_TIMEOUT_50US_50MS; + break; + case EFI_PCI_EXPRESS_CTO_RANGE_A1: + PciDevice->SetupCTO.Override = 1; + PciDevice->SetupCTO.Act = 1; + PciDevice->SetupCTO.Support = PCIE_COMPLETION_TIMEOUT_50US_100US; + break; + case EFI_PCI_EXPRESS_CTO_RANGE_A2: + PciDevice->SetupCTO.Override = 1; + PciDevice->SetupCTO.Act = 1; + PciDevice->SetupCTO.Support = PCIE_COMPLETION_TIMEOUT_1MS_10MS; + break; + case EFI_PCI_EXPRESS_CTO_RANGE_B1: + PciDevice->SetupCTO.Override = 1; + PciDevice->SetupCTO.Act = 1; + PciDevice->SetupCTO.Support = PCIE_COMPLETION_TIMEOUT_16MS_55MS; + break; + case EFI_PCI_EXPRESS_CTO_RANGE_B2: + PciDevice->SetupCTO.Override = 1; + PciDevice->SetupCTO.Act = 1; + PciDevice->SetupCTO.Support = PCIE_COMPLETION_TIMEOUT_65MS_210MS; + break; + case EFI_PCI_EXPRESS_CTO_RANGE_C1: + PciDevice->SetupCTO.Override = 1; + PciDevice->SetupCTO.Act = 1; + PciDevice->SetupCTO.Support = PCIE_COMPLETION_TIMEOUT_260MS_900MS; + break; + case EFI_PCI_EXPRESS_CTO_RANGE_C2: + PciDevice->SetupCTO.Override = 1; + PciDevice->SetupCTO.Act = 1; + PciDevice->SetupCTO.Support = PCIE_COMPLETION_TIMEOUT_1S_3_5S; + break; + case EFI_PCI_EXPRESS_CTO_RANGE_D1: + PciDevice->SetupCTO.Override = 1; + PciDevice->SetupCTO.Act = 1; + PciDevice->SetupCTO.Support = PCIE_COMPLETION_TIMEOUT_4S_13S; + break; + case EFI_PCI_EXPRESS_CTO_RANGE_D2: + PciDevice->SetupCTO.Override = 1; + PciDevice->SetupCTO.Act = 1; + PciDevice->SetupCTO.Support = PCIE_COMPLETION_TIMEOUT_17S_64S; + break; + case EFI_PCI_EXPRESS_CTO_DET_DISABLE: + PciDevice->SetupCTO.Override = 1; + PciDevice->SetupCTO.Act = 0; + PciDevice->SetupCTO.Support = PCIE_COMPLETION_TIMEOUT_50US_50MS; + break; + } +} + /** Generic routine to setup the PCI features as per its predetermined defaults. **/ @@ -253,6 +332,8 @@ SetupDefaultPciExpressDevicePolicy ( PciDevice->SetupNS.Override = 0; + PciDevice->SetupCTO.Override = 0; + } /** @@ -360,6 +441,15 @@ GetPciExpressDevicePolicy ( PciDevice->SetupNS.Override = 0; } + // + // set the device specific policy for Completion Timeout (CTO) + // + if (mPciExpressPlatformPolicy.Cto) { + SetDevicePolicyPciExpressCto (PciExpressDevicePolicy.CTOsupport, PciDevice); + } else { + PciDevice->SetupCTO.Override = 0; + } + DEBUG (( DEBUG_INFO, @@ -498,6 +588,34 @@ GetPciExpressMrrs ( return EFI_PCI_EXPRESS_NOT_APPLICABLE; } +EFI_PCI_EXPRESS_CTO_SUPPORT +GetPciExpressCto ( + IN UINT8 Cto + ) +{ + switch (Cto) { + case PCIE_COMPLETION_TIMEOUT_50US_50MS: + return EFI_PCI_EXPRESS_CTO_DEFAULT; + case PCIE_COMPLETION_TIMEOUT_50US_100US: + return EFI_PCI_EXPRESS_CTO_RANGE_A1; + case PCIE_COMPLETION_TIMEOUT_1MS_10MS: + return EFI_PCI_EXPRESS_CTO_RANGE_A2; + case PCIE_COMPLETION_TIMEOUT_16MS_55MS: + return EFI_PCI_EXPRESS_CTO_RANGE_B1; + case PCIE_COMPLETION_TIMEOUT_65MS_210MS: + return EFI_PCI_EXPRESS_CTO_RANGE_B2; + case PCIE_COMPLETION_TIMEOUT_260MS_900MS: + return EFI_PCI_EXPRESS_CTO_RANGE_C1; + case PCIE_COMPLETION_TIMEOUT_1S_3_5S: + return EFI_PCI_EXPRESS_CTO_RANGE_C2; + case PCIE_COMPLETION_TIMEOUT_4S_13S: + return EFI_PCI_EXPRESS_CTO_RANGE_D1; + case PCIE_COMPLETION_TIMEOUT_17S_64S: + return EFI_PCI_EXPRESS_CTO_RANGE_D2; + } + return EFI_PCI_EXPRESS_NOT_APPLICABLE; +} + /** Notifies the platform about the current PCI Express state of the device. @@ -561,6 +679,19 @@ PciExpressPlatformNotifyDeviceState ( PciExDeviceConfiguration.DeviceCtlNoSnoop = EFI_PCI_EXPRESS_NOT_APPLICABLE; } + // + // get the device-specific state for the PCIe CTO feature + // + if (mPciExpressPlatformPolicy.Cto) { + PciExDeviceConfiguration.CTOsupport = PciDevice->PciExpressCapabilityStructure.DeviceControl2.Bits.CompletionTimeoutDisable + ? EFI_PCI_EXPRESS_CTO_DET_DISABLE + : GetPciExpressCto ( + (UINT8)PciDevice->PciExpressCapabilityStructure.DeviceControl2.Bits.CompletionTimeoutValue + ); + } else { + PciExDeviceConfiguration.CTOsupport = EFI_PCI_EXPRESS_NOT_APPLICABLE; + } + if (mPciExPlatformProtocol != NULL) { return mPciExPlatformProtocol->NotifyDeviceState ( -- 2.21.0.windows.1