一、PCI-E/PCI拓扑结构
    PCI-E点对点结构
    PCI总线结构
    
二、PCI-E总线特性
    协议支持258个bus、每条bus最多支持32个device,每个device最多支持8个function
    由BDF构成了每个PCI-E设备几点的身份证,用于PCI-E地址空间寻址。
    
三、PCI-E一般拓扑图
    CPU --> RC --> SWITCH
               --> ENDPOINT
               --> PCIE2PCI Bridge
    RC里面包括:
        1.host_bridge
        2.多个virtual_p2p(每个virtual_p2p也是一个PCIE设备)
        
四、设备枚举过程
    1、PCI-E扫描法则
        深度优先
    2、扫描过程
        (1) 对CPU来说,最开始仅仅知道Bus0的存在,Bus0下面都有什么设备,以及PCI-E树是什么样的一概不知
        (2) 从bus0的dev0(是一个virtual_p2p)开始,读dev0的func0的DID&VID,如果不为0表示功能存在;读取
            Header寄存器(0:表示是端点设备;1:表示是桥)。如果返回0xFFFF,表示设备不存在。
        (3) 如果通过Header寄存器判断是桥设备,那么要写配置空进间:
                Primary Bus Number = 2;                  
             Secondary Bus Number = 3;               
             Subordinate  Bus Number = 3;        
             然后再更新所有上游桥的:Subordinate Bus Number = 3    
                (这里,2/3是示例值,以实际为准)
        (4) a.如果通过Header寄存器判断是EndPoint设备,并且bit7是1,表示一台多功能设备,那么继续扫描每个fun(0~7)。完成之后就返回扫描其他总线
            b.如果通过Header寄存器判断是EndPoint设备,并且bit7是0,表示一台单一功能设备,处理完fun0后,返回扫描其他总线("注意:VID是vender ID;DID是device ID")。
            
五、PCI/PCIE配置空间
    1、pci的配置空间是256字节,其中64字节是标准配置空间header, 后面的192字节是Capability结构, 展示pci能提供的能力。 为了兼容PCI,PCIe的配置空间前256字节与PCI保持一致,256~4096字节是pcie 扩展配置空间,包含pcie的扩展能力如AER。

2、PCI标准配置空间头(0 ~ 64 bytes)
        PCI标准配置空间分type0和type1两种。type0主要是针对PCI的endpoint设备,type1主要是针对PCI bridge, switch。(知道”五、设备枚举过程“为什么通过0/1来判断是端点设备还是桥设备了吧?)

六、BAR寄存器如何实现地址映射
    1、在BAR寄存器有些bit是只读的,是PCI设备在出厂前就固定好的bit,写全1进去,如果值保持不变,就说明这些bit是厂家固化好的,这些固化好的bit提供了这块内部空间的一些信息。

2、举个例子:
        上电时,系统软件首先会读取PCIe设备的BAR0(未初始化的BAR寄存器),得到数据:
            -------------------------------------------------------------------
            |xxxx xxxx xxxx xxxx xxxx | 0000 0000 | 0 | 0 0 | 0 |
            -------------------------------------------------------------------
             31                                 12  11            4   3  2  1   0
        然后系统软件往该BAR0写入全1(BAR寄存器写0xffffffff),得到:
            -------------------------------------------------------------------
            |1111 1111 1111 1111 1111 | 0000 0000 | 0 | 0 0 | 0 |
            -------------------------------------------------------------------
             31                                12  11            4   3   2  1   0

3、低12bit没变,表明该设备空间大小是4KB(2的12次方),BAR地址的低4位表明了该存储空间的一些属性([0]: IO映射还是memory映射,[2:1]32bit地址还是64bit地址,[3]能否可预取)。然后系统软件根据这些信息,在PCI总线地址空间分配4KB,并把分配到的基地址(PCI总线地址空间)写入到BAR寄存器(bit12~bit31),这样我们就可以在构建一张表,用于记录所有PCI设备所需要的PCI总线空间空间。这也是PCI枚举的主要任务之一。

这里,非常重要的一个概念是,BAR读取到的是PCI地址空间中的地址,不等同于CPU认识的内存地址。虽然在x86上如果没有开启IOMMU时,它们的值一般是相同的,但是对于其他构架的CPU如PowerPC就可以是不一样的。所以正确的使用BAR空间的方法:

