diff -r 4a8fed1c0ef6 -r 597aaf25e343 kernel/eka/drivers/dma/dmapil.cpp --- a/kernel/eka/drivers/dma/dmapil.cpp Sat Feb 20 00:10:51 2010 +0200 +++ b/kernel/eka/drivers/dma/dmapil.cpp Fri Mar 12 15:50:11 2010 +0200 @@ -861,30 +861,55 @@ // release threads doing CancelAll() waiters->Signal(); } - else if (!error && !iDfc.Queued() && !iReqQ.IsEmpty() && iController->IsIdle(*this)) + else if (!error && iController->IsIdle(*this) && !iReqQ.IsEmpty() && !iDfc.Queued()) { - __KTRACE_OPT(KDMA, Kern::Printf("Missed interrupt(s) - draining request queue")); - ResetStateMachine(); - - // Move orphaned requests to temporary queue so channel queue can - // accept new requests. - SDblQue q; - q.MoveFrom(&iReqQ); + // Wait for a bit. If during that time the condition goes away then it + // was a 'spurious missed interrupt', in which case we just do nothing. + TBool spurious = EFalse; + const TUint32 nano_secs_per_loop = 1000 * 1000; // 1ms + for (TInt i = 5; i > 0; i--) + { + if (!iController->IsIdle(*this)) + { + __KTRACE_OPT(KDMA, Kern::Printf("DMAC no longer idle (i = %d)", i)); + spurious = ETrue; + break; + } + else if (iDfc.Queued()) + { + __KTRACE_OPT(KDMA, Kern::Printf("DFC now queued (i = %d)", i)); + spurious = ETrue; + break; + } + Kern::NanoWait(nano_secs_per_loop); + } + if (!spurious) + { + __KTRACE_OPT(KDMA, + Kern::Printf("Missed interrupt(s) - draining request queue on ch %d", + PslId())); + ResetStateMachine(); - SDblQueLink* pL; - while ((pL = q.GetFirst()) != NULL) - { - iQueuedRequests--; - DDmaRequest* pR = _LOFF(pL, DDmaRequest, iLink); - __KTRACE_OPT(KDMA, Kern::Printf("Removing request from queue and notifying client")); - pR->OnDeque(); - DDmaRequest::TCallback cb = pR->iCb; - TAny* arg = pR->iCbArg; - if (cb) + // Move orphaned requests to temporary queue so channel queue can + // accept new requests. + SDblQue q; + q.MoveFrom(&iReqQ); + + SDblQueLink* pL; + while ((pL = q.GetFirst()) != NULL) { - Signal(); - (*cb)(DDmaRequest::EOk, arg); - Wait(); + iQueuedRequests--; + DDmaRequest* pR = _LOFF(pL, DDmaRequest, iLink); + __KTRACE_OPT(KDMA, Kern::Printf("Removing request from queue and notifying client")); + pR->OnDeque(); + DDmaRequest::TCallback cb = pR->iCb; + TAny* arg = pR->iCbArg; + if (cb) + { + Signal(); + (*cb)(DDmaRequest::EOk, arg); + Wait(); + } } } req_count_after = iQueuedRequests;