在PCI Agent设备进行数据传送之前,系统软件需要初始化PCI Agent设备的BAR0~5寄存器和PCI桥的Base、Limit寄存器。系统软件使用DFS算法对PCI总线进行遍历时,完成这些寄存器的初始化,即分配这些设备在PCI总线域的地址空间。当这些寄存器初始化完毕后,PCI设备可以使用PCI总线地址进行数据传递。

值得注意的是,PCI Agent设备的BAR0~5寄存器和PCI桥的Base寄存器保存的地址都是PCI总线地址。而这些地址在处理器系统的存储器域中具有映像,如果一个PCI设备的BAR空间在存储器域中没有映像,处理器将不能访问该PCI设备的BAR空间。

如上文所述,处理器通过HOST主桥将PCI总线域与存储器域隔离。当处理器访问PCI设备的地址空间时,需要首先访问该设备在存储器域中的地址空间,并通过HOST主桥将这个存储器域的地址空间转换为PCI总线域的地址空间之后,再使用PCI总线事务将数据发送到指定的PCI设备中。

PCI设备访问存储器域的地址空间,即进行DMA操作时,也是首先访问该存储器地址空间所对应的PCI总线地址空间,之后通过HOST主桥将这个PCI总线地址空间转换为存储器地址空间,再由DDR控制器对存储器进行读写访问。

不同的处理器系统采用不同的机制实现存储器域和PCI总线域的转换。如PowerPC处理器使用Outbound寄存器组实现存储器域到PCI总线域间的转换,并使用Inbound寄存器组实现PCI总线域到存储器域间的转换。

而x86处理器没有这种地址空间域的转换机制,因此从PCI设备的角度上看,PCI设备可以直接访问存储器地址;从处理器的角度上看,处理器可以直接访问PCI总线地址空间。但是读者需要注意,在x86处理器的HOST主桥中仍然有存储器域与PCI总线域这个概念。只是在x86处理器的HOST主桥中,存储器域的存储器地址与PCI总线地址相等,这种“简单相等”也是一种映射关系。

3.1.1 存储器地址与PCI总线地址的转换

下文根据PowerPC和x86处理器的主桥,抽象出一个虚拟的HOST主桥,并以此为例讲述PCI Agent设备之间,以及PCI Agent设备与主存储器间的数据传送过程。

我们假设在一个32位处理器中,其存储器域的0xF000-0000~0xF7FF-FFFF(共128MB)这段物理地址空间与PCI总线的地址空间存在映射关系。

当处理器访问这段存储器地址空间时,HOST主桥将会认领这个存储器访问,并将这个存储器访问使用的物理地址空间转换为PCI总线地址空间,并与0x7000-0000~0x77FF-FFFF这段PCI总线地址空间对应。

为简化起见,我们假定在存储器域中只映射了PCI设备的存储器地址空间,而不映射PCI设备的I/O地址空间。而PCI设备的BAR空间使用0x7000-0000~0x77FF-FFFF这段PCI总线域的存储器地址空间。

在这个HOST主桥中,存储器域与PCI总线域的对应关系如图3?1所示。


当PCI设备使用DMA机制,访问存储器域地址空间时,处理器系统同样需要将存储器域的地址空间反向映射到PCI总线地址空间。假设在一个处理器系统中,如果主存储器大小为2GB,其在存储器域的地址范围为0x0000-0000~0x7FFF-FFFF,而这段地址在PCI总线域中对应的“PCI总线地址空间”为0x8000-0000~0xFFFF-FFFF。

因此PCI设备进行DMA操作时,必须使用0x8000-0000~0xFFFF-FFFF这段PCI总线域的地址,HOST主桥才能认领这个PCI总线事务,并将这个总线事务使用的PCI总线地址转换为存储器地址,并与0x0000-0000~0x7FFF-FFFF这段存储器区域进行数据传递。

在一个实际的处理器系统中,很少有系统软件采用这样的方法,实现存储器域与PCI总线域之间的映射,“简单相等”还是最常用的映射方法。本章采用图3?1的映射关系,虽然增加了映射复杂度,却便于读者深入理解存储器域到PCI总线域之间的映射关系。下文将以这种映射关系为例,详细讲述PCI设备BAR0~5寄存器的初始化。

3.1.2 PCI设备BAR寄存器和PCI桥Base、Limit寄存器的初始化

PCI桥的Base、Limit寄存器保存“该桥所管理的PCI子树”的存储器或者I/O空间的基地址和长度。值得注意的是,PCI桥也是PCI总线上的一个设备,在其配置空间中也有BAR寄存器,本节不对PCI桥BAR寄存器进行说明,因为在多数情况下透明桥并不使用其内部的BAR寄存器。下文以图3?2所示的处理器系统为例说明上述寄存器的初始化过程,该处理器系统使用的存储器域与PCI总线域的映射关系如图3?1所示。