pciaddr=pci_resource_start(pdev,1);
if(pciaddr!=NULL)
{
ioremap(pciaddr,xx_SIZE);
}

错误的方法:

pci_read_config_dword(pdev,1,&pciaddr);
ioremap(pciaddr,xx_SIZE);

4、BAR寄存器存储的总线地址,应用程序是不能直接利用的,应用程序首先要做的就是读出BAR寄存器的值,然后用mmap函数建立应用程序内存空间和总线地址空间的映射关系。这样应用程序往PCIE设备内存读写数据的时候,直接利用PCIE设备映射到应用程序中的内存地址即可。但是应用程序的内存地址该由谁解析到PCIE设备对应的总线空间给EP呢,这个工作是由北桥或者是RC(root complex)来完成的,解析到总线地址空间之后,EP会把总线的地址空间解析成PCIE设备对应的设备内存地址。

七、CPU mem地址空间/IO地址空间以及PCI Memory/IO/Configuration空间

(Fig. 1 CPU Memory空间、CPU I/O空间和PCI Memory/IO/Configuration空间)

PCI体系结构中支持三种地址空间:Memory空间、I/O空间、Configuration空间(Fig.1紫色部分)。

x86的处理器可以直接访问CPU Memory空间和I/O空间。PCI的Memory/IO 空间可以映射到CPU的Memory/IO空间以供CPU读写。特别要注意的是:PCI Memory地址空间支持32bit/64bit寻址;在PCI I/O地址空间中,PCI支持32bit地址,但是x86只用了16bit访问I/O空间,所以很多平台的I/O空间大小限制在64KB。

PCI还引入了配置空间(Configuration Space),而且CPU只能间接访问配置空间。每个功能(Function)包含配置空间的内部寄存器,允许软件以一种标准化的方式显示和控制其地址和资源,在PC中提供一个真正的“即插即用”环境。每个PCI功能(PCI Function)最大包含256 Bytes配置空间。鉴于在一个系统中,最多支持256条总线,每条总线最多支持32个设备,每个设备最多支持8个功能(Function),那么总的配置空间大小就是:256 Bytes * 8 * 32 * 256 = 16MB。

鉴于CPU不能直接访问PCI设备的配置空间,所以只能通过IO寄存器进行间接访问(PCIe设备还支持将配置空间映射到Memory空间进行访问)。就像图Fig.1所展现的那样,CPU通过配置地址端口(Configuration Address Space)和配置数据端口(Configuration Data Port)访问PCI设备的配置空间。配置地址端口的地址是CF8h~CFBh(写入配置空间某一行在配置空间中的地址),配置数据端口的地址是CFCh~CFFh(写入配置空间某一行的数据)。

lspci -vvv命令基本上就是读取所有PCI设备的配置空间信息,格式化后输出:

八、CPU如何读写PCI设备空间——CPU地址如何转换到PCI地址

关于地址相关的问题,搞清楚这三个地址之间的关系就可以了:

存储器地址(就是CPU,DMA等设备直接读写的地址)。
TLP中的地址。
BAR空间地址。
如果两两组合的话,能够形成三种关系,但是事实上,这三者之间的关系其实就两部分:

存储器地址和TLP地址字段的关系。
TLP地址字段和BAR空间地址的关系。
解决这两个问题,地址相关的问题就应该都清楚了。

1、存储器地址和TLP地址字段的关系

TLP中的地址哪里来?ATU转换过来的。这个问题就是这么的简单。ATU是什么?是一个地址转换单元,负责将一段存储器域的地址转换到PCIe总线域地址,除了地址转换外,还能提供访问类型等信息,这些信息都是ATU根据总线上的信号自己做的,数据都打包到TLP中,不用软件参与。软件需要做的是配置ATU,所以如果ATU配置完成,并且能正常工作,那么CPU访问PCIe空间就和访问本地存储器空间方法是一样的,只要读写即可。

这就解释了存储器地址和TLP地址字段的关系了。至此,地址相关的问题就解决了。

