当前位置:Linux教程 - Linux - LINUX核心之 (第六章)

LINUX核心之 (第六章)



         第 6 章 PCI

    Peripheral Component Interconnect(PCI),外设部件连接,是一个标准,描述的是如何将一个系统中
    的外设以一种结构化的,可控制化的方式连接在一起。PCI标准刻划了系统外设部件连接的电气方案,
    和在该标准下外设部件的行为归约。本章探讨Linux核心如何初始化系统的PCI总线和PCI设备。


    图6.1 基于PCI总线的系统


    图6.1是一个基于PCI总线系统的例子的逻辑框图。PCI总线和PCI桥负责将系统中的部件连接在一起。
    CPU连在PCI总线0;在主PCI总线(PCI 0)上挂着视频设备。PCI-PCI桥,一个特殊的PCI设备将主PCI
    总线于次PCI总线(PCI 1)相连。用PCI归约的术语来讲,PCI总线1被称作PCI-PCI桥的downstream,
    PCI总线0叫做桥的upstream。在第二个PCI总线上,是系统的SCSI和Ethernet设备。这个PCI-PCI桥,
    第二个PCI总线和其上的两块设备在物理上都可以在一个PCI卡上。系统中的PCI-ISA桥支持ISA设备。
    上图所示ISA总线下挂着一个多功能I/O控制器,控制系统的键盘,鼠标器和软驱。

    6.1 PCI地址空间

    CPU与PCI设备需要存取在它们之间共享的内存。设备驱动程序使用这片内存来控制PCI设备并用来传
    送信息。一般而言,这些共享内存中包含设备的控制和状态寄存器。这些寄存器用来控制设备和读
    取设备的状态。例如,PCI SCSI设备驱动程序读取SCSI设备的状态寄存器以探测该设备是否已就绪
    可以将一个数据块写入SCSI磁盘。又例如,设备驱动程序可以在控制寄存器中写入控制数据从而使
    设备开始运转在设备电源被开启之后。

    上述的共享内存可以是CPU的系统内存。但如果这样的话,每次PCI设备存取内存时,CPU将被阻塞,
    等待PCI设备存取的结束。一般而言,在某个特定时刻,只能一个系统部件存取一个特定的内存。
    所以,上述方法会使系统性能降低。另外,允许系统的外设不在一个良好的控制下存取主内存不
    是一个好的方法。这将会是非常危险的事情。一个“淘气”的设备可以使得系统非常不稳定。

    因此,外设一般拥有它们自己的内存空间。CPU可以存取这个空间。但是反之外设存取系统内存必须
    在DMA(Direct Memory Access)的控制之下。ISA设备可以存取两种地址空间,ISA I/O(Input/Output
    )和ISA memory。PCI可以有三种:PCI I/O,PCI memory和PCI Configuration空间。所有的这些地址
    空间都可以被CPU所存取。其中设备驱动程序要使用PCI I/O和PCI memory空间。Linux核心中的PCI初
    始化代码要用到PCI Configuration空间。

    6.2 PCI 配置头(Configuration Header)


    图6.2 PCI Configuration Header (配置头)


    系统中的每个PCI设备,包括PCI-PCI桥,都有一个配置数据结构在PCI Configuration地址空间中。
    这个PCI Configuraton Header(配置头)被系统用来定位和控制一个设备。至于这个数据结构具体
    位于PCI Configuration空间的何处,依赖于设备位于PCI拓朴结构中的位置。例如,一个PCI视频
    (Video)卡插在PCI 母板(motherboard)上的一个PCI槽中,它的数据配置头结构将会在一个地方;
    如果被插在另一个地方,其数据配置头将会位于PCI Configuration空间中的另外一个地方。当然,
    这没有关系。不论PCI设备和PCI桥在哪里,系统都将检测到,并使用它们的配置头中的状态和配置
    寄存器来对它们进行配置。

    一般来讲,每个PCI插槽的PCI配置头都位于在PCI Configuration空间的一个偏移量(Offset)处,
    这个偏移量是与每个PCI插槽的位置顺序相关的。例如,PCI板上的第一个PCI插槽的PCI配置在偏
    移量0;第二个PCI插槽的配置在偏移256处(所有的配置头的大小是256个字节)。系统中提供一
    与硬件有关的机制,使得PCI配置代码可以试图检测在一个给定的PCI总线上所有可能的PCI配置
    头,从而知道哪个PCI插槽上目前有设备,哪个插槽上暂无设备。这是通过读取配置头上的某个
    域而完成的(一般是“Vendor Identification\" 域)。如果一个插槽上为空,上述操作会返回一些
    错误返回值,如0xFFFFFFFF。

    图6.2所示的是一个完整的256字节的PCI配置头数据结构。它包含下列数据域:

    Vendor Identification(厂商标识)
    一个唯一的数字标识描述一个PCI设备的出处。Digital的PCI厂商标识是
    0x1011; Intel的是0x8086。
    Device Identification(设备标识)
    一个唯一的数字标识用来描述一个设备。例如Digital的21141快速Ethernet
    网卡有一个设备标识0x0009。
    Status(状态)
    这个域给出一个设备的状态。这个域的每个位的含义是由一个标准来定义的。
    Command(命令)
    系统通过在这个域中写入数据来控制设备。例如,让设备存取PCI I/O空间。
    Class Code(设备类代码)
    这个域用来标定一个设备的类型。每一种设备都对应一个标准的类。
    如video(视频),SCSI等等。SCSI设备的类码是0x0100。
    Base Address Registers(基地址寄存器)
    这些寄存器用来决定和分配一个设备可用的存储空间类型
    (如,PCI I/O和PCI memory)大小和位置。
    Interrupt Pin(中断管脚)
    在每个PCI卡上,有4个物理管脚可以传送中断信号到PCI总线上。其标准的
    标号是A,B,C和D。这个”Interrupt Pin\"域描述的是这个PCI设备正在用
    那个物理中断管脚。通常来讲,对一个特定的设备,其使用的中断管脚是
    被固定好的。也就是说,每次系统重新启动时,该设备使用同样的中断管
    脚。这个信息使得中断处理子系统知道如何管理这个设备的中断。
    (译者注:请参阅中断处理章节。注意PCI设备于ISA设备在中断方面的区别)
    Interrupt Line(中断线)
    设备的PCI配置头数据结构的\"Interrupt Line\"域用来在PCI初始化代码,
    设备驱动程序和Linux中断处理子系统之间传递一个中断处理。这个域中的
    值对于设备驱动程序而言是无意义的,但其可以使得中断例程正确地将一个
    中断从一个PCI设备传递(route)到Linux中相应的设备驱动程序的中断处理
    代码中。请参阅第七章关于Linux如何处理中断。

    6.3 PCI I/O 和PCI Memory 地址

    设备使用这两种地址空间来与其在Linux核心中运行的设备驱动程序进行通信。例如,
    DECchip 21141 快速Ethernet设备映射其内部寄存器到PCI I/O地址空间中。从而其设备驱动程
    序可以读和写这些寄存器来控制该设备。Video驱动器经常使用大量的PCImemory空间来存放视
    频信息。

    在PCI系统初始化完成,使用上述的”command“命令允许设备存取地址空间之前,系统不能存取
    这块地址。值得注意的是只有PCI配置代码才读和写PCI Configuration地址。Linux设备驱动程
    序只能读和写PCI I/O和PCI memory地址空间。

    6.4 PCI-ISA桥

    PCI-ISA桥通过将对PCI I/O和PCI memory地址空间的存取转换到对ISA I/O和ISA memory地址空间
    的存取来支持对ISA设备的支持。许多系统中含有一些ISA总线槽和几个PCI总线槽。随着时间的推
    移,这种为了向后兼容的机器配置将会消失。系统将会只支持PCI系统。在ISA地址空间中(ISA
    I/O和ISA memory),系统中的ISA设备的寄存器地址被固定在某个地方(自从早期的Intel 8080 PC开
    始)。例如,一个$5000的基于Alpha AXP的计算机的软盘控制器与早期的IBM PC的在ISA地址空间中
    占据的是同一片地址。PCI归约(Specification)通过在PCI I/O 和PCI memory地址空间的低端为
    ISA外设的使用保留一片区域并通过PCI-ISA桥来将对这片保留的PCI地址空间的存取映射到对系统中
    ISA地址的存取上。(译者注:细心的读者不难发现,这种通过加”Layer\",或“映射”的方法在计算
    机软硬件系统中几乎无处不见。系统就是这样一层一层的抽象出更高的概念提供给更高的层使用,
    直到用户层,从而使得一切细节的复杂性变的越来越透明。)

    6.5 PCI-PCI桥

    PCI-PCI桥是一种特殊的PCI设备。它将系统中的PCI总线粘合作一起。简单的系统只有通常一个PCI总
    线。一个PCI总线上可支持的PCI设备的数目是有限的。使用PCI-PCI桥可以解决上述问题,允许将更
    多的PCI总线加入系统从而支持更多的PCI设备。这对于高性能的服务器来说是非常重要的。Linux全
    面地支持PCI-PCI桥机制。

    6.5.1 PCI-PCI桥:PCI I/O 和PCI memory 窗口

    PCI-PCI桥只负责传递一部份对PCI I/O和PCI memory读和写的请求到downstream(请参见第一节)。例
    如,图6.1中,仅当读和写请求中的PCI I/O或PCI memory地址属于PCI-PCI桥SCSI或Ethernet设备时
    PCI-PCI桥才将这些总线上的请求从PCI总线0传递到PCI总线1。其他的将被忽略。这种过滤机制可以
    避免地址在系统中没必要的繁衍。为了做到这点,每个PCI-PCI桥必须正确地被设置好它所负责的PCI
    I/O和PCI memory地址的起始和大小。当一个读或写请求落在其负责的范围之内,这个请求将被映射到
    次一级的PCI总线上。系统中的PCI-PCI桥一旦设置完毕,如果Linux中的设备驱动程序存取的PCI I/O
    和PCI memory地址只在这些窗口之内,这些PCI-PCI桥是不可见的(译者注:窗口在这里的含义是指每
    个PCI-PCI桥都仅负责一定范围的空间映射;上述原文是:\"Once the PCI-PCIBridges in a system
    have been configured then so long as the Linux device drivers only access PCI I/O and PCI
    Memeory space via these windows, the PCI-PCI Bridges are invisible.\")。这是个很重要的特性
    使得Linux PCI设备驱动程序开发者的工作容易些。然而,这也使得Linux配置PCI-PCI桥变的有点迷惑。
    我们将在下面的章节中看到这一点。

    6.5.2 PCI-PCI桥:PCI配置周期(Configuration Cycles)和PCI总线计数方法(Bus Numbering)


    图6.3 PCI配置周期类型0


    图6.4 PCI配置周期类型1


    既然CPU的PCI初始化代码可以存取那些不在主PCI总线上的设备,那么必须存在一个机制使得这些桥能
    够判断是否将一个PCI配置周期从它们的(译者住:它们指的是PCI-PCI桥设备)主接口传递它们的次接口。
    所谓一个“周期”指的是一个出现在PCI总线上的一个地址。PCI归约(Specification)定义了两种PCI配
    置寻址格式;类型0和类型1。图6.3和图6.4所示分别是这两种寻址类型。PCI配置周期类型0中不含有总
    线号码,被所有的设备当作针对当前这个PCI总线上的PCI配置周期。类型0地址中的31-11位被用来作为
    设备选择域。一种设计方案是每一位对应一个设备。在这种情况下,位11表示插槽0上的PCI设备。位12
    表示插槽2上的PCI设备并以此类推。另一种方法是直接地将设备的插槽号码写入位31-11中。具体采用
    哪种机制依赖于系统的PCI存储控制器(memory controller)。

    类型1的PCI配置周期地址中含有一个PCI总线号码。当这种类型的配置周期(或命令)出现在一个PCI总线
    上时,除了PCI-PCI桥之外,所有其他的PCI设备会将其忽略。所有”看见“配置命令类型1的PCI-PCI桥
    可能选择将类型1的配置周期传递到其downstream PCI总线上或忽略之。选择的决定依赖于PCI-PCI桥的
    配置。没一个PCI-PCI桥有一个主PCI总线接口号和一个第二PCI总线接口号。主总线接口是那个离CPU更
    近的;第二总线接口是那个离CPU较远的。每个PCI-PCI桥还拥有一个次级总线号码。这个数目代表着在
    这个PCI-PCI桥第二总线接口之下的所有PCI总线中的最大数。换种方式讲,这个次级总线数目是这个
    PCI-PCI桥的PCI总线downstream的最大数目。当一个PCI-PCI桥看见一个类型1 PCI配置周期时,桥的行
    为如下:

    * 忽略这个命令,如果指定的总线号码不在第二和次级总线号码之间。(包含边界值)

    * 将其转换成类型0配置命令,如果指定的总线号码是桥的第二级总线接口。

    * 将其(原封不动地)传递到第二级总线接口,如果指定的总线号码大于该桥的第二总线号
    但小于或等于次级总线号。

    因此,如果我们想访问在图6.9中总线3上的设备1,我们必须从CPU产生一个类型1的PCI配置命令。桥1
    将原封不动地将此命令传递到总线1;桥2将忽略此命令,但桥3将接受这个命令并将其转换成一个类型0
    的配置命令,然后发送到设备1所在的PCI总线3上。

    关于在PCI配置期间如何分配总线号码依赖于具体的操作系统。然而不论什么样的分配方案,对系统中所
    有的PCI-PCI桥来说,必须满足下列要求:

    ”在PCI-PCI桥后面的所有PCI总线的编号必须在该桥的第二总线接口号码和次级总线号码之间“

    如果违反这个规则,PCI-PCI桥将不会正确地传递和翻译类型1的PCI配置命令。系统将不能正确地发现和
    初始化系统中的PCI设备。为了完成这个赋值方案,Linux依照一个特殊的顺序来配置这些PCI设备。
    从图6.6开始我们描述了Linux PCI桥和总线的号码赋值方案。并举出了一个例子。

    6.6 Linux PCI初始化

    Linux PCI 初始化代码逻辑上分为三个部份:

    PCI设备驱动程序
    这个伪设备驱动程序从总线0开始查询PCI系统并且定位系统中所有的PCI设备和桥。它建立一个
    可以用来描述这个PCI系统拓朴层次的数据结构链表。并且对所有的发现的桥编码。

    PCI BIOS
    这个软件层提供在bib-pci-bios归约中描述的服务。虽然Alpha AXP不提供BIOS服务,在其Linux
    版本中包含了相应的功能。

    PCI Fixup
    与特定系统相关的PCI初始化修补代码

    6.6.1 Linux核心的PCI数据结构


    图6.5 Linux 核心PCI数据结构


    当Linux核心初始化PCI系统时,它建立一些可以描述系统PCI拓朴的数据结构。图6.5所示是反映图6.1系统
    的数据结构之间的关系。

    每一个PCI设备(包括PCI-PCI桥)用一个pci_dev数据结构来描述。每个PCI总线用一个pci_bus结构来描述。
    这样的结果是产生了一个PCI总线树状关系结构。每个PCI总线结构pci_bus下挂着在该总线上的PCI设备。
    因为除了主PCI总线,总线0,PCI总线只能通过PCI-PCI桥来存取,每个pci_bus中含有一个指向其上的PCI
    设备(PCI桥)的指针(这些设备pci_bus结构用链表连在一起,如图6.5)。一个PCI设备是其”父“PCI总线的
    ”孩子“。(请注意图6.5中指针children)

    图6.5中没有显示出来的一个指针是pci_devices。它用来指向系统中所有的PCI设备。系统中所有的PCI设
    备将其pci_dev数据结构加入到这个队列中。这个队列被Linux核心用来快速查找系统中的PCI设备。

    6.6.2 PCI设备驱动程序

    PCI设备驱动程序并不是真正的,严格意义上的驱动程序。它是在系统初始化时被调用的一个操作系统函数。
    PCI初始化代码必须扫描系统中所有的PCI总线,寻找系统中所有的PCI设备(包括PCI-PCI桥设备)。

    它使用PCI BIOS代码来发现它正在扫描的PCI总线上的每个插槽上是否已有设备安装。如果在一个插槽上发现
    了一个设备,一个用来描述该设备的pci_dev数据结构将被创建并且加入到被pci_devices所指向的队列中。

    PCI初始化代码从PCI总线0开始扫描。它通过读取”Vendor Identification\"和\"Device Identification\"
    来试图发现每一个插槽上的设备(请参阅6.2)。

    如果发现了一个PCI-PCI桥,则创建一个pci_bus数据结构并且连入到由pci_root指向的pci_bus和pci_dev
    数据结构组成的树中。PCI初始化代码通过设备类代码0x060400来判断一个PCI设备是否是PCI-PCI桥。然后,
    Linux核心开始构造这个桥设备另一端的PCI总线和其上的设备。如果还发现了桥设备,就以同样的步骤来
    进行构建。这个处理过程称之为深度优先算法。系统的PCI拓朴在广度查询之前,先进行深度优先查找。
    请参阅图6.1,由上述算法可知,在构造PCI总线0上的Video设备之前,Linux将首先构造PCI总线1和其上的
    Ethernet和SCSI设备(译者注:这里的前提是:图6.1中PCI-PCI桥所在的插槽号码小于video卡所在的PCI插
    槽的号码)

    当Linux查询downstream PCI总线时,它必须构造PCI-PCI桥的第二级和次级总线编号的号码。下面我们将对
    此进行相信描述。

    构造PCI-PCI桥---对PCI总线号码进行赋值


    图6.6构造一个PCI系统:第一步


    PCI-PCI桥要想正确传递对PCI I/O,PCI Memory或PCI Configuration地址空间的读和写请求,必须知道下
    列信息:

    Primary Bus Number(主总线号)
    该PCI-PCI桥的紧接的upstream总线的编号。
    Secondary Bus Number(第二级总线号)
    该PCI-PCI桥的紧接的downstream总线的编号。
    Subordinate Bus Number(次级总线号)
    该桥的downstream总线中最大的总线编号。
    PCI I/O 和 PCI Memory 窗口
    对于该桥的所有downstream地址中的PCI I/O和PCI Memory地址空间的窗口的基址和大小。

    存在的问题是当你想要配置一个PCI-PCI桥的时候,你不知道这个桥的次级总线接口号码。你不知道该桥下
    是否还有其他的PCI-PCI桥。即使你知道,也不清楚如何对它们进行赋值。解决方案是利用上述讲过的深度
    递归算法来扫描每个总线。每当发现PCI-PCI桥就对它们进行赋值。当发现一个PCI-PCI桥时,它的第二级
    PCI总线接口号可以被确定。然后我们暂时先将其次级总线接口号赋值为0xFF。紧接着,开始扫描该
    PCI-PCI桥的downstream桥。这个过程看起来有点复杂。但下面的例子将给出清晰的解释。

    PCI-PCI桥的赋值--第一步

    以图6.6的拓扑结构为例,扫描时首先发现的桥是Bridge1(桥1)。桥1的downstream PCI总线号码被赋值1。
    自然该桥的第二级总线号码也是1。其次级总线号码被暂时赋值为0xFF。上述赋值的含义是所有类型1的
    含有PCI总线1或更高(<255)的号码的PCI配置地址将被桥1传递到PCI总线1上。如果PCI总线号是1,桥1
    还负责将配置地址的类型转换成类型0。否则,就不做转换。上述动作就是开始扫描总线1时Linux初始化
    代码所完成的对总线0的配置工作。


    图6.7 构造一个PCI系统:第二步


    PCI-PCI桥的赋值--第二步

    Linux使用深度优先算法进行扫描。所以初始化代码开始扫描总线1。从而PCI-PCI桥2被发现。因为在桥2
    下面不再发现有PCI-PCI桥,所以桥2的次级总线号是2,等于它的第二总线接口号。图6.7显示了在这个时刻
    总线和PCI-PCI桥的赋值情况。


    图6.8 构造一个PCI系统:第三步


    PCI-PCI桥的赋值--第三步

    PCI初始化代码从总线2的扫描中回来接着进行扫描总线1。这时,另外一个PCI-PCI桥,桥3,被发现。它的
    主总线号被赋值为1;第二级总线号为3。因为总线3上还发现了桥,所以桥3的次级总线号被暂时赋值0xFF。
    图6.8显示了这个时刻系统配置的状态。到目前为止,含有总线号1,2和3的类型1PCI配置周期都可以被正确
    地传送到相应的总线上。


    图6.9 构造一个PCI系统:第四步


    PCI-PCI桥的赋值--第四步

    现在Linux开始扫描PCI总线3,桥3的downstream.PCI总线3上有另外一个PCI-PCI桥,桥4。因此桥4的主总线
    号的值为3。第二总线号为4。由于桥4下面没有别的桥设备,所以桥4的次级总线号为4。然后初始化代码回到
    PCI-PCI桥3。这时就将桥3的次级总线号从0xFF改为4,表示总线4是从桥3往下走的最远的PCI-PCI桥。最后,
    PCI初始化代码将4以同样的道理赋值给桥1的次级总线号。图6.9反映了系统最后的状态。

    6.6.3 PCI BIOS函数

    PCI BIOS函数是一些在所有平台上都通用的一些标准例程。例如,对于Intel和Alpha AXP系统,它们都一样。
    BIOS函数的存在使得CPU可以存取所有的PCI地址空间。

    只有Linux核心代码和设备驱动程序可以使用这些函数。

    6.6.4 PCI Fixup(补充或修补)

    相对于Intel系统,Alpha AXP系统的PCI fixup代码要作更多的事情。对于Intel系统,基本上PCI fixup
    什么也不做。

    对于Intel系统,系统的BIOS在启动时,已经基本上将PCI系统构造好了。这使得Linux只需将配置映射过来
    就好了。对于非Intel系统,Linux还需做如下构建:

    *为每个PCI设备分配PCI I/O和PCI Memory空间。
    *为系统中的每个PCI-PCI桥,配置相应的PCI I/O和PCI Memory地址窗口。
    *为每个设备的配置头产生“Interrupt Line\"值;这些值控制设备的中断处理。

    下面我们讲述上述行为的实现。

    查询设备所需的PCI I/O和PCI Memory空间大小

    系统对每个找到的PCI设备查询设备所需的PCI I/O和PCI Memory空间大小。为了做到这一点,每个基址
    寄存器先全写入1然后再读。设备将在没有用的位上返回0值。从而我们可以得知地址空间的大小。


    图6.10 PCI配置头:基地址寄存器


    基地址寄存器分两种类型,以表示一个寄存器是位于PCI I/O空间或PCI Memory空间。这是通过寄存器的位
    0来设置的。图6.10所示是对应于PCI I/O和PCI Memory的两种形式的基址寄存器。

    为了探测一个给定的基地址寄存器要申请的地址空间的大小,可以通过上述先向寄存器写入全1然后再读取
    的方法。返回值即是该基地址寄存器所申请的空间大小。这种设计还保证了所有的地址空间都是2的幂数从
    而且是自然对齐的。

    例如当初始化DECChip 21142 PCI快速Ethernet设备时,我们会知道它需要0x100字节的PCI I/O或PCI Memory
    空间。Linux PCI初始化代码将负责分配这片内存。然后,21142的控制和状态寄存器就可以在这些地址上被
    访问。

    为PCI-PCI桥和PCI设备分配PCI I/O和PCI Memory空间

    象所有的存储空间一样,PCI I/O和PCI Memory空间也是非常有限的,或稀少的。PCI Fixup代码必须非常
    有效地为每个设备分配其申请的空间。PCI I/O和PCI Memory必须以自然对齐的方式来被分配。例如,如果一
    个设备申请0xB0字节的PCI I/O空间,它必须对齐在一个是0xB0倍数的地址上。另外,对任何一个桥,其所需
    要的PCI I/O和PCI Memory必须分别对齐4K和1M的边界。由于一个桥的所有的downstream设备的地址空间都必
    须位于PCI-PCI桥的地址空间内,所以有必要提供一个有效的算法来进行控制。

    Linux使用的算法依赖于由PCI设备驱动程序建立的总线/设备树状数据结构中的每个设备分配的空间。空间
    是朝上增长的。系统使用一个递归算法来扫描pci_bus和pci_dev数据结构。扫描从PCI总线的根开始
    (其指针是pci_root)。具体的行为如下:

    *分别依照4K和1M字节的边界,调整当前的PCI I/O和PCI Memory的基址。

    *对当前总线上的每个设备:
    。分配PCI I/O和Memory空间
    。相应调整全局的PCI I/O和PCI Memory基址
    。使能(enable)设备使用被分配的空间

    *递归地对该总线下面的所有总线进行空间分配。注意这会改变PCI I/O和PCI Memory基址。

    *分别依照4K和1M字节的边界,调整当前的PCI I/O和PCI Memory的基址。并且计算出当前
    PCI-PCI桥的PCI I/O和PCI Memory空间窗口的基址和大小。

    *将上一步骤计算出来的值对当前的PCI桥进行赋值。

    *打开桥的对PCI I/O和PCI Memory地址过滤功能。这意味着如果一个在桥的主总线上的对
    PCI I/O和PCI Memory 地址的寻址落在这个桥的PCI I/O和PCI Memory窗口内,该寻址指令
    将被传递到桥的第二级总线上。

    以图6.1 PCI系统为例,我们给出PCI Fixup代码的工作如下:

    校准PCI基址

    PCI I/O在0x4000; PCI Memory在0x100000。这使得PCI-ISA桥将接受所有低于这些值的寻址,作为ISA寻
    址周期。

    Video 设备

    这个设备需要0x200000字节的PCI Memory。因为为了和要求的空间大小对齐,我们从0x20000地址开始
    分配0x200000空间。PCI Memory的基址移到0x400000。PCI I/O的基址还是0x4000。

    PCI-PCI桥

    现在碰到了PCI-PCI桥并对其分配PCI内存。 注意在这里我们不需要调整基地址。

    Ethernet 设备

    该设备为其PCI I/O和PCI Memory空间各要求0xB0字节。在PCI Memory的基址0x400000和PCI I/O的基址
    0x4000的基础上进行分配。结果是PCI I/O基址的值为0x40B0。PCI Memory基址为0x4000B0。

    SCSI 设备

    该设备要求0x1000 PCI Memory空间。系统依照对齐的要求,在0x401000的基础上开始分配。从而PCI
    Memory的基址被调整至0x402000。PCI I/O的基址不变。

    PCI-PCI桥的PCI I/O和PCI Memory 窗口

    现在来设置桥的PCI I/O和PCI Memory的窗口大小。PCI I/O的窗口在0x4000与0x40B0之间。
    PCI Memory的窗口在0x400000与0x402000之间。这将使得桥总线上忽略对Video的寻址,而将传递对
    SCSI和Ethernet的寻址。



    发布人:netbull 来自:linuxeden