在PCI设备的BAR寄存器中,包含该设备使用的PCI总线域的地址范围。在PCI设备的配置空间中共有6个BAR寄存器,因此一个PCI设备最多可以使用6组32位的PCI总线地址空间,或者3组64位的PCI总线地址空间。这些BAR空间可以保存PCI总线域的存储器地址空间或者I/O地址空间,目前多数PCI设备仅使用存储器地址空间。而在通常情况下,一个PCI设备使用2到3个BAR寄存器就足够了。

为简化起见,我们首先假定在图3?2中所示的PCI总线树中,所有PCI Agent设备只使用了BAR0寄存器,其申请的数据空间大小为16M字节(即0x1000000字节)而且不可预读,而且PCI桥不占用PCI总线地址空间,即PCI桥不含有BAR空间。并且假定当前HOST主桥已经完成了对PCI总线树的编号。

根据以上假设,系统软件该PCI总线树的遍历过程如下所示。

(1)      系统软件根据DFS算法,系统软件率先寻找到第一组PCI设备,分别为PCI设备31和PCI设备32[1],并根据这两个PCI设备需要的PCI空间大小,从PCI总线地址空间中(0x7000-0000~0x77FF-FFFF)为这两个PCI设备的BAR0寄存器分配基地址,分别为0x7000-0000和0x7100-0000。

(2)      当系统软件完成PCI总线3下所有设备的BAR空间的分配后,将初始化PCI桥3的配置空间。这个桥片的Memory Base寄存器保存其下所有PCI设备使用的“PCI总线域地址空间的基地址”,而Memory Limit寄存器保存其下PCI设备使用的“PCI总线域地址空间的大小”。系统软件将Memory Base寄存器赋值为0x7000-0000,而将Memory Limit寄存器赋值为0x200-0000。

(3)      系统软件回朔到PCI总线2,并找到PCI总线2上的PCI设备21,并将PCI设备21的BAR0寄存器赋值为0x7200-0000。

(4)      完成PCI总线2的遍历后,系统软件初始化PCI桥2的配置寄存器,将Memory Base寄存器赋值为0x7000-0000,Memory Limit寄存器赋值为0x300-0000。

(5)      系统软件回朔到PCI总线1,并找到PCI设备11,并将这个设备的BAR0寄存器赋值为0x7300-0000。并将PCI桥1的Memory Base寄存器赋值为0x7000-0000,Memory Limit寄存器赋值为0x400-0000。

(6)      系统软件回朔到PCI总线0,并在这条总线上发现另外一个PCI桥,即PCI桥4。并使用DFS算法继续遍历PCI桥4。首先系统软件将遍历PCI总线4,并发现PCI设备41和PCI设备42,并将这两个PCI设备的BAR0寄存器分别赋值为0x7400-0000和0x7500-0000。

(7)      系统软件初始化PCI桥4的配置寄存器,将Memory Base寄存器赋值为0x7400-0000,Memory Limit寄存器赋值为0x200-0000。系统软件再次回到PCI总线0,这一次系统软件没有发现新的PCI桥,于是将初始化这条总线上的所有PCI设备。

(8)      PCI总线0上只有一个PCI设备,PCI设备01。系统软件将这个设备的BAR0寄存器赋值为0x7600-0000,并结束整个DFS遍历过程。




[1] HOST主桥下的第一个桥片是PCI桥片1,PCI桥片1下的第一个桥片是PCI桥片2,而PCI桥片2下的第一个桥片是PCI桥片3,因而第一组PCI设备为PCI总线3下的PCI设备。不同的系统软件查找第一组PCI设备的方法不同,Linux认为第一组PCI设备为PCI总线0下的PCI设备。