ATU配置举例:以kernel 4.4中designware PCIe host驱动为例:

static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,int type, u64 cpu_addr, u64 pci_addr, u32 size)
{// 使用哪个ATUdw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | index,PCIE_ATU_VIEWPORT);// source地址(存储器域)的低32位dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr), PCIE_ATU_LOWER_BASE);dw_pcie_writel_rc(pp, upper_32_bits(cpu_addr), PCIE_ATU_UPPER_BASE);// space sizedw_pcie_writel_rc(pp, lower_32_bits(cpu_addr + size - 1),PCIE_ATU_LIMIT);// 目标地址空间(PCIe总线地址)dw_pcie_writel_rc(pp, lower_32_bits(pci_addr), PCIE_ATU_LOWER_TARGET);dw_pcie_writel_rc(pp, upper_32_bits(pci_addr), PCIE_ATU_UPPER_TARGET);// 空间类型(mem or IO)dw_pcie_writel_rc(pp, type, PCIE_ATU_CR1);// 使能ATUdw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
}

2、TLP地址字段和BAR空间地址的关系

首先要知道BAR有什么用?通过BAR寄存器,我们首先知道这个基址对应的空间属性,然后给这段空间分配一个基址(这个基址只是用来路由寻址用的,不能和存储器空间的地址搞混,很多软件实现上会把两个地址设置成一样,但是本质上没有任何关系,只是TLP寻址的时候用的!)。这样的话,TLP就能根据地址被路由到对应设备的BAR空间中去。比如说现在有一个mem read request,如果路由地址(地址信息包含在TLP中)是0x71000000,而有一个设备func0的mem空间范围是0x70000000~0x80000000,那么这个TLP就会被这个func处理。从func0的0x71000000对应的地址读取相应数据。

九、Linux访问PCIe的Memory空间、I/O空间、Configuration空间

1、访问配置空间(位于drivers/pci/access.c)

1.1 读配置空间
pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val);
pci_read_config_word(const struct pci_dev *dev, int where, u16 *val);
pci_read_config_dword(const struct pci_dev *dev, int where, u32 *val);
1.2 写配置空间
pci_write_config_byte(const struct pci_dev *dev, int where, u8 *val);
pci_write_config_word(const struct pci_dev *dev, int where, u16 *val);
pci_write_config_dword(const struct pci_dev *dev, int where, u32 *val);

2、访问BAR空间

1、在枚举过程中,PCI驱动已经分配了address给各个BAR,通过一些接口就可以访问到BAR Resource。

2、获取BAR resource(位于include/linux/pci.h)

pci_resource_start(dev, bar)
pci_resource_end(dev, bar)
pci_resource_flags(dev, bar)
pci_resource_len(dev, bar)

通过pci_resource_start宏取得bar值之后,Linux认为这个地址是IO地址,如果要访问的话可以通过ioremap映射到内核空间,然后通过readl/writel等IO接口进行操作。

参考资料:

PCIe实践之路:Linux访问PCIe空间_Camus-CSDN博客

(17条消息) PCI Address Space Map_老王的笔记-CSDN博客

(17条消息) PCIe实践之路:BAR空间和TLP_Camus-CSDN博客

深入PCI与PCIe之二:软件篇 - 知乎 (zhihu.com)

