LDD-PCI

简介

PCI(Peripheral Component Interconnect)用来指明计算机的各个部分如何进行交互,用来取代ISA(Industry Standard Architecture),实现更高效的、平台独立的、使外围设备更加易于移动的总线标准。
每个PCI设备通过bus number(8bit)、device number(5bit)、function number(3bit)寻址。可以通过lspci,/proc/bus/pci/devices,/sys/bus/pci/devices等查看这些信息。
 
地址空间

PCI的地址空间分为三种:memory locations、IO ports、configuration registers。同一PCI总线上的所有设备共享前两种地址空间。
PCI设备上电时,处于非活跃状态,只能进行configuration transaction——对PCI controller内的寄存器进行读写。系统启动阶段,固件(或者kernel)会对PCI外设进行配置,将其地址空间映射到CPU的地址空间。
PCI设备通过struct pci_device_id来标识,然后通过MODULE_DEVICE_TABLE宏导出到用户空间——
MODULE_DEVICE_TABLE(PCI, id_table);
会创建一个指向struct pci_device_id表的局部变量__mod_pci_device_table。在编译内核的过程中,depmod会寻找__mod_pci_device_table中所有设备的模块,并且把模块的名称和设备的名称添加到/lib/modules/KERNEL_VERSION/modules.pcimap中。
 
PCI驱动

PCI驱动的内核数据结构struct pci_driver,包括名称(显示在sysfs)、适用的id_table、回调函数probe、remove、suspend。调用pci_register_driver可以将struct  pci_driver注册到PCI core中;调用pci_unregister_driver可以移除所有与之绑定的pci设备,在函数返回前还会调用回调函数remove。2.6内核可以通过修改/sys/bus/pci/drivers/NAME/new_id动态分配驱动的PCI设备ID。
probe函数内,驱动程序需要首先调用pci_enable_device唤醒设备。
要访问PCI设备的配置空间,通过<linux/pci.h>中的函数pci_read(write)_config_WORDLEN读写配置寄存器,这些函数通过pci_bus_read(write)_config_WORDLEN实现。每个PCI设备最多实现六个IO地址区域,每个区域包括内存或IO寄存器;许多设备将IO寄存器实现在内存区域中。和计算机的主存不一样,有的IO寄存器不能采用高速缓存——读操作会清空其内容,因此需要配置其是否可进行预取。pci_resource_start/end/flags可以获取到PCI设备的地址空间资源;flag的值定义在linux/ioport.h中。
 
中断

系统启动阶段,计算机的固件会分配中断号,保存在配置寄存器60(PCI_INTERRUPT_LINE)中,一个字节,最多256个中断号。如果设备不支持中断,61号寄存器(PCI_INTERRUPT_PIN)为0;否则是非0值。
每个PCI connector有四个中断引脚,每个引脚都单独地引到主板的中断控制器。
PCI_INTERRUPT_PIN是只读寄存器,告知计算机使用的是哪个引脚。每个device board能够连接最多8个设备,每个设备使用一个引脚,写在自己的配置寄存器中。用一个设备板上的不同设备可以使用不同的中断引脚,也可以使用相同的引脚。
PCI_INTERRPU_LIN是读写寄存器,计算机启动时,固件扫描PCI设备,根据中断引脚的路由方法设置寄存器的值;对于设备驱动,这个寄存器是只读的。最新版本的内核在某些情况下可以不通过BIOS分配中断line。
 
LDD接下来简要介绍了iSA,MCA,EISA,VLB,SBus,NuBus以及一些external buses。
 
posted @ 2018-11-02 10:47  glob  阅读(280)  评论(0编辑  收藏  举报