免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1439 | 回复: 0
打印 上一主题 下一主题

Linux 系统下基于PCI 控制器(PLX9054)的DMA 编程 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-06-08 14:20 |只看该作者 |倒序浏览

1.引言
在多媒体应用中,在实现视频数据从设
备到主存的传输时,直接内存访问(DMA ,
Direct Memory Access)方式一直是实现大
批量数据快速传输的首选方式。DMA 方式是
依靠硬件在主存和I/O 设备之间进行直接的
数据传送的方式,其传送过程无须CPU 执行
程序来控制干预,能够满足大数据传输的对
速度的要求。DMA 通信高度依赖操作系统和
硬件特性,尤其是在嵌入式环境下,操作系
统、硬件特性和有限的环境资源对DMA 通信
的实现方式和实现手段有很大的影响。在
DMA 通信的具体实现中所遇到的问题则因此
而有所不同。
本文以一个嵌入式视频处理项目为例,
来分析在Linux 系统下实现DMA 编程的主要
问题。在此项目中,视频采集卡采用PLX9054
芯片做PCI 总线接口。视频数据由采集卡生
成,缓存于卡上RAM 存储器中,并通过设备
驱动程序传输到主机内存中。要求编写
Linux 设备驱动程序,利用PLX9054 芯片的
DMA 功能实现将卡上RAM 中的数据快速的传
输到系统的内核内存中。在这里,DMA 编程
主要涉及到PCI 接口、PLX9054 芯片和Linux
系统。
Linux 内核的发展很快。内核版本不同,
设备驱动程序的结构、所使用的硬件接口和
相关的内核支持函数可能会有很大的区别。
因此在Linux 系统下做驱动程序,必须确定
内核的版本。本项目所用的Linux 内核版本
是在2.4.20。下面所介绍的内容全部以该版
本为基础。
2.PCI 及PLX9054
PCI 是外围设备互连( Peripheral
Component Interconnect)的简称,它是一
种通用总线接口标准。PCI 提供了一组完整
的总线接口规范、电气特性和行为规约,通
过该规范,计算机系统中的外围设备能够实
现结构化、可控化的连接以及正确地进行交
互。PCI 设备上有三种地址空间:I/O 空间、
存储空间和配置空间。配置空间的信息主要
包括:设备识别号、供应商代码号、Local
总线三个空间的大小以及三个空间的基址
等。在计算机启动时,系统将根据配置信息
分配系统资源。CPU 可以访问PCI 设备上的
所有地址空间,其中I/O 空间和存储空间提
供给设备驱动程序使用,而配置空间则由
Linux 内核中的PCI 初始化代码使用。PCI
总线接口因其传输速度快、即插即用、自动
配置的优点而成为实现数据采集设备到主
机之间的接口的首选。
PLX9054 是PLX 公司生产的PCI 总线接
口控制器芯片。PLX9054 符合PCIV2.2 规范,
32 位,工作频率为33MHz,拥有两个独立的
DMA 通道,传输速度达132MB/s。PLX9054
提供了PCI 总线、EEPROM、LOCAL 总线三个
接口,其中LOCAL 总线有三种工作模式:M
模式、C 模式和J 模式。在实际的数据采集
时, LOCAL 总线接口一般设置为C 模式。
PLX9054 芯片在PCI 总线和LOCAL 总线之间
有三种直接的数据传输模式:PCI Initiator
模式--LOCAL 总线主设备通过PLX9054 访问
PCI 总线存储空间和I/O 空间;PCI Target
模式--PCI 总线主设备通过PLX9054 访问
LOCAL 总线存储空间和I/O 空间;DMA 方式
--PLX9054 作为两总线的主设备,实现PCI
总线存储空间与LOCAL 总线存储空间之间的
数据传输。
PLX9054 的DMA 模式有两种:block 模
式 --单块连续数据传输。这种模式适合于
源、目的存储空间连续,数据连续存放的传
输,最大传输长度为4MB;scatter/gather
模式--多块分散数据传输。该模式允许源、
目的存储空间不止一个,块地址不连续。
我们的视频采集卡LOCAL 总线接口设置
为C 模式,数据传输模式使用PCI Target
和DMA 两种:PCI Target 用于对控制模块中
的寄存器进行读写,用于采集方式的设定;
DMA 用于视频数据的传输。DMA 模式采用
block 模式。设计选用PLX9054 的DMA0 通
道实现数据由本地RAM 到主存的传输。
PLX9054 DMA0通道的操作涉及到如下的
控制寄存器( 详见9054db-21.pdf 文档的
P11-34,P11-35,P11-38):
寄存器 偏移地址功能
DMAMODE0 (PCI:80H) 设置局部总线工作模
式,中断使能等
DMAPADR0 (PCI:84H) PCI总线上的地址,主
存地址,必须是物理地

DMALADR0 (PCI:88H) 局部总线的地址,存储
空间在局部总线的地

