Linux下的PCI_Express设备驱动程序的研究与实现

合集下载

Linux下PCI驱动程序的开发

Linux下PCI驱动程序的开发
算 机 系统 中应 用最 为广 泛 , 且 最 为通 用 的总 线标 准 。 并 Ln x的 内核 能较 好地 支 持 P I iu C 总线 , 论 述基 于 P X 本 L
用 3 2位 数 据 总 线 , 但
PI C 规范 中已 经 给 出 了 6 4位 的扩 展 实现 , 而 从
使 PI C 总线能 够更好 地
气 特性 和行 为 规约 ,并 且 详 细定 义 了计 算 机 系统 中的 各 个不 同部件 之 间应该 如何 正确 地进 行交 互 。
无论 是 在基 于 It 芯 片 的 P ne l C机 中 ,或 是 在 基 于
Apa芯 片 的工 作 站 上 ,C 毫 无 疑 问 都是 目前 使 用最 lh PI 广 泛 的 一种 总 线 接 口标 准 。 同 旧式 的 IA 总 线 不 同 , S
信. 电技 术
2 1 年( 3 卷) 1 00 第 9 第 期
来 完 成 同总线 子系统 的交 互 , 图 1 示 。 见 所
以像普通文件一样来看待 :它们可以使用和操作文件
相 同 的 、 准 的 系统 调 用 接 口来 完 成 打 开 、 闭 、 写 标 关 读 和I / O控制 操作 , 驱动程 序 的 主要任 务也 就是 要 实现 而
1 9
由于 使 用 了更 高 的时 钟频 率 ,因此 P I C 总线 能够
关键 词 : iu ; C 驱 动 ; 动架 构 Ln x P I 驱
Ln x 作 系 统 因 为其 高效 、 全 、 动 态 加 载 及 iu 操 安 可
源代码 开放 等 特点 ,深受 设 备驱 动 程序 开 发人 员 的喜
获得 比 IA总线更 好 的 S 整 体性 能 。P I C 总线 的 时 钟 频 率 一 般 在

Linux下PCI设备驱动开发方法及应用实例

Linux下PCI设备驱动开发方法及应用实例

种 平台 和 体 系结 构 中 采用 不 同 的方 法 设 计出 各 种 PCI 接 口 卡 , ule 函数从内核中将该驱动程序卸载, 否则返回出错信息。
编 写出 各 种 平台 下 的 接口 卡 驱 动程 序 实 现控 制 系 统高 速 、高 精
1.3 设备驱动程序接口
度、低功耗下通过 PCI 总线对外围 I/O 设备的操作。
1.4 设备驱动程序结构 Linux 的设备驱动程序大致可以分为如下几个 部 分:驱动 程 序 的注 册 与 注销 、设 备 的打 开 与 释放 、设 备 的读 写 操 作、设 备 的
的 内容 , 如 果 缓冲 区 中 的数 据 能 满足 用 户 的要 求 就 返回 相 应 的 控制 操 作 、设备 的 中 断和 轮 询 处理 。驱 动 程序 的 注 册是 通 过 内
struct file_operations dispatch_table; /* 系 统 参 数 dis- patch_table 是 设 备 驱动 程 序 对 应 用 程 序 提 供 诸 如 打 开 , 读 写 , I/ 0 控制等等操作的入口 */
}dev_object ; 3.1 初始化 PCI 设备 在初 始 化 PCI 设 备 时 , 首 先 要 检 查 PCI 总 线 是 否 被 Linux 内 核 支持,主 要 是通 过 内 核函 数 pci_ present()来 实 现 , 该 函 数 用 来 确 定 PCI 总 线 是 否 己 经 被 Linux 内 核 支 持 。 然 后 调 用 pci_ find_device()函数 用 来 查找 系 统 中存 在 的 第一 个 PCI 设 备, 函 数 如下所示: pci_ find_device( PCI_ANY_ID, PCI_ANY_ID,NULL); 该函数检查设备是否插在总线插槽上, 如果在的话则保存

一、如何编写LinuxPCI驱动程序

一、如何编写LinuxPCI驱动程序

⼀、如何编写LinuxPCI驱动程序PCI的世界是⼴阔的,充满了(⼤部分令⼈不快的)惊喜。

