PCI驱动开发实现 vxworks.docx
《PCI驱动开发实现 vxworks.docx》由会员分享,可在线阅读,更多相关《PCI驱动开发实现 vxworks.docx(26页珍藏版)》请在冰豆网上搜索。
![PCI驱动开发实现 vxworks.docx](https://file1.bdocx.com/fileroot1/2023-6/1/d8ad6883-7483-428c-95e1-a6eae5af8a1a/d8ad6883-7483-428c-95e1-a6eae5af8a1a1.gif)
PCI驱动开发实现vxworks
嵌入式系统中平台PCI模块驱动讲解
1、PCI系统需求
PCI网卡
2、PCI总线的基础知识
PCI是PeripheralComponentInterconnect(外设部件互连标准)的缩写,它是目前个人电脑中使用最为广泛的接口,其位宽为32位或64位,工作频率为33MHz,最大数据传输率为133MB/sec(32位)和266MB/sec(64位)。
可插接显卡、声卡、网卡、内置Modem、内置ADSLModem、USB2.0卡、IEEE1394卡、IDE接口卡、RAID卡、电视卡、视频采集卡以及其它种类繁多的扩展卡.
目前PCI-E是PCI最新的发展方向,串行,点对点传输,每个传输通道独享带宽;支持双向传输模式和数据分通道传输模式;在PCI-E3.0规范中,X32端口的双向速率高达320Gbps,可以满足新一代的I/O接口,比如:
千兆(GE)、万兆(10GE)的以太网技术、4G/8G的FC技术。
实现PCI驱动开发需要了解的基础知识主要包括三个方面,PCI控制器、PCI设备以及PCI总线。
PCI拓扑结构如下图,在总线结构中,ethernet、SCSI、video设备和pci-pcibridge都为PCI设备,CPU中包含PCI控制器、Pcibus0和pcibus1为PCI设备总线。
1、PCI总线
每一个PCIdevice都有其uniquePFA(PCIFcntionAddress)PFA由busnumber、devicenumber、functionnumber组成。
一条PCI总线支持256个PFA,即支持256个PCIdevice。
每个PCI芯片都有自己的devicenumber(取决于IDSEL管脚),每个PCI芯片占用8个PFA。
每个PCI芯片的第一个PCIdevice的PFA必为8的倍数。
若PCIdevice的配置空间中PCI_HEADER_TYPE寄存器的最高bit为1,说明此芯片还有其他PFA,即还有其他device,即当前芯片是multi-functiondevice.
在系统中,每个PCI芯片上的所独有的信号线是:
INTA、INTB、INTC、INTD、IDSEL
每个芯片上的IDSEL需要连到PCI总线中AD[31:
11]中的一根,这对应于PCIdevicePFA的devicenumber
(1)接口控制管脚(出问题时常测这些管脚)
FRAME#:
帧周期信号。
Master驱动,表示一次访问的开始和持续时间。
FRAME#无效时,是传输的最后一个数据周期。
IRDY#:
Master准备好信号。
TRDY#:
Slave准备好信号。
当这两者同时有效时,才能进行完整的数据传输,否则即为等待周期。
在写周期,IRDY#信号有效时,表示有效的数据信号已在AD0~AD31中建立;
在读周期,IRDY#信号有效时,表示Master已做好接收数据的准备。
在写周期,TRDY#信号有效,表示Slave已做好了接收数据的准备。
在读周期,TRDY#信号有效,表示有效数据已被送入AD0~AD31中,
STOP#:
停止数据传送信号,由Slave发出。
当它有效时,表示Slave请求Master终止当前的数据传送。
IDSEL:
初始化设备选择信号。
在读写配置空间时,用作Slave的片选信号(Slave通常把IDSEL连到AD[31:
0]上的一根,PFA中的deviceid就是这么确定的)
DEVSEL#:
设备选择信号,由Slave驱动,该信号有效时,当前Slave设备已被选中
(2)时序
读时序
写时序:
2、PCI设备
每个PCI逻辑设备都有自己的配置空间,里面存储了一些基本信息,生产商,IRQ中断号,还有就是定义了mem空间和io空间的起始地址和大小。
256字节的PCI配置空间分为64字节的头标区和192字节的设备相关区两部分。
头标区的各个寄存器用来唯一地识别设备;设备相关区则保存一些与设备相关的数据。
配置空间的头标区又分为两部分:
前16个字节的定义在各种类型的PCI设备中都是一样的;剩余的字节随设备类型不同而有所不同。
位于偏移地址0EH处的头标类型字段规定了头标区的布局结构。
目前,规范定义了三种头标类型。
嵌入式系统中中的PCI网卡的头标类型是0,所以下面我们就来详细说说其布局结构,至于其他类型的头标请读者自行阅读。
图3就是头标类型0的头标区的布局。
头标区中的寄存器根据功能可分成下面几组:
1.设备的识别
(1)供应商代码:
该寄存器用于识别PCI设备的制造商,具体代码由PCISIG()分配。
0FFFFH是无效的供应商代码。
(2)设备代码。
该寄存器用来标识某供应商生产的具体设备,代码由各供应商定义。
供应商代码和设备代码,读者可以到网站
(3)版本号。
该寄存器用来定义指定设备的版本信息。
(4)头标类型。
该字段的第7位为“1”标识该设备是多功能设备,为“0”标识为单功能设备;该字段的0~6位就是上文表中所述的头标类型。
(5)设备分类代码。
用来标识设备的总体功能和特定的寄存器级编程接口。
上面5个字段均为只读类型,所有的PCI设备都必须实现其功能。
2.设备控制和设备状态
(1) 命令寄存器为一个设备发出和响应PCI总线命令提供粗略的控制。
下图就是命令寄存器格式。
图命令寄存器格式
我们比较关注的位有:
a.位0(I/O空间控制):
控制对I/O空间访问的响应。
该位为0时,禁止设备响应对I/O空间的访问;该位为1时,允许设备响应I/O空间的访问。
缺省设置为0。
b.位1(存储器空间控制):
控制一个设备对存储器空间访问的响应。
该位为0时,禁止响应;该位为1时,允许设备响应对存储器空间的访问。
缺省设置为0。
(2) 状态寄存器用来记录PCI总线有关的状态信息。
3.基址寄存器
PCI设备中,除了配置空间外,还有两个物理空间:
内存空间和I/O空间。
为了访问这两个地址空间,就必须使用基址寄存器。
头标类型0中涉及3种基址寄存器:
内存空间基址寄存器、I/O空间基址寄存器和扩展ROM基址寄存器。
在所有的基址寄存器中,位0均为只读位并且用来决定能够是存储器空间还是I/O空间。
如果该位为0,则表示映射到存储器空间;若为1则表示映射到I/O地址空间。
(1)存储器基地址寄存器
映射到存储器空间的基址寄存器可以是32位宽度,也可以是64位宽度(支持映射到一个64位地址空间时)
32/64存储器基地址寄存器格式
其中位0要用硬件方法使其恒为0。
而位2和位1两位用来表示映射类型,具体如下:
位2和位1
映射类型
00
基地址寄存器为32位宽,可以在32位表示的存储器地址范围的任何地方进行映射
01
保留
10
基地址寄存器为64位宽,可以映射到以64位表示的存储器空间的任何地方
11
保留
至于位3,若数据是可预取的,就应将它置为1,否则清0。
该寄存器的区域各位用来将一设备映射到存储器空间。
基地址寄存器中用于32位存储器译码器的位【31~4】和用于64位存储器译码器的位【63~4】称为基地址单元。
它的作用是:
确定与译码器相关的存储器的大小;给译码器分配地址。
如果存储器设备需要小于4K的存储空间,规范建议存储器范围强行设为4KB。
(2)I/O基地址寄存器
映射到I/O空间的基址寄存器宽度总是32位:
I/O基地址寄存器格式
其中位0值为1(用硬件实现的),位1为保留位并且其读出值必须为0,其余各位用来把设备映射到I/O空间。
当基地址寄存器位0的返回值为1时,表示这是一个I/O译码器,而不是存储器译码器,位1保留并总是返回0,【31:
:
2】是基地址单元,并用于确定需要的I/O块容量,设置它的起始地址。
规范要求映射它的控制寄存器组到I/O空间的设备不必请求每个I/O基地址寄存器超过256个单元。
(3)确定块容量和分配地址范围
要确定存储器的容量或I/O空间大小可以通过简单地向基地址寄存器写入全“1”并回读来确定。
若返回一个是0值,则表示未实现基地址寄存器;如果读回地值为非0,则编程人员通过从基地址单元的最低有效位向上扫描返回值以找到第一个被成功置“1”的位来确定所需存储器的容量或I/0空间的大小。
假设寄存器的位0是一个加权二进制1,那么位1的值就是2,位2的值就是4,依此类推。
这样,在基地址单元中第一个发现的1所对应的加权二进制值便是所需的空间数。
这也是寄存器的第一个可读/可写位,在它之上的所有位钧定义为可读/可写位。
这个信息发现后,程序将32/64位存储器起始地址或32位I/O地址写入基地址寄存器中。
(4)扩展ROM基地址寄存器
有些PCI设备,尤其是那些准备用于PC结构扩展板上的设备,需要EPROM作为扩展ROM。
为此,在配置空间偏移地址30H处开始定义了四个字节的寄存器,用来处理这个扩展ROM的基地址和大小。
扩展ROM基地址寄存器格式
该寄存器和32位基地址寄存器相比,除了位的编码和用途不同之外,其它功能完全相似。
它的高21位对应于扩展ROM基地址的高21位。
一个设备实际实现的位数取决于该设备要求多大的地址空间。
例如,一个设备要求它的扩展ROM映射到一64KB存储区域时,它就应该实现此寄存器的高16位,其它5位用硬件方法使它们恒为0。
凡是支持扩展ROM的设备必须实现这个寄存器。
与设备无关的配置软件通过对扩展ROM基址寄存器的地址位上写入全“1”,然后再读回以确定设备要求多大的地址范围。
所有的无关位上都返回0,从而有效地指出了地址边界,也就知道了设备要求的这一块地址空间的大小。
一个设备要求的地址空间范围不能超过16MB。
这个寄存器的位0用来控制相应的设备是否能够接受对其扩展ROM的访问。
当该位为0时,禁止访问设备的扩展ROM地址空间;当该位为1时,允许将本寄存器的其它位作为参数进行地址译码。
命令寄存器中的存储器空间位优先于扩展ROM的使能位,但是,如果存储器空间位和扩展ROM的的使能位同时为1时,设备就必须响应对其扩展ROM的访问。
扩展ROM的使能位在复位后应该为0。
4.其他寄存器
其他寄存器包括一些本文不涉及到的寄存器,如中断引脚、中断线等等。
3、PCI控制器
PCI控制器担当PCI接口与CSB(统一系统总线)之间的桥,如下图为MPC8349的PCI控制器结构
主要完成如下功能:
(1)PCI设备配置空间的访问,配置访问寄存器;
(2)CPU和内存空间地址映射(outbound),I/O定序器实现;
(3)PCI设备地址空间的映射(inbound),ATU寄存器;
(4)PCI总线错误和状态等;
1、PCI设备配置空间的访问
CPU通过两个寄存器访问上面介绍的PCI设备配置空间:
CFG_ADDR和CFG_DATA。
下图我MPC8349中对应的两个寄存器:
(1)PCI配置空间对应于一个PCI逻辑设备,所以要访问一个配置空间的某个寄存器,必须要指定:
PCI总线号、PCI设备号、PCI设备功能号和寄存器号。
配置地址寄存器的格式如下:
31
3024
2316
1511
108
72
1
0
使能位
保留
总线号
设备号
功能号
寄存器号
0
0
第0、1位上的“0”是用来要求你只能按双字(4字节)来读写配置空间寄存器。
第31位“使能位”用来决定是否允许访问配置空间:
为“1”时表示可以访问;为“0”时表示不可以访问;
(2)对CFG_DATA的操作就是对配置空间相应寄存器的操作数;
(3)PCI配置空间中的BAR(BaseAddressRegister)用来映射PCI设备的寄存器,里面的值是bus地址首地址,至于空间的大小,先向bar中写0xFFFFFFFFF,然后读取,选最低的一位非0的,比如为0x1000,那个空间的大小就为0x1000。
这里需要注意,当PCI配置成64bit或32bit时,BAR有区别。
2、CPU和内存地址空间映射到PCI地址空间(outbound)
当CPU访问PCI设备的mem空间和io空间的寄存器时,需要进行地址转换。
MPC8349有6个outbound窗口0~5用来将CPU内部地址转换为PCI总线地址。
每个outbound窗口有如下三类寄存器:
(1)外部PCI总线地址的基址outbound窗口转换后(外部PCI总线地址的基址,当使用64bitPCI时会用到第二个扩展寄存器)
(2)CPU内部32bit地址的基址(EA)
(3)窗口属性寄存器,大小、转换类型等等
EN:
设置此窗口是否使能
RTT/WTT:
分别设置此窗口的存取方式(memory或io)
OWS:
设置此窗口大小
3、PCI地址映射到CPU和内存地址空间(inbound)
当PCI设备访问MPC8349时,有3个inbound窗口1~3用来将PCI总线地址转换为CPU内部地址。
和outbound窗口一样,inbound窗口有如下三类寄存器:
(1)CPU内部32bit地址的基址(TA)
(2)外部PCI总线地址的基址(使用64bitPCI时会用到第二个扩展寄存器)
(3)窗口属性寄存器,大小、转换类型等等
EN:
设置此窗口是否使能
PF:
设置此窗口是否开启prefetchable特性
TGI:
TargetInterface,见datasheetP883
RTT/WTT:
设置PCI外设访问CPU时的存取方式(snoopL2cache等等)
IWA:
设置此窗口的大小
3、驱动的实现
嵌入式系统中平台PCI驱动目录结构如下:
该PCI驱动主要分为三个主要部分:
(1)PCI总线的基本操作;
(2)mpc8349的pci控制器的配置;
(3)板级PCI总线的支持和注册;
1、PCI总线的基本操作
(1)数据结构
PCI控制器数据结构,包括了PCI控制基本的信息
typedefstructtagDRV_PciCtrlerInfo_T
{
PLT_INT32lCtrlId;/**PLT_UINT32ulState;/**PLT_UINT32ulCacheLine;/**PLT_UINT32ulLatencyTimer;/**<延迟时序参数*/
reg32_t*pulCfgAddr;/**<配置寄存器地址*/
reg8_t*pucCfgData;/**<配置数据地址*/
void*pvIoseq;/**void*pvCtrl;/**<控制器私有指针*/
PLT_UINT32ulFirstOutbNum;/**PLT_UINT32ulFirstInbNum;/**PLT_UINT32ulTotalRegion;/**DRV_PciRegion_S*apstRegion;/**DRV_PciCfgTable_S*pstCfgTable;/**DRV_PciDevInfo_S*apstDevices
[DRV_PCI_BUS_NUM_MAX][DRV_PCI_DEVICES_NUM_MAX];
/**void(*fpPciReset)(conststructtagDRV_PciCtrlerInfo_T*pstCtrl,PLT_UINT32ulVal);/**PLT_INT32(*fpPciInit)(structtagDRV_PciCtrlerInfo_T*pstCtrl);/**}DRV_PciCtrlerInfo_S;
PCI总线地址访问映射区域数据机构
/**
*\briefpciregion信息
*/
typedefstructtagDRV_PciRegion_T
{
DRV_PCI_ADDR_TulBusStart;/**DRV_PCI_ADDR_TulExtBusStart;/**DRV_PHYS_ADDR_TulPhysStart;/**<物理地址*/
DRV_PHYS_ADDR_TulAddrAlloc;/**<空闲的物理地址,已经分配好的物理地址的尾部*/
DRV_PCI_SIZE_TulSize;/*region大小*/
PLT_UINT32ulFlags;/*region资源标记*/
}DRV_PciRegion_S;
(2)PCI总线的操作
a)PCI设备配置空间的访问接口,实现对PCI设备的配置:
voidDRV_PciConfigByteRead0(constDRV_PciCtrlerInfo_S*pstCtrl,
DRV_PCI_DEV_TulDev,
PLT_UINT32ulWhere,
PLT_UINT8*pucVal);
DRV_PciConfigWordRead0();
DRV_PciConfigDwordRead0();
DRV_PciConfigByteWrite0();
DRV_PciConfigWordWrite0();
DRV_PciConfigDwordWrite0();
b)PCI控制器实例的注册接口,在MPC8349控制器配置后调用此接口完成注册
PLT_INT32DRV_PciCtrlerRegister(DRV_PciCtrlerInfo_S*pstCtrlInfo);
c)向pci控制器注册pci设备,例如DM9102网卡PCI设备注册到PCI控制器,就需要调用此接口
PLT_INT32DRV_PciDevAttach(DRV_PciDevInfo_S*pstDev);
d)pci总线地址到内存物理地址的转换
PLT_INT32DRV_PciBusToPhys(constDRV_PciCtrlerInfo_S*pstCtrlInfo,
DRV_PCI_ADDR_TulBusAddr,
PLT_UINT32ulFlags,
DRV_PHYS_ADDR_T*pulPhyAddr);
e)内存物理地址到pci总线地址的转换
PLT_INT32DRV_PciPhysToBus(constDRV_PciCtrlerInfo_S*pstCtrlInfo,
DRV_PHYS_ADDR_TulPhyAddr,
PLT_UINT32ulFlags,
DRV_PCI_ADDR_T*pulBusAddr);
f)为pci分配outbound空间,输出pci总线地址
PLT_INT32DRV_PciOutBRegionAllocate(constDRV_PciCtrlerInfo_S*pstPciCtrl,
PLT_UINT32ulSize,
PLT_UINT32ulIoMem,
DRV_PCI_ADDR_T*pulBase);
g)为pci分配inbound空间,输出内存物理地址
PLT_INT32DRV_PciInBoundRegionAllocate(constDRV_PciCtrlerInfo_S*pstPciCtrl,
PLT_UINT32ulSize,
PLT_UINT32ulIoMem,
DRV_PHYS_ADDR_T*pulPhys);
h)pci初始化
-1.注册pci控制器
-2.解复位pci总线
-3.pci总线初始化
PLT_INT32DRV_PciInit(void)
2、MPC8349的PCI控制器基本操作
(1)数据结构
a)PCI配置空间访问寄存器
typedefstructtagDRV_PciCfgMpc834x_T
{
reg32_tulCfgAddr;
reg32_tulCfgData;
reg32_tulAck;
reg8_taucRes[116U];
}DRV_PciCfgMpc834x_S;
b)PCI控制器outbound空间数据结构
typedefstructtagDRV_PciOutBWinMpc834x_T
{
reg32_tulPotar;
reg32_tulRes0;
reg32_tulPobar;
reg32_tulRes1;
reg32_tulPocmr;
reg32_tulRes2;
}DRV_PciOutBWinMpc834x_S;
typedefstructtagDRV_IosMpc834x_T
{
DRV_PciOutBWinMpc834x_SastPot[6U];
reg32_tulres0[0x60];
reg32_tulPmcr;
reg32_tulRes1;
reg32_tulDtcr;
reg32_tulRes2;
}DRV_IosMpc834x_S;.
c)PCI控制器错误和状态数据结构
typedefstructtagDRV_PciCtrlMpc834x_T
{
reg32_tulEsr;/*0x00*/
reg32_tulEcdr;/*0x04*/
reg32_tulEer;/*0x08*/
reg32_tulEatcr;/*0x0C*/
reg32_tulEacr;/*0x10*/
reg32_tulEeacr;/*0x14*/
reg32_tulEdlcr;
reg32_tulEdhcr;
reg32_tulGcr;/*0x20*/
reg32_tulEcr;
reg32_tulGsr;/*0x28*/
reg32_taulRes0[3];/*0x34*/
reg32_tulPitar2;/*0x38*/
reg32_tulRes1;
reg32_tulPibar2;/*0x40*/
reg32_tulPiebar2;
reg32_tulPiwar2;
reg32_tulRes2;
reg32_tulPitar1;/*0x50*/
reg32_