Patchwork [v2] qxl: add QXL_IO_MONITORS_CONFIG_ASYNC

login
register
mail settings
Submitter Alon Levy
Date July 23, 2012, 4:33 p.m.
Message ID <1343061216-15647-1-git-send-email-alevy@redhat.com>
Download mbox | patch
Permalink /patch/172710/
State New
Headers show

Comments

Alon Levy - July 23, 2012, 4:33 p.m.
bumps spice-protocol to 0.12.0 for new IO.
revision bumped to 4 for new IO support, enabled for spice-server >= 0.11.1

RHBZ: 770842

Signed-off-by: Alon Levy <alevy@redhat.com>
---
v2: fixed interface_async_complete_io to not complain about unexpected async io.

 configure    |    2 +-
 hw/qxl.c     |   30 +++++++++++++++++++++++++++++-
 hw/qxl.h     |    4 ++++
 trace-events |    1 +
 4 files changed, 35 insertions(+), 2 deletions(-)
Yonit Halperin - July 25, 2012, 9 a.m.
Hi,
I think you should save the monitor configuration as part of the 
vmstate, and recall spice_qxl_monitors_config_async in qxl_post_load.

Regards,
Yonit.

On 07/23/2012 07:33 PM, Alon Levy wrote:
> bumps spice-protocol to 0.12.0 for new IO.
> revision bumped to 4 for new IO support, enabled for spice-server>= 0.11.1
>
> RHBZ: 770842
>
> Signed-off-by: Alon Levy<alevy@redhat.com>
> ---
> v2: fixed interface_async_complete_io to not complain about unexpected async io.
>
>   configure    |    2 +-
>   hw/qxl.c     |   30 +++++++++++++++++++++++++++++-
>   hw/qxl.h     |    4 ++++
>   trace-events |    1 +
>   4 files changed, 35 insertions(+), 2 deletions(-)
>
> diff --git a/configure b/configure
> index cef0a71..5fcd315 100755
> --- a/configure
> +++ b/configure
> @@ -2630,7 +2630,7 @@ EOF
>     spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
>     spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
>     if $pkg_config --atleast-version=0.8.2 spice-server>/dev/null 2>&1&&  \
> -     $pkg_config --atleast-version=0.8.1 spice-protocol>  /dev/null 2>&1&&  \
> +     $pkg_config --atleast-version=0.12.0 spice-protocol>  /dev/null 2>&1&&  \
>        compile_prog "$spice_cflags" "$spice_libs" ; then
>       spice="yes"
>       libs_softmmu="$libs_softmmu $spice_libs"
> diff --git a/hw/qxl.c b/hw/qxl.c
> index 3a883ce..0440440 100644
> --- a/hw/qxl.c
> +++ b/hw/qxl.c
> @@ -249,6 +249,18 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
>       }
>   }
>
> +#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
> +static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl)
> +{
> +    trace_qxl_spice_monitors_config(qxl->id);
> +    spice_qxl_monitors_config_async(&qxl->ssd.qxl,
> +            qxl->ram->monitors_config,
> +            MEMSLOT_GROUP_GUEST,
> +            (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
> +                                      QXL_IO_MONITORS_CONFIG_ASYNC));
> +}
> +#endif
> +
>   void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
>   {
>       trace_qxl_spice_reset_image_cache(qxl->id);
> @@ -538,6 +550,7 @@ static const char *io_port_to_string(uint32_t io_port)
>                                           = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
>           [QXL_IO_FLUSH_SURFACES_ASYNC]   = "QXL_IO_FLUSH_SURFACES_ASYNC",
>           [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
> +        [QXL_IO_MONITORS_CONFIG_ASYNC]  = "QXL_IO_MONITORS_CONFIG_ASYNC",
>       };
>       return io_port_to_string[io_port];
>   }
> @@ -819,6 +832,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
>       case QXL_IO_DESTROY_PRIMARY_ASYNC:
>       case QXL_IO_UPDATE_AREA_ASYNC:
>       case QXL_IO_FLUSH_SURFACES_ASYNC:
> +    case QXL_IO_MONITORS_CONFIG_ASYNC:
>           break;
>       case QXL_IO_CREATE_PRIMARY_ASYNC:
>           qxl_create_guest_primary_complete(qxl);
> @@ -1333,7 +1347,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
>               io_port, io_port_to_string(io_port));
>           /* be nice to buggy guest drivers */
>           if (io_port>= QXL_IO_UPDATE_AREA_ASYNC&&
> -            io_port<= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
> +            io_port<= QXL_IO_MONITORS_CONFIG_ASYNC) {
>               qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
>           }
>           return;
> @@ -1361,6 +1375,9 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
>           io_port = QXL_IO_DESTROY_ALL_SURFACES;
>           goto async_common;
>       case QXL_IO_FLUSH_SURFACES_ASYNC:
> +#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
> +    case QXL_IO_MONITORS_CONFIG_ASYNC:
> +#endif
>   async_common:
>           async = QXL_ASYNC;
>           qemu_mutex_lock(&d->async_lock);
> @@ -1490,6 +1507,11 @@ async_common:
>           d->mode = QXL_MODE_UNDEFINED;
>           qxl_spice_destroy_surfaces(d, async);
>           break;
> +#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
> +    case QXL_IO_MONITORS_CONFIG_ASYNC:
> +        qxl_spice_monitors_config_async(d);
> +        break;
> +#endif
>       default:
>           qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
>       }
> @@ -1785,9 +1807,15 @@ static int qxl_init_common(PCIQXLDevice *qxl)
>           io_size = 16;
>           break;
>       case 3: /* qxl-3 */
> +        pci_device_rev = QXL_REVISION_STABLE_V10;
> +        io_size = 32; /* PCI region size must be pow2 */
> +        break;
> +#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
> +    case 4: /* qxl-4 */
>           pci_device_rev = QXL_DEFAULT_REVISION;
>           io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
>           break;
> +#endif
>       default:
>           error_report("Invalid revision %d for qxl device (max %d)",
>                        qxl->revision, QXL_DEFAULT_REVISION);
> diff --git a/hw/qxl.h b/hw/qxl.h
> index 172baf6..c1aadaa 100644
> --- a/hw/qxl.h
> +++ b/hw/qxl.h
> @@ -128,7 +128,11 @@ typedef struct PCIQXLDevice {
>           }                                                               \
>       } while (0)
>
> +#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
> +#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12
> +#else
>   #define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
> +#endif
>
>   /* qxl.c */
>   void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
> diff --git a/trace-events b/trace-events
> index 2a5f074..3db04ad 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -954,6 +954,7 @@ qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d"
>   qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d"
>   qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d"
>   qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d"
> +qxl_spice_monitors_config(int id) "%d"
>   qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d"
>   qxl_spice_oom(int qid) "%d"
>   qxl_spice_reset_cursor(int qid) "%d"
Alon Levy - July 25, 2012, 5:29 p.m.
On Wed, Jul 25, 2012 at 12:00:21PM +0300, Yonit Halperin wrote:
> Hi,
> I think you should save the monitor configuration as part of the vmstate,
> and recall spice_qxl_monitors_config_async in qxl_post_load.