3.1 PCI设备BAR空间的初始化的更多相关文章

  1. 008 PCI设备BAR空间的初始化

    一.PCI设备BAR空间的初始化 在PCI Agent设备进行数据传送之前,系统软件需要初始化PCI Agent设备的BAR0~5寄存器和PCI桥的Base.Limit寄存器.系统软件使用DFS算法对 ...

  2. 2.3 PCI桥与PCI设备的配置空间

    PCI设备都有独立的配置空间,HOST主桥通过配置读写总线事务访问这段空间.PCI总线规定了三种类型的PCI配置空间,分别是PCI Agent设备使用的配置空间,PCI桥使用的配置空间和Cardbus ...

  3. linux PCI设备初始化过程

    linux PCI设备初始化过程 start_kernel->rest_init 这个函数会启动一个核心线程0, 核心线程然后调用init -> do_basic_setup. 然后我们开 ...

  4. 3.3.3 PCI设备对可Cache的存储器空间进行DMA读写

    PCI设备向"可Cache的存储器空间"进行读操作的过程相对简单.对于x86处理器或者PowerPC处理器,如果访问的数据在Cache中命中,CPU会通知FSB总线,PCI设备所访 ...

  5. 3.3.2 PCI设备对不可Cache的存储器空间进行DMA读写

    在x86处理器和PowerPC处理器中,PCI设备对"不可Cache的存储器空间"进行DMA读写的过程并不相同.其中PowerPC处理器对"不可Cache的存储器空间&q ...

  6. 3.2 PCI设备的数据传递

    PCI设备的数据传递使用地址译码方式,当一个存储器读写总线事务到达PCI总线时,在这条总线上的所有PCI设备将进行地址译码,如果当前总线事务使用的地址在某个PCI设备的BAR空间中时,该PCI设备将使 ...

  7. PCI 设备详解二

    上篇文章主要从硬件的角度分析了PCI设备的特性以及各种寄存器,那么本节就结合LInux源代码分析下内核中PCI设备的各种数据结构以及相互之间的联系和工作机制 2016-10-09 注:一下代码参考LI ...

  8. PCI 设备详解一

    2016-10-09 其实之前是简单学习过PCI设备的相关知识,但是总感觉 自己的理解很函数,很多东西说不清楚,正好今天接着写这篇文章自己重新梳理一下,文章想要分为三部分,首先介绍PCI设备硬件相关的 ...

  9. 【DPDK】谈谈DPDK如何实现bypass内核的原理 其一 PCI设备与UIO驱动

    [前言] 随着网络的高速发展,对网络的性能要求也越来越高,DPDK框架是目前的一种加速网络IO的解决方案之一,也是最为流行的一套方案.DPDK通过bypass内核协议栈与内核驱动,将驱动的工作从内核态 ...

随机推荐

  1. 小白的.Net Core 2.0 ConsoleApp入门(keng)指南(一)

    一.准备工作 准备工作很简单,甚至可以不用Visual Studio,一只.NET CORE和Runtime即可(你有考虑过世界第一IDE的感受吗) 下载:https://www.microsoft. ...

  2. spark头脑镜像

    思考是一件有意思的事情.遇到问题,思考出结论,那么脑子里面的过程是什么呢,或者脑子里面是什么呢.我一直认为,这团团的里面是一个模糊的n维空间.理解一个复杂的系统.公式.算法,都要在这个n维空间里具象化 ...

  3. Python学习笔记(二):字典

    字典由多个键及与其对应的值构成的键值对构成,字典中键唯一,值不唯一. 1)dict 函数: >>>items=[('name','lilei'),('age',12)] >&g ...

  4. SpringMVC源码情操陶冶-HandlerAdapter适配器简析

    springmvc中对业务的具体处理是通过HandlerAdapter适配器操作的 HandlerAdapter接口方法 列表如下 /** * Given a handler instance, re ...

  5. 利用QuickCHM制作chm

    CHM是一种常见的帮助文件格式,也是电子书的一种格式. 下面是使用QuickCHM制作chm的步骤: 1.先将所有的word文档存储为mht格式,点击,文件--另存为网页,如下 2.确保所有的word ...

  6. BZOJ 4710: [Jsoi2011]分特产 [容斥原理]

    4710: [Jsoi2011]分特产 题意:m种物品分给n个同学,每个同学至少有一个物品,求方案数 对于每种物品是独立的,就是分成n组可以为空,然后可以用乘法原理合起来 容斥容斥 \[ 每个同学至少 ...

  7. Django搭建博客网站(四)

    Django搭建博客网站(四) 最后一篇主要讲讲在后台文章编辑加入markdown,已经在文章详情页对markdown的解析. Django搭建博客网站(一) Django搭建博客网站(二) Djan ...

  8. ES6 学习笔记之一 块作用域与let和const

    ---恢复内容开始--- 在学习ES6的块作用域和 let.const 之前,我们先来看看ES5以前的 var 关键字. var 关键字用于定义一个变量,通常我们会将其与变量的赋值合并为一条语句,就像 ...

  9. Swift iOS 日期操作:NSDate、NSDateFormatter

    1.日期(NSDate) // 1.初始化 // 初始化一个当前时刻对象 var now = NSDate() // 初始化一个明天当前时刻对象 var tomorrow = NSDate(timeI ...

  10. Ehcache入门基础

    1.ehcache的简介  EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvider. 2.ehcache入门实例 1.首先先导入 ...