由于每个CPU体系结构实现不同的芯⽚集,并且PCI设备有不同的需求(“特性”),因此Linux内核中的PCI⽀持并不像⼈们希望的那么简单。

这篇简短的⽂章介绍⽤于PCI设备驱动程序的Linux APIs。

1.1 PCI驱动程序结构PCI驱动程序通过pci_register_driver()在系统中"发现"PCI设备。

事实上,恰恰相反。

当PCI通⽤代码发现⼀个新设备时,具有匹配“描述”的驱动程序将被通知。

详情如下。

pci_register_driver()将设备的⼤部分探测留给PCI层,并⽀持在线插⼊/删除设备[因此在单个驱动程序中⽀持热插拔PCI、CardBus和Express-Card]。

pci_register_driver()调⽤需要传⼊⼀个函数指针表,从⽽指⽰驱动程序的更⾼⼀级结构体。

⼀旦驱动程序知道了⼀个PCI设备并获得了所有权,驱动程序通常需要执⾏以下初始化:启⽤设备请求MMIO / IOP资源设置DMA掩码⼤⼩(⽤于⼀致性DMA和流式DMA)分配和初始化共享控制数据(pci_allocate_coherent())访问设备配置空间(如果需要)注册IRQ处理程序(request_irq())初始化non-PCI(即LAN/SCSI/等芯⽚部分)启⽤DMA /处理引擎当使⽤设备完成时,可能需要卸载模块,驱动程序需要采取以下步骤:禁⽌设备产⽣irq释放IRQ (free_irq())停⽌所有DMA活动释放DMA缓冲区(包括流式DMA和⼀致性DMA)从其他⼦系统注销(例如scsi或netdev)释放MMIO / IOP资源禁⽤该设备下⾯⼏节将介绍这些主题中的⼤部分。

其余部分请查看LDD3或<linux/pci.h>。

如果PCI⼦系统没有配置(没有设置CONFIG_PCI),下⾯描述的⼤多数PCI函数都被定义为内联函数,要么完全空,要么只是返回⼀个适当的错误代码,以避免在驱动程序中出现⼤量ifdefs。

Linux系统下PCI设备驱动程序的研究

Linux系统下PCI设备驱动程序的研究

配置头。 目前 P I2 C2 规范定义 了 3 . 种配置头格式 , 分别是 0 1 2 , 和 型配 置头 。其 中类型 0 为标准的 P I C 应用设备 , 指除类型 l 和类 型 2 的所 外
有PI C 设备 。类型 ‘ 为 P IP I I C— C 桥设 备 , 于对 P I 用 C 总线扩展 , 将两条
置寄存器组 成 , P I 在 C 配置空间中对 P I 备信息进行描 述 , C设 包括设备
图 1 PI C 总线的体 系结构
P I 外围设备互联 (epeaC m oetn r net的简称 。 C是 P rhr o pnn Ie onc i l tc ) 作 为一种通用 的总线接 口标准 。 它在 目前的计算机系统中得到了2 P I a u 桥 , 为 C— r s 主要用于笔记本 的插 卡式 CB 总线 。这里只对类 型 0的配置头加以说 明, 配置空间见图 2 。 组成 P I C 配置空 问的寄存器 当中包括 厂商代码 、 设备号 、 版本号 、 类 别 号 、 系统 厂商号和子 系统号 , 些寄存 器标 明 P I 子 这 C 设备类 , 启动 时。 系统将根据这些寄存器辨 别出 P I C 设备 , 并为它加载 相应 的驱动程
20 年 第 1 卷 第 2 期 06 6 3
收稿 日 : 0 — 7 1 期 2 6 0—5 0
Lnx系统 下 P I i u C 设备驱动程序 的研究
贺金平 , 刘永祥 , 杨 吕
( 昆明理工大学信息工程与 自动化学院 , 云南昆明 ,5 0 1 6 05 )
摘 要 :C 总线提 供 了许 多优于其他 总线标准( ES PI 如 IA) 新特性 , 目前 已经成 为计
由于一个计算机系统 中可 能有多个主设备 , 墨 l 由l 可知 . 】 这些设备 都直接或间接地连接在 P I C 总线上 , 它们有可能在同一时间都需要 占用 P1 C 总线。这将发生 P I C 总线的竞 争问题 。为 了解决竞争使 用总线 的问 题, P1 在 C 总线上配备 了总线 仲裁器。 在一个 P 1 C 应用 系统 中。 了总 取得 线控制权的设备称为“ 主设备”而被主设备选中以进 行通信 的设备称为 , “ 从设备” “ 标 设备 ” 或 目 。外部设备如果要使用 P I C 总线 , 首先发 出总线

