ASAravind Sivakumaran
Theme

Theme and appearance

Appearance
Palette

Pick any colour. The displayed accent adjusts for readable contrast in light or dark mode.

← PCIe guide

PCIe / READING LSPCI

What is this card, and what may it do?

Think of a PCIe device as a flat in a big building. It has a door number (its address), a nameplate and a row of switches by the door (its configuration space), and the flat itself behind the door (its registers and memory, reached through BARs). DMA is the tenant going out to the shops on its own. One switch decides whether it may leave at all, and the IOMMU is the guard at the building's exit.

lspci reads the nameplate and the switches. This page reads them with you, one field at a time, on an emulated network card, and flips a few with setpci. For optional depth, the feature chapter covers switches the IOMMU cares about: PASID, ATS, PRI and SR-IOV.

What claims does this page make? 3 points
  • Spec rule: the 64-byte header, the capability lists, the BAR bit layout and the Command register come from the PCI and PCI Express specifications (members only, so not checked here).
  • Platform assumption: how lspci prints each field, the 64-byte limit without root and the BAR sizes shown follow pciutils 3.15 and Linux, and a real machine can differ.
  • Teaching model: the network card, its register values and the setpci console are emulated; the GPU and N100 examples are a reader's real output.

One line of lspci

Plain lspci -nn prints one line per device. Press each part.

The line 03:00.0 Ethernet controller [0200]: Device [1ee7:0001] (rev 01), in four parts. 03:00.0 is bus, device and function, the requester ID, like street, building and flat. The class says what it is. 1ee7:0001 is vendor and device ID, like maker and model. rev 01 is the revision. 03000bus : device . functionthe requester IDstreet : building . flat Ethernet controller [0200]class: what it isbase 02, subclass 00a job title 1ee7 : 0001vendor : device IDpicks the drivermaker : model rev 01revisionsilicon or firmwarea batch number

:. : Device [:]

Nothing selected yet.

The three numbers bus:device.function are also the device's requester ID: the return address on every request it sends. The IOMMU uses exactly this number to decide whose page table applies.

The CPU's root complex holds the IOMMU and a root port, 00:01.1. A 16-lane link runs from the root port to the card at 03:00.0, which reaches memory through the IOMMU. CPU: root complex IOMMU root port00:01.1 memory link: 16 lanes, each a pair of wires each way (x16) network card 03:00.0 config space · BAR0 registers
The CPU and OS reach the card through the root port. The card's requests go through the root port to the IOMMU, then to memory. CPU + OSconfig reads, MMIO IOMMUin the root complex MemoryRAM Root port00:01.1, the link Card 03:00.0config, BARs, ATC

Experiments

One platform, chosen for teaching: a PC whose IOMMU sits in the root complex, as on AMD and Intel systems.

