Index: trunk/src/VBox/Devices/USB/DevOHCI.cpp
===================================================================
--- trunk/src/VBox/Devices/USB/DevOHCI.cpp	(revision 49957)
+++ trunk/src/VBox/Devices/USB/DevOHCI.cpp	(revision 49958)
@@ -361,4 +361,7 @@
 
     uint32_t            Alignment3;     /**< Align size on a 8 byte boundary. */
+
+    /** Critical section synchronising interrupt handling. */
+    PDMCRITSECT         CsIrq;
 
     /** The framer thread. */
@@ -797,11 +800,7 @@
  * Update PCI IRQ levels
  */
-static void ohciUpdateInterrupt(POHCI ohci, const char *msg)
+static void ohciUpdateInterruptLocked(POHCI ohci, const char *msg)
 {
     int level = 0;
-
-#ifdef IN_RING3
-    PDMCritSectEnter(ohci->pDevInsR3->pCritSectRoR3, VERR_IGNORED);
-#endif
 
     if (    (ohci->intr & OHCI_INTR_MASTER_INTERRUPT_ENABLED)
@@ -818,8 +817,4 @@
               (val >> 6) & 1, (val >> 30) & 1, msg)); NOREF(val); NOREF(msg);
     }
-
-#ifdef IN_RING3
-    PDMCritSectLeave(ohci->pDevInsR3->pCritSectRoR3);
-#endif
 }
 
@@ -827,10 +822,20 @@
  * Set an interrupt, use the wrapper ohciSetInterrupt.
  */
