}
 
 /*
- * This function handles all OS-owned events on the event ring.  It may drop
+ * This function handles one OS-owned event on the event ring. It may drop
  * xhci->lock between event processing (e.g. to pass up port status changes).
- * Returns >0 for "possibly more events to process" (caller should call again),
- * otherwise 0 if done.  In future, <0 returns should indicate error code.
  */
-static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
+                                union xhci_trb *event)
 {
-       union xhci_trb *event;
        u32 trb_type;
 
-       event = ir->event_ring->dequeue;
-
-       if (!unhandled_event_trb(ir->event_ring))
-               return 0;
-
        trace_xhci_handle_event(ir->event_ring, &event->generic);
 
        /*
-        * Barrier between reading the TRB_CYCLE (valid) flag above and any
+        * Barrier between reading the TRB_CYCLE (valid) flag before, and any
         * speculative reads of the event's flags/data below.
         */
        rmb();
         * to make sure a watchdog timer didn't mark the host as non-responsive.
         */
        if (xhci->xhc_state & XHCI_STATE_DYING) {
-               xhci_dbg(xhci, "xHCI host dying, returning from "
-                               "event handler.\n");
-               return 0;
+               xhci_dbg(xhci, "xHCI host dying, returning from event handler.\n");
+               return -ENODEV;
        }
 
-       /* Are there more items on the event ring?  Caller will call us again to
-        * check.
-        */
-       return 1;
+       return 0;
 }
 
 /*
        }
 }
 
+/*
+ * Handle all OS-owned events on an interrupter event ring. It may drop
+ * and reaquire xhci->lock between event processing.
+ */
 static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
 {
        int event_loop = 0;
+       int err;
        u64 temp;
 
        xhci_clear_interrupt_pending(xhci, ir);
                return -ENODEV;
        }
 
-       while (xhci_handle_event(xhci, ir) > 0) {
+       /* Process all OS owned event TRBs on this event ring */
+       while (unhandled_event_trb(ir->event_ring)) {
+               err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue);
+
                /*
                 * If half a segment of events have been handled in one go then
                 * update ERDP, and force isoc trbs to interrupt more often
 
                /* Update SW event ring dequeue pointer */
                inc_deq(xhci, ir->event_ring);
+
+               if (err)
+                       break;
        }
 
        xhci_update_erst_dequeue(xhci, ir, true);