Good point, will do. Would be nice if I could differentiate same client
(that doesn't need the recalling) and new client.

> 
> Regards,
> Yonit.
> 
> On 07/23/2012 07:33 PM, Alon Levy wrote:
> >bumps spice-protocol to 0.12.0 for new IO.
> >revision bumped to 4 for new IO support, enabled for spice-server>= 0.11.1
> >
> >RHBZ: 770842
> >
> >Signed-off-by: Alon Levy<alevy@redhat.com>
> >---
> >v2: fixed interface_async_complete_io to not complain about unexpected async io.
> >
> >  configure    |    2 +-
> >  hw/qxl.c     |   30 +++++++++++++++++++++++++++++-
> >  hw/qxl.h     |    4 ++++
> >  trace-events |    1 +
> >  4 files changed, 35 insertions(+), 2 deletions(-)
> >
> >diff --git a/configure b/configure
> >index cef0a71..5fcd315 100755
> >--- a/configure
> >+++ b/configure
> >@@ -2630,7 +2630,7 @@ EOF
> >    spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
> >    spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
> >    if $pkg_config --atleast-version=0.8.2 spice-server>/dev/null 2>&1&&  \
> >-     $pkg_config --atleast-version=0.8.1 spice-protocol>  /dev/null 2>&1&&  \
> >+     $pkg_config --atleast-version=0.12.0 spice-protocol>  /dev/null 2>&1&&  \
> >       compile_prog "$spice_cflags" "$spice_libs" ; then
> >      spice="yes"
> >      libs_softmmu="$libs_softmmu $spice_libs"
> >diff --git a/hw/qxl.c b/hw/qxl.c
> >index 3a883ce..0440440 100644
> >--- a/hw/qxl.c
> >+++ b/hw/qxl.c
> >@@ -249,6 +249,18 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
> >      }
> >  }
> >
> >+#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
> >+static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl)
> >+{
> >+    trace_qxl_spice_monitors_config(qxl->id);
> >+    spice_qxl_monitors_config_async(&qxl->ssd.qxl,
> >+            qxl->ram->monitors_config,
> >+            MEMSLOT_GROUP_GUEST,
> >+            (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
> >+                                      QXL_IO_MONITORS_CONFIG_ASYNC));
> >+}
> >+#endif
> >+
> >  void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
> >  {
> >      trace_qxl_spice_reset_image_cache(qxl->id);
> >@@ -538,6 +550,7 @@ static const char *io_port_to_string(uint32_t io_port)
> >                                          = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
> >          [QXL_IO_FLUSH_SURFACES_ASYNC]   = "QXL_IO_FLUSH_SURFACES_ASYNC",
> >          [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
> >+        [QXL_IO_MONITORS_CONFIG_ASYNC]  = "QXL_IO_MONITORS_CONFIG_ASYNC",
> >      };
> >      return io_port_to_string[io_port];
> >  }
> >@@ -819,6 +832,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
> >      case QXL_IO_DESTROY_PRIMARY_ASYNC:
> >      case QXL_IO_UPDATE_AREA_ASYNC:
> >      case QXL_IO_FLUSH_SURFACES_ASYNC:
> >+    case QXL_IO_MONITORS_CONFIG_ASYNC:
> >          break;
> >      case QXL_IO_CREATE_PRIMARY_ASYNC:
> >          qxl_create_guest_primary_complete(qxl);
> >@@ -1333,7 +1347,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
> >              io_port, io_port_to_string(io_port));
> >          /* be nice to buggy guest drivers */
> >          if (io_port>= QXL_IO_UPDATE_AREA_ASYNC&&
> >-            io_port<= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
> >+            io_port<= QXL_IO_MONITORS_CONFIG_ASYNC) {
> >              qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
> >          }
> >          return;
> >@@ -1361,6 +1375,9 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
> >          io_port = QXL_IO_DESTROY_ALL_SURFACES;
> >          goto async_common;
> >      case QXL_IO_FLUSH_SURFACES_ASYNC:
> >+#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
> >+    case QXL_IO_MONITORS_CONFIG_ASYNC:
> >+#endif
> >  async_common:
> >          async = QXL_ASYNC;
> >          qemu_mutex_lock(&d->async_lock);
> >@@ -1490,6 +1507,11 @@ async_common:
> >          d->mode = QXL_MODE_UNDEFINED;
> >          qxl_spice_destroy_surfaces(d, async);
> >          break;
> >+#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
> >+    case QXL_IO_MONITORS_CONFIG_ASYNC:
> >+        qxl_spice_monitors_config_async(d);
> >+        break;
> >+#endif
> >      default:
> >          qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
> >      }
> >@@ -1785,9 +1807,15 @@ static int qxl_init_common(PCIQXLDevice *qxl)
> >          io_size = 16;
> >          break;
> >      case 3: /* qxl-3 */
> >+        pci_device_rev = QXL_REVISION_STABLE_V10;
> >+        io_size = 32; /* PCI region size must be pow2 */
> >+        break;
> >+#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
> >+    case 4: /* qxl-4 */
> >          pci_device_rev = QXL_DEFAULT_REVISION;
> >          io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
> >          break;
> >+#endif
> >      default:
> >          error_report("Invalid revision %d for qxl device (max %d)",
> >                       qxl->revision, QXL_DEFAULT_REVISION);
> >diff --git a/hw/qxl.h b/hw/qxl.h
> >index 172baf6..c1aadaa 100644
> >--- a/hw/qxl.h
> >+++ b/hw/qxl.h
> >@@ -128,7 +128,11 @@ typedef struct PCIQXLDevice {
> >          }                                                               \
> >      } while (0)
> >
> >+#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
> >+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12
> >+#else
> >  #define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
> >+#endif
> >
> >  /* qxl.c */
> >  void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
> >diff --git a/trace-events b/trace-events
> >index 2a5f074..3db04ad 100644
> >--- a/trace-events
> >+++ b/trace-events
> >@@ -954,6 +954,7 @@ qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d"
> >  qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d"
> >  qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d"
> >  qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d"
> >+qxl_spice_monitors_config(int id) "%d"
> >  qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d"
> >  qxl_spice_oom(int qid) "%d"
> >  qxl_spice_reset_cursor(int qid) "%d"
>
Yonit Halperin - July 26, 2012, 5:26 a.m.
Hi,
On 07/25/2012 08:29 PM, Alon Levy wrote:
> On Wed, Jul 25, 2012 at 12:00:21PM +0300, Yonit Halperin wrote:
>> Hi,
>> I think you should save the monitor configuration as part of the vmstate,
>> and recall spice_qxl_monitors_config_async in qxl_post_load.
>
> Good point, will do. Would be nice if I could differentiate same client
> (that doesn't need the recalling) and new client.
>
The client doesn't need the recalling (if it the same client that was 
connected to the src); It is the destination server which needs the 
recalling, for the future clients that will get connected.

Cheers,
Yonit.
>>
>> Regards,
>> Yonit.
>>
>> On 07/23/2012 07:33 PM, Alon Levy wrote:
>>> bumps spice-protocol to 0.12.0 for new IO.
>>> revision bumped to 4 for new IO support, enabled for spice-server>= 0.11.1
>>>
>>> RHBZ: 770842
>>>
>>> Signed-off-by: Alon Levy<alevy@redhat.com>
>>> ---
>>> v2: fixed interface_async_complete_io to not complain about unexpected async io.
>>>
>>>   configure    |    2 +-
>>>   hw/qxl.c     |   30 +++++++++++++++++++++++++++++-
>>>   hw/qxl.h     |    4 ++++
>>>   trace-events |    1 +
>>>   4 files changed, 35 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/configure b/configure
>>> index cef0a71..5fcd315 100755
>>> --- a/configure
>>> +++ b/configure
>>> @@ -2630,7 +2630,7 @@ EOF
>>>     spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
>>>     spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
>>>     if $pkg_config --atleast-version=0.8.2 spice-server>/dev/null 2>&1&&   \
>>> -     $pkg_config --atleast-version=0.8.1 spice-protocol>   /dev/null 2>&1&&   \
>>> +     $pkg_config --atleast-version=0.12.0 spice-protocol>   /dev/null 2>&1&&   \
>>>        compile_prog "$spice_cflags" "$spice_libs" ; then
>>>       spice="yes"
>>>       libs_softmmu="$libs_softmmu $spice_libs"
>>> diff --git a/hw/qxl.c b/hw/qxl.c
>>> index 3a883ce..0440440 100644
>>> --- a/hw/qxl.c
>>> +++ b/hw/qxl.c
>>> @@ -249,6 +249,18 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
>>>       }
>>>   }
>>>
>>> +#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
>>> +static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl)
>>> +{
>>> +    trace_qxl_spice_monitors_config(qxl->id);
>>> +    spice_qxl_monitors_config_async(&qxl->ssd.qxl,
>>> +            qxl->ram->monitors_config,
>>> +            MEMSLOT_GROUP_GUEST,
>>> +            (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
>>> +                                      QXL_IO_MONITORS_CONFIG_ASYNC));
>>> +}
>>> +#endif
>>> +
>>>   void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
>>>   {
>>>       trace_qxl_spice_reset_image_cache(qxl->id);
>>> @@ -538,6 +550,7 @@ static const char *io_port_to_string(uint32_t io_port)
>>>                                           = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
>>>           [QXL_IO_FLUSH_SURFACES_ASYNC]   = "QXL_IO_FLUSH_SURFACES_ASYNC",
>>>           [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
>>> +        [QXL_IO_MONITORS_CONFIG_ASYNC]  = "QXL_IO_MONITORS_CONFIG_ASYNC",
>>>       };
>>>       return io_port_to_string[io_port];
>>>   }
>>> @@ -819,6 +832,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
>>>       case QXL_IO_DESTROY_PRIMARY_ASYNC:
>>>       case QXL_IO_UPDATE_AREA_ASYNC:
>>>       case QXL_IO_FLUSH_SURFACES_ASYNC:
>>> +    case QXL_IO_MONITORS_CONFIG_ASYNC:
>>>           break;
>>>       case QXL_IO_CREATE_PRIMARY_ASYNC:
>>>           qxl_create_guest_primary_complete(qxl);
>>> @@ -1333,7 +1347,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
>>>               io_port, io_port_to_string(io_port));
>>>           /* be nice to buggy guest drivers */
>>>           if (io_port>= QXL_IO_UPDATE_AREA_ASYNC&&
>>> -            io_port<= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
>>> +            io_port<= QXL_IO_MONITORS_CONFIG_ASYNC) {
>>>               qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
>>>           }
>>>           return;
>>> @@ -1361,6 +1375,9 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
>>>           io_port = QXL_IO_DESTROY_ALL_SURFACES;
>>>           goto async_common;
>>>       case QXL_IO_FLUSH_SURFACES_ASYNC:
>>> +#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
>>> +    case QXL_IO_MONITORS_CONFIG_ASYNC:
>>> +#endif
>>>   async_common:
>>>           async = QXL_ASYNC;
>>>           qemu_mutex_lock(&d->async_lock);
>>> @@ -1490,6 +1507,11 @@ async_common:
>>>           d->mode = QXL_MODE_UNDEFINED;
>>>           qxl_spice_destroy_surfaces(d, async);
>>>           break;
>>> +#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
>>> +    case QXL_IO_MONITORS_CONFIG_ASYNC:
>>> +        qxl_spice_monitors_config_async(d);
>>> +        break;
>>> +#endif
>>>       default:
>>>           qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
>>>       }
>>> @@ -1785,9 +1807,15 @@ static int qxl_init_common(PCIQXLDevice *qxl)
>>>           io_size = 16;
>>>           break;
>>>       case 3: /* qxl-3 */
>>> +        pci_device_rev = QXL_REVISION_STABLE_V10;
>>> +        io_size = 32; /* PCI region size must be pow2 */
>>> +        break;
>>> +#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
>>> +    case 4: /* qxl-4 */
>>>           pci_device_rev = QXL_DEFAULT_REVISION;
>>>           io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
>>>           break;
>>> +#endif
>>>       default:
>>>           error_report("Invalid revision %d for qxl device (max %d)",
>>>                        qxl->revision, QXL_DEFAULT_REVISION);
>>> diff --git a/hw/qxl.h b/hw/qxl.h
>>> index 172baf6..c1aadaa 100644
>>> --- a/hw/qxl.h
>>> +++ b/hw/qxl.h
>>> @@ -128,7 +128,11 @@ typedef struct PCIQXLDevice {
>>>           }                                                               \
>>>       } while (0)
>>>
>>> +#if SPICE_SERVER_VERSION>= 0x000b01 /* 0.11.1 */
>>> +#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12
>>> +#else
>>>   #define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
>>> +#endif
>>>
>>>   /* qxl.c */
>>>   void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
>>> diff --git a/trace-events b/trace-events
>>> index 2a5f074..3db04ad 100644
>>> --- a/trace-events
>>> +++ b/trace-events
>>> @@ -954,6 +954,7 @@ qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d"
>>>   qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d"
>>>   qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d"
>>>   qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d"
>>> +qxl_spice_monitors_config(int id) "%d"
>>>   qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d"
>>>   qxl_spice_oom(int qid) "%d"
>>>   qxl_spice_reset_cursor(int qid) "%d"
>>

