欧博allbet深入解析PCIe地址空间与寄存器机制:从地址映射到TLP生成的完整流程
Uart子系统专栏:
专栏地址:Uart子系统
Linux内核早期打印机制与RS485通信技术
– 末片,有专栏内容观看顺序
interrupt子系统专栏:
专栏地址:interrupt子系统
Linux 链式与层级中断控制器讲解:原理与驱动开发
– 末片,有专栏内容观看顺序
pinctrl和gpio子系统专栏:
专栏地址:
– 末片,有专栏内容观看顺序
input子系统专栏:
专栏地址:
input角度:I2C触摸屏驱动分析和编写一个简单的I2C驱动程序
– 末片,有专栏内容观看顺序
I2C子系统专栏:
专栏地址:
具体芯片的IIC控制器驱动程序分析:i2c-imx.c-CSDN博客
– 末篇,有专栏内容观看顺序
总线和设备树专栏:
专栏地址:
设备树与 Linux 内核设备驱动模型的整合-CSDN博客
– 末篇,有专栏内容观看顺序
目录
1.地址空间和寄存器介绍 1.1 地址空间
从PCIe的角度来看,内部总线可寻址资源分为两个地址空间。也就是说,PCIe有两个地址空间。第一个专用于内部寄存器,第二个专用于远程设备。cpu发出的地址信息范围符合这两个地址空间的范围
内部寄存器
Client Register Set:地址范围 0xFD000000~0xFD7FFFFF,比如选择PCIe协议的版本(Gen1/Gen2)、电源控制等
Core Register Set :地址范围 0xFD800000~0xFDFFFFFF,所谓核心寄存器就是用来进行设置地址映射的寄存器等
远程设备
Region 0:0xF8000000~0xF9FFFFFF , 32MB,用于访问外接的PCIe设备的配置空间
Region 1:0xFA000000~0xFA0FFFFF,1MB,用于地址转换
Region 2:0xFA100000~0xFA1FFFFF,1MB,用于地址转换
……
Region 32:0xFBF00000~0xFBFFFFFF,1MB,用于地址转换
其中Region 0大小为32MB,Region1~31大小分别为1MB。
远程设备的映射,总大小为64
MB,基址为0xF8000000,共分为33个区域,以下方程式描述了如何选择0到32的区域。区域0由A[RW]ADDR[25]==0解码,区域大小为32M字节。当A[RW]ADDR[25]==1时,区域1至32(配置的区域数量)由区域x=A[RW]ADDR[24:20]+1解码:
Region 0:0xF8000000~0xF9FFFFFF,大小为32 MB。
Region 1 到 32:每个大小为1 MB,共32个区域。
区域0通过 A[RW]ADDR[25] == 0 来选择,表示当 A[RW]ADDR 的第25位为0时,选择 Region 0,其大小为 32 MB。
当 A[RW]ADDR[25] == 1 时,选择 Region 1 到 32,这些区域通过以下公式选择:
区域 x = A[RW]ADDR[24:20] + 1
注意:A[RW]ADDR[25] 是地址信号的第 25 位, A[RW] 是区分读地址的信号还是写地址的信号
这些Region存在于PCIe控制器内部,并且是由控制器通过寄存器进行管理和配置的。
Region 的作用:
每个 Region 代表了PCIe控制器中用于访问外部PCIe设备的一部分地址空间。
CPU发出的地址如果在某个 Region 内,那么这个地址会被映射到相应的PCIe外设上。
Region 是在 PCIe 控制器内部管理的:
这些Region并不直接对应外设,而是PCIe控制器内部用来定义访问哪些外设,或者配置空间的一个机制。通过这些Region,PCIe控制器可以管理和调度外部PCIe设备的访问。
PCIe控制器通过寄存器(如ob_addr0, ob_desc0等)来描述和管理这些Region。寄存器会包含如何将主机的地址转换为PCIe TLP,以及如何访问外设。
外部设备的配置空间:
例如,Region 0 可能用于外部PCIe设备的配置空间,允许主机通过该Region访问PCIe设备的配置寄存器。
Region 1~32 可能用于外设的内存访问(例如设备的BAR空间)。
CPU访问Region 0的地址时,将会导致PCIe控制器发出读写配置空间的TLP。
CPU访问Region 1~32的地址时,将会导致PCIe控制器发出读写内存、IO空间的TLP。
1.2 寄存器介绍CPU访问一个地址,导致PCIe控制器发出TLP。TLP里含有PCIe地址、其他信息。
这些寄存器必定涉及这2部分:
地址转换:把CPU地址转换为PCIe地址
提供TLP的其他信息
Region0、Region1~32,每个Region都有类似的寄存器。
一个Region,可以用于读写配置空间,可以用于读写内存空间、可以用于读写IO空间,还可以用于读写消息。
这由Region对应的寄存器决定。
每个Region都有一样寄存器,以Region 0为例,有6个寄存器:
CPU访问某个Region时,它是想干嘛?
读写配置空间、发出对应TLP?
读写内存空间、发出对应TLP?
读写IO空间、发出对应TLP?
读写消息、发出对应TLP?
到底是发出哪种TLP,由Region对应的ob _desc0寄存器决定:
ob_desc0[3:0]作用1010 发出的TLP用于访问Type 0的配置空间
1011 发出的TLP用于访问Type 1的配置空间
0010 发出的TLP用于读写内存空间
0110 发出的TLP用于读写IO空间
1100 发出的TLP是"Normal Message"
1101 发出的TLP是"Vendor-Defined Message"
CPU访问某个Region时,最终都是要发出TLP,TLP的内容怎么确定?
地址信息:ob_addr0/1把CPU地址转换为PCIe地址,提供TLP里面的地址信息
其他信息:ob_desc0/1/2/3提供TLP的其他信息
注 – 配置空间和寄存器这提到的两个地址怎么不一样?
Region 0 的地址范围为 0xF8000000 ~ 0xF9FFFFFF,表示这是 32MB 的内存区域,用于访问外部 PCIe 设备的配置空间。这是地址空间,即主机通过 PCIe 总线访问外部设备时使用的实际物理地址。
而在寄存器表中提到的 Region 0 Outbound Config Registers,如
ob_addr0、ob_addr1 等,则是配置这些设备地址空间的控制寄存器。这个寄存器范围从 0x000
开始,表示这是主机内部的配置寄存器的偏移地址。它们在PCIe控制器内部,并用于设置 PCIe 控制器如何管理和访问这些设备的地址空间。
区别与联系:
Region 0 (0xF8000000 ~ 0xF9FFFFFF) 是外部设备的实际内存空间,主机可以通过这个范围访问连接的 PCIe 设备。
Outbound Config Registers(例如 ob_addr0, ob_addr1, ob_desc0 等)是用于配置和映射这个设备地址空间的控制寄存器。通过这些寄存器,可以指定设备如何响应主机的内存访问请求,或者主机如何通过这些配置寄存器访问PCIe设备。
配置流程:
配置阶段:
主机首先通过控制器的配置寄存器(如 ob_addr0、ob_desc0 等)来设置如何映射外部设备的地址空间。这些寄存器通常位于PCIe控制器内部。
通过这些寄存器,主机可以指定外部设备的基地址、大小、访问方式等信息。也就是说,主机通过这些寄存器告诉PCIe控制器:当我访问某个特定的地址区间时,我希望它指向某个PCIe设备。
访问阶段:
一旦配置完成,主机就可以通过特定的地址空间(例如 0xF8000000 ~ 0xF9FFFFFF 这样的外部设备地址空间)访问外部PCIe设备。
当主机试图访问这些地址空间时,PCIe控制器会根据配置寄存器中的设置,将这些访问请求转换并转发给实际的外部PCIe设备。
举例说明:
配置阶段:主机通过 ob_addr0 等寄存器,将控制器配置空间的0xF8000000 (Region0)这一段内存映射到某个外部 PCIe 设备的寄存器或内存空间。例如,0xF8000000 可以映射到一个 PCIe
网络卡的配置空间。
访问阶段:当主机读取或写入 0xF8000000 这一地址时,实际上是在和这个 PCIe 网络卡进行通信。PCIe控制器负责将这个请求转发给外部设备,并将设备的响应返回给主机。
疑问: CPU发出地址信息,落在PCIe控制器对应的地址空间上,地址空间对应的(比如Region0)PCIe控制器中的寄存器根据region0中的信息去解析,然后寄存器就发出TLP到对应的PCIe外设,去设置/访问PCIe外设的配置空间(地址空间) ???
1. CPU发出地址请求:
CPU发出一个内存读写请求(可能是访问PCIe外设的配置空间或内存空间),该请求的地址落入了PCIe控制器的地址空间。例如,落在了提到的Region
0(用于PCIe设备的配置空间),设置了里面Region0空间里面的信息。
2. 地址请求到达PCIe控制器:
该地址请求进入了PCIe控制器。在PCIe控制器中,每个Region(如Region 0、Region
1等)通过对应的寄存器(例如ob_addr0、ob_desc0等)来解析这个请求,决定如何处理。
ob_addr0 和 ob_addr1 寄存器定义了CPU AXI地址如何映射到PCIe设备的地址空间。
desc0等描述符寄存器包含了如何生成PCIe TLP的具体信息,尤其是TLP头部的信息。
3. 寄存器生成TLP:
PCIe控制器通过这些寄存器,生成TLP(Transaction Layer
Packet)。TLP是PCIe协议中用于通信的基本单位,负责在主机和PCIe设备之间传递读写请求、配置请求等。
例如,当CPU需要访问某个PCIe外设的配置空间时,PCIe控制器根据Region 0的寄存器配置,生成一个配置写或配置读的TLP。
4. TLP发送到PCIe外设:
生成的TLP包通过PCIe链路发送到目标PCIe设备。TLP包会包含地址、操作类型(读/写)、数据等信息。
5. PCIe外设接收并执行:
PCIe设备接收到TLP包后,会根据TLP中的地址和操作类型,执行相应的操作。例如:
如果是写操作,PCIe设备会更新其配置空间或内存。
如果是读操作,PCIe设备会返回读取的数据。
6. PCIe设备的响应:
如果是读请求,PCIe设备会返回相应的读响应TLP。PCIe控制器接收到这个响应后,会将结果转换为主机能够理解的形式,并返回给CPU。
大概:
CPU发出的请求首先到达PCIe控制器。
PCIe控制器通过配置寄存器(如ob_addr0、ob_desc0等)解析和生成TLP。
TLP发送到PCIe外设,执行相应的操作。
最终,PCIe设备的响应(如数据读取)通过TLP返回给CPU。
在这个过程中,寄存器起到桥接CPU的地址请求和PCIe外设地址空间的作用。它们负责地址映射和生成正确的TLP,从而实现主机和PCIe设备的通信。
CPU去设置PCIe控制器的Region中的信息,PCIe控制器中的寄存器(肯定是需要先去设置好reg才行)去解析Region中的信息然后发出TPL
PCIe设备内部的配置空间和寄存器的关系???
配置空间是PCIe设备中访问寄存器的一种机制和入口。它定义了设备的控制和状态寄存器的位置和访问方式。**可以把配置空间看作是设备寄存器访问的"目录",而寄存器是具体的操作和状态信息。**寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。
配置空间中的寄存器:在PCIe配置空间中,有专门的控制和状态寄存器,这些寄存器的内容定义了设备的行为。例如:
Command Register:用于启用或禁用I/O空间、内存空间、总线主设备等功能。
Status Register:反映设备的状态,例如中断、总线错误等。
基址寄存器(BAR,Base Address Registers):配置空间中的基址寄存器(BARs)定义了PCIe设备的寄存器(或内存)映射。它指定了设备的内存空间或I/O空间在系统地址空间中的位置。这些寄存器address告诉操作系统设备的寄存器或数据缓冲区在哪个地址范围,从而可以进行内存映射I/O(MMIO)或端口映射I/O操作。
内存映射寄存器:通过配置空间中的BAR,设备的寄存器可以映射到系统的内存地址空间,主机可以通过对这些内存地址进行读写来操作设备的寄存器。
1.2.1 用于配置空间CPU访问Region 0的地址时,将会导致PCIe控制器发出读写配置空间的TLP。
Region0一般用于读写配置空间,它对应的寄存器如下:
1.2.2 用于内存和IOCPU访问Region 1~32的地址时,将会导致PCIe控制器发出读写内存、IO空间的TLP。
而其寄存器如下:
2.访问示例 2.1 配置空间读写设置寄存器,才能去解析转化CPU地址信息
要读写设备的配置空间,首先要定位:Bus/Dev/Function/Reg:
怎么发出这些"Bus/Dev/Function/Register"信息?如下图所示:
当Region 0的寄存器ob_desc0[3:0]被配置为读写配置空间时, CPU发出Region 0的地址,地址里面隐含有这些信息:
Bus:cpu_addr[27:20]
Dev:cpu_addr[19:15]
Fun:cpu_addr[14:12]
Reg:cpu_addr[11:0]
使用过程步骤如下:
配置Region 0对应的ob_desc寄存器用于读写配置空间
通过设置寄存器ob_desc0来配置要发送的TLP的Header中的Fmt和Type字段,选择配置读/写还是IO读/写等。
配置Region 0对应的地址转换寄存器ob_addr
比如我们可以设置bit[5:0]为27,意味着cpu_addr[27:0]这28条地址线都会传入TLP。
CPU读写Region 0的地址
Region 0的地址范围是:0xF8000000~0xF9FFFFFF。
CPU想访问这个设备:Bus=bus,Dev=dev,Fun=fun,Reg=reg,那么CPU读写这个地址即可:
0xF8000000 + (bus<<20) | (dev<<15) | (fun<<12) | (reg)(bus<<20) | (dev<<15) | (fun<<12) | (reg)就可以组成cpu发出的addr_cpu
2.2 MEM/IO读写示例设置寄存器,才能去解析转化CPU地址信息
配置Region 1对应的ob_desc0寄存器用于内存读写
通过设置寄存器ob_desc0来配置要发送的TLP的Header中的Fmt和Type字段,选择配置读/写还是IO读/写等。
配置Region 1对应的地址转换寄存器ob_addr0/1
addr0、addr1寄存器里保存的是PCIe地址,也就是CPU发出这个Region的CPU地址后,将会转换为某个PCI地址。
怎么转换?由addr0、addr1决定。
Region 1的CPU地址范围是:0xFA000000~0xFA0FFFFF,是1M空间。
我们一般会让PCI地址等于CPU地址,所以这样设置:
addr0:
[5:0]等于19,表示CPU_ADDR[19:0]共20位地址传入TLP
[31:8]等于0xFA0000
addr1:设置为0
如上设置后,CPU读写地址时0xFA0???,就会转换为PCI地址:0xFA0???,转换过程如下:
pci_addr = cpu_addr[19:0] | (addr0[31:20] << 20) | (addr1<<32) = 0x????? + (0xFA0 << 20) | (0 << 32) = 0xFA0?????