Index: uspace/drv/bus/usb/xhci/isoch.c
===================================================================
--- uspace/drv/bus/usb/xhci/isoch.c	(revision 929599a8d927390e0ba2dac24b9c478c06a31496)
+++ uspace/drv/bus/usb/xhci/isoch.c	(revision 4ed803f13d7ef1d64d640831064ef239e177589b)
@@ -84,4 +84,37 @@
 }
 
+static void isoch_reset_no_timer(xhci_endpoint_t *ep)
+{
+	xhci_isoch_t * const isoch = ep->isoch;
+	assert(fibril_mutex_is_locked(&isoch->guard));
+	/*
+	 * As we cannot clear timer when we are triggered by it,
+	 * we have to avoid doing it in common method.
+	 */
+	fibril_timer_clear_locked(isoch->reset_timer);
+	isoch_reset(ep);
+}
+
+static void isoch_reset_timer(void *ep) {
+	xhci_isoch_t * const isoch = xhci_endpoint_get(ep)->isoch;
+	fibril_mutex_lock(&isoch->guard);
+	isoch_reset(ep);
+	fibril_mutex_unlock(&isoch->guard);
+}
+
+/*
+ * Fast transfers could trigger the reset timer before the data is processed,
+ * leading into false reset.
+ */
+#define RESET_TIMER_DELAY 100000
+static void timer_schedule_reset(xhci_endpoint_t *ep) {
+	xhci_isoch_t * const isoch = ep->isoch;
+	const suseconds_t delay = isoch->buffer_count * ep->interval * 125 + RESET_TIMER_DELAY;
+
+	fibril_timer_clear_locked(isoch->reset_timer);
+	fibril_timer_set_locked(isoch->reset_timer, delay,
+		isoch_reset_timer, ep);
+}
+
 void isoch_fini(xhci_endpoint_t *ep)
 {
@@ -92,4 +125,6 @@
 		fibril_timer_clear(isoch->feeding_timer);
 		fibril_timer_destroy(isoch->feeding_timer);
+		fibril_timer_clear(isoch->reset_timer);
+		fibril_timer_destroy(isoch->reset_timer);
 	}
 
@@ -109,4 +144,5 @@
 
 	isoch->feeding_timer = fibril_timer_create(&isoch->guard);
+	isoch->reset_timer = fibril_timer_create(&isoch->guard);
 	if (!isoch->feeding_timer)
 		return ENOMEM;
@@ -115,5 +151,5 @@
 	if(!isoch->transfers)
 		goto err;
- 
+
 	for (size_t i = 0; i < isoch->buffer_count; ++i) {
 		xhci_isoch_transfer_t *transfer = &isoch->transfers[i];
@@ -124,5 +160,5 @@
 
 	fibril_mutex_lock(&isoch->guard);
-	isoch_reset(ep);
+	isoch_reset_no_timer(ep);
 	fibril_mutex_unlock(&isoch->guard);
 
@@ -226,5 +262,5 @@
 	 * to ensure correct scheduling of transfers, that are
 	 * buffer_count * interval away from now.
-	 * Maximum interval is 8 seconds, which means we need a size of 
+	 * Maximum interval is 8 seconds, which means we need a size of
 	 * 16 seconds. The size of MFIINDEX is 2 seconds only.
 	 *
@@ -301,10 +337,12 @@
 		}
 	}
+
 out:
-
 	if (fed) {
 		const uint8_t slot_id = xhci_device_get(ep->base.device)->slot_id;
 		const uint8_t target = xhci_endpoint_index(ep) + 1; /* EP Doorbells start at 1 */
 		hc_ring_doorbell(hc, slot_id, target);
+		/* The ring may be dead. If no event happens until the delay, reset the endpoint. */
+		timer_schedule_reset(ep);
 	}
 
