diff -r 43365a9b78a3 -r d8d70de2bd36 kernel/eka/drivers/dma/dma2_pil.cpp --- a/kernel/eka/drivers/dma/dma2_pil.cpp Tue Jul 06 15:50:07 2010 +0300 +++ b/kernel/eka/drivers/dma/dma2_pil.cpp Wed Aug 18 11:08:29 2010 +0300 @@ -22,23 +22,21 @@ #include -// Symbian Min() & Max() are broken, so we have to define them ourselves -inline TUint Min(TUint aLeft, TUint aRight) +// Symbian _Min() & _Max() are broken, so we have to define them ourselves +inline TUint _Min(TUint aLeft, TUint aRight) {return(aLeft < aRight ? aLeft : aRight);} -inline TUint Max(TUint aLeft, TUint aRight) +inline TUint _Max(TUint aLeft, TUint aRight) {return(aLeft > aRight ? aLeft : aRight);} -// Uncomment the following #define only when freezing the DMA2 export library. -//#define __FREEZE_DMA2_LIB -#ifdef __FREEZE_DMA2_LIB +// The following section is used only when freezing the DMA2 export library +/* TInt DmaChannelMgr::StaticExtension(TInt, TAny*) {return 0;} TDmaChannel* DmaChannelMgr::Open(TUint32, TBool, TUint) {return 0;} void DmaChannelMgr::Close(TDmaChannel*) {} EXPORT_C const TDmaTestInfo& DmaTestInfo() {static TDmaTestInfo a; return a;} EXPORT_C const TDmaV2TestInfo& DmaTestInfoV2() {static TDmaV2TestInfo a; return a;} -#endif // #ifdef __FREEZE_DMA2_LIB - +*/ static const char KDmaPanicCat[] = "DMA " __FILE__; @@ -202,7 +200,7 @@ { // TDmac needs to override this function if it has reported the channel // type for which the PIL calls it. - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); } @@ -211,7 +209,7 @@ { // TDmac needs to override this function if it has reported the channel // type for which the PIL calls it. - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); } @@ -265,7 +263,7 @@ } else { - iDesPool = new TDmaTransferArgs[iMaxDesCount]; + iDesPool = Kern::Alloc(iMaxDesCount * sizeof(TDmaTransferArgs)); r = iDesPool ? KErrNone : KErrNoMemory; } return r; @@ -450,7 +448,7 @@ TInt TDmac::InitHwDes(const SDmaDesHdr& /*aHdr*/, const TDmaTransferArgs& /*aTransferArgs*/) { // concrete controller must override if SDmacCaps::iHwDescriptors set - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); return KErrGeneral; } @@ -458,7 +456,7 @@ TInt TDmac::InitSrcHwDes(const SDmaDesHdr& /*aHdr*/, const TDmaTransferArgs& /*aTransferArgs*/) { // concrete controller must override if SDmacCaps::iAsymHwDescriptors set - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); return KErrGeneral; } @@ -466,7 +464,7 @@ TInt TDmac::InitDstHwDes(const SDmaDesHdr& /*aHdr*/, const TDmaTransferArgs& /*aTransferArgs*/) { // concrete controller must override if SDmacCaps::iAsymHwDescriptors set - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); return KErrGeneral; } @@ -502,7 +500,7 @@ TUint /*aTransferCount*/, TUint32 /*aPslRequestInfo*/) { // concrete controller must override if SDmacCaps::iHwDescriptors set - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); return KErrGeneral; } @@ -511,7 +509,7 @@ TUint /*aTransferCount*/, TUint32 /*aPslRequestInfo*/) { // concrete controller must override if SDmacCaps::iAsymHwDescriptors set - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); return KErrGeneral; } @@ -520,7 +518,7 @@ TUint /*aTransferCount*/, TUint32 /*aPslRequestInfo*/) { // concrete controller must override if SDmacCaps::iAsymHwDescriptors set - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); return KErrGeneral; } @@ -528,7 +526,7 @@ void TDmac::ChainHwDes(const SDmaDesHdr& /*aHdr*/, const SDmaDesHdr& /*aNextHdr*/) { // concrete controller must override if SDmacCaps::iHwDescriptors set - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); } @@ -536,7 +534,7 @@ const SDmaDesHdr& /*aNewHdr*/) { // concrete controller must override if SDmacCaps::iHwDescriptors set - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); } @@ -545,14 +543,14 @@ const SDmaDesHdr& /*aDstLastHdr*/, const SDmaDesHdr& /*aDstNewHdr*/) { // concrete controller must override if SDmacCaps::iAsymHwDescriptors set - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); } void TDmac::UnlinkHwDes(const TDmaChannel& /*aChannel*/, SDmaDesHdr& /*aHdr*/) { // concrete controller must override if SDmacCaps::iHwDescriptors set - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); } @@ -601,7 +599,7 @@ TUint32 TDmac::HwDesNumDstElementsTransferred(const SDmaDesHdr& /*aHdr*/) { // Concrete controller must override if SDmacCaps::iHwDescriptors set. - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); return 0; } @@ -609,7 +607,7 @@ TUint32 TDmac::HwDesNumSrcElementsTransferred(const SDmaDesHdr& /*aHdr*/) { // Concrete controller must override if SDmacCaps::iHwDescriptors set. - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); return 0; } @@ -856,7 +854,7 @@ } -TInt DDmaRequest::CheckMemFlags(const TDmaTransferConfig& aTarget, TUint aCount) const +TInt DDmaRequest::CheckMemFlags(const TDmaTransferConfig& aTarget) const { __KTRACE_OPT(KDMA, Kern::Printf("DDmaRequest::CheckMemFlags")); @@ -892,7 +890,7 @@ TUint rem = 0; TInt r = KErrNone; - while (1) + FOREVER { // If an element size is defined, make sure the fragment size is // greater or equal. @@ -1101,13 +1099,13 @@ aTransferArgs.iChannelCookie = iChannel.PslId(); // Client shouldn't specify contradictory or invalid things - TInt r = CheckMemFlags(aTransferArgs.iSrcConfig, count); + TInt r = CheckMemFlags(aTransferArgs.iSrcConfig); if (r != KErrNone) { __KTRACE_OPT(KPANIC, Kern::Printf("Error: CheckMemFlags(src)")); return r; } - r = CheckMemFlags(aTransferArgs.iDstConfig, count); + r = CheckMemFlags(aTransferArgs.iDstConfig); if (r != KErrNone) { __KTRACE_OPT(KPANIC, Kern::Printf("Error: CheckMemFlags(dst)")); @@ -1160,7 +1158,7 @@ // Max aligned length is used to make sure the beginnings of subtransfers // (i.e. fragments) are correctly aligned. const TUint max_aligned_len = (aMaxTransferLen & - ~(Max(align_mask_src, align_mask_dst))); + ~(_Max(align_mask_src, align_mask_dst))); __KTRACE_OPT(KDMA, Kern::Printf("max_aligned_len: %d", max_aligned_len)); // Client and PSL sane? __DMA_ASSERTD(max_aligned_len > 0); @@ -1235,8 +1233,8 @@ break; } // Compute fragment size - TUint c = Min(aMaxTransferLen, aCount); - __KTRACE_OPT(KDMA, Kern::Printf("c = Min(aMaxTransferLen, aCount) = %d", c)); + TUint c = _Min(aMaxTransferLen, aCount); + __KTRACE_OPT(KDMA, Kern::Printf("c = _Min(aMaxTransferLen, aCount) = %d", c)); // SRC if (mem_src && !(src.iFlags & KDmaMemIsContiguous)) @@ -1422,8 +1420,8 @@ break; } // Compute fragment size - TUint c = Min(aMaxTransferLen, aCount); - __KTRACE_OPT(KDMA, Kern::Printf("c = Min(aMaxTransferLen, aCount) = %d", c)); + TUint c = _Min(aMaxTransferLen, aCount); + __KTRACE_OPT(KDMA, Kern::Printf("c = _Min(aMaxTransferLen, aCount) = %d", c)); if (mem_src && !(src.iFlags & KDmaMemIsContiguous)) { @@ -1536,8 +1534,8 @@ break; } // Compute fragment size - TUint c = Min(aMaxTransferLen, aCount); - __KTRACE_OPT(KDMA, Kern::Printf("c = Min(aMaxTransferLen, aCount) = %d", c)); + TUint c = _Min(aMaxTransferLen, aCount); + __KTRACE_OPT(KDMA, Kern::Printf("c = _Min(aMaxTransferLen, aCount) = %d", c)); if (mem_dst && !(dst.iFlags & KDmaMemIsContiguous)) { @@ -1642,7 +1640,7 @@ // Max aligned length is used to make sure the beginnings of subtransfers // (i.e. fragments) are correctly aligned. const TUint max_aligned_len = (aMaxTransferLen & - ~(Max(align_mask_src, align_mask_dst))); + ~(_Max(align_mask_src, align_mask_dst))); __KTRACE_OPT(KDMA, Kern::Printf("max_aligned_len: %d", max_aligned_len)); // Client and PSL sane? __DMA_ASSERTD(max_aligned_len > 0); @@ -1708,6 +1706,7 @@ // Revert any previous fragmentation attempt FreeSrcDesList(); FreeDstDesList(); + __DMA_ASSERTD(iSrcDesCount == iDstDesCount); do { // Allocate fragment @@ -1721,9 +1720,10 @@ { break; } + __DMA_ASSERTD(iSrcDesCount == iDstDesCount); // Compute fragment size - TUint c = Min(aMaxTransferLen, aCount); - __KTRACE_OPT(KDMA, Kern::Printf("c = Min(aMaxTransferLen, aCount) = %d", c)); + TUint c = _Min(aMaxTransferLen, aCount); + __KTRACE_OPT(KDMA, Kern::Printf("c = _Min(aMaxTransferLen, aCount) = %d", c)); // SRC if (mem_src && !(src.iFlags & KDmaMemIsContiguous)) @@ -1851,7 +1851,7 @@ // Not configured? Call Fragment() first! if (iChannel.iDmacCaps->iAsymHwDescriptors) { - __DMA_ASSERTD((iSrcDesCount < 0) && (iDstDesCount < 0)); + __DMA_ASSERTD((iSrcDesCount > 0) && (iDstDesCount > 0)); } else { @@ -1863,11 +1863,14 @@ iChannel.Wait(); TUint32 req_count = iChannel.iQueuedRequests++; - if (req_count == 0) + if (iChannel.iCallQueuedRequestFn) { - iChannel.Signal(); - iChannel.QueuedRequestCountChanged(); - iChannel.Wait(); + if (req_count == 0) + { + iChannel.Signal(); + iChannel.QueuedRequestCountChanged(); + iChannel.Wait(); + } } TInt r = KErrGeneral; @@ -1883,9 +1886,12 @@ req_count = --iChannel.iQueuedRequests; __DMA_INVARIANT(); iChannel.Signal(); - if (req_count == 0) + if (iChannel.iCallQueuedRequestFn) { - iChannel.QueuedRequestCountChanged(); + if (req_count == 0) + { + iChannel.QueuedRequestCountChanged(); + } } } else if (iIsrCb && !iChannel.IsQueueEmpty()) @@ -1899,9 +1905,12 @@ req_count = --iChannel.iQueuedRequests; __DMA_INVARIANT(); iChannel.Signal(); - if (req_count == 0) + if (iChannel.iCallQueuedRequestFn) { - iChannel.QueuedRequestCountChanged(); + if (req_count == 0) + { + iChannel.QueuedRequestCountChanged(); + } } } else if (iChannel.iIsrDfc & (TUint32)TDmaChannel::KCancelFlagMask) @@ -1911,18 +1920,19 @@ req_count = --iChannel.iQueuedRequests; __DMA_INVARIANT(); iChannel.Signal(); - if (req_count == 0) + if (iChannel.iCallQueuedRequestFn) { - iChannel.QueuedRequestCountChanged(); + if (req_count == 0) + { + iChannel.QueuedRequestCountChanged(); + } } } else { iQueued = ETrue; iChannel.iReqQ.Add(&iLink); - // iChannel.iNullPtr points to iChannel.iCurHdr for an empty queue - *iChannel.iNullPtr = iFirstHdr; - iChannel.iNullPtr = &(iLastHdr->iNext); + iChannel.SetNullPtr(*this); if (iIsrCb) { // Since we've made sure that there is no other request in the @@ -1934,7 +1944,7 @@ // possible. __e32_atomic_store_rel32(&iChannel.iIsrCbRequest, ETrue); } - iChannel.DoQueue(const_cast(*this)); + iChannel.DoQueue(*this); r = KErrNone; __DMA_INVARIANT(); iChannel.Signal(); @@ -2112,21 +2122,6 @@ __KTRACE_OPT(KDMA, Kern::Printf("DDmaRequest::TotalNumSrcElementsTransferred")); // Not yet implemented. - - // So far largely bogus code (just to touch some symbols)... - iTotalNumSrcElementsTransferred = 0; - TDmac& c = *(iChannel.iController); - if (c.iCapsHwDes) - { - for (const SDmaDesHdr* pH = iFirstHdr; pH != NULL; pH = pH->iNext) - { - iTotalNumSrcElementsTransferred += c.HwDesNumDstElementsTransferred(*pH); - } - } - else - { - // Do something different for pseudo descriptors... - } return iTotalNumSrcElementsTransferred; } @@ -2213,22 +2208,26 @@ (0 <= iDstDesCount) && (iDstDesCount <= iChannel.iMaxDesCount)); if (iSrcDesCount == 0) { + // Not fragmented yet __DMA_ASSERTD(iDstDesCount == 0); __DMA_ASSERTD(!iQueued); __DMA_ASSERTD(!iSrcFirstHdr && !iSrcLastHdr && !iDstFirstHdr && !iDstLastHdr); } + else if (iDstDesCount == 0) + { + // Src side only fragmented yet + __DMA_ASSERTD(iChannel.iController->IsValidHdr(iSrcFirstHdr)); + __DMA_ASSERTD(iChannel.iController->IsValidHdr(iSrcLastHdr)); + } else { + // Src & Dst sides fragmented __DMA_ASSERTD(iChannel.iController->IsValidHdr(iSrcFirstHdr)); __DMA_ASSERTD(iChannel.iController->IsValidHdr(iSrcLastHdr)); __DMA_ASSERTD(iChannel.iController->IsValidHdr(iDstFirstHdr)); __DMA_ASSERTD(iChannel.iController->IsValidHdr(iDstLastHdr)); } - if (iChannel.iDmacCaps->iBalancedAsymSegments) - { - __DMA_ASSERTD(iSrcDesCount == iDstDesCount); - } } else { @@ -2271,6 +2270,7 @@ iReqQ(), iReqCount(0), iQueuedRequests(0), + iCallQueuedRequestFn(ETrue), iCancelInfo(NULL), iRedoRequest(EFalse), iIsrCbRequest(EFalse) @@ -2416,7 +2416,8 @@ // ISR should not happen after this function returns. iController->StopTransfer(*this); - ResetStateMachine(); + DoCancelAll(); + ResetNullPtr(); // Clean-up the request queue. SDblQueLink* pL; @@ -2472,9 +2473,12 @@ // 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)) + if (iCallQueuedRequestFn) { - QueuedRequestCountChanged(); + if ((req_count_before != 0) && (req_count_after == 0)) + { + QueuedRequestCountChanged(); + } } __DMA_INVARIANT(); @@ -2687,8 +2691,7 @@ { SDmaDesHdr* pCompletedSrcHdr = NULL; SDmaDesHdr* pCompletedDstHdr = NULL; - DoDfc(const_cast(*pCurReq), - pCompletedSrcHdr, pCompletedDstHdr); + DoDfc(*pCurReq, pCompletedSrcHdr, pCompletedDstHdr); // We don't support asymmetrical ISR notifications and request // completions yet, hence we can do the following assert test // here; also 'complete' is determined equally by either the @@ -2700,7 +2703,7 @@ else { SDmaDesHdr* pCompletedHdr = NULL; - DoDfc(const_cast(*pCurReq), pCompletedHdr); + DoDfc(*pCurReq, pCompletedHdr); complete = (pCompletedHdr == pCurReq->iLastHdr); } // If just completed last fragment from current request, switch to @@ -2711,7 +2714,7 @@ pCurReq->iLink.Deque(); iQueuedRequests--; if (iReqQ.IsEmpty()) - iNullPtr = &iCurHdr; + ResetNullPtr(); pCompletedReq->OnDeque(); } } @@ -2786,30 +2789,22 @@ // 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)) + if (iCallQueuedRequestFn) { - QueuedRequestCountChanged(); + if ((req_count_before != 0) && (req_count_after == 0)) + { + QueuedRequestCountChanged(); + } } __DMA_INVARIANT(); } -// -// Reset state machine only, request queue is unchanged */ -// -void TDmaChannel::ResetStateMachine() - { - DoCancelAll(); - iCurHdr = NULL; - iNullPtr = &iCurHdr; - } - - void TDmaChannel::DoQueue(const DDmaRequest& /*aReq*/) { // Must be overridden - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); } @@ -2828,7 +2823,7 @@ // To make sure this version of the function isn't called for channels for // which it isn't appropriate (and which therefore don't override it) we // put this check in here. - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); } @@ -2838,21 +2833,33 @@ // To make sure this version of the function isn't called for channels for // which it isn't appropriate (and which therefore don't override it) we // put this check in here. - __DMA_CANT_HAPPEN(); + __DMA_UNREACHABLE_DEFAULT(); + } + + +void TDmaChannel::SetNullPtr(const DDmaRequest& aReq) + { + // iNullPtr points to iCurHdr for an empty queue + *iNullPtr = aReq.iFirstHdr; + iNullPtr = &(aReq.iLastHdr->iNext); + } + + +void TDmaChannel::ResetNullPtr() + { + iCurHdr = NULL; + iNullPtr = &iCurHdr; } /** PSL may override */ void TDmaChannel::QueuedRequestCountChanged() { -#ifdef _DEBUG + __KTRACE_OPT(KDMA, Kern::Printf("TDmaChannel::QueuedRequestCountChanged(): " + "disabling further calls")); Wait(); - __KTRACE_OPT(KDMA, - Kern::Printf("TDmaChannel::QueuedRequestCountChanged() %d", - iQueuedRequests)); - __DMA_ASSERTA(iQueuedRequests >= 0); + iCallQueuedRequestFn = EFalse; Signal(); -#endif } @@ -3018,6 +3025,35 @@ ////////////////////////////////////////////////////////////////////////////// // TDmaAsymSgChannel +TDmaAsymSgChannel::TDmaAsymSgChannel() + : iSrcCurHdr(NULL), + iSrcNullPtr(&iSrcCurHdr), + iDstCurHdr(NULL), + iDstNullPtr(&iDstCurHdr) + { + __DMA_INVARIANT(); + } + + +void TDmaAsymSgChannel::SetNullPtr(const DDmaRequest& aReq) + { + // i{Src|Dst}NullPtr points to i{Src|Dst}CurHdr for an empty queue + *iSrcNullPtr = aReq.iSrcFirstHdr; + *iDstNullPtr = aReq.iDstFirstHdr; + iSrcNullPtr = &(aReq.iSrcLastHdr->iNext); + iDstNullPtr = &(aReq.iDstLastHdr->iNext); + } + + +void TDmaAsymSgChannel::ResetNullPtr() + { + iSrcCurHdr = NULL; + iSrcNullPtr = &iSrcCurHdr; + iDstCurHdr = NULL; + iDstNullPtr = &iDstCurHdr; + } + + void TDmaAsymSgChannel::DoQueue(const DDmaRequest& aReq) { if (iState == ETransferring) @@ -3062,3 +3098,34 @@ iState = (iSrcCurHdr != NULL) ? ETransferring : EIdle; } + +#ifdef _DEBUG +void TDmaAsymSgChannel::Invariant() + { + Wait(); + + __DMA_ASSERTD(iReqCount >= 0); + + __DMA_ASSERTD(iSrcCurHdr == NULL || iController->IsValidHdr(iSrcCurHdr)); + __DMA_ASSERTD(iDstCurHdr == NULL || iController->IsValidHdr(iDstCurHdr)); + + // should always point to NULL pointer ending fragment queue + __DMA_ASSERTD(*iSrcNullPtr == NULL); + __DMA_ASSERTD(*iDstNullPtr == NULL); + + __DMA_ASSERTD((0 <= iAvailDesCount) && (iAvailDesCount <= iMaxDesCount)); + + __DMA_ASSERTD((iSrcCurHdr && iDstCurHdr && !IsQueueEmpty()) || + (!iSrcCurHdr && !iDstCurHdr && IsQueueEmpty())); + if (iSrcCurHdr == NULL) + { + __DMA_ASSERTD(iSrcNullPtr == &iSrcCurHdr); + } + if (iDstCurHdr == NULL) + { + __DMA_ASSERTD(iDstNullPtr == &iDstCurHdr); + } + + Signal(); + } +#endif