讲讲对PCIE总线协议的一点理解吧。感觉每一年又会多一点理解,但不懂得地方仍很多。
PCI总线是拓扑结构,PCI总线从0开始,不超过256(但一般不会一层一层挂太多)。Device不超过32,Function不超过8。如下图,挂在总线0,即Bus 0上的为根(root)设备,下面还挂设备的则为桥(Bridge),不再挂设备的即为设备(Device)。挂在桥下的设备总线号必然大于桥的总线号,下图中,PCI桥片1位Bus 0,PCI设备11为bus 1,PCI设备31为Bus 3。所以PCI桥片1的从属总线是1-3。

挂在PCI总线上的所有桥或设备都有特定的编号,即为Bus,Device,Function,不会重复。CPU对于挂在root上的设备都有固定定义,查看datasheet即可。

PCI设备的配置空间如下图:

该空间寄存器的详细信息可查看PCIE Spec,以Class Code为例,Class Code是判断PCI类型:LAN、VGA、存储设备等等。对于下面一段代码进行分析。

 if (Hdr->ClassCode[2] == 0x0C) {if (Hdr->ClassCode[1] < sizeof (gPciSerialClassCodes) / sizeof (VOID *)) {Str = gPciSerialClassCodes[Hdr->ClassCode[1]];if (Hdr->ClassCode[1] == 0x03) {switch (Hdr->ClassCode[0]) {case 0x00:Str = L"USB-UHCI               ";break;case 0x10:Str = L"USB-OHCI               ";break;case 0x20:Str = L"USB-EHCI               ";break;default:break;}}}}

首先要判断Class Code的高位为0x0c(串行总线控制器),才能找到0x0c对应的Sub-Class Code,代码对应下图:


如何访问PCI设备?
两种方式:IO或memory
IO:即地址端口0xcf8/数据端口0xcfc,特定Bus,Device,Function按下图方式得到地址(实际中寄存器地址不用偏移两位),写入0xcf8;从0xcfc得到数据。

memory:方式类似,但Bus,Device,Function全部左移四位,bit31-28也根据CPU不同而不同,以Intel为例:Address = 0xE0000000+(Bus<<20)+(Device<<15)+(Function<<12)+Register.**(这里有点忘了,不确定!)o(╥﹏╥)o
以此可以看出IO方式只能访问256字节,即为PCI的配置空间。
PCI和PCIE的不同?
每种function包含4K的配置空间,前256字节为兼容配置空间,PCI的配置空间为0x00- 0xFF,PCIe设备还支持0x100 -0xFFF这段扩展配置空间。
怎么判断是PCI还是PCIE?
PCIE扩展空间的头指针存放于Capability Pointer(Config_ddress+0x34),从偏移地址0x34开始,读取值,该值为指向下一个ID的指针,判断ID是否为0x10,不是则读取指针+1的寄存器的值,该值为下一个ID的指针,直到ID为0x10,,当ID为0x10时,则该设备为PCIE设备,此ID开始的地方为PCIE Capability结构的开始,PCI设备不能使用这段空间。当Pointer为0,结束。
原话:PCI Express Capability ID Register
This read-only field must contain the value 10h,indicating this is the start of the PCI Express Capability register set


举个栗子:如下图,地址0x70开始为PCIE Capability结构配置空间

该空间的具体寄存器信息如下,里面包含设备种类(上下游)、负载、PCIE Link速度,Link宽度等等。

以速度和宽度举例:

下列代码是判断该PCIE速度(Gen1/Gen2/Gen3)和宽度(x1/x2/x4/x8/x16/x32).

