[Spice-devel] [RfC PATCH 7/7] async qxl I/O

Alon Levy alevy at redhat.com
Thu Jun 23 09:35:23 PDT 2011


On Wed, Jun 22, 2011 at 10:46:06AM +0200, Gerd Hoffmann wrote:
> Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
> ---
>  hw/qxl.c |  134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  hw/qxl.h |    3 +
>  2 files changed, 133 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/qxl.c b/hw/qxl.c
> index 03c871a..60caff9 100644
> --- a/hw/qxl.c
> +++ b/hw/qxl.c
> @@ -28,6 +28,18 @@
>  
>  #include "qxl.h"
>  
> +/* old spice-protocol */
> +#ifndef QXL_INTERRUPT_IO_CMD
> +#define QXL_INTERRUPT_IO_CMD               (1 << 2)
> +#define QXL_IO_UPDATE_AREA_ASYNC           (QXL_IO_DESTROY_ALL_SURFACES +1)
> +#define QXL_IO_NOTIFY_OOM_ASYNC            (QXL_IO_DESTROY_ALL_SURFACES +2)
> +#define QXL_IO_MEMSLOT_ADD_ASYNC           (QXL_IO_DESTROY_ALL_SURFACES +3)
> +#define QXL_IO_CREATE_PRIMARY_ASYNC        (QXL_IO_DESTROY_ALL_SURFACES +4)
> +#define QXL_IO_DESTROY_PRIMARY_ASYNC       (QXL_IO_DESTROY_ALL_SURFACES +5)
> +#define QXL_IO_DESTROY_SURFACE_ASYNC       (QXL_IO_DESTROY_ALL_SURFACES +6)
> +#define QXL_IO_DESTROY_ALL_SURFACES_ASYNC  (QXL_IO_DESTROY_ALL_SURFACES +7)
> +#endif
> +

Can you drop this? I think it's better to just not support the io if spice-protocol
is too old, or better yet just require a newer spice-protocol for building (and
bump spice-protocol version).

