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 <ashraf.javeed@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
---
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.<BR>
+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.<BR>
+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
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#54066): https://edk2.groups.io/g/devel/message/54066
Mute This Topic: https://groups.io/mt/71063076/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
© 2016 - 2024 Red Hat, Inc.