资源描述:
《linux设备驱动之pci设备的枚举》由会员上传分享,免费在线阅读,更多相关内容在工程资料-天天文库。
1、一:前言Pci,是PeripheralComponentInterconnect的缩写,翻译成中文即为外部设备互联.与传统的总线相比.它的传输速率较高.能为用户提供动态查询pcideivce.和局部总线信息的方法,此外,它还能自动为总线提供仲裁.在近几年的发展过程中,被广泛应用于多种平台.pci协议比较复杂,关于它的详细说明,请查阅有关pci规范的资料,本文不会重复这些部份.对于驱动工程师来说,Pci设备的枚举是pci设备驱动编写最复杂的操作。分析和理解这部份,是进行深入分析pci设备驱动架构的基础。我们也顺便来研究一下,linux
2、是怎么对这个庞然大物进行封装的。二:pci架构概貌上图展现了pci驱动架构中,pci_bus、pci_dev之间的关系。如上图所示,所有的根总线都链接在pci_root_buses链表中。Pci_bus->device链表链接着该总线下的所有设备。而pci_bus->children链表链接着它的下层总线。对于pci_dev来说。pci_dev->bus指向它所属的pci_bus。Pci_dev->bus_list链接在它所属bus的device链表上。此外,所有pci设备都链接在pci_device链表中。三:pci设备的配置空间
3、每个pci设备都有最多256个连续的配置空间。配置空间中包含了设备的厂商ID,设备ID,IRQ,设备存储区信息等.摘下LDD3中的一副说明图,如下:21要注意了,上图是以字节为单位的,而不是以位为单位.那怎么去读取每个设备的配置空间呢?我们在开篇的时候提到过,pci总线为用户提供了动态查询pci设备信息的方法。在x86上,保留了0xCF8~0xCFF的8个寄存器.实际上就是对应地址为0xCF8的32位寄存器和地址为0xCFC的32位寄存器。在0xCF8寄存中写入要访问设备对应的总线号,设备号、功能号和寄存器号组成的一个32位数写入0
4、xCF8.然后从0xCFC上就可以取出对应pci设备的信息.写入到0xCF8寄存器的格式如下:低八位(0~7): (寄存器地址)&0xFC.低二位为零8~10:功能位. 有时候,一个pci设备对应多个功能.将每个功能单元分离出来,对应一个独立的pcidevice11~15位:设备号 对应该pci总线上的设备序号16~23位:总线号 根总线的总线号为0.每遍历到下层总线,总线号+131:有效位 如果该位为1.则说明写入的数据有效,否则无效例如:要读取n总线号m设备号f
5、功能号对应设备的vendorid和Deviceid.过程如下:要写入到0xCF8中的数为:l=0x80<<23
6、n<<16
7、m<<11
8、f<<8
9、0x00即:outl(l,0xCF8)从0xCFC中读相关信息:L=Inw(0xCFC) (从上图中看到,vendorid和deviceid总共占四个字节.因此用inw)所以deviceid=L&0xFF,Vendorid=(L>>8)&0xFF。四:总线枚举入口分析Pci的代码分为两个部份。一个部份是与平台相关的部份,存放在linux-2.6.25archXXXpci。在x86,对
10、应为linux-2.6.25archx86pci 另一个部份是平台无关的代码,存放在linux-2.6.25driverpci下面。大致浏览一下这两个地方的init函数.发现可能枚举pci设备是由函数pcibios_scan_root()完成的.不过搜索源代码后,发现有两个地方会调用这个调数.一个是在linux-2.6.25archx86pciuma.c另一个是linux-2.6.25archx86pciLegacy.c这两个地方都是封装在一个subsys_initcall()所引用的初始化函数呢?到
11、底哪一个文件才是我们要分析的呢?分析一下linux-2.6.25archx86pci下的Makefile_32.内容如下:obj-y :=i386.oinit.o obj-$(CONFIG_PCI_BIOS) +=pcbios.oobj-$(CONFIG_PCI_MMCONFIG) +=mmconfig_32.odirect.ommconfig-shared.oobj-$(CONFIG_PCI_DIRECT) +=direct.o 21
12、pci-y :=fixup.opci-$(CONFIG_ACPI) +=acpi.opci-y