--- 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;