[Spice-devel] [PATCH] asynchronous io port support (introduced in revision 3 of qxl device)

Alon Levy alevy at redhat.com
Thu Jun 23 11:13:24 PDT 2011


Fixes same issue in RHBZ#700134, but for a windows guest. Requires a revision 3
pci device, that will be introduced with qemu patches. If the revision is 2 the
old behavior is maintained, namely using the non asynchronous io ports.

qxl revision 3 (QXL_REVISION_V10) gains support for async io operations for

 NOTIFY_OOM
 UPDATE_AREA
 CREATE_PRIMARY
 DESTROY_PRIMARY
 DESTROY_SURFACE_WAIT (not used currently, just exported)
 DESTROY_SURFACES

use that if the revision is large enough.

Async io ports let qemu return faster to the guest, and issue an interrupt
when the operation started by the io write is complete. This means less
time when the qemu global mutex is held.
---
 display/driver.c     |   17 +++++++++++++----
 display/qxldd.h      |   26 ++++++++++++++++++++++++++
 display/res.c        |   19 +++++++++----------
 include/qxl_driver.h |    8 ++++++++
 miniport/qxl.c       |   34 +++++++++++++++++++++++++++++++++-
 5 files changed, 89 insertions(+), 15 deletions(-)

diff --git a/display/driver.c b/display/driver.c
index 2c88cc5..094e386 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -572,19 +572,20 @@ static VOID CreatePrimarySurface(PDev *pdev, UINT32 depth, UINT32 format,
     pdev->primary_surface_create->flags = 0;
     pdev->primary_surface_create->type = QXL_SURF_TYPE_PRIMARY;
 
-    WRITE_PORT_UCHAR(pdev->create_primary_port, 0);
+    async_io(pdev, pdev->create_primary_async_port, pdev->create_primary_port, 0);
 }
 
 static void DestroyPrimarySurface(PDev *pdev)
 {
     HideMouse(pdev);
-    WRITE_PORT_UCHAR(pdev->destroy_primary_port, 0);
+    async_io(pdev, pdev->destroy_primary_async_port, pdev->destroy_primary_port, 0);
 }
 
 static void DestroyAllSurfaces(PDev *pdev)
 {
     HideMouse(pdev);
-    WRITE_PORT_UCHAR(pdev->destroy_all_surfaces_port, 0);
+    async_io(pdev, pdev->destroy_all_surfaces_async_port,
+                       pdev->destroy_all_surfaces_port, 0);
 }
 
 BOOL SetHardwareMode(PDev *pdev)
@@ -642,7 +643,7 @@ static BOOLEAN CreateVRamSlot(PDev *pdev)
     *pdev->ram_slot_start = pdev->fb_phys;
     *pdev->ram_slot_end = pdev->fb_phys + pdev->fb_size;
 
-    WRITE_PORT_UCHAR(pdev->memslot_add_port, slot_id);
+    async_io(pdev, pdev->memslot_add_async_port, pdev->memslot_add_port, slot_id);
 
     pdev->vram_mem_slot = slot_id;
 
@@ -696,9 +697,17 @@ static BOOL PrepareHardware(PDev *pdev)
     pdev->notify_cmd_port = dev_info.notify_cmd_port;
     pdev->notify_cursor_port = dev_info.notify_cursor_port;
     pdev->notify_oom_port = dev_info.notify_oom_port;
+    pdev->update_area_async_port = dev_info.update_area_async_port;
+    pdev->notify_oom_async_port = dev_info.notify_oom_async_port;
+    pdev->memslot_add_async_port = dev_info.memslot_add_async_port;
+    pdev->create_primary_async_port = dev_info.create_primary_async_port;
+    pdev->destroy_primary_async_port = dev_info.destroy_primary_async_port;
+    pdev->destroy_surface_async_port = dev_info.destroy_surface_async_port;
+    pdev->destroy_all_surfaces_async_port = dev_info.destroy_all_surfaces_async_port;
     pdev->display_event = dev_info.display_event;
     pdev->cursor_event = dev_info.cursor_event;
     pdev->sleep_event = dev_info.sleep_event;
+    pdev->io_cmd_event = dev_info.io_cmd_event;
 #if (WINVER < 0x0501)
     pdev->WaitForEvent = dev_info.WaitForEvent;
 #endif
diff --git a/display/qxldd.h b/display/qxldd.h
index fcfa752..d5623c5 100644
--- a/display/qxldd.h
+++ b/display/qxldd.h
@@ -30,6 +30,7 @@
 #include "windef.h"
 #include "wingdi.h"
 #include "winddi.h"
+#include "ioaccess.h"
 #include "qxl_driver.h"
 #include "mspace.h"
 #if (WINVER < 0x0501)
