pci 设备与其它接口的设备 (如 i2c 设备) 最大的不同是存在内存地址空间和配置地址空间
首先区分一下 IO 空间和内存空间
CPU 会访问的设备一般有内存和外设寄存器, 如下图所示. x86 架构采用独立编址将内存操作与外设 IO 操作分开了才有了内存空间和 IO 空间的区分, x86 平台 CPU 内部对内存和外设寄存器访问的指令也是不同的. ARM 等其他平台都采用统一编址, 不区分内存和外设的访问.
IO 空间: 访问外部设备寄存器的地址区域, x86 平台为 64k
内存空间: 访问内存的地址空间, 32 位平台为 4G
pci 设备的内存空间是怎么回事呢?
常见的设备都只提供寄存器供 CPU 访问, 对于低速外设这样的模式是足够的. 但是对于需要大量, 高速数据交互的外设就需要引入外设内存空间了. 在网卡, 显卡这样的 pci 高速外设中不仅有寄存器还有了一块内存.
配置空间和 IO 空间不都是外设的寄存器吗, 它们有什么区别呢?
IO 空间就和 i2c 设备的寄存器空间一样, 用来获取外设状态, 配置外设.
配置空间是一段特殊的 IO 空间, 它的作用是为外设内存空间, IO 空间分配物理地址基地址, 即配置 BAR(Base Address Registers). 这里类似 Linux 对虚拟地址的映射了, 但现在分配的却是物理地址. 因为外设内部的内存地址都是从 0 开始编址的, 当 pci 控制器接入多个 pci 设备时如何确保 pci 上的内存地址不混乱呢, 这就是配置空间的一个作用, 配置空间有固定的结构, 在 pci 总线扫描设备时配置好 BAR, 这样各个 pci 设备的内存空间和 IO 空间才可访问, 而不至于和其他设备物理地址冲突.
在 pci 总线之前的 ISA 总线是使用跳线帽来分配外设的物理地址的, 每插入一个新设备都要改变跳线帽以分配物理地址, 这是十分麻烦且易错的, 但这样的方式似乎我们更容易理解. 能够分配自己总线上挂载设备的物理地址这也是 PCI 总线相较于 I2C,SPI 等低速总线一个最大的特色.
为什么只有 pci 设备可以有外设内存空间, i2c,usb 等设备没有?
说起外设上可以有设备专属的内存时, 指的都是 pci 设备. 我们更为常用的 i2c,usb,spi,uart 设备怎么都没有这样的说法呢?
这是因为在 CPU 内部架构中会有系统总线和外设总线. 系统总线一般是连接 CPU 与主存的, 外设总线是 CPU 连接外部设备的. 在有 pci 控制器的 CPU 架构中 pci 总线就取代了 CPU 内部的外设总线的位置, 所有外设都是挂在不同层级的 pci 桥上的, 再由 pci 转成了 usb,i2c,uart 等接口. 因此 pci 设备相当于直接连在 CPU 总线上了, 这样 pci 设备中就可以拥有 CPU 总线上的物理地址, 和主存共享 CPU 的物理地址空间, 当然就可以存在外设内存(相当于 pci 设备与其他外设的控制器在一个层级上).i2c 等外设只能通过 i2c 控制器间接的与 CPU 通信, pci 设备拥有 CPU 的物理地址, 可以直接与 CPU 对话.
可简要理解为 pci 总线类似 CPU 内部总线的延伸, i2c,usb 等都仅仅是纯粹的外设总线, 社会层级不同.
来源: http://www.bubuko.com/infodetail-3204576.html