[Spice-devel,6/7] qxl-wddm-dod: VSync processing for QXL rev.4

Submitted by Yuri Benditovich on Feb. 12, 2017, 1:09 p.m.

Details

Message ID 1486904994-169784-7-git-send-email-yuri.benditovich@daynix.com
State New
Headers show
Series "Changes for Win10 HLK test" ( rev: 1 ) in Spice

Not browsing as part of any series.

Commit Message

Yuri Benditovich Feb. 12, 2017, 1:09 p.m.
QXL rev.4 device sends interrupts to guest system and they
should be synchronized with VSync interrupt indication to avoid
failure to queue DPC when real interrupt happens.
When the driver needs to raise VSync interrupt indication to OS
it checks active interrupts in hardware and in any case stops
interrupt generation, then queues DPC (if it is not done by the
interrupt handler). DPC procedure of the interrupt processes
interrupt events and enables interrupts from the device.

Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
---
 qxldod/QxlDod.cpp | 47 ++++++++++++++++++++++++++++++++++++++++-------
 qxldod/QxlDod.h   |  5 +++++
 2 files changed, 45 insertions(+), 7 deletions(-)

Patch hide | download patch | download mbox

diff --git a/qxldod/QxlDod.cpp b/qxldod/QxlDod.cpp
index b3e0938..fcca7d1 100755
--- a/qxldod/QxlDod.cpp
+++ b/qxldod/QxlDod.cpp
@@ -4765,6 +4765,28 @@  BOOLEAN QxlDevice::InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_
 }
 
 QXL_NON_PAGED
+VOID QxlDevice::VSyncInterruptPostProcess(_In_ PDXGKRNL_INTERFACE pDxgkInterface)
+{
+    if (!InterruptRoutine(pDxgkInterface, 0))
+    {
+        // disable interrupt generation
+        m_RamHdr->int_mask = 0;
+        WRITE_PORT_UCHAR((PUCHAR)(m_IoBase + QXL_IO_UPDATE_IRQ), 0);
+        // it is still possible that the DPC is already queued for previous interrupts,
+        // then its callback will enable interrupts and IRQ will fire
+        if (!pDxgkInterface->DxgkCbQueueDpc(pDxgkInterface->DeviceHandle)) {
+            DbgPrint(TRACE_LEVEL_WARNING, ("---> %s can't enqueue DPC, pending interrupts %X\n", __FUNCTION__, m_Pending));
+        }
+    }
+    else
+    {
+        // interrupt routine found pending active interrupt,
+        // so it masks interrupts, spawns DPC and enables interrupts
+        // in DPC processing, we do not need to do anything
+    }
+}
+
+QXL_NON_PAGED
 VOID QxlDevice::DpcRoutine(PVOID ptr)
 {
     PDXGKRNL_INTERFACE pDxgkInterface = (PDXGKRNL_INTERFACE)ptr;
@@ -4898,14 +4920,25 @@  NTSTATUS HwDeviceInterface::AcquireDisplayInfo(DXGK_DISPLAY_INFORMATION& DispInf
     return Status;
 }
 
-QXL_NON_PAGED static BOOLEAN VSynchRoutine(PVOID context)
+// Vga device does not generate interrupts
+QXL_NON_PAGED VOID VgaDevice::VSyncInterruptPostProcess(_In_ PDXGKRNL_INTERFACE pxface)
+{
+    pxface->DxgkCbQueueDpc(pxface->DeviceHandle);
+}
+
+QXL_NON_PAGED VOID QxlDod::IndicateVSyncInterrupt()
 {
-    DXGKRNL_INTERFACE *pxface = (DXGKRNL_INTERFACE *)context;
     DXGKARGCB_NOTIFY_INTERRUPT_DATA data = {};
     data.InterruptType = DXGK_INTERRUPT_DISPLAYONLY_VSYNC;
-    pxface->DxgkCbNotifyInterrupt(pxface->DeviceHandle, &data);
-    pxface->DxgkCbQueueDpc(pxface->DeviceHandle);
-    return 0;
+    m_DxgkInterface.DxgkCbNotifyInterrupt(m_DxgkInterface.DeviceHandle, &data);
+    m_pHWDevice->VSyncInterruptPostProcess(&m_DxgkInterface);
+}
+
+QXL_NON_PAGED BOOLEAN QxlDod::VsyncTimerSynchRoutine(PVOID context)
+{
+    QxlDod* pQxl = reinterpret_cast<QxlDod*>(context);
+    pQxl->IndicateVSyncInterrupt();
+    return FALSE;
 }
 
 QXL_NON_PAGED VOID QxlDod::VsyncTimerProc()
@@ -4916,8 +4949,8 @@  QXL_NON_PAGED VOID QxlDod::VsyncTimerProc()
     {
         m_DxgkInterface.DxgkCbSynchronizeExecution(
             m_DxgkInterface.DeviceHandle,
-            VSynchRoutine,
-            &m_DxgkInterface,
+            VsyncTimerSynchRoutine,
+            this,
             0,
             &bDummy
         );
diff --git a/qxldod/QxlDod.h b/qxldod/QxlDod.h
index 005aaed..b14a02f 100755
--- a/qxldod/QxlDod.h
+++ b/qxldod/QxlDod.h
@@ -239,6 +239,7 @@  public:
     QXL_NON_PAGED virtual BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_  ULONG MessageNumber) = 0;
     QXL_NON_PAGED virtual VOID DpcRoutine(PVOID) = 0;
     QXL_NON_PAGED virtual VOID ResetDevice(void) = 0;
+    QXL_NON_PAGED virtual VOID VSyncInterruptPostProcess(_In_ PDXGKRNL_INTERFACE) = 0;
     virtual NTSTATUS AcquireFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode) { return STATUS_SUCCESS; }
     virtual NTSTATUS ReleaseFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode) { return STATUS_SUCCESS; }
 
@@ -306,6 +307,7 @@  public:
     QXL_NON_PAGED BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_  ULONG MessageNumber);
     QXL_NON_PAGED VOID DpcRoutine(PVOID);
     QXL_NON_PAGED VOID ResetDevice(VOID);
+    QXL_NON_PAGED VOID VSyncInterruptPostProcess(_In_ PDXGKRNL_INTERFACE);
     NTSTATUS AcquireFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode);
     NTSTATUS ReleaseFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode);
     NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape);
@@ -480,6 +482,7 @@  public:
     QXL_NON_PAGED BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_  ULONG MessageNumber);
     QXL_NON_PAGED VOID DpcRoutine(PVOID);
     QXL_NON_PAGED VOID ResetDevice(VOID);
+    QXL_NON_PAGED VOID VSyncInterruptPostProcess(_In_ PDXGKRNL_INTERFACE);
     NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape);
     NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition);
     NTSTATUS Escape(_In_ CONST DXGKARG_ESCAPE* pEscap);
@@ -753,6 +756,8 @@  private:
     NTSTATUS RegisterHWInfo(_In_ ULONG Id);
     QXL_NON_PAGED VOID VsyncTimerProc();
     static QXL_NON_PAGED VOID VsyncTimerProcGate(_In_ _KDPC *dpc, _In_ PVOID context, _In_ PVOID arg1, _In_ PVOID arg2);
+    QXL_NON_PAGED VOID IndicateVSyncInterrupt();
+    static QXL_NON_PAGED BOOLEAN VsyncTimerSynchRoutine(PVOID context);
 };
 
 NTSTATUS