DMASIZE0 (PCI:8CH) 需传送数据的长度,以
字节为单位,最大4MB
DMADPR0 (PCI:90H) 设置传输方向,
scatter/gather模式
的描述块地址等
DMACSR0 (PCI:A8H) DMA0的使能和启动,中
断的清除
INTCSR (PCI:68H) 设置PCI中断使能等
3.Linux 系统下的DMA 编程
从上面的介绍看,要实现对PLX9054 的
DMA 操作,设置DMA 控制寄存器,设备驱动程
序需要做两件事:一是收集设备信息;二是
建立DMA 操作环境。
PCI 设备信息包括两类:一类是PCI 卡
的设计约定信息:PLX9054 的工作模式、控
制寄存器的偏移地址说明、局部总线存储器
地址、卡上RAM 容量、局部总线上的设备操
命令及时序。约定信息是设备设计时产生
的,在DMA 操作时直接引用就可以了。另一
类是PCI 配置信息:PLX9054 控制寄存器的
I/O 基地址、局部总线控制寄存器I/O 基地
址、设备中断号。配置信息是计算机启动时
自动配置的,需要通过设备驱动程序读取。
在早期的Linux 系统中,编程者需要通过系
统调用自行编写代码实现读取PCI 设备配置
空间信息。
在x86 平台下,Linux 2.4 内核将BIOS
检测到的所有PCI 设备的相关信息-包括
PCI 配置信息-都存储在pci_dev 结构中,并
链接到pci_devices 链表中了。因此配置信
息是在PCI 设备初始化阶段直接获取的。
建立DMA 操作环境的工作包括:PCI 设
备检测和初始化、DMA 缓冲区分配和中断处
理。
3.1 PCI 设备检测和初始化
PCI 设备检测和初始化要完成的工作
有:PCI 设备搜索、PCI 设备使能、DMA 地
址长度设定、设备I/O 资源、MEM 资源请
求、中断注册、保存PCI 配置信息等。
PCI 设备检测和初始化通过专门的注册
函数pci_register_driver 来实现。该函数通过
pci_driver 结构向系统提供设备探测(probe)
和注销(remove) 函数接口, 并根据
pci_device_id 结构中的设备ID 来对
pci_devices 链表进行搜索。一旦找到目标
PCI 设备,pci_register_driver 函数调用设备
探测函数并向该函数传递该设备的pci_dev
变量,由设备探测函数完成对设备的初始
化。下面给出主要的数据结构和函数内容。
//PCI 设备信息描述结构
struct pci_device_id
my_pci_table[] = {
{
vendor_id,
device_id,
0,0,0,0,0
},
{0,} //最后以0 结尾
};
//PCI 设备结构(包括设备名称、探测函数、
热插拔时的注销函数和PCI 设备信息描述
数组)
struct pci_driver my_pci = {
name: MY_DEVICE_NAME,
id_table: my_pci_table,
probe: my_pci_probe,
remove:my_pci_remove,
};
//PCI 设备注册
pci_register_driver(&my_pci);
//设备探测函数
probe( struct pci_dev * pdev,const struct
pci_device_id * pdevid)
{
//PCI 设备使能
pci_enable_device(pdev);
//DMA 掩码设置
pci_set_dma_mask(pdev, DMAMASK));
//I/O、MEM 资源注册
pci_request_regions(pdev,DEV_NAME);
//中断注册, my_pci_interrupt 为中断处
理函数
request_irq( pdev->irq, my_pci_interrupt ,
SA_SHIRQ, DEV_NAME, 0 )
//PCI 配置信息保存
io_port_addr = pci_resource_start(pdev,3);
io_dma_addr = pci_resource_start(pdev,1);
irq = pdev->irq;
}
//设备注销函数
remove( struct pci_dev *pdev)
{
//注销资源
pci_release_regions(pdev);
//释放中断
free_irq( pdev->irq, 0 );
//停用PCI 设备
pci_disable_device(pdev);
}
3.2 DMA 缓冲区的分配
在使用DMA 方式传输数据时,设备使
用局部总线和PCI 总线将数据从本地RAM
传输到主存,数据被存放在连续的内存块
中,而在PC 上PCI 总线地址就是物理地址,
因此提供给DMA 的主存地址和局部总线地
址必须是物理地址,而且缓冲区必须是物理
连续的。对于PLX9054 的scatter/gather 模
式,每一个内存块也必须是连续的物理空
间。
此外, 可供DMA 使用的主存地址空
间是有限制的。Linux 内核将内存分为三个
区段:可用于DMA 的内存、常规内存和高
端内存。可用于DMA 的内存是唯一能够和
外部设备进行DMA 数据传输的内存。这种
限制是由连接外部设备到处理器的地址总
线的数量小于访问内存的地址总线的数量
造成的。因此在分配DMA 缓冲区时必须声
明该空间是允许DMA 使用的。在Linux 2.4
的内核中,可用于DMA 的内存空间范围是
0 至16MB。在本项目的硬件环境中,实测可
以分配到的总的DMA 缓冲区是11MB。
因此,DMA 缓冲区的分配要求是:物
理连续、DMA 可以访问、足够大。Linux
系统是使用虚拟地址的系统。系统的内存分
配函数提供的地址都是虚拟地址,必须经过
virt_to_bus 函数转换才能得到物理地址。分
配内核内存空间的函数有三个: kmalloc --
该函数实现小于128KB 的内核内存的申请,
所申请的空间物理连续;__get_free_pages --
实现最大2MB 的内存申请(在Linux 2.4 的
内核下),以页为单位,所申请的空间物理
连续;vmalloc -- 所分配的内存空间不保证
物理连续。此外, Linux 2.4 内核还提供了
一个专门用于PCI 设备申请内核内存的函
数pci_alloc_consistent,该函数支持按字节
长度申请。通过对内核的分析,该函数是通
过__get_free_pages 函数实现对内核内存的
分配,因此,其可能的最大分配空间也是
2MB。
从上面的分析可以看出,Linux 2.4 内核
中能够用于分配DMA 缓冲区的函数有三个:
kmalloc 、__get_free_pages 和
pci_alloc_consistent,而且最大可分配的内存
为2MB。
在处理视频等大数据量的嵌入式系统
中,很多情况下数据都会超过2MB,因此
必须实现超过2MB 的内核内存的申请。在
本项目中采取如下方法:增加一套内存管理
机制,用__get_free_pages 函数连续申请
DMA 内存块,然后将这些块地址排序并从
中找到符合要求的连续的块集,将这些块组
合成满足大小要求的DMA 缓冲区。使用完
毕后,在通过管理机制释放这些内存块。另
外, 如果PLX9054 在设计时支持
scatter/gather 模式,那也可以申请多个不连
续的、大小小于2MB 的DMA 缓冲区,从
而解决DMA 缓冲区的尺寸问题。
申请DMA 缓冲区的时机要根据数据的
变化情况和处理数据的要求来决定。在本项
目中,数据长度固定不变,处理简单,缓冲
区可重复使用。因此申请缓冲区的代码被放
在驱动初始化阶段完成。卸载驱动时再释放
缓冲区。
3.3 中断处理
Linux 系统通过request_irq 函数实现中
断处理程序的注册。本项目的中断处理比较
简单,仅需要清除中断信号并将缓冲区标志
置位即可。需要注意的问题有两点:一是PCI
设备注册中断时必须使用的共享中断方式,
因此,在中断处理程序中增加了对中断源的
检查;二是PLX9054 的中断信号一旦产生
就一直有效,必须通过代码清除中断。在
PLX9054 中有专门的寄存器来清除中断位
(见DMA 控制寄存器-DMACSR0)。
通过上述准备工作,DMA 操作的实现
环境就完全建立起来了。数据采集的触发采
用用户需求驱动,即当应用程序需要图像
时,向驱动程序发出采集指令。应用程序通
过轮询标志位确定DMA 缓冲区是否准备好
数据。整个数据传输过程如下:设备驱动程
序向局部总线控制寄存器发出采集命令,视
频采集卡采集信号并生成一帧图像,缓存于
卡上RAM 中。设备驱动程序通过轮询确定
采集是否结束。数据准备完毕后,将收集的
信息写入各DMA 控制寄存器,触发DMA
传送数据。数据传送完毕后产生中断。中断
处理程序清除中断源,设置DMA 缓冲区准
备好的标志位。
以下是PLX9054 DMA 控制寄存器的
值,仅供参考。
DMAMODE0= 0x20443
DMAPADR0= 0x700000
DMALADR0= 0x800000
DMASIZE0= 0x300000
DMADPR0 = 0x08
DMACSR0 = 0x03
INTCSR = 0x40100
4.总结
综上所述,DMA 通信高度倚赖操作系
统、硬件特性和资源。在实现DMA 通信的
过程中,项目要求、DMA 本身的特点、操
作系统提供的支持、具体硬件特性以及系统
资源之间是相互作用的。DMA 环境的建立
过程,就是各部分相互协调、互为支持的过
程。DMA 编程必须充分了解控制芯片的所
提供的手段和限制,这些手段和限制是实现
DMA 的基础。在Linux 系统下实现DMA
通信,需要处理的主要问题有:DMA 缓冲
区的物理连续问题、PCI 设备检测和初始化
问题、缓冲区的大小问题、PCI 设备信息收
集问题等。此外,由于Linux 内核的发展变
化,系统提供的编程资源因内核的不同而变
化,编程者必须充分了解所选内核版本提供
的支持以及这种支持的发展方向。
参考文献
[1]. Alessandro Rubini, Jonathan Corbet, 魏
永明译.Linux 设备驱动程序(第二版)[M].中
国电力出版社.2002.11.
[2]. 俸远祯等.计算机组成原理(修订本)[M].
电子工业出版社.1996.4.
[3]. 王长清 顾 红.基于PCI 总线的大容量
雷达数据采集系统的设计[J]. 电子工程
师.2002,Vol.28,No.8.
[4].PLX9054 Data Book V2.1[S],2000.1


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/15278/showart_317493.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP