PCI和PCIe
PCI即Peripheral Component Interconnect,中文意思是“外围器件互联”,是由PCISIG (PCI Special Interest Group)推出的一种局部并行总线标准。 它曾经是个人电脑中使用最为广泛的接口,几乎所有的主板产品上都带有这种插槽。目前该总线已经逐渐被PCI Express总线所取代。
PCI-Express是继ISA和PCI总线之后的第三代I/O总线,即3GIO。 由Intel在2001年的IDF上提出,由PCI-SIG(PCI特殊兴趣组织)认证发布后才改名为“PCI-Express”。它的主要优势就是数据传输速率高,另外还有抗干扰能力强,传输距离远,功耗低等优点。
PCI做的工作
0、Driver通过pci_register_driver()向PCI subsystem注册
1、PCI subsystem扫描可用设备,通过设备ID找到对应的driver,调用driver的probe()函数初始化设备
2、PCI subsystem是driver和HW之间的桥梁,driver通过调用PCI subsystem提供的函数控制HW
3、PCI设备有唯一的总线地址BDF,内核通过BDF(Bus Device Function)对设备进行寻址
4、PCI设备通过PCI总线访问内存,PCI设备之间也可以通过PCI总线传输数据
PCI总线结构
PCI总线是一种树型结构,并且独立于CPU总线,可以和CPU总线并行操作。PCI总线上可以挂接PCI设备和PCI桥,PCI总线上只允许有一个PCI主设备(同一时刻), 其他的均为PCI 从设备,而且读写操作只能在主从设备之间进行,从设备之间的数据交换需要通过主设备中转。 但是这并不意味着所有的读写操作都需要通过北桥中转,因为PCI总线上的主设备和从设备属性是可以变化的。 下面是一个典型的总线结构。
PCI总线是一种共享总线,所以需要特定的仲裁器(Arbiter)来决定当前时刻的总线的控制权。 一般该仲裁器位于北桥中,而仲裁器(主机)则通过一对引脚,REQ#(request) 和GNT# (grant)来与各个从机连接。
三种数据传输模型
Programmed I/O(PIO):
比如说某一个PCI设备需要向内存(SDRAM)中写入一些数据,该PCI设备会向CPU请求一个中断,然后CPU首先先通过PCI总线把该PCI设备的数据读取到CPU内部的寄存器中,然后再把数据从内部寄存器写入到内存(SDRAM)中。
DMA:
DMA是一种在传输过程中,几乎不需要CPU进行干预的数据传输方式。如上面的图片所示,以太网可以直接向内存(SDRAM)中写入数据,而几乎不需要CPU的干预。
Peer-To-Peer:
前面的文章中,我们介绍过PCI总线系统中的主机身份并不是固定不变的,而是可以切换的(借助仲裁器),但是同一时刻只能存在一个主机。完成Peer-to-Peer这一传输方式的前提是,PCI总线系统中至少存在一个有能力成为主机的设备。在仲裁器的控制下,完成主机身份的切换,进而获得PCI总线的控制权,然后与总线上的其他PCI设备进行通信。不过,需要注意的是,在实际的系统中,Peer-to-Peer这一传输方式却很少被使用,这是因为获得主机身份的PCI设备(Initiator)和另一个PCI设备(Target)通常采用不同的数据格式,除非他们是同一个厂家的设备。
PCI地址空间
PCI总线具有32位数据/地址复用总线,所以其存储地址空间为2的32次方=4GB。也就是PCI上的所有设备共同映射到这4GB上,每个PCI设备占用唯一的一段PCI地址,以便于PCI总线统一寻址。每个PCI设备通过PCI寄存器中的基地址寄存器来指定映射的首地址。如下图所示:
PCI体系结构中,一共支持三种地址空间:Memory Address Space、I/O Address Space和Configuration Address Space。其中x86处理器可以直接访问的只有Memory Address Space和I/O Address Space。而访问Configuration Address Space则需要通过索引IO寄存器来完成。
注:
在PCIe中,则引入了一种新的Configuration Address Space访问方式:将其直接映射到了Memory Address Space当中。
CPU使用不同的指令进行Memory和I/O地址空间的访问,Memory地址空间的访问效率更高。因为I/O访问效率低,现在建议使用Memory地址空间。
PCIe总线结构
PCI是并行总线,PCIe是串行总线。
PCI是共享总线,PCIe是点对点的。
典型的PCIe总线结构图如下:
图中的Root Complex经常被称为RC或者Root。在PCIe的Spec中,并没有特别详细的关于Root Complex的定义,从实际的角度来讲,可以把Root Complex理解为CPU与PCIe总线系统通信的媒介。
需要特别说明的是,Root Complex(RC or Root)和Switch都是全新的PCIe中的概念,它们结构中的每一个端口(Port)都可以对应于PCI总线中的PCI-to-PCI桥的概念。也就是说,每一个RC和Switch中一般都有多个类似于PCI-to-PCI桥的东西。分别如下两张图所示:
PCIe层次结构
和很多的串行传输协议一样,一个完整的PCIe体系结构包括应用层、事务层(Transaction Layer)、数据链路层(Data Link Layer)和物理层(Physical Layer)。其中,应用层并不是PCIe Spec所规定的内容,完全由用户根据自己的需求进行设计,另外三层都是PCIe Spec明确规范的,并要求设计者严格遵循的。
PCIe带宽
# lspci -s 02:00.0 -vvvv | grep Lnk
LnkCap: Port #0, Speed 8GT/s, Width x16, ASPM not supported, Exit Latency L0s unlimited, L1 unlimited
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk+
LnkSta: Speed 8GT/s, Width x16, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
LnkCtl2: Target Link Speed: 8GT/s, EnterCompliance- SpeedDis-
LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete+, EqualizationPhase1+
LnkCap means -> cababilities of host PCIe port
2.5GT -> PCIe1
5.0GT -> PCIe2
8.0GT -> PCIe3
x16 -> number of PCIe links
LnkSta -> status of PCIe port -> what is inserted
LnkCtl2 -> Negotiated speed -> PCIe version
1 PCIe link is able to transfer:
for PCIe 1.0 250 MB/s
for PCIe 2.0 500 MB/s
for PCIe 3.0 985 MB/s
with 16 PCIe links you can achieve:
with PCIe 1.0: 250 * 16 = 4000 MB/s -> 32000 Mbps -> 32 Gbps
with PCIe 2.0: 500 * 16 = 8000 MB/s -> 64000 Mbps -> 64 Gbps
with PCIe 3.0: 985 * 16 = 15760 MB/s -> 126080 Mbps -> ~126 Gbps
Domain
domain应该不是socket序号。
gigabyte-r120-01.rhts.eng.pek2.xxx.com
这这台机器上,只有一个socket:
[root@gigabyte-r120-01 ~]# lscpu
Architecture: aarch64
Byte Order: Little Endian
CPU(s): 32
On-line CPU(s) list: 0-31
Thread(s) per core: 1
Core(s) per cluster: 16
Socket(s): 1
但却有下面这些domain:
[root@gigabyte-r120-01 ~]# lspci -D | awk -F ":" '{print $1}'| sort|uniq
0000
0001
0002
0004
0006
https://stackoverflow.com/questions/49050847/how-is-pci-segmentdomain-related-to-multiple-host-bridgesor-root-bridges
下面是我基于这篇文章的一些理解:
linux中,domain号的意思是:
对于PCI,代表的是Host Bridge号,
对于PCIe,代表的是PCI complex root (PCR)号,
Host Bridge和PRC的功能类似,都是链接CPU和PCI/PCIe system的桥梁。
所以linux系统中有几个domain取决于硬件有几个Host Bridge/PCR。
另外,
linux中的domain号和PCI规范里面的domain号,指的算是一个意思。
linux中的domain号和PCIe规范里面的domain号,指的不是一个意思,
PCIe规范中每一个root port都有一个domain(它这个domain是用来控制流量路由的,所以和linux中domain的意思不一样)
PCIe规范中的PCI segment group和linux中的domain是一个意思。
code in linux
pci_bus_max_busnr(struct pci_bus *bus) # returns maximum PCI bus number of given bus' children
pci_status_get_and_clear_errors(struct pci_dev *pdev) # return and clear error bits in PCI_STATUS
__iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar) # iomap
pci_find_capability(struct pci_dev *dev, int cap) # query for devices' capabilities
pci_get_dsn(struct pci_dev *dev) # Read and return the 8-byte Device Serial Number
platform_pci_power_manageable(struct pci_dev *dev) # power management
platform_pci_set_power_state(struct pci_dev *dev,pci_power_t t) # power management
pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) # Use PCI PM registers to set the power state of given PCI device
pci_wakeup(struct pci_dev *pci_dev, void *ign) # Wake up a PCI device
pci_power_up(struct pci_dev *dev) # Put the given device into D0 (http://blog.chinaaet.com/justlxy/p/5100061872)
pci_save_state(struct pci_dev *dev) # save the PCI configuration space of a device before suspending
pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) # set device flag
pci_enable_device_io(struct pci_dev *dev) # Initialize a device for use with IO space
pci_enable_device_mem(struct pci_dev *dev) # Initialize a device for use with Memory space
pci_enable_device(struct pci_dev *dev) # Initialize device before it's used by a driver.
pci_configure_ari(struct pci_dev *dev) # enable or disable ARI forwarding
pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) # Reserve PCI I/O and memory resource