Patch

diff --git a/configure b/configure
index cef0a71..5fcd315 100755
--- a/configure
+++ b/configure
@@ -2630,7 +2630,7 @@  EOF
   spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
   spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
   if $pkg_config --atleast-version=0.8.2 spice-server >/dev/null 2>&1 && \
-     $pkg_config --atleast-version=0.8.1 spice-protocol > /dev/null 2>&1 && \
+     $pkg_config --atleast-version=0.12.0 spice-protocol > /dev/null 2>&1 && \
      compile_prog "$spice_cflags" "$spice_libs" ; then
     spice="yes"
     libs_softmmu="$libs_softmmu $spice_libs"
diff --git a/hw/qxl.c b/hw/qxl.c
index 3a883ce..0440440 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -249,6 +249,18 @@  static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
     }
 }
 
+#if SPICE_SERVER_VERSION >= 0x000b01 /* 0.11.1 */
+static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_monitors_config(qxl->id);
+    spice_qxl_monitors_config_async(&qxl->ssd.qxl,
+            qxl->ram->monitors_config,
+            MEMSLOT_GROUP_GUEST,
+            (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                      QXL_IO_MONITORS_CONFIG_ASYNC));
+}
+#endif
+
 void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
 {
     trace_qxl_spice_reset_image_cache(qxl->id);
@@ -538,6 +550,7 @@  static const char *io_port_to_string(uint32_t io_port)
                                         = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
         [QXL_IO_FLUSH_SURFACES_ASYNC]   = "QXL_IO_FLUSH_SURFACES_ASYNC",
         [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
+        [QXL_IO_MONITORS_CONFIG_ASYNC]  = "QXL_IO_MONITORS_CONFIG_ASYNC",
     };
     return io_port_to_string[io_port];
 }
