DPDK中断管理
DPDK中的网卡都是PCI设备,多数中断都属于
PCI_MSIX类型的中断。
中断执行流程跟踪:
kernel uio驱动uio_interrupt -> igb_uio注册的回调函数igbuio_pci_irqhandler -> kernel uio驱动调用 uio_event_notify -> 唤醒DPDK中断线程(epoll机制) -> 网卡驱动注册的回调(rte_intr_callback_register注册的) -> 用户注册的回调(rte_eth_dev_callback_register)。
主要连接点:打开的/dev/uiox文件fd描述符。
igb_uio的创建
下面是igb_uio创建过程部分代码。
static int
igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
/* 省略代码 */
/* fill uio infos */
udev->info.name = "igb_uio";
udev->info.version = "0.1";
udev->info.handler = igbuio_pci_irqhandler;
udev->info.irqcontrol = igbuio_pci_irqcontrol;
switch (igbuio_intr_mode_preferred) {
case RTE_INTR_MODE_MSIX:
/* Only 1 msi-x vector needed */
msix_entry.entry = 0;
if (pci_enable_msix(dev, &msix_entry, 1) == 0) {
dev_dbg(&dev->dev, "using MSI-X");
udev->info.irq = msix_entry.vector;
udev->mode = RTE_INTR_MODE_MSIX;
break;
}
/* fall back to INTX */
case RTE_INTR_MODE_LEGACY:
if (pci_intx_mask_supported(dev)) {
dev_dbg(&dev->dev, "using INTX");
udev->info.irq_flags = IRQF_SHARED;
udev->info.irq = dev->irq;
udev->mode = RTE_INTR_MODE_LEGACY;
break;
}
default:
dev_err(&dev->dev, "invalid IRQ mode %u",
igbuio_intr_mode_preferred);
err = -EINVAL;
goto fail_release_iomem;
}
/* 省略代码 */
/* register uio driver */
err = uio_register_device(&dev->dev, &udev->info);
if (err != 0)
goto fail_remove_group;
dev_info(&dev->dev, "uio device registered with irq %lx\n",
udev->info.irq);
return 0;
这里创建了一个uio设备,uio设备的中断回调函数是igbuio_pci_irqhandler,当pci设备发生了中断,就会调用此函数。
static irqreturn_t
igbuio_pci_irqhandler(int irq, struct uio_info *info)
{
struct rte_uio_pci_dev *udev = igbuio_get_uio_pci_dev(info);
/* Legacy mode need to mask in hardware */
if (udev->mode == RTE_INTR_MODE_LEGACY &&
!pci_check_and_mask_intx(udev->pdev))
return IRQ_NONE;
/* Message signal mode, no share IRQ and automasked */
return IRQ_HANDLED;
}
linux中uio设备的创建
先看一下uio设备注册函数,文件driver/uio/uio.c
/* use a define to avoid include chaining to get THIS_MODULE */
#define uio_register_device(parent, info) \
__uio_register_device(THIS_MODULE, parent, info)
int __uio_register_device(struct module *owner,
struct device *parent,
struct uio_info *info)
{
struct uio_device *idev;
int ret = 0;
if (!parent || !info || !info->name || !info->version)
return -EINVAL;
info->uio_dev = NULL;
idev = devm_kzalloc(parent, sizeof(*idev), GFP_KERNEL);
if (!idev) {
return -ENOMEM;
}
idev->owner = owner;
idev->info = info;
init_waitqueue_head(&idev->wait);
atomic_set(&idev->event, 0);
ret = uio_get_minor(idev);
if (ret)
return ret;
idev->dev = device_create(&uio_class, parent,
MKDEV(uio_major, idev->minor), idev,
"uio%d", idev->minor);
if (IS_ERR(idev->dev)) {
printk(KERN_ERR "UIO: device register failed\n");
ret = PTR_ERR(idev->dev);
goto err_device_create;
}
ret = uio_dev_add_attributes(idev);
if (ret)
goto err_uio_dev_add_attributes;
info->uio_dev = idev;
if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) {
/*
* Note that we deliberately don't use devm_request_irq
* here. The parent module can unregister the UIO device
* and call pci_disable_msi, which requires that this
* irq has been freed. However, the device may have open
* FDs at the time of unregister and therefore may not be
* freed until they are released.
*/
ret = request_irq(info->irq, uio_interrupt,
info->irq_flags, info->name, idev);
if (ret)
goto err_request_irq;
}
return 0;
err_request_irq:
uio_dev_del_attributes(idev


962

被折叠的 条评论
为什么被折叠?



