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:
parent
150ad30b09
commit
e3f4e34c01
|
@ -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 */
|
||||
return -1;
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue