vfio: add device IO ops vector

For vfio-user, device operations such as IRQ handling and region
read/writes are implemented in userspace over the control socket, not
ioctl() to the vfio kernel driver; add an ops vector to generalize this,
and implement vfio_device_io_ops_ioctl for interacting with the kernel
vfio driver.

Originally-by: John Johnson <john.g.johnson@oracle.com>
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
Signed-off-by: John Levon <john.levon@nutanix.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20250507152020.1254632-11-john.levon@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
This commit is contained in:
John Levon 2025-05-07 16:20:15 +01:00 committed by Cédric Le Goater
parent 9458d9b4dc
commit 38bf025d0d
5 changed files with 114 additions and 27 deletions

View file

@ -82,7 +82,7 @@ void vfio_device_irq_disable(VFIODevice *vbasedev, int index)
.count = 0,
};
ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
vbasedev->io_ops->set_irqs(vbasedev, &irq_set);
}
void vfio_device_irq_unmask(VFIODevice *vbasedev, int index)
@ -95,7 +95,7 @@ void vfio_device_irq_unmask(VFIODevice *vbasedev, int index)
.count = 1,
};
ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
vbasedev->io_ops->set_irqs(vbasedev, &irq_set);
}
void vfio_device_irq_mask(VFIODevice *vbasedev, int index)
@ -108,7 +108,7 @@ void vfio_device_irq_mask(VFIODevice *vbasedev, int index)
.count = 1,
};
ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
vbasedev->io_ops->set_irqs(vbasedev, &irq_set);
}
static inline const char *action_to_str(int action)
@ -167,7 +167,7 @@ bool vfio_device_irq_set_signaling(VFIODevice *vbasedev, int index, int subindex
pfd = (int32_t *)&irq_set->data;
*pfd = fd;
if (!ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
if (!vbasedev->io_ops->set_irqs(vbasedev, irq_set)) {
return true;
}
@ -188,22 +188,19 @@ bool vfio_device_irq_set_signaling(VFIODevice *vbasedev, int index, int subindex
int vfio_device_get_irq_info(VFIODevice *vbasedev, int index,
struct vfio_irq_info *info)
{
int ret;
memset(info, 0, sizeof(*info));
info->argsz = sizeof(*info);
info->index = index;
ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_IRQ_INFO, info);
return ret < 0 ? -errno : ret;
return vbasedev->io_ops->get_irq_info(vbasedev, info);
}
int vfio_device_get_region_info(VFIODevice *vbasedev, int index,
struct vfio_region_info **info)
{
size_t argsz = sizeof(struct vfio_region_info);
int ret;
*info = g_malloc0(argsz);
@ -211,10 +208,11 @@ int vfio_device_get_region_info(VFIODevice *vbasedev, int index,
retry:
(*info)->argsz = argsz;
if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) {
ret = vbasedev->io_ops->get_region_info(vbasedev, *info);
if (ret != 0) {
g_free(*info);
*info = NULL;
return -errno;
return ret;
}
if ((*info)->argsz > argsz) {
@ -320,11 +318,14 @@ void vfio_device_set_fd(VFIODevice *vbasedev, const char *str, Error **errp)
vbasedev->fd = fd;
}
static VFIODeviceIOOps vfio_device_io_ops_ioctl;
void vfio_device_init(VFIODevice *vbasedev, int type, VFIODeviceOps *ops,
DeviceState *dev, bool ram_discard)
{
vbasedev->type = type;
vbasedev->ops = ops;
vbasedev->io_ops = &vfio_device_io_ops_ioctl;
vbasedev->dev = dev;
vbasedev->fd = -1;
@ -442,3 +443,54 @@ void vfio_device_unprepare(VFIODevice *vbasedev)
QLIST_REMOVE(vbasedev, global_next);
vbasedev->bcontainer = NULL;
}
/*
* Traditional ioctl() based io
*/
static int vfio_device_io_device_feature(VFIODevice *vbasedev,
struct vfio_device_feature *feature)
{
int ret;
ret = ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature);
return ret < 0 ? -errno : ret;
}
static int vfio_device_io_get_region_info(VFIODevice *vbasedev,
struct vfio_region_info *info)
{
int ret;
ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, info);
return ret < 0 ? -errno : ret;
}
static int vfio_device_io_get_irq_info(VFIODevice *vbasedev,
struct vfio_irq_info *info)
{
int ret;
ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_IRQ_INFO, info);
return ret < 0 ? -errno : ret;
}
static int vfio_device_io_set_irqs(VFIODevice *vbasedev,
struct vfio_irq_set *irqs)
{
int ret;
ret = ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irqs);
return ret < 0 ? -errno : ret;
}
static VFIODeviceIOOps vfio_device_io_ops_ioctl = {
.device_feature = vfio_device_io_device_feature,
.get_region_info = vfio_device_io_get_region_info,
.get_irq_info = vfio_device_io_get_irq_info,
.set_irqs = vfio_device_io_set_irqs,
};