PCIE 设备
最近在学习PCIE相关的东西,参考了一些大神的资料和官方文档,也写点总结。
PCIE驱动遵循内核的驱动模型,总体都是以总线,设备,驱动三大块来实现的。
一 PCIE所有数据结构如图

1)struct pci_host_bridge 主桥数据结构,用来描述连接CPU和PCIE设备的主桥,该结构有Root bus0成员,它也是一个设备,需要注册。
2)struct pci_dev该结构体用来描述PCI设备,包括EP和pci to pci 桥等设备.
Bus:用来关联该设备在哪条bus下,
device,version: 枚举出来的设备配置空间的重要东西都会保存该数据结构。
3)struct pci_bus 该结构体用来描述PCI的总线。
struct list_head devices: 设备链表用于关联该bus下的所有设备。
children: PCI桥可以使当前总线得到扩展,当前总线上有几个PCI桥,那么当前总线就会拥有几个子总线,子总线会连接到父总线的children链表中。
ops: 当前总线访问总线上设备配置空间的 read、write 方法。
4)struct pci_slot 用来描述bus下的物理插槽
5)struct pci_bus_type 这个是pci的总线模型,和之前的pci_bus是两码事事情, pci_driver和pci_dev就是通过该总线关联起来.
match: 通过pci_dev 对应的字段 vendor 、subvendor 、device 、subdevice 来匹 配对应的pci_driver
所以大致的流程是内核启动之后,通过PCI_BUS之间的关系枚举出来所有设备,并为每一个设备创建一个PCI_DEV的数据结构,将配置空间的信息填入PCI_DEV之后,注册到总线PCI_BUS_TYPE. 然后我们编写的pci_driver中,填写了此驱动适配的设备号版本号等,在一个pci_device_id的数据结构中,同样也注册到pci_bus_type的总线中,如果信息一致则执行驱动probe函数。
二 PCIE枚举流程
1)首先驱动创建host bridge的数据结构,然后将其注册到系统,在注册的过程中也会创建一个root bus也是bus0,将其挂到host bridge下,然后解析设备树,为总线分配资源,还有地址空间。
2)pci_scan_child_bus开始,扫描下面所有设备和桥。
3)进一步到pci_scan_child_bus_extend分为两部分:
①扫描PCI设备,每条总线支持32个设备,每个设置最多支持8个功能号,若读取配置空间版本号和设备号不为0xff,则创建PCI_DEV设备,填充设备信息到数据结构,并设置设备的BAR寄存器,将之前设备树读取到的IO空间分配给设备,将设备注册到总线。
②扫描PCI桥设备,当发现有下一级桥设备时候则继续创建bus,扫描bus下面的设备,进行递归的枚举,整个过程是一个深度遍历的算法,最终枚举出所有设备。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2021-12-01 判断一个IP是否有效(牛客网通过正确)
2021-12-01 牛客网c++如何处理输入输出
2021-12-01 驱动开发
2020-12-01 import java.net.Socket;
2020-12-01 StringBuffer类
2020-12-01 import java.io.IOException;
2020-12-01 java invoke方法