Linux下PCI设备驱动开发详解

Linux下PCI设备驱动开发详解

一、设备驱动程序概述自Linux在中国发展以来,得到了许多公司的青睐。

在国内的玩家也越来越多了,但目前还是停留在玩的水平上,很少有玩家对Linux的系统进行研究。

因为它的开放,我们可以随时拿来“把玩”。

这也是Linux一个无可比拟的优势,这样我们可以修改后再加入到里面。

但很少有专门的书籍讲到Linux驱动程序的开发,像上海这样的大城市也很少有讲Linux驱动开发的资料,唉,谁让这个是人家的东西呢,我们还是得跟着人家跑。

我现在讲的这些驱动开发的细节,并不特定哪个版本的内核,这只是大体的思路与步骤。

因为大家都知道Linux 2.6.x 与Linux 2.4.x是有不少改动的。

所以,具体的大家可以去参考Linux Device Driver 2.4 和Linux Device Driver 2.6这几本书。

这是我们学习开发驱动必不可少的东西。

好了,下面就开始学习吧。

根据设备的行为,我们可以把设备分为字符设备和块设备,还有网络设备。

字符设备是以字节为单位进行顺序读写,数据缓冲系统对它们的访问不提供缓存。

而块设备则是允许随机访问与读写,每次读写的数据量都是数据块长度的整数倍,并且访问还会经过缓冲区缓存系统才能实现。

与Unix版本不同的是:Linux的内核允许不是数据块长度整数倍的数据量被读取,用官方的语言就是:但这种不同只是纯粹学术方面的东西。

大多数设备驱动程序都要通过文件系统来进行访问的,但网络设备是不同的。

/dev子目录里都是关于设备的特殊文件,但看起来它们与普通的目录没有什么两样。

如下:$ ls -l /dev...brw-rw--- 1 root disk 22, 1 May 5 1998 hdc1crw-rw--- 1 root daemon 6 0 May 5 1998 lp0与普通文件有所不同是开头的“C” 和“B”,即char 和block的意思,即字符设备和块设备。

再后面的“22,1” 和“6,0”即设备的主设备号和次设备号,主设备号表明它是哪一种设备,这与你在Windows里添加硬件时看到的那些是一个意思。

Linux 2.6.10内核下PCI Express Native热插拔框架的实现机制

Linux 2.6.10内核下PCI Express Native热插拔框架的实现机制

Linux 2.6.10内核下PCI Express Native热插拔框架的实现机制王兵 (bingwang_nudt@)国防科学技术大学计算机学院软件所2005 年 8 月 01 日PCI热插拔技术,可以有效避免由更换外设引起的服务器系统停机,对于提高服务器系统可用性和可扩展性意义重大。

本文讨论了PCI Express热插拔所涉及的软件因素,并基于此,剖析了Linux 2.6.10内核下PCI Express 插槽热插拔子系统的关键实现机制。

一相关技术与研究1997年,PCI SIG制定了第一个PCI热插拔规范,其中定义了支持热插拔所必需的平台、板卡和软件元素。

PCI SIG推出了标准热插拔控制器规范(SHPC SPEC),其中明确了热插拔的标准使用模式和严格的寄存器组要求,并且允许操作系统提供商在平台特定的软件之外提供热插拔支持,逐步完成了热插拔标准制定工作,进入技术的全面推广阶段。

2002年以后,Intel把热插拔作为一种天然属性赋予新推出的PCI Express规范,PCI Express热插拔总结了五年来工业标准的经验,具有如下特点:•基于SHPC模式并对其进行了功能扩展;•PCI Express从设计上就把热插拔寄存器集成进入了其标准的性能寄存器组(而在SHPC 1.0中,热插拔寄存器是附加的);•提供给操作系统一个统一的热插拔硬件寄存器接口,赋予了操作系统进行原生热插拔(绕过了传统基于BIOS的热插拔方法)的能力;•通过在基本的体系机构层次定义热插拔必须的硬件要求,完善了一种标准的使用模式;•提供了规格参数来保证OEM产品的低成本而高平台可靠性。

