vfio 通过eventfd拿到kernel的中断

vfio是通过eventfd来将中断提供给user space,当上层通过ioctl(VFIO_DEVICE_SET_IRQS)来设置中断后,在kernel中vfio_pci_ioctl->vfio_pci_set_irqs_ioctl->vfio_pci_set_msi_trigger,假定这时中断的flag包含VFIO_IRQ_SET_DATA_EVENTFD 。
则vfio_msi_set_block->vfio_msi_set_vector_signal
在vfio_msi_set_vector_signal 中最终要的就是
    ret = request_irq(irq, vfio_msihandler, 0,
              vdev->ctx[vector].name, trigger);
可见是通过request_irq 申请中断的,其中断函数是vfio_msihandler
static irqreturn_t vfio_msihandler(int irq, void *arg)
{
    struct eventfd_ctx *trigger = arg;

    eventfd_signal(trigger, 1);
    return IRQ_HANDLED;
}

这里仅仅是通过eventfd 发送signal
于此同时在qemu中
static int vfio_set_trigger_eventfd(VFIOINTp *intp,
                                    eventfd_user_side_handler_t handler)
{
    VFIODevice *vbasedev = &intp->vdev->vbasedev;
    struct vfio_irq_set *irq_set;
    int argsz, ret;
    int32_t *pfd;

    argsz = sizeof(*irq_set) + sizeof(*pfd);
    irq_set = g_malloc0(argsz);
    irq_set->argsz = argsz;
    irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
    irq_set->index = intp->pin;
    irq_set->start = 0;
    irq_set->count = 1;
    pfd = (int32_t *)&irq_set->data;
    *pfd = event_notifier_get_fd(intp->interrupt);
    qemu_set_fd_handler(*pfd, (IOHandler *)handler, NULL, intp);
    ret = ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
    g_free(irq_set);
    if (ret < 0) {
        error_report("vfio: Failed to set trigger eventfd: %m");
        qemu_set_fd_handler(*pfd, NULL, NULL, NULL);
    }
    return ret;
}
在通过VFIO_DEVICE_SET_IRQS 设定中断之前会通过 *pfd = event_notifier_get_fd(intp->interrupt); 得到和这个中断绑定的fd,然后通过qemu_set_fd_handler 给这个fd 设定一个handler
    ret = vfio_set_trigger_eventfd(intp, vfio_intp_interrupt);

可见handler为vfio_intp_interrupt 在event_notifier_test_and_clear中又会调用event_notifier_test_and_clear来等待kernel通过eventfd_signal(trigger, 1);发送的中断.
int event_notifier_test_and_clear(EventNotifier *e)
{
    int value;
    ssize_t len;
    char buffer[512];

    /* Drain the notify pipe.  For eventfd, only 8 bytes will be read.  */
    value = 0;
    do {
        len = read(e->rfd, buffer, sizeof(buffer));
        value |= (len > 0);
    } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));

    return value;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值