@@ -394,4 +432,6 @@
 		const uint8_t target = xhci_endpoint_index(ep) + 1; /* EP Doorbells start at 1 */
 		hc_ring_doorbell(hc, slot_id, target);
+		/* The ring may be dead. If no event happens until the delay, reset the endpoint. */
+		timer_schedule_reset(ep);
 	}
 }
@@ -541,5 +581,5 @@
 			/* For IN, the buffer has overfilled, we empty the buffers and readd TRBs */
 			usb_log_warning("Ring over/underrun.");
-			isoch_reset(ep);
+			isoch_reset_no_timer(ep);
 			fibril_condvar_broadcast(&ep->isoch->avail);
 			fibril_mutex_unlock(&ep->isoch->guard);
@@ -555,26 +595,21 @@
 	}
 
-	bool found_mine = false;
-	bool found_incomplete = false;
-
 	/*
 	 * The order of delivering events is not necessarily the one we would
-	 * expect. It is safer to walk the list of our 4 transfers and check
+	 * expect. It is safer to walk the list of our transfers and check
 	 * which one it is.
+	 * To minimize the amount of transfers checked, we start at dequeue pointer
+	 * and exit the loop as soon as the transfer is found.
 	 */
-	for (size_t i = 0; i < isoch->buffer_count; ++i) {
-		xhci_isoch_transfer_t * const it = &isoch->transfers[i];
-
-		switch (it->state) {
-		case ISOCH_FILLED:
-			found_incomplete = true;
-			break;
-
-		case ISOCH_FED:
-			if (it->interrupt_trb_phys != trb->parameter) {
-				found_incomplete = true;
-				break;
-			}
-
+	bool found_mine = false;
+	for (size_t i = 0, di = isoch->dequeue; i < isoch->buffer_count; ++i, ++di) {
+		/* Wrap it back to 0, don't use modulo every loop traversal */
+		if (di == isoch->buffer_count) {
+			di = 0;
+		}
+
+		xhci_isoch_transfer_t * const it = &isoch->transfers[di];
+
+		if (it->state == ISOCH_FED && it->interrupt_trb_phys == trb->parameter) {
 			usb_log_debug2("[isoch] buffer %zu completed", it - isoch->transfers);
 			it->state = ISOCH_COMPLETE;
@@ -583,6 +618,4 @@
 			found_mine = true;
 			break;
-		default:
-			break;
 		}
 	}
@@ -595,12 +628,9 @@
 	 * It may happen that the driver already stopped reading (writing),
 	 * and our buffers are filled (empty). As QEMU (and possibly others)
-	 * does not send RING_UNDERRUN (OVERRUN) event, detect it here.
+	 * does not send RING_UNDERRUN (OVERRUN) event, we set a timer to
+	 * reset it after the buffers should have been consumed. If there
+	 * is no issue, the timer will get restarted often enough.
 	 */
-	if (!found_incomplete) {
-		usb_log_warning("[isoch] Endpoint" XHCI_EP_FMT ": Detected "
-		    "isochronous ring %s.", XHCI_EP_ARGS(*ep),
-		    (ep->base.direction == USB_DIRECTION_IN) ? "underrun" : "overrun");
-		isoch_reset(ep);
-	}
+	timer_schedule_reset(ep);
 
 	fibril_condvar_broadcast(&ep->isoch->avail);
Index: uspace/drv/bus/usb/xhci/isoch.h
===================================================================
--- uspace/drv/bus/usb/xhci/isoch.h	(revision 929599a8d927390e0ba2dac24b9c478c06a31496)
+++ uspace/drv/bus/usb/xhci/isoch.h	(revision 4ed803f13d7ef1d64d640831064ef239e177589b)
@@ -81,4 +81,7 @@
 	fibril_timer_t *feeding_timer;
 
+	/** Resets endpoint if there is no traffic. */
+	fibril_timer_t *reset_timer;
+
 	/** The maximum size of an isochronous transfer and therefore the size of buffers */
 	size_t max_size;
