diff -r 36bfc973b146 -r 329ab0095843 kernel/eka/drivers/dma/dmapil.cpp --- a/kernel/eka/drivers/dma/dmapil.cpp Thu Jan 07 13:38:45 2010 +0200 +++ b/kernel/eka/drivers/dma/dmapil.cpp Mon Jan 18 21:31:10 2010 +0200 @@ -475,6 +475,15 @@ // append request to queue and link new descriptor list to existing one. iChannel.Wait(); + + TUint32 req_count = iChannel.iQueuedRequests++; + if (req_count == 0) + { + iChannel.Signal(); + iChannel.QueuedRequestCountChanged(); + iChannel.Wait(); + } + if (!(iChannel.iIsrDfc & (TUint32)TDmaChannel::KCancelFlagMask)) { iQueued = ETrue; @@ -482,8 +491,18 @@ *iChannel.iNullPtr = iFirstHdr; iChannel.iNullPtr = &(iLastHdr->iNext); iChannel.DoQueue(*this); + iChannel.Signal(); } - iChannel.Signal(); + else + { + // Someone is cancelling all requests... + req_count = --iChannel.iQueuedRequests; + iChannel.Signal(); + if (req_count == 0) + { + iChannel.QueuedRequestCountChanged(); + } + } __DMA_INVARIANT(); } @@ -586,14 +605,19 @@ TDmaChannel::TDmaChannel() - : iNullPtr(&iCurHdr), - iDfc(Dfc, NULL, 0) + : iController(NULL), + iPslId(0), + iCurHdr(NULL), + iNullPtr(&iCurHdr), + iDfc(Dfc, NULL, 0), + iMaxDesCount(0), + iAvailDesCount(0), + iIsrDfc(0), + iReqQ(), + iReqCount(0), + iQueuedRequests(0), + iCancelInfo(NULL) { - // iController = NULL; - // iPslId = 0; - // iCurHdr = NULL; - // iMaxDesCount = iAvailDesCount = 0; - // iReqCount = 0; __DMA_INVARIANT(); } @@ -640,6 +664,8 @@ __DMA_ASSERTD(IsQueueEmpty()); __DMA_ASSERTD(iReqCount == 0); + __DMA_ASSERTD(iQueuedRequests == 0); + // descriptor leak? bug in request code __DMA_ASSERTD(iAvailDesCount == iMaxDesCount); @@ -665,8 +691,10 @@ TBool wait = FALSE; TDmaCancelInfo c; TDmaCancelInfo* waiters = 0; + NKern::ThreadEnterCS(); Wait(); + const TUint32 req_count_before = iQueuedRequests; NThreadBase* dfcnt = iDfc.Thread(); __e32_atomic_store_ord32(&iIsrDfc, (TUint32)KCancelFlagMask); // ISRs after this point will not post a DFC, however a DFC may already be queued or running or both @@ -683,6 +711,7 @@ SDblQueLink* pL; while ((pL = iReqQ.GetFirst()) != NULL) { + iQueuedRequests--; DDmaRequest* pR = _LOFF(pL, DDmaRequest, iLink); pR->OnDeque(); } @@ -709,12 +738,21 @@ wait = TRUE; iDfc.Enque(); } + const TUint32 req_count_after = iQueuedRequests; Signal(); if (waiters) waiters->Signal(); if (wait) NKern::FSWait(&c.iSem); NKern::ThreadLeaveCS(); + + // Only call PSL if there were requests queued when we entered AND there + // are now no requests left on the queue. + if ((req_count_before != 0) && (req_count_after == 0)) + { + QueuedRequestCountChanged(); + } + __DMA_INVARIANT(); } @@ -740,6 +778,8 @@ const TBool error = w & (TUint32)KErrorFlagMask; TBool stop = w & (TUint32)KCancelFlagMask; __DMA_ASSERTD(count>0 || stop); + const TUint32 req_count_before = iQueuedRequests; + TUint32 req_count_after = 0; while(count && !stop) { @@ -767,6 +807,7 @@ { pCompletedReq = pCurReq; pCurReq->iLink.Deque(); + iQueuedRequests--; if (iReqQ.IsEmpty()) iNullPtr = &iCurHdr; pCompletedReq->OnDeque(); @@ -814,6 +855,7 @@ // reset the ISR count - new requests can now be processed __e32_atomic_store_rel32(&iIsrDfc, 0); + req_count_after = iQueuedRequests; Signal(); // release threads doing CancelAll() @@ -832,6 +874,7 @@ 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(); @@ -844,10 +887,22 @@ Wait(); } } + req_count_after = iQueuedRequests; Signal(); } else + { + req_count_after = iQueuedRequests; Signal(); + } + + // Only call PSL if there were requests queued when we entered AND there + // are now no requests left on the queue (after also having executed all + // client callbacks). + if ((req_count_before != 0) && (req_count_after == 0)) + { + QueuedRequestCountChanged(); + } __DMA_INVARIANT(); } @@ -870,6 +925,21 @@ { } + +/** PSL may override */ +void TDmaChannel::QueuedRequestCountChanged() + { +#ifdef _DEBUG + Wait(); + __KTRACE_OPT(KDMA, + Kern::Printf("TDmaChannel::QueuedRequestCountChanged() %d", + iQueuedRequests)); + __DMA_ASSERTA(iQueuedRequests >= 0); + Signal(); +#endif + } + + #ifdef _DEBUG void TDmaChannel::Invariant()