859 Signal(); |
859 Signal(); |
860 |
860 |
861 // release threads doing CancelAll() |
861 // release threads doing CancelAll() |
862 waiters->Signal(); |
862 waiters->Signal(); |
863 } |
863 } |
864 else if (!error && !iDfc.Queued() && !iReqQ.IsEmpty() && iController->IsIdle(*this)) |
864 else if (!error && iController->IsIdle(*this) && !iReqQ.IsEmpty() && !iDfc.Queued()) |
865 { |
865 { |
866 __KTRACE_OPT(KDMA, Kern::Printf("Missed interrupt(s) - draining request queue")); |
866 // Wait for a bit. If during that time the condition goes away then it |
867 ResetStateMachine(); |
867 // was a 'spurious missed interrupt', in which case we just do nothing. |
868 |
868 TBool spurious = EFalse; |
869 // Move orphaned requests to temporary queue so channel queue can |
869 const TUint32 nano_secs_per_loop = 1000 * 1000; // 1ms |
870 // accept new requests. |
870 for (TInt i = 5; i > 0; i--) |
871 SDblQue q; |
|
872 q.MoveFrom(&iReqQ); |
|
873 |
|
874 SDblQueLink* pL; |
|
875 while ((pL = q.GetFirst()) != NULL) |
|
876 { |
871 { |
877 iQueuedRequests--; |
872 if (!iController->IsIdle(*this)) |
878 DDmaRequest* pR = _LOFF(pL, DDmaRequest, iLink); |
|
879 __KTRACE_OPT(KDMA, Kern::Printf("Removing request from queue and notifying client")); |
|
880 pR->OnDeque(); |
|
881 DDmaRequest::TCallback cb = pR->iCb; |
|
882 TAny* arg = pR->iCbArg; |
|
883 if (cb) |
|
884 { |
873 { |
885 Signal(); |
874 __KTRACE_OPT(KDMA, Kern::Printf("DMAC no longer idle (i = %d)", i)); |
886 (*cb)(DDmaRequest::EOk, arg); |
875 spurious = ETrue; |
887 Wait(); |
876 break; |
|
877 } |
|
878 else if (iDfc.Queued()) |
|
879 { |
|
880 __KTRACE_OPT(KDMA, Kern::Printf("DFC now queued (i = %d)", i)); |
|
881 spurious = ETrue; |
|
882 break; |
|
883 } |
|
884 Kern::NanoWait(nano_secs_per_loop); |
|
885 } |
|
886 if (!spurious) |
|
887 { |
|
888 __KTRACE_OPT(KDMA, |
|
889 Kern::Printf("Missed interrupt(s) - draining request queue on ch %d", |
|
890 PslId())); |
|
891 ResetStateMachine(); |
|
892 |
|
893 // Move orphaned requests to temporary queue so channel queue can |
|
894 // accept new requests. |
|
895 SDblQue q; |
|
896 q.MoveFrom(&iReqQ); |
|
897 |
|
898 SDblQueLink* pL; |
|
899 while ((pL = q.GetFirst()) != NULL) |
|
900 { |
|
901 iQueuedRequests--; |
|
902 DDmaRequest* pR = _LOFF(pL, DDmaRequest, iLink); |
|
903 __KTRACE_OPT(KDMA, Kern::Printf("Removing request from queue and notifying client")); |
|
904 pR->OnDeque(); |
|
905 DDmaRequest::TCallback cb = pR->iCb; |
|
906 TAny* arg = pR->iCbArg; |
|
907 if (cb) |
|
908 { |
|
909 Signal(); |
|
910 (*cb)(DDmaRequest::EOk, arg); |
|
911 Wait(); |
|
912 } |
888 } |
913 } |
889 } |
914 } |
890 req_count_after = iQueuedRequests; |
915 req_count_after = iQueuedRequests; |
891 Signal(); |
916 Signal(); |
892 } |
917 } |