PCI总线配置与应用.docx
- 文档编号:23716379
- 上传时间:2023-05-20
- 格式:DOCX
- 页数:13
- 大小:125.74KB
PCI总线配置与应用.docx
《PCI总线配置与应用.docx》由会员分享,可在线阅读,更多相关《PCI总线配置与应用.docx(13页珍藏版)》请在冰豆网上搜索。
PCI总线配置与应用
这篇文章是进行VxWorks下PCI驱动开发的基础,故将其放在首位。
(当然更首位的是您有一定的Vxworks使用和开发经验)主要介绍PCI总线配置空间,如何查看和读取PCI配置相关信息,最后有VxWorks下相关的示例代码。
关键字:
PCI总线vxworksPCI配置空间内存映射PlxPCI9056
我把个人认为比较重要的地方:
用粗体和蓝色进行了标识。
如果您对文章有异议,请提出宝贵意见,您的名字和意见,将出现在下面!
专用术语解释:
PCI:
PeripheralComponentInterconnect的缩写,一种由英特尔(Intel)公司1991年推出的用于定义局部总线的标准。
POST:
PowerOnSelfTest的缩写,即上电自检,接通微机的电源后,系统将执行一个自我检查的例行程序,是BIOS功能的一部分。
1引言
在众多的实时操作系统(RTOS)中,美国WindRiver公司的嵌入式多任务VxWorks实时操作系统是目前世界上用户数量最大的实时操作系统.已成功应用于航空航天、武器控制、舰船、通信、科学研究等领域,如在美国的火星探测器、爱国者导弹上均使用了VxWorks实时操作系统。
当前在我国该操作系统也占有较大的市场分额。
VxWorks操作系统专门对PCI设备提供支持,包括PCI总线驱动和一套PCI支持函数。
配置总线上的设备还与硬件的体系结构和BSP支持程度相关。
本文结合PCI原理。
谈谈实际使用中的经验与体会。
(上面的是中国的客套话)
2PCI总线架构
2.1典型架构
在典型的PCI总线系统架构中.处理器、高速缓存和内存子系统通过PCI桥连接至JJPCI总线。
桥提供一种高速通道使得处理器可以直接访问PCI设备。
还提供高带宽的通道允许PCI直接访问主存。
桥也包含了可选择的功能,比如总线仲裁和热插拔。
2.2总线号、设备号、功能号
PCI总线可以通过桥芯片级连.按与CPU总线所隔的桥数目和同一层总线的扫描顺序,从0开始依次编号,扩展最多N256,0—256就是总线号;在指定的局部总线上.按硬件扫描顺序从O开始依次编号,扩展最多到32。
0~32就是设备号;在一个多功能PCI设备上,最多可以实现8种功能,按设备上配置存储区的顺序从0开始依次编号,称其为功能号,一般的设备只有一个功能。
这三个号组合起来就可确定唯一的一个PCI设备。
以及该设备上的某项功能。
通过这三个参数就可操作PCI设备。
3PCI配置空间
根据PCI规范。
每个PCI设备都要有一个PCI配置空间,容量最大为256字节,称为配置寄存器。
配置寄存器是PCI设备的硬件与其初始化软件信息交接的地方,软件可以通过它对设备进行识别和监控。
3.1配置空间组织结构
256字节的空间分为头标区和设备关联区两部分,如图1所示:
PCI设备的头标区中寄存器布局和格式大致相同,其布局如图2所示。
头标区又分为两部分,头16个字节定义都相同,余下的48个字节根据设备的功能类别不同而布局不同。
位于0Eh的头标识类型字段规定了后48个字节所用布局。
目前的规范只规定了00h和01hN个头标识类型:
01h用于PCI—to—PCI桥。
00h用于其余PCI设备。
3.2配置空间的功能
类型O配置空间头标区里的寄存器实现了很多功能,这里介绍常用的几类。
(1)设备识别
在头标区内有五个寄存器是与一个PCI设备的识别有关的。
配置软件通过访问这些寄存器很容易确定在该PCI总线上有什么PCI设备。
这五个寄存器都是只读的。
◆厂商标识:
标识设备的制造厂商,由PCt规范的权威组织SIG统一分配,以保证唯一性。
如Intel公司的标识码为。
8086h”“FFFFh”是无效标识。
◆设备标识:
标识某一设备,由制造厂商分配。
◆修订版本标识:
标识设备具体的修订版本,由厂商选择。
◆头标类型:
表明头标区中10h到3Fh字节空间的布局类型和该设备是否是多功能设备。
位7用来标识一个多功能设备,为1则该设备是多功能设备,为oN是单一功能设备。
位6到0规定头标区中10h到3Fh字节的布局类型,如上所述,目前只有两类:
00h和01h。
◆分类代码:
该寄存器有三个字节段:
高字节(0Bh)是基本分类码,租略地对功能分类:
中字节(0Ah)是子分类码。
标识具体功能;低字节(09h)标识所用寄存器一级的编程接1:
3。
(2)设备控制
位于配置空间04h偏移地址处的命令寄存器是控制设备产生和响应PCI周期的,是可读写寄存器。
其各位定义和作用如下(这里仅描述软件常用的位):
◆I/O空间使能位:
控制l,O空间访问的响应,为1时,允许设备响应I/O空间的访问。
为0时禁止。
◆存储空间使能位:
控制本设备对存储器空间访问的响应。
为1时允许.为0时禁止。
(3)基地址
头标区中有6个双字的基地址寄存器,在加电时,6个寄存器向POST软件反映该设备需要多少存储器空间和I/O空间。
POST软件就此了解到PCI总线上有哪些存储设备和I/O设备。
再根据它们的容量需求将其映射定位到适当的存储器地址和I/O地址。
并把起始地址写入基地址寄存器,再启动系统。
◆基地址寄存器
xml:
namespaceprefix=ons="urn:
schemas-microsoft-com:
office:
office"/>
位0只读。
用来表示此寄存器申请的是存储器空间还是I/0空间。
为1则该基址寄存器用于I/0空间映射。
此时位1是保留位,位2—31用来把从寄存器映射到系统I/O空间,POST再把系统分配的系统I/O空间基地址写回寄存器的2—31位。
如果位0为0.则要映射到存储器空间。
位1—3是只读的.其中1—2是类型编码,表示映射要求,表1列出了类型编码:
64位寄存器占据两个字.其后面的基地址寄存器的偏移地址要向后推一个双字,但总容量不变,保持6个双字大小。
◆地址映射
映射过程分为两个步骤:
(a)确定空间类别和容量要求:
读取各设备基址寄存器,获取需要的空间和容量。
类别可通过最低位0位判断。
容量判断是把寄存器中的基地址字段的若干低位从硬件上连接到地,从PCI总线向寄存器全写一1。
再读回其值。
由于接了地,读回的值中,从bit4(存储器类型)和bit2(I/O类型)到最高位返回的O的个数反映了所需空间。
(b)分配基地址:
POST软件分配起始地址,并向各寄存器高位字段写入分配空间的基地址,把寄存器对应的存储器和l/o映射到系统物理地址空间去。
3.3如何得到PCI配置信息?
1.如果你是初次做PCI的驱动,建议你安装WinDriver,使用这个工具可以方便的查看你的PCI板卡的信息,比如:
VENDOR_ID,DEVICE_ID,BAR基地址,中断号等等,可以直观上感受一下PCI配置。
2.也可以使用Vxworks下相关的PCI函数,比如:
pciDeviceShow(intbusNo/*busnumber*/)
STATUS pciHeaderShow(intbusNo,intdeviceNo,intfuncNo)
3.3VxWorks对PCI设备的支持
VxWorks操作系统对PCI设备提供了专门的支持库,用户可以利用该库实现对PCI设备的控制:
通过库里的配置函数,可以动态寻找指定PCI设备,并可以读取和修改该设备的配置空间内容。
在配置空间的映射过程中这些函数非常有用,下面列举几个常用的函数,并简单描述其功能以供参考:
pciFindDevice:
查找指定设备,并获得其总线号,设备号,功能号
pciConfigInLong:
以双字为单位读入指定PCI设备配置空间的配置。
sysMmuMapAdd:
对指定内存大小进行映射。
PcIIntConnect:
挂接中断服务程序
PciIntDIsconnect:
清除中断服务程序的挂接
PCI支持库中的函数较多且功能强大,详细内容可以参照开发工具Tornado所提供的帮助手册。
3.4VxWorks中PCI设备的地址映射
VxWorks操作系统在加电过程中会对设备执行地址映射操作,以便程序正确访问设备。
在使用全面的MMU管理组件时。
这个过程是系统自动完成的,但如果系统只包含了基本的MMU功能。
用户就必须手动修改BSP来配置。
先简单了解一下内存映射表。
在sysLib.C中有一张表
sysPhysMemDesc描述了系统物理内存的分配,如下所示:
PHYS_MEM—DESCsysPhysMemDesc[】=
{
/★地址和长度参数必须按页对齐(4kB/4MB的倍数)。
/
f/‘低端内存。
/
(void。
)LOCAL_MEM—LOCAL—ADRS,
(void。
)LOCALMEM—LOCAL』DRS,
0xa0000.
VM—STATE_MASKFOR_ALL,
VM—STATE_FOR_MEM—OS,
},
{/★显示内存等。
/
(void。
)Oxa0000.
(void。
)Oxa0000,
Ox60000。
VM—STATE—MASKFOR_ALL,
VM—STATE—FOR—MEM—lO,
},
f/★为操作系统保留的高端内存’/
(void+)Oxl00000,
(void+)Oxl00000,
Ox080000。
VM—STATE_MASK_FOR—ALL,
VM—STATE—FOR—MEM—OS,
}。
{r为应用程序保留的高端内存。
/
(void’)Oxl800000,
(void‘)Oxl80000,
LOCALMEM—SIZE—Oxl80000,/’在sys—Mem—Top()
中会改变。
,
VM-sTATE_MASK_FOR_ALL,
VM—STATE_FOR—MEM—OS,
}.
,★用于动态映射的条目+/
DUMMY—MMU—ENTRY.
DUMMY.JⅥMU—ENTRY,
}:
上面描述了系统物理内存在逻辑内存中所分配的空间,系统引导时会根据这里的描述管理内存空间。
手动配置PCI设备的方法就是根据PCI基地址寄存器的值在源码中修改上表。
但是通常不推荐这样做,不然将不能适应硬件环境的变化而局限了BSP的使用。
通常使用的方法是
半自动配置方法。
所谓半自动方法是相对于包含完整MMU的VxWorks所采用的自动化方法。
自动化配置方法将自动发现PCI设备并自动为其分配所需空间。
但是仅包含了基本MMU的VxWorks并不会自动完成上表配置,还需要其他辅助步骤帮助系统映射内存,包括为所有设备分配不冲突的内存,以及编程使系统找到指定的PCI设备并分配空间。
4PCI设备配置应用实例
4.1自动配置方法
首先根据设备类型f如显示设备、网络设备)查询总线,以此获取此类设备的PCI总线号、设备号、功能号、厂商号和设备标识,此处假设系统中没有同类的设备。
然后。
根据总线号、设备号、功能号获取该设备的PCI配置空间信息,并写入MMU用于系统物理内存分配。
4.2显示设备的配置
显示设备的配置,首先要包括VxWorks系统组件。
basicMMU”基本内存控制单元。
然后再将PCI显示设备的内存空间配置到MMU里面,否则该内存空间的访问会出现异常。
如果该内存空间是预先知道的,可以在syslib.c的sysPhysMemDesc表中静态配置:
否则需要通过动态查询得到,然后再调用MMU配置函数加入MMU表。
其简要过程如下:
(1)在PCI总线上查找显示设备,并获取其总线号、设备号和功能号;
(2)根据这三个号来读取该设备的内存基地址和需要的内存大小(注意:
内存大小是从开始位到最高位所返回的零的个数,需要用户自己计算。
内存地址要去掉低位非地址含义的位。
);
(3)在sysLib.c的sysHwlnit()函数中调用配置函数sysMmuMapAdd,该函数将基地址和内存大小配置入MMU表,整个配置工作就完成了。
5.实战代码
/************************************************************************
Copyright(C),2010-08-09-2010-08-1X,
Filename :
PlxPCI9056.c,PCI9056驱动程序
Author :
qcj_21
Version :
V1.0
Date :
2010-08-05
Description:
此文件为PlxPCI9056的驱动程序,主要作用是读取PCI9056的配置信息,将PCI上的8路AD信息映射到内存中
由于8路AD的整个内存空间需求大于1000Byte,通过Windows下的WinDriver程序查看PCI的基地址,确定
BAR2为8路AD的映射空间。
特别注意:
将PCI9056映射到内存空间以后,对该空间的读写操作,要用操作内存的方式,比如:
*(volatileunsignedchar*)(ulPortAddr+ucRegister);
Others:
//其它内容的说明
History:
//修改历史记录列表,每条修改记录应包括修改日期、修改者及修改内容简述
1.Author:
Date:
Modification:
2....
************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include"config.h"
#include"PlxPCI9056.h"
#define VENDOR_ID0x10B5 /*厂商标识,标识设备的制造厂商*/
#define DEVICE_ID0x9056 /*设备标识,由制造厂商分配*/
LOCALUINT32g_nMemBaseAddress=0; /*PCIBAR2内存映射空间*/
LOCALUINT32g_nMemSpaceLen =0; /*PIC内存映射空间*/
LOCALUINT32g_nIOBaseAddress=0; /*PCIIO空间*/
LOCALUINT32g_nCAN_IRQNum =0; /*PCICAN卡的中断号*/
/************************************************************************/
/*Function:
PlxPCI9056的初始化
/* 1.根据VENDORID,DEVICEID,Index查找自己的PCI设备
/* 2.读取PCI配置信息
/* 3.对内存空间进行映射
/*Input :
无
/*RetValue:
成功返回OK,失败返回ERROR
/*Author :
qcj_21at[2010-8-514:
02:
19]
/************************************************************************/
STATUSPCI_CAN_Init(void)
{
int nIndex =0;
int nPciBusNO =0; /*总线号, 0~255*/
int nDeviceNO =0; /*设备号, 0~32*/
int nFuncNO =0; /*设备功能号,0~8*/
UINT32nMemBaseAddress =0; /*内存映射的基地址*/
UINT32nIOBaseAddress =0; /*IO基地址*/
UINT32nMemSpaceLen =0; /*内存映射空间的容量即长度*/
UINT32nIOSpaceLen =0; /*IO空间容量*/
UINT32nIRQNum =0; /*中断号*/
UINT32nCommand =0;
STATUSnStatus =0;
UINT32nTemp =0;
UINT32nOffset=0;
/*查找指定设备,并获得其总线号,设备号,功能号*/
if(OK!
=pciFindDevice(VENDOR_ID,DEVICE_ID,nIndex,&nPciBusNO,&nDeviceNO,&nFuncNO))
{
printf("pciFindDevice()functonnotfindthedevice!
");
returnERROR;
}
else
{
printf("FindthePCIdevice!
nIndex=%d,nPciBusNO=%d,nDeviceNO=%d,nFuncNO=%d\n",nIndex,nPciBusNO,nDeviceNO,nFuncNO);
}
pciConfigInLong(nPciBusNO,nDeviceNO,nFuncNO,PCI_CFG_COMMAND,&nCommand);
pciConfigOutLong(nPciBusNO,nDeviceNO,nFuncNO,PCI_CFG_COMMAND,nCommand|CSR_MEM_EN|CSR_BM_EN);
nStatus=pciConfigInLong(nPciBusNO,nDeviceNO,nFuncNO,PCI_CFG_BASE_ADDRESS_2,&nMemBaseAddress);/*得到内存映射基地址*/
if(OK!
=nStatus)printf("Cannotfindmemorybaseaddressregister\n");
nStatus=pciConfigInLong(nPciBusNO,nDeviceNO,nFuncNO,PCI_CFG_BASE_ADDRESS_1,&nIOBaseAddress);/*得到IO映射基地址*/
if(OK!
=nStatus)printf("CannotfindIObaseaddressregister\n");
nStatus=pciConfigInByte(nPciBusNO,nDeviceNO,nFuncNO,PCI_CFG_DEV_INT_LINE, &nIRQNum); /*得到中断号*/
if(OK!
=nStatus)printf("CannotfindInteruptRegister.\n");
g_nCAN_IRQNum=nIRQNum;
printf("nMemBaseAddress=%x,nIOBaseAddress=%x,nIRQNum=%d\n",
nMemBaseAddress,nIOBaseAddress,nIRQNum);
if(0==(nMemBaseAddress&PCI_BAR_SPACE_MEM)) //bit0=0,表示内存映射
{
/*首先需要判断所需内存的大小,根据PCI的规范,将内容全1,写回就可以得到大小*/
pciConfigOutLong(nPciBusNO,nDeviceNO,nFuncNO,PCI_CFG_BASE_ADDRESS_2,0xFFFFFFFF);
pciConfigInLong(nPciBusNO,nDeviceNO,nFuncNO,PCI_CFG_BASE_ADDRESS_2,&nMemSpaceLen);
nMemSpaceLen=~nMemSpaceLen; /*取反*/
/*nMemSpaceLen+=1; //将上一步的值加上1后就是该空间的大小*/
nMemBaseAddress&=(PCI_MEMBASE_MASK);
nIOBaseAddress&=(PCI_IOBASE_MASK);
/*再把地址写回去*/
pciConfigOutLong(nPciBusNO,nDeviceNO,nFuncNO,PCI_CFG_BASE_ADDRESS_2,nMemBaseAddress);
printf("\nmemoryspaceis:
0x%x,lengthis:
%d\n",nMemBaseAddress,nMemSpaceLen);
g_nMemSpaceLen=nMemSpaceLen;
/*此时就可以将内存映射过去了,VM_PAGE_SIZE*/
if(ERROR==sysMmuMapAdd((void*)nMemBaseAddress,nMemSpaceLen,VM_STATE_MASK_FOR_ALL,VM_STATE_FOR_PCI))
{
printf("sysMmuMapAdd(),Error!
");
return(ERROR);
}
}
/*
//elseif(1==(nMemBaseAddress&PCI_BAR_SPACE_MEM)) //bit0=1,表示I/O映射
//{
//
//}
//
*/
g_nMemBaseAddress=nMemBaseAddress;
g_nIOBaseAddress =nIOBaseAddress;
/*操作命令字,使能映射的存储器空间和IO空间*/
pciConfigOutWord(nDeviceNO,nDeviceNO,nFuncNO,PCI_CFG_COMMAND,
PCI_CMD_IO_ENABLE|PCI_CMD_MEM_ENABLE|PCI_CMD_MASTER_ENABLE);
/*操作关闭睡眠模式 */
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- PCI 总线 配置 应用