sl@0: // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\dma\d_dma.cpp sl@0: // sl@0: // sl@0: sl@0: #include "platform.h" sl@0: #include sl@0: #include sl@0: #include "d_dma.h" sl@0: sl@0: _LIT(KClientPanicCat, "D_DMA"); sl@0: _LIT(KDFCThreadName,"D_DMA_DFC_THREAD"); sl@0: const TInt KDFCThreadPriority=26; sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: // sl@0: // Class abstracting the way DMA buffers are created and destroyed to sl@0: // allow tests to run both on WINS and hardware. sl@0: // sl@0: sl@0: class TBufferMgr sl@0: { sl@0: public: sl@0: TInt Alloc(TInt aIdx, TInt aSize); sl@0: void FreeAll(); sl@0: TUint8* Addr(TInt aIdx) const; sl@0: TPhysAddr PhysAddr(TInt aIdx) const; sl@0: TInt Size(TInt aIdx) const; sl@0: enum { KMaxBuf = 8 }; sl@0: private: sl@0: #ifdef __WINS__ sl@0: struct {TUint8* iPtr; TInt iSize;} iBufs[KMaxBuf]; sl@0: #else sl@0: struct {DPlatChunkHw* iChunk; TInt iSize;} iBufs[KMaxBuf]; sl@0: #endif sl@0: }; sl@0: sl@0: #ifdef __WINS__ sl@0: sl@0: TUint8* TBufferMgr::Addr(TInt aIdx) const sl@0: { sl@0: __ASSERT_DEBUG(0 <= aIdx && aIdx < KMaxBuf, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: __ASSERT_DEBUG(iBufs[aIdx].iPtr != NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: return iBufs[aIdx].iPtr; sl@0: } sl@0: sl@0: sl@0: TInt TBufferMgr::Size(TInt aIdx) const sl@0: { sl@0: __ASSERT_DEBUG(0 <= aIdx && aIdx < KMaxBuf, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: __ASSERT_DEBUG(iBufs[aIdx].iPtr != NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: return iBufs[aIdx].iSize; sl@0: } sl@0: sl@0: sl@0: TInt TBufferMgr::Alloc(TInt aIdx, TInt aSize) sl@0: { sl@0: __ASSERT_DEBUG(0 <= aIdx && aIdx < KMaxBuf, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: __ASSERT_DEBUG(iBufs[aIdx].iPtr == NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: NKern::ThreadEnterCS(); sl@0: iBufs[aIdx].iPtr = new TUint8[aSize]; sl@0: NKern::ThreadLeaveCS(); sl@0: iBufs[aIdx].iSize = aSize; sl@0: return iBufs[aIdx].iPtr ? KErrNone : KErrNoMemory; sl@0: } sl@0: sl@0: sl@0: void TBufferMgr::FreeAll() sl@0: { sl@0: NKern::ThreadEnterCS(); sl@0: for (TInt i=0; iLinearAddress(); sl@0: } sl@0: sl@0: sl@0: TPhysAddr TBufferMgr::PhysAddr(TInt aIdx) const sl@0: { sl@0: __ASSERT_DEBUG(0 <= aIdx && aIdx < KMaxBuf, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: __ASSERT_DEBUG(iBufs[aIdx].iChunk != NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: return iBufs[aIdx].iChunk->PhysicalAddress(); sl@0: } sl@0: sl@0: sl@0: TInt TBufferMgr::Size(TInt aIdx) const sl@0: { sl@0: __ASSERT_DEBUG(0 <= aIdx && aIdx < KMaxBuf, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: __ASSERT_DEBUG(iBufs[aIdx].iChunk != NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: return iBufs[aIdx].iSize; sl@0: } sl@0: sl@0: sl@0: TInt TBufferMgr::Alloc(TInt aIdx, TInt aSize) sl@0: { sl@0: __ASSERT_DEBUG(0 <= aIdx && aIdx < KMaxBuf, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: __ASSERT_DEBUG(iBufs[aIdx].iChunk == NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: NKern::ThreadEnterCS(); sl@0: TPhysAddr phys; sl@0: TInt r = Epoc::AllocPhysicalRam(aSize, phys); sl@0: if (r == KErrNone) sl@0: { sl@0: r = DPlatChunkHw::New(iBufs[aIdx].iChunk, phys, aSize, EMapAttrSupRw | EMapAttrFullyBlocking); sl@0: if (r != KErrNone) sl@0: Epoc::FreePhysicalRam(phys, aSize); sl@0: iBufs[aIdx].iSize = aSize; sl@0: sl@0: __KTRACE_OPT(KDMA, Kern::Printf("TBufferMgr::Alloc buffer %d linAddr=0x%08x, physAddr=0x%08x, size=%d", sl@0: aIdx, Addr(aIdx), PhysAddr(aIdx), Size(aIdx))); sl@0: } sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: void TBufferMgr::FreeAll() sl@0: { sl@0: for (TInt i=0; iPhysicalAddress(); sl@0: TInt size = iBufs[i].iSize; sl@0: __ASSERT_DEBUG(iBufs[i].iChunk->AccessCount() == 1, sl@0: Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: NKern::ThreadEnterCS(); sl@0: iBufs[i].iChunk->Close(NULL); sl@0: iBufs[i].iChunk = NULL; sl@0: Epoc::FreePhysicalRam(base, size); sl@0: NKern::ThreadLeaveCS(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: #endif sl@0: sl@0: sl@0: #ifndef DMA_APIV2 sl@0: static TInt FragmentCount(DDmaRequest* aRequest) sl@0: { sl@0: TInt count = 0; sl@0: for (SDmaDesHdr* pH = aRequest->iFirstHdr; pH != NULL; pH = pH->iNext) sl@0: count++; sl@0: return count; sl@0: } sl@0: #endif sl@0: sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: class DDmaTestChannel : public DLogicalChannelBase sl@0: { sl@0: public: sl@0: virtual ~DDmaTestChannel(); sl@0: protected: sl@0: // from DLogicalChannelBase sl@0: virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); sl@0: virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); sl@0: virtual TInt RequestUserHandle(DThread* aThread, TOwnerType aType); sl@0: private: sl@0: TInt Execute(const TDesC8& aDes); sl@0: static void Dfc(DDmaRequest::TResult aResult, TAny* aArg); sl@0: TInt DoGetInfo(TAny* aInfo); sl@0: private: sl@0: TUint32 iCookie; sl@0: TBufferMgr iBufMgr; sl@0: TDmaChannel* iChannel; sl@0: enum { KMaxRequests = 8 }; sl@0: DDmaRequest* iRequests[KMaxRequests]; sl@0: TClientRequest* iClientRequests[KMaxRequests]; sl@0: DDmaTestChannel* iMap[KMaxRequests]; sl@0: TUint32 iMemMemPslInfo; sl@0: DThread* iClient; sl@0: TDynamicDfcQue* iDfcQ; sl@0: }; sl@0: sl@0: sl@0: TInt DDmaTestChannel::RequestUserHandle(DThread* aThread, TOwnerType aType) sl@0: { sl@0: if (aType!=EOwnerThread || aThread!=iClient) sl@0: return KErrAccessDenied; sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DDmaTestChannel::DoGetInfo(TAny* aInfo) sl@0: { sl@0: RTestDma::TInfo uinfo; sl@0: const TDmaTestInfo& kinfo = DmaTestInfo(); sl@0: uinfo.iMaxTransferSize = kinfo.iMaxTransferSize; sl@0: uinfo.iMemAlignMask = kinfo.iMemAlignMask; sl@0: uinfo.iMaxSbChannels = kinfo.iMaxSbChannels; sl@0: memcpy(&(uinfo.iSbChannels), kinfo.iSbChannels, 4 * kinfo.iMaxSbChannels); sl@0: uinfo.iMaxDbChannels = kinfo.iMaxDbChannels; sl@0: memcpy(&(uinfo.iDbChannels), kinfo.iDbChannels, 4 * kinfo.iMaxDbChannels); sl@0: uinfo.iMaxSgChannels = kinfo.iMaxSgChannels; sl@0: memcpy(&(uinfo.iSgChannels), kinfo.iSgChannels, 4 * kinfo.iMaxSgChannels); sl@0: sl@0: XTRAPD(r, XT_DEFAULT, kumemput(aInfo, &uinfo, sizeof(RTestDma::TInfo))); sl@0: return r == KErrNone ? KErrDied : KErrGeneral; sl@0: } sl@0: sl@0: sl@0: // called in thread critical section sl@0: TInt DDmaTestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* aInfo, const TVersion& /*aVer*/) sl@0: { sl@0: TPckgBuf infoBuf; sl@0: sl@0: TInt r=Kern::ThreadDesRead(&Kern::CurrentThread(), aInfo, infoBuf, 0, KChunkShiftBy0); sl@0: if (r != KErrNone) sl@0: return r; sl@0: sl@0: if (infoBuf().iWhat == RTestDma::TOpenInfo::EGetInfo) sl@0: return DoGetInfo(infoBuf().U.iInfo); sl@0: else sl@0: { sl@0: if (!iDfcQ) sl@0: { sl@0: r = Kern::DynamicDfcQCreate(iDfcQ, KDFCThreadPriority, KDFCThreadName); sl@0: if (r != KErrNone) sl@0: return r; sl@0: #ifdef CPU_AFFINITY_ANY sl@0: NKern::ThreadSetCpuAffinity((NThread*)(iDfcQ->iThread), KCpuAffinityAny); sl@0: #endif sl@0: } sl@0: sl@0: iMemMemPslInfo = DmaTestInfo().iMemMemPslInfo; sl@0: iCookie = infoBuf().U.iOpen.iId; sl@0: TDmaChannel::SCreateInfo info; sl@0: info.iCookie = iCookie; sl@0: info.iDfcQ = iDfcQ; sl@0: info.iDfcPriority = 3; sl@0: info.iDesCount = infoBuf().U.iOpen.iDesCount; sl@0: r = TDmaChannel::Open(info, iChannel); sl@0: if (r!= KErrNone) sl@0: return r; sl@0: iClient = &Kern::CurrentThread(); sl@0: for (TInt i=0; iCancelAll(); sl@0: TInt i; sl@0: for (i=0; iClose(); sl@0: for (i=0; iDestroy(); sl@0: } sl@0: iBufMgr.FreeAll(); sl@0: } sl@0: sl@0: sl@0: TInt DDmaTestChannel::Request(TInt aFunction, TAny* a1, TAny* a2) sl@0: { sl@0: switch (aFunction) sl@0: { sl@0: case RTestDma::EAllocBuffer: sl@0: return iBufMgr.Alloc((TInt)a1, (TInt)a2); sl@0: case RTestDma::EFreeAllBuffers: sl@0: iBufMgr.FreeAll(); sl@0: return KErrNone; sl@0: case RTestDma::EFillBuffer: sl@0: { sl@0: TInt i = (TInt)a1; sl@0: TUint8 val = (TUint8)(TUint)a2; sl@0: memset(iBufMgr.Addr(i), val, iBufMgr.Size(i)); sl@0: return KErrNone; sl@0: } sl@0: case RTestDma::ECheckBuffer: sl@0: { sl@0: TInt i = (TInt)a1; sl@0: TUint8 val = (TUint8)(TUint)a2; sl@0: TUint8* p = iBufMgr.Addr(i); sl@0: TUint8* end = p + iBufMgr.Size(i); sl@0: while (p < end) sl@0: if (*p++ != val) sl@0: { sl@0: #ifdef _DEBUG sl@0: const TUint8 prevValue = *(p-1); sl@0: #endif sl@0: __KTRACE_OPT(KDMA, Kern::Printf("Check DMA buffer number %d failed at offset: %d value: %d(%c)", sl@0: i, p-iBufMgr.Addr(i)-1, prevValue, prevValue)); sl@0: return EFalse; sl@0: } sl@0: return ETrue; sl@0: } sl@0: case RTestDma::EFragment: sl@0: { sl@0: RTestDma::TFragmentInfo info; sl@0: kumemget(&info, a1, sizeof info); sl@0: __ASSERT_DEBUG(iBufMgr.Size(info.iSrcBufIdx) == iBufMgr.Size(info.iDestBufIdx), sl@0: Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: __ASSERT_DEBUG(info.iSize <= iBufMgr.Size(info.iSrcBufIdx), sl@0: Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: __ASSERT_DEBUG(0 <= info.iRequestIdx && info.iRequestIdx < KMaxRequests, sl@0: Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: #ifdef __DMASIM__ sl@0: // DMASIM doesn't use physical addresses sl@0: TUint32 src = (TUint32)iBufMgr.Addr(info.iSrcBufIdx); sl@0: TUint32 dest = (TUint32)iBufMgr.Addr(info.iDestBufIdx); sl@0: TUint KFlags = KDmaMemSrc | KDmaIncSrc | KDmaMemDest | KDmaIncDest; sl@0: #else sl@0: TUint32 src = iBufMgr.PhysAddr(info.iSrcBufIdx); sl@0: TUint32 dest = iBufMgr.PhysAddr(info.iDestBufIdx); sl@0: TUint KFlags = KDmaMemSrc | KDmaIncSrc | KDmaPhysAddrSrc | sl@0: KDmaMemDest | KDmaIncDest | KDmaPhysAddrDest | KDmaAltTransferLen; sl@0: #endif sl@0: TInt r = iRequests[info.iRequestIdx]->Fragment(src, dest, info.iSize, KFlags, iMemMemPslInfo); sl@0: if (r == KErrNone && info.iRs) sl@0: r = iClientRequests[info.iRequestIdx]->SetStatus(info.iRs); sl@0: return r; sl@0: } sl@0: case RTestDma::EExecute: sl@0: return Execute(*(TDesC8*)a1); sl@0: case RTestDma::EFailNext: sl@0: return iChannel->FailNext((TInt)a1); sl@0: case RTestDma::EFragmentCount: sl@0: { sl@0: TInt reqIdx = (TInt)a1; sl@0: __ASSERT_DEBUG(0 <= reqIdx && reqIdx < KMaxRequests, Kern::PanicCurrentThread(KClientPanicCat, __LINE__)); sl@0: #ifdef DMA_APIV2 sl@0: return iRequests[reqIdx]->FragmentCount(); sl@0: #else sl@0: return FragmentCount(iRequests[reqIdx]); sl@0: #endif sl@0: } sl@0: case RTestDma::EMissInterrupts: sl@0: return iChannel->MissNextInterrupts((TInt)a1); sl@0: default: sl@0: Kern::PanicCurrentThread(KClientPanicCat, __LINE__); sl@0: return KErrNone; // work-around spurious warning sl@0: } sl@0: } sl@0: sl@0: sl@0: TInt DDmaTestChannel::Execute(const TDesC8& aDes) sl@0: { sl@0: TBuf8<64> cmd; sl@0: Kern::KUDesGet(cmd, aDes); sl@0: __KTRACE_OPT(KDMA, Kern::Printf("DDmaTestChannel::Execute cmd=%S", &cmd)); sl@0: sl@0: const TText8* p = cmd.Ptr(); sl@0: const TText8* pEnd = p + cmd.Length(); sl@0: while (pQueue(); sl@0: break; sl@0: } sl@0: case 'C': sl@0: iChannel->CancelAll(); sl@0: break; sl@0: default: sl@0: Kern::PanicCurrentThread(KClientPanicCat, __LINE__); sl@0: } sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: void DDmaTestChannel::Dfc(DDmaRequest::TResult aResult, TAny* aArg) sl@0: { sl@0: DDmaTestChannel** ppC = (DDmaTestChannel**)aArg; sl@0: DDmaTestChannel* pC = *ppC; sl@0: TInt i = ppC - pC->iMap; sl@0: TClientRequest* req = pC->iClientRequests[i]; sl@0: TInt r = (aResult==DDmaRequest::EOk) ? KErrNone : KErrGeneral; sl@0: if (req->IsReady()) sl@0: Kern::QueueRequestComplete(pC->iClient, req, r); sl@0: } sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: class DDmaTestFactory : public DLogicalDevice sl@0: { sl@0: public: sl@0: DDmaTestFactory(); sl@0: // from DLogicalDevice sl@0: virtual TInt Install(); sl@0: virtual void GetCaps(TDes8& aDes) const; sl@0: virtual TInt Create(DLogicalChannelBase*& aChannel); sl@0: }; sl@0: sl@0: sl@0: DDmaTestFactory::DDmaTestFactory() sl@0: { sl@0: iVersion = TestDmaLddVersion(); sl@0: iParseMask = KDeviceAllowUnit; // no info, no PDD sl@0: // iUnitsMask = 0; // Only one thing sl@0: } sl@0: sl@0: sl@0: TInt DDmaTestFactory::Create(DLogicalChannelBase*& aChannel) sl@0: { sl@0: aChannel=new DDmaTestChannel; sl@0: return aChannel ? KErrNone : KErrNoMemory; sl@0: } sl@0: sl@0: sl@0: TInt DDmaTestFactory::Install() sl@0: { sl@0: return SetName(&KTestDmaLddName); sl@0: } sl@0: sl@0: sl@0: void DDmaTestFactory::GetCaps(TDes8& /*aDes*/) const sl@0: { sl@0: } sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: DECLARE_STANDARD_LDD() sl@0: { sl@0: return new DDmaTestFactory; sl@0: }