dm: virtio: implement vhost_vq_register_eventfd

There are 2 eventfds for one virtqueue, one is for kick and the other
is for notify. eventfd used for kick is associated with a PIO/MMIO
region. eventfd used for notify is associated with a MSIx/INTx. The
eventfd pair is registered to VHM thru VHM char dev.

VHM irqfd currently only support MSIx. If INTx is used, vhost proxy
uses mevent to poll the call fd from vhost then inject interrupt to
guest.

Tracked-On: #1329
Signed-off-by: Jian Jun Chen <jian.jun.chen@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
Jian Jun Chen 2018-08-10 15:14:35 +08:00 committed by lijinxia
parent 150ad30b09
commit e3f4e34c01
1 changed files with 122 additions and 2 deletions

View File

@ -153,12 +153,132 @@ vhost_eventfd_test_and_clear(int fd)
return -1;
}
static void
vhost_vq_notify(int fd __attribute__((unused)),
enum ev_type t __attribute__((unused)),
void *arg)
{
struct vhost_vq *vq = arg;
struct virtio_vq_info *vqi;
struct vhost_dev *vdev;
vdev = vq->dev;
vqi = &vdev->base->queues[vdev->vq_idx + vq->idx];
vq_interrupt(vdev->base, vqi);
}
static int
vhost_vq_register_eventfd(struct vhost_dev *vdev,
int idx, bool is_register)
{
/* to be implemented */
struct acrn_ioeventfd ioeventfd = {0};
struct acrn_irqfd irqfd = {0};
struct virtio_base *base;
struct vhost_vq *vq;
struct virtio_vq_info *vqi;
struct pcibar *bar;
int rc = -1;
/* this interface is called only by vhost_vq_start,
* parameters have been checked there
*/
base = vdev->base;
vqi = &vdev->base->queues[vdev->vq_idx + idx];
vq = &vdev->vqs[idx];
if (!is_register) {
ioeventfd.flags = ACRN_IOEVENTFD_FLAG_DEASSIGN;
irqfd.flags = ACRN_IRQFD_FLAG_DEASSIGN;
}
/* register ioeventfd for kick */
if (base->device_caps & ACRN_VIRTIO_F_VERSION_1) {
/*
* in the current implementation, if virtio 1.0 with pio
* notity, its bar idx should be set to non-zero
*/
if (base->modern_pio_bar_idx) {
bar = &vdev->base->dev->bar[base->modern_pio_bar_idx];
ioeventfd.data = vdev->vq_idx + idx;
ioeventfd.addr = bar->addr;
ioeventfd.len = 2;
ioeventfd.flags |= (ACRN_IOEVENTFD_FLAG_DATAMATCH |
ACRN_IOEVENTFD_FLAG_PIO);
} else if (base->modern_mmio_bar_idx) {
bar = &vdev->base->dev->bar[base->modern_mmio_bar_idx];
ioeventfd.data = 0;
ioeventfd.addr = bar->addr + VIRTIO_CAP_NOTIFY_OFFSET
+ (vdev->vq_idx + idx) *
VIRTIO_MODERN_NOTIFY_OFF_MULT;
ioeventfd.len = 2;
/* no additional flag bit should be set for MMIO */
} else {
WPRINTF("invalid virtio 1.0 parameters, 0x%lx\n",
base->device_caps);
return -1;
}
} else {
bar = &vdev->base->dev->bar[base->legacy_pio_bar_idx];
ioeventfd.data = vdev->vq_idx + idx;
ioeventfd.addr = bar->addr + VIRTIO_CR_QNOTIFY;
ioeventfd.len = 2;
ioeventfd.flags |= (ACRN_IOEVENTFD_FLAG_DATAMATCH |
ACRN_IOEVENTFD_FLAG_PIO);
}
ioeventfd.fd = vq->kick_fd;
DPRINTF("[ioeventfd: %d][0x%lx@%d][flags: 0x%x][data: 0x%lx]\n",
ioeventfd.fd, ioeventfd.addr, ioeventfd.len,
ioeventfd.flags, ioeventfd.data);
rc = vm_ioeventfd(vdev->base->dev->vmctx, &ioeventfd);
if (rc < 0) {
WPRINTF("vm_ioeventfd failed rc = %d, errno = %d\n",
rc, errno);
return -1;
}
if (pci_msix_enabled(base->dev)) {
/* register irqfd for notify */
struct msix_table_entry *mte;
struct acrn_msi_entry msi;
mte = &vdev->base->dev->msix.table[vqi->msix_idx];
msi.msi_addr = mte->addr;
msi.msi_data = mte->msg_data;
irqfd.fd = vq->call_fd;
/* no additional flag bit should be set */
irqfd.msi = msi;
DPRINTF("[irqfd: %d][MSIX: %d]\n", irqfd.fd, vqi->msix_idx);
rc = vm_irqfd(vdev->base->dev->vmctx, &irqfd);
} else {
/*
* irqfd only supports MSIx now. For non-MSIx, call_fd is polled
* by dm then inject interrupts to guest
*/
if (is_register) {
vq->mevp = mevent_add(vq->call_fd, EVF_READ,
vhost_vq_notify, vq);
if (!vq->mevp) {
WPRINTF("mevent_add failed\n");
rc = -1;
}
} else if (vq->mevp) {
mevent_delete(vq->mevp);
vq->mevp = NULL;
}
}
if (rc < 0) {
WPRINTF("vm_irqfd failed rc = %d, errno = %d\n", rc, errno);
/* unregister ioeventfd */
if (is_register) {
ioeventfd.flags |= ACRN_IOEVENTFD_FLAG_DEASSIGN;
vm_ioeventfd(vdev->base->dev->vmctx, &ioeventfd);
}
return -1;
}
return 0;
}
static int