PCI basics
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.
Multiple buses
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.
Domains
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.
Functions
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.
Device addressing
Any PCI device is addressed as [domain:]bus:device.function
(BDF).
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.
Example
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.
Bus 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 .1
.
Other functions of the device include .0 Starship/Matisse Reserved SPP
(not used by Linux),
.1 Starship/Matisse Cryptographic Coprocessor PSPCPP
(cryptographic coprocessor),
and .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
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.
Memory space
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
/ Memory Write
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).
I/O space
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 in
/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.
Device discovery
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 .1
to .7
.
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).
References
Footnotes
This is tricky to get right, so see this article for details.