Linux DPDK UIO

前期学习了一些DPDK的demo,了解了一些基础DPDK的应用。对dpdk的一些底层原理没做过多分析,今天主要学习用户态驱动程序的实现情况。

0x02 用户态驱动程序UIO

UIO(Userspace I/O)是运行在用户空间的I/O技术。Linux系统中一般的驱动设备都是运行在内核空间,而在用户空间用应用程序调用即可。

UIO的内核部分和用户空间的工作

内核空间

UIO的少量运行在内核空间的驱动所做的工作有哪些呢?

(1)分配和记录设备需要的资源和注册uio设备

在设备的探测函数中:

-使能PCI 设备

-申请资源

-读取并记录配置信息

-注册uio设备// uio_register_device()

// uio_8139d_pci_probe & uio_8139d_handler

(2)必须在内核空间实现的小部分中断应答函数

用户空间的关键操作

(1)关键操作

(2)响应硬件中断

有什么优势?

1、用户空间驱动程序的优点

1、可以和整个C库链接。

2、在驱动中可以使用浮点数,在某些特殊的硬件中,可能需要使用浮点数,而linux内核并不提供浮点数的支持。如果能在用户态实现驱动,就可以轻松解决这一问题。

3、驱动问题不会导致整个系统挂起。内核态驱动的一些错误常常导致整个系统挂起。

4、用户态的驱动调试方便。

5、可以给出封闭源码的驱动程序,不必采用GPL,更为灵活。

我的理解为将以前内核模块驱动所需要做的工作移到了用户态空间操作。dpdk实现一个uio驱动,然后实现e1000e驱动的相关操作。

0x03 源码简单分析

与其他内核PCI模块开发一样代码结构,UIO驱动实现部分:

关键数据结构:

//dpdk定义的uio pci设备描述结构

struct rte_uio_pci_dev {

struct uio_info info; //uio 通用结构

struct pci_dev *pdev; //pci设备描述结构

enum rte_intr_mode mode; //中断模式

};

struct uio_info {

struct uio_device *uio_dev; //uio设备属于

const char *name; //名称

const char *version; //版本号

struct uio_mem mem[MAX_UIO_MAPS];//可映射的内存区域列表,size == 0表示列表结束

struct uio_port port[MAX_UIO_PORT_REGIONS]; //网口区域列表

long irq; //UIO_IRQ_CUSTOM 中断号

unsigned long irq_flags; //请求中断号的标志

void *priv; //可选的私有数据

irqreturn_t (*handler)(int irq, struct uio_info *dev_info); //中断信息处理

int (*mmap)(struct uio_info *info, struct vm_area_struct *vma);//内存映射操作

int (*open)(struct uio_info *info, struct inode *inode); //打开

int (*release)(struct uio_info *info, struct inode *inode); //释放

int (*irqcontrol)(struct uio_info *info, s32 irq_on); //中断控制操作 关闭/打开 当向/dev/uioX中写入值时

};

关键处理函数:

static int __init

igbuio_pci_init_module(void)

{

int ret;

ret = igbuio_config_intr_mode(intr_mode); //内核insmod时带的参数,中断模式

if (ret < 0)

return ret;

return pci_register_driver(&igbuio_pci_driver);//注册PCI设备,实际调用pci_module_init。

}

关键的pci驱动操作函数,主要是探测和删除

static struct pci_driver igbuio_pci_driver = {

.name = "igb_uio", //名称

.id_table = NULL,

.probe = igbuio_pci_probe, //探测回调函数

.remove = igbuio_pci_remove,//删除回调函数

};

关键看下igbuio_pci_probe:

//根据内核版本不同,返回类型不同

#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)

static int __devinit

#else

static int

#endif

igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)

{

struct rte_uio_pci_dev *udev;

struct msix_entry msix_entry;

int err;

//分配内核空间内存,rte_uio_pci_dev一个设备类型大小

udev = kzalloc(sizeof(struct rte_uio_pci_dev), GFP_KERNEL);

if (!udev)

return -ENOMEM;

/*

* 使能设备: 调用更底层的PCI代码使能设备的内存和I/O区域

*/

err = pci_enable_device(dev);

if (err != 0) {

dev_err(&dev->dev, "Cannot enable PCI device\n");

goto fail_free;

}

/*

预留PCI设备的i/o或内存区域,pci_request_regions这个函数封装了一些PCI驱动相关的内存操作,不深入理解;

*/

err = pci_request_regions(dev, "igb_uio");

if (err != 0) {

dev_err(&dev->dev, "Cannot request regions\n");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值