Skip to content

Commit b074eb7

Browse files
ashishsinghamergify[bot]
authored andcommitted
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 <[email protected]>
1 parent ddcd0fd commit b074eb7

3 files changed

Lines changed: 162 additions & 11 deletions

File tree

MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# The PCI bus driver will probe all PCI devices and allocate MMIO and IO space for these devices.
33
# Please use PCD feature flag PcdPciBusHotplugDeviceSupport to enable hot plug supporting.
44
#
5+
# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.<BR>
56
# Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
67
#
78
# SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -97,6 +98,8 @@
9798
gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration ## SOMETIMES_CONSUMES
9899
gEfiMdeModulePkgTokenSpaceGuid.PcdPcieResizableBarSupport ## CONSUMES
99100
gEfiMdeModulePkgTokenSpaceGuid.PcdPcieResizableBarMaxSize ## CONSUMES
101+
gEfiMdeModulePkgTokenSpaceGuid.PcdPciCrsRetryIntervalUs ## CONSUMES
102+
gEfiMdeModulePkgTokenSpaceGuid.PcdPciCrsTimeoutSeconds ## CONSUMES
100103

101104
[UserExtensions.TianoCore."ExtraFiles"]
102105
PciBusDxeExtra.uni

MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c

Lines changed: 144 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/** @file
22
PCI emumeration support functions implementation for PCI Bus module.
33
4+
Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.<BR>
45
Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
56
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
67
Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
@@ -18,6 +19,18 @@ extern EDKII_DEVICE_SECURITY_PROTOCOL *mDeviceSecurityProtocol;
1819
#define SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL
1920
#define DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL
2021

22+
//
23+
// Microseconds per second/millisecond for time conversions
24+
//
25+
#define MICROSECONDS_PER_SECOND 1000000
26+
#define MICROSECONDS_PER_MILLISECOND 1000
27+
28+
//
29+
// Special PCI Vendor ID values per PCIe Base Specification
30+
//
31+
#define PCI_VENDOR_ID_NONE 0xFFFF // No device present
32+
#define PCI_VENDOR_ID_CRS 0x0001 // Configuration Request Retry Status
33+
2134
/**
2235
This routine is used to check whether the pci device is present.
2336
@@ -42,6 +55,27 @@ PciDevicePresent (
4255
{
4356
UINT64 Address;
4457
EFI_STATUS Status;
58+
UINTN CrsRetryCount;
59+
UINTN CrsRetryIntervalUs;
60+
UINTN CrsTimeoutSeconds;
61+
UINTN CrsMaxRetries;
62+
63+
//
64+
// Get CRS retry parameters from PCDs
65+
//
66+
CrsRetryIntervalUs = PcdGet32 (PcdPciCrsRetryIntervalUs);
67+
CrsTimeoutSeconds = PcdGet32 (PcdPciCrsTimeoutSeconds);
68+
69+
//
70+
// Calculate max retries. CRS retry is disabled if:
71+
// - PcdPciCrsTimeoutSeconds is 0 (default)
72+
// - PcdPciCrsRetryIntervalUs is 0 (avoid division by zero)
73+
//
74+
if ((CrsTimeoutSeconds == 0) || (CrsRetryIntervalUs == 0)) {
75+
CrsMaxRetries = 0;
76+
} else {
77+
CrsMaxRetries = (CrsTimeoutSeconds * MICROSECONDS_PER_SECOND) / CrsRetryIntervalUs;
78+
}
4579

4680
//
4781
// Create PCI address map in terms of Bus, Device and Func
@@ -59,17 +93,97 @@ PciDevicePresent (
5993
Pci
6094
);
6195

96+
if (EFI_ERROR (Status)) {
97+
return EFI_NOT_FOUND;
98+
}
99+
62100
//
63-
// The host bridge may be programmed to accept Configuration Retry Status (CRS). If the PCI device
64-
// is slow, and CRS is enabled, the VendorId may read as 0x0001 when not ready.
65-
// This behavior is defined in PCI spec that VendorId is 0x0001.
66-
// PCI EXPRESS BASE SPECIFICATION, REV. 3.1 section 2.3.1.
67-
// Skip the device, as all the other data read will be invalid.
101+
// Check for valid device (not absent and not CRS)
68102
//
69-
if (!EFI_ERROR (Status)) {
70-
if (((Pci->Hdr).VendorId != 0xffff) && ((Pci->Hdr).VendorId != 0x0001)) {
103+
if (((Pci->Hdr).VendorId != PCI_VENDOR_ID_NONE) && ((Pci->Hdr).VendorId != PCI_VENDOR_ID_CRS)) {
104+
//
105+
// Valid device found - read the entire config header
106+
//
107+
Status = PciRootBridgeIo->Pci.Read (
108+
PciRootBridgeIo,
109+
EfiPciWidthUint32,
110+
Address,
111+
sizeof (PCI_TYPE00) / sizeof (UINT32),
112+
Pci
113+
);
114+
115+
return EFI_SUCCESS;
116+
}
117+
118+
//
119+
// Check for no device present
120+
//
121+
if ((Pci->Hdr).VendorId == PCI_VENDOR_ID_NONE) {
122+
return EFI_NOT_FOUND;
123+
}
124+
125+
//
126+
// CRS detected (Vendor ID = PCI_VENDOR_ID_CRS)
127+
// The host bridge may be programmed to accept Configuration Retry Status (CRS).
128+
// If the PCI device is slow, and CRS is enabled, the VendorId reads as PCI_VENDOR_ID_CRS.
129+
// This behavior is defined in PCI EXPRESS BASE SPECIFICATION, REV. 3.1 section 2.3.1.
130+
//
131+
132+
//
133+
// If CRS retry is disabled, skip the device
134+
//
135+
if (CrsMaxRetries == 0) {
136+
DEBUG ((
137+
DEBUG_WARN,
138+
"PCI %02x:%02x.%x returned CRS but retry is disabled (PcdPciCrsTimeoutSeconds=%d, PcdPciCrsRetryIntervalUs=%d)\n",
139+
Bus,
140+
Device,
141+
Func,
142+
CrsTimeoutSeconds,
143+
CrsRetryIntervalUs
144+
));
145+
return EFI_NOT_FOUND;
146+
}
147+
148+
//
149+
// CRS retry is enabled - wait for device to become ready
150+
//
151+
DEBUG ((
152+
DEBUG_INFO,
153+
"PCI %02x:%02x.%x returned CRS, waiting for device ready (timeout %d s)...\n",
154+
Bus,
155+
Device,
156+
Func,
157+
CrsTimeoutSeconds
158+
));
159+
160+
for (CrsRetryCount = 1; CrsRetryCount <= CrsMaxRetries; CrsRetryCount++) {
161+
//
162+
// Stall before retry
163+
//
164+
gBS->Stall (CrsRetryIntervalUs);
165+
166+
//
167+
// Re-read the Vendor ID register
168+
//
169+
Status = PciRootBridgeIo->Pci.Read (
170+
PciRootBridgeIo,
171+
EfiPciWidthUint32,
172+
Address,
173+
1,
174+
Pci
175+
);
176+
177+
if (EFI_ERROR (Status)) {
178+
return EFI_NOT_FOUND;
179+
}
180+
181+
//
182+
// Check if device is now ready (no longer returning CRS)
183+
//
184+
if ((Pci->Hdr).VendorId != PCI_VENDOR_ID_CRS) {
71185
//
72-
// Read the entire config header for the device
186+
// Valid device found - read the entire config header
73187
//
74188
Status = PciRootBridgeIo->Pci.Read (
75189
PciRootBridgeIo,
@@ -79,12 +193,32 @@ PciDevicePresent (
79193
Pci
80194
);
81195

196+
DEBUG ((
197+
DEBUG_INFO,
198+
"PCI %02x:%02x.%x ready after %d CRS retries (%d ms)\n",
199+
Bus,
200+
Device,
201+
Func,
202+
CrsRetryCount,
203+
(CrsRetryCount * CrsRetryIntervalUs) / MICROSECONDS_PER_MILLISECOND
204+
));
205+
82206
return EFI_SUCCESS;
83-
} else if ((Pci->Hdr).VendorId == 0x0001) {
84-
DEBUG ((DEBUG_WARN, "CRS response detected. Devices that return a CRS response during enumeration are currently ignored\n"));
85207
}
86208
}
87209

210+
//
211+
// CRS timeout - device never became ready
212+
//
213+
DEBUG ((
214+
DEBUG_ERROR,
215+
"PCI %02x:%02x.%x CRS timeout after %d seconds - device not ready\n",
216+
Bus,
217+
Device,
218+
Func,
219+
CrsTimeoutSeconds
220+
));
221+
88222
return EFI_NOT_FOUND;
89223
}
90224

MdeModulePkg/MdeModulePkg.dec

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# It also provides the definitions(including PPIs/PROTOCOLs/GUIDs and library classes)
44
# and libraries instances, which are used for those modules.
55
#
6-
# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
6+
# Copyright (c) 2019 - 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.<BR>
77
# Copyright (c) 2007 - 2024, Intel Corporation. All rights reserved.<BR>
88
# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
99
# (C) Copyright 2016 - 2019 Hewlett Packard Enterprise Development LP<BR>
@@ -2325,6 +2325,20 @@
23252325
# @Prompt Max size to accept in PCIe Resizable BAR Capability register.
23262326
gEfiMdeModulePkgTokenSpaceGuid.PcdPcieResizableBarMaxSize|43|UINT8|0x10000030
23272327

2328+
## PCIe Configuration Request Retry Status (CRS) retry interval in microseconds.
2329+
# When a PCIe device returns CRS during enumeration, the PCI bus driver will wait
2330+
# this interval before retrying. Default is 10000us (10ms) to match Linux kernel.
2331+
# If set to 0, CRS retry is disabled regardless of PcdPciCrsTimeoutSeconds.
2332+
# @Prompt PCI CRS retry interval in microseconds.
2333+
gEfiMdeModulePkgTokenSpaceGuid.PcdPciCrsRetryIntervalUs|10000|UINT32|0x1000002A
2334+
2335+
## PCIe Configuration Request Retry Status (CRS) timeout in seconds.
2336+
# Maximum time to wait for a device returning CRS to become ready.
2337+
# When set to 0 (default), devices returning CRS are skipped during enumeration.
2338+
# Platforms requiring CRS retry support should set a non-zero value.
2339+
# @Prompt PCI CRS timeout in seconds.
2340+
gEfiMdeModulePkgTokenSpaceGuid.PcdPciCrsTimeoutSeconds|0|UINT32|0x1000002B
2341+
23282342
[PcdsPatchableInModule]
23292343
## Specify memory size with page number for PEI code when
23302344
# Loading Module at Fixed Address feature is enabled.

0 commit comments

Comments
 (0)