PCIe / ENUMERATION
Nobody gives the computer a list. How does it find every device?
At power-on the processor knows one thing about PCIe: where the root complex is. It does not know that a network card sits in the second slot or that an NVMe drive hides behind a switch. Firmware, and then the operating system, find out the way a new postman learns a town: walk every street, knock on every door, and write down who answers. Junctions get signposts ("streets 02 to 05 this way"), and every house gets a postbox address it can be reached at.
This chapter walks a real machine: QEMU's q35 PC with SeaBIOS, three root ports, a switch, a network card and an NVMe drive, booted with Linux 6.8. The bus numbers, BAR sizes and windows below are what that boot produced. Start with the simple guide; the second half is for people who write firmware, drivers or tests.
What claims does this page make? 5 points
- Spec rule: configuration headers, bus-number routing, BARs and Request Retry Status come from the PCI Express Base Specification (members only, cited by section as Linux cites it, not checked here).
- Emulated observation: bus numbers, BAR values, windows and the boot log come from QEMU 8.2's q35 with SeaBIOS, booted with Ubuntu's Linux 6.8; the raw captures, versions and commands are in the site's repository under
docs/evidence/pcie-qemu. QEMU emulates the devices, so link speeds and timings are not a real board's. - Simulation: the bus walk and the experiments are models that replay that boot; the walk is condensed, and UEFI firmware and Linux walk in a slightly different order and can reach the same numbers.
- Real hardware: none on this page; the N100's own tree is in Reading lspci.
- Linux behaviour is quoted from its source, read on 2 October 2026.
The simple guide, in five ideas
- Every function has an address: bus, device, function.
04:00.0is bus 4, device 0, function 0, written in hex. A card can hold up to eight functions (a network card with two ports often has two); each looks like a separate device to software. - Every function has 4 KiB of configuration space (256 bytes on older, conventional PCI devices). Its first bytes say who it is: vendor ID, device ID, and a class code (network, storage, bridge). lspci prints them.
- Finding devices is knocking on doors. Software reads the vendor ID at every address. A device answers with its ID; an empty address answers
ffff, a value no vendor may use. - Bridges are junctions, and software numbers the streets. A root port or a switch port is a bridge. Each holds three numbers: the bus it sits on (primary), the bus just below it (secondary) and the highest bus anywhere below it (subordinate). A request for a bus in that range goes through.
- Devices ask for address space; software hands it out. A device's BARs (base address registers) say how much memory its registers need. Firmware or the OS picks an address for each, and every bridge above gets a window that covers them.
That is all of enumeration: number the buses top-down, add up the BAR sizes bottom-up, then hand out addresses top-down. The rest of this page shows each step on the real machine.
The bus walk, step by step
This is the walk SeaBIOS ran on the QEMU machine: depth first, so
when it meets a bridge it gives it the next free bus number, walks
everything below it, and only then writes the bridge's subordinate
bus. Addresses show ?? until the walk reaches them,
because a device's bus number does not exist until a bridge above
it is numbered.
A condensed model of the depth-first numbering, not a trace: one
step stands for one or more configuration accesses, and SeaBIOS's
first pass over each bus, which closes every bridge on it (secondary
ff, subordinate 00) so stale numbers cannot
route a request, is left out (pci_bios_init_bus_rec).
Watch the subordinate numbers: each bridge opens with
ff ("send me everything") so reads for buses not yet
numbered still reach the walk, then closes to the real highest bus
on its way back up. The result, [01],
[02-05], [03-05], [04],
[05] and [06], is exactly what Linux 6.8
printed for this machine.
Experiments
The QEMU machine: q35, SeaBIOS, Linux 6.8. Bus numbers from the walk above; addresses from that boot.
Experiment
This "What if" step ran on its own copy; the panels show that copy.
Configuration addresses: ECAM and port cf8
Software reaches configuration space in one of two ways. The
original PC way writes an address to I/O port cf8 and
reads the value from port cfc: two accesses, so the
kernel holds a lock between them, and it reaches only the first 256
bytes. PCIe's way, ECAM (Enhanced Configuration
Access Mechanism), gives every function's 4 KiB its own memory
address: 1 MiB a bus, 32 KiB a device, 4 KiB a function, so 256
buses take 256 MiB. On this machine the window starts at
b0000000 (PCI: ECAM [mem 0xb0000000-0xbfffffff]
in the boot log). Type an address:
Try register 100, the first extended capability: ECAM
reaches it, the legacy ports do not (AMD processors have an
extension that puts register bits 11-8 into bits 27-24 of the
cf8 value; Linux uses it only where ECAM is missing).
Arm and RISC-V boards have no I/O ports and use ECAM, or a
controller-specific window, only.
Type 0 and Type 1 headers, byte by byte
The first 64 bytes of configuration space are the header. Byte
0e says which kind: type 0 for an
endpoint (six BARs), type 1 for a bridge (two BARs,
then bus numbers and windows). Bit 7 of the same byte says the
device has more functions. Both dumps are from the QEMU machine
(lspci -x, bytes in little-endian order). Press any
highlighted bytes:
04:00.0, the NVMe drive: type 0
00: 10 00 02 00 00 00 10: 00 00 00 00 00 00 00 00 20: 00 00 00 00 00 00 00 00 00 00 00 00 f4 1a 00 11 30: 00 00 00 00 00 00 00 00 00 00 00 0a 01 00 00
03:00.0, the switch's downstream port above it: type 1
00: 4c 10 33 82 03 01 10 00 01 00 00 00 00 10: 00 00 00 00 00 00 00 00 00 00 00 20: 00 00 00 00 00 00 00 00 30: 00 00 00 00 90 00 00 00 00 00 00 00 00 00 02 00
Nothing selected yet.
| Offset | Type 0 (endpoint) | Type 1 (bridge) |
|---|---|---|
| 00-0f | Vendor, device, command, status, class, header type: the same in both | |
| 10-17 | BAR0, BAR1 | BAR0, BAR1 (often unused) |
| 18-1b | BAR2 | primary, secondary, subordinate bus; secondary latency |
| 1c-1f | BAR3 | I/O base and limit; secondary status |
| 20-27 | BAR4, BAR5 | memory base and limit; prefetchable base and limit |
| 28-2f | CardBus CIS; subsystem vendor and ID | prefetchable base and limit, upper 32 bits |
| 30-33 | expansion ROM | I/O base and limit, upper 16 bits |
| 34 | capabilities pointer | |
| 38-3b | reserved | expansion ROM |
| 3c-3f | interrupt line and pin; min grant, max latency | interrupt line and pin; bridge control |
BARs and windows: sizes up, addresses down
Bus numbers are given out top-down. Address space works the other way: software first learns the size of every BAR at the bottom, adds them up into each bridge's window on the way up, and only then hands out addresses from the top. The NVMe drive's numbers, read from Linux in that QEMU guest:
BAR0 before: fe400004 00000000 command, decoding off: 0107 → 0000 (Linux writes 0104) after writing ffffffff ffffffff: ffffc004 ffffffff restored: fe400004 00000000, command 0107
- The size: ignore the four type bits, and the lowest bit the device let through is bit 14: 214 = 16 KiB. Linux finds it the same way, as the lowest set bit (
pci_size()); firmware such as EDK2 computes~mask + 1, which is the same number. - The type:
4in the low digit is 64-bit, not prefetchable. A prefetchable BAR (bit 3) promises reads have no side effects, so bridges may read ahead and merge. It goes in a bridge's prefetchable window, or in the non-prefetchable one when that is all there is (Linux falls back to it); the rule runs the other way: a non-prefetchable BAR must never sit in a prefetchable window. Whether the CPU maps a BAR write-combining is a separate choice, made when a driver maps it (ioremap_wc()). - Why decoding goes off: between the write and the restore, the BAR claims the addresses
ffffffff_ffffc000upwards. Linux sizes all of a device's BARs in one batch with memory and I/O decoding off, and prints nothing meanwhile ("No printks while decoding is disabled!"). - The windows: a bridge's memory window counts in 1 MiB steps, so the drive's port gets at least 1 MiB; SeaBIOS uses at least 2 MiB, and gives an empty port that supports hot-plug 2 MiB too. The Windows experiment adds them up.
The existing BAR decoder on
the lspci page turns any BAR value into lspci's
Region line. Two features change these rules on big
devices: Resizable BAR (extended capability
0x15) lets a GPU offer several sizes, so the OS can map
all of its memory at once, and SR-IOV adds a second
set of BARs for the virtual functions, sized once and repeated for
each VF (see SR-IOV).
For professionals: Linux's scan, step by step
Linux has its own walk, even on a PC where the firmware already did
one. It runs once per host bridge the platform described (ACPI on
PCs, the device tree on many Arm boards, see the
boot discovery chapter), from
drivers/pci/probe.c:
pci_create_root_bus(), fromacpi_pci_root_create()on PCs orpci_scan_root_bus_bridge()on device-tree hosts: create the root bus with the bus range and windows the platform gave (theroot bus resourcelines in the log).pci_scan_child_bus_extend(): for devices 0 to 31,pci_scan_slot(). Below a root or downstream port only device 0 is tried (only_one_child(): a PCIe link carries one device;pci=pcie_scan_alloverrides it).pci_scan_single_device()→pci_bus_read_dev_vendor_id():ffffffff,00000000,0000ffffandffff0000all mean empty; vendor0001means "retry", and Linux waits about a minute for it (pci_bus_wait_rrs(), a 60 s limit).pci_setup_device(): read the header type and class, print the[vendor:device] type 01 class 0x060400line, thenpci_read_bases(): six BARs for type 0, two plus the windows for type 1. Functions 1 to 7 are read only if function 0's header has bit 7 set, or through ARI.- Bridges, in two passes over the whole bus: pass 0 keeps bridges the firmware configured and walks below them; pass 1 numbers the rest (an unconfigured or invalid bridge, "bridge configuration invalid ([bus …]), reconfiguring"), from the highest bus used so far, plus spare buses for hot-plug ports (
pci=hpbussize, default 1). - Resources: on x86,
pcibios_resource_survey()claims what the firmware assigned and Linux places only what is left (the I/O windows in this boot). Generic Arm and RISC-V hosts (pci_host_probe()) reassign everything unless the platform asks to preserve its setup. - Drivers bind once all of this is done:
pci_bus_add_devices().
| SeaBIOS (this boot) | EDK2 (UEFI) | Linux | |
|---|---|---|---|
| Order | descends into a bridge as soon as it meets it | descends as soon as it meets it | scans the whole bus, then each bridge |
| Bus numbers | assigns all | assigns all, with hot-plug padding | x86: keeps the firmware's; generic DT hosts: assigns all; pci=assign-busses forces it |
| Windows | at least 2 MiB each | from the platform's resource map | at least 1 MiB; pci=realloc may move firmware's choices |
| Below a downstream port | tries all 32 devices | tries all 32 | device 0 only |
Kernel parameters that change enumeration, from the kernel's parameter list:
pci=assign-busses: number every bus again, ignoring the firmware (x86).pci=realloc: move the firmware's BARs and windows when something does not fit; Linux turns it on by itself when SR-IOV BARs are unassigned.pci=hpbussize=,pci=hpmmiosize=,pci=hpmemsize=: spare buses and address space for hot-plug ports.pci=nocrs: ignore the host bridge windows from ACPI; the kernel asks you to report a bug if you need it.pci=pcie_scan_all: try all 32 devices below a downstream port.
The real boot log, line by line
Linux 6.8 on the QEMU machine (dmesg, timestamps removed). Press a line:
Nothing selected yet.
Try it in QEMU
The machine on this page is one command (QEMU 8.2, any kernel; add
a root filesystem or an initramfs to get a shell, then
lspci -tv and dmesg | grep pci):
qemu-system-x86_64 -M q35 -m 512 -nographic -kernel vmlinuz -append console=ttyS0 \ -device pcie-root-port,id=rp1,bus=pcie.0,chassis=1,slot=1,addr=0x1c.0,multifunction=on \ -device pcie-root-port,id=rp2,bus=pcie.0,chassis=2,slot=2,addr=0x1c.1 \ -device pcie-root-port,id=rp3,bus=pcie.0,chassis=5,slot=5,addr=0x1c.2 \ -device x3130-upstream,id=up,bus=rp2 \ -device xio3130-downstream,id=dn1,bus=up,chassis=3,slot=3 \ -device xio3130-downstream,id=dn2,bus=up,chassis=4,slot=4 \ -device e1000e,bus=rp1,netdev=n0,romfile= -netdev user,id=n0 \ -device nvme,bus=dn1,serial=x,drive=d0 -drive if=none,id=d0,file=disk.img,format=raw
What lspci -tv prints for it:
-[0000:00]-+-00.0 Intel Corporation 82G33/G31/P35/P31 Express DRAM Controller
+-01.0 Device 1234:1111
+-1c.0-[01]----00.0 Intel Corporation 82574L Gigabit Network Connection
+-1c.1-[02-05]----00.0-[03-05]--+-00.0-[04]----00.0 Red Hat, Inc. QEMU NVM Express Controller
| \-01.0-[05]--
+-1c.2-[06]--
+-1f.0 Intel Corporation 82801IB (ICH9) LPC Interface Controller
+-1f.2 Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode]
\-1f.3 Intel Corporation 82801I (ICH9 Family) SMBus Controller
Then change one thing and predict the log before you boot: move the
drive to dn2, add a fourth root port, or boot with
pci=assign-busses. On your own PC, sudo lspci
-tv and sudo dmesg | grep -E 'pci (0000|bus)'
show the same story for real hardware.
Sources
- The boot: QEMU 8.2.2 (q35, SeaBIOS) and Ubuntu 24.04's Linux 6.8.0 kernel, run on 2 October 2026; the guest's
/sys/bus/pci/devices/*/configwas dumped and decoded with lspci 3.10.tests/iommu-pcie-enum.test.mjschecks the walk and the numbers against that capture. - Linux, read on 2 October 2026 (7.3-rc5):
drivers/pci/probe.c(pci_scan_child_bus_extend,pci_scan_slot,only_one_child,pci_bus_read_dev_vendor_id,pci_bus_wait_rrs,pci_setup_device,pci_read_bases,__pci_read_base,pci_size,pci_scan_bridge_extend),drivers/pci/setup-bus.c(pbus_size_mem),drivers/pci/setup-res.c,drivers/pci/pci.c(PCI_RESET_WAIT,PCIE_RESET_READY_POLL_MS),include/linux/pci-ecam.h,arch/x86/pci/direct.c(PCI_CONF1_ADDRESS),arch/x86/pci/i386.c(pcibios_resource_survey),include/uapi/linux/pci_regs.h, kernel parameters. - Firmware: SeaBIOS
src/fw/pciinit.c(pci_bios_init_bus_rec,PCI_BRIDGE_MEM_MIN); EDK2MdeModulePkg/Bus/Pci/PciBusDxe(PciScanBus,PciParseBar); corebootsrc/device/pci_device.c. - The PCI Express Base Specification (PCI-SIG, members only) defines configuration space, the headers, routing by bus number and Request Retry Status. Linux cites r6.0 sections 2.3.1 (RRS) and 6.6.1 (ready 1 s after reset). This page cites only public sources.