Experiment

    Registers, as lspci prints them

      Commands and reads

        Notes

          The nameplate: configuration space

          Every function has 4096 bytes of configuration space. The first 64 are a fixed header, laid out the same on every endpoint (bridges use a second layout). Here they are, as lspci -x prints them:

          00: e7 1e 01 00 06 04 10 00 01 00 00 02 10 00 00 00
          10: 00 00 80 fe 00 00 00 00 00 00 00 00 00 00 00 00
          20: 00 00 00 00 00 00 00 00 00 00 00 00 e7 1e 01 00
          30: 00 00 00 00 40 00 00 00 00 00 00 00 00 01 00 00

          Bytes are little-endian: e7 1e at offset 00 is vendor ID 1ee7; 06 04 at 04 is the Command register, 0406; 00 00 80 fe at 10 is BAR0, the address where the card's own registers appear, fe800000; and 40 at 34 points to the first capability.

          Everything else a device can do is described by capabilities: small structures chained by pointers. The classic list lives in bytes 0x40 to 0xff; PCI Express added an extended list from 0x100 to 0xfff, where ATS, PASID and SR-IOV live. lspci prints each as Capabilities: [offset] name. Follow the pointers as lspci does:

            That walk is why lspci -vvv prints Capabilities: [40] Power Management, [50] MSI-X, [70] Express, then [100 v1] Advanced Error Reporting, [148 v1] Address Translation Service (ATS) and so on: the number in brackets is where the walk found it.

            Run lspci -vvv as root. Linux lets other users read only the first 64 bytes, so without root the capabilities are missing.

            The Command register: may it start requests?

            The Control: line of lspci -vv is the Command register, decoded bit by bit. A + is a 1 and a - is a 0. Three bits matter today:

            Flip them. Each switch runs the setpci command you see in the log.

            What lspci prints

            
                    

            Prerequisites controlled here

            setpci

              Compare the two writes: COMMAND=0 clears Mem too; =0:4 uses a mask and changes only bit 2.

              With BusMaster off the card cannot even ask, so the IOMMU never sees a request. Turning it on is the first step of Before DMA; whether the request then reaches memory is the IOMMU's decision, which the IOMMU foundations follow.

              Regions: where the card's memory appears

              Each Region n: line is one BAR: a window of addresses the card answers. Here are the regions of a GPU a reader sent in:

              Region 0: Memory at 6000000000 (64-bit, non-prefetchable) [size=16M]
              Region 2: Memory at 4000000000 (64-bit, prefetchable) [size=256M]
              Region 4: I/O ports at 3000 [size=64]
              Expansion ROM at 000c0000 [virtual] [disabled] [size=128K]

              lspci builds each line from a BAR's bits. The lowest four bits describe the window; the rest are its address. Pick a region and watch the bits turn into the line:

              
                      

              Prefetchable or not

              The one bit that changes how the CPU may touch a region is bit 3. Non-prefetchable memory may have side effects: reading a FIFO register can take the entry out, reading a status register can clear it. Every read must happen exactly as the driver wrote it, once, so the OS maps it uncached. Region 0 holds the GPU's control registers.

              Prefetchable memory behaves like RAM: reading it changes nothing, so the CPU and bridges may read ahead and merge writes. The OS may map it write-combining, which is how a driver streams textures into Region 2, the GPU's video memory window. Linux offers /sys/bus/pci/devices/…/resourceN_wc only for prefetchable regions. The experiment Prefetchable or not above shows what goes wrong when a FIFO is read ahead.

              So how is a non-prefetchable Region 0 at 6000000000, above 4 GiB? Behind a bridge it could not be: a bridge's non-prefetchable window has only 32-bit address registers, and Linux puts every non-prefetchable BAR there. But this GPU is built into the processor (00:02.0, an Intel N100), on bus 00 with no bridge above it, so it takes addresses straight from the windows firmware gives the host bridge, which can be anywhere.

              The last two lines

              A link is a bundle of lanes, each a pair of wires in each direction, like the lanes of a road. The width is how many lanes (x1, x2, x4, x8, x16); the generation is the speed limit on each one. Each generation roughly doubles what a lane carries:

              Genlspci saysLine codePer lane, each wayx4x16
              12.5GT/s8b/10b250 MB/s1.00 GB/s4.00 GB/s
              25GT/s8b/10b500 MB/s2.00 GB/s8.00 GB/s
              38GT/s128b/130b984 MB/s3.94 GB/s15.75 GB/s
              416GT/s128b/130b1969 MB/s7.88 GB/s31.51 GB/s
              532GT/s128b/130b3938 MB/s15.75 GB/s63.01 GB/s
              664GT/sFLIT, PAM48000 MB/s32.00 GB/s128.00 GB/s

              GT/s counts transfers on the wire, not data. Gen 1 and 2 spend 10 bits to send 8; Gen 3 to 5 spend 130 to send 128. Gen 6 doubles again by sending four voltage levels (PAM4), so each symbol carries two bits: 64 GT/s is 32 Gbaud. It packs traffic into fixed-size FLITs with error correction; Linux counts its rate as the full 64 Gb/s. These are the numbers Linux itself uses to report a link's bandwidth, before packet headers.

              A link trains to what both ends support: the lower generation and the fewer lanes. lspci shows what the card could do in LnkCap and what it got in LnkSta, and marks the gap (downgraded). Put a Gen 4 x16 card in a slot wired as Gen 3 x4:

              
                        

              A slot can be x16 long and x4 wired, and slots that share lanes with an M.2 socket drop to fewer when both are used; the board manual says which. Some devices, GPUs especially, also slow their link when idle to save power, so read LnkSta while the device is busy.

              Every line of lspci -vvv

              The full output is long, but it has a pattern. Each capability is a block; inside it, registers come in threes: Cap says what the device can do, Ctl what software turned on, Sta what is happening now. So DevCap, DevCtl, DevSta for the device, LnkCap, LnkCtl, LnkSta for the link, and the same again with a 2 for features added later. A feature works only when Cap has it and Ctl turns it on.

              Below is the real lspci 3.15 output for this page's card and for the bridges above it. Press any line to see what it means, flag by flag, and the setpci command that reads it. Or paste your own: it is explained in this page and sent nowhere.

              The fourth example is real: the integrated GPU of an Intel N100, as a reader's machine printed it. Read its DevCap2 and its PASID lines together. The GPU has a PASID capability but says EETLPPrefix-, and Linux's pci_enable_pasid() refuses any device without prefix support (unless a quirk says otherwise). Intel's IOMMU driver asks for PASID first and then turns ATS on, so this GPU ends up with PASIDCtl: Enable- next to ATSCtl: Enable+.

                Changing a bit with setpci

                Every switch above ran a command shaped like this:

                setpci -s 03:00.0 ECAP_PASID+6.w=1:1

                Once you have a dump, everything after it is safe: lspci and setpci read the saved copy as if it were the machine, and never touch the hardware. Capturing it is the one read that carries the risk above:

                # capture all 4096 bytes: reads the live device
                sudo lspci -xxxx -s 03:00.0 > card.txt
                # decode the copy: no root, no hardware
                lspci -F card.txt -vvv
                # read from the copy
                setpci -A dump -O dump.name=card.txt -s 03:00.0 COMMAND

                Writes to a dump are refused, which is what the console on this page is for. For more detail: PASID, ATS, PRI, SR-IOV and ASPM, the switches that make a device an IOMMU client.

                Sources