linux PCI 寻址
每个 PCI 外设有一个总线号, 一个设备号, 一个功能号标识. PCI 规范允许单个系统占 用多达 256 个总线, 但是因为 256 个总线对许多大系统是不够的, Linux 现在支持 PCI 域. 每个 PCI 域可以占用多达 256 个总线. 每个总线占用 32 个设备, 每个设备可以是 一个多功能卡(例如一个声音设备, 带有一个附加的 CD-ROM 驱动)有最多 8 个功能. 因 此, 每个功能可在硬件层次被一个 16-位地址或者 key , 标识. Linux 的设备驱动编写 者, 然而, 不需要处理这些二进制地址, 因为它们使用一个特定的数据结构, 称为 pci_dev, 来在设备上操作.
大部分近期的工作站至少有 2 个 PCI 总线. 在单个系统插入多于 1 个总线要通过桥实 现, 桥是特殊用途的 PCI 外设, 它的工作是连接 2 个总线. 一个 PCI 系统的全部分布 是一个树, 这里每个总线都连接到一个上层总线, 直到在树根的总线 0 . CardBus PC- card 系统也通过桥连接到 PCI 系统. 图一个典型 PCI 系统的布局表示了一个典型的 PCI 系统, 其中各种桥被突出表示了.
和 PCI 外设相关的 16-位硬件地址, 尽管大部分隐藏在 struct pci_dev 结构中, 仍然 是可偶尔见到, 特别是当使用设备列表. 一个这样的情形是 lspci 的输出( pciutils 的 一部分, 在大部分发布中都有)和在 /proc/pci 和 /porc/bus/pci 中的信息排布. PCI 设备的 sysfs 表示也显示了这种寻址方案, 还有 PCI 域信息. [40]当显示硬件地址时, 它 可被显示为 2 个值( 一个 8-位总线号和一个 8-位 设备和功能号), 作为 3 个值( bus, device, 和 function), 或者作为 4 个值(domain, bus, device, 和 function); 所有 的值常常用 16 进制显示.
例如, /proc/bus/pci/devices 使用一个单个 16-位 字段(来便于分析和排序), 而
/proc/bus/busnumber 划分地址为 3 个字段. 下面内容显示了这些地址如何显示, 只显 示了输出行的开始:
$ lspci | cut -d: -f1-3 0000:00:00.0 Host bridge
0000:00:00.1 RAM memory
0000:00:00.2 RAM memory
0000:00:02.0 USB Controller
0000:00:04.0 Multimedia audio controller 0000:00:06.0 Bridge
0000:00:07.0 ISA bridge
0000:00:09.0 USB Controller
0000:00:09.1 USB Controller
0000:00:09.2 USB Controller 0000:00:0c.0 CardBus bridge 0000:00:0f.0 IDE interface 0000:00:10.0 Ethernet controller
0000:00:12.0
Network controller
0000:00:13.0
FireWire (IEEE 1394)
0000:00:14.0 VGA
compatible controller
$
cat /proc/bus/pci/devices | cut -f1 0000
0001
0002
0010
0020
0030
0038
0048
0049
004a
0060
0078
0080
0090
0098
00a0
$ tree
/sys/bus/pci/devices/
/sys/bus/pci/devices/
|-- 0000:00:00.0
-> ../../../devices/pci0000:00/0000:00:00.0
|-- 0000:00:00.1
-> ../../../devices/pci0000:00/0000:00:00.1
|-- 0000:00:00.2
-> ../../../devices/pci0000:00/0000:00:00.2
|-- 0000:00:02.0 ->
../../../devices/pci0000:00/0000:00:02.0
|-- 0000:00:04.0
-> ../../../devices/pci0000:00/0000:00:04.0
|-- 0000:00:06.0
-> ../../../devices/pci0000:00/0000:00:06.0
|-- 0000:00:07.0
-> ../../../devices/pci0000:00/0000:00:07.0
|-- 0000:00:09.0
-> ../../../devices/pci0000:00/0000:00:09.0
|-- 0000:00:09.1
-> ../../../devices/pci0000:00/0000:00:09.1
|-- 0000:00:09.2
-> ../../../devices/pci0000:00/0000:00:09.2
|-- 0000:00:0c.0
-> ../../../devices/pci0000:00/0000:00:0c.0
|-- 0000:00:0f.0
-> ../../../devices/pci0000:00/0000:00:0f.0
|-- 0000:00:10.0
-> ../../../devices/pci0000:00/0000:00:10.0
|-- 0000:00:12.0
-> ../../../devices/pci0000:00/0000:00:12.0
|-- 0000:00:13.0
-> ../../../devices/pci0000:00/0000:00:13.0
`-- 0000:00:14.0
-> ../../../devices/pci0000:00/0000:00:14.0
所有的 3 个设备列表都以相同顺序排列, 因为 lspci
使用 /proc 文件作为它的信息源. 拿 VGA 视频控制器作一个例子, 0x00a 意思是 0000:00:14.0 当划分为域(16 位), 总线 (8 位), 设备(5
位)和功能(3 位).
每个外设板的硬件电路回应查询, 固定在 3 个地址空间: 内存位置, I/O 端口, 和配置 寄存器. 前 2 个地址空间由所有在同一个 PCI 总线上的设备共享(即, 当你存取一个内
存位置, 在那个 PCI 总线上的所有的设备在同一时间都看到总线周期). 配置空间, 另外 的, 采用地理式寻址. 配置只一次一个插槽地查询地址, 因此它们从不冲突.
至于驱动, 内存和 I/O 区用通常的方法, 通过 inb, readb, 等等来存取. 另一方面, 配 置传输通过调用特殊的内核函数来存取配置寄存器. 考虑到中断, 每个 PCI 插槽有 4 个
中断脚, 并且每个设备功能可以使用它们中的一个, 不必关心这些引脚如何连入 CPU. 这
样的连接是计算机平台的责任并且是在 PCI 总线之外实现的. 因为 PCI 规范要求中断线 是可共享的, 即便一个处理器有有限的 IRQ 线数,
例如 x86, 可以驻有许多 PCI 接口板 ( 每个有 4 个中断脚).
PCI 总线的 I/O 空间使用一个 32-位地址总线( 产生了 4 GB 的 I/O 端口), 而内存空 间可使用 32-位或者
64-位地址存取. 64-位地址在大部分近期的平台上可用. 假设地址
对每个设备是唯一的, 但是软件可能错误地配置 2 个设备到同样的地址, 使得不可能存 取任何一个. 但是这个问题不会产生, 除非一个驱动想玩弄不应当触动的寄存器. 好消息 是每个由接口板提供的内存和 I/O 地址区可被重新映射, 通过配置交易. 那是, 在系统 启动时固件初始化
PCI 硬件, 映射每个区到不同地址来避免冲突.[41]这些区当前被映射到 的地址可从配置空间读出, 因此 Linux 驱动可存取它的设备而不用探测. 在读取了配置 寄存器后, 驱动可安全地存取它的硬件.
PCI 配置空间为每个设备包含 256 字节(除了 PCI Express 设备, , 它每个功能有 4 KB 地配置空间), 并且配置寄存器的排布是标准化的. 配置空间的 4 个字节含有一个唯一的 功能 ID, 因此驱动可标识它的设备, 通过查找那个设备的特定的 ID.[42] 总之,
每个设备 板被地理式寻址来获取它的配置寄存器; 这些寄存器中的信息可接着被用来进行正常的 I/O 存取, 不必进一步的地理式寻址.
从这个描述应当清楚, PCI 接口标准对比 ISA 主要的创新是配置地址空间. 因此, 除了 通常的驱动代码, 一个 PCI 驱动需要存取配置空间的能力, 为了从冒险的探测任务中解 放自己.
本章的剩余部分, 我们使用词语设备来指一个设备功能, 因为在多功能板的每个功能如同 一个独立的实体. 当我们引用一个设备, 我们的意思是"域号, 总线号, 设备号, 和功能 号"的组合.
linux PCI 寻址的更多相关文章
- Linux PCI设备驱动的实现思路与思想
概述 1.PCI设备一般都具有双重身份,一方面作为PCI设备注册到Linux内核,另一方面,作为字符设备或者块设备,或者网络设备注册到Linux内核,所以,在看PCI设备时一定要注意到这点. 2. 一 ...
- 【VS开发】【DSP开发】浅谈Linux PCI设备驱动(一)
要弄清楚Linux PCI设备驱动,首先要明白,所谓的Linux PCI设备驱动实际包括Linux PCI设备驱动和设备本身驱动两部分.不知道读者理不理解这句话,本人觉得这句话很重要,对于PCI.US ...
- 【原创】Linux PCI驱动框架分析(一)
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- linux PCI设备初始化过程
linux PCI设备初始化过程 start_kernel->rest_init 这个函数会启动一个核心线程0, 核心线程然后调用init -> do_basic_setup. 然后我们开 ...
- Linux内存寻址之分页机制
在上一篇文章Linux内存寻址之分段机制中,我们了解逻辑地址通过分段机制转换为线性地址的过程.下面,我们就来看看更加重要和复杂的分页机制. 分页机制在段机制之后进行,以完成线性—物理地址的转换过程.段 ...
- Linux PCI网卡驱动的详细分析
学习应该是一个先把问题简单化,在把问题复杂化的过程.一开始就着手处理复杂的问题,难免让人有心惊胆颤,捉襟见肘的感觉.读Linux网卡驱动也是一 样.那长长的源码夹杂着那些我们陌生的变量和符号,望而生畏 ...
- Linux PCI/PCI-E设备配置空间读取与修改
Linux PCI/PCI-E设备配置空间读取与修改 1 前言 PCI和PCI Express,是计算机常使用的一种高速总线.操作系统中的PCI/PCI-E设备驱动以及操作系统内核,都需要访问PCI及 ...
- Linux内存寻址之分段机制及分页机制【转】
前言 本文涉及的硬件平台是X86,如果是其他平台的话,如ARM,是会使用到MMU,但是没有使用到分段机制: 最近在学习Linux内核,读到<深入理解Linux内核>的内存寻址一章.原本以为 ...
- Linux pci驱动源码
#include <linux/kernel.h>#include <linux/errno.h>#include <linux/module.h>#include ...
随机推荐
- 2019-8-31-C#-标准性能测试高级用法
title author date CreateTime categories C# 标准性能测试高级用法 lindexi 2019-08-31 16:55:58 +0800 2018-07-08 0 ...
- 2019.9.10附加题while练习
题目:企业发放的奖金根据利润提成.利润(I)低于或等于10万元时,奖金可提10%:利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%:20万到40万之 ...
- 2019-11-20-dotnet-Blazor-用-C#-控制界面行为
title author date CreateTime categories dotnet Blazor 用 C# 控制界面行为 lindexi 2019-11-20 18:26:25 +0800 ...
- Flask学习之六 个人资料和头像
英文博客地址:http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-vi-profile-page-and-avatars ...
- How to use AutoMapper
http://docs.automapper.org/en/stable/Getting-started.html IMappingExpression<TSource, TDestinatio ...
- Android 监听软键盘搜索键
现在很多的Android应用都有了数据搜索功能,在以往的设计上,会使用搜索框+搜索按钮来实现搜索功能: 现在呢,越来越流行的是,去除搜索按钮,直接监听软键盘搜索键,当用户输入完搜索关键字后,直接点击软 ...
- docker compose安装gitea
docker-compose.yml version: "3.4" networks: gitea: external: false services: server: image ...
- 如何减少idea的内存消耗
如何减少idea的内存消耗 标签: idea 内存 内存泄露 异常 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u014028392/articl ...
- oracle函数 UPPER(c1)
[功能]将字符串全部转为大写 [参数]c1,字符表达式 [返回]字符型 [示例] SQL> select upper('AaBbCcDd') upper from dual; UPPER --- ...
- Redis源码解析:02链表
链表提供了高效的节点重排能力,以及顺序性的节点访问方式,因为Redis使用的C语言并没有内置这种数据结构,所以Redis自己实现了链表. 链表在Redis中的应用非常广泛,比如列表的底层实现之一就是链 ...