@@ -819,6 +832,7 @@  static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
     case QXL_IO_DESTROY_PRIMARY_ASYNC:
     case QXL_IO_UPDATE_AREA_ASYNC:
     case QXL_IO_FLUSH_SURFACES_ASYNC:
+    case QXL_IO_MONITORS_CONFIG_ASYNC:
         break;
     case QXL_IO_CREATE_PRIMARY_ASYNC:
         qxl_create_guest_primary_complete(qxl);
@@ -1333,7 +1347,7 @@  static void ioport_write(void *opaque, target_phys_addr_t addr,
             io_port, io_port_to_string(io_port));
         /* be nice to buggy guest drivers */
         if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
-            io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
+            io_port <= QXL_IO_MONITORS_CONFIG_ASYNC) {
             qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
         }
         return;
@@ -1361,6 +1375,9 @@  static void ioport_write(void *opaque, target_phys_addr_t addr,
         io_port = QXL_IO_DESTROY_ALL_SURFACES;
         goto async_common;
     case QXL_IO_FLUSH_SURFACES_ASYNC:
+#if SPICE_SERVER_VERSION >= 0x000b01 /* 0.11.1 */
+    case QXL_IO_MONITORS_CONFIG_ASYNC:
+#endif
 async_common:
         async = QXL_ASYNC;
         qemu_mutex_lock(&d->async_lock);
@@ -1490,6 +1507,11 @@  async_common:
         d->mode = QXL_MODE_UNDEFINED;
         qxl_spice_destroy_surfaces(d, async);
         break;
+#if SPICE_SERVER_VERSION >= 0x000b01 /* 0.11.1 */
+    case QXL_IO_MONITORS_CONFIG_ASYNC:
+        qxl_spice_monitors_config_async(d);
+        break;
+#endif
     default:
         qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
     }
