xhci_intr_raise() returned early whenever ERDP.EHB was set; that also
skipped IRQ assertion after the guest cleared IMAN.IP while leaving the
event handler busy bit asserted.

Track the previous IMAN.IP state and suppress only duplicate raises;
when ERDP.EHB remains set after IMAN.IP is cleared, assert the IRQ again
so the guest can observe the pending event.

Signed-off-by: Kirill A. Korinsky <[email protected]>
---
 hw/usb/hcd-xhci.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 2cdab3ba0e..ce06d52c36 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -577,12 +577,13 @@ static void xhci_intr_update(XHCIState *xhci, int v)
 static void xhci_intr_raise(XHCIState *xhci, int v)
 {
     bool pending = (xhci->intr[v].erdp_low & ERDP_EHB);
+    bool was_raised = (xhci->intr[v].iman & IMAN_IP);
 
     xhci->intr[v].erdp_low |= ERDP_EHB;
     xhci->intr[v].iman |= IMAN_IP;
     xhci->usbsts |= USBSTS_EINT;
 
-    if (pending) {
+    if (pending && was_raised) {
         return;
     }
     if (!(xhci->intr[v].iman & IMAN_IE)) {
-- 
2.54.0


Reply via email to