// check is pcie capabilityStatus = Pci->Pci.Read (Pci, EfiPciIoWidthUint8, PcieCapabilityPtr, 1, &CapabilityId);LinkStatusPtr = (UINT16)(PcieCapabilityPtr + 0x0C);Status = Pci->Pci.Read (Pci, EfiPciIoWidthUint16, LinkStatusPtr, 1, &LinkStatusValue);GenValue = (UINT8)(LinkStatusValue & 0xF);LaneValue = (UINT8)((LinkStatusValue & 0x3FF) >> 4);switch (GenValue) {case PCIE_GEN1:GenStr = L"Gen1";break;case PCIE_GEN2:GenStr = L"Gen2";break;case PCIE_GEN3:GenStr = L"Gen3";break;default:break;}switch (LaneValue) {case PCIE_LANEX1:LaneStr = L"Lane:1";break;case PCIE_LANEX2:LaneStr = L"Lane:2";break;case PCIE_LANEX4:LaneStr = L"Lane:4";break;case PCIE_LANEX8:LaneStr = L"Lane:8";break;case PCIE_LANEX12:LaneStr = L"Lane:12";break;case PCIE_LANEX16:LaneStr = L"Lane:16";break;case PCIE_LANEX32:LaneStr = L"Lane:32";break;default:break;}

另:附上遍历主板所有PCI设备并判断是PCI还是PCIE设备的代码(将设备的地址送入0xCF8,从数据端0xCFC读出来的vendor值为0xFFFF,即为无效,没有设备。)
注:PCI空间是以double word读取,字节和字读取都无效。

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>void delay(unsigned int max);
void PCIE_SCAN(unsigned int Address);int main()
{char bus,device,function;unsigned int cfg_add,ventor_val;for(char i=0;i<5;i++)       //scan bus{for(char j=0;j<32;j++)      //scan device{for(char k=0;k<8;k++)      //scan function{bus = i;device = j;function = k;// the base address of every devicecfg_add = 0x80000000+bus*0x10000+(device*8)*0x100+function*0x100;    outpd(0xCF8,cfg_add);// vendor numberventor_val = inpd(0xCFC);//judge the device exist or notif(ventor_val!=0xffffffff){printf("%04x  ",ventor_val);printf("bus = %02x,device = %02x,function = %02x",bus,device,function);delay(100);//find PCIE devicePCIE_SCAN(cfg_add);}}}}system("pause");return 0;
}
void delay(unsigned int max)
{unsigned int d;for(d=0;d<max;d++);
}
void PCIE_SCAN(unsigned int Address)
{int flag =1;unsigned int capability_pointer,capability_ID,capability_Npointer,p;// printf("%0x",Address);//capability pointer register is 0x34outpd(0xCF8,(Address+0x34));capability_pointer = inp(0xCFC);while(flag){outpd(0xCF8,(Address+capability_pointer));//capability ID and next pointer and other 16 bitsp = inpd(0xCFC);capability_ID = p%256;if(capability_ID==0x10){printf("  PCIE device\n");goto ex;}p = p>>8;capability_Npointer = p%256;//When pointer is 0x00,there is no space of extensionif(capability_Npointer==0){flag = 0;}capability_pointer = capability_Npointer;}printf("  PCI device\n");
ex:                 ;
}

在DOS下运行结果如下图:

