Introduction
PCIe enumeration is the process by which the operating system discovers all devices in the system, assigns them unique identifiers (BDFs), and configures their resources.
This article walks through PCIe enumeration using a simple topology and shows how configuration transactions (CfgRd/CfgWr) and completion packets (CplD) are used during device discovery and setup.
Topology
+----------------------+
| SoC (Root Complex) |
+----------+-----------+
| Bus 0
-----------------------------------------
| |
+---------+ +---------------+
| EP1 | | Switch |
+---------+ +-------+-------+
| Bus 1
+---------+
| EP2 |
+---------+
This topology represents a typical PCIe hierarchy:
- The Root Complex (RC) initiates all configuration transactions
- Bus 0 is directly connected to the RC
- EP1 is an endpoint on Bus 0
- The switch is also on Bus 0 and creates a secondary bus
- EP2 is located behind the switch on Bus 1
ECAM base address: 0x20000000
Initial BDF assignments:
- RC: Bus 0, Device 0, Function 0
- EP1: Bus 0, Device 1, Function 0
- Switch: Bus 0, Device 2, Function 0
Phase 1 - Scanning Bus 0
The enumeration process begins with the RC scanning Bus 0. It probes each device number by issuing configuration read requests to offset 0x00 (Vendor ID / Device ID).
A valid completion indicates the presence of a device.
Probe EP1 (Bus 0, Device 1, Function 0)
CfgRd0 TLP (RC -> EP1)
--------------------------------------------------------
DW0
Byte 0: 0x04 Fmt=000, Type=00100 (CfgRd0)
Byte 1: 0x00 TC=0, Attr=0
Byte 2: 0x00
Byte 3: 0x01 Length = 1 DW
DW1
Byte 4: 0x00 Requester ID [15:8] (Bus=0)
Byte 5: 0x00 Requester ID [7:0] (Dev=0, Fn=0)
Byte 6: 0x01 Tag = 1
Byte 7: 0x0F LastBE=0000, FirstBE=1111
DW2
Byte 8: 0x00 Bus Number = 0
Byte 9: 0x08 Device=1, Function=0
Byte 10: 0x00 Register Number [15:8]
Byte 11: 0x00 Register Number [7:2], Rsvd
--------------------------------------------------------
Completion TLP (EP1 -> RC)
--------------------------------------------------------
DW0
Byte 0: 0x4A Fmt=010, Type=01010 (CplD)
Byte 1: 0x00 TC=0
Byte 2: 0x00
Byte 3: 0x01 Length = 1 DW
DW1
Byte 4: 0x00 Completer ID [15:8] (Bus=0)
Byte 5: 0x08 Completer ID [7:0] (Dev=1, Fn=0)
Byte 6: 0x00 Status=000 (Successful)
Byte 7: 0x04 Byte Count = 4 bytes
DW2
Byte 8: 0x00 Requester ID [15:8]
Byte 9: 0x00 Requester ID [7:0]
Byte 10: 0x01 Tag = 1
Byte 11: 0x00 Lower Address
DW3 (Data)
Byte 12: 0x8C
Byte 13: 0x16
Byte 14: 0x09
Byte 15: 0x11
--------------------------------------------------------
The device responds with a valid Vendor ID and Device ID, confirming its presence.
Assigned BDF: 0000:00:01.0
Probe Switch (Bus 0, Device 2, Function 0)
The same process is repeated for the switch.
- A valid completion confirms the device
- The Header Type register (offset 0x0E) is read
- Value indicates a PCIe-to-PCIe bridge (Type 1 header)
Assigned BDF: 0000:00:02.0
Probe Remaining Devices
Devices from 3 to 31 are probed. No responses are received.
Bus 0 scan is complete.
Phase 2 - Configuring the Switch
Once the switch is identified as a bridge, the RC assigns bus numbers to enable access to downstream devices.
Bus Number Assignment
For Bus 0, Device 2, Function 0:
- Primary Bus Number = 0
- Secondary Bus Number = 1
- Subordinate Bus Number = 0xFF (temporary upper limit)
Configuration Write
CfgWr0: Bus=0, Dev=2, Fn=0, Reg=0x018
Data: 0x00FF0100
Routing Behavior of the Switch
After configuration:
- If Bus Number equals Secondary Bus -> forward downstream
- If Bus Number is greater than Secondary -> forward further downstream
- Otherwise -> do not forward
This routing logic is used for Type 1 configuration transactions.
Phase 3 - Scanning Bus 1
The RC now scans Bus 1 using Type 1 configuration transactions.
Probe EP2 (Bus 1, Device 0, Function 0)
CfgRd1 TLP (RC -> Switch)
--------------------------------------------------------
DW0
Byte 0: 0x05 Fmt=000, Type=00101 (CfgRd1)
Byte 1: 0x00
Byte 2: 0x00
Byte 3: 0x01
DW1
Byte 4: 0x00 Requester ID (Bus=0, Dev=0, Fn=0)
Byte 6: 0x03 Tag = 3
DW2
Byte 8: 0x01 Bus Number = 1
Byte 9: 0x00 Device=0, Function=0
--------------------------------------------------------
Switch Processing
- Bus Number matches Secondary Bus (1)
- Switch converts CfgRd1 to CfgRd0
- Forwards request to EP2
Completion Flow
EP2 -> Switch
Completion TLP (CplD)
Completer ID = Bus 1, Dev 0, Fn 0
Requester ID = Bus 0, Dev 0, Fn 0
Tag = 3
Switch -> RC
- Switch forwards completion upstream
- Packet remains unchanged
Assigned BDF: 0000:01:00.0
Key Observation
- Requests are routed using Bus Number
- Completions are routed using Requester ID
This distinction is essential for understanding PCIe routing behavior.
Phase 4 - Finalizing Bus Numbers
After scanning Bus 1:
- No additional bridges are found
- Highest bus number is 1
Update subordinate bus number:
CfgWr0: Bus=0, Dev=2, Fn=0, Reg=0x018
Data: 0x00010100
BAR Assignment
After enumeration, the kernel assigns memory regions to devices.
EP1 BAR Assignment
CfgWr0: Bus=0, Dev=1, Fn=0, Reg=0x010, Data=0xFFFFFFFF
CfgRd0: Bus=0, Dev=1, Fn=0, Reg=0x010
CfgWr0: Bus=0, Dev=1, Fn=0, Data=0x30000000
EP2 BAR Assignment
Note: EP2 is at Bus=1, Device=0, Function=0
CfgWr1 -> Switch -> CfgWr0: Reg=0x010, Data=0xFFFFFFFF
CfgRd1 -> Switch -> CfgRd0: Read size
CfgWr1 -> Switch -> CfgWr0: Data=0x30200000
Switch Memory Window
CfgWr0: Bus=0, Dev=2, Fn=0, Reg=0x020 = 0x30200000
CfgWr0: Bus=0, Dev=2, Fn=0, Reg=0x024 = 0x303FFFFF
This allows the switch to forward memory transactions to EP2.
Final Topology
RC (Bus 0)
|
|---- EP1: 0000:00:01.0 BAR0=0x30000000
|
|---- Switch: 0000:00:02.0
Primary=0 Secondary=1 Subordinate=1
|
|---- EP2: 0000:01:00.0 BAR0=0x30200000
Conclusion
PCIe enumeration follows a structured and predictable sequence:
- Devices are discovered using configuration reads
- Bridges are configured with bus numbers
- Downstream buses are scanned using Type 1 transactions
- Routing is based on Bus Number (requests) and Requester ID (completions)
- Resources such as BARs are assigned after discovery
Top comments (0)