mirror of
https://github.com/tianocore/edk2
synced 2026-08-27 00:23:19 -04:00
MdeModulePkg/PciBusDxe: Add optional CRS retry for enumeration
The current PciDevicePresent() implementation skips PCIe devices that return Configuration Request Retry Status (CRS) during enumeration. This causes devices that are slow to initialize (e.g., after power-on or reset) to be missed entirely. Per PCIe Base Specification Rev 3.1 Section 2.3.1, when CRS Software Visibility is enabled and a device returns CRS, the Root Complex reports Vendor ID as 0x0001. The specification recommends software retry the configuration read until the device becomes ready. This patch adds optional CRS retry support controlled by PCDs: - PcdPciCrsRetryIntervalUs: Retry interval in microseconds (default 10000) - PcdPciCrsTimeoutSeconds: Total timeout in seconds (default 0) By default (PcdPciCrsTimeoutSeconds=0), CRS retry is disabled and devices returning CRS are skipped during enumeration. Platforms requiring CRS retry support should set PcdPciCrsTimeoutSeconds to a non-zero value. Additional improvements: - Add PCI_VENDOR_ID_NONE and PCI_VENDOR_ID_CRS macros for readability - Handle invalid PCD configurations (e.g., zero retry interval) - Add DEBUG output for CRS detection, successful retry, and timeout Signed-off-by: Ashish Singhal <ashishsingha@nvidia.com>
This commit is contained in:
parent
ddcd0fd167
commit
b074eb78b4
3 changed files with 162 additions and 11 deletions
|
|
@ -2,6 +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) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.<BR>
|
||||
# Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
|
@ -97,6 +98,8 @@
|
|||
gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration ## SOMETIMES_CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdPcieResizableBarSupport ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdPcieResizableBarMaxSize ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdPciCrsRetryIntervalUs ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdPciCrsTimeoutSeconds ## CONSUMES
|
||||
|
||||
[UserExtensions.TianoCore."ExtraFiles"]
|
||||
PciBusDxeExtra.uni
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/** @file
|
||||
PCI emumeration support functions implementation for PCI Bus module.
|
||||
|
||||
Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.<BR>
|
||||
Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
|
||||
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
|
||||
Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
|
||||
|
|
@ -18,6 +19,18 @@ extern EDKII_DEVICE_SECURITY_PROTOCOL *mDeviceSecurityProtocol;
|
|||
#define SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL
|
||||
#define DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL
|
||||
|
||||
//
|
||||
// Microseconds per second/millisecond for time conversions
|
||||
//
|
||||
#define MICROSECONDS_PER_SECOND 1000000
|
||||
#define MICROSECONDS_PER_MILLISECOND 1000
|
||||
|
||||
//
|
||||
// Special PCI Vendor ID values per PCIe Base Specification
|
||||
//
|
||||
#define PCI_VENDOR_ID_NONE 0xFFFF // No device present
|
||||
#define PCI_VENDOR_ID_CRS 0x0001 // Configuration Request Retry Status
|
||||
|
||||
/**
|
||||
This routine is used to check whether the pci device is present.
|
||||
|
||||
|
|
@ -42,6 +55,27 @@ PciDevicePresent (
|
|||
{
|
||||
UINT64 Address;
|
||||
EFI_STATUS Status;
|
||||
UINTN CrsRetryCount;
|
||||
UINTN CrsRetryIntervalUs;
|
||||
UINTN CrsTimeoutSeconds;
|
||||
UINTN CrsMaxRetries;
|
||||
|
||||
//
|
||||
// Get CRS retry parameters from PCDs
|
||||
//
|
||||
CrsRetryIntervalUs = PcdGet32 (PcdPciCrsRetryIntervalUs);
|
||||
CrsTimeoutSeconds = PcdGet32 (PcdPciCrsTimeoutSeconds);
|
||||
|
||||
//
|
||||
// Calculate max retries. CRS retry is disabled if:
|
||||
// - PcdPciCrsTimeoutSeconds is 0 (default)
|
||||
// - PcdPciCrsRetryIntervalUs is 0 (avoid division by zero)
|
||||
//
|
||||
if ((CrsTimeoutSeconds == 0) || (CrsRetryIntervalUs == 0)) {
|
||||
CrsMaxRetries = 0;
|
||||
} else {
|
||||
CrsMaxRetries = (CrsTimeoutSeconds * MICROSECONDS_PER_SECOND) / CrsRetryIntervalUs;
|
||||
}
|
||||
|
||||
//
|
||||
// Create PCI address map in terms of Bus, Device and Func
|
||||
|
|
@ -59,17 +93,97 @@ PciDevicePresent (
|
|||
Pci
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
//
|
||||
// The host bridge may be programmed to accept Configuration Retry Status (CRS). If the PCI device
|
||||
// is slow, and CRS is enabled, the VendorId may read as 0x0001 when not ready.
|
||||
// This behavior is defined in PCI spec that VendorId is 0x0001.
|
||||
// PCI EXPRESS BASE SPECIFICATION, REV. 3.1 section 2.3.1.
|
||||
// Skip the device, as all the other data read will be invalid.
|
||||
// Check for valid device (not absent and not CRS)
|
||||
//
|
||||
if (!EFI_ERROR (Status)) {
|
||||
if (((Pci->Hdr).VendorId != 0xffff) && ((Pci->Hdr).VendorId != 0x0001)) {
|
||||
if (((Pci->Hdr).VendorId != PCI_VENDOR_ID_NONE) && ((Pci->Hdr).VendorId != PCI_VENDOR_ID_CRS)) {
|
||||
//
|
||||
// Valid device found - read the entire config header
|
||||
//
|
||||
Status = PciRootBridgeIo->Pci.Read (
|
||||
PciRootBridgeIo,
|
||||
EfiPciWidthUint32,
|
||||
Address,
|
||||
sizeof (PCI_TYPE00) / sizeof (UINT32),
|
||||
Pci
|
||||
);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Check for no device present
|
||||
//
|
||||
if ((Pci->Hdr).VendorId == PCI_VENDOR_ID_NONE) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
//
|
||||
// CRS detected (Vendor ID = PCI_VENDOR_ID_CRS)
|
||||
// The host bridge may be programmed to accept Configuration Retry Status (CRS).
|
||||
// If the PCI device is slow, and CRS is enabled, the VendorId reads as PCI_VENDOR_ID_CRS.
|
||||
// This behavior is defined in PCI EXPRESS BASE SPECIFICATION, REV. 3.1 section 2.3.1.
|
||||
//
|
||||
|
||||
//
|
||||
// If CRS retry is disabled, skip the device
|
||||
//
|
||||
if (CrsMaxRetries == 0) {
|
||||
DEBUG ((
|
||||
DEBUG_WARN,
|
||||
"PCI %02x:%02x.%x returned CRS but retry is disabled (PcdPciCrsTimeoutSeconds=%d, PcdPciCrsRetryIntervalUs=%d)\n",
|
||||
Bus,
|
||||
Device,
|
||||
Func,
|
||||
CrsTimeoutSeconds,
|
||||
CrsRetryIntervalUs
|
||||
));
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
//
|
||||
// CRS retry is enabled - wait for device to become ready
|
||||
//
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"PCI %02x:%02x.%x returned CRS, waiting for device ready (timeout %d s)...\n",
|
||||
Bus,
|
||||
Device,
|
||||
Func,
|
||||
CrsTimeoutSeconds
|
||||
));
|
||||
|
||||
for (CrsRetryCount = 1; CrsRetryCount <= CrsMaxRetries; CrsRetryCount++) {
|
||||
//
|
||||
// Stall before retry
|
||||
//
|
||||
gBS->Stall (CrsRetryIntervalUs);
|
||||
|
||||
//
|
||||
// Re-read the Vendor ID register
|
||||
//
|
||||
Status = PciRootBridgeIo->Pci.Read (
|
||||
PciRootBridgeIo,
|
||||
EfiPciWidthUint32,
|
||||
Address,
|
||||
1,
|
||||
Pci
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
//
|
||||
// Check if device is now ready (no longer returning CRS)
|
||||
//
|
||||
if ((Pci->Hdr).VendorId != PCI_VENDOR_ID_CRS) {
|
||||
//
|
||||
// Read the entire config header for the device
|
||||
// Valid device found - read the entire config header
|
||||
//
|
||||
Status = PciRootBridgeIo->Pci.Read (
|
||||
PciRootBridgeIo,
|
||||
|
|
@ -79,12 +193,32 @@ PciDevicePresent (
|
|||
Pci
|
||||
);
|
||||
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"PCI %02x:%02x.%x ready after %d CRS retries (%d ms)\n",
|
||||
Bus,
|
||||
Device,
|
||||
Func,
|
||||
CrsRetryCount,
|
||||
(CrsRetryCount * CrsRetryIntervalUs) / MICROSECONDS_PER_MILLISECOND
|
||||
));
|
||||
|
||||
return EFI_SUCCESS;
|
||||
} else if ((Pci->Hdr).VendorId == 0x0001) {
|
||||
DEBUG ((DEBUG_WARN, "CRS response detected. Devices that return a CRS response during enumeration are currently ignored\n"));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// CRS timeout - device never became ready
|
||||
//
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"PCI %02x:%02x.%x CRS timeout after %d seconds - device not ready\n",
|
||||
Bus,
|
||||
Device,
|
||||
Func,
|
||||
CrsTimeoutSeconds
|
||||
));
|
||||
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# It also provides the definitions(including PPIs/PROTOCOLs/GUIDs and library classes)
|
||||
# and libraries instances, which are used for those modules.
|
||||
#
|
||||
# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2019 - 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.<BR>
|
||||
# Copyright (c) 2007 - 2024, Intel Corporation. All rights reserved.<BR>
|
||||
# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
|
||||
# (C) Copyright 2016 - 2019 Hewlett Packard Enterprise Development LP<BR>
|
||||
|
|
@ -2325,6 +2325,20 @@
|
|||
# @Prompt Max size to accept in PCIe Resizable BAR Capability register.
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdPcieResizableBarMaxSize|43|UINT8|0x10000030
|
||||
|
||||
## PCIe Configuration Request Retry Status (CRS) retry interval in microseconds.
|
||||
# When a PCIe device returns CRS during enumeration, the PCI bus driver will wait
|
||||
# this interval before retrying. Default is 10000us (10ms) to match Linux kernel.
|
||||
# If set to 0, CRS retry is disabled regardless of PcdPciCrsTimeoutSeconds.
|
||||
# @Prompt PCI CRS retry interval in microseconds.
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdPciCrsRetryIntervalUs|10000|UINT32|0x1000002A
|
||||
|
||||
## PCIe Configuration Request Retry Status (CRS) timeout in seconds.
|
||||
# Maximum time to wait for a device returning CRS to become ready.
|
||||
# When set to 0 (default), devices returning CRS are skipped during enumeration.
|
||||
# Platforms requiring CRS retry support should set a non-zero value.
|
||||
# @Prompt PCI CRS timeout in seconds.
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdPciCrsTimeoutSeconds|0|UINT32|0x1000002B
|
||||
|
||||
[PcdsPatchableInModule]
|
||||
## Specify memory size with page number for PEI code when
|
||||
# Loading Module at Fixed Address feature is enabled.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue