之前调试了几个pci网卡驱动,虽然功能没什么问题,但驱动中调用的某些内核提供的pci相关的接口一直没搞太清楚,所以最近准备深入研究一把。
pci设备的识别及配置方式
pci总线使用单端并行数据总线,采用地址译码方式进行数据传递,而采用id译码方式进行配置信息(比如配置某个pci设备的物理地址)的传递。其中地址译码方式使用地址信号,而id译码方式使用pci设备的id号,包括bus number、device number、function number和register number。linux系统中使用了bus number、device number和function number区分不同的设备;对于有两个接口的网卡,linux会按照两个设备处理,因为这两个接口会呈现出不同的function number。
posted和non-posted传送方式
pci总线规定了两类数据传送方式,分别是posted和non-posted数据传送方式。又分别对应了posted和non-posted总线事务。
posted总线事务指pci主设备向pci目标设备进行数据传递时,当数据到达pci桥后,即由pci桥接管来自上游总线的总线事务,并将其转发到下游总线。采用这种数据传递方式,在数据还没有到达最终的目的地之前,pci总线就可以结束当前总线事务,从而在一定程度上解决了pci总线的拥塞问题,所以这种方式的pci总线利用率较高。只有存储器写请求可以采用posted总线事务,简称为pmw(posted memory write)。
non-posted总线事务是指pci主设备向pci目标设备进行数据传递时,数据必须到达最终目的地之后,才能结束当前总线事务的一种数据传递方式。存储器读请求、i/o读写请求、配置读写请求只能采用non-posted总线事务。
中断请求和数据传送的同步问题(msi中断机制不存在这个问题)
在pci总线中,intx信号是一个异步信号。所谓异步,是指intx信号的传递并不与pci总线的数据传送同步。假设某个pci设备在使用dma方式将一组数据写入存储器,该设备在最后一个数据离开自己的发送fifo时,即认为dma操作已经完成。此时这个设备将通过intx信号,通知处理器dma写操作完成。
但是,当处理器收到intx信号时,并不意味着pci设备已经将数据写入存储器中,因为pci设备的数据传递需要经过pci桥/host主桥,最终才能到达存储器。
pci总线提供了以下两种方法解决这个同步问题。
(1)pci设备保证在数据到达目的地之后,再提交中断请求。具体来说,pci设备在提交中断请求之前,向dma写的数据区域发出一个读请求。pci总线的“序”机制,保证了在这个存储器读请求完成前,会将以前发出的dma数据写入存储器。pci总线规范要求host主桥和pci桥必须保证这种读操作可以刷新写操作。但问题是,没有多少芯片设计者愿意提供这种机制,因为这将极大地增加他们的设计难度。除此之外,使用这种方法也将增加中断请求的延时。
(2)中断服务程序在使用“pci设备写入存储器”的这些数据之前,需要对这个pci设备进行读操作。这个读操作也可以强制将数据最终写入存储器。这种方法也是利用了pci总线的传送序规则,与第1种方法类似。只是这种方法使用软件方式,而第1种方式使用硬件方式。这是绝大多数处理器系统采用的方法。在中断服务程序中,往往都是先读取pci设备的中断状态寄存器,判断中断产生原因之后,才对pci设备写入的数据进行操作。这个读取中断状态寄存器的过程,一方面可以获得设备的中断状态,另一方面可以保证dma写的数据(在被cpu读取前)已经到达存储器。
pci配置空间中的几个寄存器的作用
(1)cache line size寄存器:记录host处理器使用的cache line长度。在pci总线中和cache相关的总线事务,如存储器写并无效和cache多行读等总线事务需要使用这个寄存器。该寄存器由系统软件设置,但是在pci设备的运行过程中,只有其硬件逻辑才会使用该寄存器。对于pcie设备,该寄存器的值无意义,因为pcie设备在进行数据传送时,在其报文中含有一次数据传送的大小,pcie总线控制器可以使用这个“大小”,判断数据区域与cache line的对应关系。
(2)interrupt line寄存器:由系统软件对pci设备进行配置时写入,记录当前pci设备使用的中断向量号。设备驱动程序可以通过这个寄存器,判断当前pci设备使用处理器中的哪个中断向量号,并将驱动程序中的中断服务例程注册到操作系统中。但是,目前在绝大多数处理器系统中,并没有使用该寄存器存放pci设备使用的中断向量号。
(3)base address register 0~5 寄存器:简称为bar寄存器。保存的是pci设备在pci总线域中的基地址,由操作系统配置。在pci设备复位之后,该寄存器将存放pci设备需要使用的基址空间大小、这段空间是i/o空间还是存储器空间、如果是存储器空间是否可预取等。
系统软件对pci总线进行配置时,先获取bar寄存器中的初始化信息,之后根据处理器系统的配置,将合理的基地址写入相应的bar寄存器中。系统软件还可以使用该寄存器获得pci设备使用的bar空间的长度,方法是向bar寄存器中写入0xffffffff,然后再读取该寄存器。
(4)command寄存器:在初始化时,其值为0,此时这个pci设备除了能够接收配置请求总线事务外,不能接收任何存储器或者i/o请求。在linux系统中,设备驱动程序调用pci_enable_device函数(也可以是pci_enable_device_mem-> pci_enable_device_flags-> do_pci_enable_device-> pcibios_enable_device-> pci_enable_resources-> pci_write_config_word),使能该寄存器的i/o和memory space位之后,才能访问该设备的存储器或者i/o地址空间。
另外,该寄存器中还有bus master位表示该设备是否可以作为主设备(linux驱动程序中调用pci_set_master函数,将此位设置为1,表示设备可作为master)。寄存器中的interrupt disable位默认为0,为1时表示不允许该设备使用intx信号提交中断请求,当pci设备使用msi中断方式时,该位将被设置为1(linux驱动程序中调用的函数为pci_alloc_irq_vectors-> pci_alloc_irq_vectors_affinity-> __pci_enable_msi_range-> msi_capability_init-> pci_intx_for_msi-> pci_intx)。
linux的pci设备驱动程序中调用的dma_set_mask_and_coherent函数有什么作用
linux的pci设备驱动中一般都会调用诸如dma_set_mask_and_coherent(dev, dma_bit_mask(64))之类的接口。这是用来通知内核当前设备支持的dma访问的寻址能力,作用是限制内核为当前设备分配的内存地址范围。比如之前的例子就表示当前设备支持64位寻址,并且在此范围内支持一致性dma访问。
linux的pci设备驱动程序中调用的pci_disable_link_state函数有什么作用
有些pci设备的驱动中会调用诸如pci_disable_link_state(pdev, pcie_link_state_l0s | pcie_link_state_l1 | pcie_link_state_clkpm)之类的接口。其作用是设置pcie设备的扩展配置空间中的link control寄存器。具体到前例,是把link control寄存器中的“aspm control”字段和“enable clkreq”字段设置为0,作用分别是禁止pci设备进入l0s和l1(低功耗)状态以及禁止clkreq功能(相当于禁止设备的时钟管理功能,起到性能优先的效果,不考虑省电;具体效果还取决于内核中config_pcieaspm_xxxx相关的配置)。
纳米电池组成_纳米电池充放电原理
将数据存储到身体?下一代的存储容器也许会是DNA
电机内磁场的增磁和去磁控制
科大飞讯公布财报有大幅度上涨
中国电信5G试点首定六大城市,5G步入新阶段
PCI Express体系结构导读笔记之寄存器和配置
是USB也是摄像头的神奇“眼睛”
两岸共谋做大TD-SCDMA 时机成熟将在台测试
新能源的下一个风口,钛酸锂电池是锂电池里的“奇葩”
阿里云Teambition待办全新升级,增加了哪些新功能
4mA至20mA电流环路将消失?
新玩家们跨界参与对于整个汽车市场竞争格局会带来哪些变化?
小米11屏幕采用钻石排列
华为P10/Plus确认屏幕规格 全部前置指纹识别并搭载麒麟960!
软件定义超构光学元件未来发展方向
分布式存储集群设计,集群网络规划方案
工业I/O加上软件可配置,解决控制网络升级阵痛
健身房中的智能镜子可让更多人感受到智能的魔力
消费总线电力线接口电路的设计
arduino如何停止loop循环