@@ -1785,9 +1807,15 @@  static int qxl_init_common(PCIQXLDevice *qxl)
         io_size = 16;
         break;
     case 3: /* qxl-3 */
+        pci_device_rev = QXL_REVISION_STABLE_V10;
+        io_size = 32; /* PCI region size must be pow2 */
+        break;
+#if SPICE_SERVER_VERSION >= 0x000b01 /* 0.11.1 */
+    case 4: /* qxl-4 */
         pci_device_rev = QXL_DEFAULT_REVISION;
         io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
         break;
+#endif
     default:
         error_report("Invalid revision %d for qxl device (max %d)",
                      qxl->revision, QXL_DEFAULT_REVISION);
diff --git a/hw/qxl.h b/hw/qxl.h
index 172baf6..c1aadaa 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -128,7 +128,11 @@  typedef struct PCIQXLDevice {
         }                                                               \
     } while (0)
 
+#if SPICE_SERVER_VERSION >= 0x000b01 /* 0.11.1 */
+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12
+#else
 #define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
+#endif
 
 /* qxl.c */
 void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
diff --git a/trace-events b/trace-events
index 2a5f074..3db04ad 100644
--- a/trace-events
+++ b/trace-events
@@ -954,6 +954,7 @@  qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d"
 qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d"
 qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d"
 qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d"
+qxl_spice_monitors_config(int id) "%d"
 qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d"
 qxl_spice_oom(int qid) "%d"
 qxl_spice_reset_cursor(int qid) "%d"