>  #undef SPICE_RING_PROD_ITEM
>  #define SPICE_RING_PROD_ITEM(r, ret) {                                  \
>          typeof(r) start = r;                                            \
> @@ -910,22 +922,90 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
>      qxl_rom_set_dirty(d);
>  }
>  
> +struct qxl_io_async {
> +    QXLDevMemSlot memslot;
> +    QXLDevSurfaceCreate surface;
> +    QXLRect update_area;
> +    uint32_t update_surface;
> +    uint32_t port;
> +    uint32_t val;
> +};
> +
> +static void *ioport_write_async(void *arg)
> +{
> +    PCIQXLDevice *d = arg;
> +    struct qxl_io_async *io;
> +    uint32_t io_port;
> +    uint32_t val;
> +    int ret;
> +
> +    while (true) {
> +        ret = read(d->aio_pipe[0], &io, sizeof(io));
> +        if (ret != sizeof(io)) {
> +            break;
> +        }
> +        io_port = io->port;
> +        val = io->val;
> +
> +        fprintf(stderr, "%s: 0x%x\n", __FUNCTION__, io_port);
> +        switch (io_port) {
> +        case QXL_IO_UPDATE_AREA_ASYNC:
> +            qemu_spice_update_area(&d->ssd, io->update_surface,
> +                                   &io->update_area, NULL, 0, 0);
> +            break;
> +        case QXL_IO_NOTIFY_OOM_ASYNC:
> +            d->oom_running = 1;
> +            qemu_spice_oom(&d->ssd);
> +            d->oom_running = 0;
> +            break;
> +        case QXL_IO_MEMSLOT_ADD_ASYNC:
> +            qemu_spice_add_memslot(&d->ssd, &io->memslot);
> +            break;
> +        case QXL_IO_CREATE_PRIMARY_ASYNC:
> +            qemu_spice_create_primary_surface(&d->ssd, 0, &io->surface);
> +            break;
> +        case QXL_IO_DESTROY_PRIMARY_ASYNC:
> +            qemu_spice_destroy_primary_surface(&d->ssd, 0);
> +            break;
> +        case QXL_IO_DESTROY_SURFACE_ASYNC:
> +            qemu_spice_destroy_surface_wait(&d->ssd, val);
> +            break;
> +        case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
> +            qemu_spice_destroy_surfaces(&d->ssd);
> +            break;
> +        }
> +        qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
> +        qemu_free(io);
> +    }
> +    qemu_thread_exit(NULL);
> +    return NULL;
> +}
> +
>  static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
>  {
>      PCIQXLDevice *d = opaque;
>      uint32_t io_port = addr - d->io_base;
> +    struct qxl_io_async *async;
> +    int ret;
>  
>      switch (io_port) {
>      case QXL_IO_RESET:
>      case QXL_IO_SET_MODE:
>      case QXL_IO_MEMSLOT_ADD:
> +    case QXL_IO_MEMSLOT_ADD_ASYNC:
>      case QXL_IO_MEMSLOT_DEL:
>      case QXL_IO_CREATE_PRIMARY:
> +    case QXL_IO_CREATE_PRIMARY_ASYNC:
missing for windows driver, which does QXL_IO_MEMSLOT_ADD before CREATE_PRIMARY,
and with async this turns to QXL_IO_MEMSLOT_ADD_ASYNC followed by QXL_IO_UPDATE_IRQ

+    case QXL_IO_UPDATE_IRQ:

>          break;
>      default:
>          if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
>              break;
>          dprint(d, 1, "%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port);
> +        /* be nice to buggy guest drivers */
> +        if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
> +            io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
> +            qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
> +        }
>          return;
>      }
>  
> @@ -1010,6 +1090,46 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
>      case QXL_IO_DESTROY_ALL_SURFACES:
>          qemu_spice_destroy_surfaces(&d->ssd);
>          break;
> +    case QXL_IO_MEMSLOT_ADD_ASYNC:
> +        PANIC_ON(val >= NUM_MEMSLOTS);
> +        PANIC_ON(d->guest_slots[val].active);
> +        d->guest_slots[val].slot = d->ram->mem_slot;
> +        async = qemu_mallocz(sizeof(*async));
> +        qxl_add_memslot(d, val, 0, &async->memslot);
> +        goto async_common;
> +    case QXL_IO_CREATE_PRIMARY_ASYNC:
> +        PANIC_ON(val != 0);
> +        dprint(d, 1, "QXL_IO_CREATE_PRIMARY_ASYNC\n");
> +        d->guest_primary.surface = d->ram->create_surface;
> +        async = qemu_mallocz(sizeof(*async));
> +        qxl_create_guest_primary(d, 0, &async->surface);
> +        goto async_common;
> +    case QXL_IO_DESTROY_PRIMARY_ASYNC:
> +        PANIC_ON(val != 0);
> +        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY_ASYNC\n");
> +        if (d->mode != QXL_MODE_UNDEFINED) {
> +            d->mode = QXL_MODE_UNDEFINED;
> +            async = qemu_mallocz(sizeof(*async));
> +            goto async_common;
> +        } else {
> +            qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
> +            break;
> +        }
> +    case QXL_IO_UPDATE_AREA_ASYNC:
> +        async = qemu_mallocz(sizeof(*async));
> +        async->update_area = d->ram->update_area;
> +        async->update_surface = d->ram->update_surface;
> +        goto async_common;
> +    case QXL_IO_NOTIFY_OOM_ASYNC:
> +    case QXL_IO_DESTROY_SURFACE_ASYNC:
> +    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
> +        async = qemu_mallocz(sizeof(*async));
> +    async_common:
> +        async->port = io_port;
> +        async->val = val;
> +        ret = write(d->aio_pipe[1], &async, sizeof(async));
> +        assert(ret == sizeof(async));
> +        break;
>      default:
>          fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
>          abort();
> @@ -1095,7 +1215,8 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
>  
>  static void init_pipe_signaling(PCIQXLDevice *d)
>  {
> -   if (pipe(d->pipe) < 0) {
> +   if (pipe(d->pipe) < 0 ||
> +       pipe(d->aio_pipe) < 0 ) {
>         dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__);
>         return;
>     }
> @@ -1233,6 +1354,10 @@ static int qxl_init_common(PCIQXLDevice *qxl)
>          pci_device_id  = QXL_DEVICE_ID_STABLE;
>          pci_device_rev = QXL_REVISION_STABLE_V06;
>          break;
> +    case 3: /* qxl-3 */
> +        pci_device_id  = QXL_DEVICE_ID_STABLE;
> +        pci_device_rev = 3;
> +        break;
>      default: /* experimental */
>          pci_device_id  = QXL_DEVICE_ID_DEVEL;
>          pci_device_rev = 1;
> @@ -1258,7 +1383,7 @@ static int qxl_init_common(PCIQXLDevice *qxl)
>      qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
>      qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vram", qxl->vram_size);
>  
> -    io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
> +    io_size = msb_mask((QXL_IO_RANGE_SIZE+7) * 2 - 1);
>      if (qxl->revision == 1) {
>          io_size = 8;
>      }
> @@ -1282,6 +1407,7 @@ static int qxl_init_common(PCIQXLDevice *qxl)
>      qemu_spice_add_interface(&qxl->ssd.qxl.base);
>      qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl);
>  
> +    qemu_thread_create(&qxl->aio_thread, ioport_write_async, qxl);
>      init_pipe_signaling(qxl);
>      qxl_reset_state(qxl);
>  
> @@ -1504,7 +1630,7 @@ static PCIDeviceInfo qxl_info_primary = {
>      .qdev.props = (Property[]) {
>          DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
>          DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
> -        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
> +        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 3),
>          DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
>          DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
>          DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
> @@ -1522,7 +1648,7 @@ static PCIDeviceInfo qxl_info_secondary = {
>      .qdev.props = (Property[]) {
>          DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
>          DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
> -        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
> +        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 3),
>          DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
>          DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
>          DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
> diff --git a/hw/qxl.h b/hw/qxl.h
> index f6c450d..6dd38e6 100644
> --- a/hw/qxl.h
> +++ b/hw/qxl.h
> @@ -30,6 +30,9 @@ typedef struct PCIQXLDevice {
>      int32_t            num_memslots;
>      int32_t            num_surfaces;
>  
> +    QemuThread         aio_thread;
> +    int                aio_pipe[2];
> +
>      struct guest_slots {
>          QXLMemSlot     slot;
>          void           *ptr;
> -- 
> 1.7.1
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel


More information about the Spice-devel mailing list