具有完整功能的PCI Express热插拔系统在平台硬件和固件支持之外,还必须有操作系统以及设备驱动程序的支持。

在各大芯片厂商纷纷推出支持PCI热插拔的产品的同时,Microsoft,Novell,SCO等公司在他们相关的操作系统中也都包括了支持热插拔的技术,Novell NetWare 4.11&5和SCO UnixWare 7以及更新版本支持完整PCI热插拔(热替换和热添加)。

linux设备驱动之pci设备的IO和内存

linux设备驱动之pci设备的IO和内存

linux设备驱动之pci设备的I/O和内存------------------------------------------Pci设备的I/O和内存是一个比较复杂的问题.如下的总线结构:在上图的总线结构中,ethernet设备和pci-pci bridge的同类型资源空间必须要是pci bus0的一个子集例如,pci bus 0的I/O端口资源是0x00CC~0x01CC. Ethernet设备的I/O范围的是0x00CC~0x0xE0.那么pci-pci bridge的I/O端口范围就必须要在0x0xE0~0x01CC之间. 同样,SCSI和VIDEO同类型资源必须要是pci_bus1的子集.pci bus1上有一个pci桥,对应的资源也就是它所连桥上的资源.即pci_bus->self.也就是说,下层总线的资源是它上层总线资源的子集。

上层总线资源是下层总线资源的父集。

其实,每个PCI设备的资源地始地址都是由操作系统设置的.在x86上,都由bios设置好了.假若没有bios的时候,我们应该怎么去设置设备的资源起始范围呢?可能在pci枚举完成之后:1:从根总线开始,设置根总线的资源范围是从0开始,到0xFFFF或者0xFFFFFFFF的最大范围. 2:对其它的设备,可往其资源寄存器全部写入1,就可以求得该资源项的类型和长度.3:设备从根总线的资源那里分得对应长度的资源.4:如果设备是pci-pci bridge,则递归配置它.可能有人会有这样迷惑,对应于上图,如果pci-pci bridge的资源大小是N.而SCSI和video资源范围超过了N怎么办呢?我们必须要注意一点,总线的区间是可以自已设定的,而设备资源的区间是在设计的时候就已经确定好了.也就是说,我们可以更改pci device区间的起始地址,但我们不能改变它的大小.因此,出现了上面所说的这种情况.可能是由bios在处理PCI的时候出现了BUG.我们需要调整总线的资源区间.其实对于pci_bus的资源范围就是它的过滤窗口.对于过滤窗口的作用,我们在枚举的时候分析的很清楚了.CPU访问PC过程是这样的(只有一个根总线和pci-pci bridge过滤窗口功能打开的情况): 1:cpu向pci发出一个I/O请求.首先经过根总线.它会判断是否在它的资源范围内.如果在它的范围,它就会丢向总线所在的每一个设备.包括pci bridge. 如果没有在根总线的资源范围,则不会处理这个请求.2:如果pci设备判断该地址属于它的资源范围,则处理后发出应答4:pci bridge接收到这个请求,它会判断I/O地址是否在它的资源范围内.如果在它的范围,它会把它丢到它的下层子线.5:下层总线经过经过相同的处理后,就会找到这个PCI设备了一个PCI设备访问其它PCI设备或者其它外设的过程:1:首先这个PCI发出一个请求,这个请求会在总线上广播2:如果要请求的设备是在同级总线,就会产生应答3:请求的设备不是在同层总线,就会进行pci bridge.pci桥判断该请求不在它的范围内(目的地不是它下层的设备),就会将它丢向上层.4:这样辗转之后,就能找到对应的设备了经过这样的分析过来,相信对pci bridge的过滤窗口有更深的理解了.Linux中使用struct resource的结构来表示I/O端口或者是设备内存。

linux中pcie设备初始化流程

linux中pcie设备初始化流程

linux中pcie设备初始化流程PCIe(Peripheral Component Interconnect Express)是一种高速串行总线接口,用于连接计算机主板和外部设备。

在Linux系统中,PCIe设备的初始化是一个重要的过程,它确保设备能够正常工作并与系统进行通信。

本文将介绍Linux中PCIe设备初始化的流程。

