编辑
2024-02-27
工作知识
0
请注意,本文编写于 465 天前,最后修改于 451 天前,其中某些信息可能已经过时。

目录

pcie读取配置空间bar空间的size
type0和type1
type0/1 headers的标志位
lspci读取type0/1
type0/1的配置空间
bar0的地址
bar0的大小
通过lspci读取
通过setpci读取
通过io命令获取
内核代码

pcie读取配置空间bar空间的size

pcie开始通过配置空间来读取pcie基本信息,改信息通过上层lspci能够正常解析,客户反馈自己的xilinx设备bar0只有512k,需要我们确定一下,遂确定如下

type0和type1

For device Functions with Type 0 headers (all types of Endpoints) For device Functions with Type 1 headers (Root Ports, Switches and Bridges)
  • 所有的ep设备都是type0 headers
  • 所有的rc设备,switch,bridge都是type1 headers

type0/1 headers的标志位

如何查看设备是type0还是type1 headers,可以通过配置空间的0x1e的值来确定,如下 image.png

For Functions that implement a Type 0 Configuration Space header the encoding 000 0000b must be used. For Functions that implement a Type 1 Configuration Space header the encoding 000 0001b must be used

也就是说,对于0x0e的值,如果是0x1则是type1 headers型设备,通常是rc或bridges,如果是0x0则是type0 headers型设备,通常是ep。

lspci读取type0/1

root@kylin:~# lspci -x 00:00.0 PCI bridge: Fuzhou Rockchip Electronics Co., Ltd Device 3588 (rev 01) 00: 87 1d 88 35 07 05 10 00 01 00 04 06 00 00 01 00 10: 00 00 00 00 00 00 00 00 00 01 ff 00 f0 00 00 00 20: 00 f0 00 f0 f1 ff 01 00 00 00 00 00 00 00 00 00 30: 00 00 00 00 40 00 00 00 00 00 00 00 70 01 02 00 01:00.0 Memory controller: Xilinx Corporation Device 7014 00: ee 10 14 70 00 00 10 00 00 00 80 05 00 00 00 00 10: 00 00 f8 ff 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 ee 10 07 00 30: 00 00 00 00 80 00 00 00 00 00 00 00 00 01 00 00

lspci -x可以读到0xe的值,这里可以看到00:00.0 是type1 headers,而01:00.0则是type0 headers

type0/1的配置空间

通常的配置空间布局如下图所示

image.png type0的配置空间布局如下图所示

image.png type1的配置空间布局如下图所示

image.png

这里可以知道,无论哪种type设备,bar0的寄存器都在0x10处,这里聚焦0x10处的信息

bar0的地址

对于0x10的值,默认是linux设置的映射地址,用作pcie域的读写操作。如下可以确定

root@kylin:~# lspci -x -s 01:00.0 01:00.0 Memory controller: Xilinx Corporation Device 7014 00: ee 10 14 70 00 00 10 00 00 00 80 05 00 00 00 00 10: 00 00 00 f0 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 ee 10 07 00 30: 00 00 00 00 80 00 00 00 00 00 00 00 ff 01 00 00

这里可以知道0x10的值为f0000000,这个0xf0000000是linux内通过设备树映射的可访问的地址。

bar0的大小

通过lspci读取

对于bar0的大小lspci已经读取出来了是512k,如下

root@kylin:~# lspci -s 01:00.0 -v 01:00.0 Memory controller: Xilinx Corporation Device 7014 Subsystem: Xilinx Corporation Device 0007 Flags: fast devsel, IRQ 255 Memory at f0200000 (32-bit, non-prefetchable) [disabled] [size=512K] Capabilities: [80] Power Management version 3 Capabilities: [90] MSI: Enable- Count=1/1 Maskable- 64bit+ Capabilities: [c0] Express Endpoint, MSI 00 Capabilities: [100] Advanced Error Reporting lspci: Unable to load libkmod resources: error -2

通过setpci读取

setpci --dumpregs setpci -s 01:00.0 0x10.L=0xffffffff root@kylin:~# lspci -s 01:00.0 -x 01:00.0 Memory controller: Xilinx Corporation Device 7014 00: ee 10 14 70 00 00 10 00 00 00 80 05 00 00 00 00 10: 00 00 f8 ff 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 ee 10 07 00 30: 00 00 00 00 80 00 00 00 00 00 00 00 ff 01 00 00

这时候读出来是0xfff80000,取最低有效位0x80000,则正好是512k

通过io命令获取

io -4 0xf0000000 -r -l 64 io -4 -w 0xf0000010 0xffffffff io -4 0xf0000010 -r

这里读出来仍是0xfff80000,换算也是512k

内核代码

内核主要代码实现在如下两个函数

  • __pci_read_base
  • pci_size

主要函数如下:

__pci_read_base pci_read_config_dword(dev, pos, &l); pci_write_config_dword(dev, pos, l | mask); pci_read_config_dword(dev, pos, &sz); pci_size u64 size = mask & maxbase; size = size & ~(size-1);