vfio/display: adding region support

Wire up region-based display.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed By: Kirti Wankhede <kwankhede@nvidia.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
Gerd Hoffmann 2018-03-13 11:17:30 -06:00 committed by Alex Williamson
parent a9994687cb
commit 00195ba710
3 changed files with 124 additions and 2 deletions

View File

@ -19,6 +19,113 @@
#include "qapi/error.h"
#include "pci.h"
/* ---------------------------------------------------------------------- */
static void vfio_display_region_update(void *opaque)
{
VFIOPCIDevice *vdev = opaque;
VFIODisplay *dpy = vdev->dpy;
struct vfio_device_gfx_plane_info plane = {
.argsz = sizeof(plane),
.flags = VFIO_GFX_PLANE_TYPE_REGION
};
pixman_format_code_t format;
int ret;
ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &plane);
if (ret < 0) {
error_report("ioctl VFIO_DEVICE_QUERY_GFX_PLANE: %s",
strerror(errno));
return;
}
if (!plane.drm_format || !plane.size) {
return;
}
format = qemu_drm_format_to_pixman(plane.drm_format);
if (!format) {
return;
}
if (dpy->region.buffer.size &&
dpy->region.buffer.nr != plane.region_index) {
/* region changed */
vfio_region_exit(&dpy->region.buffer);
vfio_region_finalize(&dpy->region.buffer);
dpy->region.surface = NULL;
}
if (dpy->region.surface &&
(surface_width(dpy->region.surface) != plane.width ||
surface_height(dpy->region.surface) != plane.height ||
surface_format(dpy->region.surface) != format)) {
/* size changed */
dpy->region.surface = NULL;
}
if (!dpy->region.buffer.size) {
/* mmap region */
ret = vfio_region_setup(OBJECT(vdev), &vdev->vbasedev,
&dpy->region.buffer,
plane.region_index,
"display");
if (ret != 0) {
error_report("%s: vfio_region_setup(%d): %s",
__func__, plane.region_index, strerror(-ret));
goto err;
}
ret = vfio_region_mmap(&dpy->region.buffer);
if (ret != 0) {
error_report("%s: vfio_region_mmap(%d): %s", __func__,
plane.region_index, strerror(-ret));
goto err;
}
assert(dpy->region.buffer.mmaps[0].mmap != NULL);
}
if (dpy->region.surface == NULL) {
/* create surface */
dpy->region.surface = qemu_create_displaysurface_from
(plane.width, plane.height, format,
plane.stride, dpy->region.buffer.mmaps[0].mmap);
dpy_gfx_replace_surface(dpy->con, dpy->region.surface);
}
/* full screen update */
dpy_gfx_update(dpy->con, 0, 0,
surface_width(dpy->region.surface),
surface_height(dpy->region.surface));
return;
err:
vfio_region_exit(&dpy->region.buffer);
vfio_region_finalize(&dpy->region.buffer);
}
static const GraphicHwOps vfio_display_region_ops = {
.gfx_update = vfio_display_region_update,
};
static int vfio_display_region_init(VFIOPCIDevice *vdev, Error **errp)
{
vdev->dpy = g_new0(VFIODisplay, 1);
vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0,
&vfio_display_region_ops,
vdev);
return 0;
}
static void vfio_display_region_exit(VFIODisplay *dpy)
{
if (!dpy->region.buffer.size) {
return;
}
vfio_region_exit(&dpy->region.buffer);
vfio_region_finalize(&dpy->region.buffer);
}
/* ---------------------------------------------------------------------- */
int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp)
{
struct vfio_device_gfx_plane_info probe;
@ -38,8 +145,7 @@ int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp)
probe.flags = VFIO_GFX_PLANE_TYPE_PROBE | VFIO_GFX_PLANE_TYPE_REGION;
ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &probe);
if (ret == 0) {
error_setg(errp, "vfio-display: region support not implemented yet");
return -1;
return vfio_display_region_init(vdev, errp);
}
if (vdev->display == ON_OFF_AUTO_AUTO) {
@ -53,4 +159,11 @@ int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp)
void vfio_display_finalize(VFIOPCIDevice *vdev)
{
if (!vdev->dpy) {
return;
}
graphic_console_close(vdev->dpy->con);
vfio_display_region_exit(vdev->dpy);
g_free(vdev->dpy);
}

View File

@ -148,6 +148,7 @@ typedef struct VFIOPCIDevice {
bool no_kvm_msi;
bool no_kvm_msix;
bool no_geforce_quirks;
VFIODisplay *dpy;
} VFIOPCIDevice;
uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);

View File

@ -142,6 +142,14 @@ typedef struct VFIOGroup {
QLIST_ENTRY(VFIOGroup) container_next;
} VFIOGroup;
typedef struct VFIODisplay {
QemuConsole *con;
struct {
VFIORegion buffer;
DisplaySurface *surface;
} region;
} VFIODisplay;
void vfio_put_base_device(VFIODevice *vbasedev);
void vfio_disable_irqindex(VFIODevice *vbasedev, int index);
void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index);