edit SideBar

Main / Pci


This is a point-to-point connection (like Ethernet) rather than a multi-drop bus, although a switch can be used to connect multiple devices. The performance is scalable because of the flexibility of wire counts (can use powers of 2 starting at 1 wire). It is packet-based and includes hot plug support. Where PCI and PCI-X use bus cycles, PCIe is actually packet based like Ethernet. A lane is a bi-directional signal pair, and a link is another name for a lane. An x32 link connection has 128 wires (4 for each link, 2x differential pairs).

There is no clock line, so each device uses a known frequency and an internally generated clock.

Various speeds are supported, like 2.5Gb, 5Gb, 10Gb.

Transaction = a series of transmissions for info transfer between requester and completer


There are two modes for PCIe: RC (root complex) and EP (end point). RC is reserved for the CPU and connects to an endpoint. Endpoints are the devices for data sink/source.

The Linux PCIe driver code can be kind of a mess. A couple files of note are /source/include/linux/pci_ids.h and /source/include/uapi/linux/pci_regs.h, the latter of which contain register and field offsets to a sort of universal PCI memory-mapped register space.

Addressing and Memory

There are 4 address spaces: memory, I/O, configuration, message.

What is a split transaction?

A memory read request looks like this:
{addr | type of request | size | traffic class | byte enables | attributes}


Configuration space registers related to routing implemented by all devices which require system memory, I/O, MMIO addresses allocated to them.

Terminology for memory start/end is base/limit.

BARs not normally used in RC applications. RC does not receive config or I/O requests.


Here is the start of the call trace of the iMX6 version of the driver, found in drivers/host/pci:
host_init calls core reset, init phy, and deassert reset... followed by setup_rc and then start_link.

Driver uses the common clock framework, info here

Basic steps to getting the Deos iMX6 version up and running:

1. Created a registers header file
2. Created a master driver library API header file with status codes, port info and port descriptor structs 
(could contain base addresses, and lane number, things to identify the port, etc) and function prototypes.
3. Created a udelay function, timing is very sensitive with the registers setting up the PHY and link training, etc.
4. Borrowed the Linux init sequence:
--setup access to the clock and GPR register space using platform resources
--assert core reset function which powers down the PHY and turns off its ref clock
--call PHY init function which holds off link training while setting the device type, loss of signal level, and other PHY tx flags.
--end core reset function which sets up the Ethernet PLL, power on the PHY, gates on the 100M and 125M clocks, 
sets the LVDS clock select and the PCIE AXI select, and gates on the PCIE AXI clock.  Finally enables the PHY ref clock.
--Root Complex mode setup function for writing BAR regs, writes bus number reg, the memory base/limit reg, and then all 
the enables in the RC command reg.
--do the port logic setup with number of lanes, link width/speed, link enable, num of training sequences
5. Make the call to link startup functions which first set the link speed to Gen1 and then set application ready bit
6. Wait for link to come up by using a delay and check while loop.  Looking for the PHY debug reg to indicate link up, 
with link training over.  On a timeout the PHY is reset.
7. That's it for init, then begin to set up communication.

Page last modified on July 08, 2019, at 07:30 PM