1. 设备检测与识别在Linux系统启动时,内核会进行设备检测与识别的过程。

对于PCIe设备,内核会扫描PCIe总线,识别连接在总线上的设备。

这个过程是通过读取PCIe设备的配置空间来完成的。

配置空间是一块特殊的内存区域,包含了设备的各种信息,如设备ID、厂商ID、设备类别等。

2. 分配资源一旦设备被识别,内核会为其分配必要的资源,如内存空间、中断线等。

这些资源的分配是通过解析设备的配置空间来完成的。

内核会根据设备的需求和系统的可用资源进行分配,以确保设备能够正常工作。

3. 驱动加载设备的驱动程序是用来控制和管理设备的软件模块。

在Linux系统中,驱动程序是以内核模块的形式存在的。

一旦设备被识别并分配了资源,内核会加载与之对应的驱动程序。

驱动程序会与设备进行通信,配置设备的寄存器、中断等,并提供相应的接口供用户空间程序使用。

4. 设备初始化设备初始化是指对设备进行一系列的配置和初始化操作,以使其能够正常工作。

设备初始化的具体过程是由设备的驱动程序来完成的。

驱动程序会根据设备的特性和需求,对设备进行相应的配置和初始化。

这包括设置设备的工作模式、参数、中断处理等。

5. 设备注册设备注册是将设备与系统进行关联的过程。

在Linux系统中,设备注册是通过设备模型来完成的。

设备模型是一种用于描述和管理设备的框架,它提供了一套标准的接口和方法,用于设备的注册、管理和访问。

设备注册的过程包括将设备添加到设备模型中,并分配设备号等。

6. 设备启动设备启动是指设备开始正常工作的过程。

在Linux系统中,设备启动是由设备的驱动程序来完成的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Linux下的PCI-Express设备驱动程序的研究与实现邵科技 赖新(江南计算技术研究所,江苏 无锡 214083)摘 要本文研究了Linux下的PCI-Express高速数据采集卡的驱动程序,在内核空间申请了足够大的DMA循环缓冲区,从而满足了系统对高速数据实时采集处理的要求。

分别实现了查询模式和中断模式下的驱动程序,并通过实验结果的分析表明了中断模式在其性能上的优异性,提出了PCI-Express设备驱动程序进一步优化的方向。

关键词Linux;PCI-Express;DMA;设备驱动;中断1 引言PCI-Express已经成长为新一代的I/O总线技术的主流,已经在服务器、存储系统、通信系统、数据处理、传输系统等领域中得到广泛的应用。

基于PCI-Express总线的高速数据采集卡是信息处理系统中一个非常重要的设备,而驱动程序是硬件和操作系统之间的桥梁,对硬件设备的性能有着很大的影响,高效的驱动程序是实现高速数据实时采集、处理的一个重要保证。

因此本文针对PCI-Express高速数据采集卡在Linux系统下的驱动程序进行了研究,并就如何设计和实现Linux下的驱动程序进行了深入的探讨。

2 Linux设备驱动程序2.1 驱动程序的功能驱动程序的作用是应用程序与硬件之间的一个中间软件层,硬件通过驱动程序向应用程序展现其具有的功能。

Linux 将所有外部设备看成是一类特殊文件[1],称之为“设备文件”,如果说系统调用是Linux内核和应用程序之间的接口,那么设备驱动程序则可以看成是Linux内核与外部设备之间的接口。

设备驱动程序向应用程序屏蔽了硬件在实现上的细节,使得应用程序可以像操作普通文件一样来操作外部设备。

Linux操作系统抽象了对硬件的处理,所有的硬件设备都可以像普通文件一样来看待:它们可以使用和操作文件相同的、标准的系统调用接口来完成打开、关闭、读写和I/O控制操作,而驱动程序的主要任务也就是要实现这些系统调用函数。

Linux系统中的所有硬件设备都使用一个特殊的设备文件来表示,例如,系统中的第一个IDE硬盘使用/dev/hda表示。

每个设备文件对应有两个设备号:一个是主设备号,标识该设备的种类,也标识了该设备所使用的驱动程序;另一个是次设备号,标识使用同一设备驱动程序的不同硬件设备。

设备文件的主设备号必须与设备驱动程序在登录该设备时申请的主设备号一致,否则用户进程将无法访问到设备驱动程序。

