vhost-vdpa: map virtqueue notification area if possible

This patch implements the vq notification mapping support for
vhost-vDPA. This is simply done by using mmap()/munmap() for the
vhost-vDPA fd during device start/stop. For the device without
notification mapping support, we fall back to eventfd based
notification gracefully.

Reviewed-by: Si-Wei Liu <si-wei.liu@oracle.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
This commit is contained in:
Jason Wang 2021-04-15 15:33:56 +08:00
parent d60c75d28f
commit d0416d487b
2 changed files with 91 additions and 0 deletions

View File

@ -286,12 +286,95 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque)
return 0;
}
static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev,
int queue_index)
{
size_t page_size = qemu_real_host_page_size;
struct vhost_vdpa *v = dev->opaque;
VirtIODevice *vdev = dev->vdev;
VhostVDPAHostNotifier *n;
n = &v->notifier[queue_index];
if (n->addr) {
virtio_queue_set_host_notifier_mr(vdev, queue_index, &n->mr, false);
object_unparent(OBJECT(&n->mr));
munmap(n->addr, page_size);
n->addr = NULL;
}
}
static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n)
{
int i;
for (i = 0; i < n; i++) {
vhost_vdpa_host_notifier_uninit(dev, i);
}
}
static int vhost_vdpa_host_notifier_init(struct vhost_dev *dev, int queue_index)
{
size_t page_size = qemu_real_host_page_size;
struct vhost_vdpa *v = dev->opaque;
VirtIODevice *vdev = dev->vdev;
VhostVDPAHostNotifier *n;
int fd = v->device_fd;
void *addr;
char *name;
vhost_vdpa_host_notifier_uninit(dev, queue_index);
n = &v->notifier[queue_index];
addr = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED, fd,
queue_index * page_size);
if (addr == MAP_FAILED) {
goto err;
}
name = g_strdup_printf("vhost-vdpa/host-notifier@%p mmaps[%d]",
v, queue_index);
memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name,
page_size, addr);
g_free(name);
if (virtio_queue_set_host_notifier_mr(vdev, queue_index, &n->mr, true)) {
munmap(addr, page_size);
goto err;
}
n->addr = addr;
return 0;
err:
return -1;
}
static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev)
{
int i;
for (i = dev->vq_index; i < dev->vq_index + dev->nvqs; i++) {
if (vhost_vdpa_host_notifier_init(dev, i)) {
goto err;
}
}
return;
err:
vhost_vdpa_host_notifiers_uninit(dev, i);
return;
}
static int vhost_vdpa_cleanup(struct vhost_dev *dev)
{
struct vhost_vdpa *v;
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA);
v = dev->opaque;
trace_vhost_vdpa_cleanup(dev, v);
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
memory_listener_unregister(&v->listener);
dev->opaque = NULL;
@ -468,6 +551,7 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
if (started) {
uint8_t status = 0;
memory_listener_register(&v->listener, &address_space_memory);
vhost_vdpa_host_notifiers_init(dev);
vhost_vdpa_set_vring_ready(dev);
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status);
@ -477,6 +561,7 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
vhost_vdpa_reset_device(dev);
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE |
VIRTIO_CONFIG_S_DRIVER);
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
memory_listener_unregister(&v->listener);
return 0;

View File

@ -14,11 +14,17 @@
#include "hw/virtio/virtio.h"
typedef struct VhostVDPAHostNotifier {
MemoryRegion mr;
void *addr;
} VhostVDPAHostNotifier;
typedef struct vhost_vdpa {
int device_fd;
uint32_t msg_type;
MemoryListener listener;
struct vhost_dev *dev;
VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX];
} VhostVDPA;
#endif