PCI设备初始化(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hz5034/article/details/79790074

访问PCI设备

我们知道CPU和网卡是通过PCI总线相连的,CPU可以直接访问系统内存(虚拟地址),也可以通过映射间接访问总线地址,那CPU怎么访问网卡的存储空间呢?

每个网卡都有自己的存储空间,这些空间的卡上地址(在网卡上的地址)本质上是局部的,所以都从0开始,它们不与总线直接相连,在把网卡插上总线并加电之初,从总线上还访问不到这些空间

系统初始化时扫描PCI总线上的各个PCI设备(包括网卡),为这些设备分配总线地址,并建立起其卡上地址和总线地址的映射,那映射是怎么建立起来的?

每个PCI设备上都有用来建立映射的配置寄存器组配置空间),系统初始化时通过这组寄存器来为设备”配置”总线地址,那CPU怎么访问这组寄存器呢?这就又回到原点了

PCI标准规定配置寄存器组最大256 byte,其中开头64 byte是标准的(对每个PCI设备都一样),所有PCI设备的配置寄存器组都使用相同的地址(卡上地址或偏移量)

这里写图片描述

系统在IO地址空间预留了八个字节(0xCF8~0xCFF),其中前四个字节做地址寄存器,后四个字节做数据寄存器,当CPU访问某个设备的某个配置寄存器时,首先通过I/O命令向地址寄存器写入目标地址(包括总线号、设备号、功能号、寄存器地址的综合地址),然后通过I/O命令读写数据寄存器

这里写图片描述

综合地址的结构如下所示,其中寄存器地址的高6位用于寻址最大64 word(256 byte)的配置寄存器组

这里写图片描述

写入综合地址后,从0号总线开始,每个PCI桥将综合地址中的总线号和自己的总线号相比,若符合,根据设备号+功能号寻找设备;若不符合,将综合地址传递给下一级总线的PCI桥继续寻找,直到找到设备,最后根据8位寄存器地址找到配置寄存器,此时通过I/O命令读写数据寄存器就可以读写配置寄存器了

系统初始化时扫描PCI总线上的各个PCI设备(包括网卡),为这些设备分配总线地址,设备的每个BAR对应设备的一段存储空间,系统通过将总线地址写入BAR就建立了存储空间的卡上地址和总线地址的映射

设备驱动程序调用pci_ioremap_bar()将写入BAR的总线地址(保存在resource数组中)映射到系统内存的虚拟地址,之后CPU就可以通过虚拟地址访问PCI设备的存储空间,而不用再通过IO命令了

探测PCI设备

配置寄存器组中的Header Type为0表示普通PCI设备、为1表示PCI桥,PCI桥根据功能又分为Host-PCI桥、PCI-PCI桥、PCI-ISA桥、PCI-CardBus桥等

每个PCI总线都挂在一个PCI桥下,其中0号总线挂在Host-PCI桥下(CPU通过Host-PCI桥连到0号总线),所有总线组成一颗总线树

这里写图片描述

直接探测

探测PCI设备有BIOS探测直接探测两种方式,两者都是从Host-PCI桥开始深度优先搜索总线树上的所有设备,我们以直接探测为例讨论

  • 申请IO地址空间0xCF8~0xCFF,探测Host-PCI桥
1 2 3 4 5
arch_initcall pci_arch_init pci_direct_probe pci_check_type1 pci_sanity_check
  • 深度优先搜索总线树,读取BAR,写入resource
1 2 3 4 5 6
subsys_initcall pci_legacy_init pcibios_scan_root pci_scan_bus_parented pci_scan_child_bus pci_scan_slot
pcibios_fixup_bus
pci_scan_bridge
6 7 8 9 10 11
pci_scan_slot pci_scan_single_device pci_scan_device pci_setup_device pci_read_bases __pci_read_base
pcibios_fixup_bus pci_read_bridge_bases
pci_scan_bridge pci_scan_child_bus
  • 深度优先搜索总线树,分配总线地址,写入BAR建立映射
1 2 3 4
subsys_initcall pcibios_init pcibios_resource_survey pcibios_allocate_bus_resources
为每个总线分配地址
pcibios_allocate_resources
为每个PCI设备分配地址
fs_initcall pcibios_assign_resources
为起始地址已改成0的区间分配地址
pci_assign_unassigned_resources pci_bus_assign_resources
4 5 6 7
pcibios_allocate_bus_resources pci_find_parent_resource
request_resource __request_resource
pcibios_allocate_resources alloc_resource pci_find_parent_resource
request_resource __request_resource
pci_bus_assign_resources pbus_assign_resources_sorted pci_assign_resource __pci_assign_resource
7 8 9 10
__pci_assign_resource pci_bus_alloc_resource allocate_resource find_resource
__request_resource
pci_update_resource

深度优先搜索

这里写图片描述

这里写图片描述

参考资料

《Linux内核源代码情景分析》
《PCI Express 体系结构导读》
http://blog.sina.com.cn/s/articlelist_1685243084_3_1.html
http://blog.chinaaet.com/justlxy/p/5100057779

猜你喜欢

转载自blog.csdn.net/hz5034/article/details/79790074
今日推荐