2.2 设备和模块的分类Linux系统将设备分成字符设备(Char Device)、块设备(Block Device)、网络设备(Network Device)三种基本类型。

字符设备是个能够像字节流(类似文件)一样被访问的设备,是以字节为单位逐个进行I/O操作,在对字符设备发出读写请求后,实际的硬件I/O紧接着就发生了;块设备和字符设备类似,两者之间的区别仅仅在于内核内部管理数据的方式上,也就是内核及驱动程序之间的软件接口上。

块设备则是利用一块系统内存作为缓冲区,当用户进程对设备进行读写请求时,驱动程序先查看缓冲区中的内容,如果缓冲区中的数据能满足用户的要求就返回相应的数据,否则就调用相应的请求函数来进行实际的I/O操作。

块设备主要是针对磁盘等慢速设备设计的,其目的是避免耗费过多的CPU时间来等待操作的完成。

网络设备,任何网络事务都经过一个网络接口,即一个能够和其它主机交换数据的设备。

Linux系统下的设备驱动程序可以按照两种方式进行编译,一种是直接静态编译成内核的一部分,另一种则是编译成可以动态加载的模块。

如果编译进内核的话,会增加内核的大小,还要改动内核的源文件,而且不能动态地卸载,不利于调试,因此推荐使用动态模块加载的方式。

3 PCI-Express驱动程序设计与实现3.1 PCI-Express驱动程序实现的难点传统的PCI/PCI-X总线传输最高突发速率是512Mbps,这远远不能满足对高速信号实时采集处理传输的需要,因此在设计时采用了PCI-Express总线来代替传统的PCI总线。

PCI-Express与PCI在软件上兼容,但在硬件上改为串行差分传输,其主要优点是时延短、传输快、带宽提升潜力大和节省空间。

PCI-Express采用的是点对点通信机制,各个插槽都将通过各自独享的通道发送和接收数据,这样就可以避免出现不同设备同时争抢系统和CPU资源的情况。

PCI-Express 有x1、x2、x4、x8、x16和x32多种线宽,如x1的传输带宽为2.5Gbps,x2为5Gbps,依次类推。

因此与以往PCI设备驱动程序在实现上不同的是基于Linux下的PCI-Express设备的驱动程序必须要注重考虑数据传输的速度和效率。

以往的Liunx下PCI设备最大只能申请到11M的DMA内核缓冲区,显而易见这不能满足高速率数据传输的要求,同时在传输过程中对数据的抗抖动性也很差,因此为了能够很好的达到实际的应用要求,同时又能在数据传输过程中具有很好的抗抖动性,如何实现大容量的DMA 内核缓冲区的申请、采用何种数据传输模式实现等等都是PCI-Express设备程序在设计时需要重点考虑和深入研究的。

3.2 PCI-Express逻辑结构图图1是PCI-Express高速数据采集卡逻辑图。

PCI-Express 高速数据采集卡对接入的光信号经过光电转换模块进行转换成电信号后,再经过一系列的相关处理后经PCI-Express总线传输通过驱动程序传输至应用软件进行处理,传输带宽为PCI-Express x4。

即单方向具有10Gbps的传输带宽。

本项目中实现的PCI-Express高速数据采集卡在Linux系统中可以被认为一种字符设备。

在用模块方式实现PCI-Express设备驱动程序时,通常至少要实现以下几个部分:初始化设备模块、设备打开模块、数据读写和控制模块、中断处理模块、设备释放模块、设备卸载模块等。

因此本文下面对如何分配和实现大容量的DMA 循环缓冲区、及DMA数据传输处理模式的选择作了重点的研究并进行了详细的阐述。

图1 PCI-Express高速数据采集卡逻辑图3.3 DMA循环缓冲区的分配与实现对于高速数据信号的采集处理,需要在驱动程序的初始化模块中即系统成功加载驱动程序的过程中申请大量的DMA循环缓冲区,DMA缓冲区申请的大小直接关系着能否实时对高速数据处理的成败。

直接内存访问或者叫DMA是实现高速数据快速传输处理的一种重要手段,DMA是一种硬件机制,它允许外围设备和主内存之间直接传输它们的I/O 数据,而不需要系统处理器的参与,使用这种机制可以大大提高与设备通信的吞吐量,因为DMA的实现避免了大量的计算开销。