@@ -267,6 +268,7 @@ typedef struct PDev {
     PEVENT display_event;
     PEVENT cursor_event;
     PEVENT sleep_event;
+    PEVENT io_cmd_event;
 
     PUCHAR log_port;
     UINT8 *log_buf;
@@ -308,6 +310,13 @@ typedef struct PDev {
     PUCHAR memslot_add_port;
     PUCHAR memslot_del_port;
     PUCHAR destroy_all_surfaces_port;
+    PUCHAR update_area_async_port;
+    PUCHAR notify_oom_async_port;
+    PUCHAR memslot_add_async_port;
+    PUCHAR create_primary_async_port;
+    PUCHAR destroy_primary_async_port;
+    PUCHAR destroy_surface_async_port;
+    PUCHAR destroy_all_surfaces_async_port;
 
     UINT8* primary_memory_start;
     UINT32 primary_memory_size;
@@ -398,4 +407,21 @@ static _inline RingItem *RingGetTail(PDev *pdev, Ring *ring)
     return ret;
 }
 
+#if (WINVER < 0x0501)
+#define WAIT_FOR_EVENT(pdev, event, timeout) (pdev)->WaitForEvent(event, timeout)
+#else
+#define WAIT_FOR_EVENT(pdev, event, timeout) EngWaitForSingleObject(event, timeout)
+#endif
+
+static _inline void async_io(PDev *pdev, PUCHAR async, PUCHAR sync, UCHAR val)
+{
+    if (pdev->pci_revision >= QXL_REVISION_STABLE_V10) {
+        WRITE_PORT_UCHAR(async, val);
+        WAIT_FOR_EVENT(pdev, pdev->io_cmd_event, NULL);
+        DEBUG_PRINT((pdev, 3, "finished async %d\n", (int)async));
+    } else {
+        WRITE_PORT_UCHAR(sync, val);
+    }
+}
+
 #endif
diff --git a/display/res.c b/display/res.c
index c69b600..0e5b310 100644
--- a/display/res.c
+++ b/display/res.c
@@ -21,6 +21,7 @@
 
 #include <ddraw.h>
 #include <dxmini.h>
+#include "qxldd.h"
 #include "os_dep.h"
 #include "res.h"
 #include "ioaccess.h"
@@ -33,12 +34,6 @@
 #include "devioctl.h"
 #include "ntddvdeo.h"
 
-#if (WINVER < 0x0501)
-#define WAIT_FOR_EVENT(pdev, event, timeout) (pdev)->WaitForEvent(event, timeout)
-#else
-#define WAIT_FOR_EVENT(pdev, event, timeout) EngWaitForSingleObject(event, timeout)
-#endif
-
 static _inline QXLPHYSICAL PA(PDev *pdev, PVOID virt, UINT8 slot_id)
 {
     PMemSlot *p_slot = &pdev->mem_slots[slot_id];
@@ -223,6 +218,11 @@ static void QXLSleep(PDev* pdev, int msec)
     DEBUG_PRINT((pdev, 19, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
 }
 
+static void NotifyOOM(PDev *pdev)
+{
+    async_io(pdev, pdev->notify_oom_async_port, pdev->notify_oom_port, 0);
+}
+
 /* Called with malloc_sem held */
 static void WaitForReleaseRing(PDev* pdev)
 {
@@ -238,7 +238,7 @@ static void WaitForReleaseRing(PDev* pdev)
             if (!SPICE_RING_IS_EMPTY(pdev->release_ring)) {
                 break;
             }
-            WRITE_PORT_UCHAR(pdev->notify_oom_port, 0);
+            NotifyOOM(pdev);
         }
         SPICE_RING_CONS_WAIT(pdev->release_ring, wait);
 
@@ -262,8 +262,7 @@ static void WaitForReleaseRing(PDev* pdev)
                          pdev->Res->num_glyphs_pages,
                          pdev->Res->num_cursor_pages));
 #endif
-            //oom
-            WRITE_PORT_UCHAR(pdev->notify_oom_port, 0);
+            NotifyOOM(pdev);
         }
     }
     DEBUG_PRINT((pdev, 16, "%s: 0x%lx, done\n", __FUNCTION__, pdev));
@@ -2538,7 +2537,7 @@ void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id)
     DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
     CopyRect(pdev->update_area, area);
     *pdev->update_surface = surface_id;
-    WRITE_PORT_UCHAR(pdev->update_area_port, 0);
+    async_io(pdev, pdev->update_area_async_port, pdev->update_area_port, 0);
 }
 
 #endif
diff --git a/include/qxl_driver.h b/include/qxl_driver.h
index 9827a13..f9a31f1 100644
--- a/include/qxl_driver.h
+++ b/include/qxl_driver.h
@@ -54,9 +54,17 @@ typedef struct QXLDriverInfo {
     PUCHAR notify_cmd_port;
     PUCHAR notify_cursor_port;
     PUCHAR notify_oom_port;
+    PUCHAR update_area_async_port;
+    PUCHAR notify_oom_async_port;
+    PUCHAR memslot_add_async_port;
+    PUCHAR create_primary_async_port;
+    PUCHAR destroy_primary_async_port;
+    PUCHAR destroy_surface_async_port;
+    PUCHAR destroy_all_surfaces_async_port;
     PEVENT display_event;
     PEVENT cursor_event;
     PEVENT sleep_event;
+    PEVENT io_cmd_event;
 
     UINT32 num_pages;
     void *io_pages_virt;
diff --git a/miniport/qxl.c b/miniport/qxl.c
index f3ee090..c7aba3f 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -86,6 +86,7 @@ typedef struct QXLExtension {
     PEVENT display_event;
     PEVENT cursor_event;
     PEVENT sleep_event;
+    PEVENT io_cmd_event;
 
     MemSlot *mem_slots;
 
@@ -520,6 +521,10 @@ void DevExternsionCleanup(QXLExtension *dev)
         VideoPortDeleteEvent(dev, dev->display_event);
     }
 
+    if (dev->io_cmd_event) {
+        VideoPortDeleteEvent(dev, dev->io_cmd_event);
+    }
+
     if (dev->rom) {
         VideoPortUnmapMemory(dev, dev->rom, NULL);
     }
@@ -551,6 +556,7 @@ VP_STATUS FindAdapter(PVOID dev_extension,
     PEVENT display_event = NULL;
     PEVENT cursor_event = NULL;
     PEVENT sleep_event = NULL;
+    PEVENT io_cmd_event = NULL;
 #if (WINVER >= 0x0501)
     VPOSVERSIONINFO  sys_info;
 #endif
@@ -602,9 +608,19 @@ VP_STATUS FindAdapter(PVOID dev_extension,
         return status;
     }
 
+    if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &io_cmd_event)) != NO_ERROR) {
+        DEBUG_PRINT((dev_ext, 0,  "%s: create cursor event failed %lu\n",
+                     __FUNCTION__, status));
+        VideoPortDeleteEvent(dev_ext, sleep_event);
+        VideoPortDeleteEvent(dev_ext, display_event);
+        VideoPortDeleteEvent(dev_ext, cursor_event);
+        return status;
+    }
+
     dev_ext->display_event = display_event;
     dev_ext->cursor_event = cursor_event;
     dev_ext->sleep_event = sleep_event;
+    dev_ext->io_cmd_event = io_cmd_event;
 
     if ((status = Prob(dev_ext, conf_info, ranges, QXL_PCI_RANGES)) != NO_ERROR ||
         (status = InitIO(dev_ext, &ranges[QXL_IO_RANGE_INDEX])) != NO_ERROR ||
@@ -948,12 +964,24 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             driver_info->display_event = dev_ext->display_event;
             driver_info->cursor_event = dev_ext->cursor_event;
             driver_info->sleep_event = dev_ext->sleep_event;
+            driver_info->io_cmd_event = dev_ext->io_cmd_event;
             driver_info->cmd_ring = &dev_ext->ram_header->cmd_ring;
             driver_info->cursor_ring = &dev_ext->ram_header->cursor_ring;
             driver_info->release_ring = &dev_ext->ram_header->release_ring;
             driver_info->notify_cmd_port = dev_ext->io_port + QXL_IO_NOTIFY_CMD;
             driver_info->notify_cursor_port = dev_ext->io_port + QXL_IO_NOTIFY_CURSOR;
             driver_info->notify_oom_port = dev_ext->io_port + QXL_IO_NOTIFY_OOM;
+            driver_info->update_area_async_port = dev_ext->io_port + QXL_IO_UPDATE_AREA_ASYNC;
+            driver_info->notify_oom_async_port = dev_ext->io_port + QXL_IO_NOTIFY_OOM_ASYNC;
+            driver_info->memslot_add_async_port = dev_ext->io_port + QXL_IO_MEMSLOT_ADD_ASYNC;
+            driver_info->create_primary_async_port =
+                dev_ext->io_port + QXL_IO_CREATE_PRIMARY_ASYNC;
+            driver_info->destroy_primary_async_port =
+                dev_ext->io_port + QXL_IO_DESTROY_PRIMARY_ASYNC;
+            driver_info->destroy_surface_async_port =
+                dev_ext->io_port + QXL_IO_DESTROY_SURFACE_ASYNC;
+            driver_info->destroy_all_surfaces_async_port =
+                dev_ext->io_port + QXL_IO_DESTROY_ALL_SURFACES_ASYNC;
 
             driver_info->log_port = dev_ext->io_port + QXL_IO_LOG;
             driver_info->log_buf = dev_ext->ram_header->log_buf;
@@ -1023,9 +1051,13 @@ VOID InterruptCallback(PVOID dev_extension, PVOID Context)
 
     if (pending & QXL_INTERRUPT_DISPLAY) {
         VideoPortSetEvent(dev_ext, dev_ext->display_event);
-    } if (pending & QXL_INTERRUPT_CURSOR) {
+    }
+    if (pending & QXL_INTERRUPT_CURSOR) {
         VideoPortSetEvent(dev_ext, dev_ext->cursor_event);
     }
+    if (pending & QXL_INTERRUPT_IO_CMD) {
+        VideoPortSetEvent(dev_ext, dev_ext->io_cmd_event);
+    }
 
     dev_ext->ram_header->int_mask = ~0;
     VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_UPDATE_IRQ, 0);
-- 
1.7.5.4



More information about the Spice-devel mailing list