PCI-E 基础知识相关推荐

  1. 【PCI】PCI PCIE基础(一)

    关于PCI相关基础知识请参阅 王齐 先生的著作<PCI Express 体系结构导读>,个人认为这本书是学习PCI与PCIE的经典之作,以下简要说明初学者应阅读哪些章节. PCI 第一 ~ ...

  2. 关于微型计算机的ppt,微型计算机基础知识.ppt

    <微型计算机基础知识.ppt>由会员分享,可在线阅读,更多相关<微型计算机基础知识.ppt(34页珍藏版)>请在装配图网上搜索. 1.微机原理与接口技术,主讲:乔桂芳老师 二0 ...

  3. 公共基础知识计算机,公共基础知识计算机基础知识试题

    计算机基础知识是公共基础知识考试的组成成分之一,以下是由学习啦小编整理关于共基础知识计算机基础知识试题的内容,希望大家喜欢! 公共基础知识计算机基础知识试题 1.CPU的主要功能是进行( ). A.算 ...

  4. 计算机信息处理技术知识点,计算机信息处理技术基础知识.doc

    计算机信息处理技术基础知识 计算机信息处理技术基础知识 信息技术概况 集成电路的基本知识(20世纪50年代) 集成电路是微电子技术的核心. 分类:①小规模.中规模.大规模.超大规模.极大规模(包含的电 ...

  5. 计算机硬件价钱分配,电脑基础知识计算机硬件基础课件.ppt

    电脑基础知识计算机硬件基础课件 操作系统的概念 指直接控制和管理计算机的硬件和软件资源以便于有效的使用这些资源的程序. 操作系统分类 :单用户操作系统.批处理操作系统.实时操作系统.分时操作系统.网络 ...

  6. crawler4j_迷你搜索引擎–使用Neo4j,Crawler4j,Graphstream和Encog的基础知识

    crawler4j 继续执行正在实现搜索引擎的Programming Collection Intelligence (PCI)的第4章. 我可能比做一次运动所咬的东西要多. 我认为,与其使用本书中所 ...

  7. 迷你搜索引擎–使用Neo4j,Crawler4j,Graphstream和Encog的基础知识

    继续执行正在实现搜索引擎的Programming Collection Intelligence (PCI)的第4章. 我可能比做一次运动所咬的东西要多. 我认为, 与其一直使用本书中使用的普通关系数 ...

  8. 计算机维修与维护入门,计算机组装与维护基础知识

    <计算机组装与维护基础知识>由会员分享,可在线阅读,更多相关<计算机组装与维护基础知识(5页珍藏版)>请在人人文库网上搜索. 1.计算机组装与维护基础知识关键考点:CPU主板内 ...

  9. 计算机课件知识,计算机基础知识1认识计算机课件.ppt

    <计算机基础知识1认识计算机课件.ppt>由会员分享,提供在线免费全文阅读可下载,此文档格式为ppt,更多相关<计算机基础知识1认识计算机课件.ppt>文档请在天天文库搜索. ...

  10. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之设备树模型

    文章目录 前言 1.设备树的作用 2.设备树的语法 2.1.设备树的逻辑图和dts文件.dtb文件 2.1.1.1Devicetree格式 1DTS文件的格式 node的格式 properties的格 ...

最新文章

  1. android contacts电话查询头像,android怎么取得本地通讯录的头像的原图
  2. C ++定义QML类型
  3. mysql列别名引用_引用聚合列的MySQL别名
  4. HTML5中的webSocket、ajax、http
  5. (原创)SpringBoot入门
  6. python加载机制_Python 模块的加载顺序
  7. 云服务器一般选什么系统,云服务器一般选择什么系统好
  8. 传入一个月份获取该月的统计信息
  9. JetBrains系列产品学生认证申请免费使用教程
  10. request.getParameter()与request.getParameterValues()
  11. 一次搞定亚马逊 Used Sold as New 二手品申诉,速度 Get!
  12. 贝叶斯估计理论——引子
  13. jQuery拖拽图片拼图验证插件
  14. 投影、坐标系统、基准面和椭圆体、空间参考几个概念的详述
  15. 策略迭代与值迭代的区别
  16. 基于Logistic混沌序列和DNA编码的图像加解密算法仿真
  17. 关于MII、RMII、GMII、RGMII、PHY、网络变压器、RJ45的硬件总结
  18. 谷歌浏览器怎么同步收藏夹,书签云帮助你
  19. Programming OpenGL in Linux: GLX and Xlib
  20. 刘强东:我请你来,不是让你证明我错了!

热门文章

  1. python apply()函数
  2. 笔记本电脑无法找不到网卡解决方案
  3. POI Excel 插入新的行,下面的行动态移动
  4. Diet Disk 5.4.4 中文特别版 Mac 优秀磁盘瘦身清理软件
  5. IIS环境下隐藏index.php
  6. 科幻场景将成为现实,这架飞行汽车已完成首次城际飞行
  7. MotionBuilder不同的骨骼结构映射动作
  8. 57_解决adb一直重启
  9. 十大机器学习算法的一个小总结
  10. PostGreSQL设置主键自增