diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h index 97e816cb1e5..729170b9fce 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h @@ -284,7 +284,8 @@ struct _PCI_IO_DEVICE { UINT16 BridgeIoAlignment; UINT32 ResizableBarOffset; UINT32 ResizableBarNumber; - BOOLEAN IgnoreROM; // MS_CHANGE + BOOLEAN IgnoreROM; // MS_CHANGE + UINT8 MaxPayloadSize; // MU_CHANGE: Add support for initializing PCIe MPS }; #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 5ad3026d238..4aa804d05c6 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf @@ -112,6 +112,7 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdPcieResizableBarSupport ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdDisableBMEonEBS ## MU_CHANGE + gEfiMdeModulePkgTokenSpaceGuid.PcdPcieInitializeMps ## MU_CHANGE: Add support for initializing PCIe MPS [UserExtensions.TianoCore."ExtraFiles"] PciBusDxeExtra.uni diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c index 16c8e10b260..2b60f74f244 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c @@ -207,6 +207,161 @@ PciPciDeviceInfoCollector ( return EFI_SUCCESS; } +// MU_CHANGE BEGIN: Add support for initializing PCIe MPS + +/** + Searches a PCI device and it's children to find the optimum Max Payload Size + supported by the provided device and its children. + + @param[in] PciIoDevice The PCI IO Device to find the optimal MPS for. + @param[out] MaxPayloadSize The optimum MPS for the device and it's children. + + @retval EFI_SUCCESS Optimum MPS was found. + @retval EFI_UNSUPPORTED MPS not supported by provided device or its children. + +**/ +EFI_STATUS +PciGetMaxPayloadSize ( + IN PCI_IO_DEVICE *PciIoDevice, + OUT UINT8 *MaxPayloadSize + ) +{ + LIST_ENTRY *CurrentLink; + UINT8 ChildMps; + PCI_IO_DEVICE *Child; + EFI_STATUS Status; + + // + // Skip the root bridge. + // + + if (PciIoDevice->Parent != NULL) { + if (!PciIoDevice->IsPciExp) { + return EFI_UNSUPPORTED; + } + + *MaxPayloadSize = PciIoDevice->MaxPayloadSize; + } else { + *MaxPayloadSize = MAX_UINT8; + } + + // + // Recurse into each child to find the max payload size supported. + // + CurrentLink = PciIoDevice->ChildList.ForwardLink; + while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) { + Child = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + Status = PciGetMaxPayloadSize (Child, &ChildMps); + if (!EFI_ERROR (Status) && (ChildMps < *MaxPayloadSize)) { + *MaxPayloadSize = ChildMps; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + if (*MaxPayloadSize == MAX_UINT8) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Sets the PCIe Max PayloadSize for the provided device and it's children. + + @param[in] PciIoDevice The PCI IO Device to set the MPS for. + @param[out] MaxPayloadSize The MPS to set. + + @retval EFI_SUCCESS The MPS ws set for the device and it's children. + @retval EFI_UNSUPPORTED MPS not supported by provided device or its children. + @retval Other MPS could not be read or written. + +**/ +EFI_STATUS +PciProgramMps ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT8 MaxPayloadSize + ) +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Child; + EFI_STATUS Status; + PCI_REG_PCIE_DEVICE_CONTROL DeviceControl; + + // + // Skip the root bridge. + // + + if (PciIoDevice->Parent != NULL) { + if (!PciIoDevice->IsPciExp) { + return EFI_UNSUPPORTED; + } + + Status = PciIoDevice->PciIo.Pci.Read ( + &PciIoDevice->PciIo, + EfiPciIoWidthUint16, + PciIoDevice->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL, + 1, + &DeviceControl.Uint16 + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: Failed to read MPS for device %02x %02x %02x. %r\n", + __FUNCTION__, + PciIoDevice->BusNumber, + PciIoDevice->DeviceNumber, + PciIoDevice->FunctionNumber, + Status + )); + } else if (DeviceControl.Bits.MaxPayloadSize != MaxPayloadSize) { + DeviceControl.Bits.MaxPayloadSize = MaxPayloadSize; + DEBUG (( + DEBUG_VERBOSE, + "%a: %02x %02x %02x Setting MPS: %x\n", + __FUNCTION__, + PciIoDevice->BusNumber, + PciIoDevice->DeviceNumber, + PciIoDevice->FunctionNumber, + MaxPayloadSize + )); + + Status = PciIoDevice->PciIo.Pci.Write ( + &PciIoDevice->PciIo, + EfiPciIoWidthUint16, + PciIoDevice->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL, + 1, + &DeviceControl.Uint16 + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: Failed to set MPS for device %02x %02x %02x. %r\n", + __FUNCTION__, + PciIoDevice->BusNumber, + PciIoDevice->DeviceNumber, + PciIoDevice->FunctionNumber, + Status + )); + } + } + } + + // + // Recurse into each child to set the max payload size. + // + CurrentLink = PciIoDevice->ChildList.ForwardLink; + while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) { + Child = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + PciProgramMps (Child, MaxPayloadSize); + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_SUCCESS; +} + +// MU_CHANGE END: Add support for initializing PCIe MPS + /** Search required device and create PCI device instance. @@ -2535,6 +2690,24 @@ CreatePciIoDevice ( } } + // MU_CHANGE BEGIN: Add support for initializing PCIe MPS + // Capture the maximum payload size supported for the device. + if (PcdGetBool (PcdPcieInitializeMps) && PciIoDevice->IsPciExp) { + PCI_REG_PCIE_DEVICE_CAPABILITY DeviceCapabilities; + Status = PciIoDevice->PciIo.Pci.Read ( + &PciIoDevice->PciIo, + EfiPciIoWidthUint32, + PciIoDevice->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES, + 1, + &DeviceCapabilities.Uint32 + ); + + ASSERT (!EFI_ERROR (Status)); + PciIoDevice->MaxPayloadSize = (UINT8)DeviceCapabilities.Bits.MaxPayloadSize; + } + + // MU_CHANGE END + // // Initialize the reserved resource list // diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h index bab1fe94e0b..e8a9a4a48df 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h @@ -50,6 +50,44 @@ PciPciDeviceInfoCollector ( IN UINT8 StartBusNumber ); +// MU_CHANGE BEGIN: Add support for initializing PCIe MPS + +/** + Searches a PCI device and it's children to find the optimum Max Payload Size + supported by the provided device and its children. + + @param[in] PciIoDevice The PCI IO Device to find the optimal MPS for. + @param[out] MaxPayloadSize The optimum MPS for the device and it's children. + + @retval EFI_SUCCESS Optimum MPS was found. + @retval EFI_UNSUPPORTED MPS not supported by provided device or its children. + +**/ +EFI_STATUS +PciGetMaxPayloadSize ( + IN PCI_IO_DEVICE *PciIoDevice, + OUT UINT8 *MaxPayloadSize + ); + +/** + Sets the PCIe Max PayloadSize for the provided device and it's children. + + @param[in] PciIoDevice The PCI IO Device to set the MPS for. + @param[out] MaxPayloadSize The MPS to set. + + @retval EFI_SUCCESS The MPS ws set for the device and it's children. + @retval EFI_UNSUPPORTED MPS not supported by provided device or its children. + @retval Other MPS could not be read or written. + +**/ +EFI_STATUS +PciProgramMps ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT8 MaxPayloadSize + ); + +// MU_CHANGE END: Add support for initializing PCIe MPS + /** Search required device and create PCI device instance. diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c index 7f1266cbacc..bbe315231b6 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c @@ -1802,6 +1802,20 @@ PciHostBridgeEnumerator ( return Status; } + // MU_CHANGE BEGIN: Add support for initializing PCIe MPS + if (PcdGetBool (PcdPcieInitializeMps) && gFullEnumeration) { + UINT8 MaxPayloadSize; + Status = PciGetMaxPayloadSize (RootBridgeDev, &MaxPayloadSize); + if (!EFI_ERROR (Status)) { + Status = PciProgramMps (RootBridgeDev, MaxPayloadSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to set root bridge MPS to %x. %r\n", __FUNCTION__, MaxPayloadSize, Status)); + } + } + } + + // MU_CHANGE END: Add support for initializing PCIe MPS + InsertRootBridge (RootBridgeDev); // diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index d5ebbdf0a17..13617c0512d 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -1307,9 +1307,9 @@ # MU_CHANGE [END] # MU_CHANGE [BEGIN] - Support indefinite boot retries - # # Some platforms require that all EfiLoadOptions are retried until one of the options - # # succeeds. When True, this Pcd will force Bds to retry all the valid EfiLoadOptions - # # indefinitely until one of the options succeeds. + # # Some platforms require that all EfiLoadOptions are retried until one of the options + # # succeeds. When True, this Pcd will force Bds to retry all the valid EfiLoadOptions + # # indefinitely until one of the options succeeds. # # TRUE - Efi boot options will be retried indefinitely. # # FALSE - Efi boot options will not be retried. gEfiMdeModulePkgTokenSpaceGuid.PcdSupportInfiniteBootRetries|FALSE|BOOLEAN|0x40000152 @@ -2176,6 +2176,13 @@ # @Prompt Disable full PCI enumeration. gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration|FALSE|BOOLEAN|0x10000048 + # MU_CHANGE: Add support for initializing PCIe MPS + ## Indicates if Max Payload Size should be set for PCIe devices + # TRUE - Initialize MPS for PCI devices. + # FALSE - Leave MPS to the default value. + # @Prompt Enable initializing PCIe Max Payload Sizes. + gEfiMdeModulePkgTokenSpaceGuid.PcdPcieInitializeMps|FALSE|BOOLEAN|0x10000049 + ## Disk I/O - Number of Data Buffer block. # Define the size in block of the pre-allocated buffer. It provide better # performance for large Disk I/O requests. diff --git a/MdePkg/Include/IndustryStandard/PciExpress21.h b/MdePkg/Include/IndustryStandard/PciExpress21.h index 2f819725514..104ed32349d 100644 --- a/MdePkg/Include/IndustryStandard/PciExpress21.h +++ b/MdePkg/Include/IndustryStandard/PciExpress21.h @@ -392,6 +392,8 @@ typedef struct { } PCI_CAPABILITY_PCIEXP; #define EFI_PCIE_CAPABILITY_BASE_OFFSET 0x100 +#define EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES 0x04 // MU_CHANGE: Add support for PCIe MPS +#define EFI_PCIE_CAPABILITY_DEVICE_CONTROL 0x08 // MU_CHANGE: Add support for PCIe MPS #define EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY 0x10 #define EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET 0x24 #define EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING 0x20