-DECLINLINE(void) ohciSetInterruptInt(POHCI ohci, uint32_t intr, const char *msg)
-{
-    if ( (ohci->intr_status & intr) == intr )
-        return;
-    ohci->intr_status |= intr;
-    ohciUpdateInterrupt(ohci, msg);
+DECLINLINE(int) ohciSetInterruptInt(POHCI ohci, int rcBusy, uint32_t intr, const char *msg)
+{
+    int rc = VINF_SUCCESS;
+
+    rc = PDMCritSectEnter(&ohci->CsIrq, rcBusy);
+    if (rc != VINF_SUCCESS)
+        return rc;
+
+    if ( (ohci->intr_status & intr) != intr )
+    {
+        ohci->intr_status |= intr;
+        ohciUpdateInterruptLocked(ohci, msg);
+    }
+
+    PDMCritSectLeave(&ohci->CsIrq);
+    return rc;
 }
 
@@ -838,6 +843,6 @@
  * Set an interrupt wrapper macro for logging purposes.
  */
-#define ohciSetInterrupt(ohci, intr) ohciSetInterruptInt(ohci, intr, #intr)
-
+#define ohciSetInterrupt(ohci, a_rcBusy, intr) ohciSetInterruptInt(ohci, a_rcBusy, intr, #intr)
+#define ohciR3SetInterrupt(ohci, intr) ohciSetInterruptInt(ohci, VERR_IGNORED, intr, #intr)
 
 #ifdef IN_RING3
@@ -960,5 +965,5 @@
 
     ohci_remote_wakeup(pThis);
-    ohciSetInterrupt(pThis, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
+    ohciR3SetInterrupt(pThis, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
 
     PDMCritSectLeave(pThis->pDevInsR3->pCritSectRoR3);
@@ -997,5 +1002,5 @@
 
     ohci_remote_wakeup(pThis);
-    ohciSetInterrupt(pThis, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
+    ohciR3SetInterrupt(pThis, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
 
     PDMCritSectLeave(pThis->pDevInsR3->pCritSectRoR3);
@@ -3555,5 +3560,5 @@
     ohciPhysWrite(pThis, pThis->hcca + OHCI_HCCA_OFS, (uint8_t *)&hcca, sizeof(hcca));
     if (fWriteDoneHeadInterrupt)
-        ohciSetInterrupt(pThis, OHCI_INTR_WRITE_DONE_HEAD);
+        ohciR3SetInterrupt(pThis, OHCI_INTR_WRITE_DONE_HEAD);
 }
 
@@ -3701,9 +3706,9 @@
 
     /* "After writing to HCCA, HC will set SF in HcInterruptStatus" - guest isn't executing, so ignore the order! */
-    ohciSetInterrupt(pThis, OHCI_INTR_START_OF_FRAME);
+    ohciR3SetInterrupt(pThis, OHCI_INTR_START_OF_FRAME);
 
     if (pThis->fno)
     {
-        ohciSetInterrupt(pThis, OHCI_INTR_FRAMENUMBER_OVERFLOW);
+        ohciR3SetInterrupt(pThis, OHCI_INTR_FRAMENUMBER_OVERFLOW);
         pThis->fno = 0;
     }
@@ -3921,5 +3926,5 @@
 
     if (fHardware && (pThis->ctl & OHCI_CTL_RWE))
-        ohciSetInterrupt(pThis, OHCI_INTR_RESUME_DETECT);
+        ohciR3SetInterrupt(pThis, OHCI_INTR_RESUME_DETECT);
 
     ohciBusStart(pThis);
@@ -4127,4 +4132,10 @@
     uint32_t res = pThis->intr_status & ~val;
     uint32_t chg = pThis->intr_status ^ res; NOREF(chg);
+    int rc = VINF_SUCCESS;
+
+    rc = PDMCritSectEnter(&pThis->CsIrq, VINF_IOM_R3_MMIO_WRITE);
+    if (rc != VINF_SUCCESS)
+        return rc;
+
     Log2(("HcInterruptStatus_w(%#010x) => %sSO=%d %sWDH=%d %sSF=%d %sRD=%d %sUE=%d %sFNO=%d %sRHSC=%d %sOC=%d\n",
           val,
@@ -4145,5 +4156,6 @@
      */
     pThis->intr_status &= ~val;
-    ohciUpdateInterrupt(pThis, "HcInterruptStatus_w");
+    ohciUpdateInterruptLocked(pThis, "HcInterruptStatus_w");
+    PDMCritSectLeave(&pThis->CsIrq);
     return VINF_SUCCESS;
 }
@@ -4169,4 +4181,10 @@
     uint32_t res = pThis->intr | val;
     uint32_t chg = pThis->intr ^ res; NOREF(chg);
+    int rc = VINF_SUCCESS;
+
+    rc = PDMCritSectEnter(&pThis->CsIrq, VINF_IOM_R3_MMIO_WRITE);
+    if (rc != VINF_SUCCESS)
+        return rc;
+
     Log2(("HcInterruptEnable_w(%#010x) => %sSO=%d %sWDH=%d %sSF=%d %sRD=%d %sUE=%d %sFNO=%d %sRHSC=%d %sOC=%d %sMIE=%d\n",
           val,
@@ -4184,5 +4202,6 @@
 
     pThis->intr |= val;
-    ohciUpdateInterrupt(pThis, "HcInterruptEnable_w");
+    ohciUpdateInterruptLocked(pThis, "HcInterruptEnable_w");
+    PDMCritSectLeave(&pThis->CsIrq);
     return VINF_SUCCESS;
 }
@@ -4213,4 +4232,10 @@
     uint32_t res = pThis->intr & ~val;
     uint32_t chg = pThis->intr ^ res; NOREF(chg);
+    int rc = VINF_SUCCESS;
+
+    rc = PDMCritSectEnter(&pThis->CsIrq, VINF_IOM_R3_MMIO_WRITE);
+    if (rc != VINF_SUCCESS)
+        return rc;
+
     Log2(("HcInterruptDisable_w(%#010x) => %sSO=%d %sWDH=%d %sSF=%d %sRD=%d %sUE=%d %sFNO=%d %sRHSC=%d %sOC=%d %sMIE=%d\n",
           val,
@@ -4228,5 +4253,6 @@
 
     pThis->intr &= ~val;
-    ohciUpdateInterrupt(pThis, "HcInterruptDisable_w");
+    ohciUpdateInterruptLocked(pThis, "HcInterruptDisable_w");
+    PDMCritSectLeave(&pThis->CsIrq);
     return VINF_SUCCESS;
 }
@@ -4768,5 +4794,5 @@
 
     /* Raise roothub status change interrupt. */
-    ohciSetInterrupt(pThis, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
+    ohciR3SetInterrupt(pThis, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
 }
 
@@ -4792,5 +4818,5 @@
     {
         pRh->aPorts[iPort].fReg |= OHCI_PORT_R_CONNECT_STATUS_CHANGE;
-        ohciSetInterrupt(pRh->pOhci, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
+        ohciR3SetInterrupt(pRh->pOhci, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
         return false;
     }
@@ -4887,5 +4913,5 @@
         pThis->RootHub.aPorts[i].fReg &= ~OHCI_PORT_R_SUSPEND_STATUS;
         pThis->RootHub.aPorts[i].fReg |= OHCI_PORT_R_SUSPEND_STATUS_CHANGE;
-        ohciSetInterrupt(pThis, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
+        ohciR3SetInterrupt(pThis, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
     }
 
@@ -5518,4 +5544,5 @@
     RTSemEventDestroy(pThis->hSemEventFrame);
     RTCritSectDelete(&pThis->CritSect);
+    PDMR3CritSectDelete(&pThis->CsIrq);
 
     /*
@@ -5664,22 +5691,13 @@
     pThis->fBusStarted = false;
 
+    rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CsIrq, RT_SRC_POS, "OHCI#%uIrq", iInstance);
+    if (RT_FAILURE(rc))
+        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
+                                   N_("EHCI: Failed to create critical section"));
+
     rc = RTSemEventCreate(&pThis->hSemEventFrame);
     AssertRCReturn(rc, rc);
 
-    /*
-     * Initialize the critical section without the lock validator.
-     * This is necessary because USB devices attached to this controller
-     * will be detached in the save state callback with the
-     * per device PDM critical section held. If there are still URBs pending
-     * for this device they will get reaped and cause a lock validator error
-     * because they will take this critical section.
-     *
-     * The framer thread on the other hand will first take this critical section
-     * during a run and might take the PDM critical section when issuing an interrupt.
-     * Normally this is a real deadlock issue but we make sure
-     * that the framer thread is not running when the save state handler is called.
-     */
-    rc = RTCritSectInitEx(&pThis->CritSect, RTCRITSECT_FLAGS_NO_LOCK_VAL,
-                          NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_USER, "OhciCritSect");
+    rc = RTCritSectInit(&pThis->CritSect);
     if (RT_FAILURE(rc))
         return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
Index: trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
===================================================================
--- trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp	(revision 49957)
+++ trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp	(revision 49958)
@@ -1003,4 +1003,5 @@
     GEN_CHECK_OFF(OHCI, hSemEventFrame);
     GEN_CHECK_OFF(OHCI, fBusStarted);
+    GEN_CHECK_OFF(OHCI, CsIrq);
     GEN_CHECK_OFF(OHCI, nsWait);
     GEN_CHECK_OFF(OHCI, CritSect);
@@ -1085,4 +1086,5 @@
     GEN_CHECK_OFF(EHCI, hSemEventFrame);
     GEN_CHECK_OFF(EHCI, fBusStarted);
+    GEN_CHECK_OFF(EHCI, CsIrq);
     GEN_CHECK_OFF(EHCI, nsWait);
     GEN_CHECK_OFF(EHCI, CritSect);
