1.PCI设备驱动编写(一)
2.PCI-PCIe设备驱动编写方法论
3.RTL8111H-PCIE网卡ARM驱动构建
4.Linux下PCI设备驱动开发详解(三)
5.群晖NAS搭配兮克PCIE网卡安装驱动教程
6.Linux下PCI设备驱动开发详解(六)
PCI设备驱动编写(一)
理解并编写PCIe驱动的驱动驱动关键在于模仿内核的现有实现,并熟悉设备匹配机制。源码PCI设备驱动依赖于厂商ID、程序子厂商ID、驱动驱动设备ID和子设备ID的源码独特标识,这些ID用于在Linux系统中的程序协议分析源码设备树中定位正确驱动,确保设备被正确识别和使用。驱动驱动
驱动程序必须在probe函数中启用设备,源码通过pci_enable_device函数实现,程序这会唤醒设备并分配必要的驱动驱动资源,如中断线和I/O区域。源码例如,程序对于CardBus设备,驱动驱动这是源码至关重要的。
配置空间的程序访问是驱动程序的核心环节,驱动程序需要从内存、端口和配置空间进行读写操作,尤其是配置空间,是驱动获取设备映射位置的关键。虽然CPU不能直接访问,但Linux通过标准接口提供配置空间操作,支持8、或位数据传输,驱动程序通过相关函数来完成配置空间的读写操作。
驱动程序的完整流程包括设备的启用、配置空间的访问,以及读写操作的实现。编写PCIe驱动程序时,首先要学会观察和模仿内核中的驱动代码,然后逐步实现这些功能,包括注册和注销驱动,以确保设备的正常工作。
PCI-PCIe设备驱动编写方法论
在进行PCI或PCIe设备驱动编写时,首先需要明确硬件拓扑结构。PCI/PCIe是设备互联的规范,属于总线规范。编写驱动通常涉及两大部分:一是PCI/PCIe接口芯片本身的驱动,二是针对字符设备、块设备、网络设备的驱动。
在Linux操作系统下,授权源码免费PCI/PCIe接口芯片的驱动框架由内核实现,开发者主要需要确定VID/DID/bar的使用情况、中断与DMA的启用等。针对字符设备、块设备、网络设备的驱动,则需根据具体芯片手册,明确时钟、复位、中断、读写操作及涉及的寄存器。
在Linux中,PCI设备驱动程序从总线0开始搜索整个PCI系统,记录所有PCI设备和桥接器,并建立描述系统拓扑层次的数据结构链表。PCI BIOS提供在bios-pci-bios描述中的服务。PCI Fixup是针对特定系统相关的初始化修补代码。
PCI有三种地址空间:I/O空间、内存空间和配置空间。I/O空间和内存空间由设备驱动程序使用,配置空间则由Linux内核的PCI初始化代码使用,用于配置PCI设备,如中断号和I/O或内存基地址。
简而言之,Linux内核的主要任务是枚举和配置PCI设备,通常在内核初始化阶段完成。通过BIOS或内核自身实现对PCI设备的初始化,根据PCI access mode选项提供选择。在枚举和配置过程中,PCI配置寄存器组提供设备配置信息,用于进一步解释和处理。
PCI配置空间头部包含设备类型、性质等信息,用于检测PCI总线上的设备。头部类型分为标准的字节头部和3种类型,用于识别设备。配置寄存器通过统一的入口点访问,由PCI桥提供具体读写操作。对于地址访问,Linux内核保留了特定地址空间,电脑stl源码如i结构处理器的0xCF8~0xCFF,用于配置寄存器组的访问。
PCI设备驱动编写时,需要确定是内存访问还是I/O访问,然后按照设备手册实现相应的逻辑。
RTLH-PCIE网卡ARM驱动构建
最近在探索 Linux 内核中网口部分的代码,特别关注的是 PCIe-Switch/Eth 控制器,它利用 MSI-X 中断和 DMA 完成数据包的接收与发送。本次驱动的构建采用 RealTek 的 RTLH-PCIE Ethernet Controller,该控制器内部集成了一对 MAC 和 PHY,实现单个 // 网络接口。
本次驱动的构建平台是使用 RK 实现,数据收发通过 DMA-PCIE 进行。为了全面理解 PCIe 网卡驱动的注册和数据包处理流程,我们参照芯片手册构建了一套 RTLH 的驱动代码。
编写 PCIe 驱动的首要步骤是识别总线下设备的唯一性标识信息,即 PCIe 配置空间中的设备 DeviceID 和厂商 VendorID。通过使用 lspci 工具箱读取 PCIe 网卡前 字节的配置字,确定关键信息。工具箱获取的信息如下:Class 为 的设备是 RK 内置的 PCIe-RC 节点,VendorID:0x1D、DeviceID:0x;Class 为 的设备是外置 PCIe 网卡配置空间的信息,VendorID:0xEC、DeviceID:0x。
接下来,构建标准 PCIe 设备驱动框架,该框架包含基本的注册和初始化步骤。PCIE 设备的注册使用 module_pci_driver 结构体,其入参为 pci_driver 结构体。在内核初始化过程中,相应的驱动被注册到内核中。
在完成基础驱动框架后,接下来需要参照芯片手册构建网卡驱动的特定部分。
在完成基础驱动框架和参照芯片手册构建特定部分之后,我们的 RTL 的驱动已经具备了初步可用的能力,在 PCI 驱动、ifconfig 等操作下,可以正常识别出该驱动并将其暴露在 sysfs 中。
PCI 驱动注册后,在最后一个驱动列表中即可看到注册的进场源码驱动。ifconfig 操作下可以看到获取的 MAC 地址与通过 MMIO 读取获取到的 MAC 地址一致。
此外,驱动还需要实现中断处理和网络通信包的上送,包括实现 MSIX 中断注册和测试。内核网口测试中,注册 net_device 结构体实现内核网口控制,引入 NAPI 机制提高网络通信效率。测试显示,当打开内核收包功能并触发大量数据报文传输时,会触发内核的 NAPI 机制进行数据包收取。测试包括 ARP 收包、端口计数功能等。
最后,代码开源部分已准备就绪,等待部署到 gitee 平台。
Linux下PCI设备驱动开发详解(三)
在深入PCIe硬件和软件开发之前,理解几个关键概念至关重要,它们能帮助我们把握整个PCIe异构系统的工作原理,以及驱动和设备在系统中的定位。PCIe软硬异构系统基础
应用程序通过文件系统访问硬件,通常通过读写文件操作抽象设备。非内核功能的库函数直接实现,涉及硬件操作的则通过系统调用,由内核处理。 Linux将硬件分为字符设备、块设备和网络设备,设备通过文件名(设备文件)和设备号(主、从设备号)区分。设备文件以文件形式在/dev目录下,通过文件操作如open、read、write、close进行硬件操作。 驱动程序作为内核模块,不包含main()函数,由初始化函数启动,应用程序与驱动的工作模式不同,前者在用户态,后者在内核态。 设备驱动由总线、溯源码概念设备和驱动组成,总线作为硬件连接的桥梁,设备通过总线注册自身,匹配合适的驱动进行通信。总线、设备和驱动的协作
系统启动时自动创建总线目录。总线驱动通过bus_register()进行注册,生成设备和驱动文件夹,再通过device_register()和driver_register()进行设备和驱动的具体注册。 总线初始化和注册是内核初始化的一部分,新总线的添加通常由系统自动处理,驱动的probe函数在匹配成功后执行初始化。 设备和驱动的实例展示了PCI设备和其对应的驱动注册过程。 Linux设备驱动模型的核心在于总线、设备和驱动的紧密配合,它们共同构建了系统与硬件的交互机制。后续文章将深入探讨实际PCI设备驱动的开发细节。参考资料:
群晖NAS搭配兮克PCIE网卡安装驱动教程
针对群晖NAS与兮克PCIE网卡的兼容与驱动安装问题,本文将提供详细的教程帮助用户解决问题。 当遇到网卡识别不正常的情况,首先需要安装相应的驱动。以下是具体的步骤: 1. 访问兮克官网下载终端软件,地址为visit.seekswan.com:,将软件解压并安装到桌面。 2. 打开终端,输入sudo -i并输入NAS登录密码,获取root权限,然后执行curl命令安装模块。 3. 根据网卡类型,查找对应的驱动代码。例如:对于USB2.5G外置网卡,使用代码r进行安装。
对于PCIE网卡如SKS-i-2.5ET,输入igc;SKS-A-1BT/SKN-A-MINI用atlantic;SKN-X-1SFP+等型号用ixgbe。
4. 安装完成后,回到群晖管理页面,检查网络端口。如果新添加的网卡已被识别,如显示千兆网卡之外还看到了新安装的PCIE网卡,说明驱动安装成功。 通过以上步骤,用户可以顺利安装并配置兮克网卡,确保群晖NAS的网络连接稳定。如果有任何疑问,务必根据网卡型号选择正确的驱动代码,以确保驱动与设备兼容性。Linux下PCI设备驱动开发详解(六)
本章及其后续章节将深入探讨通过PCI Express总线实现CPU与FPGA之间数据通信的简单框架,并介绍Linux PCI内核态设备驱动(KMD)的实战开发。
该框架以开源界知名的RIFFA(可重用集成框架,用于FPGA加速器)为基础,这是一个针对FPGA加速器的可重用集成框架,同时也是一款第三方开源的PCIe框架。
该框架需要使用支持PCIe的工作站以及带有PCIe连接器的FPGA板卡。RIFFA支持Windows、Linux操作系统,以及altera和xilinx的FPGA,可以通过c/c++、python、matlab、java等编程语言实现数据的发送和接收。驱动程序可在Linux或Windows系统上运行,每个系统最多支持5个FPGA设备。
在用户端,存在独立的发送和接收端口,用户只需编写少量代码即可实现与FPGA IP内核的通信。
RIFFA使用直接存储器访问(DMA)传输和中断信号传输数据,从而在PCIe链路上实现高带宽,运行速率可达到PCIe链路的饱和点。
开源地址:github.com/KastnerRG/ri...
一、Linux下PCI驱动结构
在《Linux下PCI设备驱动开发详解(四)》中,我们了解到,通常用模块方式编写PCI设备驱动,至少需要实现以下几个部分:初始化设备模块、设备打开模块、数据读写模块、中断处理模块、设备释放模块、设备卸载模块。通常的编写方式如下:
好的,带着这个框架,我们将进入RIFFA框架的driver源代码分析。
二、初始化设备模块
我们直接给出源代码:
OK,我们已经看到了几个关键词,驱动程序、字符设备、class、文件节点。在《Linux下PCI设备驱动开发详解(三)》中,我们知道总线、设备、驱动模型:
硬件拓扑描述Linux设备模型中四个重要概念:
三、probe探测硬件设备
这个fpga_probe函数非常重要和关键:
四、写操作
基本的读写操作通过ioctl来调用对应的driver驱动的实现。我们补充一下,ioctl是设备驱动程序中设备控制接口函数,一个字符设备驱动通常会实现设备打开、关闭、读、写等功能,在一些需要细分的情境下,如果需要扩展新的功能,通常以增设ioctl()命令的方式实现。
直接给出代码:
在处理ioctl_send的时候,我们发现实现用户数据拷贝到内核态之后,调用了chnl_send_wrapcheck,将api层打包过来的参数一一传递过去。
直接给出chnl_send_wrapcheck():
这段代码主要做了一些避免错误的判断,值得一提的就是通过自旋锁避免了多线程错误的判断,其实我们可以知道riffa架构支持多线程,之后调用了chnl_send。
将数据写入指定的FPGA通道。除非配置了非零超时,否则将阻塞,直到所有数据都发送到FPGA。如果超时不为零,则该函数将阻塞,直到发送所有数据或超时毫秒过去。来自bufp指针的用户数据将被发送,最多len字(每个字==位)。通道将被告知预期数据量和偏移量。如果last==1,则FPGA通道将在发送后将此事务识别为完成。如果last==0,则FPGA通道将需要额外的事务。
成功后,返回发送的字数。出错时,返回负值。
核心思想就是,初始化sg_maps,通过bar空间告知FPGA通道号、长度、大小等信息、使用通用buffer发送数据、更新sg_mapping,最后进入到while(1)的循环函数中。
while(1)大循环,只有当处理完Tx数据完成中断或出错时函数才会返回。在每一轮执行中,首先执行内嵌的小while,在小while中首先读取对应通道上的send消息队列,若返回值为0说明成功出队,小while运行一遍后就会执行下面的代码;若返回值为1说明队列可能是空的,也就是还没有中断到来,此时调用prepare_to_wait函数将本进程添加到等待队列里,然后执行schedule_timeout休眠该进程(有阻塞时间限制),此时在用户看来表现为ioctl函数阻塞等待,但中断还能在后台运行(中断也是一个进程)。
若此时驱动接收到一个该通道的Tx中断,那么在中断回调函数里将中断信息推入消息队列后就会唤醒chnl_send所在的进程。进程唤醒后调用finish_wait函数将本进程pop出等待队列并用signal_pending查看是否因信号而被唤醒,如果是需要返回给用户并让其再次重试。如果不是被信号唤醒,则再去读一下消息队列,此时会将消息类型存入msg_type,消息存入msg中,然后退出小while。
接下来进入一个switch语句,这个switch是根据msg_type消息类型选择处理动作的,即中断处理的下半部。
若执行Tx SG读完成中断,则消息类型发送EVENT_SG_BUF_READ,数据填0,其实是没用的数据。在这里如果剩余长度大于0或者剩余溢出值大于0时就会重新执行上一段讲述的过程,即从上一次分配的结尾处再分配SG缓冲区,并发送SG链表给FPGA等等,不过一般不会发送这种情况,除非分配页时的get_user_pages函数锁定物理页出现了问题,少分了页才会出现这样的现象。
然后FPGA就会按SG链表一个一个SG缓存块的进行流式DMA传输,传输完毕后FPGA发送一个Tx数据读完成中断,即EVENT_TXN_DONE消息类型。这里比较好处理,调用dma_unmap_sg取消内存空间的SGDMA映射,然后释放掉页。
五、读操作
读操作和写操作类似,不再详细描述。
函数chnl_recv用于将FPGA发送的数据读到缓冲区内。
首先调用宏DEFINE_WAIT初始化等待队列项;然后把传入的参数timeout换算成毫秒,这个时间是最长阻塞时间。
剩下的就是中断处理过程,等待读完成。
六、销毁/卸载设备
释放设备模块主要是负责释放对设备的控制权,释放占用的内存和中断等,所做的事情正好和打开设备模块相反。
本文详细介绍了RIFFA框架的驱动模块,涉及的内容非常多,包括内核页面、中断处理等。
一个驱动的框架主要包括:初始化设备模块、设备打开模块、数据读写模块、中断处理模块、设备释放模块、设备卸载模块。
七、未完待续
《Linux下PCI设备驱动开发详解(七)》将详细分析RIFFA的环形通信队列,最大的好处就是不需要对后续的队列内容进行搬移,可以后续由入队(写入)覆盖。
八、参考资料
blog.csdn.net/mcupro/...
zhuanlan.zhihu.com/p/...
在NI Linux RT中安装Xillybus PCIE驱动
在NI Linux RT中安装Xillybus PCIE驱动步骤如下:
1. 从Xillybus站点下载驱动文件xillybus.tar.gz。
2. 将目标文件目录映射到计算机。
3. 将驱动文件拷贝至/home/lvuser。
4. 进入驱动文件所在目录。
5. 解压下载的文件,生成xillybus文件夹。
6. 将目录更改为Xillybus/module所在位置。
7. 将Makefile拷贝回计算机,用记事本修改KDIR位置为:KDIR := /var/volatile/tmp/headers/kernel,或用vi命令修改。
8. 将新Makefile拷贝至/home/lvuser。
9. 用新Makefile覆盖旧版本。
. 更改目录至Xillybus/module所在位置。
. 键入source /usr/local/natinst/tools/versioning_utils.sh加载所需编译工具。
. 键入setup_versioning_env设置运行Makefile环境。
. 键入versioning_call make进行编译。
. 编译完成后,将Xillybus_PCIE.ko及Xillybus_Core.ko两个文件拷贝至/lib/modules/4.9.-rt-6.1.0f0/kernel/drivers/char文件夹中(版本号因个人安装不同而异)。
. 执行depmod -a。
. 键入modprobe Xillybus_PCIE加载驱动。
. 键入lsmod显示已加载的模块。
. 为了在神电开发包中调用PCIE,将xillybus-PCIe-X-Linux-DLW.so重命名为xillybus-LV-DLW.so,并拷贝至/home/lvuser/natinst/bin目录中。现在,可在Linux RT下直接使用LabVIEW开发实时控制器程序,通过My FPGA工具包与LabVIEW开发FPGA,并通过PCIE在两者间传递数据。
注意:使用xillybus-LV-DLW.so时,避免使用Xillybus最新驱动文件编译ko文件,建议使用-5-版本,此版本在调用xillybus-LV-DLW.so后可正常进行PCIE通信。