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