PCI is a bus: there is a number of wires, PCI devices (targets in PCI parlance) connected to these wires, a protocol how to make it all work and PCI host controller that arbitrates bus access and provides interface for CPU to talk to the devices.
There is a limited amount of devices that can be addressed on a single PCI bus, so PCI can be extended by bridges: a PCI-PCI bridge attaches a separate PCI bus (wires, slots, devices etc) to a main bus.
CPU addresses these extended buses through the same PCI host controller, and bridges take care of routing commands to the proper device.
Bridges are PCI devices themselves, so they occupy an address on a bus they are connected to.
There might be several independent sets of PCI devices (e.g. several host PCI controllers on a mainboard chipset). Each of these sets are called PCI domain.
One PCI device (e.g. pluggable card) may implement several functions (e.g. sound card and joystick controller used to be a common combo), so PCI provides for up to 8 separate functions on a single PCI device.
Any PCI device is addressed as
Amount of PCI domains is not limited, though in practice in PCs there is only one domain 0, omitted from the PCI device addresses.
There might be 256 PCI buses in a PCI domain.
There might be 32 devices on a single PCI bus.
One device might have from 1 to 8 functions. Function
.0 is required to
be present, other functions, if any, may be assigned any number from 1 to 7.
There is only one PCI domain in the example system, so it is omitted.
10:00.4 Audio device: Advanced Micro Devices, Inc. [AMD] Starship/Matisse HD Audio Controller
The device is on the PCI bus
10, and the device itself is
00. There are multiple functions
on the device, and function
.4 is audio controller.
10 is claimed by the bridge
00:08.1 00:08.1 PCI bridge: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B],
and this bridge is sitting on the main bus
00 with device address
08 and function
Other functions of the device include
.0 Starship/Matisse Reserved SPP (not used by Linux),
.1 Starship/Matisse Cryptographic Coprocessor PSPCPP (cryptographic coprocessor),
.3 Matisse USB 3.0 Host Controller (USB 3.0 controller).
.2 is not populated,
and the the functions seem to be completely unrelated, so it is a composition of several
unrelated controllers designers of mainboard chipset exposed as a single PCI device either to
conserve PCI bus space, or to make the chipset a bit cheaper to produce.
Configuration space is 256 (4096 for PCIe) bytes that can be read/written by the host.
This is done by sending
Configuration Read /
Configuration Write command to PCI bus
with the BDF address and offset in configuration space. On PC these requests are typically
mapped to several MMIO registers: one sets an address and offset in a couple of registers,
and reads the retrieved data from the data register.
Any PCI device might request some memory to be mapped. This is communicated by BAR
(base address) registers in configuration space. Host can query the amount of memory
requested, and then set the BARs to the values that are distinct from memory of other
PCI devices. Once done, the device will respond to
Memory Read /
PCI commands on the bus for the specific region.
On PC, a memory read/write, if it failed to be served by RAM or other memory-mapped devices,
is typically passed to PCI controller that issues
Memory Read /
Memory Write command.
This means that on a PC OS kernel should set up memory mapping of PCI devices so that the ranges do not overlap with memory ranges claimed by other devices (RAM etc).
Any PCI device may also request I/O space mapping. This is also communicated by BAR registers.
On PC I/O space is mapped to
out I/O ports. There are only 65536 I/O ports, and some
of them are claimed by other devices, so allocating and assigning a range of I/O ports for
a PCI device might be a huge problem.
Every PCI device is required to return answer to configuration space requests, so discovery is simple: read first 2 bytes of configuration space for every possible device. If the result is not 0xffff, then the device is present.
To enumerate functions, read
Header Type byte (offset
0xd in configuration space), and
see if 7th bit is set. If it is, probe functions
To descend into bridges, check
Header Type byte, ignoring “multiple functions” bit. If it is
1, then the device is a PCI-to-PCI bridge. This device needs to be configured with bridge bus
number, and then the devices on this bus can be enumerated1.
DMA, IRQ etc
Not covered (yet).
This is tricky to get right, so see this article for details.