对PCIE设备访问及其配置空间的一点理解相关推荐

  1. PCIE设备访问及其配置空间

    早期的PCI时期,系统为每个PCI设备分配的内存大小仅有256个Bytes.到后来的PCIE时期,随着设备性能增强,PCIE设备的配置空间扩展至4K个Bytes.在这里需要注意: PCIE一共支持25 ...

  2. PowerPC下PCI、PCI-E设备的配置空间

    PCI总线规定访问配置空间的总线事务,称为配置读写事务.不同于存储访问事务使用存储地址访问,而是使用ID号来寻址访问PCI配置空间. PCI设备的ID号由总线号(BUS NUMBER).设备号(DEV ...

  3. PCIe配置空间和PCI设备中的寄存器

    1.访问PCI配置空间,PCI基本配置空间的读写使用下列函数: 原型定义在<linux/pci.h> int pci_read_config_byte(struct pci_dev *pd ...

  4. PCIe ECAM机制访问PCIE的配置空间

    1.PCIe ECAM机制 PCI Express Enhanced Configuration Access Mechanism (ECAM)是访问PCIe配置空间的一种机制.是将PCIe的配置空间 ...

  5. PCIe学习笔记之pcie结构和配置空间

    PCIe概述 PCI Express,是计算机总线PCI的一种,它沿用现有的PCI编程概念及通信标准,但建基于更快的串行通信系统. PCIE总线使用的是高速差分总线,并采用端到端的连接方式, 现在的高 ...

  6. pci配置基地址_PCI/PCIe基础——配置空间

    简介 PCI/PCIe设备有自己的独立地址空间,这部分空间会映射到整个系统的地址空间. 映射地址在BIOS/UEFI下指定(如果有的话,对于使用非BIOS启动的OS,不清楚),它有两种类型,一种是MM ...

  7. PCI设备与PCI桥的配置空间

    PCI配置空间 HOST主桥通过配置读写事务报文访问设备的配置空间,PCI总线规定了三种类型的PCI配置空间.配置空间中出现的地址都是PCI总线域的地址. (1)Agent设备配置空间 (2)Brid ...

  8. 【总线】【PCI】【PCIe】【转】配置空间

    PCI Express,是计算机总线PCI的一种,它沿用现有的PCI编程概念及通信标准,但建基于更快的串行通信系统:PCIE总线使用的是高速差分总线,并采用端到端的连接方式, 现在的高速总线基本上都是 ...

  9. PCI设备的配置空间

    1.基本介绍 其实PCI设备的配置空间就是配置PCI设备的那些寄存器集合.PCI通常将PCI配置信息存放在E2PROM中,PCI设备上电初始化时,将E2PROM中的信息读到PCI设备的配置空间中作为初 ...

最新文章

  1. HTML5开发笔记:初窥CANVAS,上传canvas图片到服务器
  2. import android.view.window;,尝试在空对象引用上调用虚拟方法‘android.view.Window$回调...
  3. [FlareOn2]very_success [FlareOn3]Challenge1
  4. C++类的使用(二)—— explicit构造与const成员赋值
  5. qt开发环境 - 丁林松教程,丑陋的计算器
  6. CSS3笔记之基础篇(二)颜色和渐变色彩
  7. 用jQuery插件jVectorMap制作中国省份区域图
  8. linux-centos连网
  9. java 8 新特性 时间api使用实例
  10. HTML5-Ajax文件上传(转)
  11. 剑指Offer——二维数组中的查找
  12. Hyperledger Fabric教程(8)--byfn.sh分析-script.sh
  13. 有道词典java下载电脑版下载手机版下载安装_网易有道词典下载-网易有道词典 安卓版v8.3.4-PC6安卓网...
  14. DSP学习笔记——基于TMS320F28335
  15. 何凯明:Single Image Haze Removal Using Dark Channel Prior[CVPR 2009]
  16. 瓦片地图面面观之缩放级别
  17. 浮点数与32位16进制互转(有代码)
  18. 【UE4 附源工程】VR直升机模拟飞行与轰炸制作流程
  19. poi-tl填充动态word表格数据
  20. docker命令讲解

热门文章

  1. PowerPivot——DAX(函数)
  2. 桌面 计算机屏蔽,Win10家庭版如何禁止别人修改电脑桌面壁纸?
  3. 华为数通笔记-IPV6基础
  4. java必备的开发知识和技能
  5. POJ-29932996
  6. 如何实现实时音视频聊天功能
  7. dsp的ad标志位是什么_关于STM32 AD转换的ADC_FLAG_EOC标志位问题
  8. Linux上显示sh-4.2$,笔记四、Linux基础入门
  9. 缠中说禅《论语》详解:给所有曲解孔子的人
  10. gtest测试框架使用详解_【python】新手小白必看,教你如何使用全功能Python测试框架 - python秋枫...