Linux内核把内存分为三个区段:可用于DMA的内存、常规内存以及高端内存。

通常的内存分配都发生在常规内存区,但通过设置内存标志也可以请求在其它区段中分配。

可用于DMA的内存是指存在于特别地址范围内的内存,外设可以利用这些内存执行DMA访问,进行数据通信传输。

因此,DMA缓冲区的分配要求是:物理连续、DMA可以访问、足够大。

Linux系统是使用虚拟地址的系统,系统的内存分配函数提供的地址都是虚拟地址,必须经过virt_to_bus函数转换才能得到物理地址。

分配内核内存空间的函数有三个: kmalloc 该函数实现小于128KB的内核内存的申请,所申请的空间是物理连续的;__get_free_pages实现最大4MB的内存申请(在Linux 2.6的内核下),以页为单位,一次申请或释放的页面数必须为2的幂,可一次允许申请到的最大页面依赖于体系结构,一般为2的(10或11次幂)页面,所申请的空间物理连续;vmalloc 虽然分配的虚拟地址空间是连续区域,但是在物理上可能是不连续的。

此外,Linux内核还提供了一个专门用于PCI设备申请内核内存的函数pci_alloc_ consistent,该函数支持按字节长度申请。

通过对内核源代码的分析,该函数是通过__get_free_pages函数实现对内核内存的分配,因此,其一次可能的最大分配空间也是4MB[3]。

从上面的分析可以看出,Linux2.6内核中能够用于分配DMA缓冲区的函数有三个:kmalloc、__get_free_pages和pci_alloc_consistent,而且一次最大可分配的内存为4MB。

因此在高速信号采集处理系统中,必须实现超过4MB的内核内存申请。

在本驱动程序的实现中采用了一种类似数组的内存管理机制,用__get_free_pages函数连续申请DMA内存块,然后从这些块地址排序中找到符合要求的连续内存块集,将这些块组成满足驱动程序要求的DMA缓冲区。

使用完毕后,再通过这套管理机制释放这些内存块。

在这里需要说明的是,在大多数健全的系统上,申请DMA内存都是位于上面所述的区段,在x86平台上,DMA 驱动是RAM的前16M;对于ISA等老的设备,进行DMA 操作必须使用DMA内存区段,虽然对于PCI设备,没有这个限制,但是通过查证相关资料和在实际多次实验中总结可得,用以往的方法对PCI设备申请内存最大也只能申请到11M。

因此必须对内存申请进行深入的研究和理解后大胆的进行各种尝试,通过研究发现在64位的系统上根据设置不同的内存分配标志位能申请到更大的符合驱动程序需求的DMA内存。

所以在本驱动程序中实现了大小为512M的DMA 内存申请,最大可申请到1G大小的DMA内存(在实验中的操作系统为Linux 2.6.9-42、双CPU双核、内存8G),从而有效的减少了后端软件处理数据时带来的抖动影响。

另外,使用循环缓冲区能够有效地避免了系统对内存的并发访问问题,循环缓冲区使用一种叫做“生产者和消费者”的算法:一个进程通过DMA将数据放入缓冲区,另一个进程通过read函数将数据取出。

由于在本驱动程序中,PCI-Express卡要求的DMA缓冲区大小相对固定,处理简单,缓冲区需要循环利用,所以在驱动程序的初始化阶段完成对DMA循环缓冲区的申请,卸载驱动程序时再释放DMA循环缓冲区。

3.4 共享中断处理DMA数据传输有两种方式,一种是软件发起的数据请求(例如通过read函数调用);一种是硬件异步的将数据传递给系统。

对于一个数据采集设备来讲,即使没有进程去读取数据,它也要不断的写入数据,随时等待应用进程的调用,因此,驱动程序应该维护一个循环缓冲区,当read调用时会随时返回给用户空间所要求的数据。

在高速数据采集设备上,常见的有查询模式和中断模式两种数据传输模式。

对于查询模式,驱动程序需要在内核维护一个内核线程,动态的不间断的进行DMA,在发起一个新的DMA后,内核线程会持续的查询PCI-Express设备的相关寄存器,等待硬件将数据写入到DMA缓冲区完毕后,再发起新的DMA,周而复之。

相关文档
最新文档