Now we have the region info cache, add ->region_read/write device I/O operations instead of explicit pread()/pwrite() system calls. --- hw/vfio/device.c | 38 +++++++++++++++++++++++++++++++++++ hw/vfio/pci.c | 28 +++++++++++++------------- hw/vfio/region.c | 17 ++++++++++------ include/hw/vfio/vfio-device.h | 18 +++++++++++++++++ 4 files changed, 81 insertions(+), 20 deletions(-)
diff --git a/hw/vfio/device.c b/hw/vfio/device.c index d08c0ab536..ceb7bbebda 100644 --- a/hw/vfio/device.c +++ b/hw/vfio/device.c @@ -510,9 +510,47 @@ static int vfio_device_io_set_irqs(VFIODevice *vbasedev, return ret < 0 ? -errno : ret; } +static int vfio_device_io_region_read(VFIODevice *vbasedev, uint8_t index, + off_t off, uint32_t size, void *data) +{ + struct vfio_region_info *info = vbasedev->reginfo[index]; + int ret; + + if (info == NULL) { + ret = vfio_device_get_region_info(vbasedev, index, &info); + if (ret != 0) { + return ret; + } + } + + ret = pread(vbasedev->fd, data, size, info->offset + off); + + return ret < 0 ? -errno : ret; +} + +static int vfio_device_io_region_write(VFIODevice *vbasedev, uint8_t index, + off_t off, uint32_t size, void *data) +{ + struct vfio_region_info *info = vbasedev->reginfo[index]; + int ret; + + if (info == NULL) { + ret = vfio_device_get_region_info(vbasedev, index, &info); + if (ret != 0) { + return ret; + } + } + + ret = pwrite(vbasedev->fd, data, size, info->offset + off); + + 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, + .region_read = vfio_device_io_region_read, + .region_write = vfio_device_io_region_write, }; diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 1aeb4d91d2..5e811d5d6a 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -918,18 +918,22 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev) memset(vdev->rom, 0xff, size); while (size) { - bytes = pread(vbasedev->fd, vdev->rom + off, - size, vdev->rom_offset + off); + bytes = vbasedev->io_ops->region_read(vbasedev, + VFIO_PCI_ROM_REGION_INDEX, + off, size, vdev->rom + off); + if (bytes == 0) { break; } else if (bytes > 0) { off += bytes; size -= bytes; } else { - if (errno == EINTR || errno == EAGAIN) { + if (bytes == -EINTR || bytes == -EAGAIN) { continue; } - error_report("vfio: Error reading device ROM: %m"); + error_report("vfio: Error reading device ROM: %s", + strreaderror(bytes)); + break; } } @@ -969,22 +973,18 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev) static int vfio_pci_config_space_read(VFIOPCIDevice *vdev, off_t offset, uint32_t size, void *data) { - ssize_t ret; - - ret = pread(vdev->vbasedev.fd, data, size, vdev->config_offset + offset); - - return ret < 0 ? -errno : (int)ret; + return vdev->vbasedev.io_ops->region_read(&vdev->vbasedev, + VFIO_PCI_CONFIG_REGION_INDEX, + offset, size, data); } /* "Raw" write of underlying config space. */ static int vfio_pci_config_space_write(VFIOPCIDevice *vdev, off_t offset, uint32_t size, void *data) { - ssize_t ret; - - ret = pwrite(vdev->vbasedev.fd, data, size, vdev->config_offset + offset); - - return ret < 0 ? -errno : (int)ret; + return vdev->vbasedev.io_ops->region_write(&vdev->vbasedev, + VFIO_PCI_CONFIG_REGION_INDEX, + offset, size, data); } static uint64_t vfio_rom_read(void *opaque, hwaddr addr, unsigned size) diff --git a/hw/vfio/region.c b/hw/vfio/region.c index ef2630cac3..34752c3f65 100644 --- a/hw/vfio/region.c +++ b/hw/vfio/region.c @@ -45,6 +45,7 @@ void vfio_region_write(void *opaque, hwaddr addr, uint32_t dword; uint64_t qword; } buf; + int ret; switch (size) { case 1: @@ -64,11 +65,13 @@ void vfio_region_write(void *opaque, hwaddr addr, break; } - if (pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { + ret = vbasedev->io_ops->region_write(vbasedev, region->nr, + addr, size, &buf); + if (ret != size) { error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64 - ",%d) failed: %m", + ",%d) failed: %s", __func__, vbasedev->name, region->nr, - addr, data, size); + addr, data, size, strwriteerror(ret)); } trace_vfio_region_write(vbasedev->name, region->nr, addr, data, size); @@ -96,11 +99,13 @@ uint64_t vfio_region_read(void *opaque, uint64_t qword; } buf; uint64_t data = 0; + int ret; - if (pread(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { - error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %m", + ret = vbasedev->io_ops->region_read(vbasedev, region->nr, addr, size, &buf); + if (ret != size) { + error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %s", __func__, vbasedev->name, region->nr, - addr, size); + addr, size, strreaderror(ret)); return (uint64_t)-1; } switch (size) { diff --git a/include/hw/vfio/vfio-device.h b/include/hw/vfio/vfio-device.h index b4a28c2a54..d3ab13ca6a 100644 --- a/include/hw/vfio/vfio-device.h +++ b/include/hw/vfio/vfio-device.h @@ -178,6 +178,24 @@ struct VFIODeviceIOOps { * Configure IRQs as defined by @irqs. */ int (*set_irqs)(VFIODevice *vdev, struct vfio_irq_set *irqs); + + /** + * @region_read + * + * Read @size bytes from the region @nr at offset @off into the buffer + * @data. + */ + int (*region_read)(VFIODevice *vdev, uint8_t nr, off_t off, uint32_t size, + void *data); + + /** + * @region_write + * + * Write @size bytes to the region @nr at offset @off from the buffer + * @data. + */ + int (*region_write)(VFIODevice *vdev, uint8_t nr, off_t off, uint32_t size, + void *data); }; int vfio_device_get_region_info(VFIODevice *vbasedev, int index, -- 2.43.0